eBPF-based device cgroup controller
Subsystems (7)
v3 cover eBPF-based device cgroup controller
This patchset introduces an eBPF-based device controller for cgroup v2.
Patches (1) and (2) are a preparational work required to share some code
with the existing device controller implementation.
Patch (3) is the main patch, which introduces a new bpf prog type
and all necessary infrastructure.
Patch (4) moves cgroup_helpers.c/h to use them by patch (4). Patch (5) implements an example of eBPF program which controls access
to device files and corresponding userspace test.
v3:
Renamed constants introduced by patch (3) to BPF_DEVCG_*
v2:
Added patch (1).
v1:
https://lkml.org/lkml/2017/11/1/363
Roman Gushchin (5):
device_cgroup: add DEVCG_ prefix to ACC_* and DEV_* constants
device_cgroup: prepare code for bpf-based device controller bpf, cgroup: implement eBPF-based device controller for cgroup v2
bpf: move cgroup_helpers from samples/bpf/ to
tools/testing/selftesting/bpf/
selftests/bpf: add a test for device cgroup controller
include/linux/bpf-cgroup.h | 15 ++++
include/linux/bpf_types.h | 3 +
include/linux/device_cgroup.h | 67 +++++++++++++++-
include/uapi/linux/bpf.h | 15 ++++
kernel/bpf/cgroup.c | 67 ++++++++++++++++
kernel/bpf/syscall.c | 7 ++
kernel/bpf/verifier.c | 1 +
samples/bpf/Makefile | 5 +-
security/device_cgroup.c | 91 ++++++---------------
tools/include/uapi/linux/bpf.h | 15 ++++
tools/testing/selftests/bpf/Makefile | 6 +-
.../testing/selftests}/bpf/cgroup_helpers.c | 0
.../testing/selftests}/bpf/cgroup_helpers.h | 0
tools/testing/selftests/bpf/dev_cgroup.c | 60 ++++++++++++++
tools/testing/selftests/bpf/test_dev_cgroup.c | 93 ++++++++++++++++++++++
15 files changed, 369 insertions(+), 76 deletions(-)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.c (100%)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.h (100%)
create mode 100644 tools/testing/selftests/bpf/dev_cgroup.c
create mode 100644 tools/testing/selftests/bpf/test_dev_cgroup.cSignature · 1 line
2.13.6
PATCH v3 1/5 device_cgroup: add DEVCG_ prefix to ACC_* and DEV_* constants
Rename device type and access type constants defined in security/device_cgroup.c by adding the DEVCG_ prefix.
The reason behind this renaming is to make them global namespace friendly, as they will be moved to the corresponding header file by following patches.
--- security/device_cgroup.c | 72 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 36 deletions(-)
security/device_cgroup.c +36 -36
@@ -14,14 +14,14 @@#include <linux/rcupdate.h> #include <linux/mutex.h> -#define ACC_MKNOD 1 -#define ACC_READ 2 -#define ACC_WRITE 4 -#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE) +#define DEVCG_ACC_MKNOD 1 +#define DEVCG_ACC_READ 2 +#define DEVCG_ACC_WRITE 4 +#define DEVCG_ACC_MASK (DEVCG_ACC_MKNOD | DEVCG_ACC_READ | DEVCG_ACC_WRITE) -#define DEV_BLOCK 1 -#define DEV_CHAR 2 -#define DEV_ALL 4/* this represents all devices */ +#define DEVCG_DEV_BLOCK 1 +#define DEVCG_DEV_CHAR 2 +#define DEVCG_DEV_ALL 4/* this represents all devices */ static DEFINE_MUTEX (devcgroup_mutex);
@@ -245,21 +245,21 @@ static void set_access(char *acc, short access) {int idx =0 ;memset (acc,0 ,ACCLEN ); -if (access &ACC_READ ) +if (access &DEVCG_ACC_READ ) acc[idx++] ='r' ; -if (access &ACC_WRITE ) +if (access &DEVCG_ACC_WRITE ) acc[idx++] ='w' ; -if (access &ACC_MKNOD ) +if (access &DEVCG_ACC_MKNOD ) acc[idx++] ='m' ; }static char type_to_char (short type) { -if (type ==DEV_ALL ) +if (type ==DEVCG_DEV_ALL )return 'a' ; -if (type ==DEV_CHAR ) +if (type ==DEVCG_DEV_CHAR )return 'c' ; -if (type ==DEV_BLOCK ) +if (type ==DEVCG_DEV_BLOCK )return 'b' ;return 'X' ; }
@@ -286,10 +286,10 @@ static int devcgroup_seq_show(struct seq_file *m, void *v)* This way, the file remains as a "whitelist of devices" */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { -set_access (acc,ACC_MASK ); +set_access (acc,DEVCG_ACC_MASK );set_majmin (maj, ~0 );set_majmin (min, ~0 ); -seq_printf (m,"%c %s:%s %s\n" ,type_to_char (DEV_ALL ), +seq_printf (m,"%c %s:%s %s\n" ,type_to_char (DEVCG_DEV_ALL ), maj, min, acc); }else {list_for_each_entry_rcu (ex, &devcgroup->exceptions, list) {
@@ -308,10 +308,10 @@ static int devcgroup_seq_show(struct seq_file *m, void *v)/** * match_exception - iterates the exception list trying to find a complete match * @exceptions: list of exceptions -* @type: device type (DEV_BLOCK or DEV_CHAR) +* @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR) * @major: device file major number, ~0 to match all * @minor: device file minor number, ~0 to match all -* @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) +* @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD) * * It is considered a complete match if an exception is found that will * contain the entire range of provided parameters.
@@ -324,9 +324,9 @@ static bool match_exception(struct list_head *exceptions, short type,struct dev_exception_item *ex;list_for_each_entry_rcu (ex, exceptions, list) { -if ((type &DEV_BLOCK ) && !(ex->type &DEV_BLOCK )) +if ((type &DEVCG_DEV_BLOCK ) && !(ex->type &DEVCG_DEV_BLOCK ))continue ; -if ((type &DEV_CHAR ) && !(ex->type &DEV_CHAR )) +if ((type &DEVCG_DEV_CHAR ) && !(ex->type &DEVCG_DEV_CHAR ))continue ;if (ex->major != ~0 && ex->major != major)continue ;
@@ -343,10 +343,10 @@ static bool match_exception(struct list_head *exceptions, short type,/** * match_exception_partial - iterates the exception list trying to find a partial match * @exceptions: list of exceptions -* @type: device type (DEV_BLOCK or DEV_CHAR) +* @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR) * @major: device file major number, ~0 to match all * @minor: device file minor number, ~0 to match all -* @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) +* @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD) * * It is considered a partial match if an exception's range is found to * contain *any* of the devices specified by provided parameters. This is
@@ -361,9 +361,9 @@ static bool match_exception_partial(struct list_head *exceptions, short type,struct dev_exception_item *ex;list_for_each_entry_rcu (ex, exceptions, list) { -if ((type &DEV_BLOCK ) && !(ex->type &DEV_BLOCK )) +if ((type &DEVCG_DEV_BLOCK ) && !(ex->type &DEVCG_DEV_BLOCK ))continue ; -if ((type &DEV_CHAR ) && !(ex->type &DEV_CHAR )) +if ((type &DEVCG_DEV_CHAR ) && !(ex->type &DEVCG_DEV_CHAR ))continue ;/* * We must be sure that both the exception and the provided
@@ -646,10 +646,10 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, }return 0 ;case 'b' : - ex.type =DEV_BLOCK ; + ex.type =DEVCG_DEV_BLOCK ;break ;case 'c' : - ex.type =DEV_CHAR ; + ex.type =DEVCG_DEV_CHAR ;break ;default :return -EINVAL ;
@@ -702,13 +702,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,for (b++, count =0 ; count <3 ; count++, b++) {switch (*b) {case 'r' : - ex.access |=ACC_READ ; + ex.access |=DEVCG_ACC_READ ;break ;case 'w' : - ex.access |=ACC_WRITE ; + ex.access |=DEVCG_ACC_WRITE ;break ;case 'm' : - ex.access |=ACC_MKNOD ; + ex.access |=DEVCG_ACC_MKNOD ;break ;case '\n' :case '\0' :
@@ -805,7 +805,7 @@ struct cgroup_subsys devices_cgrp_subsys = {* @type: device type * @major: device major number * @minor: device minor number -* @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD +* @access: combination of DEVCG_ACC_WRITE, DEVCG_ACC_READ and DEVCG_ACC_MKNOD * * returns 0 on success, -EPERM case the operation is not permitted */
@@ -838,13 +838,13 @@ int __devcgroup_inode_permission(struct inode *inode, int mask)short type, access =0 ;if (S_ISBLK (inode->i_mode)) - type =DEV_BLOCK ; + type =DEVCG_DEV_BLOCK ;if (S_ISCHR (inode->i_mode)) - type =DEV_CHAR ; + type =DEVCG_DEV_CHAR ;if (mask &MAY_WRITE ) - access |=ACC_WRITE ; + access |=DEVCG_ACC_WRITE ;if (mask &MAY_READ ) - access |=ACC_READ ; + access |=DEVCG_ACC_READ ;return __devcgroup_check_permission (type,imajor (inode),iminor (inode), access);
@@ -858,11 +858,11 @@ int devcgroup_inode_mknod(int mode, dev_t dev)return 0 ;if (S_ISBLK (mode)) - type =DEV_BLOCK ; + type =DEVCG_DEV_BLOCK ;else - type =DEV_CHAR ; + type =DEVCG_DEV_CHAR ;return __devcgroup_check_permission (type,MAJOR (dev),MINOR (dev), -ACC_MKNOD ); +DEVCG_ACC_MKNOD ); }
Signature · 1 line
2.13.6
Re: [PATCH v3 net-next 1/5] device_cgroup: add DEVCG_ prefix to ACC_* and DEV_* constants
Quoted 6 lines · Roman Gushchin
Rename device type and access type constants defined in
security/device_cgroup.cby adding theDEVCG_prefix.The reason behind this renaming is to make them global namespace friendly, as they will be moved to the corresponding header file by following patches.
[]
security/device_cgroup.c
Quoted 1 line
security/device_cgroup.c +0
-0
[]
security/device_cgroup.c line 20
Quoted 12 lines
security/device_cgroup.c +4
-4@@ -14,14 +14,14 @@#include <linux/rcupdate.h> #include <linux/mutex.h> -#define ACC_MKNOD 1 -#define ACC_READ 2 -#define ACC_WRITE 4 -#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE) +#define DEVCG_ACC_MKNOD 1 +#define DEVCG_ACC_READ 2 +#define DEVCG_ACC_WRITE 4 +#define DEVCG_ACC_MASK (DEVCG_ACC_MKNOD | DEVCG_ACC_READ | DEVCG_ACC_WRITE)
trivia:
major and minor are u32 but all the
type and access uses seem to be "short"
Perhaps u16 (or __u16 if uapi public) instead?
Quoted 37 lines
security/device_cgroup.c +9
-9-#define DEV_BLOCK 1 -#define DEV_CHAR 2 -#define DEV_ALL 4/* this represents all devices */ +#define DEVCG_DEV_BLOCK 1 +#define DEVCG_DEV_CHAR 2 +#define DEVCG_DEV_ALL 4/* this represents all devices */ static DEFINE_MUTEX (devcgroup_mutex);@@ -245,21 +245,21 @@ static void set_access(char *acc, short access) {int idx =0 ;memset (acc,0 ,ACCLEN ); -if (access &ACC_READ ) +if (access &DEVCG_ACC_READ ) acc[idx++] ='r' ; -if (access &ACC_WRITE ) +if (access &DEVCG_ACC_WRITE ) acc[idx++] ='w' ; -if (access &ACC_MKNOD ) +if (access &DEVCG_ACC_MKNOD ) acc[idx++] ='m' ; }static char type_to_char (short type) { -if (type ==DEV_ALL ) +if (type ==DEVCG_DEV_ALL )return 'a' ; -if (type ==DEV_CHAR ) +if (type ==DEVCG_DEV_CHAR )return 'c' ; -if (type ==DEV_BLOCK ) +if (type ==DEVCG_DEV_BLOCK )return 'b' ;return 'X' ; }
Re: [PATCH v3 net-next 1/5] device_cgroup: add DEVCG_ prefix to ACC_* and DEV_* constants
Quoted 25 lines · Joe Perches
Quoted 6 lines · Roman Gushchin
Rename device type and access type constants defined in
security/device_cgroup.cby adding theDEVCG_prefix.The reason behind this renaming is to make them global namespace friendly, as they will be moved to the corresponding header file by following patches.
[]
security/device_cgroup.c
Quoted 1 line
security/device_cgroup.c +0
-0[]
security/device_cgroup.c line 20
Quoted 12 lines
security/device_cgroup.c +4
-4@@ -14,14 +14,14 @@#include <linux/rcupdate.h> #include <linux/mutex.h> -#define ACC_MKNOD 1 -#define ACC_READ 2 -#define ACC_WRITE 4 -#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE) +#define DEVCG_ACC_MKNOD 1 +#define DEVCG_ACC_READ 2 +#define DEVCG_ACC_WRITE 4 +#define DEVCG_ACC_MASK (DEVCG_ACC_MKNOD | DEVCG_ACC_READ | DEVCG_ACC_WRITE)trivia:
Quoted 4 lines
major and minor are u32 but all the
type and access uses seem to be "short"Perhaps u16 (or
__u16if uapi public) instead?
It was so for a while, and it doesn't seem to be related with this patchset. So, I'd prefer to change this in a separate patch.
Thanks!
PATCH v3 2/5 device_cgroup: prepare code for bpf-based device controller
In reply to Roman GushchinThis is non-functional change to prepare the device cgroup code for adding eBPF-based controller for cgroups v2.
The patch performs the following changes:
1) __devcgroup_inode_permission() and devcgroup_inode_mknod() are moving to the device-cgroup.h and converting into static inline.
2) __devcgroup_check_permission() is exported.
3) devcgroup_check_permission() wrapper is introduced to be used by both existing and new bpf-based implementations.
--- include/linux/device_cgroup.h | 61 ++++++++++++++++++++++++++++++++++++++++--- security/device_cgroup.c | 47 ++------------------------------- 2 files changed, 59 insertions(+), 49 deletions(-)
include/linux/device_cgroup.h +57 -4
@@ -1,16 +1,69 @@#include <linux/fs.h> +#define DEVCG_ACC_MKNOD 1 +#define DEVCG_ACC_READ 2 +#define DEVCG_ACC_WRITE 4 +#define DEVCG_ACC_MASK (DEVCG_ACC_MKNOD | DEVCG_ACC_READ | DEVCG_ACC_WRITE) + +#define DEVCG_DEV_BLOCK 1 +#define DEVCG_DEV_CHAR 2 +#define DEVCG_DEV_ALL 4/* this represents all devices */ + +#ifdef CONFIG_CGROUP_DEVICE +extern int __devcgroup_check_permission (short type,u32 major,u32 minor, +short access); +#else +static inline int __devcgroup_check_permission (short type,u32 major,u32 minor, +short access) +{return 0 ; } +#endif +#ifdef CONFIG_CGROUP_DEVICE -extern int __devcgroup_inode_permission (struct inode *inode,int mask); -extern int devcgroup_inode_mknod (int mode,dev_t dev); +static inline int devcgroup_check_permission (short type,u32 major,u32 minor, +short access) +{ +return __devcgroup_check_permission (type, major, minor, access); +} +static inline int devcgroup_inode_permission (struct inode *inode,int mask) { +short type, access =0 ; +if (likely (!inode->i_rdev))return 0 ; -if (!S_ISBLK (inode->i_mode) && !S_ISCHR (inode->i_mode)) + +if (S_ISBLK (inode->i_mode)) + type =DEVCG_DEV_BLOCK ; +else if (S_ISCHR (inode->i_mode)) + type =DEVCG_DEV_CHAR ; +else return 0 ; -return __devcgroup_inode_permission (inode, mask); + +if (mask &MAY_WRITE ) + access |=DEVCG_ACC_WRITE ; +if (mask &MAY_READ ) + access |=DEVCG_ACC_READ ; + +return devcgroup_check_permission (type,imajor (inode),iminor (inode), + access); } + +static inline int devcgroup_inode_mknod (int mode,dev_t dev) +{ +short type; + +if (!S_ISBLK (mode) && !S_ISCHR (mode)) +return 0 ; + +if (S_ISBLK (mode)) + type =DEVCG_DEV_BLOCK ; +else + type =DEVCG_DEV_CHAR ; + +return devcgroup_check_permission (type,MAJOR (dev),MINOR (dev), +DEVCG_ACC_MKNOD ); +} +#else static inline int devcgroup_inode_permission (struct inode *inode,int mask) {return 0 ; }
security/device_cgroup.c +2 -45
62 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v3 3/5 bpf, cgroup: implement eBPF-based device controller for cgroup v2
In reply to Roman GushchinCgroup v2 lacks the device controller, provided by cgroup v1. This patch adds a new eBPF program type, which in combination of previously added ability to attach multiple eBPF programs to a cgroup, will provide a similar functionality, but with some additional flexibility.
This patch introduces a BPF_PROG_TYPE_CGROUP_DEVICE program type. A program takes major and minor device numbers, device type (block/character) and access type (mknod/read/write) as parameters and returns an integer which defines if the operation should be allowed or terminated with -EPERM.
--- include/linux/bpf-cgroup.h | 15 ++++++++++ include/linux/bpf_types.h | 3 ++ include/linux/device_cgroup.h | 8 ++++- include/uapi/linux/bpf.h | 15 ++++++++++ kernel/bpf/cgroup.c | 67 ++++++++++++++++++++++++++++++++++++++++++ kernel/bpf/syscall.c | 7 +++++ kernel/bpf/verifier.c | 1 + tools/include/uapi/linux/bpf.h | 15 ++++++++++ 8 files changed, 130 insertions(+), 1 deletion(-)
include/linux/bpf-cgroup.h +15 -0
@@ -66,6 +66,9 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk,struct bpf_sock_ops_kern *sock_ops, enum bpf_attach_type type); +int __cgroup_bpf_check_dev_permission (short dev_type,u32 major,u32 minor, +short access,enum bpf_attach_type type); +/* Wrappers for __cgroup_bpf_run_filter_skb() guarded by cgroup_bpf_enabled. */ #define BPF_CGROUP_RUN_PROG_INET_INGRESS (sk, skb) \ ({ \
@@ -111,6 +114,17 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, } \ __ret; \ }) + +#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP (type, major, minor, access) \ +({ \ + int __ret = 0; \ + if (cgroup_bpf_enabled) \ + __ret = __cgroup_bpf_check_dev_permission(type, major, minor, \ + access, \ + BPF_CGROUP_DEVICE); \ + \ + __ret; \ +})#else struct cgroup_bpf {};
@@ -121,6 +135,7 @@ static inline int cgroup_bpf_inherit(struct cgroup *cgrp) { return 0; }#define BPF_CGROUP_RUN_PROG_INET_EGRESS (sk,skb) ({ 0; })#define BPF_CGROUP_RUN_PROG_INET_SOCK (sk) ({ 0; })#define BPF_CGROUP_RUN_PROG_SOCK_OPS (sock_ops) ({ 0; }) +#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP (type,major,minor,access) ({ 0; })#endif /* CONFIG_CGROUP_BPF */
include/linux/bpf_types.h +3 -0
@@ -18,6 +18,9 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe) BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint) BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event)#endif +#ifdef CONFIG_CGROUP_BPF +BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_DEVICE, cg_dev) +#endif BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)BPF_MAP_TYPE (BPF_MAP_TYPE_PERCPU_ARRAY , percpu_array_map_ops)
include/linux/device_cgroup.h +7 -1
@@ -1,4 +1,5 @@#include <linux/fs.h> +#include <linux/bpf-cgroup.h> #define DEVCG_ACC_MKNOD 1#define DEVCG_ACC_READ 2
@@ -18,10 +19,15 @@ static inline int __devcgroup_check_permission(short type, u32 major, u32 minor, {return 0 ; }#endif -#ifdef CONFIG_CGROUP_DEVICE +#if defined(CONFIG_CGROUP_DEVICE ) || defined(CONFIG_CGROUP_BPF )static inline int devcgroup_check_permission (short type,u32 major,u32 minor,short access) { +int rc =BPF_CGROUP_RUN_PROG_DEVICE_CGROUP (type, major, minor, access); + +if (rc) +return -EPERM ; +return __devcgroup_check_permission (type, major, minor, access); }
include/uapi/linux/bpf.h +15 -0
@@ -131,6 +131,7 @@ enum bpf_prog_type {BPF_PROG_TYPE_LWT_XMIT ,BPF_PROG_TYPE_SOCK_OPS ,BPF_PROG_TYPE_SK_SKB , + BPF_PROG_TYPE_CGROUP_DEVICE, }; enum bpf_attach_type {
@@ -140,6 +141,7 @@ enum bpf_attach_type {BPF_CGROUP_SOCK_OPS ,BPF_SK_SKB_STREAM_PARSER ,BPF_SK_SKB_STREAM_VERDICT , +BPF_CGROUP_DEVICE , __MAX_BPF_ATTACH_TYPE };
@@ -984,4 +986,17 @@ struct bpf_perf_event_value { __u64 running; }; +#define BPF_DEVCG_ACC_MKNOD (1ULL << 0) +#define BPF_DEVCG_ACC_READ (1ULL << 1) +#define BPF_DEVCG_ACC_WRITE (1ULL << 2) + +#define BPF_DEVCG_DEV_BLOCK (1ULL << 0) +#define BPF_DEVCG_DEV_CHAR (1ULL << 1) + +struct bpf_cgroup_dev_ctx { +__u32 access_type;/* (access << 16) | type */ +__u32 major; +__u32 minor; +}; +#endif /* _UAPI__LINUX_BPF_H__ */
kernel/bpf/cgroup.c +67 -0
70 lines not on this page · raw message
kernel/bpf/syscall.c +7 -0
@@ -1291,6 +1291,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)case BPF_CGROUP_SOCK_OPS : ptype =BPF_PROG_TYPE_SOCK_OPS ;break ; +case BPF_CGROUP_DEVICE : + ptype =BPF_PROG_TYPE_CGROUP_DEVICE ; +break ;case BPF_SK_SKB_STREAM_PARSER :case BPF_SK_SKB_STREAM_VERDICT :return sockmap_get_from_fd (attr, true);
@@ -1343,6 +1346,9 @@ static int bpf_prog_detach(const union bpf_attr *attr)case BPF_CGROUP_SOCK_OPS : ptype =BPF_PROG_TYPE_SOCK_OPS ;break ; +case BPF_CGROUP_DEVICE : + ptype =BPF_PROG_TYPE_CGROUP_DEVICE ; +break ;case BPF_SK_SKB_STREAM_PARSER :case BPF_SK_SKB_STREAM_VERDICT :return sockmap_get_from_fd (attr, false);
@@ -1385,6 +1391,7 @@ static int bpf_prog_query(const union bpf_attr *attr,case BPF_CGROUP_INET_EGRESS :case BPF_CGROUP_INET_SOCK_CREATE :case BPF_CGROUP_SOCK_OPS : +case BPF_CGROUP_DEVICE :break ;default :return -EINVAL ;
kernel/bpf/verifier.c +1 -0
@@ -3100,6 +3100,7 @@ static int check_return_code(struct bpf_verifier_env *env)case BPF_PROG_TYPE_CGROUP_SKB :case BPF_PROG_TYPE_CGROUP_SOCK :case BPF_PROG_TYPE_SOCK_OPS : +case BPF_PROG_TYPE_CGROUP_DEVICE :break ;default :return 0 ;
tools/include/uapi/linux/bpf.h +15 -0
@@ -131,6 +131,7 @@ enum bpf_prog_type {BPF_PROG_TYPE_LWT_XMIT ,BPF_PROG_TYPE_SOCK_OPS ,BPF_PROG_TYPE_SK_SKB , + BPF_PROG_TYPE_CGROUP_DEVICE, }; enum bpf_attach_type {
@@ -140,6 +141,7 @@ enum bpf_attach_type {BPF_CGROUP_SOCK_OPS ,BPF_SK_SKB_STREAM_PARSER ,BPF_SK_SKB_STREAM_VERDICT , +BPF_CGROUP_DEVICE , __MAX_BPF_ATTACH_TYPE };
@@ -984,4 +986,17 @@ struct bpf_perf_event_value { __u64 running; }; +#define BPF_DEVCG_ACC_MKNOD (1ULL << 0) +#define BPF_DEVCG_ACC_READ (1ULL << 1) +#define BPF_DEVCG_ACC_WRITE (1ULL << 2) + +#define BPF_DEVCG_DEV_BLOCK (1ULL << 0) +#define BPF_DEVCG_DEV_CHAR (1ULL << 1) + +struct bpf_cgroup_dev_ctx { +__u32 access_type;/* (access << 16) | type */ +__u32 major; +__u32 minor; +}; +#endif /* _UAPI__LINUX_BPF_H__ */
Signature · 1 line
2.13.6
PATCH v3 4/5 bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/
In reply to Roman GushchinThe purpose of this move is to use these files in bpf tests.
---
samples/bpf/Makefile | 5 +++--
tools/testing/selftests/bpf/Makefile | 2 +-
{samples => tools/testing/selftests}/bpf/cgroup_helpers.c | 0
{samples => tools/testing/selftests}/bpf/cgroup_helpers.h | 0
4 files changed, 4 insertions(+), 3 deletions(-)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.c (100%)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.h (100%)samples/bpf/Makefile +3 -2
@@ -45,6 +45,7 @@ hostprogs-y += syscall_tp # Libbpf dependencies LIBBPF := ../../tools/lib/bpf/bpf.o +CGROUP_HELPERS := ../../tools/testing/selftests/bpf/cgroup_helpers.o test_lru_dist-objs := test_lru_dist.o $(LIBBPF) sock_example-objs := sock_example.o $(LIBBPF)
@@ -68,13 +69,13 @@ map_perf_test-objs := bpf_load.o $(LIBBPF) map_perf_test_user.o test_overhead-objs := bpf_load.o $(LIBBPF) test_overhead_user.o test_cgrp2_array_pin-objs := $(LIBBPF) test_cgrp2_array_pin.o test_cgrp2_attach-objs := $(LIBBPF) test_cgrp2_attach.o -test_cgrp2_attach2-objs := $(LIBBPF) test_cgrp2_attach2.o cgroup_helpers.o +test_cgrp2_attach2-objs := $(LIBBPF) test_cgrp2_attach2.o $(CGROUP_HELPERS) test_cgrp2_sock-objs := $(LIBBPF) test_cgrp2_sock.o test_cgrp2_sock2-objs := bpf_load.o $(LIBBPF) test_cgrp2_sock2.o xdp1-objs := bpf_load.o $(LIBBPF) xdp1_user.o # reuse xdp1 source intentionally xdp2-objs := bpf_load.o $(LIBBPF) xdp1_user.o -test_current_task_under_cgroup-objs := bpf_load.o $(LIBBPF) cgroup_helpers.o \ +test_current_task_under_cgroup-objs := bpf_load.o $(LIBBPF) $(CGROUP_HELPERS) \ test_current_task_under_cgroup_user.o trace_event-objs := bpf_load.o $(LIBBPF) trace_event_user.o sampleip-objs := bpf_load.o $(LIBBPF) sampleip_user.o
tools/testing/selftests/bpf/Makefile +1 -1
@@ -22,7 +22,7 @@ TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh include ../lib.mk -BPFOBJ := $(OUTPUT)/libbpf.a +BPFOBJ := $(OUTPUT)/libbpf.a $(OUTPUT)/cgroup_helpers.c $(TEST_GEN_PROGS): $(BPFOBJ)
tools/testing/selftests/bpf/cgroup_helpers.c renamed from samples/bpf/cgroup_helpers.c +0 -0
tools/testing/selftests/bpf/cgroup_helpers.h renamed from samples/bpf/cgroup_helpers.h +0 -0
Signature · 1 line
2.13.6
PATCH v3 5/5 selftests/bpf: add a test for device cgroup controller
In reply to Roman GushchinAdd 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)
--- tools/testing/selftests/bpf/Makefile | 4 +- tools/testing/selftests/bpf/dev_cgroup.c | 60 +++++++++++++++++ tools/testing/selftests/bpf/test_dev_cgroup.c | 93 +++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/dev_cgroup.c create mode 100644 tools/testing/selftests/bpf/test_dev_cgroup.c
tools/testing/selftests/bpf/Makefile +2 -2
@@ -12,11 +12,11 @@ CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../i LDLIBS += -lcap -lelf TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_align test_verifier_log + test_align test_verifier_log test_dev_cgroup TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ - sockmap_verdict_prog.o + sockmap_verdict_prog.o dev_cgroup.o TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh
tools/testing/selftests/bpf/dev_cgroup.c new file +60 -0
60 lines not on this page · raw message
tools/testing/selftests/bpf/test_dev_cgroup.c new file +93 -0
93 lines not on this page · raw message
Signature · 1 line
2.13.6
David Miller
maintainerFrom: Roman Gushchin <[email protected]>
Date: Thu, 2 Nov 2017 13:15:25 -0400
Quoted 2 lines
This patchset introduces an eBPF-based device controller for cgroup v2.
This doesn't apply cleanly to net-next, please respin.
Thank you.
v3 cover eBPF-based device cgroup controller
This patchset introduces an eBPF-based device controller for cgroup v2.
Patches (1) and (2) are a preparational work required to share some code
with the existing device controller implementation.
Patch (3) is the main patch, which introduces a new bpf prog type
and all necessary infrastructure.
Patch (4) moves cgroup_helpers.c/h to use them by patch (4). Patch (5) implements an example of eBPF program which controls access
to device files and corresponding userspace test.
v3:
Renamed constants introduced by patch (3) to BPF_DEVCG_*
v2:
Added patch (1).
v1:
https://lkml.org/lkml/2017/11/1/363
Roman Gushchin (5):
device_cgroup: add DEVCG_ prefix to ACC_* and DEV_* constants
device_cgroup: prepare code for bpf-based device controller bpf, cgroup: implement eBPF-based device controller for cgroup v2
bpf: move cgroup_helpers from samples/bpf/ to
tools/testing/selftesting/bpf/
selftests/bpf: add a test for device cgroup controller
include/linux/bpf-cgroup.h | 15 ++++
include/linux/bpf_types.h | 3 +
include/linux/device_cgroup.h | 67 +++++++++++++++-
include/uapi/linux/bpf.h | 15 ++++
kernel/bpf/cgroup.c | 67 ++++++++++++++++
kernel/bpf/syscall.c | 7 ++
kernel/bpf/verifier.c | 1 +
samples/bpf/Makefile | 5 +-
security/device_cgroup.c | 91 ++++++---------------
tools/include/uapi/linux/bpf.h | 15 ++++
tools/testing/selftests/bpf/Makefile | 6 +-
.../testing/selftests}/bpf/cgroup_helpers.c | 0
.../testing/selftests}/bpf/cgroup_helpers.h | 0
tools/testing/selftests/bpf/dev_cgroup.c | 60 ++++++++++++++
tools/testing/selftests/bpf/test_dev_cgroup.c | 93 ++++++++++++++++++++++
15 files changed, 369 insertions(+), 76 deletions(-)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.c (100%)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.h (100%)
create mode 100644 tools/testing/selftests/bpf/dev_cgroup.c
create mode 100644 tools/testing/selftests/bpf/test_dev_cgroup.cSignature · 1 line
2.13.6
PATCH v3 1/5 device_cgroup: add DEVCG_ prefix to ACC_* and DEV_* constants
Rename device type and access type constants defined in security/device_cgroup.c by adding the DEVCG_ prefix.
The reason behind this renaming is to make them global namespace friendly, as they will be moved to the corresponding header file by following patches.
--- security/device_cgroup.c | 72 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 36 deletions(-)
security/device_cgroup.c +36 -36
@@ -15,14 +15,14 @@#include <linux/rcupdate.h> #include <linux/mutex.h> -#define ACC_MKNOD 1 -#define ACC_READ 2 -#define ACC_WRITE 4 -#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE) +#define DEVCG_ACC_MKNOD 1 +#define DEVCG_ACC_READ 2 +#define DEVCG_ACC_WRITE 4 +#define DEVCG_ACC_MASK (DEVCG_ACC_MKNOD | DEVCG_ACC_READ | DEVCG_ACC_WRITE) -#define DEV_BLOCK 1 -#define DEV_CHAR 2 -#define DEV_ALL 4/* this represents all devices */ +#define DEVCG_DEV_BLOCK 1 +#define DEVCG_DEV_CHAR 2 +#define DEVCG_DEV_ALL 4/* this represents all devices */ static DEFINE_MUTEX (devcgroup_mutex);
@@ -246,21 +246,21 @@ static void set_access(char *acc, short access) {int idx =0 ;memset (acc,0 ,ACCLEN ); -if (access &ACC_READ ) +if (access &DEVCG_ACC_READ ) acc[idx++] ='r' ; -if (access &ACC_WRITE ) +if (access &DEVCG_ACC_WRITE ) acc[idx++] ='w' ; -if (access &ACC_MKNOD ) +if (access &DEVCG_ACC_MKNOD ) acc[idx++] ='m' ; }static char type_to_char (short type) { -if (type ==DEV_ALL ) +if (type ==DEVCG_DEV_ALL )return 'a' ; -if (type ==DEV_CHAR ) +if (type ==DEVCG_DEV_CHAR )return 'c' ; -if (type ==DEV_BLOCK ) +if (type ==DEVCG_DEV_BLOCK )return 'b' ;return 'X' ; }
@@ -287,10 +287,10 @@ static int devcgroup_seq_show(struct seq_file *m, void *v)* This way, the file remains as a "whitelist of devices" */ if (devcgroup->behavior ==DEVCG_DEFAULT_ALLOW ) { -set_access (acc,ACC_MASK ); +set_access (acc,DEVCG_ACC_MASK );set_majmin (maj, ~0 );set_majmin (min, ~0 ); -seq_printf (m,"%c %s:%s %s\n" ,type_to_char (DEV_ALL ), +seq_printf (m,"%c %s:%s %s\n" ,type_to_char (DEVCG_DEV_ALL ), maj, min, acc); }else {list_for_each_entry_rcu (ex, &devcgroup->exceptions, list) {
@@ -309,10 +309,10 @@ static int devcgroup_seq_show(struct seq_file *m, void *v)/** * match_exception - iterates the exception list trying to find a complete match * @exceptions: list of exceptions -* @type: device type (DEV_BLOCK or DEV_CHAR) +* @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR) * @major: device file major number, ~0 to match all * @minor: device file minor number, ~0 to match all -* @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) +* @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD) * * It is considered a complete match if an exception is found that will * contain the entire range of provided parameters.
@@ -325,9 +325,9 @@ static bool match_exception(struct list_head *exceptions, short type,struct dev_exception_item *ex;list_for_each_entry_rcu (ex, exceptions, list) { -if ((type &DEV_BLOCK ) && !(ex->type &DEV_BLOCK )) +if ((type &DEVCG_DEV_BLOCK ) && !(ex->type &DEVCG_DEV_BLOCK ))continue ; -if ((type &DEV_CHAR ) && !(ex->type &DEV_CHAR )) +if ((type &DEVCG_DEV_CHAR ) && !(ex->type &DEVCG_DEV_CHAR ))continue ;if (ex->major != ~0 && ex->major != major)continue ;
@@ -344,10 +344,10 @@ static bool match_exception(struct list_head *exceptions, short type,/** * match_exception_partial - iterates the exception list trying to find a partial match * @exceptions: list of exceptions -* @type: device type (DEV_BLOCK or DEV_CHAR) +* @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR) * @major: device file major number, ~0 to match all * @minor: device file minor number, ~0 to match all -* @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) +* @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD) * * It is considered a partial match if an exception's range is found to * contain *any* of the devices specified by provided parameters. This is
@@ -362,9 +362,9 @@ static bool match_exception_partial(struct list_head *exceptions, short type,struct dev_exception_item *ex;list_for_each_entry_rcu (ex, exceptions, list) { -if ((type &DEV_BLOCK ) && !(ex->type &DEV_BLOCK )) +if ((type &DEVCG_DEV_BLOCK ) && !(ex->type &DEVCG_DEV_BLOCK ))continue ; -if ((type &DEV_CHAR ) && !(ex->type &DEV_CHAR )) +if ((type &DEVCG_DEV_CHAR ) && !(ex->type &DEVCG_DEV_CHAR ))continue ;/* * We must be sure that both the exception and the provided
@@ -647,10 +647,10 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, }return 0 ;case 'b' : - ex.type =DEV_BLOCK ; + ex.type =DEVCG_DEV_BLOCK ;break ;case 'c' : - ex.type =DEV_CHAR ; + ex.type =DEVCG_DEV_CHAR ;break ;default :return -EINVAL ;
@@ -703,13 +703,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,for (b++, count =0 ; count <3 ; count++, b++) {switch (*b) {case 'r' : - ex.access |=ACC_READ ; + ex.access |=DEVCG_ACC_READ ;break ;case 'w' : - ex.access |=ACC_WRITE ; + ex.access |=DEVCG_ACC_WRITE ;break ;case 'm' : - ex.access |=ACC_MKNOD ; + ex.access |=DEVCG_ACC_MKNOD ;break ;case '\n' :case '\0' :
@@ -806,7 +806,7 @@ struct cgroup_subsys devices_cgrp_subsys = {* @type: device type * @major: device major number * @minor: device minor number -* @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD +* @access: combination of DEVCG_ACC_WRITE, DEVCG_ACC_READ and DEVCG_ACC_MKNOD * * returns 0 on success, -EPERM case the operation is not permitted */
@@ -839,13 +839,13 @@ int __devcgroup_inode_permission(struct inode *inode, int mask)short type, access =0 ;if (S_ISBLK (inode->i_mode)) - type =DEV_BLOCK ; + type =DEVCG_DEV_BLOCK ;if (S_ISCHR (inode->i_mode)) - type =DEV_CHAR ; + type =DEVCG_DEV_CHAR ;if (mask &MAY_WRITE ) - access |=ACC_WRITE ; + access |=DEVCG_ACC_WRITE ;if (mask &MAY_READ ) - access |=ACC_READ ; + access |=DEVCG_ACC_READ ;return __devcgroup_check_permission (type,imajor (inode),iminor (inode), access);
@@ -859,11 +859,11 @@ int devcgroup_inode_mknod(int mode, dev_t dev)return 0 ;if (S_ISBLK (mode)) - type =DEV_BLOCK ; + type =DEVCG_DEV_BLOCK ;else - type =DEV_CHAR ; + type =DEVCG_DEV_CHAR ;return __devcgroup_check_permission (type,MAJOR (dev),MINOR (dev), -ACC_MKNOD ); +DEVCG_ACC_MKNOD ); }
Signature · 1 line
2.13.6
PATCH v3 2/5 device_cgroup: prepare code for bpf-based device controller
In reply to Roman GushchinThis is non-functional change to prepare the device cgroup code for adding eBPF-based controller for cgroups v2.
The patch performs the following changes:
1) __devcgroup_inode_permission() and devcgroup_inode_mknod() are moving to the device-cgroup.h and converting into static inline.
2) __devcgroup_check_permission() is exported.
3) devcgroup_check_permission() wrapper is introduced to be used by both existing and new bpf-based implementations.
--- include/linux/device_cgroup.h | 61 ++++++++++++++++++++++++++++++++++++++++--- security/device_cgroup.c | 47 ++------------------------------- 2 files changed, 59 insertions(+), 49 deletions(-)
include/linux/device_cgroup.h +57 -4
@@ -1,17 +1,70 @@/* SPDX-License-Identifier: GPL-2.0 */ #include <linux/fs.h> +#define DEVCG_ACC_MKNOD 1 +#define DEVCG_ACC_READ 2 +#define DEVCG_ACC_WRITE 4 +#define DEVCG_ACC_MASK (DEVCG_ACC_MKNOD | DEVCG_ACC_READ | DEVCG_ACC_WRITE) + +#define DEVCG_DEV_BLOCK 1 +#define DEVCG_DEV_CHAR 2 +#define DEVCG_DEV_ALL 4/* this represents all devices */ + +#ifdef CONFIG_CGROUP_DEVICE +extern int __devcgroup_check_permission (short type,u32 major,u32 minor, +short access); +#else +static inline int __devcgroup_check_permission (short type,u32 major,u32 minor, +short access) +{return 0 ; } +#endif +#ifdef CONFIG_CGROUP_DEVICE -extern int __devcgroup_inode_permission (struct inode *inode,int mask); -extern int devcgroup_inode_mknod (int mode,dev_t dev); +static inline int devcgroup_check_permission (short type,u32 major,u32 minor, +short access) +{ +return __devcgroup_check_permission (type, major, minor, access); +} +static inline int devcgroup_inode_permission (struct inode *inode,int mask) { +short type, access =0 ; +if (likely (!inode->i_rdev))return 0 ; -if (!S_ISBLK (inode->i_mode) && !S_ISCHR (inode->i_mode)) + +if (S_ISBLK (inode->i_mode)) + type =DEVCG_DEV_BLOCK ; +else if (S_ISCHR (inode->i_mode)) + type =DEVCG_DEV_CHAR ; +else return 0 ; -return __devcgroup_inode_permission (inode, mask); + +if (mask &MAY_WRITE ) + access |=DEVCG_ACC_WRITE ; +if (mask &MAY_READ ) + access |=DEVCG_ACC_READ ; + +return devcgroup_check_permission (type,imajor (inode),iminor (inode), + access); } + +static inline int devcgroup_inode_mknod (int mode,dev_t dev) +{ +short type; + +if (!S_ISBLK (mode) && !S_ISCHR (mode)) +return 0 ; + +if (S_ISBLK (mode)) + type =DEVCG_DEV_BLOCK ; +else + type =DEVCG_DEV_CHAR ; + +return devcgroup_check_permission (type,MAJOR (dev),MINOR (dev), +DEVCG_ACC_MKNOD ); +} +#else static inline int devcgroup_inode_permission (struct inode *inode,int mask) {return 0 ; }
security/device_cgroup.c +2 -45
62 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH v3 3/5 bpf, cgroup: implement eBPF-based device controller for cgroup v2
In reply to Roman GushchinCgroup v2 lacks the device controller, provided by cgroup v1. This patch adds a new eBPF program type, which in combination of previously added ability to attach multiple eBPF programs to a cgroup, will provide a similar functionality, but with some additional flexibility.
This patch introduces a BPF_PROG_TYPE_CGROUP_DEVICE program type. A program takes major and minor device numbers, device type (block/character) and access type (mknod/read/write) as parameters and returns an integer which defines if the operation should be allowed or terminated with -EPERM.
--- include/linux/bpf-cgroup.h | 15 ++++++++++ include/linux/bpf_types.h | 3 ++ include/linux/device_cgroup.h | 8 ++++- include/uapi/linux/bpf.h | 15 ++++++++++ kernel/bpf/cgroup.c | 67 ++++++++++++++++++++++++++++++++++++++++++ kernel/bpf/syscall.c | 7 +++++ kernel/bpf/verifier.c | 1 + tools/include/uapi/linux/bpf.h | 15 ++++++++++ 8 files changed, 130 insertions(+), 1 deletion(-)
include/linux/bpf-cgroup.h +15 -0
@@ -67,6 +67,9 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk,struct bpf_sock_ops_kern *sock_ops, enum bpf_attach_type type); +int __cgroup_bpf_check_dev_permission (short dev_type,u32 major,u32 minor, +short access,enum bpf_attach_type type); +/* Wrappers for __cgroup_bpf_run_filter_skb() guarded by cgroup_bpf_enabled. */ #define BPF_CGROUP_RUN_PROG_INET_INGRESS (sk, skb) \ ({ \
@@ -112,6 +115,17 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk, } \ __ret; \ }) + +#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP (type, major, minor, access) \ +({ \ + int __ret = 0; \ + if (cgroup_bpf_enabled) \ + __ret = __cgroup_bpf_check_dev_permission(type, major, minor, \ + access, \ + BPF_CGROUP_DEVICE); \ + \ + __ret; \ +})#else struct cgroup_bpf {};
@@ -122,6 +136,7 @@ static inline int cgroup_bpf_inherit(struct cgroup *cgrp) { return 0; }#define BPF_CGROUP_RUN_PROG_INET_EGRESS (sk,skb) ({ 0; })#define BPF_CGROUP_RUN_PROG_INET_SOCK (sk) ({ 0; })#define BPF_CGROUP_RUN_PROG_SOCK_OPS (sock_ops) ({ 0; }) +#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP (type,major,minor,access) ({ 0; })#endif /* CONFIG_CGROUP_BPF */
include/linux/bpf_types.h +3 -0
@@ -19,6 +19,9 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_KPROBE, kprobe) BPF_PROG_TYPE(BPF_PROG_TYPE_TRACEPOINT, tracepoint) BPF_PROG_TYPE(BPF_PROG_TYPE_PERF_EVENT, perf_event)#endif +#ifdef CONFIG_CGROUP_BPF +BPF_PROG_TYPE(BPF_PROG_TYPE_CGROUP_DEVICE, cg_dev) +#endif BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)BPF_MAP_TYPE (BPF_MAP_TYPE_PERCPU_ARRAY , percpu_array_map_ops)
include/linux/device_cgroup.h +7 -1
@@ -1,5 +1,6 @@/* SPDX-License-Identifier: GPL-2.0 */ #include <linux/fs.h> +#include <linux/bpf-cgroup.h> #define DEVCG_ACC_MKNOD 1#define DEVCG_ACC_READ 2
@@ -19,10 +20,15 @@ static inline int __devcgroup_check_permission(short type, u32 major, u32 minor, {return 0 ; }#endif -#ifdef CONFIG_CGROUP_DEVICE +#if defined(CONFIG_CGROUP_DEVICE ) || defined(CONFIG_CGROUP_BPF )static inline int devcgroup_check_permission (short type,u32 major,u32 minor,short access) { +int rc =BPF_CGROUP_RUN_PROG_DEVICE_CGROUP (type, major, minor, access); + +if (rc) +return -EPERM ; +return __devcgroup_check_permission (type, major, minor, access); }
include/uapi/linux/bpf.h +15 -0
@@ -132,6 +132,7 @@ enum bpf_prog_type {BPF_PROG_TYPE_LWT_XMIT ,BPF_PROG_TYPE_SOCK_OPS ,BPF_PROG_TYPE_SK_SKB , + BPF_PROG_TYPE_CGROUP_DEVICE, }; enum bpf_attach_type {
@@ -141,6 +142,7 @@ enum bpf_attach_type {BPF_CGROUP_SOCK_OPS ,BPF_SK_SKB_STREAM_PARSER ,BPF_SK_SKB_STREAM_VERDICT , +BPF_CGROUP_DEVICE , __MAX_BPF_ATTACH_TYPE };
@@ -984,4 +986,17 @@ struct bpf_perf_event_value { __u64 running; }; +#define BPF_DEVCG_ACC_MKNOD (1ULL << 0) +#define BPF_DEVCG_ACC_READ (1ULL << 1) +#define BPF_DEVCG_ACC_WRITE (1ULL << 2) + +#define BPF_DEVCG_DEV_BLOCK (1ULL << 0) +#define BPF_DEVCG_DEV_CHAR (1ULL << 1) + +struct bpf_cgroup_dev_ctx { +__u32 access_type;/* (access << 16) | type */ +__u32 major; +__u32 minor; +}; +#endif /* _UAPI__LINUX_BPF_H__ */
kernel/bpf/cgroup.c +67 -0
70 lines not on this page · raw message
kernel/bpf/syscall.c +7 -0
@@ -1291,6 +1291,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)case BPF_CGROUP_SOCK_OPS : ptype =BPF_PROG_TYPE_SOCK_OPS ;break ; +case BPF_CGROUP_DEVICE : + ptype =BPF_PROG_TYPE_CGROUP_DEVICE ; +break ;case BPF_SK_SKB_STREAM_PARSER :case BPF_SK_SKB_STREAM_VERDICT :return sockmap_get_from_fd (attr, true);
@@ -1343,6 +1346,9 @@ static int bpf_prog_detach(const union bpf_attr *attr)case BPF_CGROUP_SOCK_OPS : ptype =BPF_PROG_TYPE_SOCK_OPS ;break ; +case BPF_CGROUP_DEVICE : + ptype =BPF_PROG_TYPE_CGROUP_DEVICE ; +break ;case BPF_SK_SKB_STREAM_PARSER :case BPF_SK_SKB_STREAM_VERDICT :return sockmap_get_from_fd (attr, false);
@@ -1385,6 +1391,7 @@ static int bpf_prog_query(const union bpf_attr *attr,case BPF_CGROUP_INET_EGRESS :case BPF_CGROUP_INET_SOCK_CREATE :case BPF_CGROUP_SOCK_OPS : +case BPF_CGROUP_DEVICE :break ;default :return -EINVAL ;
kernel/bpf/verifier.c +1 -0
@@ -3127,6 +3127,7 @@ static int check_return_code(struct bpf_verifier_env *env)case BPF_PROG_TYPE_CGROUP_SKB :case BPF_PROG_TYPE_CGROUP_SOCK :case BPF_PROG_TYPE_SOCK_OPS : +case BPF_PROG_TYPE_CGROUP_DEVICE :break ;default :return 0 ;
tools/include/uapi/linux/bpf.h +15 -0
@@ -131,6 +131,7 @@ enum bpf_prog_type {BPF_PROG_TYPE_LWT_XMIT ,BPF_PROG_TYPE_SOCK_OPS ,BPF_PROG_TYPE_SK_SKB , + BPF_PROG_TYPE_CGROUP_DEVICE, }; enum bpf_attach_type {
@@ -140,6 +141,7 @@ enum bpf_attach_type {BPF_CGROUP_SOCK_OPS ,BPF_SK_SKB_STREAM_PARSER ,BPF_SK_SKB_STREAM_VERDICT , +BPF_CGROUP_DEVICE , __MAX_BPF_ATTACH_TYPE };
@@ -983,4 +985,17 @@ struct bpf_perf_event_value { __u64 running; }; +#define BPF_DEVCG_ACC_MKNOD (1ULL << 0) +#define BPF_DEVCG_ACC_READ (1ULL << 1) +#define BPF_DEVCG_ACC_WRITE (1ULL << 2) + +#define BPF_DEVCG_DEV_BLOCK (1ULL << 0) +#define BPF_DEVCG_DEV_CHAR (1ULL << 1) + +struct bpf_cgroup_dev_ctx { +__u32 access_type;/* (access << 16) | type */ +__u32 major; +__u32 minor; +}; +#endif /* _UAPI__LINUX_BPF_H__ */
Signature · 1 line
2.13.6
PATCH v3 4/5 bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/
In reply to Roman GushchinThe purpose of this move is to use these files in bpf tests.
---
samples/bpf/Makefile | 5 +++--
tools/testing/selftests/bpf/Makefile | 2 +-
{samples => tools/testing/selftests}/bpf/cgroup_helpers.c | 0
{samples => tools/testing/selftests}/bpf/cgroup_helpers.h | 0
4 files changed, 4 insertions(+), 3 deletions(-)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.c (100%)
rename {samples => tools/testing/selftests}/bpf/cgroup_helpers.h (100%)samples/bpf/Makefile +3 -2
@@ -46,6 +46,7 @@ hostprogs-y += syscall_tp # Libbpf dependencies LIBBPF := ../../tools/lib/bpf/bpf.o +CGROUP_HELPERS := ../../tools/testing/selftests/bpf/cgroup_helpers.o test_lru_dist-objs := test_lru_dist.o $(LIBBPF) sock_example-objs := sock_example.o $(LIBBPF)
@@ -69,13 +70,13 @@ map_perf_test-objs := bpf_load.o $(LIBBPF) map_perf_test_user.o test_overhead-objs := bpf_load.o $(LIBBPF) test_overhead_user.o test_cgrp2_array_pin-objs := $(LIBBPF) test_cgrp2_array_pin.o test_cgrp2_attach-objs := $(LIBBPF) test_cgrp2_attach.o -test_cgrp2_attach2-objs := $(LIBBPF) test_cgrp2_attach2.o cgroup_helpers.o +test_cgrp2_attach2-objs := $(LIBBPF) test_cgrp2_attach2.o $(CGROUP_HELPERS) test_cgrp2_sock-objs := $(LIBBPF) test_cgrp2_sock.o test_cgrp2_sock2-objs := bpf_load.o $(LIBBPF) test_cgrp2_sock2.o xdp1-objs := bpf_load.o $(LIBBPF) xdp1_user.o # reuse xdp1 source intentionally xdp2-objs := bpf_load.o $(LIBBPF) xdp1_user.o -test_current_task_under_cgroup-objs := bpf_load.o $(LIBBPF) cgroup_helpers.o \ +test_current_task_under_cgroup-objs := bpf_load.o $(LIBBPF) $(CGROUP_HELPERS) \ test_current_task_under_cgroup_user.o trace_event-objs := bpf_load.o $(LIBBPF) trace_event_user.o sampleip-objs := bpf_load.o $(LIBBPF) sampleip_user.o
tools/testing/selftests/bpf/Makefile +1 -1
@@ -23,7 +23,7 @@ TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh include ../lib.mk -BPFOBJ := $(OUTPUT)/libbpf.a +BPFOBJ := $(OUTPUT)/libbpf.a $(OUTPUT)/cgroup_helpers.c $(TEST_GEN_PROGS): $(BPFOBJ)
tools/testing/selftests/bpf/cgroup_helpers.c renamed from samples/bpf/cgroup_helpers.c +0 -0
tools/testing/selftests/bpf/cgroup_helpers.h renamed from samples/bpf/cgroup_helpers.h +0 -0
Signature · 1 line
2.13.6
PATCH v3 5/5 selftests/bpf: add a test for device cgroup controller
In reply to Roman GushchinAdd 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)
--- tools/testing/selftests/bpf/Makefile | 4 +- tools/testing/selftests/bpf/dev_cgroup.c | 60 +++++++++++++++++ tools/testing/selftests/bpf/test_dev_cgroup.c | 93 +++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/dev_cgroup.c create mode 100644 tools/testing/selftests/bpf/test_dev_cgroup.c
tools/testing/selftests/bpf/Makefile +2 -2
@@ -13,11 +13,11 @@ CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../i LDLIBS += -lcap -lelf TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_align test_verifier_log + test_align test_verifier_log test_dev_cgroup TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ - sockmap_verdict_prog.o + sockmap_verdict_prog.o dev_cgroup.o TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh
tools/testing/selftests/bpf/dev_cgroup.c new file +60 -0
60 lines not on this page · raw message
tools/testing/selftests/bpf/test_dev_cgroup.c new file +93 -0
93 lines not on this page · raw message
Signature · 1 line
2.13.6
David Miller
maintainerFrom: Roman Gushchin <[email protected]>
Date: Sun, 5 Nov 2017 08:15:29 -0500
Quoted 9 lines
This patchset introduces an eBPF-based device controller for cgroup v2.
Patches (1) and (2) are a preparational work required to share some code
with the existing device controller implementation.
Patch (3) is the main patch, which introduces a new bpf prog type
and all necessary infrastructure.
Patch (4) moves cgroup_helpers.c/h to use them by patch (4). Patch (5) implements an example of eBPF program which controls access
to device files and corresponding userspace test.
Series applied, thank you.