Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: add a test for device cgroup controller

Add a test for device cgroup controller.

The test loads a simple bpf program which logs all
device access attempts using trace_printk() and forbids
all operations except operations with /dev/zero and
/dev/urandom.

Then the test creates and joins a test cgroup, and attaches
the bpf program to it.

Then it tries to perform some simple device operations
and checks the result:

create /dev/null (should fail)
create /dev/zero (should pass)
copy data from /dev/urandom to /dev/zero (should pass)
copy data from /dev/urandom to /dev/full (should fail)
copy data from /dev/random to /dev/zero (should fail)

Signed-off-by: Roman Gushchin <guro@fb.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Roman Gushchin and committed by
David S. Miller
37f1ba09 9d1f1594

+155 -2
+2 -2
tools/testing/selftests/bpf/Makefile
··· 13 13 LDLIBS += -lcap -lelf 14 14 15 15 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ 16 - test_align test_verifier_log 16 + test_align test_verifier_log test_dev_cgroup 17 17 18 18 TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ 19 19 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ 20 - sockmap_verdict_prog.o 20 + sockmap_verdict_prog.o dev_cgroup.o 21 21 22 22 TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh 23 23
+60
tools/testing/selftests/bpf/dev_cgroup.c
··· 1 + /* Copyright (c) 2017 Facebook 2 + * 3 + * This program is free software; you can redistribute it and/or 4 + * modify it under the terms of version 2 of the GNU General Public 5 + * License as published by the Free Software Foundation. 6 + */ 7 + 8 + #include <linux/bpf.h> 9 + #include <linux/version.h> 10 + #include "bpf_helpers.h" 11 + 12 + SEC("cgroup/dev") 13 + int bpf_prog1(struct bpf_cgroup_dev_ctx *ctx) 14 + { 15 + short type = ctx->access_type & 0xFFFF; 16 + #ifdef DEBUG 17 + short access = ctx->access_type >> 16; 18 + char fmt[] = " %d:%d \n"; 19 + 20 + switch (type) { 21 + case BPF_DEVCG_DEV_BLOCK: 22 + fmt[0] = 'b'; 23 + break; 24 + case BPF_DEVCG_DEV_CHAR: 25 + fmt[0] = 'c'; 26 + break; 27 + default: 28 + fmt[0] = '?'; 29 + break; 30 + } 31 + 32 + if (access & BPF_DEVCG_ACC_READ) 33 + fmt[8] = 'r'; 34 + 35 + if (access & BPF_DEVCG_ACC_WRITE) 36 + fmt[9] = 'w'; 37 + 38 + if (access & BPF_DEVCG_ACC_MKNOD) 39 + fmt[10] = 'm'; 40 + 41 + bpf_trace_printk(fmt, sizeof(fmt), ctx->major, ctx->minor); 42 + #endif 43 + 44 + /* Allow access to /dev/zero and /dev/random. 45 + * Forbid everything else. 46 + */ 47 + if (ctx->major != 1 || type != BPF_DEVCG_DEV_CHAR) 48 + return 0; 49 + 50 + switch (ctx->minor) { 51 + case 5: /* 1:5 /dev/zero */ 52 + case 9: /* 1:9 /dev/urandom */ 53 + return 1; 54 + } 55 + 56 + return 0; 57 + } 58 + 59 + char _license[] SEC("license") = "GPL"; 60 + __u32 _version SEC("version") = LINUX_VERSION_CODE;
+93
tools/testing/selftests/bpf/test_dev_cgroup.c
··· 1 + /* Copyright (c) 2017 Facebook 2 + * 3 + * This program is free software; you can redistribute it and/or 4 + * modify it under the terms of version 2 of the GNU General Public 5 + * License as published by the Free Software Foundation. 6 + */ 7 + 8 + #include <stdio.h> 9 + #include <stdlib.h> 10 + #include <string.h> 11 + #include <errno.h> 12 + #include <assert.h> 13 + 14 + #include <linux/bpf.h> 15 + #include <bpf/bpf.h> 16 + #include <bpf/libbpf.h> 17 + 18 + #include "cgroup_helpers.h" 19 + 20 + #define DEV_CGROUP_PROG "./dev_cgroup.o" 21 + 22 + #define TEST_CGROUP "test-bpf-based-device-cgroup/" 23 + 24 + int main(int argc, char **argv) 25 + { 26 + struct bpf_object *obj; 27 + int error = EXIT_FAILURE; 28 + int prog_fd, cgroup_fd; 29 + __u32 prog_cnt; 30 + 31 + if (bpf_prog_load(DEV_CGROUP_PROG, BPF_PROG_TYPE_CGROUP_DEVICE, 32 + &obj, &prog_fd)) { 33 + printf("Failed to load DEV_CGROUP program\n"); 34 + goto err; 35 + } 36 + 37 + if (setup_cgroup_environment()) { 38 + printf("Failed to load DEV_CGROUP program\n"); 39 + goto err; 40 + } 41 + 42 + /* Create a cgroup, get fd, and join it */ 43 + cgroup_fd = create_and_get_cgroup(TEST_CGROUP); 44 + if (!cgroup_fd) { 45 + printf("Failed to create test cgroup\n"); 46 + goto err; 47 + } 48 + 49 + if (join_cgroup(TEST_CGROUP)) { 50 + printf("Failed to join cgroup\n"); 51 + goto err; 52 + } 53 + 54 + /* Attach bpf program */ 55 + if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, 0)) { 56 + printf("Failed to attach DEV_CGROUP program"); 57 + goto err; 58 + } 59 + 60 + if (bpf_prog_query(cgroup_fd, BPF_CGROUP_DEVICE, 0, NULL, NULL, 61 + &prog_cnt)) { 62 + printf("Failed to query attached programs"); 63 + goto err; 64 + } 65 + 66 + /* All operations with /dev/zero and and /dev/urandom are allowed, 67 + * everything else is forbidden. 68 + */ 69 + assert(system("rm -f /tmp/test_dev_cgroup_null") == 0); 70 + assert(system("mknod /tmp/test_dev_cgroup_null c 1 3")); 71 + assert(system("rm -f /tmp/test_dev_cgroup_null") == 0); 72 + 73 + /* /dev/zero is whitelisted */ 74 + assert(system("rm -f /tmp/test_dev_cgroup_zero") == 0); 75 + assert(system("mknod /tmp/test_dev_cgroup_zero c 1 5") == 0); 76 + assert(system("rm -f /tmp/test_dev_cgroup_zero") == 0); 77 + 78 + assert(system("dd if=/dev/urandom of=/dev/zero count=64") == 0); 79 + 80 + /* src is allowed, target is forbidden */ 81 + assert(system("dd if=/dev/urandom of=/dev/full count=64")); 82 + 83 + /* src is forbidden, target is allowed */ 84 + assert(system("dd if=/dev/random of=/dev/zero count=64")); 85 + 86 + error = 0; 87 + printf("test_dev_cgroup:PASS\n"); 88 + 89 + err: 90 + cleanup_cgroup_environment(); 91 + 92 + return error; 93 + }