Message ID | 20200329004356.27286-8-kpsingh@chromium.org |
---|---|
State | Accepted |
Delegated to: | BPF Maintainers |
Headers | show |
Series | MAC and Audit policy using eBPF (KRSI) | expand |
On Sat, Mar 28, 2020 at 5:44 PM KP Singh <kpsingh@chromium.org> wrote: > +int BPF_PROG(test_int_hook, struct vm_area_struct *vma, > + unsigned long reqprot, unsigned long prot, int ret) > +{ > + if (ret != 0) > + return ret; > + > + __u32 pid = bpf_get_current_pid_tgid() >> 32; > + int is_heap = 0; > + > + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && > + vma->vm_end <= vma->vm_mm->brk); This test fails for me. I've added: bpf_printk("start %llx %llx\n", vma->vm_start, vma->vm_mm->start_brk); bpf_printk("end %llx %llx\n", vma->vm_end, vma->vm_mm->brk); and see cat /sys/kernel/debug/tracing/trace_pipe true-2285 [001] ...2 858.717432: 0: start 7f66470a2000 607000 true-2285 [001] ...2 858.717440: 0: end 7f6647443000 607000 true-2285 [001] ...2 858.717658: 0: start 7f6647439000 607000 true-2285 [001] ...2 858.717659: 0: end 7f664743f000 607000 true-2285 [001] ...2 858.717691: 0: start 605000 607000 true-2285 [001] ...2 858.717692: 0: end 607000 607000 true-2285 [001] ...2 858.717700: 0: start 7f6647666000 607000 true-2285 [001] ...2 858.717701: 0: end 7f6647668000 607000 test_progs-2283 [000] ...2 858.718030: 0: start 523000 39b9000 test_progs-2283 [000] ...2 858.718033: 0: end 39e0000 39e0000 523000 is not >= 39b9000. 523000 is higher than vm_mm->end_data, but lower than vm_mm->start_brk. No idea why this addr is passed into security_file_mprotect(). The address user space is passing to mprotect() is 0x39c0000 which is correct. Could you please help debug?
On 01-Apr 17:09, Alexei Starovoitov wrote: > On Sat, Mar 28, 2020 at 5:44 PM KP Singh <kpsingh@chromium.org> wrote: > > +int BPF_PROG(test_int_hook, struct vm_area_struct *vma, > > + unsigned long reqprot, unsigned long prot, int ret) > > +{ > > + if (ret != 0) > > + return ret; > > + > > + __u32 pid = bpf_get_current_pid_tgid() >> 32; > > + int is_heap = 0; > > + > > + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && > > + vma->vm_end <= vma->vm_mm->brk); > > This test fails for me. Trying this from bpf/master: b9258a2cece4 ("slcan: Don't transmit uninitialized stack data in padding") also from bpf-next/master: 1a323ea5356e ("x86: get rid of 'errret' argument to __get_user_xyz() macross") and I am unable to reproduce the failure (the output when using bpf/master): ./test_progs -t test_lsm #70 test_lsm:OK Summary: 1/0 PASSED, 0 SKIPPED, 0 FAILED cat /sys/kernel/debug/tracing/trace # tracer: nop # # entries-in-buffer/entries-written: 10/10 #P:4 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | true-322 [001] ...2 187.127231: 0: start 7fc7ffccc000 556a623be000 true-322 [001] ...2 187.127238: 0: end 7fc7ffe8c000 556a623be000 true-322 [001] ...2 187.128233: 0: start 7fc7ffe82000 556a623be000 true-322 [001] ...2 187.128237: 0: end 7fc7ffe88000 556a623be000 true-322 [001] ...2 187.128306: 0: start 556a604f7000 556a623be000 true-322 [001] ...2 187.128309: 0: end 556a604f9000 556a623be000 true-322 [001] ...2 187.128372: 0: start 7fc7ffebf000 556a623be000 true-322 [001] ...2 187.128375: 0: end 7fc7ffec1000 556a623be000 test_progs-321 [000] ...2 187.129952: 0: start 55dc6e8df000 55dc6e8df000 test_progs-321 [000] ...2 187.129955: 0: end 55dc6e906000 55dc6e906000 The full run also works for me: ./test_progs [...] #70 test_lsm:OK #71 test_overhead:OK #72 tp_attach_query:OK My config is: https://gist.githubusercontent.com/sinkap/cb24b955e1b6e6c1dc736054a774fb41/raw/ and the kernel commandline is (on a QEMU VM): cat /proc/cmdline console=ttyS0,115200 root=/dev/sda rw nokaslr Could you share your config and cmdline? Also, I am wondering if this happens just in the BPF program or also in the kernel as the other variable I can think of is the compiled bpf program itself which might be reading a different value thinking it's vm->vma_start, possible something to do with BTF / CO RE due to a compiler bug: Here's the version of clang I am using: clang version 10.0.0 (https://github.com/llvm/llvm-project.git 2026d7b80a1a5534b5e263683c85aa95e7593b98) - KP > I've added: > bpf_printk("start %llx %llx\n", vma->vm_start, vma->vm_mm->start_brk); > bpf_printk("end %llx %llx\n", vma->vm_end, vma->vm_mm->brk); > and see > cat /sys/kernel/debug/tracing/trace_pipe > true-2285 [001] ...2 858.717432: 0: start 7f66470a2000 607000 > true-2285 [001] ...2 858.717440: 0: end 7f6647443000 607000 > true-2285 [001] ...2 858.717658: 0: start 7f6647439000 607000 > true-2285 [001] ...2 858.717659: 0: end 7f664743f000 607000 > true-2285 [001] ...2 858.717691: 0: start 605000 607000 > true-2285 [001] ...2 858.717692: 0: end 607000 607000 > true-2285 [001] ...2 858.717700: 0: start 7f6647666000 607000 > true-2285 [001] ...2 858.717701: 0: end 7f6647668000 607000 > test_progs-2283 [000] ...2 858.718030: 0: start 523000 39b9000 > test_progs-2283 [000] ...2 858.718033: 0: end 39e0000 39e0000 > > 523000 is not >= 39b9000. > 523000 is higher than vm_mm->end_data, but lower than vm_mm->start_brk. > No idea why this addr is passed into security_file_mprotect(). > The address user space is passing to mprotect() is 0x39c0000 which is correct. > Could you please help debug?
On Thu, Apr 02, 2020 at 06:03:57AM +0200, KP Singh wrote: > On 01-Apr 17:09, Alexei Starovoitov wrote: > > On Sat, Mar 28, 2020 at 5:44 PM KP Singh <kpsingh@chromium.org> wrote: > > > +int BPF_PROG(test_int_hook, struct vm_area_struct *vma, > > > + unsigned long reqprot, unsigned long prot, int ret) > > > +{ > > > + if (ret != 0) > > > + return ret; > > > + > > > + __u32 pid = bpf_get_current_pid_tgid() >> 32; > > > + int is_heap = 0; > > > + > > > + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && > > > + vma->vm_end <= vma->vm_mm->brk); > > > > This test fails for me. > > Trying this from bpf/master: > > b9258a2cece4 ("slcan: Don't transmit uninitialized stack data in padding") > > also from bpf-next/master: > > 1a323ea5356e ("x86: get rid of 'errret' argument to __get_user_xyz() macross") > > and I am unable to reproduce the failure (the output when using bpf/master): .. > > Also, I am wondering if this happens just in the BPF program or also > in the kernel as the other variable I can think of is the compiled > bpf program itself which might be reading a different value thinking > it's vm->vma_start, possible something to do with BTF / CO RE due to a > compiler bug: I don't think it's anything to do with clang/btf or core. I think that condition is simply incorrect. I've added: diff --git a/mm/mprotect.c b/mm/mprotect.c index 311c0dadf71c..16ae0ada34ba 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -577,6 +577,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len, goto out; } + printk("start %llx %llx\n", vma->vm_start, vma->vm_mm->start_brk); error = security_file_mprotect(vma, reqprot, prot); and see exactly the same values as bpf side (at least it was nice to see that all CO-RE logic is working as expected :)) [ 24.787442] start 523000 39b9000 I think it has something to do with the way test_progs is linked. But the problem is in condition itself. I suspect you copy-pasted it from selinux_file_mprotect() ? I think it's incorrect there as well. Did we just discover a way to side step selinux protection? Try objdump -h test_progs|grep bss the number I see in vma->vm_start is the beginning of .bss rounded to page boundary. I wonder where your 55dc6e8df000 is coming from.
On Thu, Apr 2, 2020 at 6:30 AM Alexei Starovoitov <alexei.starovoitov@gmail.com> wrote: > On Thu, Apr 02, 2020 at 06:03:57AM +0200, KP Singh wrote: > > On 01-Apr 17:09, Alexei Starovoitov wrote: > > > On Sat, Mar 28, 2020 at 5:44 PM KP Singh <kpsingh@chromium.org> wrote: > > > > +int BPF_PROG(test_int_hook, struct vm_area_struct *vma, > > > > + unsigned long reqprot, unsigned long prot, int ret) > > > > +{ > > > > + if (ret != 0) > > > > + return ret; > > > > + > > > > + __u32 pid = bpf_get_current_pid_tgid() >> 32; > > > > + int is_heap = 0; > > > > + > > > > + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && > > > > + vma->vm_end <= vma->vm_mm->brk); > > > > > > This test fails for me. > > > > Trying this from bpf/master: > > > > b9258a2cece4 ("slcan: Don't transmit uninitialized stack data in padding") > > > > also from bpf-next/master: > > > > 1a323ea5356e ("x86: get rid of 'errret' argument to __get_user_xyz() macross") > > > > and I am unable to reproduce the failure (the output when using bpf/master): > .. > > > > Also, I am wondering if this happens just in the BPF program or also > > in the kernel as the other variable I can think of is the compiled > > bpf program itself which might be reading a different value thinking > > it's vm->vma_start, possible something to do with BTF / CO RE due to a > > compiler bug: > > I don't think it's anything to do with clang/btf or core. > I think that condition is simply incorrect. > I've added: > diff --git a/mm/mprotect.c b/mm/mprotect.c > index 311c0dadf71c..16ae0ada34ba 100644 > --- a/mm/mprotect.c > +++ b/mm/mprotect.c > @@ -577,6 +577,7 @@ static int do_mprotect_pkey(unsigned long start, size_t len, > goto out; > } > > + printk("start %llx %llx\n", vma->vm_start, vma->vm_mm->start_brk); > error = security_file_mprotect(vma, reqprot, prot); > > and see exactly the same values as bpf side (at least it was nice to see > that all CO-RE logic is working as expected :)) > > [ 24.787442] start 523000 39b9000 > > I think it has something to do with the way test_progs is linked. > But the problem is in condition itself. > I suspect you copy-pasted it from selinux_file_mprotect() ? > I think it's incorrect there as well. > Did we just discover a way to side step selinux protection? > Try objdump -h test_progs|grep bss > the number I see in vma->vm_start is the beginning of .bss rounded to page boundary. > I wonder where your 55dc6e8df000 is coming from. I suspect that you're using different versions of libc, or something's different in the memory layout, or something like that. The brk region is used for memory allocations using brk(), but memory allocations using mmap() land outside it. At least some versions of libc try to allocate memory for malloc() with brk(), then fall back to mmap() if that fails because there's something else behind the current end of the brk region; but I think there might also be versions of libc that directly use mmap() and don't even try to use brk(). So yeah, security checks based on the brk region aren't exactly useful; but e.g. in SELinux, both cases have appropriate checks. The brk region gets SECCLASS_PROCESS:PROCESS__EXECHEAP, anonymous mmap allocations get SECCLASS_PROCESS:PROCESS__EXECMEM in file_map_prot_check() instead. (This makes *some* amount of sense - although not a lot - because for the brk region you know that it comes from something like malloc(), while an anonymous mmap() allocation might reasonably be used for JIT executable memory.) In other words, you may want to pick something different as test case, since the behavior here depends on libc.
Thanks Jann and Alexei, On 02-Apr 07:15, Jann Horn wrote: > On Thu, Apr 2, 2020 at 6:30 AM Alexei Starovoitov > <alexei.starovoitov@gmail.com> wrote: > > On Thu, Apr 02, 2020 at 06:03:57AM +0200, KP Singh wrote: > > > On 01-Apr 17:09, Alexei Starovoitov wrote: > > > > > + unsigned long reqprot, unsigned long prot, int ret) > > > > > +{ [...] > > > > and see exactly the same values as bpf side (at least it was nice to see > > that all CO-RE logic is working as expected :)) > > > > [ 24.787442] start 523000 39b9000 > > > > I think it has something to do with the way test_progs is linked. > > But the problem is in condition itself. > > I suspect you copy-pasted it from selinux_file_mprotect() ? > > I think it's incorrect there as well. > > Did we just discover a way to side step selinux protection? > > Try objdump -h test_progs|grep bss > > the number I see in vma->vm_start is the beginning of .bss rounded to page boundary. > > I wonder where your 55dc6e8df000 is coming from. > > I suspect that you're using different versions of libc, or something's > different in the memory layout, or something like that. The brk region > is used for memory allocations using brk(), but memory allocations > using mmap() land outside it. At least some versions of libc try to > allocate memory for malloc() with brk(), then fall back to mmap() if > that fails because there's something else behind the current end of > the brk region; but I think there might also be versions of libc that > directly use mmap() and don't even try to use brk(). Yeah missed this that heap can also be allocated using mmap: Quoting the manual: """ Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2). When allocating blocks of memory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using mmap(2). MMAP_THRESHOLD is 128 kB by default, but is adjustable using mallopt(3). Prior to Linux 4.7 allocations performed using mmap(2) were unaffected by the RLIMIT_DATA resource limit; since Linux 4.7, this limit is also enforced for allocations performed using mmap(2). """ So it seems like we might have separate MMAP_THRESHOLD or resource limits. I updated my test case to check for mmaps on the stack instead: diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index 1e4c258de09d..64c13c850611 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -15,8 +15,13 @@ char *CMD_ARGS[] = {"true", NULL}; -int heap_mprotect(void) +#define PAGE_SIZE 4096 +#define GET_PAGE_ADDR(ADDR) \ + (char *)(((unsigned long) ADDR) & ~(PAGE_SIZE-1)) + +int stack_mprotect(void) { + void *buf; long sz; int ret; @@ -25,12 +30,9 @@ int heap_mprotect(void) if (sz < 0) return sz; - buf = memalign(sz, 2 * sz); - if (buf == NULL) - return -ENOMEM; - - ret = mprotect(buf, sz, PROT_READ | PROT_WRITE | PROT_EXEC); - free(buf); + buf = alloca(PAGE_SIZE * 3); + ret = mprotect(GET_PAGE_ADDR(buf + PAGE_SIZE), PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC); return ret; } @@ -73,8 +75,8 @@ void test_test_lsm(void) skel->bss->monitored_pid = getpid(); - err = heap_mprotect(); - if (CHECK(errno != EPERM, "heap_mprotect", "want errno=EPERM, got %d\n", + err = stack_mprotect(); + if (CHECK(errno != EPERM, "stack_mprotect", "want err=EPERM, got %d\n", errno)) goto close_prog; diff --git a/tools/testing/selftests/bpf/progs/lsm.c b/tools/testing/selftests/bpf/progs/lsm.c index a4e3c223028d..b4598d4bc4f7 100644 --- a/tools/testing/selftests/bpf/progs/lsm.c +++ b/tools/testing/selftests/bpf/progs/lsm.c @@ -23,12 +23,12 @@ int BPF_PROG(test_int_hook, struct vm_area_struct *vma, return ret; __u32 pid = bpf_get_current_pid_tgid() >> 32; - int is_heap = 0; + int is_stack = 0; - is_heap = (vma->vm_start >= vma->vm_mm->start_brk && - vma->vm_end <= vma->vm_mm->brk); + is_stack = (vma->vm_start <= vma->vm_mm->start_stack && + vma->vm_end >= vma->vm_mm->start_stack); - if (is_heap && monitored_pid == pid) { + if (is_stack && monitored_pid == pid) { mprotect_count++; ret = -EPERM; } and the the logic seems to work for me. Do you think we could use this instead? - KP > > So yeah, security checks based on the brk region aren't exactly > useful; but e.g. in SELinux, both cases have appropriate checks. The > brk region gets SECCLASS_PROCESS:PROCESS__EXECHEAP, anonymous mmap > allocations get SECCLASS_PROCESS:PROCESS__EXECMEM in > file_map_prot_check() instead. (This makes *some* amount of sense - > although not a lot - because for the brk region you know that it comes > from something like malloc(), while an anonymous mmap() allocation > might reasonably be used for JIT executable memory.) > > In other words, you may want to pick something different as test case, > since the behavior here depends on libc.
On Thu, Apr 2, 2020 at 1:53 PM KP Singh <kpsingh@chromium.org> wrote: > On 02-Apr 07:15, Jann Horn wrote: [...] > > I suspect that you're using different versions of libc, or something's > > different in the memory layout, or something like that. The brk region > > is used for memory allocations using brk(), but memory allocations > > using mmap() land outside it. At least some versions of libc try to > > allocate memory for malloc() with brk(), then fall back to mmap() if > > that fails because there's something else behind the current end of > > the brk region; but I think there might also be versions of libc that > > directly use mmap() and don't even try to use brk(). > > Yeah missed this that heap can also be allocated using mmap: [...] > I updated my test case to check for mmaps on the stack instead: [...] > + is_stack = (vma->vm_start <= vma->vm_mm->start_stack && > + vma->vm_end >= vma->vm_mm->start_stack); > > - if (is_heap && monitored_pid == pid) { > + if (is_stack && monitored_pid == pid) { > mprotect_count++; > ret = -EPERM; > } > > and the the logic seems to work for me. Do you think we could use > this instead? Yeah, I think that should work. (Just keep in mind that a successful mprotect() operation will split the VMA into three VMAs - but that shouldn't be a problem here, since you only do it once per process, and since you're denying the operation, it won't go through anyway.)
On Thu, Apr 2, 2020 at 4:39 PM Jann Horn <jannh@google.com> wrote: > > On Thu, Apr 2, 2020 at 1:53 PM KP Singh <kpsingh@chromium.org> wrote: > > On 02-Apr 07:15, Jann Horn wrote: > [...] > > > I suspect that you're using different versions of libc, or something's > > > different in the memory layout, or something like that. The brk region > > > is used for memory allocations using brk(), but memory allocations > > > using mmap() land outside it. At least some versions of libc try to > > > allocate memory for malloc() with brk(), then fall back to mmap() if > > > that fails because there's something else behind the current end of > > > the brk region; but I think there might also be versions of libc that > > > directly use mmap() and don't even try to use brk(). > > > > Yeah missed this that heap can also be allocated using mmap: > [...] > > I updated my test case to check for mmaps on the stack instead: > [...] > > + is_stack = (vma->vm_start <= vma->vm_mm->start_stack && > > + vma->vm_end >= vma->vm_mm->start_stack); > > > > - if (is_heap && monitored_pid == pid) { > > + if (is_stack && monitored_pid == pid) { > > mprotect_count++; > > ret = -EPERM; > > } > > > > and the the logic seems to work for me. Do you think we could use > > this instead? > > Yeah, I think that should work. (Just keep in mind that a successful > mprotect() operation will split the VMA into three VMAs - but that > shouldn't be a problem here, since you only do it once per process, > and since you're denying the operation, it won't go through anyway.) Okay I will send a patch that fixes this test. Thanks everyone! - KP
On Thu, Apr 02, 2020 at 01:53:06PM +0200, KP Singh wrote: > > -int heap_mprotect(void) > +#define PAGE_SIZE 4096 > +#define GET_PAGE_ADDR(ADDR) \ > + (char *)(((unsigned long) ADDR) & ~(PAGE_SIZE-1)) > + > +int stack_mprotect(void) > { > + > void *buf; > long sz; > int ret; > @@ -25,12 +30,9 @@ int heap_mprotect(void) > if (sz < 0) > return sz; > > - buf = memalign(sz, 2 * sz); > - if (buf == NULL) > - return -ENOMEM; > - > - ret = mprotect(buf, sz, PROT_READ | PROT_WRITE | PROT_EXEC); > - free(buf); > + buf = alloca(PAGE_SIZE * 3); > + ret = mprotect(GET_PAGE_ADDR(buf + PAGE_SIZE), PAGE_SIZE, > + PROT_READ | PROT_WRITE | PROT_EXEC); Great. Something like this should work. Please use sysconf(_SC_PAGE_SIZE); like prog_tests/mmap.c does. selftests/bpf are run not only on x86
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 5dc109f4c097..60e3ae5d4e48 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -35,3 +35,5 @@ CONFIG_MPLS_ROUTING=m CONFIG_MPLS_IPTUNNEL=m CONFIG_IPV6_SIT=m CONFIG_BPF_JIT=y +CONFIG_BPF_LSM=y +CONFIG_SECURITY=y diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c new file mode 100644 index 000000000000..1e4c258de09d --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2020 Google LLC. + */ + +#include <test_progs.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <unistd.h> +#include <malloc.h> +#include <stdlib.h> + +#include "lsm.skel.h" + +char *CMD_ARGS[] = {"true", NULL}; + +int heap_mprotect(void) +{ + void *buf; + long sz; + int ret; + + sz = sysconf(_SC_PAGESIZE); + if (sz < 0) + return sz; + + buf = memalign(sz, 2 * sz); + if (buf == NULL) + return -ENOMEM; + + ret = mprotect(buf, sz, PROT_READ | PROT_WRITE | PROT_EXEC); + free(buf); + return ret; +} + +int exec_cmd(int *monitored_pid) +{ + int child_pid, child_status; + + child_pid = fork(); + if (child_pid == 0) { + *monitored_pid = getpid(); + execvp(CMD_ARGS[0], CMD_ARGS); + return -EINVAL; + } else if (child_pid > 0) { + waitpid(child_pid, &child_status, 0); + return child_status; + } + + return -EINVAL; +} + +void test_test_lsm(void) +{ + struct lsm *skel = NULL; + int err, duration = 0; + + skel = lsm__open_and_load(); + if (CHECK(!skel, "skel_load", "lsm skeleton failed\n")) + goto close_prog; + + err = lsm__attach(skel); + if (CHECK(err, "attach", "lsm attach failed: %d\n", err)) + goto close_prog; + + err = exec_cmd(&skel->bss->monitored_pid); + if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno)) + goto close_prog; + + CHECK(skel->bss->bprm_count != 1, "bprm_count", "bprm_count = %d\n", + skel->bss->bprm_count); + + skel->bss->monitored_pid = getpid(); + + err = heap_mprotect(); + if (CHECK(errno != EPERM, "heap_mprotect", "want errno=EPERM, got %d\n", + errno)) + goto close_prog; + + CHECK(skel->bss->mprotect_count != 1, "mprotect_count", + "mprotect_count = %d\n", skel->bss->mprotect_count); + +close_prog: + lsm__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/lsm.c b/tools/testing/selftests/bpf/progs/lsm.c new file mode 100644 index 000000000000..a4e3c223028d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/lsm.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2020 Google LLC. + */ + +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <errno.h> + +char _license[] SEC("license") = "GPL"; + +int monitored_pid = 0; +int mprotect_count = 0; +int bprm_count = 0; + +SEC("lsm/file_mprotect") +int BPF_PROG(test_int_hook, struct vm_area_struct *vma, + unsigned long reqprot, unsigned long prot, int ret) +{ + if (ret != 0) + return ret; + + __u32 pid = bpf_get_current_pid_tgid() >> 32; + int is_heap = 0; + + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && + vma->vm_end <= vma->vm_mm->brk); + + if (is_heap && monitored_pid == pid) { + mprotect_count++; + ret = -EPERM; + } + + return ret; +} + +SEC("lsm/bprm_committed_creds") +int BPF_PROG(test_void_hook, struct linux_binprm *bprm) +{ + __u32 pid = bpf_get_current_pid_tgid() >> 32; + + if (monitored_pid == pid) + bprm_count++; + + return 0; +}