* [PATCH net-next 0/4] eBPF-based device cgroup controller
@ 2017-11-01 15:20 Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller Roman Gushchin
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Roman Gushchin @ 2017-11-01 15:20 UTC (permalink / raw)
To: netdev
Cc: Tejun Heo, Alexei Starovoitov, Daniel Borkmann, linux-kernel,
Roman Gushchin
This patchset introduces an eBPF-based device controller for cgroup v2.
Patch (1) is a preparational work required to share some code with
the existing device controller implementation.
Patch (2) is the main patch, which introduces a new bpf prog type
and all necessary infrastructure.
Patch (3) moves cgroup_helpers.c/h to use them by patch (4).
Patch (4) implements an example of eBPF program which controls access
to device files and corresponding userspace test.
Roman Gushchin (4):
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 | 47 +----------
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, 347 insertions(+), 54 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.c
--
2.13.6
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller
2017-11-01 15:20 [PATCH net-next 0/4] eBPF-based device cgroup controller Roman Gushchin
@ 2017-11-01 15:20 ` Roman Gushchin
2017-11-02 7:28 ` David Miller
2017-11-01 15:20 ` [PATCH net-next 2/4] bpf, cgroup: implement eBPF-based device controller for cgroup v2 Roman Gushchin
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Roman Gushchin @ 2017-11-01 15:20 UTC (permalink / raw)
To: netdev
Cc: Tejun Heo, Alexei Starovoitov, Daniel Borkmann, linux-kernel,
Roman Gushchin
This 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.
Signed-off-by: Roman Gushchin <guro@fb.com>
Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Alexei Starovoitov <ast@kernel.org>
---
include/linux/device_cgroup.h | 61 ++++++++++++++++++++++++++++++++++++++++---
security/device_cgroup.c | 47 ++-------------------------------
2 files changed, 59 insertions(+), 49 deletions(-)
diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h
index 8b64221b432b..25f1dc7673db 100644
--- a/include/linux/device_cgroup.h
+++ b/include/linux/device_cgroup.h
@@ -1,16 +1,69 @@
#include <linux/fs.h>
+#define ACC_MKNOD 1
+#define ACC_READ 2
+#define ACC_WRITE 4
+#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE)
+
+#define DEV_BLOCK 1
+#define DEV_CHAR 2
+#define 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 = DEV_BLOCK;
+ else if (S_ISCHR(inode->i_mode))
+ type = DEV_CHAR;
+ else
return 0;
- return __devcgroup_inode_permission(inode, mask);
+
+ if (mask & MAY_WRITE)
+ access |= ACC_WRITE;
+ if (mask & MAY_READ)
+ access |= 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 = DEV_BLOCK;
+ else
+ type = DEV_CHAR;
+
+ return devcgroup_check_permission(type, MAJOR(dev), MINOR(dev),
+ ACC_MKNOD);
+}
+
#else
static inline int devcgroup_inode_permission(struct inode *inode, int mask)
{ return 0; }
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 03c1652c9a1f..d6fb42274ed4 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -14,15 +14,6 @@
#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 DEV_BLOCK 1
-#define DEV_CHAR 2
-#define DEV_ALL 4 /* this represents all devices */
-
static DEFINE_MUTEX(devcgroup_mutex);
enum devcg_behavior {
@@ -809,8 +800,8 @@ struct cgroup_subsys devices_cgrp_subsys = {
*
* returns 0 on success, -EPERM case the operation is not permitted
*/
-static int __devcgroup_check_permission(short type, u32 major, u32 minor,
- short access)
+int __devcgroup_check_permission(short type, u32 major, u32 minor,
+ short access)
{
struct dev_cgroup *dev_cgroup;
bool rc;
@@ -832,37 +823,3 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor,
return 0;
}
-
-int __devcgroup_inode_permission(struct inode *inode, int mask)
-{
- short type, access = 0;
-
- if (S_ISBLK(inode->i_mode))
- type = DEV_BLOCK;
- if (S_ISCHR(inode->i_mode))
- type = DEV_CHAR;
- if (mask & MAY_WRITE)
- access |= ACC_WRITE;
- if (mask & MAY_READ)
- access |= ACC_READ;
-
- return __devcgroup_check_permission(type, imajor(inode), iminor(inode),
- access);
-}
-
-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 = DEV_BLOCK;
- else
- type = DEV_CHAR;
-
- return __devcgroup_check_permission(type, MAJOR(dev), MINOR(dev),
- ACC_MKNOD);
-
-}
--
2.13.6
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next 2/4] bpf, cgroup: implement eBPF-based device controller for cgroup v2
2017-11-01 15:20 [PATCH net-next 0/4] eBPF-based device cgroup controller Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller Roman Gushchin
@ 2017-11-01 15:20 ` Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 3/4] bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/ Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 4/4] selftests/bpf: add a test for device cgroup controller Roman Gushchin
3 siblings, 0 replies; 6+ messages in thread
From: Roman Gushchin @ 2017-11-01 15:20 UTC (permalink / raw)
To: netdev
Cc: Tejun Heo, Alexei Starovoitov, Daniel Borkmann, linux-kernel,
Roman Gushchin
Cgroup 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.
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>
---
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(-)
diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index 359b6f5d3d90..d77cefb3fe99 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -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 */
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index 36418ad43245..963a97ee4b7c 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -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)
diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h
index 25f1dc7673db..9a4f849f73cb 100644
--- a/include/linux/device_cgroup.h
+++ b/include/linux/device_cgroup.h
@@ -1,4 +1,5 @@
#include <linux/fs.h>
+#include <linux/bpf-cgroup.h>
#define ACC_MKNOD 1
#define 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);
}
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0b7b54d898bd..4deb3c9acbb2 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -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 DEV_BPF_ACC_MKNOD (1ULL << 0)
+#define DEV_BPF_ACC_READ (1ULL << 1)
+#define DEV_BPF_ACC_WRITE (1ULL << 2)
+
+#define DEV_BPF_DEV_BLOCK (1ULL << 0)
+#define DEV_BPF_DEV_CHAR (1ULL << 1)
+
+struct bpf_cgroup_dev_ctx {
+ __u32 access_type; /* (access << 16) | type */
+ __u32 major;
+ __u32 minor;
+};
+
#endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 3db5a17fcfe8..b789ab78d28f 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -522,3 +522,70 @@ int __cgroup_bpf_run_filter_sock_ops(struct sock *sk,
return ret == 1 ? 0 : -EPERM;
}
EXPORT_SYMBOL(__cgroup_bpf_run_filter_sock_ops);
+
+int __cgroup_bpf_check_dev_permission(short dev_type, u32 major, u32 minor,
+ short access, enum bpf_attach_type type)
+{
+ struct cgroup *cgrp;
+ struct bpf_cgroup_dev_ctx ctx = {
+ .access_type = (access << 16) | dev_type,
+ .major = major,
+ .minor = minor,
+ };
+ int allow = 1;
+
+ rcu_read_lock();
+ cgrp = task_dfl_cgroup(current);
+ allow = BPF_PROG_RUN_ARRAY(cgrp->bpf.effective[type], &ctx,
+ BPF_PROG_RUN);
+ rcu_read_unlock();
+
+ return !allow;
+}
+EXPORT_SYMBOL(__cgroup_bpf_check_dev_permission);
+
+static const struct bpf_func_proto *
+cgroup_dev_func_proto(enum bpf_func_id func_id)
+{
+ switch (func_id) {
+ case BPF_FUNC_map_lookup_elem:
+ return &bpf_map_lookup_elem_proto;
+ case BPF_FUNC_map_update_elem:
+ return &bpf_map_update_elem_proto;
+ case BPF_FUNC_map_delete_elem:
+ return &bpf_map_delete_elem_proto;
+ case BPF_FUNC_get_current_uid_gid:
+ return &bpf_get_current_uid_gid_proto;
+ case BPF_FUNC_trace_printk:
+ if (capable(CAP_SYS_ADMIN))
+ return bpf_get_trace_printk_proto();
+ default:
+ return NULL;
+ }
+}
+
+static bool cgroup_dev_is_valid_access(int off, int size,
+ enum bpf_access_type type,
+ struct bpf_insn_access_aux *info)
+{
+ if (type == BPF_WRITE)
+ return false;
+
+ if (off < 0 || off + size > sizeof(struct bpf_cgroup_dev_ctx))
+ return false;
+ /* The verifier guarantees that size > 0. */
+ if (off % size != 0)
+ return false;
+ if (size != sizeof(__u32))
+ return false;
+
+ return true;
+}
+
+const struct bpf_prog_ops cg_dev_prog_ops = {
+};
+
+const struct bpf_verifier_ops cg_dev_verifier_ops = {
+ .get_func_proto = cgroup_dev_func_proto,
+ .is_valid_access = cgroup_dev_is_valid_access,
+};
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 323be2473c4b..08f7b450828e 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -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;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2bb6d6aa7085..811f0582a1cc 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -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;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 4a4b6e78c977..c0306ac49860 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -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 DEV_BPF_ACC_MKNOD (1ULL << 0)
+#define DEV_BPF_ACC_READ (1ULL << 1)
+#define DEV_BPF_ACC_WRITE (1ULL << 2)
+
+#define DEV_BPF_DEV_BLOCK (1ULL << 0)
+#define DEV_BPF_DEV_CHAR (1ULL << 1)
+
+struct bpf_cgroup_dev_ctx {
+ __u32 access_type; /* (access << 16) | type */
+ __u32 major;
+ __u32 minor;
+};
+
#endif /* _UAPI__LINUX_BPF_H__ */
--
2.13.6
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next 3/4] bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/
2017-11-01 15:20 [PATCH net-next 0/4] eBPF-based device cgroup controller Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 2/4] bpf, cgroup: implement eBPF-based device controller for cgroup v2 Roman Gushchin
@ 2017-11-01 15:20 ` Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 4/4] selftests/bpf: add a test for device cgroup controller Roman Gushchin
3 siblings, 0 replies; 6+ messages in thread
From: Roman Gushchin @ 2017-11-01 15:20 UTC (permalink / raw)
To: netdev
Cc: Tejun Heo, Alexei Starovoitov, Daniel Borkmann, linux-kernel,
Roman Gushchin
The purpose of this move is to use these files in bpf tests.
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>
---
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%)
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index ea2b9e6135f3..adb1e5dba1ea 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -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
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 2e7880ea0add..36c34f0218a3 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -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)
diff --git a/samples/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c
similarity index 100%
rename from samples/bpf/cgroup_helpers.c
rename to tools/testing/selftests/bpf/cgroup_helpers.c
diff --git a/samples/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h
similarity index 100%
rename from samples/bpf/cgroup_helpers.h
rename to tools/testing/selftests/bpf/cgroup_helpers.h
--
2.13.6
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next 4/4] selftests/bpf: add a test for device cgroup controller
2017-11-01 15:20 [PATCH net-next 0/4] eBPF-based device cgroup controller Roman Gushchin
` (2 preceding siblings ...)
2017-11-01 15:20 ` [PATCH net-next 3/4] bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/ Roman Gushchin
@ 2017-11-01 15:20 ` Roman Gushchin
3 siblings, 0 replies; 6+ messages in thread
From: Roman Gushchin @ 2017-11-01 15:20 UTC (permalink / raw)
To: netdev
Cc: Tejun Heo, Alexei Starovoitov, Daniel Borkmann, linux-kernel,
Roman Gushchin
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>
---
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
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 36c34f0218a3..64ba3684a4f4 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -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
diff --git a/tools/testing/selftests/bpf/dev_cgroup.c b/tools/testing/selftests/bpf/dev_cgroup.c
new file mode 100644
index 000000000000..f15d5befa099
--- /dev/null
+++ b/tools/testing/selftests/bpf/dev_cgroup.c
@@ -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 DEV_BPF_DEV_BLOCK:
+ fmt[0] = 'b';
+ break;
+ case DEV_BPF_DEV_CHAR:
+ fmt[0] = 'c';
+ break;
+ default:
+ fmt[0] = '?';
+ break;
+ }
+
+ if (access & DEV_BPF_ACC_READ)
+ fmt[8] = 'r';
+
+ if (access & DEV_BPF_ACC_WRITE)
+ fmt[9] = 'w';
+
+ if (access & DEV_BPF_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 != DEV_BPF_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;
diff --git a/tools/testing/selftests/bpf/test_dev_cgroup.c b/tools/testing/selftests/bpf/test_dev_cgroup.c
new file mode 100644
index 000000000000..02c85d6c89b0
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_dev_cgroup.c
@@ -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;
+}
--
2.13.6
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller
2017-11-01 15:20 ` [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller Roman Gushchin
@ 2017-11-02 7:28 ` David Miller
0 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2017-11-02 7:28 UTC (permalink / raw)
To: guro; +Cc: netdev, tj, ast, daniel, linux-kernel
From: Roman Gushchin <guro@fb.com>
Date: Wed, 1 Nov 2017 11:20:34 -0400
> diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h
> index 8b64221b432b..25f1dc7673db 100644
> --- a/include/linux/device_cgroup.h
> +++ b/include/linux/device_cgroup.h
> @@ -1,16 +1,69 @@
> #include <linux/fs.h>
>
> +#define ACC_MKNOD 1
> +#define ACC_READ 2
> +#define ACC_WRITE 4
> +#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE)
> +
> +#define DEV_BLOCK 1
> +#define DEV_CHAR 2
> +#define DEV_ALL 4 /* this represents all devices */
When these macros existed solely inside of security/device_cgroup.c,
such naming was probably fine.
But once you move them into a global header file, we have to take
global namespace issues into consideration.
I would therefore like to ask that you give some kind of appropriate
prefix to the names of these macros, in order to make them more global
namespace friendly.
Thank you.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-11-02 7:28 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-01 15:20 [PATCH net-next 0/4] eBPF-based device cgroup controller Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 1/4] device_cgroup: prepare code for bpf-based device controller Roman Gushchin
2017-11-02 7:28 ` David Miller
2017-11-01 15:20 ` [PATCH net-next 2/4] bpf, cgroup: implement eBPF-based device controller for cgroup v2 Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 3/4] bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/ Roman Gushchin
2017-11-01 15:20 ` [PATCH net-next 4/4] selftests/bpf: add a test for device cgroup controller Roman Gushchin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).