diff options
-rw-r--r-- | net/netlink/af_netlink.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a17dda1bbee0..8df7f64c6db3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -168,16 +168,43 @@ int netlink_remove_tap(struct netlink_tap *nt) | |||
168 | } | 168 | } |
169 | EXPORT_SYMBOL_GPL(netlink_remove_tap); | 169 | EXPORT_SYMBOL_GPL(netlink_remove_tap); |
170 | 170 | ||
171 | static bool netlink_filter_tap(const struct sk_buff *skb) | ||
172 | { | ||
173 | struct sock *sk = skb->sk; | ||
174 | bool pass = false; | ||
175 | |||
176 | /* We take the more conservative approach and | ||
177 | * whitelist socket protocols that may pass. | ||
178 | */ | ||
179 | switch (sk->sk_protocol) { | ||
180 | case NETLINK_ROUTE: | ||
181 | case NETLINK_USERSOCK: | ||
182 | case NETLINK_SOCK_DIAG: | ||
183 | case NETLINK_NFLOG: | ||
184 | case NETLINK_XFRM: | ||
185 | case NETLINK_FIB_LOOKUP: | ||
186 | case NETLINK_NETFILTER: | ||
187 | case NETLINK_GENERIC: | ||
188 | pass = true; | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | return pass; | ||
193 | } | ||
194 | |||
171 | static int __netlink_deliver_tap_skb(struct sk_buff *skb, | 195 | static int __netlink_deliver_tap_skb(struct sk_buff *skb, |
172 | struct net_device *dev) | 196 | struct net_device *dev) |
173 | { | 197 | { |
174 | struct sk_buff *nskb; | 198 | struct sk_buff *nskb; |
199 | struct sock *sk = skb->sk; | ||
175 | int ret = -ENOMEM; | 200 | int ret = -ENOMEM; |
176 | 201 | ||
177 | dev_hold(dev); | 202 | dev_hold(dev); |
178 | nskb = skb_clone(skb, GFP_ATOMIC); | 203 | nskb = skb_clone(skb, GFP_ATOMIC); |
179 | if (nskb) { | 204 | if (nskb) { |
180 | nskb->dev = dev; | 205 | nskb->dev = dev; |
206 | nskb->protocol = htons((u16) sk->sk_protocol); | ||
207 | |||
181 | ret = dev_queue_xmit(nskb); | 208 | ret = dev_queue_xmit(nskb); |
182 | if (unlikely(ret > 0)) | 209 | if (unlikely(ret > 0)) |
183 | ret = net_xmit_errno(ret); | 210 | ret = net_xmit_errno(ret); |
@@ -192,6 +219,9 @@ static void __netlink_deliver_tap(struct sk_buff *skb) | |||
192 | int ret; | 219 | int ret; |
193 | struct netlink_tap *tmp; | 220 | struct netlink_tap *tmp; |
194 | 221 | ||
222 | if (!netlink_filter_tap(skb)) | ||
223 | return; | ||
224 | |||
195 | list_for_each_entry_rcu(tmp, &netlink_tap_all, list) { | 225 | list_for_each_entry_rcu(tmp, &netlink_tap_all, list) { |
196 | ret = __netlink_deliver_tap_skb(skb, tmp->dev); | 226 | ret = __netlink_deliver_tap_skb(skb, tmp->dev); |
197 | if (unlikely(ret)) | 227 | if (unlikely(ret)) |