/* Returns 0 if the the sandbox is enabled using * the time setter policy. */ int enable_setter_seccomp (void) { static const struct sock_filter insns[] = { /* Ensure the syscall arch convention is as expected. */ BPF_STMT (BPF_LD+BPF_W+BPF_ABS, offsetof (struct seccomp_data, arch)), BPF_JUMP (BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0), BPF_STMT (BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), /* Load the syscall number for checking. */ BPF_STMT (BPF_LD+BPF_W+BPF_ABS, offsetof (struct seccomp_data, nr)), /* Process ALLOWs as quickly as possible */ SC_ALLOW (read), SC_ALLOW (write), SC_ALLOW (pwritev), SC_ALLOW (settimeofday), SC_ALLOW (ioctl), /* TODO(wad) filter for fd and RTC_SET_TIME */ #ifdef __NR_time /* This is required for x86 systems */ SC_ALLOW (time), #endif SC_ALLOW (lseek), SC_ALLOW (close), SC_ALLOW (munmap), SC_ALLOW (exit_group), SC_ALLOW (exit), SC_DENY (open, EINVAL), SC_DENY (fcntl, EINVAL), SC_DENY (fstat, EINVAL), #ifdef __NR_mmap SC_DENY (mmap, EINVAL), #endif #ifdef __NR_mmap2 SC_DENY (mmap2, EINVAL), #endif #ifdef __NR_sendto SC_DENY (sendto, EINVAL), #endif #ifdef __NR_socket SC_DENY (socket, EINVAL), #endif #ifdef __NR_socketcall SC_DENY (socketcall, EINVAL), #endif BPF_STMT (BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), }; static const struct sock_fprog prog = { .len = (unsigned short) (sizeof (insns) /sizeof (insns[0])), .filter = (struct sock_filter *) insns, }; return (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)); }
/* * npfctl_bpf_icmp: code block to match ICMP type and/or code. * Note: suitable both for the ICMPv4 and ICMPv6. */ void npfctl_bpf_icmp(npf_bpf_t *ctx, int type, int code) { const u_int type_off = offsetof(struct icmp, icmp_type); const u_int code_off = offsetof(struct icmp, icmp_code); assert(offsetof(struct icmp6_hdr, icmp6_type) == type_off); assert(offsetof(struct icmp6_hdr, icmp6_code) == code_off); assert(type != -1 || code != -1); /* X <- IP header length */ fetch_l3(ctx, AF_UNSPEC, X_EQ_L4OFF); if (type != -1) { struct bpf_insn insns_type[] = { BPF_STMT(BPF_LD+BPF_B+BPF_IND, type_off), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, type, 0, JUMP_MAGIC), }; add_insns(ctx, insns_type, __arraycount(insns_type)); uint32_t mwords[] = { BM_ICMP_TYPE, 1, type }; done_block(ctx, mwords, sizeof(mwords)); } if (code != -1) { struct bpf_insn insns_code[] = { BPF_STMT(BPF_LD+BPF_B+BPF_IND, code_off), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, code, 0, JUMP_MAGIC), }; add_insns(ctx, insns_code, __arraycount(insns_code)); uint32_t mwords[] = { BM_ICMP_CODE, 1, code }; done_block(ctx, mwords, sizeof(mwords)); } }
/** * Create the berkeley packet filter for our ethertype * * Creates a BPF for our ether type. * * @param [in,out] ether The MetisGenericEther to modify * * @retval true success * @retval false failure * * Example: * @code * <#example#> * @endcode */ static bool _darwinEthernet_SetFilter(MetisGenericEther *ether) { struct bpf_program filterCode = { 0 }; // BPF instructions: // Load 12 to accumulator (offset of ethertype) // Jump Equal to netbyteorder_ethertype 0 instructions, otherwise 1 instruction // 0: return a length of -1 (meaning whole packet) // 1: return a length of 0 (meaning skip packet) struct bpf_insn instructions[] = { BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0801, 0, 1), BPF_STMT(BPF_RET + BPF_K, (u_int) - 1), BPF_STMT(BPF_RET + BPF_K, 0), }; // BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ether->ethertype, 0, 1), /* Set the filter */ filterCode.bf_len = sizeof(instructions) / sizeof(struct bpf_insn); filterCode.bf_insns = &instructions[0]; if (ioctl(ether->etherSocket, BIOCSETF, &filterCode) < 0) { return false; } return true; }
int filter_syscall(int syscall_nr, unsigned int flags) { struct sock_filter filter[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), }; struct sock_fprog bpf_prog = { .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), .filter = filter, }; if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flags, &bpf_prog) < 0) { pr_perror("seccomp failed"); return -1; } return 0; } void *wait_and_getpid(void *arg) { pthread_mutex_lock(&getpid_wait); pthread_mutex_unlock(&getpid_wait); pthread_mutex_destroy(&getpid_wait); /* we expect the tg to get killed by the seccomp filter that was * installed via TSYNC */ ptrace(PTRACE_TRACEME); pthread_exit((void *)1); }
/* * npfctl_bpf_tcpfl: code block to match TCP flags. */ void npfctl_bpf_tcpfl(npf_bpf_t *ctx, uint8_t tf, uint8_t tf_mask) { const u_int tcpfl_off = offsetof(struct tcphdr, th_flags); /* X <- IP header length */ fetch_l3(ctx, AF_UNSPEC, X_EQ_L4OFF); struct bpf_insn insns_tf[] = { /* A <- TCP flags */ BPF_STMT(BPF_LD+BPF_B+BPF_IND, tcpfl_off), }; add_insns(ctx, insns_tf, __arraycount(insns_tf)); if (tf_mask != tf) { /* A <- (A & mask) */ struct bpf_insn insns_mask[] = { BPF_STMT(BPF_ALU+BPF_AND+BPF_K, tf_mask), }; add_insns(ctx, insns_mask, __arraycount(insns_mask)); } struct bpf_insn insns_cmp[] = { /* A == expected-TCP-flags? */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, tf, 0, JUMP_MAGIC), }; add_insns(ctx, insns_cmp, __arraycount(insns_cmp)); uint32_t mwords[] = { BM_TCPFL, 2, tf, tf_mask}; done_block(ctx, mwords, sizeof(mwords)); }
/* Filter out messages from self that occur on listener socket, caused by our actions on the command socket */ static void netlink_install_filter (int sock, __u32 pid) { struct sock_filter filter[] = { /* 0: ldh [4] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)), /* 1: jeq 0x18 jt 3 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0), /* 2: jeq 0x19 jt 3 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3), /* 3: ldw [12] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)), /* 4: jeq XX jt 5 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1), /* 5: ret 0 (skip) */ BPF_STMT(BPF_RET|BPF_K, 0), /* 6: ret 0xffff (keep) */ BPF_STMT(BPF_RET|BPF_K, 0xffff), }; struct sock_fprog prog = { .len = sizeof(filter) / sizeof(filter[0]), .filter = filter, }; if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno)); } /* Exported interface function. This function simply calls netlink_socket (). */ void kernel_init (void) { unsigned long groups; groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR; #ifdef HAVE_IPV6 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR; #endif /* HAVE_IPV6 */ netlink_socket (&netlink, groups); netlink_socket (&netlink_cmd, 0); /* Register kernel socket. */ if (netlink.sock > 0) { /* Only want non-blocking on the netlink event socket */ if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0) zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name, safe_strerror (errno)); /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) netlink_recvbuf (&netlink, nl_rcvbufsize); netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid); thread_add_read (hm->master, kernel_read, NULL, netlink.sock); } }
static void install_filter(void) { struct sock_filter filter[] = { /* Load architecture */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Kill process if the architecture is not what we expect */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), /* Load system call number */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), /* Allow system calls other than open() */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 1, 0), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), /* Kill process on open() */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; if (seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog) == -1) errExit("seccomp"); /* On Linux 3.16 and earlier, we must instead use: if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) errExit("prctl-PR_SET_SECCOMP"); */ } int main(int argc, char **argv) { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) errExit("prctl"); install_filter(); if (open("/tmp/a", O_RDONLY) == -1) errExit("open"); printf("We shouldn't see this message\n"); exit(EXIT_SUCCESS); }
static void install_filter(void) { struct sock_filter filter[] = { /* Load system call number from 'seccomp_data' buffer into accumulator */ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)), /* Jump forward 1 instruction if system call number is not SYS_pipe */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_pipe, 0, 1), /* Error out with ESRCH */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (ESRCH & SECCOMP_RET_DATA)), /* Jump forward 1 instruction if system call number is not SYS_geteuid */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_geteuid, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Jump forward 1 instruction if system call number is not SYS_open */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_open, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Jump forward 1 instruction if system call number is not SYS_rrcall_init_buffers */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_rrcall_init_buffers, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Jump forward 1 instruction if system call number is not SYS_ioctl */ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SYS_ioctl, 0, 1), /* Trigger SIGSYS */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), /* Destination of system call number mismatch: allow other system calls */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; int ret; ret = syscall(RR_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog); if (ret == -1 && errno == ENOSYS) { ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); } test_assert(ret == 0); } static void* waiting_thread(void* p) { char buf; test_assert(1 == read(pipe_fds[0], &buf, 1)); /* Check this thread wasn't affected by the SET_SECCOMP */ test_assert(0 == prctl(PR_GET_SECCOMP)); return NULL; }
int main(int argc, char *argv[]) { pid_t pid; struct sock_filter filter[] = { /* Load architecture */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), /* Kill process if the architecture is not what we expect */ /* AUDIT_ARCH_X86_64 or AUDIT_ARCH_I386 */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), /* Load system call number */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, nr))), /* Allow system calls other than open() */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_open, 1, 0), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), /* Kill process on open() */ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog prog = { .len = (unsigned short) (sizeof(filter) / sizeof(filter[0])), .filter = filter, }; printf("\n*** Appling BPF filter ***\n\n"); if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) perror("prctl"); if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) perror("seccomp"); pid=fork(); if(pid==0) { printf("I am the child\n"); printf("The PID of child is %d\n",getpid()); printf("The PID of parent of child is %d\n\n",getppid()); } else { printf("I am the parent\n"); printf("The PID of parent is %d\n",getpid()); printf("The PID of parent of parent is %d\n\n",getppid()); } exit(EXIT_SUCCESS); }
static int _open_socket(const char *device) { int etherSocket; etherSocket = _open_bpf_device(); if (etherSocket == -1) { perror("bpf"); return -1; } // Attach the requested interface struct ifreq if_idx = { {0} }; strncpy(if_idx.ifr_name, device, strlen(device) + 1); if (ioctl(etherSocket, BIOCSETIF, &if_idx)) { perror("BIOCSETIF"); return -1; } // Set immediate read on packet reception uint32_t on = 1; if (ioctl(etherSocket, BIOCIMMEDIATE, &on)) { perror("BIOCIMMEDIATE"); return -1; } // Setup the BPF filter for CCNX_ETHERTYPE struct bpf_program filterCode = { 0 }; // BPF instructions: // Load 12 to accumulator (offset of ethertype) // Jump Equal to netbyteorder_ethertype 0 instructions, otherwise 1 instruction // 0: return a length of -1 (meaning whole packet) // 1: return a length of 0 (meaning skip packet) struct bpf_insn instructions[] = { BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, CCNX_ETHERTYPE,0, 1), BPF_STMT(BPF_RET + BPF_K, (u_int) - 1), BPF_STMT(BPF_RET + BPF_K, 0), }; // Install the filter filterCode.bf_len = sizeof(instructions) / sizeof(struct bpf_insn); filterCode.bf_insns = &instructions[0]; if (ioctl(etherSocket, BIOCSETF, &filterCode) < 0) { perror("BIOCSETF"); return -1; } return etherSocket; }
/* * npfctl_bpf_table: code block to match source/destination IP address * against NPF table specified by ID. */ void npfctl_bpf_table(npf_bpf_t *ctx, u_int opts, u_int tid) { const bool src = (opts & MATCH_SRC) != 0; struct bpf_insn insns_table[] = { BPF_STMT(BPF_LD+BPF_IMM, (src ? SRC_FLAG_BIT : 0) | tid), BPF_STMT(BPF_MISC+BPF_COP, NPF_COP_TABLE), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, JUMP_MAGIC, 0), }; add_insns(ctx, insns_table, __arraycount(insns_table)); uint32_t mwords[] = { src ? BM_SRC_TABLE: BM_DST_TABLE, 1, tid }; done_block(ctx, mwords, sizeof(mwords)); }
static int load_arp_bpflet(int fd) { static struct sock_filter insns[] = { BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ARPOP_RREQUEST, 0, 1), BPF_STMT(BPF_RET|BPF_K, 1024), BPF_STMT(BPF_RET|BPF_K, 0), }; static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns }; return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); }
int bpf_arp_filter(int fd, int type_offset, int type, int pkt_size) { struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, type_offset), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, type, 0, 1), BPF_STMT(BPF_RET+BPF_K, pkt_size), BPF_STMT(BPF_RET+BPF_K, 0), }; struct bpf_program prog; prog.bf_len = sizeof(insns) / sizeof(struct bpf_insn); prog.bf_insns = insns; return ioctl(fd, BIOCSETF, &prog); }
void npfctl_bpf_endgroup(npf_bpf_t *ctx) { struct bpf_program *bp = &ctx->prog; const size_t curoff = bp->bf_len; /* If there are no blocks or only one - nothing to do. */ if ((ctx->nblocks - ctx->gblock) <= 1) { ctx->goff = ctx->gblock = 0; return; } /* * Append a failure return as a fall-through i.e. if there is * no match within the group. */ struct bpf_insn insns_ret[] = { BPF_STMT(BPF_RET+BPF_K, NPF_BPF_FAILURE), }; add_insns(ctx, insns_ret, __arraycount(insns_ret)); /* * Adjust jump offsets: on match - jump outside the group i.e. * to the current offset. Otherwise, jump to the next instruction * which would lead to the fall-through code above if none matches. */ fixup_jumps(ctx, ctx->goff, curoff, true); ctx->goff = ctx->gblock = 0; }
ATF_TC_BODY(bpfjit_extmem_side_effect, tc) { static struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A <- P[0] */ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2 */ BPF_STMT(BPF_ST, 1), /* M[1] <- A */ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */ BPF_STMT(BPF_STX, 2), /* M[2] <- X */ BPF_STMT(BPF_ST, 3), /* M[3] <- A */ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */ BPF_STMT(BPF_RET+BPF_A, 0) /* ret A */ }; bpfjit_func_t code; uint8_t pkt[1] = { 1 }; uint32_t mem[ctx.extwords]; /* Pre-inited words. */ mem[0] = 0; mem[3] = 7; mem[1] = mem[2] = 0xdeadbeef; bpf_args_t args = { .pkt = pkt, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, }; size_t insn_count = sizeof(insns) / sizeof(insns[0]); RZ(rump_init()); rump_schedule(); code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); rump_unschedule(); ATF_REQUIRE(code != NULL); ATF_CHECK(code(&ctx, &args) == 0); rump_schedule(); rumpns_bpfjit_free_code(code); rump_unschedule(); ATF_CHECK(mem[0] == 0); ATF_CHECK(mem[1] == 1); ATF_CHECK(mem[2] == 2); ATF_CHECK(mem[3] == 3); } ATF_TC(bpfjit_extmem_invalid_store); ATF_TC_HEAD(bpfjit_extmem_invalid_store, tc) { atf_tc_set_md_var(tc, "descr", "Test that out-of-range store " "fails validation"); }
/* * npfctl_bpf_tcpfl: code block to match TCP flags. */ void npfctl_bpf_tcpfl(npf_bpf_t *ctx, uint8_t tf, uint8_t tf_mask, bool checktcp) { const u_int tcpfl_off = offsetof(struct tcphdr, th_flags); const bool usingmask = tf_mask != tf; /* X <- IP header length */ fetch_l3(ctx, AF_UNSPEC, X_EQ_L4OFF); if (checktcp) { const u_int jf = usingmask ? 3 : 2; assert(ctx->ingroup == false); /* A <- L4 protocol; A == TCP? If not, jump out. */ struct bpf_insn insns_tcp[] = { BPF_STMT(BPF_LD+BPF_W+BPF_MEM, BPF_MW_L4PROTO), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, jf), }; add_insns(ctx, insns_tcp, __arraycount(insns_tcp)); } else { assert(ctx->flags & CHECKED_L4); } struct bpf_insn insns_tf[] = { /* A <- TCP flags */ BPF_STMT(BPF_LD+BPF_B+BPF_IND, tcpfl_off), }; add_insns(ctx, insns_tf, __arraycount(insns_tf)); if (usingmask) { /* A <- (A & mask) */ struct bpf_insn insns_mask[] = { BPF_STMT(BPF_ALU+BPF_AND+BPF_K, tf_mask), }; add_insns(ctx, insns_mask, __arraycount(insns_mask)); } struct bpf_insn insns_cmp[] = { /* A == expected-TCP-flags? */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, tf, 0, JUMP_MAGIC), }; add_insns(ctx, insns_cmp, __arraycount(insns_cmp)); if (!checktcp) { uint32_t mwords[] = { BM_TCPFL, 2, tf, tf_mask}; done_block(ctx, mwords, sizeof(mwords)); } }
ATF_TC_BODY(bpfjit_extmem_invalid_store, tc) { static struct bpf_insn insns[] = { BPF_STMT(BPF_ST, 4), BPF_STMT(BPF_RET+BPF_A, 0) }; bpfjit_func_t code; size_t insn_count = sizeof(insns) / sizeof(insns[0]); RZ(rump_init()); rump_schedule(); code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); rump_unschedule(); ATF_CHECK(code == NULL); }
struct bpf_program * npfctl_bpf_complete(npf_bpf_t *ctx) { struct bpf_program *bp = &ctx->prog; const u_int retoff = bp->bf_len; /* Add the return fragment (success and failure paths). */ struct bpf_insn insns_ret[] = { BPF_STMT(BPF_RET+BPF_K, NPF_BPF_SUCCESS), BPF_STMT(BPF_RET+BPF_K, NPF_BPF_FAILURE), }; add_insns(ctx, insns_ret, __arraycount(insns_ret)); /* Fixup all jumps to the main failure path. */ fixup_jumps(ctx, 0, retoff, false); return &ctx->prog; }
ATF_TC_BODY(bpfjit_extmem_load_preinited, tc) { static struct bpf_insn insns[] = { BPF_STMT(BPF_LD+BPF_MEM, 3), BPF_STMT(BPF_RET+BPF_A, 0) }; bpfjit_func_t code; uint8_t pkt[1] = { 0 }; uint32_t mem[ctx.extwords]; /* Pre-inited words. */ mem[0] = 0; mem[3] = 3; bpf_args_t args = { .pkt = pkt, .buflen = sizeof(pkt), .wirelen = sizeof(pkt), .mem = mem, }; size_t insn_count = sizeof(insns) / sizeof(insns[0]); RZ(rump_init()); rump_schedule(); code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); rump_unschedule(); ATF_REQUIRE(code != NULL); ATF_CHECK(code(&ctx, &args) == 3); rump_schedule(); rumpns_bpfjit_free_code(code); rump_unschedule(); } ATF_TC(bpfjit_extmem_invalid_load); ATF_TC_HEAD(bpfjit_extmem_invalid_load, tc) { atf_tc_set_md_var(tc, "descr", "Test that out-of-range load " "fails validation"); }
static int setup_seccomp_filter(void) { struct sock_filter filter[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), /* Allow all syscalls except ptrace */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ptrace, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), }; struct sock_fprog bpf_prog = { .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), .filter = filter, }; if (sys_prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (long) &bpf_prog, 0, 0) < 0) return -1; return 0; } static int check_ptrace_dump_seccomp_filters(void) { pid_t pid; int ret = 0, len; if (opts.check_ms_kernel) { pr_warn("Skipping PTRACE_SECCOMP_GET_FILTER check"); return 0; } pid = fork_and_ptrace_attach(setup_seccomp_filter); if (pid < 0) return -1; len = ptrace(PTRACE_SECCOMP_GET_FILTER, pid, 0, NULL); if (len < 0) { ret = -1; pr_perror("Dumping seccomp filters not supported"); } kill(pid, SIGKILL); return ret; }
/********************************************************************** *%FUNCTION: initFilter *%ARGUMENTS: * fd -- file descriptor of BSD device * type -- Ethernet frame type (0 for watch mode) * hwaddr -- buffer with ehthernet address *%RETURNS: * Nothing *%DESCRIPTION: * Initializes the packet filter rules. ***********************************************************************/ void initFilter(int fd, UINT16_t type, unsigned char *hwaddr) { /* Packet Filter Instructions: * Note that the ethernet type names come from "pppoe.h" and are * used here to maintain consistency with the rest of this file. */ static struct bpf_insn bpfRun[] = { /* run PPPoE */ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), /* ethernet type */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */ #define PPPOE_BCAST_CMPW 4 /* offset of word compare */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */ #define PPPOE_BCAST_CMPH 6 /* offset of 1/2 word compare */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* first word of dest. addr */ #define PPPOE_FILTER_CMPW 8 /* offset of word compare */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* next 1/2 word of dest. */ #define PPPOE_FILTER_CMPH 10 /* offset of 1/rd compare */ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1), BPF_STMT(BPF_RET+BPF_K, (u_int) -1), /* keep packet */ BPF_STMT(BPF_RET+BPF_K, 0), /* drop packet */ }; /* Fix the potentially varying parts */ bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K; bpfRun[1].jt = 5; bpfRun[1].jf = 0; bpfRun[1].k = Eth_PPPOE_Session; bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K; bpfRun[2].jt = 0; bpfRun[2].jf = 9; bpfRun[2].k = Eth_PPPOE_Discovery; { struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])]; struct bpf_program bpfProgram; memcpy(bpfInsn, bpfRun, sizeof(bpfRun)); bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) | (0xff << 8) | 0xff); bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff); bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) | (hwaddr[2] << 8) | hwaddr[3]); bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]); bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0])); bpfProgram.bf_insns = &bpfInsn[0]; /* Apply the filter */ if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) { fatalSys("ioctl(BIOCSETF)"); } } }
static int install_filter(int nr, int arch, int error) { struct sock_filter filter[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, arch, 0, 3), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, nr))), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(error & SECCOMP_RET_DATA)), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter)/sizeof(filter[0])), .filter = filter, }; if (prctl(PR_SET_SECCOMP, 2, &prog)) { perror("prctl"); return 1; } return 0; } int main(int argc, char **argv) { if (argc < 5) { fprintf(stderr, "Usage:\n" "dropper <syscall_nr> <arch> <errno> <prog> [<args>]\n" "Hint: AUDIT_ARCH_I386: 0x%X\n" " AUDIT_ARCH_X86_64: 0x%X\n" "\n", AUDIT_ARCH_I386, AUDIT_ARCH_X86_64); return 1; } if (install_filter(strtol(argv[1], NULL, 0), strtol(argv[2], NULL, 0), strtol(argv[3], NULL, 0))) return 1; execv(argv[4], &argv[4]); printf("Failed to execv\n"); return 255; }
int bpf_filter_receive_none(int fd) { struct bpf_insn insns[] = { BPF_STMT(BPF_RET+BPF_K, 0), }; struct bpf_program prog; prog.bf_len = sizeof(insns) / sizeof(struct bpf_insn); prog.bf_insns = insns; return ioctl(fd, BIOCSETF, &prog); }
int qrpc_set_filter(const int sock) { struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETH_ALEN << 1), /* read packet type id */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, QRPC_RAW_SOCK_PROT, 0, 1), /* if qtn packet */ BPF_STMT(BPF_RET + BPF_K, ETH_FRAME_LEN), /* accept packet */ BPF_STMT(BPF_RET + BPF_K, 0) /* else ignore packet */ }; struct sock_fprog fp; fp.filter = filter; fp.len = ARRAY_SIZE(filter); if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &fp, sizeof(fp)) < 0) { printf("Cannot set rpc packet filter\n"); return -1; } return 0; }
int lldp_network_bind_raw_socket(int ifindex) { typedef struct LLDPFrame { struct ethhdr hdr; uint8_t tlvs[0]; } LLDPFrame; struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_proto)), /* A <- protocol */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */ }; struct sock_fprog fprog = { .len = ELEMENTSOF(filter), .filter = filter }; _cleanup_close_ int s = -1; union sockaddr_union saddrll = { .ll.sll_family = AF_PACKET, .ll.sll_ifindex = ifindex, }; int r; assert(ifindex > 0); s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (s < 0) return -errno; r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); if (r < 0) return -errno; r = bind(s, &saddrll.sa, sizeof(saddrll.ll)); if (r < 0) return -errno; r = s; s = -1; return r; }
void initFilter(int fd, UINT16_t type, unsigned char *hwaddr) { static struct bpf_insn bpfRun[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), #define PPPOE_BCAST_CMPW 4 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), #define PPPOE_BCAST_CMPH 6 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), #define PPPOE_FILTER_CMPW 8 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), #define PPPOE_FILTER_CMPH 10 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1), BPF_STMT(BPF_RET+BPF_K, (u_int) -1), BPF_STMT(BPF_RET+BPF_K, 0), }; bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K; bpfRun[1].jt = 5; bpfRun[1].jf = 0; bpfRun[1].k = Eth_PPPOE_Session; bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K; bpfRun[2].jt = 0; bpfRun[2].jf = 9; bpfRun[2].k = Eth_PPPOE_Discovery; { struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])]; struct bpf_program bpfProgram; memcpy(bpfInsn, bpfRun, sizeof(bpfRun)); bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) | (0xff << 8) | 0xff); bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff); bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) | (hwaddr[2] << 8) | hwaddr[3]); bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]); bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0])); bpfProgram.bf_insns = &bpfInsn[0]; if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) { fatalSys("ioctl(BIOCSETF)"); } } }
int arp_network_bind_raw_socket(int ifindex, union sockaddr_union *link) { static const struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 0, 1), /* protocol == request ? */ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), /* protocol == reply ? */ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ }; struct sock_fprog fprog = { .len = ELEMENTSOF(filter), .filter = (struct sock_filter*) filter }; _cleanup_close_ int s = -1; int r; assert(ifindex > 0); assert(link); s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (s < 0) return -errno; r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); if (r < 0) return -errno; link->ll.sll_family = AF_PACKET; link->ll.sll_protocol = htons(ETH_P_ARP); link->ll.sll_ifindex = ifindex; link->ll.sll_halen = ETH_ALEN; memset(link->ll.sll_addr, 0xff, ETH_ALEN); r = bind(s, &link->sa, sizeof(link->ll)); if (r < 0) return -errno; r = s; s = -1; return r; }
static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) { if (hardwareAddressType != ARPHRD_ETHER) { jniThrowExceptionFmt(env, "java/net/SocketException", "attachRaFilter only supports ARPHRD_ETHER"); return; } uint32_t ipv6_offset = sizeof(ether_header); uint32_t ipv6_next_header_offset = ipv6_offset + offsetof(ip6_hdr, ip6_nxt); uint32_t icmp6_offset = ipv6_offset + sizeof(ip6_hdr); uint32_t icmp6_type_offset = icmp6_offset + offsetof(icmp6_hdr, icmp6_type); struct sock_filter filter_code[] = { // Check IPv6 Next Header is ICMPv6. BPF_STMT(BPF_LD | BPF_B | BPF_ABS, ipv6_next_header_offset), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3), // Check ICMPv6 type is Router Advertisement. BPF_STMT(BPF_LD | BPF_B | BPF_ABS, icmp6_type_offset), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1), // Accept or reject. BPF_STMT(BPF_RET | BPF_K, 0xffff), BPF_STMT(BPF_RET | BPF_K, 0) }; struct sock_fprog filter = { sizeof(filter_code) / sizeof(filter_code[0]), filter_code, }; int fd = jniGetFDFromFileDescriptor(env, javaFd); if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { jniThrowExceptionFmt(env, "java/net/SocketException", "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); } }
static void install_filter(void) { struct sock_filter filter[] = { /* Allow all system calls */ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) }; struct sock_fprog prog = { .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), .filter = filter, }; int ret; ret = syscall(RR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog); if (ret == -1 && errno == ENOSYS) { atomic_puts("seccomp syscall not supported"); atomic_puts("EXIT-SUCCESS"); exit(0); } test_assert(ret == 0); } static void* waiting_thread(__attribute__((unused)) void* p) { char buf; test_assert(1 == read(pipe_fds[0], &buf, 1)); /* Check this thread *was* affected by SECCOMP_FILTER_FLAG_TSYNC */ test_assert(2 == prctl(PR_GET_SECCOMP)); return NULL; } int main(void) { pthread_t w_thread; test_assert(0 == pipe(pipe_fds)); pthread_create(&w_thread, NULL, waiting_thread, NULL); /* Prepare syscallbuf patch path. Need to do this after pthread_create since when we have more than one thread we take a different syscall path... */ test_assert(0 == prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); install_filter(); test_assert(2 == prctl(PR_GET_SECCOMP)); test_assert(1 == write(pipe_fds[1], "c", 1)); pthread_join(w_thread, NULL); atomic_puts("EXIT-SUCCESS"); return 0; }
int main(void) { const size_t arch_offset = offsetof(struct seccomp_data, arch); const size_t syscall_offset = offsetof(struct seccomp_data, nr); struct sock_fprog program; #define ARCH_NR AUDIT_ARCH_X86_64 struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_ABS, arch_offset), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, AUDIT_ARCH_X86_64, 0, 1), BPF_STMT(BPF_LD + BPF_W + BPF_ABS, syscall_offset), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE) }; program.filter = filter; program.len = sizeof(filter) / sizeof(struct sock_filter); (void) prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); (void) prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program); return 1; }