Skip to content

Commit

Permalink
bpf: Add file mode configuration into bpf maps
Browse files Browse the repository at this point in the history
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: Chenbo Feng <fengc@google.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Chenbo Feng authored and davem330 committed Oct 20, 2017
1 parent aec72f3 commit 6e71b04
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 26 deletions.
8 changes: 5 additions & 3 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,11 +315,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);
Expand All @@ -338,6 +338,8 @@ int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file,
void *key, void *value, u64 map_flags);
int bpf_fd_htab_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);

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
Expand Down Expand Up @@ -421,7 +423,7 @@ static inline void __bpf_prog_uncharge(struct user_struct *user, u32 pages)
{
}

static inline int bpf_obj_get_user(const char __user *pathname)
static inline int bpf_obj_get_user(const char __user *pathname, int flags)
{
return -EOPNOTSUPP;
}
Expand Down
6 changes: 6 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ enum bpf_attach_type {

#define BPF_OBJ_NAME_LEN 16U

/* 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 */
Expand Down Expand Up @@ -260,6 +264,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 */
Expand Down Expand Up @@ -287,6 +292,7 @@ union bpf_attr {
__u32 map_id;
};
__u32 next_id;
__u32 open_flags;
};

struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
Expand Down
6 changes: 5 additions & 1 deletion kernel/bpf/arraymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

#include "map_in_map.h"

#define ARRAY_CREATE_FLAG_MASK \
(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)

static void bpf_array_free_percpu(struct bpf_array *array)
{
int i;
Expand Down Expand Up @@ -56,7 +59,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 & ~BPF_F_NUMA_NODE ||
attr->value_size == 0 ||
attr->map_flags & ~ARRAY_CREATE_FLAG_MASK ||
(percpu && numa_node != NUMA_NO_NODE))
return ERR_PTR(-EINVAL);

Expand Down
5 changes: 4 additions & 1 deletion kernel/bpf/devmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
#include <linux/bpf.h>
#include <linux/filter.h>

#define DEV_CREATE_FLAG_MASK \
(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)

struct bpf_dtab_netdev {
struct net_device *dev;
struct bpf_dtab *dtab;
Expand Down Expand Up @@ -80,7 +83,7 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr)

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

dtab = kzalloc(sizeof(*dtab), GFP_USER);
Expand Down
5 changes: 3 additions & 2 deletions kernel/bpf/hashtab.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
#include "bpf_lru_list.h"
#include "map_in_map.h"

#define HTAB_CREATE_FLAG_MASK \
(BPF_F_NO_PREALLOC | BPF_F_NO_COMMON_LRU | BPF_F_NUMA_NODE)
#define HTAB_CREATE_FLAG_MASK \
(BPF_F_NO_PREALLOC | BPF_F_NO_COMMON_LRU | BPF_F_NUMA_NODE | \
BPF_F_RDONLY | BPF_F_WRONLY)

struct bucket {
struct hlist_nulls_head head;
Expand Down
15 changes: 10 additions & 5 deletions kernel/bpf/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,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;
Expand All @@ -307,7 +307,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;

Expand All @@ -326,18 +326,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;
Expand All @@ -346,7 +351,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;

Expand Down
3 changes: 2 additions & 1 deletion kernel/bpf/lpm_trie.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ static int trie_delete_elem(struct bpf_map *map, void *_key)
#define LPM_KEY_SIZE_MAX LPM_KEY_SIZE(LPM_DATA_SIZE_MAX)
#define LPM_KEY_SIZE_MIN LPM_KEY_SIZE(LPM_DATA_SIZE_MIN)

#define LPM_CREATE_FLAG_MASK (BPF_F_NO_PREALLOC | BPF_F_NUMA_NODE)
#define LPM_CREATE_FLAG_MASK (BPF_F_NO_PREALLOC | BPF_F_NUMA_NODE | \
BPF_F_RDONLY | BPF_F_WRONLY)

static struct bpf_map *trie_alloc(union bpf_attr *attr)
{
Expand Down
5 changes: 4 additions & 1 deletion kernel/bpf/sockmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
#include <linux/list.h>
#include <net/strparser.h>

#define SOCK_CREATE_FLAG_MASK \
(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)

struct bpf_stab {
struct bpf_map map;
struct sock **sock_map;
Expand Down Expand Up @@ -489,7 +492,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)

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

if (attr->value_size > KMALLOC_MAX_SIZE)
Expand Down
5 changes: 4 additions & 1 deletion kernel/bpf/stackmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include <linux/perf_event.h>
#include "percpu_freelist.h"

#define STACK_CREATE_FLAG_MASK \
(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)

struct stack_map_bucket {
struct pcpu_freelist_node fnode;
u32 hash;
Expand Down Expand Up @@ -60,7 +63,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
if (!capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);

if (attr->map_flags & ~BPF_F_NUMA_NODE)
if (attr->map_flags & ~STACK_CREATE_FLAG_MASK)
return ERR_PTR(-EINVAL);

/* check sanity of attributes */
Expand Down
Loading

0 comments on commit 6e71b04

Please sign in to comment.