On Wed, Oct 7, 2015 at 10:23 PM, Alexei Starovoitov <ast@xxxxxxxxxxxx> wrote: > Add new tests samples/bpf/test_verifier: > > unpriv: return pointer > checks that pointer cannot be returned from the eBPF program > > unpriv: add const to pointer > unpriv: add pointer to pointer > unpriv: neg pointer > checks that pointer arithmetic is disallowed > > unpriv: cmp pointer with const > unpriv: cmp pointer with pointer > checks that comparison of pointers is disallowed > Only one case allowed 'void *value = bpf_map_lookup_elem(..); if (value == 0) ...' > > unpriv: check that printk is disallowed > since bpf_trace_printk is not available to unprivileged > > unpriv: pass pointer to helper function > checks that pointers cannot be passed to functions that expect integers > If function expects a pointer the verifier allows only that type of pointer. > Like 1st argument of bpf_map_lookup_elem() must be pointer to map. > (applies to non-root as well) > > unpriv: indirectly pass pointer on stack to helper function > checks that pointer stored into stack cannot be used as part of key > passed into bpf_map_lookup_elem() > > unpriv: mangle pointer on stack 1 > unpriv: mangle pointer on stack 2 > checks that writing into stack slot that already contains a pointer > is disallowed > > unpriv: read pointer from stack in small chunks > checks that < 8 byte read from stack slot that contains a pointer is > disallowed > > unpriv: write pointer into ctx > checks that storing pointers into skb->fields is disallowed > > unpriv: write pointer into map elem value > checks that storing pointers into element values is disallowed > For example: > int bpf_prog(struct __sk_buff *skb) > { > u32 key = 0; > u64 *value = bpf_map_lookup_elem(&map, &key); > if (value) > *value = (u64) skb; > } > will be rejected. > > unpriv: partial copy of pointer > checks that doing 32-bit register mov from register containing > a pointer is disallowed > > unpriv: pass pointer to tail_call > checks that passing pointer as an index into bpf_tail_call > is disallowed > > unpriv: cmp map pointer with zero > checks that comparing map pointer with constant is disallowed > > unpriv: write into frame pointer > checks that frame pointer is read-only (applies to root too) > > unpriv: cmp of frame pointer > checks that R10 cannot be using in comparison > > unpriv: cmp of stack pointer > checks that Rx = R10 - imm is ok, but comparing Rx is not > > unpriv: obfuscate stack pointer > checks that Rx = R10 - imm is ok, but Rx -= imm is not > > Signed-off-by: Alexei Starovoitov <ast@xxxxxxxxxxxx> > --- > v1-v2: > - split tests into separate patch > - add tail_call and other tests and explain tests in commit log > --- > samples/bpf/libbpf.h | 8 + > samples/bpf/test_verifier.c | 357 +++++++++++++++++++++++++++++++++++++++++-- Instead of living in samples/ could these be moved and hooked up to tools/testing/selftests/ instead? -Kees > 2 files changed, 355 insertions(+), 10 deletions(-) > > diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h > index 7235e292a03b..b7f63c70b4a2 100644 > --- a/samples/bpf/libbpf.h > +++ b/samples/bpf/libbpf.h > @@ -64,6 +64,14 @@ extern char bpf_log_buf[LOG_BUF_SIZE]; > .off = 0, \ > .imm = 0 }) > > +#define BPF_MOV32_REG(DST, SRC) \ > + ((struct bpf_insn) { \ > + .code = BPF_ALU | BPF_MOV | BPF_X, \ > + .dst_reg = DST, \ > + .src_reg = SRC, \ > + .off = 0, \ > + .imm = 0 }) > + > /* Short form of mov, dst_reg = imm32 */ > > #define BPF_MOV64_IMM(DST, IMM) \ > diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c > index ee0f110c9c54..563c507c0a09 100644 > --- a/samples/bpf/test_verifier.c > +++ b/samples/bpf/test_verifier.c > @@ -15,20 +15,27 @@ > #include <string.h> > #include <linux/filter.h> > #include <stddef.h> > +#include <stdbool.h> > +#include <sys/resource.h> > #include "libbpf.h" > > #define MAX_INSNS 512 > #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) > > +#define MAX_FIXUPS 8 > + > struct bpf_test { > const char *descr; > struct bpf_insn insns[MAX_INSNS]; > - int fixup[32]; > + int fixup[MAX_FIXUPS]; > + int prog_array_fixup[MAX_FIXUPS]; > const char *errstr; > + const char *errstr_unpriv; > enum { > + UNDEF, > ACCEPT, > REJECT > - } result; > + } result, result_unpriv; > enum bpf_prog_type prog_type; > }; > > @@ -96,6 +103,7 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .errstr = "invalid BPF_LD_IMM insn", > + .errstr_unpriv = "R1 pointer comparison", > .result = REJECT, > }, > { > @@ -109,6 +117,7 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .errstr = "invalid BPF_LD_IMM insn", > + .errstr_unpriv = "R1 pointer comparison", > .result = REJECT, > }, > { > @@ -219,6 +228,7 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .errstr = "R0 !read_ok", > + .errstr_unpriv = "R1 pointer comparison", > .result = REJECT, > }, > { > @@ -294,7 +304,9 @@ static struct bpf_test tests[] = { > BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "R0 leaks addr", > .result = ACCEPT, > + .result_unpriv = REJECT, > }, > { > "check corrupted spill/fill", > @@ -310,6 +322,7 @@ static struct bpf_test tests[] = { > > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "attempt to corrupt spilled", > .errstr = "corrupted spill", > .result = REJECT, > }, > @@ -473,6 +486,7 @@ static struct bpf_test tests[] = { > }, > .fixup = {3}, > .errstr = "R0 invalid mem access", > + .errstr_unpriv = "R0 leaks addr", > .result = REJECT, > }, > { > @@ -495,6 +509,8 @@ static struct bpf_test tests[] = { > BPF_MOV64_IMM(BPF_REG_0, 0), > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "R1 pointer comparison", > + .result_unpriv = REJECT, > .result = ACCEPT, > }, > { > @@ -521,6 +537,8 @@ static struct bpf_test tests[] = { > BPF_MOV64_IMM(BPF_REG_0, 0), > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "R1 pointer comparison", > + .result_unpriv = REJECT, > .result = ACCEPT, > }, > { > @@ -555,6 +573,8 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .fixup = {24}, > + .errstr_unpriv = "R1 pointer comparison", > + .result_unpriv = REJECT, > .result = ACCEPT, > }, > { > @@ -603,6 +623,8 @@ static struct bpf_test tests[] = { > BPF_MOV64_IMM(BPF_REG_0, 0), > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "R1 pointer comparison", > + .result_unpriv = REJECT, > .result = ACCEPT, > }, > { > @@ -642,6 +664,8 @@ static struct bpf_test tests[] = { > BPF_MOV64_IMM(BPF_REG_0, 0), > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "R1 pointer comparison", > + .result_unpriv = REJECT, > .result = ACCEPT, > }, > { > @@ -699,6 +723,7 @@ static struct bpf_test tests[] = { > }, > .fixup = {4}, > .errstr = "different pointers", > + .errstr_unpriv = "R1 pointer comparison", > .result = REJECT, > }, > { > @@ -720,6 +745,7 @@ static struct bpf_test tests[] = { > }, > .fixup = {6}, > .errstr = "different pointers", > + .errstr_unpriv = "R1 pointer comparison", > .result = REJECT, > }, > { > @@ -742,6 +768,7 @@ static struct bpf_test tests[] = { > }, > .fixup = {7}, > .errstr = "different pointers", > + .errstr_unpriv = "R1 pointer comparison", > .result = REJECT, > }, > { > @@ -752,6 +779,7 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .errstr = "invalid bpf_context access", > + .errstr_unpriv = "R1 leaks addr", > .result = REJECT, > }, > { > @@ -762,6 +790,7 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .errstr = "invalid bpf_context access", > + .errstr_unpriv = "R1 leaks addr", > .result = REJECT, > }, > { > @@ -772,16 +801,18 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .errstr = "invalid bpf_context access", > + .errstr_unpriv = "R1 leaks addr", > .result = REJECT, > }, > { > "check out of range skb->cb access", > .insns = { > BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, > - offsetof(struct __sk_buff, cb[60])), > + offsetof(struct __sk_buff, cb[0]) + 256), > BPF_EXIT_INSN(), > }, > .errstr = "invalid bpf_context access", > + .errstr_unpriv = "", > .result = REJECT, > .prog_type = BPF_PROG_TYPE_SCHED_ACT, > }, > @@ -803,6 +834,8 @@ static struct bpf_test tests[] = { > BPF_EXIT_INSN(), > }, > .result = ACCEPT, > + .errstr_unpriv = "R1 leaks addr", > + .result_unpriv = REJECT, > }, > { > "write skb fields from tc_cls_act prog", > @@ -819,6 +852,8 @@ static struct bpf_test tests[] = { > offsetof(struct __sk_buff, cb[3])), > BPF_EXIT_INSN(), > }, > + .errstr_unpriv = "", > + .result_unpriv = REJECT, > .result = ACCEPT, > .prog_type = BPF_PROG_TYPE_SCHED_CLS, > }, > @@ -881,6 +916,270 @@ static struct bpf_test tests[] = { > .result = REJECT, > .errstr = "invalid stack off=0 size=8", > }, > + { > + "unpriv: return pointer", > + .insns = { > + BPF_MOV64_REG(BPF_REG_0, BPF_REG_10), > + BPF_EXIT_INSN(), > + }, > + .result = ACCEPT, > + .result_unpriv = REJECT, > + .errstr_unpriv = "R0 leaks addr", > + }, > + { > + "unpriv: add const to pointer", > + .insns = { > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .result = ACCEPT, > + .result_unpriv = REJECT, > + .errstr_unpriv = "R1 pointer arithmetic", > + }, > + { > + "unpriv: add pointer to pointer", > + .insns = { > + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_10), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .result = ACCEPT, > + .result_unpriv = REJECT, > + .errstr_unpriv = "R1 pointer arithmetic", > + }, > + { > + "unpriv: neg pointer", > + .insns = { > + BPF_ALU64_IMM(BPF_NEG, BPF_REG_1, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .result = ACCEPT, > + .result_unpriv = REJECT, > + .errstr_unpriv = "R1 pointer arithmetic", > + }, > + { > + "unpriv: cmp pointer with const", > + .insns = { > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .result = ACCEPT, > + .result_unpriv = REJECT, > + .errstr_unpriv = "R1 pointer comparison", > + }, > + { > + "unpriv: cmp pointer with pointer", > + .insns = { > + BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .result = ACCEPT, > + .result_unpriv = REJECT, > + .errstr_unpriv = "R10 pointer comparison", > + }, > + { > + "unpriv: check that printk is disallowed", > + .insns = { > + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), > + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), > + BPF_MOV64_IMM(BPF_REG_2, 8), > + BPF_MOV64_REG(BPF_REG_3, BPF_REG_1), > + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_trace_printk), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "unknown func 6", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: pass pointer to helper function", > + .insns = { > + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), > + BPF_LD_MAP_FD(BPF_REG_1, 0), > + BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), > + BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), > + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .fixup = {3}, > + .errstr_unpriv = "R4 leaks addr", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: indirectly pass pointer on stack to helper function", > + .insns = { > + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8), > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), > + BPF_LD_MAP_FD(BPF_REG_1, 0), > + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .fixup = {3}, > + .errstr = "invalid indirect read from stack off -8+0 size 8", > + .result = REJECT, > + }, > + { > + "unpriv: mangle pointer on stack 1", > + .insns = { > + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8), > + BPF_ST_MEM(BPF_W, BPF_REG_10, -8, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "attempt to corrupt spilled", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: mangle pointer on stack 2", > + .insns = { > + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8), > + BPF_ST_MEM(BPF_B, BPF_REG_10, -1, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "attempt to corrupt spilled", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: read pointer from stack in small chunks", > + .insns = { > + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_10, -8), > + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_10, -8), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr = "invalid size", > + .result = REJECT, > + }, > + { > + "unpriv: write pointer into ctx", > + .insns = { > + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "R1 leaks addr", > + .result_unpriv = REJECT, > + .errstr = "invalid bpf_context access", > + .result = REJECT, > + }, > + { > + "unpriv: write pointer into map elem value", > + .insns = { > + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), > + BPF_LD_MAP_FD(BPF_REG_1, 0), > + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), > + BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .fixup = {3}, > + .errstr_unpriv = "R0 leaks addr", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: partial copy of pointer", > + .insns = { > + BPF_MOV32_REG(BPF_REG_1, BPF_REG_10), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "R10 partial copy", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: pass pointer to tail_call", > + .insns = { > + BPF_MOV64_REG(BPF_REG_3, BPF_REG_1), > + BPF_LD_MAP_FD(BPF_REG_2, 0), > + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .prog_array_fixup = {1}, > + .errstr_unpriv = "R3 leaks addr into helper", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: cmp map pointer with zero", > + .insns = { > + BPF_MOV64_IMM(BPF_REG_1, 0), > + BPF_LD_MAP_FD(BPF_REG_1, 0), > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .fixup = {1}, > + .errstr_unpriv = "R1 pointer comparison", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: write into frame pointer", > + .insns = { > + BPF_MOV64_REG(BPF_REG_10, BPF_REG_1), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr = "frame pointer is read only", > + .result = REJECT, > + }, > + { > + "unpriv: cmp of frame pointer", > + .insns = { > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_10, 0, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "R10 pointer comparison", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: cmp of stack pointer", > + .insns = { > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), > + BPF_JMP_IMM(BPF_JEQ, BPF_REG_2, 0, 0), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "R2 pointer comparison", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > + { > + "unpriv: obfuscate stack pointer", > + .insns = { > + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), > + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), > + BPF_MOV64_IMM(BPF_REG_0, 0), > + BPF_EXIT_INSN(), > + }, > + .errstr_unpriv = "R2 pointer arithmetic", > + .result_unpriv = REJECT, > + .result = ACCEPT, > + }, > }; > > static int probe_filter_length(struct bpf_insn *fp) > @@ -896,13 +1195,24 @@ static int probe_filter_length(struct bpf_insn *fp) > > static int create_map(void) > { > - long long key, value = 0; > int map_fd; > > - map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024); > - if (map_fd < 0) { > + map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, > + sizeof(long long), sizeof(long long), 1024); > + if (map_fd < 0) > printf("failed to create map '%s'\n", strerror(errno)); > - } > + > + return map_fd; > +} > + > +static int create_prog_array(void) > +{ > + int map_fd; > + > + map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, > + sizeof(int), sizeof(int), 4); > + if (map_fd < 0) > + printf("failed to create prog_array '%s'\n", strerror(errno)); > > return map_fd; > } > @@ -910,13 +1220,17 @@ static int create_map(void) > static int test(void) > { > int prog_fd, i, pass_cnt = 0, err_cnt = 0; > + bool unpriv = geteuid() != 0; > > for (i = 0; i < ARRAY_SIZE(tests); i++) { > struct bpf_insn *prog = tests[i].insns; > int prog_type = tests[i].prog_type; > int prog_len = probe_filter_length(prog); > int *fixup = tests[i].fixup; > - int map_fd = -1; > + int *prog_array_fixup = tests[i].prog_array_fixup; > + int expected_result; > + const char *expected_errstr; > + int map_fd = -1, prog_array_fd = -1; > > if (*fixup) { > map_fd = create_map(); > @@ -926,13 +1240,31 @@ static int test(void) > fixup++; > } while (*fixup); > } > + if (*prog_array_fixup) { > + prog_array_fd = create_prog_array(); > + > + do { > + prog[*prog_array_fixup].imm = prog_array_fd; > + prog_array_fixup++; > + } while (*prog_array_fixup); > + } > printf("#%d %s ", i, tests[i].descr); > > prog_fd = bpf_prog_load(prog_type ?: BPF_PROG_TYPE_SOCKET_FILTER, > prog, prog_len * sizeof(struct bpf_insn), > "GPL", 0); > > - if (tests[i].result == ACCEPT) { > + if (unpriv && tests[i].result_unpriv != UNDEF) > + expected_result = tests[i].result_unpriv; > + else > + expected_result = tests[i].result; > + > + if (unpriv && tests[i].errstr_unpriv) > + expected_errstr = tests[i].errstr_unpriv; > + else > + expected_errstr = tests[i].errstr; > + > + if (expected_result == ACCEPT) { > if (prog_fd < 0) { > printf("FAIL\nfailed to load prog '%s'\n", > strerror(errno)); > @@ -947,7 +1279,7 @@ static int test(void) > err_cnt++; > goto fail; > } > - if (strstr(bpf_log_buf, tests[i].errstr) == 0) { > + if (strstr(bpf_log_buf, expected_errstr) == 0) { > printf("FAIL\nunexpected error message: %s", > bpf_log_buf); > err_cnt++; > @@ -960,6 +1292,8 @@ static int test(void) > fail: > if (map_fd >= 0) > close(map_fd); > + if (prog_array_fd >= 0) > + close(prog_array_fd); > close(prog_fd); > > } > @@ -970,5 +1304,8 @@ fail: > > int main(void) > { > + struct rlimit r = {1 << 20, 1 << 20}; > + > + setrlimit(RLIMIT_MEMLOCK, &r); > return test(); > } > -- > 1.7.9.5 > -- Kees Cook Chrome OS Security -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html