lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1394529560-3490-3-git-send-email-pablo@netfilter.org>
Date:	Tue, 11 Mar 2014 10:19:13 +0100
From:	Pablo Neira Ayuso <pablo@...filter.org>
To:	netfilter-devel@...r.kernel.org
Cc:	davem@...emloft.net, netdev@...r.kernel.org, kaber@...sh.net
Subject: [PATCH RFC 2/9] net: filter: account filter length in bytes

This patch converts the len field in the struct sock_filter structure
from length in filter lines to bytes. I have added the new function
sk_bpf_flen() which allows you to obtain the filter in number of
blocks (which is what you usually need to iterate over a BPF filter).

The corresponding BPF jit implementation has been also adjusted.

Signed-off-by: Pablo Neira Ayuso <pablo@...filter.org>
---
 arch/arm/net/bpf_jit_32.c       |   19 ++++++++++---------
 arch/powerpc/net/bpf_jit_comp.c |    4 ++--
 arch/s390/net/bpf_jit_comp.c    |   10 +++++-----
 arch/sparc/net/bpf_jit_comp.c   |    2 +-
 arch/x86/net/bpf_jit_comp.c     |    2 +-
 include/linux/filter.h          |   10 ++++------
 include/net/sock.h              |    4 ++--
 net/core/filter.c               |   22 +++++++++++++++-------
 net/core/sock_diag.c            |    4 ++--
 9 files changed, 42 insertions(+), 35 deletions(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 65bd347..844e97b 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -135,7 +135,7 @@ static u16 saved_regs(struct jit_ctx *ctx)
 {
 	u16 ret = 0;
 
-	if ((ctx->skf->len > 1) ||
+	if ((sk_bpf_flen(ctx->skf) > 1) ||
 	    (ctx->skf->insns[0].code == BPF_S_RET_A))
 		ret |= 1 << r_A;
 
@@ -283,7 +283,7 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx)
 		ctx->imms[i] = k;
 
 	/* constants go just after the epilogue */
-	offset =  ctx->offsets[ctx->skf->len];
+	offset =  ctx->offsets[sk_bpf_flen(ctx->skf)];
 	offset += ctx->prologue_bytes;
 	offset += ctx->epilogue_bytes;
 	offset += i * 4;
@@ -423,7 +423,7 @@ static inline void emit_err_ret(u8 cond, struct jit_ctx *ctx)
 		emit(ARM_MOV_R(ARM_R0, ARM_R0), ctx);
 	} else {
 		_emit(cond, ARM_MOV_I(ARM_R0, 0), ctx);
-		_emit(cond, ARM_B(b_imm(ctx->skf->len, ctx)), ctx);
+		_emit(cond, ARM_B(b_imm(sk_bpf_flen(ctx->skf), ctx)), ctx);
 	}
 }
 
@@ -476,10 +476,10 @@ static int build_body(struct jit_ctx *ctx)
 	const struct sk_filter *prog = ctx->skf;
 	const struct sock_filter *inst;
 	unsigned i, load_order, off, condt;
-	int imm12;
+	int imm12, flen = sk_bpf_flen(ctx->skf);
 	u32 k;
 
-	for (i = 0; i < prog->len; i++) {
+	for (i = 0; i < flen; i++) {
 		inst = &(prog->insns[i]);
 		/* K as an immediate value operand */
 		k = inst->k;
@@ -773,8 +773,8 @@ cmp_x:
 				ctx->ret0_fp_idx = i;
 			emit_mov_i(ARM_R0, k, ctx);
 b_epilogue:
-			if (i != ctx->skf->len - 1)
-				emit(ARM_B(b_imm(prog->len, ctx)), ctx);
+			if (i != flen - 1)
+				emit(ARM_B(b_imm(flen, ctx)), ctx);
 			break;
 		case BPF_S_MISC_TAX:
 			/* X = A */
@@ -867,6 +867,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 	struct jit_ctx ctx;
 	unsigned tmp_idx;
 	unsigned alloc_size;
+	int flen = sk_bpf_flen(fp);
 
 	if (!bpf_jit_enable)
 		return;
@@ -875,7 +876,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 	ctx.skf		= fp;
 	ctx.ret0_fp_idx = -1;
 
-	ctx.offsets = kzalloc(4 * (ctx.skf->len + 1), GFP_KERNEL);
+	ctx.offsets = kzalloc(4 * (flen + 1), GFP_KERNEL);
 	if (ctx.offsets == NULL)
 		return;
 
@@ -922,7 +923,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 
 	if (bpf_jit_enable > 1)
 		/* there are 2 passes here */
-		bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
+		bpf_jit_dump(flen, alloc_size, 2, ctx.target);
 
 	fp->run_filter = (void *)ctx.target;
 out:
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 6491d72..a4d8db3 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -134,7 +134,7 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
 			      unsigned int *addrs)
 {
 	const struct sock_filter *filter = fp->insns;
-	int flen = fp->len;
+	int flen = sk_bpf_flen(fp);
 	u8 *func;
 	unsigned int true_cond;
 	int i;
@@ -581,7 +581,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 	unsigned int *addrs;
 	struct codegen_context cgctx;
 	int pass;
-	int flen = fp->len;
+	int flen = sk_bpf_flen(fp);
 
 	if (!bpf_jit_enable)
 		return;
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 23089df..54906d9 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -826,11 +826,11 @@ void bpf_jit_compile(struct sk_filter *fp)
 	unsigned long size, prg_len, lit_len;
 	struct bpf_jit jit, cjit;
 	unsigned int *addrs;
-	int pass, i;
+	int pass, i, flen = sk_bpf_flen(fp);
 
 	if (!bpf_jit_enable)
 		return;
-	addrs = kcalloc(fp->len, sizeof(*addrs), GFP_KERNEL);
+	addrs = kcalloc(flen, sizeof(*addrs), GFP_KERNEL);
 	if (addrs == NULL)
 		return;
 	memset(&jit, 0, sizeof(cjit));
@@ -842,9 +842,9 @@ void bpf_jit_compile(struct sk_filter *fp)
 
 		bpf_jit_prologue(&jit);
 		bpf_jit_noleaks(&jit, fp->insns);
-		for (i = 0; i < fp->len; i++) {
+		for (i = 0; i < flen; i++) {
 			if (bpf_jit_insn(&jit, fp->insns + i, addrs, i,
-					 i == fp->len - 1))
+					 i == len - 1))
 				goto out;
 		}
 		bpf_jit_epilogue(&jit);
@@ -870,7 +870,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 		cjit = jit;
 	}
 	if (bpf_jit_enable > 1) {
-		bpf_jit_dump(fp->len, jit.end - jit.start, pass, jit.start);
+		bpf_jit_dump(flen, jit.end - jit.start, pass, jit.start);
 		if (jit.start)
 			print_fn_code(jit.start, jit.mid - jit.start);
 	}
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index ee1cd30..15e6b00 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -359,7 +359,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 	unsigned int cleanup_addr, proglen, oldproglen = 0;
 	u32 temp[8], *prog, *func, seen = 0, pass;
 	const struct sock_filter *filter = fp->insns;
-	int i, flen = fp->len, pc_ret0 = -1;
+	int i, flen = sk_bpf_flen(fp), pc_ret0 = -1;
 	unsigned int *addrs;
 	void *image;
 
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index bfadd14..81bf69a 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -193,7 +193,7 @@ void bpf_jit_compile(struct sk_filter *fp)
 	unsigned int cleanup_addr; /* epilogue code offset */
 	unsigned int *addrs;
 	const struct sock_filter *filter = fp->insns;
-	int flen = fp->len;
+	int flen = sk_bpf_flen(fp);
 
 	if (!bpf_jit_enable)
 		return;
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 6c5d597..ab37714 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -22,10 +22,9 @@ struct compat_sock_fprog {
 struct sk_buff;
 struct sock;
 
-struct sk_filter
-{
+struct sk_filter {
 	atomic_t		refcnt;
-	unsigned int         	len;	/* Number of filter blocks */
+	unsigned int		size;	/* filter bytecode size in bytes */
 	struct rcu_head		rcu;
 	unsigned int		(*run_filter)(const struct sk_buff *skb,
 					      const struct sock_filter *filter);
@@ -35,10 +34,9 @@ struct sk_filter
 	};
 };
 
-static inline unsigned int sk_filter_size(unsigned int proglen)
+static inline unsigned int sk_bpf_flen(struct sk_filter *filter)
 {
-	return max(sizeof(struct sk_filter),
-		   offsetof(struct sk_filter, insns[proglen]));
+	return filter->size / sizeof(struct sock_filter);
 }
 
 extern int sk_filter(struct sock *sk, struct sk_buff *skb);
diff --git a/include/net/sock.h b/include/net/sock.h
index 5c3f7c3..7b9723c 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1633,14 +1633,14 @@ static inline void sk_filter_release(struct sk_filter *fp)
 
 static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
 {
-	atomic_sub(sk_filter_size(fp->len), &sk->sk_omem_alloc);
+	atomic_sub(fp->size, &sk->sk_omem_alloc);
 	sk_filter_release(fp);
 }
 
 static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
 {
 	atomic_inc(&fp->refcnt);
-	atomic_add(sk_filter_size(fp->len), &sk->sk_omem_alloc);
+	atomic_add(fp->size, &sk->sk_omem_alloc);
 }
 
 /*
diff --git a/net/core/filter.c b/net/core/filter.c
index 0f63e67..3ea0e7f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -647,7 +647,7 @@ static int __sk_prepare_filter(struct sk_filter *fp)
 
 	fp->run_filter = sk_run_filter;
 
-	err = sk_chk_filter(fp->insns, fp->len);
+	err = sk_chk_filter(fp->insns, sk_bpf_flen(fp));
 	if (err)
 		return err;
 
@@ -655,6 +655,12 @@ static int __sk_prepare_filter(struct sk_filter *fp)
 	return 0;
 }
 
+static unsigned int sk_filter_size(unsigned int proglen)
+{
+	return max(sizeof(struct sk_filter),
+		   offsetof(struct sk_filter, insns[proglen]));
+}
+
 /**
  *	sk_unattached_filter_create - create an unattached filter
  *	@fprog: the filter program
@@ -682,7 +688,7 @@ int sk_unattached_filter_create(struct sk_filter **pfp,
 	memcpy(fp->insns, fprog->filter, fsize);
 
 	atomic_set(&fp->refcnt, 1);
-	fp->len = fprog->len;
+	fp->size = fsize;
 
 	err = __sk_prepare_filter(fp);
 	if (err)
@@ -735,7 +741,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 	}
 
 	atomic_set(&fp->refcnt, 1);
-	fp->len = fprog->len;
+	fp->size = fsize;
 
 	err = __sk_prepare_filter(fp);
 	if (err) {
@@ -853,6 +859,7 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
 int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int len)
 {
 	struct sk_filter *filter;
+	unsigned int flen;
 	int i, ret;
 
 	lock_sock(sk);
@@ -861,15 +868,16 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int
 	ret = 0;
 	if (!filter)
 		goto out;
-	ret = filter->len;
+
+	ret = flen = sk_bpf_flen(filter);
 	if (!len)
 		goto out;
 	ret = -EINVAL;
-	if (len < filter->len)
+	if (len < flen)
 		goto out;
 
 	ret = -EFAULT;
-	for (i = 0; i < filter->len; i++) {
+	for (i = 0; i < flen; i++) {
 		struct sock_filter fb;
 
 		sk_decode_filter(&filter->insns[i], &fb);
@@ -877,7 +885,7 @@ int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int
 			goto out;
 	}
 
-	ret = filter->len;
+	ret = flen;
 out:
 	release_sock(sk);
 	return ret;
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index a0e9cf6..343bd58 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -65,7 +65,7 @@ int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
 	rcu_read_lock();
 
 	filter = rcu_dereference(sk->sk_filter);
-	len = filter ? filter->len * sizeof(struct sock_filter) : 0;
+	len = filter ? filter->size : 0;
 
 	attr = nla_reserve(skb, attrtype, len);
 	if (attr == NULL) {
@@ -77,7 +77,7 @@ int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
 		struct sock_filter *fb = (struct sock_filter *)nla_data(attr);
 		int i;
 
-		for (i = 0; i < filter->len; i++, fb++)
+		for (i = 0; i < sk_bpf_flen(filter); i++, fb++)
 			sk_decode_filter(&filter->insns[i], fb);
 	}
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ