[RFC bpf-next 1/2] bpf: with CONFIG_BPF_UNPRIV_MAP_ACCESS=y, allow unprivileged access to BPF maps

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



With unprivileged BPF disabled, all cmds associated with the BPF syscall
are blocked to users without CAP_BPF/CAP_SYS_ADMIN.  However there are
use cases where we may wish to allow interactions with BPF programs
without being able to load and attach them.  So for example, a process
with required capabilities loads/attaches a BPF program, and a process
with less capabilities interacts with it; retrieving perf/ring buffer
events, modifying map-specified config etc.  With all BPF syscall
commands blocked as a result of unprivileged BPF being disabled,
this mode of interaction becomes impossible for processes without
CAP_BPF.

Here we propose allowing BPF_OBJ_GET (to retrieve pinned map/prog) and
BPF_MAP_* commands to work, even in cases where unprivileged BPF is
disabled and appropriate capabilities are not present.  This mode of
operation is not enabled by default; it depends on setting
CONFIG_BPF_UNPRIV_MAP_ACCESS=y (it defaults to n).

Note that the program responsible for loading and attaching the BPF program
can still control access to its pinned representation by restricting
permissions on the pin path.

For map-related BPF syscalls under CONFIG_BPF_UNPRIV_MAP_ACCESS=y,
map access is restricted to the following map types:

BPF_MAP_TYPE_ARRAY
BPF_MAP_TYPE_HASH
BPF_MAP_TYPE_PERF_EVENT_ARRAY
BPF_MAP_TYPE_PERCPU_ARRAY
BPF_MAP_TYPE_PERCPU_HASH
BPF_MAP_TYPE_RINGBUF

The set of unprivileged BPF syscall commands that are permitted for the
above map types with CONFIG_BPF_UNPRIV_MAP_ACCESS=y is

BPF_MAP_LOOKUP_ELEM
BPF_MAP_UPDATE_ELEM
BPF_MAP_DELETE_ELEM
BPF_MAP_NEXT_KEY

..and the following unprivileged BPF syscall commands are permitted
in order to allow map retrieval:

BPF_OBJ_GET
BPF_OBJ_GET_INFO_BY_FD

Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx>
---
 kernel/bpf/Kconfig   | 15 ++++++++++++
 kernel/bpf/syscall.c | 57 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig
index d56ee177d5f8..30e6f559ad08 100644
--- a/kernel/bpf/Kconfig
+++ b/kernel/bpf/Kconfig
@@ -84,6 +84,21 @@ config BPF_UNPRIV_DEFAULT_OFF
 
 	  If you are unsure how to answer this question, answer Y.
 
+config BPF_UNPRIV_MAP_ACCESS
+	bool "Allow unprivileged access to BPF map-related actions"
+	default n
+	depends on BPF_SYSCALL
+	help
+	   Allow unprivileged access to retrieve pinned objects, lookup,
+	   update and delete map elements.  Only specific BPF map types
+	   are permitted - (per-cpu) array maps, (per-cpu) hash maps,
+	   perf event and ring buffer maps.
+
+	   This allows limited use of the BPF syscall for unprivileged
+	   users; note however that this does not include loading or
+	   attaching BPF programs.  Pinned maps can also specify
+	   pin path permissions to prevent unwanted access.
+
 source "kernel/bpf/preload/Kconfig"
 
 config BPF_LSM
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 72e53489165d..951491836bbb 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1278,6 +1278,22 @@ static void *___bpf_copy_key(bpfptr_t ukey, u64 key_size)
 	return NULL;
 }
 
+static bool map_type_prevent_unprivileged_access(struct bpf_map *map)
+{
+#ifdef CONFIG_BPF_UNPRIV_MAP_ACCESS
+	return sysctl_unprivileged_bpf_disabled && !bpf_capable() &&
+	       map->map_type != BPF_MAP_TYPE_ARRAY &&
+	       map->map_type != BPF_MAP_TYPE_HASH &&
+	       map->map_type != BPF_MAP_TYPE_PERF_EVENT_ARRAY &&
+	       map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
+	       map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
+	       map->map_type != BPF_MAP_TYPE_RINGBUF;
+#else
+	/* earlier checks prevent unprivileged access */
+	return false;
+#endif
+}
+
 /* last field in 'union bpf_attr' used by this command */
 #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
 
@@ -1313,6 +1329,11 @@ static int map_lookup_elem(union bpf_attr *attr)
 		goto err_put;
 	}
 
+	if (map_type_prevent_unprivileged_access(map)) {
+		err = -EPERM;
+		goto err_put;
+	}
+
 	key = __bpf_copy_key(ukey, map->key_size);
 	if (IS_ERR(key)) {
 		err = PTR_ERR(key);
@@ -1386,6 +1407,11 @@ static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr)
 		goto err_put;
 	}
 
+	if (map_type_prevent_unprivileged_access(map)) {
+		err = -EPERM;
+		goto err_put;
+	}
+
 	key = ___bpf_copy_key(ukey, map->key_size);
 	if (IS_ERR(key)) {
 		err = PTR_ERR(key);
@@ -1439,6 +1465,11 @@ static int map_delete_elem(union bpf_attr *attr)
 		goto err_put;
 	}
 
+	if (map_type_prevent_unprivileged_access(map)) {
+		err = -EPERM;
+		goto err_put;
+	}
+
 	key = __bpf_copy_key(ukey, map->key_size);
 	if (IS_ERR(key)) {
 		err = PTR_ERR(key);
@@ -1494,6 +1525,11 @@ static int map_get_next_key(union bpf_attr *attr)
 		goto err_put;
 	}
 
+	if (map_type_prevent_unprivileged_access(map)) {
+		err = -EPERM;
+		goto err_put;
+	}
+
 	if (ukey) {
 		key = __bpf_copy_key(ukey, map->key_size);
 		if (IS_ERR(key)) {
@@ -4863,10 +4899,29 @@ static int bpf_prog_bind_map(union bpf_attr *attr)
 static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
 {
 	union bpf_attr attr;
+	bool capable;
 	int err;
 
-	if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
+	capable = bpf_capable() || !sysctl_unprivileged_bpf_disabled;
+
+#ifdef CONFIG_BPF_UNPRIV_MAP_ACCESS
+	/* A subset of cmds are allowed to unprivileged users, principally to allow
+	 * them to interact with pinned BPF maps to retrieve events, update map
+	 * values etc.  The pinning program can adjust pin path permissions
+	 * to prevent unwanted access by unprivileged users.
+	 */
+	if (!capable &&
+	    cmd != BPF_MAP_LOOKUP_ELEM &&
+	    cmd != BPF_MAP_UPDATE_ELEM &&
+	    cmd != BPF_MAP_DELETE_ELEM &&
+	    cmd != BPF_MAP_GET_NEXT_KEY &&
+	    cmd != BPF_OBJ_GET &&
+	    cmd != BPF_OBJ_GET_INFO_BY_FD)
 		return -EPERM;
+#else
+	if (!capable)
+		return -EPERM;
+#endif
 
 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
 	if (err)
-- 
2.27.0




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux