[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



BPF filters are used in networking and in application sand-boxing
and even have a arch-dependant JIT compiler in the kernel, so add
a more detailed semi-random BPF generator.

Signed-off-by: Daniel Borkmann <dborkman@xxxxxxxxxx>
---
 Compile-tested only!

 include/net.h         |   3 +
 net/bpf.c             | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++
 syscalls/setsockopt.c |   2 +
 3 files changed, 210 insertions(+)
 create mode 100644 net/bpf.c

diff --git a/include/net.h b/include/net.h
index e14430c..256533c 100644
--- a/include/net.h
+++ b/include/net.h
@@ -35,6 +35,9 @@ void gen_pppox(unsigned long *addr, unsigned long *addrlen);
 /* unix */
 void gen_unixsock(unsigned long *addr, unsigned long *addrlen);
 
+/* bpf */
+void gen_bpf(unsigned long *addr, unsigned long *addrlen);
+
 /* caif */
 void gen_caif(unsigned long *addr, unsigned long *addrlen);
 
diff --git a/net/bpf.c b/net/bpf.c
new file mode 100644
index 0000000..c628ac0
--- /dev/null
+++ b/net/bpf.c
@@ -0,0 +1,205 @@
+#include <linux/filter.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "trinity.h"
+
+/**
+ * BPF filters are used in networking such as in pf_packet, but also
+ * in seccomp for application sand-boxing. Additionally, with arch
+ * specific BPF JIT compilers, this might be good to fuzz for errors.
+ *    -- Daniel Borkmann, <borkmann@xxxxxxxxxx>
+ */
+
+/* Both here likely defined in linux/filter.h already */
+#ifndef SKF_AD_OFF
+# define SKF_AD_OFF	(-0x1000)
+#endif
+
+#ifndef SKF_AD_MAX
+# define SKF_AD_MAX	56
+#endif
+
+#define BPF_CLASS(code) ((code) & 0x07)
+#define	BPF_LD		0x00
+#define	BPF_LDX		0x01
+#define	BPF_ST		0x02
+#define	BPF_STX		0x03
+#define	BPF_ALU		0x04
+#define	BPF_JMP		0x05
+#define	BPF_RET		0x06
+#define	BPF_MISC	0x07
+
+static const uint16_t bpf_class_vars[] = {
+	BPF_LD, BPF_LDX, BPF_ST, BPF_STX, BPF_ALU, BPF_JMP, BPF_RET, BPF_MISC,
+};
+
+#define BPF_SIZE(code)	((code) & 0x18)
+#define	BPF_W		0x00
+#define	BPF_H		0x08
+#define	BPF_B		0x10
+
+static const uint16_t bpf_size_vars[] = {
+	BPF_W, BPF_H, BPF_B,
+};
+
+#define BPF_MODE(code)	((code) & 0xe0)
+#define	BPF_IMM 	0x00
+#define	BPF_ABS		0x20
+#define	BPF_IND		0x40
+#define	BPF_MEM		0x60
+#define	BPF_LEN		0x80
+#define	BPF_MSH		0xa0
+
+static const uint16_t bpf_mode_vars[] = {
+	BPF_IMM, BPF_ABS, BPF_IND, BPF_MEM, BPF_LEN, BPF_MSH,
+};
+
+#define BPF_OP(code)	((code) & 0xf0)
+#define	BPF_ADD		0x00
+#define	BPF_SUB		0x10
+#define	BPF_MUL		0x20
+#define	BPF_DIV		0x30
+#define	BPF_OR		0x40
+#define	BPF_AND		0x50
+#define	BPF_LSH		0x60
+#define	BPF_RSH		0x70
+#define	BPF_NEG		0x80
+#define BPF_MOD		0x90
+#define	BPF_XOR		0xa0
+
+static const uint16_t bpf_alu_op_vars[] = {
+	BPF_ADD, BPF_SUB, BPF_MUL, BPF_DIV, BPF_OR, BPF_AND, BPF_LSH, BPF_RSH,
+	BPF_NEG, BPF_MOD, BPF_XOR,
+};
+
+#define	BPF_JA		0x00
+#define	BPF_JEQ		0x10
+#define	BPF_JGT		0x20
+#define	BPF_JGE		0x30
+#define	BPF_JSET	0x40
+
+static const uint16_t bpf_jmp_op_vars[] = {
+	BPF_JA, BPF_JEQ, BPF_JGT, BPF_JGE, BPF_JSET,
+};
+
+#define BPF_SRC(code)	((code) & 0x08)
+#define	BPF_K		0x00
+#define	BPF_X		0x08
+
+static const uint16_t bpf_src_vars[] = {
+	BPF_K, BPF_X,
+};
+
+#define BPF_RVAL(code)	((code) & 0x18)
+#define	BPF_A		0x10
+
+static const uint16_t bpf_ret_vars[] = {
+	BPF_A, BPF_K, BPF_X,
+};
+
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define	BPF_TAX		0x00
+#define	BPF_TXA		0x80
+
+static const uint16_t bpf_misc_vars[] = {
+	BPF_TAX, BPF_TXA,
+};
+
+#define bpf_rand(type) \
+	(bpf_##type##_vars[rand() % ARRAY_SIZE(bpf_##type##_vars)])
+
+static uint16_t gen_bpf_code(void)
+{
+	uint16_t ret = bpf_rand(class);
+
+	switch (ret) {
+	case BPF_LD:
+	case BPF_LDX:
+	case BPF_ST:
+	case BPF_STX:
+		ret |= bpf_rand(size) | bpf_rand(mode) | bpf_rand(src);
+		break;
+	case BPF_ALU:
+		ret |= bpf_rand(alu_op) | bpf_rand(src);
+		break;
+	case BPF_JMP:
+		ret |= bpf_rand(jmp_op) | bpf_rand(src);
+		break;
+	case BPF_RET:
+		ret |= bpf_rand(ret);
+		break;
+	case BPF_MISC:
+		ret |= bpf_rand(misc);
+		break;
+	default:
+		ret = (uint16_t) rand();
+		break;
+	}
+
+	/* Also give it a chance to fuzz some crap into it */
+	if (rand() % 10 == 0)
+		ret |= (uint16_t) rand();
+
+	return ret;
+}
+
+void gen_bpf(unsigned long *addr, unsigned long *addrlen)
+{
+	int i;
+	struct sock_fprog *bpf = (void *) addr;
+
+	if (addrlen != NULL) {
+		bpf = malloc(sizeof(struct sock_fprog));
+		if (bpf == NULL)
+			return;
+	}
+
+	bpf->len = rand() % BPF_MAXINSNS;
+
+	bpf->filter = malloc(bpf->len * sizeof(struct sock_filter));
+	if (bpf->filter == NULL) {
+		if (addrlen != NULL)
+			free(bpf);
+		return;
+	}
+
+	for (i = 0; i < bpf->len; i++) {
+		memset(&bpf->filter[i], 0, sizeof(bpf->filter[i]));
+
+		bpf->filter[i].code = gen_bpf_code();
+
+		/* Fill out jump offsets if jmp instruction */
+		if (BPF_CLASS(bpf->filter[i].code) == BPF_JMP) {
+			bpf->filter[i].jt = (uint8_t) rand();
+			bpf->filter[i].jf = (uint8_t) rand();
+		}
+
+		/* Also give it a chance if not BPF_JMP */
+		if (rand() % 10 == 0)
+			bpf->filter[i].jt |= (uint8_t) rand();
+		if (rand() % 10 == 0)
+			bpf->filter[i].jf |= (uint8_t) rand();
+
+		/* Not always fill out k */
+		bpf->filter[i].k = rand() % 2 == 0 ? 0 : (uint32_t) rand();
+
+		/* Also try to jump into BPF extensions by chance */
+		if (BPF_CLASS(bpf->filter[i].code) == BPF_LD ||
+		    BPF_CLASS(bpf->filter[i].code) == BPF_LDX) {
+			if (bpf->filter[i].k > 65000 &&
+			    bpf->filter[i].k < (uint32_t) SKF_AD_OFF) {
+				if (rand() % 2 == 0) {
+					bpf->filter[i].k = (uint32_t) (SKF_AD_OFF +
+							   rand() % SKF_AD_MAX);
+				}
+			}
+		}
+	}
+
+	if (addrlen != NULL) {
+		*addr = (unsigned long) bpf;
+		*addrlen = sizeof(struct sock_fprog);
+	}
+}
diff --git a/syscalls/setsockopt.c b/syscalls/setsockopt.c
index 1c18847..43ffb05 100644
--- a/syscalls/setsockopt.c
+++ b/syscalls/setsockopt.c
@@ -9,6 +9,7 @@
 #include "compat.h"
 #include "maps.h"
 #include "shm.h"
+#include "net.h"
 #include "config.h"
 #include "syscalls/setsockopt.h"
 
@@ -84,6 +85,7 @@ void sanitise_setsockopt(int childno)
 			shm->a5[childno] = sizeof(struct timeval);
 			break;
 		case SO_ATTACH_FILTER:
+			gen_bpf((unsigned long *) page_rand, NULL);
 			shm->a5[childno] = sizeof(struct sock_fprog);
 			break;
 		default:
-- 
1.7.11.7

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




[Index of Archives]     [Linux SCSI]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux