forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Acked-by: Alexei Starovoitov <[email protected]> Acked-by: Tejun Heo <[email protected]> Cc: Daniel Borkmann <[email protected]> Signed-off-by: David S. Miller <[email protected]>
- Loading branch information
Showing
3 changed files
with
155 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* Copyright (c) 2017 Facebook | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of version 2 of the GNU General Public | ||
* License as published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/bpf.h> | ||
#include <linux/version.h> | ||
#include "bpf_helpers.h" | ||
|
||
SEC("cgroup/dev") | ||
int bpf_prog1(struct bpf_cgroup_dev_ctx *ctx) | ||
{ | ||
short type = ctx->access_type & 0xFFFF; | ||
#ifdef DEBUG | ||
short access = ctx->access_type >> 16; | ||
char fmt[] = " %d:%d \n"; | ||
|
||
switch (type) { | ||
case BPF_DEVCG_DEV_BLOCK: | ||
fmt[0] = 'b'; | ||
break; | ||
case BPF_DEVCG_DEV_CHAR: | ||
fmt[0] = 'c'; | ||
break; | ||
default: | ||
fmt[0] = '?'; | ||
break; | ||
} | ||
|
||
if (access & BPF_DEVCG_ACC_READ) | ||
fmt[8] = 'r'; | ||
|
||
if (access & BPF_DEVCG_ACC_WRITE) | ||
fmt[9] = 'w'; | ||
|
||
if (access & BPF_DEVCG_ACC_MKNOD) | ||
fmt[10] = 'm'; | ||
|
||
bpf_trace_printk(fmt, sizeof(fmt), ctx->major, ctx->minor); | ||
#endif | ||
|
||
/* Allow access to /dev/zero and /dev/random. | ||
* Forbid everything else. | ||
*/ | ||
if (ctx->major != 1 || type != BPF_DEVCG_DEV_CHAR) | ||
return 0; | ||
|
||
switch (ctx->minor) { | ||
case 5: /* 1:5 /dev/zero */ | ||
case 9: /* 1:9 /dev/urandom */ | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
__u32 _version SEC("version") = LINUX_VERSION_CODE; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* Copyright (c) 2017 Facebook | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of version 2 of the GNU General Public | ||
* License as published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <assert.h> | ||
|
||
#include <linux/bpf.h> | ||
#include <bpf/bpf.h> | ||
#include <bpf/libbpf.h> | ||
|
||
#include "cgroup_helpers.h" | ||
|
||
#define DEV_CGROUP_PROG "./dev_cgroup.o" | ||
|
||
#define TEST_CGROUP "test-bpf-based-device-cgroup/" | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct bpf_object *obj; | ||
int error = EXIT_FAILURE; | ||
int prog_fd, cgroup_fd; | ||
__u32 prog_cnt; | ||
|
||
if (bpf_prog_load(DEV_CGROUP_PROG, BPF_PROG_TYPE_CGROUP_DEVICE, | ||
&obj, &prog_fd)) { | ||
printf("Failed to load DEV_CGROUP program\n"); | ||
goto err; | ||
} | ||
|
||
if (setup_cgroup_environment()) { | ||
printf("Failed to load DEV_CGROUP program\n"); | ||
goto err; | ||
} | ||
|
||
/* Create a cgroup, get fd, and join it */ | ||
cgroup_fd = create_and_get_cgroup(TEST_CGROUP); | ||
if (!cgroup_fd) { | ||
printf("Failed to create test cgroup\n"); | ||
goto err; | ||
} | ||
|
||
if (join_cgroup(TEST_CGROUP)) { | ||
printf("Failed to join cgroup\n"); | ||
goto err; | ||
} | ||
|
||
/* Attach bpf program */ | ||
if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, 0)) { | ||
printf("Failed to attach DEV_CGROUP program"); | ||
goto err; | ||
} | ||
|
||
if (bpf_prog_query(cgroup_fd, BPF_CGROUP_DEVICE, 0, NULL, NULL, | ||
&prog_cnt)) { | ||
printf("Failed to query attached programs"); | ||
goto err; | ||
} | ||
|
||
/* All operations with /dev/zero and and /dev/urandom are allowed, | ||
* everything else is forbidden. | ||
*/ | ||
assert(system("rm -f /tmp/test_dev_cgroup_null") == 0); | ||
assert(system("mknod /tmp/test_dev_cgroup_null c 1 3")); | ||
assert(system("rm -f /tmp/test_dev_cgroup_null") == 0); | ||
|
||
/* /dev/zero is whitelisted */ | ||
assert(system("rm -f /tmp/test_dev_cgroup_zero") == 0); | ||
assert(system("mknod /tmp/test_dev_cgroup_zero c 1 5") == 0); | ||
assert(system("rm -f /tmp/test_dev_cgroup_zero") == 0); | ||
|
||
assert(system("dd if=/dev/urandom of=/dev/zero count=64") == 0); | ||
|
||
/* src is allowed, target is forbidden */ | ||
assert(system("dd if=/dev/urandom of=/dev/full count=64")); | ||
|
||
/* src is forbidden, target is allowed */ | ||
assert(system("dd if=/dev/random of=/dev/zero count=64")); | ||
|
||
error = 0; | ||
printf("test_dev_cgroup:PASS\n"); | ||
|
||
err: | ||
cleanup_cgroup_environment(); | ||
|
||
return error; | ||
} |