Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4672ded3 authored by Chenbo Feng's avatar Chenbo Feng
Browse files

BACKPORT: bpf: Add file mode configuration into bpf maps



Introduce the map read/write flags to the eBPF syscalls that returns the
map fd. The flags is used to set up the file mode when construct a new
file descriptor for bpf maps. To not break the backward capability, the
f_flags is set to O_RDWR if the flag passed by syscall is 0. Otherwise
it should be O_RDONLY or O_WRONLY. When the userspace want to modify or
read the map content, it will check the file mode to see if it is
allowed to make the change.

Signed-off-by: default avatarChenbo Feng <fengc@google.com>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>

Deleted the file mode configuration code in unsupported map type and
removed the file mode check in non-existing helper functions.
(cherry-pick from net-next: 6e71b04a82248ccf13a94b85cbc674a9fefe53f5)
Bug: 30950746

Change-Id: Icfad20f1abb77f91068d244fb0d87fa40824dd1b
parent e0907557
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -248,11 +248,11 @@ void bpf_map_area_free(void *base);

extern int sysctl_unprivileged_bpf_disabled;

int bpf_map_new_fd(struct bpf_map *map);
int bpf_map_new_fd(struct bpf_map *map, int flags);
int bpf_prog_new_fd(struct bpf_prog *prog);

int bpf_obj_pin_user(u32 ufd, const char __user *pathname);
int bpf_obj_get_user(const char __user *pathname);
int bpf_obj_get_user(const char __user *pathname, int flags);

int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value);
int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value);
@@ -267,6 +267,8 @@ int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file,
				 void *key, void *value, u64 map_flags);
void bpf_fd_array_map_clear(struct bpf_map *map);

int bpf_get_file_flag(int flags);

/* memcpy that is used with 8-byte aligned pointers, power-of-8 size and
 * forced to use 'long' read/writes to try to atomically copy long counters.
 * Best-effort only.  No barriers here, since it _will_ race with concurrent
+5 −0
Original line number Diff line number Diff line
@@ -124,6 +124,10 @@ enum bpf_attach_type {

#define BPF_F_NO_PREALLOC	(1U << 0)

/* Flags for accessing BPF object */
#define BPF_F_RDONLY		(1U << 3)
#define BPF_F_WRONLY		(1U << 4)

union bpf_attr {
	struct { /* anonymous struct used by BPF_MAP_CREATE command */
		__u32	map_type;	/* one of enum bpf_map_type */
@@ -157,6 +161,7 @@ union bpf_attr {
	struct { /* anonymous struct used by BPF_OBJ_* commands */
		__aligned_u64	pathname;
		__u32		bpf_fd;
		__u32		file_flags;
	};

	struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
+5 −1
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@
#include <linux/filter.h>
#include <linux/perf_event.h>

#define ARRAY_CREATE_FLAG_MASK \
	(BPF_F_RDONLY | BPF_F_WRONLY)

static void bpf_array_free_percpu(struct bpf_array *array)
{
	int i;
@@ -52,7 +55,8 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)

	/* check sanity of attributes */
	if (attr->max_entries == 0 || attr->key_size != 4 ||
	    attr->value_size == 0 || attr->map_flags)
	    attr->value_size == 0 ||
	    attr->map_flags & ~ARRAY_CREATE_FLAG_MASK)
		return ERR_PTR(-EINVAL);

	if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
+3 −1
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#include <linux/jhash.h>
#include <linux/filter.h>
#include "percpu_freelist.h"
#define HTAB_CREATE_FLAG_MASK						\
	(BPF_F_NO_PREALLOC | BPF_F_RDONLY | BPF_F_WRONLY)

struct bucket {
	struct hlist_head head;
@@ -148,7 +150,7 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
	int err, i;
	u64 cost;

	if (attr->map_flags & ~BPF_F_NO_PREALLOC)
	if (attr->map_flags & ~HTAB_CREATE_FLAG_MASK)
		/* reserved bits should not be used */
		return ERR_PTR(-EINVAL);

+10 −5
Original line number Diff line number Diff line
@@ -255,7 +255,7 @@ int bpf_obj_pin_user(u32 ufd, const char __user *pathname)
}

static void *bpf_obj_do_get(const struct filename *pathname,
			    enum bpf_type *type)
			    enum bpf_type *type, int flags)
{
	struct inode *inode;
	struct path path;
@@ -267,7 +267,7 @@ static void *bpf_obj_do_get(const struct filename *pathname,
		return ERR_PTR(ret);

	inode = d_backing_inode(path.dentry);
	ret = inode_permission(inode, MAY_WRITE);
	ret = inode_permission(inode, ACC_MODE(flags));
	if (ret)
		goto out;

@@ -286,18 +286,23 @@ static void *bpf_obj_do_get(const struct filename *pathname,
	return ERR_PTR(ret);
}

int bpf_obj_get_user(const char __user *pathname)
int bpf_obj_get_user(const char __user *pathname, int flags)
{
	enum bpf_type type = BPF_TYPE_UNSPEC;
	struct filename *pname;
	int ret = -ENOENT;
	int f_flags;
	void *raw;

	f_flags = bpf_get_file_flag(flags);
	if (f_flags < 0)
		return f_flags;

	pname = getname(pathname);
	if (IS_ERR(pname))
		return PTR_ERR(pname);

	raw = bpf_obj_do_get(pname, &type);
	raw = bpf_obj_do_get(pname, &type, f_flags);
	if (IS_ERR(raw)) {
		ret = PTR_ERR(raw);
		goto out;
@@ -306,7 +311,7 @@ int bpf_obj_get_user(const char __user *pathname)
	if (type == BPF_TYPE_PROG)
		ret = bpf_prog_new_fd(raw);
	else if (type == BPF_TYPE_MAP)
		ret = bpf_map_new_fd(raw);
		ret = bpf_map_new_fd(raw, f_flags);
	else
		goto out;

Loading