From b715631fad3ed320b85d386a84a6fb0b3f86b0b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:33:47 -0700 Subject: socket: sk_filter minor cleanups Some minor style cleanups: * Move __KERNEL__ definitions to one place in filter.h * Use const for sk_filter_len * Line wrapping * Put EXPORT_SYMBOL next to function definition Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/filter.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'include/linux/filter.h') diff --git a/include/linux/filter.h b/include/linux/filter.h index ddfa0372a3b7..bfc5d319b946 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -37,21 +37,6 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ struct sock_filter __user *filter; }; -#ifdef __KERNEL__ -struct sk_filter -{ - atomic_t refcnt; - unsigned int len; /* Number of filter blocks */ - struct rcu_head rcu; - struct sock_filter insns[0]; -}; - -static inline unsigned int sk_filter_len(struct sk_filter *fp) -{ - return fp->len*sizeof(struct sock_filter) + sizeof(*fp); -} -#endif - /* * Instruction classes */ @@ -141,10 +126,24 @@ static inline unsigned int sk_filter_len(struct sk_filter *fp) #define SKF_LL_OFF (-0x200000) #ifdef __KERNEL__ +struct sk_filter +{ + atomic_t refcnt; + unsigned int len; /* Number of filter blocks */ + struct rcu_head rcu; + struct sock_filter insns[0]; +}; + +static inline unsigned int sk_filter_len(const struct sk_filter *fp) +{ + return fp->len * sizeof(struct sock_filter) + sizeof(*fp); +} + struct sk_buff; struct sock; -extern unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); +extern unsigned int sk_run_filter(struct sk_buff *skb, + struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); extern int sk_detach_filter(struct sock *sk); extern int sk_chk_filter(struct sock_filter *filter, int flen); -- cgit v1.2.3 From 43db6d65e0ef943a361cb91f8baa49132009227b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:43:09 -0700 Subject: socket: sk_filter deinline The sk_filter function is too big to be inlined. This saves 2296 bytes of text on allyesconfig. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/filter.h | 1 + include/net/sock.h | 35 ----------------------------------- net/core/filter.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 35 deletions(-) (limited to 'include/linux/filter.h') diff --git a/include/linux/filter.h b/include/linux/filter.h index bfc5d319b946..673e5677ebcc 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -142,6 +142,7 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp) struct sk_buff; struct sock; +extern int sk_filter(struct sock *sk, struct sk_buff *skb); extern unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); diff --git a/include/net/sock.h b/include/net/sock.h index f4fdd101c9a2..09255eae93e9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -927,41 +927,6 @@ extern void sk_common_release(struct sock *sk); /* Initialise core socket variables */ extern void sock_init_data(struct socket *sock, struct sock *sk); -/** - * sk_filter - run a packet through a socket filter - * @sk: sock associated with &sk_buff - * @skb: buffer to filter - * @needlock: set to 1 if the sock is not locked by caller. - * - * Run the filter code and then cut skb->data to correct size returned by - * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller - * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to sk_run_filter. It returns 0 if the packet should - * be accepted or -EPERM if the packet should be tossed. - * - */ - -static inline int sk_filter(struct sock *sk, struct sk_buff *skb) -{ - int err; - struct sk_filter *filter; - - err = security_sock_rcv_skb(sk, skb); - if (err) - return err; - - rcu_read_lock_bh(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - unsigned int pkt_len = sk_run_filter(skb, filter->insns, - filter->len); - err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; - } - rcu_read_unlock_bh(); - - return err; -} - /** * sk_filter_release: Release a socket filter * @sk: socket diff --git a/net/core/filter.c b/net/core/filter.c index 85a5febab567..bbb53c69857c 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -63,6 +63,41 @@ static inline void *load_pointer(struct sk_buff *skb, int k, } } +/** + * sk_filter - run a packet through a socket filter + * @sk: sock associated with &sk_buff + * @skb: buffer to filter + * @needlock: set to 1 if the sock is not locked by caller. + * + * Run the filter code and then cut skb->data to correct size returned by + * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller + * than pkt_len we keep whole skb->data. This is the socket level + * wrapper to sk_run_filter. It returns 0 if the packet should + * be accepted or -EPERM if the packet should be tossed. + * + */ +int sk_filter(struct sock *sk, struct sk_buff *skb) +{ + int err; + struct sk_filter *filter; + + err = security_sock_rcv_skb(sk, skb); + if (err) + return err; + + rcu_read_lock_bh(); + filter = rcu_dereference(sk->sk_filter); + if (filter) { + unsigned int pkt_len = sk_run_filter(skb, filter->insns, + filter->len); + err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; + } + rcu_read_unlock_bh(); + + return err; +} +EXPORT_SYMBOL(sk_filter); + /** * sk_run_filter - run a filter on a socket * @skb: buffer to run the filter on -- cgit v1.2.3 From 4738c1db1593687713869fa69e733eebc7b0d6d8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 10 Apr 2008 02:02:28 -0700 Subject: [SKFILTER]: Add SKF_ADF_NLATTR instruction SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually parsing and walking attributes. It takes the offset at which to start searching in the 'A' register and the attribute type in the 'X' register and returns the offset in the 'A' register. When the attribute is not found it returns zero. A top-level attribute can be located using a filter like this (example for nfnetlink, using struct nfgenmsg): ... { /* A = offset of first attribute */ .code = BPF_LD | BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) }, { /* X = CTA_PROTOINFO */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, { /* Exit if not found */ .code = BPF_JMP | BPF_JEQ | BPF_K, .k = 0, .jt = }, ... A nested attribute below the CTA_PROTOINFO attribute would then be parsed like this: ... { /* A += sizeof(struct nlattr) */ .code = BPF_ALU | BPF_ADD | BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO_TCP, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, ... The data of an attribute can be loaded into 'A' like this: ... { /* X = A (attribute offset) */ .code = BPF_MISC | BPF_TAX, }, { /* A = skb->data[X + k] */ .code = BPF_LD | BPF_B | BPF_IND, .k = sizeof(struct nlattr), }, ... Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/filter.h | 3 ++- net/core/filter.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'include/linux/filter.h') diff --git a/include/linux/filter.h b/include/linux/filter.h index 673e5677ebcc..b6ea9aa9e853 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -121,7 +121,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ #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 bbb53c69857c..f5f3cf603064 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -303,6 +304,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; } -- cgit v1.2.3