diff --git a/include/linux/filter.h b/include/linux/filter.h index ddfa037..0e39016 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -136,7 +136,8 @@ static inline unsigned int sk_filter_len(struct sk_filter *fp) #define SKF_AD_PROTOCOL 0 #define SKF_AD_PKTTYPE 4 #define SKF_AD_IFINDEX 8 -#define SKF_AD_MAX 12 +#define SKF_AD_NLATTR 12 +#define SKF_AD_MAX 16 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/net/core/filter.c b/net/core/filter.c index e0a0694..20ed056 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -268,6 +269,22 @@ load_b: case SKF_AD_IFINDEX: A = skb->dev->ifindex; continue; + case SKF_AD_NLATTR: { + struct nlattr *nla; + + if (skb_is_nonlinear(skb)) + return 0; + if (A > skb->len - sizeof(struct nlattr)) + return 0; + + nla = nla_find((struct nlattr *)&skb->data[A], + skb->len - A, X); + if (nla) + A = (void *)nla - (void *)skb->data; + else + A = 0; + continue; + } default: return 0; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 524e826..6f68f2b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -919,6 +919,17 @@ static inline int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) { struct netlink_sock *nlk = nlk_sk(sk); + struct sk_filter *filter; + unsigned int len = skb->len; + + rcu_read_lock_bh(); + filter = rcu_dereference(sk->sk_filter); + if (filter) + len = sk_run_filter(skb, filter->insns, filter->len); + rcu_read_unlock_bh(); + + if (len == 0) + return 0; if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !test_bit(0, &nlk->state)) {