Re: [PATCH v4] Wait for running BPF programs when updating map-in-map

2018-11-09 Thread Chenbo Feng
Hi netdev,

Could we queue up this patch to stable 4.14 and stable 4.19? I can
provide a backport patch if needed. I checked it is a clean
cherry-pick for 4.19 but have some minor conflict for 4.14.

Thanks
Chenbo Feng
On Thu, Oct 18, 2018 at 4:36 PM Joel Fernandes  wrote:
>
> On Thu, Oct 18, 2018 at 08:46:59AM -0700, Alexei Starovoitov wrote:
> > On Tue, Oct 16, 2018 at 10:39:57AM -0700, Joel Fernandes wrote:
> > > On Fri, Oct 12, 2018 at 7:31 PM, Alexei Starovoitov
> > >  wrote:
> > > > On Fri, Oct 12, 2018 at 03:54:27AM -0700, Daniel Colascione wrote:
> > > >> The map-in-map frequently serves as a mechanism for atomic
> > > >> snapshotting of state that a BPF program might record.  The current
> > > >> implementation is dangerous to use in this way, however, since
> > > >> userspace has no way of knowing when all programs that might have
> > > >> retrieved the "old" value of the map may have completed.
> > > >>
> > > >> This change ensures that map update operations on map-in-map map types
> > > >> always wait for all references to the old map to drop before returning
> > > >> to userspace.
> > > >>
> > > >> Signed-off-by: Daniel Colascione 
> > > >> ---
> > > >>  kernel/bpf/syscall.c | 14 ++
> > > >>  1 file changed, 14 insertions(+)
> > > >>
> > > >> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> > > >> index 8339d81cba1d..d7c16ae1e85a 100644
> > > >> --- a/kernel/bpf/syscall.c
> > > >> +++ b/kernel/bpf/syscall.c
> > > >> @@ -741,6 +741,18 @@ static int map_lookup_elem(union bpf_attr *attr)
> > > >>   return err;
> > > >>  }
> > > >>
> > > >> +static void maybe_wait_bpf_programs(struct bpf_map *map)
> > > >> +{
> > > >> + /* Wait for any running BPF programs to complete so that
> > > >> +  * userspace, when we return to it, knows that all programs
> > > >> +  * that could be running use the new map value.
> > > >> +  */
> > > >> + if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS ||
> > > >> + map->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) {
> > > >> + synchronize_rcu();
> > > >> + }
> > > >
> > > > extra {} were not necessary. I removed them while applying to bpf-next.
> > > > Please run checkpatch.pl next time.
> > > > Thanks
> > >
> > > Thanks Alexei for taking it. Me and Lorenzo were discussing that not
> > > having this causes incorrect behavior for apps using map-in-map for
> > > this. So I CC'd stable as well.
> >
> > It is too late in the release cycle.
> > We can submit it to stable releases after the merge window.
> >
>
> Sounds good, thanks.
>
> - Joel
>


Re: Suggestions on iterating eBPF maps

2018-04-27 Thread Chenbo Feng
resend with  plain text

On Fri, Apr 27, 2018 at 11:22 AM Chenbo Feng <fe...@google.com> wrote:

> Hi net-next,

> When doing the eBPF tools user-space development I noticed that the map
iterating process in user-space have some little flaws. If we want to dump
the whole map. The only way now I know is to use a null key to start the
iteration and keep calling bpf_get_next_key and bpf_look_up_elem for each
new key value pair until we reach the end of the map. I noticed the
bpftools recently added used the similar approach.

> The overhead of repeating syscalls is acceptable, but the race problem
come with this iteration process is a little annoying. If the current key
we are using get deleted before we do the syscall to get the next key . The
next key returned will start from the beginning of the map again and some
entry will be dumped again depending on the position of the key deleted. If
the racing problem is within the same userspace process, it can be easily
fixed by adding some read/write locks. However, if multiple processes is
reading the map through pinned fd while there is one process is editing the
map entry or the kernel program is deleting entries, it become harder to
get a consistent and correct map dump.

> We are wondering if there is already implementation we didn't notice in
mainline kernel that help improved this iteration process and addressed the
racing problem mentioned above? If not, what can be down to address the
issue above. One thing we came up with is to use a single entry bpf map as
a across process lock to prevent multiple userspace process to read/write
other maps at the same time. But I don't know how safe this solution is
since there will still be a race to read the lock map value and setup the
lock.

> Thanks
> Chenbo Feng


bpf stable request

2018-03-26 Thread Chenbo Feng
0fa4fe85f4724fff89b09741c437cbee9cf8b008 bpf: skip unnecessary 
capability check


This patch fixes the false alarms from security system such as selinux 
when doing the capability check. The problem exists since the 
sysctl_unprivileged_bpf_disabled is added in linux 4.4. So I suggest to 
backport this patch to all LTS stable branches starting from linux-4.4-y.




[PATCH bpf-next] bpf: skip unnecessary capability check

2018-03-19 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

The current check statement in BPF syscall will do a capability check
for CAP_SYS_ADMIN before checking sysctl_unprivileged_bpf_disabled. This
code path will trigger unnecessary security hooks on capability checking
and cause false alarms on unprivileged process trying to get CAP_SYS_ADMIN
access. This can be resolved by simply switch the order of the statement
and CAP_SYS_ADMIN is not required anyway if unprivileged bpf syscall is
allowed.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 kernel/bpf/syscall.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index e24aa3241387..43f95d190eea 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1845,7 +1845,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, 
uattr, unsigned int, siz
union bpf_attr attr = {};
int err;
 
-   if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
+   if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
return -EPERM;
 
err = check_uarg_tail_zero(uattr, sizeof(attr), size);
-- 
2.16.2.804.g6dcf76e118-goog



[PATCH net-next v7 2/5] bpf: Add tests for eBPF file mode

2017-10-18 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Two related tests are added into bpf selftest to test read only map and
write only map. The tests verified the read only and write only flags
are working on hash maps.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Daniel Borkmann <dan...@iogearbox.net>
---
 tools/testing/selftests/bpf/test_maps.c | 48 +
 1 file changed, 48 insertions(+)

diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index fe3a443a1102..896f23cfe918 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1033,6 +1033,51 @@ static void test_map_parallel(void)
assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
 }
 
+static void test_map_rdonly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_RDONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == -1 &&
+  errno == EPERM);
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == ENOENT);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
+}
+
+static void test_map_wronly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_WRONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == 0)
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == EPERM);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == EPERM);
+}
+
 static void run_all_tests(void)
 {
test_hashmap(0, NULL);
@@ -1050,6 +1095,9 @@ static void run_all_tests(void)
test_map_large();
test_map_parallel();
test_map_stress();
+
+   test_map_rdonly();
+   test_map_wronly();
 }
 
 int main(void)
-- 
2.15.0.rc1.287.g2b38de12cc-goog



[PATCH net-next v7 1/5] bpf: Add file mode configuration into bpf maps

2017-10-18 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  8 +++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/arraymap.c|  6 +++-
 kernel/bpf/devmap.c  |  5 ++-
 kernel/bpf/hashtab.c |  5 +--
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/lpm_trie.c|  3 +-
 kernel/bpf/sockmap.c |  5 ++-
 kernel/bpf/stackmap.c|  5 ++-
 kernel/bpf/syscall.c | 88 ++--
 net/netfilter/xt_bpf.c   |  2 +-
 11 files changed, 122 insertions(+), 26 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index d67ccdc0099f..3e5508f2fa87 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -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);
@@ -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
@@ -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;
 }
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 4303fb6c3817..d83f95ea6a1b 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -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 */
@@ -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 */
@@ -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 */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 68d866628be0..988c04c91e10 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -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;
@@ -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);
 
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index e093d9a2c4dd..e5d3de7cff2e 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -50,6 +50,9 @@
 #include 
 #include 
 
+#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;
@

[PATCH net-next v7 3/5] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-18 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 34 +++--
 security/security.c   | 32 
 5 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 3e5508f2fa87..84c192da3e0b 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -193,6 +196,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYS

[PATCH net-next v7 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-18 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..12cf7de8cbed 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (fmode & FMODE_READ)
+   av |= BPF__MAP_READ;
+   if (fmode & FMODE_WRITE)
+   av |= BPF__MAP_WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   BPF__PROG_RUN, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..0a7023b5f000 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ "infiniband_

[PATCH net-next v7 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-18 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Stephen Smalley <s...@tycho.nsa.gov>
---
 include/linux/bpf.h  |  3 +++
 kernel/bpf/syscall.c |  4 ++--
 security/selinux/hooks.c | 49 
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 84c192da3e0b..1e334b248ff6 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -288,6 +288,9 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu 
*progs,
 #ifdef CONFIG_BPF_SYSCALL
 DECLARE_PER_CPU(int, bpf_prog_active);
 
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
 #define BPF_PROG_TYPE(_id, _name) \
extern const struct bpf_prog_ops _name ## _prog_ops; \
extern const struct bpf_verifier_ops _name ## _verifier_ops;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 5cb56d06b48d..323be2473c4b 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -315,7 +315,7 @@ static ssize_t bpf_dummy_write(struct file *filp, const 
char __user *buf,
return -EINVAL;
 }
 
-static const struct file_operations bpf_map_fops = {
+const struct file_operations bpf_map_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_map_show_fdinfo,
 #endif
@@ -975,7 +975,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct 
file *filp)
 }
 #endif
 
-static const struct file_operations bpf_prog_fops = {
+const struct file_operations bpf_prog_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_prog_show_fdinfo,
 #endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 12cf7de8cbed..2e3a627fc0b1 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1815,6 +1815,10 @@ static inline int file_path_has_perm(const struct cred 
*cred,
return inode_has_perm(cred, file_inode(file), av, );
 }
 
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_fd_pass(struct file *file, u32 sid);
+#endif
+
 /* Check whether a task can use an open file descriptor to
access an inode in a given way.  Check access to the
descriptor itself, and then use dentry_has_perm to
@@ -1845,6 +1849,12 @@ static int file_has_perm(const struct cred *cred,
goto out;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, cred_sid(cred));
+   if (rc)
+   return rc;
+#endif
+
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
@@ -2165,6 +2175,12 @@ static int selinux_binder_transfer_file(struct 
task_struct *from,
return rc;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, sid);
+   if (rc)
+   return rc;
+#endif
+
if (unlikely(IS_PRIVATE(d_backing_inode(dentry
return 0;
 
@@ -6288,6 +6304,39 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
return av;
 }
 
+/* This function will check the file pass through unix socket or binder to see
+ * if it is a bpf related object. And apply correspinding checks on the bpf
+ * object based on the type. The bpf maps and programs, not like other files 
and
+ * socket, are using a shared anonymous inode inside the kernel as their inode.
+ * So checking that inode cannot identify if the process have privilege to
+ * access the bpf object and that's why we have to add this additional check in
+ * selinux_file_receive and selinux_binder_transfer_files.
+ */
+static int bpf_fd_pass(struct file *file, u32 sid)
+{
+   struct bpf_security_struct *bpfsec;
+   struct bpf_prog *prog;
+   struct bpf_map *map;
+   int ret;
+
+   if (file->f_op == _map_fops) {
+   map = file->private_data;
+   bpfsec = map->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+  bpf_map_fmode_to_av(file->f_mode), NULL);
+   if (ret)
+   return ret;
+   } else if (file->f_op == _prog_fops) {
+   prog = file->private_data;
+   bpfsec = prog->aux->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+  BPF__PROG_RUN, NULL);
+   if (ret)
+   return ret;
+   }
+   return 0;
+}
+
 static int se

[PATCH net-next v7 0/5] bpf: security: New file mode and LSM hooks for eBPF object permission control

2017-10-18 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.

Change since V1:

 - Whitelist the new bpf flags in the map allocate check.
 - Added bpf selftest for the new flags.
 - Added two new security hooks for copying the security information from
   the bpf object security struct to file security struct
 - Simplified the checking action when bpf fd is passed between processes.

 Change since V2:

 - Fixed the line break problem for map flags check
 - Fixed the typo in selinux check of file mode.
 - Merge bpf_map and bpf_prog into one selinux class
 - Added bpf_type and bpf_sid into file security struct to store the
   security information when generate fd.
 - Add the hook to bpf_map_new_fd and bpf_prog_new_fd.

 Change since V3:

 - Return the actual error from security check instead of -EPERM
 - Move the hooks into anon_inode_getfd() to avoid get file again after
   bpf object file is installed with fd.
 - Removed the bpf_sid field inside file_scerity_struct to reduce the
   cache size.

 Change since V4:

 - Rename bpf av prog_use to prog_run to distinguish from fd_use.
 - Remove the bpf_type field inside file_scerity_struct and use bpf fops
   to indentify bpf object instead.

 Change since v5:

 - Fixed the incorrect selinux class name for SECCLASS_BPF

 Change since v7:

 - Fixed the build error caused by xt_bpf module.
 - Add flags check for bpf_obj_get() and bpf_map_get_fd_by_id() to make it
   uapi-wise.
 - Add the flags field to the bpf_obj_get_user function when BPF_SYSCALL
   is not configured.

Chenbo Feng (5):
  bpf: Add file mode configuration into bpf maps
  bpf: Add tests for eBPF file mode
  security: bpf: Add LSM hooks for bpf object related syscall
  selinux: bpf: Add selinux check for eBPF syscall operations
  selinux: bpf: Add addtional check for bpf object file receive

 include/linux/bpf.h |  15 ++-
 include/linux/lsm_hooks.h   |  54 +++
 include/linux/security.h|  45 +
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/arraymap.c   |   6 +-
 kernel/bpf/devmap.c |   5 +-
 kernel/bpf/hashtab.c|   5 +-
 kernel/bpf/inode.c  |  15 ++-
 kernel/bpf/lpm_trie.c   |   3 +-
 kernel/bpf/sockmap.c|   5 +-
 kernel/bpf/stackmap.c   |   5 +-
 kernel/bpf/syscall.c   

[PATCH net-next v6 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-16 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Stephen Smalley <s...@tycho.nsa.gov>
---
 include/linux/bpf.h  |  3 +++
 kernel/bpf/syscall.c |  4 ++--
 security/selinux/hooks.c | 49 
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 1479442d5293..1ac507dc19a8 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -285,6 +285,9 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu 
*progs,
 #ifdef CONFIG_BPF_SYSCALL
 DECLARE_PER_CPU(int, bpf_prog_active);
 
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
 #define BPF_PROG_TYPE(_id, _ops) \
extern const struct bpf_verifier_ops _ops;
 #define BPF_MAP_TYPE(_id, _ops) \
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index d3e152e282d8..8bdb98aa7f34 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file *filp, const 
char __user *buf,
return -EINVAL;
 }
 
-static const struct file_operations bpf_map_fops = {
+const struct file_operations bpf_map_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_map_show_fdinfo,
 #endif
@@ -967,7 +967,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct 
file *filp)
 }
 #endif
 
-static const struct file_operations bpf_prog_fops = {
+const struct file_operations bpf_prog_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_prog_show_fdinfo,
 #endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 12cf7de8cbed..2e3a627fc0b1 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1815,6 +1815,10 @@ static inline int file_path_has_perm(const struct cred 
*cred,
return inode_has_perm(cred, file_inode(file), av, );
 }
 
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_fd_pass(struct file *file, u32 sid);
+#endif
+
 /* Check whether a task can use an open file descriptor to
access an inode in a given way.  Check access to the
descriptor itself, and then use dentry_has_perm to
@@ -1845,6 +1849,12 @@ static int file_has_perm(const struct cred *cred,
goto out;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, cred_sid(cred));
+   if (rc)
+   return rc;
+#endif
+
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
@@ -2165,6 +2175,12 @@ static int selinux_binder_transfer_file(struct 
task_struct *from,
return rc;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, sid);
+   if (rc)
+   return rc;
+#endif
+
if (unlikely(IS_PRIVATE(d_backing_inode(dentry
return 0;
 
@@ -6288,6 +6304,39 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
return av;
 }
 
+/* This function will check the file pass through unix socket or binder to see
+ * if it is a bpf related object. And apply correspinding checks on the bpf
+ * object based on the type. The bpf maps and programs, not like other files 
and
+ * socket, are using a shared anonymous inode inside the kernel as their inode.
+ * So checking that inode cannot identify if the process have privilege to
+ * access the bpf object and that's why we have to add this additional check in
+ * selinux_file_receive and selinux_binder_transfer_files.
+ */
+static int bpf_fd_pass(struct file *file, u32 sid)
+{
+   struct bpf_security_struct *bpfsec;
+   struct bpf_prog *prog;
+   struct bpf_map *map;
+   int ret;
+
+   if (file->f_op == _map_fops) {
+   map = file->private_data;
+   bpfsec = map->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+  bpf_map_fmode_to_av(file->f_mode), NULL);
+   if (ret)
+   return ret;
+   } else if (file->f_op == _prog_fops) {
+   prog = file->private_data;
+   bpfsec = prog->aux->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+  BPF__PROG_RUN, NULL);
+   if (ret)
+   return ret;
+   }
+   return 0;
+}
+
 static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
 {
   

[PATCH net-next v6 0/5] bpf: security: New file mode and LSM hooks for eBPF object permission control

2017-10-16 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.

Change since V1:

 - Whitelist the new bpf flags in the map allocate check.
 - Added bpf selftest for the new flags.
 - Added two new security hooks for copying the security information from
   the bpf object security struct to file security struct
 - Simplified the checking action when bpf fd is passed between processes.

 Change since V2:

 - Fixed the line break problem for map flags check
 - Fixed the typo in selinux check of file mode.
 - Merge bpf_map and bpf_prog into one selinux class
 - Added bpf_type and bpf_sid into file security struct to store the
   security information when generate fd.
 - Add the hook to bpf_map_new_fd and bpf_prog_new_fd.

 Change since V3:

 - Return the actual error from security check instead of -EPERM
 - Move the hooks into anon_inode_getfd() to avoid get file again after
   bpf object file is installed with fd.
 - Removed the bpf_sid field inside file_scerity_struct to reduce the
   cache size.

 Change since V4:

 - Rename bpf av prog_use to prog_run to distinguish from fd_use.
 - Remove the bpf_type field inside file_scerity_struct and use bpf fops
   to indentify bpf object instead.

 Change since v5:

 - Fixed the incorrect selinux class name for SECCLASS_BPF

Chenbo Feng (5):
  bpf: Add file mode configuration into bpf maps
  bpf: Add tests for eBPF file mode
  security: bpf: Add LSM hooks for bpf object related syscall
  selinux: bpf: Add selinux check for eBPF syscall operations
  selinux: bpf: Add addtional check for bpf object file receive

 include/linux/bpf.h |  15 ++-
 include/linux/lsm_hooks.h   |  54 +++
 include/linux/security.h|  45 +
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/arraymap.c   |   6 +-
 kernel/bpf/devmap.c |   5 +-
 kernel/bpf/hashtab.c|   5 +-
 kernel/bpf/inode.c  |  15 ++-
 kernel/bpf/lpm_trie.c   |   3 +-
 kernel/bpf/sockmap.c|   5 +-
 kernel/bpf/stackmap.c   |   5 +-
 kernel/bpf/syscall.c| 118 ---
 security/security.c |  32 +++
 security/selinux/hooks.c| 160 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h  

[PATCH net-next v6 1/5] bpf: Add file mode configuration into bpf maps

2017-10-16 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  6 ++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/arraymap.c|  6 +++-
 kernel/bpf/devmap.c  |  5 ++-
 kernel/bpf/hashtab.c |  5 +--
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/lpm_trie.c|  3 +-
 kernel/bpf/sockmap.c |  5 ++-
 kernel/bpf/stackmap.c|  5 ++-
 kernel/bpf/syscall.c | 80 +++-
 10 files changed, 114 insertions(+), 22 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4373125de1f3..efbde1639970 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -308,11 +308,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);
@@ -331,6 +331,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
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6db9e1d679cd..9cb50a228c39 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -217,6 +217,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 */
@@ -259,6 +263,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 */
@@ -286,6 +291,7 @@ union bpf_attr {
__u32   map_id;
};
__u32   next_id;
+   __u32   open_flags;
};
 
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 68d866628be0..988c04c91e10 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -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;
@@ -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);
 
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index e093d9a2c4dd..e5d3de7cff2e 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -50,6 +50,9 @@
 #include 
 #include 
 
+#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;
@@ -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 &

[PATCH net-next v6 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-16 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
Acked-by: Stephen Smalley <s...@tycho.nsa.gov>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..12cf7de8cbed 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (fmode & FMODE_READ)
+   av |= BPF__MAP_READ;
+   if (fmode & FMODE_WRITE)
+   av |= BPF__MAP_WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   BPF__PROG_RUN, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..0a7023b5f000 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  

[PATCH net-next v6 3/5] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-16 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 34 +++--
 security/security.c   | 32 
 5 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index efbde1639970..1479442d5293 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -190,6 +193,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYS

[PATCH net-next v6 2/5] bpf: Add tests for eBPF file mode

2017-10-16 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Two related tests are added into bpf selftest to test read only map and
write only map. The tests verified the read only and write only flags
are working on hash maps.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 tools/testing/selftests/bpf/test_maps.c | 48 +
 1 file changed, 48 insertions(+)

diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index fe3a443a1102..896f23cfe918 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1033,6 +1033,51 @@ static void test_map_parallel(void)
assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
 }
 
+static void test_map_rdonly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_RDONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == -1 &&
+  errno == EPERM);
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == ENOENT);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
+}
+
+static void test_map_wronly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_WRONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == 0)
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == EPERM);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == EPERM);
+}
+
 static void run_all_tests(void)
 {
test_hashmap(0, NULL);
@@ -1050,6 +1095,9 @@ static void run_all_tests(void)
test_map_large();
test_map_parallel();
test_map_stress();
+
+   test_map_rdonly();
+   test_map_wronly();
 }
 
 int main(void)
-- 
2.15.0.rc0.271.g36b669edcc-goog



Re: [PATCH net-next v5 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-16 Thread Chenbo Feng
On Mon, Oct 16, 2017 at 9:34 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Thu, 2017-10-12 at 13:55 -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a bpf object related check when sending and receiving files
>> through unix domain socket as well as binder. It checks if the
>> receiving
>> process have privilege to read/write the bpf map or use the bpf
>> program.
>> This check is necessary because the bpf maps and programs are using a
>> anonymous inode as their shared inode so the normal way of checking
>> the
>> files and sockets when passing between processes cannot work properly
>> on
>> eBPF object. This check only works when the BPF_SYSCALL is
>> configured.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>> ---
>>  include/linux/bpf.h  |  3 +++
>>  kernel/bpf/syscall.c |  4 ++--
>>  security/selinux/hooks.c | 49
>> 
>>  3 files changed, 54 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 225740688ab7..81d6c01b8825 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -285,6 +285,9 @@ int bpf_prog_array_copy_to_user(struct
>> bpf_prog_array __rcu *progs,
>>  #ifdef CONFIG_BPF_SYSCALL
>>  DECLARE_PER_CPU(int, bpf_prog_active);
>>
>> +extern const struct file_operations bpf_map_fops;
>> +extern const struct file_operations bpf_prog_fops;
>> +
>>  #define BPF_PROG_TYPE(_id, _ops) \
>>   extern const struct bpf_verifier_ops _ops;
>>  #define BPF_MAP_TYPE(_id, _ops) \
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index d3e152e282d8..8bdb98aa7f34 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file *filp,
>> const char __user *buf,
>>   return -EINVAL;
>>  }
>>
>> -static const struct file_operations bpf_map_fops = {
>> +const struct file_operations bpf_map_fops = {
>>  #ifdef CONFIG_PROC_FS
>>   .show_fdinfo= bpf_map_show_fdinfo,
>>  #endif
>> @@ -967,7 +967,7 @@ static void bpf_prog_show_fdinfo(struct seq_file
>> *m, struct file *filp)
>>  }
>>  #endif
>>
>> -static const struct file_operations bpf_prog_fops = {
>> +const struct file_operations bpf_prog_fops = {
>>  #ifdef CONFIG_PROC_FS
>>   .show_fdinfo= bpf_prog_show_fdinfo,
>>  #endif
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 12cf7de8cbed..ef7e5c1de640 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -1815,6 +1815,10 @@ static inline int file_path_has_perm(const
>> struct cred *cred,
>>   return inode_has_perm(cred, file_inode(file), av, );
>>  }
>>
>> +#ifdef CONFIG_BPF_SYSCALL
>> +static int bpf_fd_pass(struct file *file, u32 sid);
>> +#endif
>> +
>>  /* Check whether a task can use an open file descriptor to
>> access an inode in a given way.  Check access to the
>> descriptor itself, and then use dentry_has_perm to
>> @@ -1845,6 +1849,12 @@ static int file_has_perm(const struct cred
>> *cred,
>>   goto out;
>>   }
>>
>> +#ifdef CONFIG_BPF_SYSCALL
>> + rc = bpf_fd_pass(file, cred_sid(cred));
>> + if (rc)
>> + return rc;
>> +#endif
>> +
>>   /* av is zero if only checking access to the descriptor. */
>>   rc = 0;
>>   if (av)
>> @@ -2165,6 +2175,12 @@ static int selinux_binder_transfer_file(struct
>> task_struct *from,
>>   return rc;
>>   }
>>
>> +#ifdef CONFIG_BPF_SYSCALL
>> + rc = bpf_fd_pass(file, sid);
>> + if (rc)
>> + return rc;
>> +#endif
>> +
>>   if (unlikely(IS_PRIVATE(d_backing_inode(dentry
>>   return 0;
>>
>> @@ -6288,6 +6304,39 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
>>   return av;
>>  }
>>
>> +/* This function will check the file pass through unix socket or
>> binder to see
>> + * if it is a bpf related object. And apply correspinding checks on
>> the bpf
>> + * object based on the type. The bpf maps and programs, not like
>> other files and
>> + * socket, are using a shared anonymous inode inside the kernel as
>> their inode.
>> + * So checking that inode cannot identify if the process have
>> privilege

[PATCH net-next v5 1/5] bpf: Add file mode configuration into bpf maps

2017-10-12 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  6 ++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/arraymap.c|  6 +++-
 kernel/bpf/devmap.c  |  5 ++-
 kernel/bpf/hashtab.c |  5 +--
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/lpm_trie.c|  3 +-
 kernel/bpf/sockmap.c |  5 ++-
 kernel/bpf/stackmap.c|  5 ++-
 kernel/bpf/syscall.c | 80 +++-
 10 files changed, 114 insertions(+), 22 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bc7da2ddfcaf..0e9ca2555d7f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -308,11 +308,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);
@@ -331,6 +331,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
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6db9e1d679cd..9cb50a228c39 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -217,6 +217,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 */
@@ -259,6 +263,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 */
@@ -286,6 +291,7 @@ union bpf_attr {
__u32   map_id;
};
__u32   next_id;
+   __u32   open_flags;
};
 
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 68d866628be0..988c04c91e10 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -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;
@@ -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);
 
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index e093d9a2c4dd..e5d3de7cff2e 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -50,6 +50,9 @@
 #include 
 #include 
 
+#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;
@@ -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 &

[PATCH net-next v5 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-12 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..12cf7de8cbed 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (fmode & FMODE_READ)
+   av |= BPF__MAP_READ;
+   if (fmode & FMODE_WRITE)
+   av |= BPF__MAP_WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   BPF__PROG_RUN, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..0a7023b5f000 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ "infiniband_

[PATCH net-next v5 3/5] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-12 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 34 +++--
 security/security.c   | 32 
 5 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0e9ca2555d7f..225740688ab7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -190,6 +193,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYS

[PATCH net-next v5 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-12 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h  |  3 +++
 kernel/bpf/syscall.c |  4 ++--
 security/selinux/hooks.c | 49 
 3 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 225740688ab7..81d6c01b8825 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -285,6 +285,9 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu 
*progs,
 #ifdef CONFIG_BPF_SYSCALL
 DECLARE_PER_CPU(int, bpf_prog_active);
 
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
 #define BPF_PROG_TYPE(_id, _ops) \
extern const struct bpf_verifier_ops _ops;
 #define BPF_MAP_TYPE(_id, _ops) \
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index d3e152e282d8..8bdb98aa7f34 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file *filp, const 
char __user *buf,
return -EINVAL;
 }
 
-static const struct file_operations bpf_map_fops = {
+const struct file_operations bpf_map_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_map_show_fdinfo,
 #endif
@@ -967,7 +967,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct 
file *filp)
 }
 #endif
 
-static const struct file_operations bpf_prog_fops = {
+const struct file_operations bpf_prog_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_prog_show_fdinfo,
 #endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 12cf7de8cbed..ef7e5c1de640 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1815,6 +1815,10 @@ static inline int file_path_has_perm(const struct cred 
*cred,
return inode_has_perm(cred, file_inode(file), av, );
 }
 
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_fd_pass(struct file *file, u32 sid);
+#endif
+
 /* Check whether a task can use an open file descriptor to
access an inode in a given way.  Check access to the
descriptor itself, and then use dentry_has_perm to
@@ -1845,6 +1849,12 @@ static int file_has_perm(const struct cred *cred,
goto out;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, cred_sid(cred));
+   if (rc)
+   return rc;
+#endif
+
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
@@ -2165,6 +2175,12 @@ static int selinux_binder_transfer_file(struct 
task_struct *from,
return rc;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, sid);
+   if (rc)
+   return rc;
+#endif
+
if (unlikely(IS_PRIVATE(d_backing_inode(dentry
return 0;
 
@@ -6288,6 +6304,39 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
return av;
 }
 
+/* This function will check the file pass through unix socket or binder to see
+ * if it is a bpf related object. And apply correspinding checks on the bpf
+ * object based on the type. The bpf maps and programs, not like other files 
and
+ * socket, are using a shared anonymous inode inside the kernel as their inode.
+ * So checking that inode cannot identify if the process have privilege to
+ * access the bpf object and that's why we have to add this additional check in
+ * selinux_file_receive and selinux_binder_transfer_files.
+ */
+static int bpf_fd_pass(struct file *file, u32 sid)
+{
+   struct bpf_security_struct *bpfsec;
+   struct bpf_prog *prog;
+   struct bpf_map *map;
+   int ret;
+
+   if (file->f_op == _map_fops) {
+   map = file->private_data;
+   bpfsec = map->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_MAP,
+  bpf_map_fmode_to_av(file->f_mode), NULL);
+   if (ret)
+   return ret;
+   } else if (file->f_op == _prog_fops) {
+   prog = file->private_data;
+   bpfsec = prog->aux->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_PROG,
+  BPF__PROG_RUN, NULL);
+   if (ret)
+   return ret;
+   }
+   return 0;
+}
+
 static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
 {
u32 sid = current_sid();
-- 
2.15.0.rc0.271.g36b669edcc-goog



[PATCH net-next v5 0/5] bpf: security: New file mode and LSM hooks for eBPF object permission control

2017-10-12 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.

Change since V1:

 - Whitelist the new bpf flags in the map allocate check.
 - Added bpf selftest for the new flags.
 - Added two new security hooks for copying the security information from
   the bpf object security struct to file security struct
 - Simplified the checking action when bpf fd is passed between processes.

 Change since V2:

 - Fixed the line break problem for map flags check
 - Fixed the typo in selinux check of file mode.
 - Merge bpf_map and bpf_prog into one selinux class
 - Added bpf_type and bpf_sid into file security struct to store the
   security information when generate fd.
 - Add the hook to bpf_map_new_fd and bpf_prog_new_fd.

 Change since V3:

 - Return the actual error from security check instead of -EPERM
 - Move the hooks into anon_inode_getfd() to avoid get file again after
   bpf object file is installed with fd.
 - Removed the bpf_sid field inside file_scerity_struct to reduce the
   cache size.

 Change since V4:

 - Rename bpf av prog_use to prog_run to distinguish from fd_use.
 - Remove the bpf_type field inside file_scerity_struct and use bpf fops
   to indentify bpf object instead.

Chenbo Feng (5):
  bpf: Add file mode configuration into bpf maps
  bpf: Add tests for eBPF file mode
  security: bpf: Add LSM hooks for bpf object related syscall
  selinux: bpf: Add selinux check for eBPF syscall operations
  selinux: bpf: Add addtional check for bpf object file receive

 include/linux/bpf.h |  15 ++-
 include/linux/lsm_hooks.h   |  54 +++
 include/linux/security.h|  45 +
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/arraymap.c   |   6 +-
 kernel/bpf/devmap.c |   5 +-
 kernel/bpf/hashtab.c|   5 +-
 kernel/bpf/inode.c  |  15 ++-
 kernel/bpf/lpm_trie.c   |   3 +-
 kernel/bpf/sockmap.c|   5 +-
 kernel/bpf/stackmap.c   |   5 +-
 kernel/bpf/syscall.c| 118 ---
 security/security.c |  32 +++
 security/selinux/hooks.c| 160 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 +
 tools/testing/selftests/bpf/test_maps.c |  48 ++
 17 files change

[PATCH net-next v5 2/5] bpf: Add tests for eBPF file mode

2017-10-12 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Two related tests are added into bpf selftest to test read only map and
write only map. The tests verified the read only and write only flags
are working on hash maps.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 tools/testing/selftests/bpf/test_maps.c | 48 +
 1 file changed, 48 insertions(+)

diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index fe3a443a1102..896f23cfe918 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1033,6 +1033,51 @@ static void test_map_parallel(void)
assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
 }
 
+static void test_map_rdonly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_RDONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == -1 &&
+  errno == EPERM);
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == ENOENT);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
+}
+
+static void test_map_wronly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_WRONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == 0)
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == EPERM);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == EPERM);
+}
+
 static void run_all_tests(void)
 {
test_hashmap(0, NULL);
@@ -1050,6 +1095,9 @@ static void run_all_tests(void)
test_map_large();
test_map_parallel();
test_map_stress();
+
+   test_map_rdonly();
+   test_map_wronly();
 }
 
 int main(void)
-- 
2.15.0.rc0.271.g36b669edcc-goog



Re: [PATCH net-next v3 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-12 Thread Chenbo Feng
On Thu, Oct 12, 2017 at 5:25 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Wed, 2017-10-11 at 13:43 -0700, Chenbo Feng via Selinux wrote:
>> On Wed, Oct 11, 2017 at 5:54 AM, Stephen Smalley <s...@tycho.nsa.gov>
>> wrote:
>> > On Tue, 2017-10-10 at 17:09 -0700, Chenbo Feng wrote:
>> > > From: Chenbo Feng <fe...@google.com>
>> > >
>> > > Introduce a bpf object related check when sending and receiving
>> > > files
>> > > through unix domain socket as well as binder. It checks if the
>> > > receiving
>> > > process have privilege to read/write the bpf map or use the bpf
>> > > program.
>> > > This check is necessary because the bpf maps and programs are
>> > > using a
>> > > anonymous inode as their shared inode so the normal way of
>> > > checking
>> > > the
>> > > files and sockets when passing between processes cannot work
>> > > properly
>> > > on
>> > > eBPF object. This check only works when the BPF_SYSCALL is
>> > > configured.
>> > > The information stored inside the file security struct is the
>> > > same as
>> > > the information in bpf object security struct.
>> > >
>> > > Signed-off-by: Chenbo Feng <fe...@google.com>
>> > > ---
>> > >  include/linux/lsm_hooks.h | 17 ++
>> > >  include/linux/security.h  |  9 ++
>> > >  kernel/bpf/syscall.c  | 27 ++--
>> > >  security/security.c   |  8 +
>> > >  security/selinux/hooks.c  | 67
>> > > +++
>> > >  security/selinux/include/objsec.h |  9 ++
>> > >  6 files changed, 135 insertions(+), 2 deletions(-)
>> > >
>> > > diff --git a/include/linux/lsm_hooks.h
>> > > b/include/linux/lsm_hooks.h
>> > > index 7161d8e7ee79..517dea60b87b 100644
>> > > --- a/include/linux/lsm_hooks.h
>> > > +++ b/include/linux/lsm_hooks.h
>> > > @@ -1385,6 +1385,19 @@
>> > >   * @bpf_prog_free_security:
>> > >   *   Clean up the security information stored inside bpf prog.
>> > >   *
>> > > + * @bpf_map_file:
>> > > + *   When creating a bpf map fd, set up the file security
>> > > information with
>> > > + *   the bpf security information stored in the map struct. So
>> > > when the map
>> > > + *   fd is passed between processes, the security module can
>> > > directly read
>> > > + *   the security information from file security struct rather
>> > > than the bpf
>> > > + *   security struct.
>> > > + *
>> > > + * @bpf_prog_file:
>> > > + *   When creating a bpf prog fd, set up the file security
>> > > information with
>> > > + *   the bpf security information stored in the prog struct. So
>> > > when the prog
>> > > + *   fd is passed between processes, the security module can
>> > > directly read
>> > > + *   the security information from file security struct rather
>> > > than the bpf
>> > > + *   security struct.
>> > >   */
>> > >  union security_list_options {
>> > >   int (*binder_set_context_mgr)(struct task_struct *mgr);
>> > > @@ -1726,6 +1739,8 @@ union security_list_options {
>> > >   void (*bpf_map_free_security)(struct bpf_map *map);
>> > >   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
>> > >   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
>> > > + void (*bpf_map_file)(struct bpf_map *map, struct file
>> > > *file);
>> > > + void (*bpf_prog_file)(struct bpf_prog_aux *aux, struct file
>> > > *file);
>> > >  #endif /* CONFIG_BPF_SYSCALL */
>> > >  };
>> > >
>> > > @@ -1954,6 +1969,8 @@ struct security_hook_heads {
>> > >   struct list_head bpf_map_free_security;
>> > >   struct list_head bpf_prog_alloc_security;
>> > >   struct list_head bpf_prog_free_security;
>> > > + struct list_head bpf_map_file;
>> > > + struct list_head bpf_prog_file;
>> > >  #endif /* CONFIG_BPF_SYSCALL */
>> > >  } __randomize_layout;
>> > >
>> > > diff --git a/include/linux/security.h b/include/linux/security

[PATCH net-next v4 3/5] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-11 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 34 +++--
 security/security.c   | 32 
 5 files changed, 169 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0e9ca2555d7f..225740688ab7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -190,6 +193,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYS

[PATCH net-next v4 0/5] bpf: security: New file mode and LSM hooks for eBPF object permission control

2017-10-11 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.

Change since V1:

 - Whitelist the new bpf flags in the map allocate check.
 - Added bpf selftest for the new flags.
 - Added two new security hooks for copying the security information from
   the bpf object security struct to file security struct
 - Simplified the checking action when bpf fd is passed between processes.

 Change since V2:

 - Fixed the line break problem for map flags check
 - Fixed the typo in selinux check of file mode.
 - Merge bpf_map and bpf_prog into one selinux class
 - Added bpf_type and bpf_sid into file security struct to store the
   security information when generate fd.
 - Add the hook to bpf_map_new_fd and bpf_prog_new_fd.

 Change since V3:

 - Return the actual error from security check instead of -EPERM
 - Move the hooks into anon_inode_getfd() to avoid get file again after
   bpf object file is installed with fd.
 - Removed the bpf_sid field inside file_scerity_struct to reduce the
   cache size.

Chenbo Feng (5):
  bpf: Add file mode configuration into bpf maps
  bpf: Add tests for eBPF file mode
  security: bpf: Add LSM hooks for bpf object related syscall
  selinux: bpf: Add selinux check for eBPF syscall operations
  selinux: bpf: Add addtional check for bpf object file receive

 fs/anon_inodes.c|   7 ++
 include/linux/bpf.h |  12 ++-
 include/linux/lsm_hooks.h   |  71 +
 include/linux/security.h|  53 ++
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/arraymap.c   |   6 +-
 kernel/bpf/devmap.c |   5 +-
 kernel/bpf/hashtab.c|   5 +-
 kernel/bpf/inode.c  |  15 ++-
 kernel/bpf/lpm_trie.c   |   3 +-
 kernel/bpf/sockmap.c|   5 +-
 kernel/bpf/stackmap.c   |   5 +-
 kernel/bpf/syscall.c| 108 +--
 security/security.c |  40 +++
 security/selinux/hooks.c| 182 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |  12 +++
 tools/testing/selftests/bpf/test_maps.c |  48 +
 18 files changed, 561 insertions(+), 24 deletions(-)

-- 
2.15.0.rc0.271.g36b669edcc-goog



[PATCH net-next v4 2/5] bpf: Add tests for eBPF file mode

2017-10-11 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Two related tests are added into bpf selftest to test read only map and
write only map. The tests verified the read only and write only flags
are working on hash maps.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 tools/testing/selftests/bpf/test_maps.c | 48 +
 1 file changed, 48 insertions(+)

diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index fe3a443a1102..896f23cfe918 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1033,6 +1033,51 @@ static void test_map_parallel(void)
assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
 }
 
+static void test_map_rdonly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_RDONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == -1 &&
+  errno == EPERM);
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == ENOENT);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
+}
+
+static void test_map_wronly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_WRONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == 0)
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == EPERM);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == EPERM);
+}
+
 static void run_all_tests(void)
 {
test_hashmap(0, NULL);
@@ -1050,6 +1095,9 @@ static void run_all_tests(void)
test_map_large();
test_map_parallel();
test_map_stress();
+
+   test_map_rdonly();
+   test_map_wronly();
 }
 
 int main(void)
-- 
2.15.0.rc0.271.g36b669edcc-goog



[PATCH net-next v4 1/5] bpf: Add file mode configuration into bpf maps

2017-10-11 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  6 ++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/arraymap.c|  6 +++-
 kernel/bpf/devmap.c  |  5 ++-
 kernel/bpf/hashtab.c |  5 +--
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/lpm_trie.c|  3 +-
 kernel/bpf/sockmap.c |  5 ++-
 kernel/bpf/stackmap.c|  5 ++-
 kernel/bpf/syscall.c | 80 +++-
 10 files changed, 114 insertions(+), 22 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bc7da2ddfcaf..0e9ca2555d7f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -308,11 +308,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);
@@ -331,6 +331,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
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6db9e1d679cd..9cb50a228c39 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -217,6 +217,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 */
@@ -259,6 +263,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 */
@@ -286,6 +291,7 @@ union bpf_attr {
__u32   map_id;
};
__u32   next_id;
+   __u32   open_flags;
};
 
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 68d866628be0..988c04c91e10 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -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;
@@ -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);
 
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index e093d9a2c4dd..e5d3de7cff2e 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -50,6 +50,9 @@
 #include 
 #include 
 
+#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;
@@ -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 &

[PATCH net-next v4 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-11 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..94e473b9c884 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (fmode & FMODE_READ)
+   av |= BPF__MAP_READ;
+   if (fmode & FMODE_WRITE)
+   av |= BPF__MAP_WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   BPF__PROG_USE, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..a91fa46a789f 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ "infiniband_

[PATCH net-next v4 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-11 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.
The information stored inside the file security struct is the same as
the information in bpf object security struct.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 fs/anon_inodes.c  |  7 
 include/linux/lsm_hooks.h | 17 ++
 include/linux/security.h  |  8 +
 security/security.c   |  8 +
 security/selinux/hooks.c  | 71 +++
 security/selinux/include/objsec.h |  8 +
 6 files changed, 119 insertions(+)

diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 3168ee4e77f4..7a950978622c 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -152,6 +153,12 @@ int anon_inode_getfd(const char *name, const struct 
file_operations *fops,
error = PTR_ERR(file);
goto err_put_unused_fd;
}
+#ifdef CONFIG_BPF_SYSCALL
+   if (!strcmp(name, "bpf-map"))
+   security_bpf_map_file(file);
+   else if (!strcmp(name, "bpf-prog"))
+   security_bpf_prog_file(file);
+#endif
fd_install(fd, file);
 
return fd;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7161d8e7ee79..fdeadb4ba590 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1385,6 +1385,19 @@
  * @bpf_prog_free_security:
  * Clean up the security information stored inside bpf prog.
  *
+ * @bpf_map_file:
+ * When creating a bpf map fd, set up the file security information with
+ * the bpf security information stored in the map struct. So when the map
+ * fd is passed between processes, the security module can directly read
+ * the security information from file security struct rather than the bpf
+ * security struct.
+ *
+ * @bpf_prog_file:
+ * When creating a bpf prog fd, set up the file security information with
+ * the bpf security information stored in the prog struct. So when the prog
+ * fd is passed between processes, the security module can directly read
+ * the security information from file security struct rather than the bpf
+ * security struct.
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1726,6 +1739,8 @@ union security_list_options {
void (*bpf_map_free_security)(struct bpf_map *map);
int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+   void (*bpf_map_file)(struct file *file);
+   void (*bpf_prog_file)(struct file *file);
 #endif /* CONFIG_BPF_SYSCALL */
 };
 
@@ -1954,6 +1969,8 @@ struct security_hook_heads {
struct list_head bpf_map_free_security;
struct list_head bpf_prog_alloc_security;
struct list_head bpf_prog_free_security;
+   struct list_head bpf_map_file;
+   struct list_head bpf_prog_file;
 #endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
diff --git a/include/linux/security.h b/include/linux/security.h
index 18800b0911e5..ebb0cca5eef1 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1740,6 +1740,8 @@ extern int security_bpf_map_alloc(struct bpf_map *map);
 extern void security_bpf_map_free(struct bpf_map *map);
 extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
 extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
+extern void security_bpf_map_file(struct file *file);
+extern void security_bpf_prog_file(struct file *file);
 #else
 static inline int security_bpf(int cmd, union bpf_attr *attr,
 unsigned int size)
@@ -1772,6 +1774,12 @@ static inline int security_bpf_prog_alloc(struct 
bpf_prog_aux *aux)
 
 static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
 { }
+
+static inline void security_bpf_map_file(struct file *file)
+{ }
+
+static inline void security_bpf_prog_file(struct file *file)
+{ }
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_BPF_SYSCALL */
 
diff --git a/security/security.c b/security/security.c
index 1cd8526cb0b7..2ee6ba5cd690 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1734,4 +1734,12 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux)
 {
call_void_hook(bpf_prog_free_security, aux);
 }
+void security_bpf_map_file(struct file *file)
+{
+   call_void_ho

Re: [PATCH net-next v3 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-11 Thread Chenbo Feng
On Wed, Oct 11, 2017 at 5:54 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Tue, 2017-10-10 at 17:09 -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a bpf object related check when sending and receiving files
>> through unix domain socket as well as binder. It checks if the
>> receiving
>> process have privilege to read/write the bpf map or use the bpf
>> program.
>> This check is necessary because the bpf maps and programs are using a
>> anonymous inode as their shared inode so the normal way of checking
>> the
>> files and sockets when passing between processes cannot work properly
>> on
>> eBPF object. This check only works when the BPF_SYSCALL is
>> configured.
>> The information stored inside the file security struct is the same as
>> the information in bpf object security struct.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>> ---
>>  include/linux/lsm_hooks.h | 17 ++
>>  include/linux/security.h  |  9 ++
>>  kernel/bpf/syscall.c  | 27 ++--
>>  security/security.c   |  8 +
>>  security/selinux/hooks.c  | 67
>> +++
>>  security/selinux/include/objsec.h |  9 ++
>>  6 files changed, 135 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
>> index 7161d8e7ee79..517dea60b87b 100644
>> --- a/include/linux/lsm_hooks.h
>> +++ b/include/linux/lsm_hooks.h
>> @@ -1385,6 +1385,19 @@
>>   * @bpf_prog_free_security:
>>   *   Clean up the security information stored inside bpf prog.
>>   *
>> + * @bpf_map_file:
>> + *   When creating a bpf map fd, set up the file security
>> information with
>> + *   the bpf security information stored in the map struct. So
>> when the map
>> + *   fd is passed between processes, the security module can
>> directly read
>> + *   the security information from file security struct rather
>> than the bpf
>> + *   security struct.
>> + *
>> + * @bpf_prog_file:
>> + *   When creating a bpf prog fd, set up the file security
>> information with
>> + *   the bpf security information stored in the prog struct. So
>> when the prog
>> + *   fd is passed between processes, the security module can
>> directly read
>> + *   the security information from file security struct rather
>> than the bpf
>> + *   security struct.
>>   */
>>  union security_list_options {
>>   int (*binder_set_context_mgr)(struct task_struct *mgr);
>> @@ -1726,6 +1739,8 @@ union security_list_options {
>>   void (*bpf_map_free_security)(struct bpf_map *map);
>>   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
>>   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
>> + void (*bpf_map_file)(struct bpf_map *map, struct file
>> *file);
>> + void (*bpf_prog_file)(struct bpf_prog_aux *aux, struct file
>> *file);
>>  #endif /* CONFIG_BPF_SYSCALL */
>>  };
>>
>> @@ -1954,6 +1969,8 @@ struct security_hook_heads {
>>   struct list_head bpf_map_free_security;
>>   struct list_head bpf_prog_alloc_security;
>>   struct list_head bpf_prog_free_security;
>> + struct list_head bpf_map_file;
>> + struct list_head bpf_prog_file;
>>  #endif /* CONFIG_BPF_SYSCALL */
>>  } __randomize_layout;
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 18800b0911e5..57573b794e2d 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -1740,6 +1740,8 @@ extern int security_bpf_map_alloc(struct
>> bpf_map *map);
>>  extern void security_bpf_map_free(struct bpf_map *map);
>>  extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
>>  extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
>> +extern void security_bpf_map_file(struct bpf_map *map, struct file
>> *file);
>> +extern void security_bpf_prog_file(struct bpf_prog_aux *aux, struct
>> file *file);
>>  #else
>>  static inline int security_bpf(int cmd, union bpf_attr *attr,
>>unsigned int size)
>> @@ -1772,6 +1774,13 @@ static inline int
>> security_bpf_prog_alloc(struct bpf_prog_aux *aux)
>>
>>  static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
>>  { }
>> +
>> +static inline void security_bpf_map_file(struct bpf_map *map, struct
>> file *file)
>> +{ }

[PATCH net-next v3 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.
The information stored inside the file security struct is the same as
the information in bpf object security struct.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/lsm_hooks.h | 17 ++
 include/linux/security.h  |  9 ++
 kernel/bpf/syscall.c  | 27 ++--
 security/security.c   |  8 +
 security/selinux/hooks.c  | 67 +++
 security/selinux/include/objsec.h |  9 ++
 6 files changed, 135 insertions(+), 2 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7161d8e7ee79..517dea60b87b 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1385,6 +1385,19 @@
  * @bpf_prog_free_security:
  * Clean up the security information stored inside bpf prog.
  *
+ * @bpf_map_file:
+ * When creating a bpf map fd, set up the file security information with
+ * the bpf security information stored in the map struct. So when the map
+ * fd is passed between processes, the security module can directly read
+ * the security information from file security struct rather than the bpf
+ * security struct.
+ *
+ * @bpf_prog_file:
+ * When creating a bpf prog fd, set up the file security information with
+ * the bpf security information stored in the prog struct. So when the prog
+ * fd is passed between processes, the security module can directly read
+ * the security information from file security struct rather than the bpf
+ * security struct.
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1726,6 +1739,8 @@ union security_list_options {
void (*bpf_map_free_security)(struct bpf_map *map);
int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+   void (*bpf_map_file)(struct bpf_map *map, struct file *file);
+   void (*bpf_prog_file)(struct bpf_prog_aux *aux, struct file *file);
 #endif /* CONFIG_BPF_SYSCALL */
 };
 
@@ -1954,6 +1969,8 @@ struct security_hook_heads {
struct list_head bpf_map_free_security;
struct list_head bpf_prog_alloc_security;
struct list_head bpf_prog_free_security;
+   struct list_head bpf_map_file;
+   struct list_head bpf_prog_file;
 #endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
diff --git a/include/linux/security.h b/include/linux/security.h
index 18800b0911e5..57573b794e2d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1740,6 +1740,8 @@ extern int security_bpf_map_alloc(struct bpf_map *map);
 extern void security_bpf_map_free(struct bpf_map *map);
 extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
 extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
+extern void security_bpf_map_file(struct bpf_map *map, struct file *file);
+extern void security_bpf_prog_file(struct bpf_prog_aux *aux, struct file 
*file);
 #else
 static inline int security_bpf(int cmd, union bpf_attr *attr,
 unsigned int size)
@@ -1772,6 +1774,13 @@ static inline int security_bpf_prog_alloc(struct 
bpf_prog_aux *aux)
 
 static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
 { }
+
+static inline void security_bpf_map_file(struct bpf_map *map, struct file 
*file)
+{ }
+
+static inline void security_bpf_prog_file(struct bpf_prog_aux *aux,
+ struct file *file)
+{ }
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_BPF_SYSCALL */
 
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 1cf31ddd7616..aee69e564c50 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -324,11 +324,22 @@ static const struct file_operations bpf_map_fops = {
 
 int bpf_map_new_fd(struct bpf_map *map, int flags)
 {
+   int fd;
+   struct fd f;
if (security_bpf_map(map, OPEN_FMODE(flags)))
return -EPERM;
 
-   return anon_inode_getfd("bpf-map", _map_fops, map,
+   fd = anon_inode_getfd("bpf-map", _map_fops, map,
flags | O_CLOEXEC);
+   if (fd < 0)
+   return fd;
+
+   f = fdget(fd);
+   if (!f.file)
+   return -EBADF;
+   security_bpf_map_file(map, f.file);
+   fdput(f);
+   return fd;
 }
 
 int bpf_get_file_flag(int 

[PATCH net-next v3 2/5] bpf: Add tests for eBPF file mode

2017-10-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Two related tests are added into bpf selftest to test read only map and
write only map. The tests verified the read only and write only flags
are working on hash maps.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 tools/testing/selftests/bpf/test_maps.c | 48 +
 1 file changed, 48 insertions(+)

diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index fe3a443a1102..896f23cfe918 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1033,6 +1033,51 @@ static void test_map_parallel(void)
assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
 }
 
+static void test_map_rdonly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_RDONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == -1 &&
+  errno == EPERM);
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == ENOENT);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
+}
+
+static void test_map_wronly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_WRONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == 0)
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == EPERM);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == EPERM);
+}
+
 static void run_all_tests(void)
 {
test_hashmap(0, NULL);
@@ -1050,6 +1095,9 @@ static void run_all_tests(void)
test_map_large();
test_map_parallel();
test_map_stress();
+
+   test_map_rdonly();
+   test_map_wronly();
 }
 
 int main(void)
-- 
2.14.2.920.gcf0c67979c-goog



[PATCH net-next v3 1/5] bpf: Add file mode configuration into bpf maps

2017-10-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  6 ++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/arraymap.c|  6 +++-
 kernel/bpf/devmap.c  |  5 ++-
 kernel/bpf/hashtab.c |  5 +--
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/lpm_trie.c|  3 +-
 kernel/bpf/sockmap.c |  5 ++-
 kernel/bpf/stackmap.c|  5 ++-
 kernel/bpf/syscall.c | 80 +++-
 10 files changed, 114 insertions(+), 22 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bc7da2ddfcaf..0e9ca2555d7f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -308,11 +308,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);
@@ -331,6 +331,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
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6db9e1d679cd..9cb50a228c39 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -217,6 +217,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 */
@@ -259,6 +263,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 */
@@ -286,6 +291,7 @@ union bpf_attr {
__u32   map_id;
};
__u32   next_id;
+   __u32   open_flags;
};
 
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 68d866628be0..988c04c91e10 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -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;
@@ -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);
 
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index e093d9a2c4dd..e5d3de7cff2e 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -50,6 +50,9 @@
 #include 
 #include 
 
+#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;
@@ -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 &

[PATCH net-next v3 3/5] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 28 ++--
 security/security.c   | 32 
 5 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0e9ca2555d7f..225740688ab7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -190,6 +193,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+#ifdef CON

[PATCH net-next v3 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..94e473b9c884 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (fmode & FMODE_READ)
+   av |= BPF__MAP_READ;
+   if (fmode & FMODE_WRITE)
+   av |= BPF__MAP_WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+   BPF__PROG_USE, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..a91fa46a789f 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ "infiniband_

[PATCH net-next v3 0/5] bpf: security: New file mode and LSM hooks for eBPF object permission control

2017-10-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.

Change since V1:

 - Whitelist the new bpf flags in the map allocate check.
 - Added bpf selftest for the new flags.
 - Added two new security hooks for copying the security information from
   the bpf object security struct to file security struct
 - Simplified the checking action when bpf fd is passed between processes.

 Change since V2:

 - Fixed the line break problem for map flags check
 - Fixed the typo in selinux check of file mode.
 - Merge bpf_map and bpf_prog into one selinux class
 - Added bpf_type and bpf_sid into file security struct to store the
   security information when generate fd.
 - Add the hook to bpf_map_new_fd and bpf_prog_new_fd.

Chenbo Feng (5):
  bpf: Add file mode configuration into bpf maps
  bpf: Add tests for eBPF file mode
  security: bpf: Add LSM hooks for bpf object related syscall
  selinux: bpf: Add selinux check for eBPF syscall operations
  selinux: bpf: Add addtional check for bpf object file receive

 include/linux/bpf.h |  12 ++-
 include/linux/lsm_hooks.h   |  71 +
 include/linux/security.h|  54 ++
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/arraymap.c   |   6 +-
 kernel/bpf/devmap.c |   5 +-
 kernel/bpf/hashtab.c|   5 +-
 kernel/bpf/inode.c  |  15 ++-
 kernel/bpf/lpm_trie.c   |   3 +-
 kernel/bpf/sockmap.c|   5 +-
 kernel/bpf/stackmap.c   |   5 +-
 kernel/bpf/syscall.c| 108 ++--
 security/security.c |  40 
 security/selinux/hooks.c| 174 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |  13 +++
 tools/testing/selftests/bpf/test_maps.c |  48 +
 17 files changed, 548 insertions(+), 24 deletions(-)

-- 
2.14.2.920.gcf0c67979c-goog



Re: [Non-DoD Source] Re: [PATCH net-next v2 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-10 Thread Chenbo Feng
On Tue, Oct 10, 2017 at 12:23 PM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Tue, 2017-10-10 at 10:48 -0700, Chenbo Feng wrote:
>> On Tue, Oct 10, 2017 at 7:24 AM, Stephen Smalley <s...@tycho.nsa.gov>
>> wrote:
>> > On Mon, 2017-10-09 at 15:20 -0700, Chenbo Feng wrote:
>> > > From: Chenbo Feng <fe...@google.com>
>> > >
>> > > Introduce a bpf object related check when sending and receiving
>> > > files
>> > > through unix domain socket as well as binder. It checks if the
>> > > receiving
>> > > process have privilege to read/write the bpf map or use the bpf
>> > > program.
>> > > This check is necessary because the bpf maps and programs are
>> > > using a
>> > > anonymous inode as their shared inode so the normal way of
>> > > checking
>> > > the
>> > > files and sockets when passing between processes cannot work
>> > > properly
>> > > on
>> > > eBPF object. This check only works when the BPF_SYSCALL is
>> > > configured.
>> > > The information stored inside the file security struct is the
>> > > same as
>> > > the information in bpf object security struct.
>> > >
>> > > Signed-off-by: Chenbo Feng <fe...@google.com>
>> > > ---
>> > >  include/linux/bpf.h   |  3 +++
>> > >  include/linux/lsm_hooks.h | 17 +
>> > >  include/linux/security.h  |  9 +++
>> > >  kernel/bpf/syscall.c  |  4 ++--
>> > >  security/security.c   |  8 +++
>> > >  security/selinux/hooks.c  | 61
>> > > +++
>> > >  6 files changed, 100 insertions(+), 2 deletions(-)
>> > >
>> > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> > > index 225740688ab7..81d6c01b8825 100644
>> > > --- a/include/linux/bpf.h
>> > > +++ b/include/linux/bpf.h
>> > > @@ -285,6 +285,9 @@ int bpf_prog_array_copy_to_user(struct
>> > > bpf_prog_array __rcu *progs,
>> > >  #ifdef CONFIG_BPF_SYSCALL
>> > >  DECLARE_PER_CPU(int, bpf_prog_active);
>> > >
>> > > +extern const struct file_operations bpf_map_fops;
>> > > +extern const struct file_operations bpf_prog_fops;
>> > > +
>> > >  #define BPF_PROG_TYPE(_id, _ops) \
>> > >   extern const struct bpf_verifier_ops _ops;
>> > >  #define BPF_MAP_TYPE(_id, _ops) \
>> > > diff --git a/include/linux/lsm_hooks.h
>> > > b/include/linux/lsm_hooks.h
>> > > index 7161d8e7ee79..517dea60b87b 100644
>> > > --- a/include/linux/lsm_hooks.h
>> > > +++ b/include/linux/lsm_hooks.h
>> > > @@ -1385,6 +1385,19 @@
>> > >   * @bpf_prog_free_security:
>> > >   *   Clean up the security information stored inside bpf prog.
>> > >   *
>> > > + * @bpf_map_file:
>> > > + *   When creating a bpf map fd, set up the file security
>> > > information with
>> > > + *   the bpf security information stored in the map struct. So
>> > > when the map
>> > > + *   fd is passed between processes, the security module can
>> > > directly read
>> > > + *   the security information from file security struct rather
>> > > than the bpf
>> > > + *   security struct.
>> > > + *
>> > > + * @bpf_prog_file:
>> > > + *   When creating a bpf prog fd, set up the file security
>> > > information with
>> > > + *   the bpf security information stored in the prog struct. So
>> > > when the prog
>> > > + *   fd is passed between processes, the security module can
>> > > directly read
>> > > + *   the security information from file security struct rather
>> > > than the bpf
>> > > + *   security struct.
>> > >   */
>> > >  union security_list_options {
>> > >   int (*binder_set_context_mgr)(struct task_struct *mgr);
>> > > @@ -1726,6 +1739,8 @@ union security_list_options {
>> > >   void (*bpf_map_free_security)(struct bpf_map *map);
>> > >   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
>> > >   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
>> > > + void (*bpf_map_file)(struct bpf_map *map, struct file
>> > > *file);
>> > > + void (*bpf_prog_file)(

Re: [PATCH net-next v2 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-10 Thread Chenbo Feng
On Tue, Oct 10, 2017 at 7:52 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Tue, 2017-10-10 at 10:18 -0400, Stephen Smalley wrote:
>> On Mon, 2017-10-09 at 15:20 -0700, Chenbo Feng wrote:
>> > From: Chenbo Feng <fe...@google.com>
>> >
>> > Implement the actual checks introduced to eBPF related syscalls.
>> > This
>> > implementation use the security field inside bpf object to store a
>> > sid that
>> > identify the bpf object. And when processes try to access the
>> > object,
>> > selinux will check if processes have the right privileges. The
>> > creation
>> > of eBPF object are also checked at the general bpf check hook and
>> > new
>> > cmd introduced to eBPF domain can also be checked there.
>> >
>> > Signed-off-by: Chenbo Feng <fe...@google.com>
>> > Acked-by: Alexei Starovoitov <a...@kernel.org>
>> > ---
>> >  security/selinux/hooks.c| 111
>> > 
>> >  security/selinux/include/classmap.h |   2 +
>> >  security/selinux/include/objsec.h   |   4 ++
>> >  3 files changed, 117 insertions(+)
>> >
>> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> > index f5d304736852..41aba4e3d57c 100644
>> > --- a/security/selinux/hooks.c
>> > +++ b/security/selinux/hooks.c
>> > @@ -85,6 +85,7 @@
>> >  #include 
>> >  #include 
>> >  #include 
>> > +#include 
>> >
>> >  #include "avc.h"
>> >  #include "objsec.h"
>> > @@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void
>> > *ib_sec)
>> >  }
>> >  #endif
>> >
>> > +#ifdef CONFIG_BPF_SYSCALL
>> > +static int selinux_bpf(int cmd, union bpf_attr *attr,
>> > +unsigned int size)
>> > +{
>> > +   u32 sid = current_sid();
>> > +   int ret;
>> > +
>> > +   switch (cmd) {
>> > +   case BPF_MAP_CREATE:
>> > +   ret = avc_has_perm(sid, sid, SECCLASS_BPF_MAP,
>> > BPF_MAP__CREATE,
>> > +  NULL);
>> > +   break;
>> > +   case BPF_PROG_LOAD:
>> > +   ret = avc_has_perm(sid, sid, SECCLASS_BPF_PROG,
>> > BPF_PROG__LOAD,
>> > +  NULL);
>> > +   break;
>> > +   default:
>> > +   ret = 0;
>> > +   break;
>> > +   }
>> > +
>> > +   return ret;
>> > +}
>> > +
>> > +static u32 bpf_map_fmode_to_av(fmode_t fmode)
>> > +{
>> > +   u32 av = 0;
>> > +
>> > +   if (f_mode & FMODE_READ)
>> > +   av |= BPF_MAP__READ;
>> > +   if (f_mode & FMODE_WRITE)
>> > +   av |= BPF_MAP__WRITE;
>> > +   return av;
>> > +}
>> > +
>> > +static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
>> > +{
>> > +   u32 sid = current_sid();
>> > +   struct bpf_security_struct *bpfsec;
>> > +
>> > +   bpfsec = map->security;
>> > +   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_MAP,
>> > +   bpf_map_fmode_to_av(fmode), NULL);
>> > +}
>> > +
>> > +static int selinux_bpf_prog(struct bpf_prog *prog)
>> > +{
>> > +   u32 sid = current_sid();
>> > +   struct bpf_security_struct *bpfsec;
>> > +
>> > +   bpfsec = prog->aux->security;
>> > +   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_PROG,
>> > +   BPF_PROG__USE, NULL);
>> > +}
>> > +
>> > +static int selinux_bpf_map_alloc(struct bpf_map *map)
>> > +{
>> > +   struct bpf_security_struct *bpfsec;
>> > +
>> > +   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
>> > +   if (!bpfsec)
>> > +   return -ENOMEM;
>> > +
>> > +   bpfsec->sid = current_sid();
>> > +   map->security = bpfsec;
>> > +
>> > +   return 0;
>> > +}
>> > +
>> > +static void selinux_bpf_map_free(struct bpf_map *map)
>> > +{
>> > +   struct bpf_security_struct *bpfsec = map->security;
>> > +
>> > +   map->security = NULL;
>> > +   kfree(bpfsec);
>> > +}
>> > +
>> > +static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
>> > +{
>> > 

Re: [PATCH net-next v2 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-10 Thread Chenbo Feng
On Tue, Oct 10, 2017 at 7:24 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Mon, 2017-10-09 at 15:20 -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a bpf object related check when sending and receiving files
>> through unix domain socket as well as binder. It checks if the
>> receiving
>> process have privilege to read/write the bpf map or use the bpf
>> program.
>> This check is necessary because the bpf maps and programs are using a
>> anonymous inode as their shared inode so the normal way of checking
>> the
>> files and sockets when passing between processes cannot work properly
>> on
>> eBPF object. This check only works when the BPF_SYSCALL is
>> configured.
>> The information stored inside the file security struct is the same as
>> the information in bpf object security struct.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>> ---
>>  include/linux/bpf.h   |  3 +++
>>  include/linux/lsm_hooks.h | 17 +
>>  include/linux/security.h  |  9 +++
>>  kernel/bpf/syscall.c  |  4 ++--
>>  security/security.c   |  8 +++
>>  security/selinux/hooks.c  | 61
>> +++
>>  6 files changed, 100 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 225740688ab7..81d6c01b8825 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -285,6 +285,9 @@ int bpf_prog_array_copy_to_user(struct
>> bpf_prog_array __rcu *progs,
>>  #ifdef CONFIG_BPF_SYSCALL
>>  DECLARE_PER_CPU(int, bpf_prog_active);
>>
>> +extern const struct file_operations bpf_map_fops;
>> +extern const struct file_operations bpf_prog_fops;
>> +
>>  #define BPF_PROG_TYPE(_id, _ops) \
>>   extern const struct bpf_verifier_ops _ops;
>>  #define BPF_MAP_TYPE(_id, _ops) \
>> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
>> index 7161d8e7ee79..517dea60b87b 100644
>> --- a/include/linux/lsm_hooks.h
>> +++ b/include/linux/lsm_hooks.h
>> @@ -1385,6 +1385,19 @@
>>   * @bpf_prog_free_security:
>>   *   Clean up the security information stored inside bpf prog.
>>   *
>> + * @bpf_map_file:
>> + *   When creating a bpf map fd, set up the file security
>> information with
>> + *   the bpf security information stored in the map struct. So
>> when the map
>> + *   fd is passed between processes, the security module can
>> directly read
>> + *   the security information from file security struct rather
>> than the bpf
>> + *   security struct.
>> + *
>> + * @bpf_prog_file:
>> + *   When creating a bpf prog fd, set up the file security
>> information with
>> + *   the bpf security information stored in the prog struct. So
>> when the prog
>> + *   fd is passed between processes, the security module can
>> directly read
>> + *   the security information from file security struct rather
>> than the bpf
>> + *   security struct.
>>   */
>>  union security_list_options {
>>   int (*binder_set_context_mgr)(struct task_struct *mgr);
>> @@ -1726,6 +1739,8 @@ union security_list_options {
>>   void (*bpf_map_free_security)(struct bpf_map *map);
>>   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
>>   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
>> + void (*bpf_map_file)(struct bpf_map *map, struct file
>> *file);
>> + void (*bpf_prog_file)(struct bpf_prog_aux *aux, struct file
>> *file);
>>  #endif /* CONFIG_BPF_SYSCALL */
>>  };
>>
>> @@ -1954,6 +1969,8 @@ struct security_hook_heads {
>>   struct list_head bpf_map_free_security;
>>   struct list_head bpf_prog_alloc_security;
>>   struct list_head bpf_prog_free_security;
>> + struct list_head bpf_map_file;
>> + struct list_head bpf_prog_file;
>>  #endif /* CONFIG_BPF_SYSCALL */
>>  } __randomize_layout;
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 18800b0911e5..57573b794e2d 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -1740,6 +1740,8 @@ extern int security_bpf_map_alloc(struct
>> bpf_map *map);
>>  extern void security_bpf_map_free(struct bpf_map *map);
>>  extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
>>  extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
>> +extern void security_bpf_map_file(struct bpf_map *map, struct file
&

Re: [PATCH net-next v2 1/5] bpf: Add file mode configuration into bpf maps

2017-10-09 Thread Chenbo Feng
On Mon, Oct 9, 2017 at 4:07 PM, Alexei Starovoitov
<alexei.starovoi...@gmail.com> wrote:
> On Mon, Oct 09, 2017 at 03:20:24PM -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> 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 <fe...@google.com>
>> Acked-by: Alexei Starovoitov <a...@kernel.org>
>> ---
>>  include/linux/bpf.h  |  6 ++--
>>  include/uapi/linux/bpf.h |  6 
>>  kernel/bpf/arraymap.c|  7 +++--
>>  kernel/bpf/devmap.c  |  5 ++-
>>  kernel/bpf/hashtab.c |  5 +--
>>  kernel/bpf/inode.c   | 15 ++---
>>  kernel/bpf/lpm_trie.c|  3 +-
>>  kernel/bpf/sockmap.c |  5 ++-
>>  kernel/bpf/stackmap.c|  5 ++-
>>  kernel/bpf/syscall.c | 80 
>> +++-
>>  10 files changed, 114 insertions(+), 23 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index bc7da2ddfcaf..0e9ca2555d7f 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -308,11 +308,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);
>> @@ -331,6 +331,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
>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>> index 6db9e1d679cd..9cb50a228c39 100644
>> --- a/include/uapi/linux/bpf.h
>> +++ b/include/uapi/linux/bpf.h
>> @@ -217,6 +217,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 */
>> @@ -259,6 +263,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 */
>> @@ -286,6 +291,7 @@ union bpf_attr {
>>   __u32   map_id;
>>   };
>>   __u32   next_id;
>> + __u32   open_flags;
>>   };
>>
>>   struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
>> diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
>> index 68d866628be0..f869e48ef2f6 100644
>> --- a/kernel/bpf/arraymap.c
>> +++ b/kernel/bpf/arraymap.c
>> @@ -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;
>> @@ -56,8 +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 ||
>> - (percpu && numa_node != NUMA_NO_NODE))
>> + attr->value_size == 0 || attr->map_flags &
>> + ~ARRAY_CREATE_FLAG_MASK || (percpu && numa_node != NUMA_NO_NODE))
>
> that's very non-standard way of breaking lines.
> Did you run checkpatch ? did it complain?
>
Will fix in next revision, checkpatch didn't say anything about
this0 error and 0 warning for this patch series.


[PATCH net-next v2 2/5] bpf: Add tests for eBPF file mode

2017-10-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Two related tests are added into bpf selftest to test read only map and
write only map. The tests verified the read only and write only flags
are working on hash maps.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 tools/testing/selftests/bpf/test_maps.c | 48 +
 1 file changed, 48 insertions(+)

diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index fe3a443a1102..896f23cfe918 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -1033,6 +1033,51 @@ static void test_map_parallel(void)
assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
 }
 
+static void test_map_rdonly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_RDONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == -1 &&
+  errno == EPERM);
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == ENOENT);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == ENOENT);
+}
+
+static void test_map_wronly(void)
+{
+   int i, fd, key = 0, value = 0;
+
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   MAP_SIZE, map_flags | BPF_F_WRONLY);
+   if (fd < 0) {
+   printf("Failed to create map for read only test '%s'!\n",
+  strerror(errno));
+   exit(1);
+   }
+
+   key = 1;
+   value = 1234;
+   /* Insert key=1 element. */
+   assert(bpf_map_update_elem(fd, , , BPF_ANY) == 0)
+
+   /* Check that key=2 is not found. */
+   assert(bpf_map_lookup_elem(fd, , ) == -1 && errno == EPERM);
+   assert(bpf_map_get_next_key(fd, , ) == -1 && errno == EPERM);
+}
+
 static void run_all_tests(void)
 {
test_hashmap(0, NULL);
@@ -1050,6 +1095,9 @@ static void run_all_tests(void)
test_map_large();
test_map_parallel();
test_map_stress();
+
+   test_map_rdonly();
+   test_map_wronly();
 }
 
 int main(void)
-- 
2.14.2.920.gcf0c67979c-goog



[PATCH net-next v2 4/5] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..41aba4e3d57c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF_MAP, BPF_MAP__CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF_PROG, BPF_PROG__LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (f_mode & FMODE_READ)
+   av |= BPF_MAP__READ;
+   if (f_mode & FMODE_WRITE)
+   av |= BPF_MAP__WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_MAP,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_PROG,
+   BPF_PROG__USE, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..7253c5eea59c 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ &qu

[PATCH net-next v2 3/5] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 28 ++--
 security/security.c   | 32 
 5 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0e9ca2555d7f..225740688ab7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -190,6 +193,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
char name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+#ifdef CON

[PATCH net-next v2 5/5] selinux: bpf: Add addtional check for bpf object file receive

2017-10-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.
The information stored inside the file security struct is the same as
the information in bpf object security struct.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h   |  3 +++
 include/linux/lsm_hooks.h | 17 +
 include/linux/security.h  |  9 +++
 kernel/bpf/syscall.c  |  4 ++--
 security/security.c   |  8 +++
 security/selinux/hooks.c  | 61 +++
 6 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 225740688ab7..81d6c01b8825 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -285,6 +285,9 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu 
*progs,
 #ifdef CONFIG_BPF_SYSCALL
 DECLARE_PER_CPU(int, bpf_prog_active);
 
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
 #define BPF_PROG_TYPE(_id, _ops) \
extern const struct bpf_verifier_ops _ops;
 #define BPF_MAP_TYPE(_id, _ops) \
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7161d8e7ee79..517dea60b87b 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1385,6 +1385,19 @@
  * @bpf_prog_free_security:
  * Clean up the security information stored inside bpf prog.
  *
+ * @bpf_map_file:
+ * When creating a bpf map fd, set up the file security information with
+ * the bpf security information stored in the map struct. So when the map
+ * fd is passed between processes, the security module can directly read
+ * the security information from file security struct rather than the bpf
+ * security struct.
+ *
+ * @bpf_prog_file:
+ * When creating a bpf prog fd, set up the file security information with
+ * the bpf security information stored in the prog struct. So when the prog
+ * fd is passed between processes, the security module can directly read
+ * the security information from file security struct rather than the bpf
+ * security struct.
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1726,6 +1739,8 @@ union security_list_options {
void (*bpf_map_free_security)(struct bpf_map *map);
int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+   void (*bpf_map_file)(struct bpf_map *map, struct file *file);
+   void (*bpf_prog_file)(struct bpf_prog_aux *aux, struct file *file);
 #endif /* CONFIG_BPF_SYSCALL */
 };
 
@@ -1954,6 +1969,8 @@ struct security_hook_heads {
struct list_head bpf_map_free_security;
struct list_head bpf_prog_alloc_security;
struct list_head bpf_prog_free_security;
+   struct list_head bpf_map_file;
+   struct list_head bpf_prog_file;
 #endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
diff --git a/include/linux/security.h b/include/linux/security.h
index 18800b0911e5..57573b794e2d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1740,6 +1740,8 @@ extern int security_bpf_map_alloc(struct bpf_map *map);
 extern void security_bpf_map_free(struct bpf_map *map);
 extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
 extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
+extern void security_bpf_map_file(struct bpf_map *map, struct file *file);
+extern void security_bpf_prog_file(struct bpf_prog_aux *aux, struct file 
*file);
 #else
 static inline int security_bpf(int cmd, union bpf_attr *attr,
 unsigned int size)
@@ -1772,6 +1774,13 @@ static inline int security_bpf_prog_alloc(struct 
bpf_prog_aux *aux)
 
 static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
 { }
+
+static inline void security_bpf_map_file(struct bpf_map *map, struct file 
*file)
+{ }
+
+static inline void security_bpf_prog_file(struct bpf_prog_aux *aux,
+ struct file *file)
+{ }
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_BPF_SYSCALL */
 
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 1cf31ddd7616..b144181d3f3a 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file *filp, const 
char __user *buf,
return -EINVAL;
 }
 
-static const struct file_operations bpf_map_fops = {
+const struct fil

[PATCH net-next v2 1/5] bpf: Add file mode configuration into bpf maps

2017-10-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  6 ++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/arraymap.c|  7 +++--
 kernel/bpf/devmap.c  |  5 ++-
 kernel/bpf/hashtab.c |  5 +--
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/lpm_trie.c|  3 +-
 kernel/bpf/sockmap.c |  5 ++-
 kernel/bpf/stackmap.c|  5 ++-
 kernel/bpf/syscall.c | 80 +++-
 10 files changed, 114 insertions(+), 23 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index bc7da2ddfcaf..0e9ca2555d7f 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -308,11 +308,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);
@@ -331,6 +331,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
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6db9e1d679cd..9cb50a228c39 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -217,6 +217,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 */
@@ -259,6 +263,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 */
@@ -286,6 +291,7 @@ union bpf_attr {
__u32   map_id;
};
__u32   next_id;
+   __u32   open_flags;
};
 
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 68d866628be0..f869e48ef2f6 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -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;
@@ -56,8 +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 ||
-   (percpu && numa_node != NUMA_NO_NODE))
+   attr->value_size == 0 || attr->map_flags &
+   ~ARRAY_CREATE_FLAG_MASK || (percpu && numa_node != NUMA_NO_NODE))
return ERR_PTR(-EINVAL);
 
if (attr->value_size > KMALLOC_MAX_SIZE)
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index e093d9a2c4dd..e5d3de7cff2e 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -50,6 +50,9 @@
 #include 
 #include 
 
+#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;
@@ -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

[PATCH net-next v2 0/5] bpf: security: New file mode and LSM hooks for eBPF object permission control

2017-10-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.

Change since V1:

 - Whitelist the new bpf flags in the map allocate check.
 - Added bpf selftest for the new flags.
 - Added two new security hooks for copying the security information from
   the bpf object security struct to file security struct
 - Simplified the checking action when bpf fd is passed between processes.

Chenbo Feng (5):
  bpf: Add file mode configuration into bpf maps
  bpf: Add tests for eBPF file mode
  security: bpf: Add LSM hooks for bpf object related syscall
  selinux: bpf: Add selinux check for eBPF syscall operations
  selinux: bpf: Add addtional check for bpf object file receive

 include/linux/bpf.h |  15 ++-
 include/linux/lsm_hooks.h   |  71 +
 include/linux/security.h|  54 ++
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/arraymap.c   |   7 +-
 kernel/bpf/devmap.c |   5 +-
 kernel/bpf/hashtab.c|   5 +-
 kernel/bpf/inode.c  |  15 ++-
 kernel/bpf/lpm_trie.c   |   3 +-
 kernel/bpf/sockmap.c|   5 +-
 kernel/bpf/stackmap.c   |   5 +-
 kernel/bpf/syscall.c| 112 ++---
 security/security.c |  40 
 security/selinux/hooks.c| 172 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 +
 tools/testing/selftests/bpf/test_maps.c |  48 +
 17 files changed, 542 insertions(+), 27 deletions(-)

-- 
2.14.2.920.gcf0c67979c-goog



Re: [PATCH net-next 4/4] selinux: bpf: Add addtional check for bpf object file receive

2017-10-06 Thread Chenbo Feng
On Thu, Oct 5, 2017 at 11:26 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Thu, 2017-10-05 at 09:37 -0400, Stephen Smalley wrote:
>> On Wed, 2017-10-04 at 11:29 -0700, Chenbo Feng wrote:
>> > From: Chenbo Feng <fe...@google.com>
>> >
>> > Introduce a bpf object related check when sending and receiving
>> > files
>> > through unix domain socket as well as binder. It checks if the
>> > receiving
>> > process have privilege to read/write the bpf map or use the bpf
>> > program.
>> > This check is necessary because the bpf maps and programs are using
>> > a
>> > anonymous inode as their shared inode so the normal way of checking
>> > the
>> > files and sockets when passing between processes cannot work
>> > properly
>> > on
>> > eBPF object. This check only works when the BPF_SYSCALL is
>> > configured.
>> >
>> > Signed-off-by: Chenbo Feng <fe...@google.com>
>> > ---
>> >  include/linux/bpf.h  |  3 +++
>> >  kernel/bpf/syscall.c |  4 ++--
>> >  security/selinux/hooks.c | 57
>> > +++-
>> >  3 files changed, 61 insertions(+), 3 deletions(-)
>> >
>> > diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> > index d757ea3f2228..ac8428a36d56 100644
>> > --- a/include/linux/bpf.h
>> > +++ b/include/linux/bpf.h
>> > @@ -250,6 +250,9 @@ int bpf_prog_test_run_skb(struct bpf_prog
>> > *prog,
>> > const union bpf_attr *kattr,
>> >  #ifdef CONFIG_BPF_SYSCALL
>> >  DECLARE_PER_CPU(int, bpf_prog_active);
>> >
>> > +extern const struct file_operations bpf_map_fops;
>> > +extern const struct file_operations bpf_prog_fops;
>> > +
>> >  #define BPF_PROG_TYPE(_id, _ops) \
>> > extern const struct bpf_verifier_ops _ops;
>> >  #define BPF_MAP_TYPE(_id, _ops) \
>> > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> > index 58ff769d58ab..5789a5359f0a 100644
>> > --- a/kernel/bpf/syscall.c
>> > +++ b/kernel/bpf/syscall.c
>> > @@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file
>> > *filp,
>> > const char __user *buf,
>> > return -EINVAL;
>> >  }
>> >
>> > -static const struct file_operations bpf_map_fops = {
>> > +const struct file_operations bpf_map_fops = {
>> >  #ifdef CONFIG_PROC_FS
>> > .show_fdinfo= bpf_map_show_fdinfo,
>> >  #endif
>> > @@ -965,7 +965,7 @@ static void bpf_prog_show_fdinfo(struct
>> > seq_file
>> > *m, struct file *filp)
>> >  }
>> >  #endif
>> >
>> > -static const struct file_operations bpf_prog_fops = {
>> > +const struct file_operations bpf_prog_fops = {
>> >  #ifdef CONFIG_PROC_FS
>> > .show_fdinfo= bpf_prog_show_fdinfo,
>> >  #endif
>> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> > index 41aba4e3d57c..381474ce3216 100644
>> > --- a/security/selinux/hooks.c
>> > +++ b/security/selinux/hooks.c
>> > @@ -1847,6 +1847,7 @@ static int file_has_perm(const struct cred
>> > *cred,
>> >
>> > /* av is zero if only checking access to the descriptor.
>> > */
>> > rc = 0;
>> > +
>> > if (av)
>> > rc = inode_has_perm(cred, inode, av, );
>> >
>> > @@ -2142,6 +2143,10 @@ static int
>> > selinux_binder_transfer_binder(struct task_struct *from,
>> > NULL);
>> >  }
>> >
>> > +#ifdef CONFIG_BPF_SYSCALL
>> > +static int bpf_fd_pass(struct file *file, u32 sid);
>> > +#endif
>> > +
>> >  static int selinux_binder_transfer_file(struct task_struct *from,
>> > struct task_struct *to,
>> > struct file *file)
>> > @@ -2165,6 +2170,12 @@ static int
>> > selinux_binder_transfer_file(struct
>> > task_struct *from,
>> > return rc;
>> > }
>> >
>> > +#ifdef CONFIG_BPF_SYSCALL
>> > +   rc = bpf_fd_pass(file, sid);
>> > +   if (rc)
>> > +   return rc;
>> > +#endif
>> > +
>> > if (unlikely(IS_PRIVATE(d_backing_inode(dentry
>> > return 0;
>> >
>> > @@ -3735,8 +3746,18 @@ static int
>> > selinux_file_send_sigiotask(struct
>> 

Re: [PATCH net-next 4/4] selinux: bpf: Add addtional check for bpf object file receive

2017-10-06 Thread Chenbo Feng
On Thu, Oct 5, 2017 at 6:37 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Wed, 2017-10-04 at 11:29 -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a bpf object related check when sending and receiving files
>> through unix domain socket as well as binder. It checks if the
>> receiving
>> process have privilege to read/write the bpf map or use the bpf
>> program.
>> This check is necessary because the bpf maps and programs are using a
>> anonymous inode as their shared inode so the normal way of checking
>> the
>> files and sockets when passing between processes cannot work properly
>> on
>> eBPF object. This check only works when the BPF_SYSCALL is
>> configured.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>> ---
>>  include/linux/bpf.h  |  3 +++
>>  kernel/bpf/syscall.c |  4 ++--
>>  security/selinux/hooks.c | 57
>> +++-
>>  3 files changed, 61 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index d757ea3f2228..ac8428a36d56 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -250,6 +250,9 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog,
>> const union bpf_attr *kattr,
>>  #ifdef CONFIG_BPF_SYSCALL
>>  DECLARE_PER_CPU(int, bpf_prog_active);
>>
>> +extern const struct file_operations bpf_map_fops;
>> +extern const struct file_operations bpf_prog_fops;
>> +
>>  #define BPF_PROG_TYPE(_id, _ops) \
>>   extern const struct bpf_verifier_ops _ops;
>>  #define BPF_MAP_TYPE(_id, _ops) \
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index 58ff769d58ab..5789a5359f0a 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file *filp,
>> const char __user *buf,
>>   return -EINVAL;
>>  }
>>
>> -static const struct file_operations bpf_map_fops = {
>> +const struct file_operations bpf_map_fops = {
>>  #ifdef CONFIG_PROC_FS
>>   .show_fdinfo= bpf_map_show_fdinfo,
>>  #endif
>> @@ -965,7 +965,7 @@ static void bpf_prog_show_fdinfo(struct seq_file
>> *m, struct file *filp)
>>  }
>>  #endif
>>
>> -static const struct file_operations bpf_prog_fops = {
>> +const struct file_operations bpf_prog_fops = {
>>  #ifdef CONFIG_PROC_FS
>>   .show_fdinfo= bpf_prog_show_fdinfo,
>>  #endif
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 41aba4e3d57c..381474ce3216 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -1847,6 +1847,7 @@ static int file_has_perm(const struct cred
>> *cred,
>>
>>   /* av is zero if only checking access to the descriptor. */
>>   rc = 0;
>> +
>>   if (av)
>>   rc = inode_has_perm(cred, inode, av, );
>>
>> @@ -2142,6 +2143,10 @@ static int
>> selinux_binder_transfer_binder(struct task_struct *from,
>>   NULL);
>>  }
>>
>> +#ifdef CONFIG_BPF_SYSCALL
>> +static int bpf_fd_pass(struct file *file, u32 sid);
>> +#endif
>> +
>>  static int selinux_binder_transfer_file(struct task_struct *from,
>>   struct task_struct *to,
>>   struct file *file)
>> @@ -2165,6 +2170,12 @@ static int selinux_binder_transfer_file(struct
>> task_struct *from,
>>   return rc;
>>   }
>>
>> +#ifdef CONFIG_BPF_SYSCALL
>> + rc = bpf_fd_pass(file, sid);
>> + if (rc)
>> + return rc;
>> +#endif
>> +
>>   if (unlikely(IS_PRIVATE(d_backing_inode(dentry
>>   return 0;
>>
>> @@ -3735,8 +3746,18 @@ static int selinux_file_send_sigiotask(struct
>> task_struct *tsk,
>>  static int selinux_file_receive(struct file *file)
>>  {
>>   const struct cred *cred = current_cred();
>> + int rc;
>> +
>> + rc = file_has_perm(cred, file, file_to_av(file));
>> + if (rc)
>> + goto out;
>> +
>> +#ifdef CONFIG_BPF_SYSCALL
>> + rc = bpf_fd_pass(file, cred_sid(sid));
>> +#endif
>>
>> - return file_has_perm(cred, file, file_to_av(file));
>> +out:
>> + return rc;
>>  }
>>
>>  static int selinux_file_open(struct file *file, const struct cred
>> *cred)
>> @@ -6288,6 +6

Re: [PATCH net-next 1/4] bpf: Add file mode configuration into bpf maps

2017-10-04 Thread Chenbo Feng
On Wed, Oct 4, 2017 at 4:29 PM, Daniel Borkmann <dan...@iogearbox.net> wrote:
> On 10/04/2017 08:29 PM, Chenbo Feng wrote:
>>
>> From: Chenbo Feng <fe...@google.com>
>>
>> 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.
>
> [...]
>>
>> +int bpf_get_file_flag(int flags)
>> +{
>> +   if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
>> +   return -EINVAL;
>> +   if (flags & BPF_F_RDONLY)
>> +   return O_RDONLY;
>> +   if (flags & BPF_F_WRONLY)
>> +   return O_WRONLY;
>> +   return O_RDWR;
>>   }
>>
>>   /* helper macro to check that unused fields 'union bpf_attr' are zero */
>> @@ -345,12 +376,17 @@ static int map_create(union bpf_attr *attr)
>>   {
>> int numa_node = bpf_map_attr_numa_node(attr);
>> struct bpf_map *map;
>> +   int f_flags;
>> int err;
>>
>> err = CHECK_ATTR(BPF_MAP_CREATE);
>> if (err)
>> return -EINVAL;
>>
>> +   f_flags = bpf_get_file_flag(attr->map_flags);
>> +   if (f_flags < 0)
>> +   return f_flags;
>
>
> Wait, I just noticed, given you add BPF_F_RDONLY/BPF_F_WRONLY
> to attr->map_flags, and later go into find_and_alloc_map(),
> for map alloc, which is e.g. array_map_alloc(). There, we
> bail out with EINVAL on attr->map_flags & ~BPF_F_NUMA_NODE,
> which is the case for both BPF_F_RDONLY/BPF_F_WRONLY ... I
> would have expected that the entire code was tested properly;
> what was tested exactly in the set?
>

Thanks for pointing out this, my test for the patch create the map
with RD/WR flag which is 0 that's why I didn't catch this. And
bpf_obj_get do not have similar checks for map_flags.
>> if (numa_node != NUMA_NO_NODE &&
>> ((unsigned int)numa_node >= nr_node_ids ||
>>  !node_online(numa_node)))
>> @@ -376,7 +412,7 @@ static int map_create(union bpf_attr *attr)
>> if (err)
>> goto free_map;
>>
>> -   err = bpf_map_new_fd(map);
>> +   err = bpf_map_new_fd(map, f_flags);
>> if (err < 0) {
>> /* failed to allocate fd.
>>  * bpf_map_put() is needed because the above
>> @@ -491,6 +527,11 @@ static int map_lookup_elem(union bpf_attr *attr)
>
> [...]


[PATCH net-next 1/4] bpf: Add file mode configuration into bpf maps

2017-10-04 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

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 <fe...@google.com>
Acked-by: Daniel Borkmann <dan...@iogearbox.net>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h  |  6 ++--
 include/uapi/linux/bpf.h |  6 
 kernel/bpf/inode.c   | 15 ++---
 kernel/bpf/syscall.c | 80 +++-
 4 files changed, 92 insertions(+), 15 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 252f4bc9eb25..d826be859589 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -273,11 +273,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);
@@ -296,6 +296,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
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 6d2137b4cf38..e812be5946a6 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -177,6 +177,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 */
@@ -219,6 +223,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 */
@@ -246,6 +251,7 @@ union bpf_attr {
__u32   map_id;
};
__u32   next_id;
+   __u32   open_flags;
};
 
struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index e833ed914358..7d8c6dd8dd5d 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -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;
@@ -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;
 
@@ -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, );
+   raw = bpf_obj_do_get(pname, , f_flags);
if (IS_ERR(raw)) {
ret = PTR_ERR(raw);
goto out;
@@ -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 (ty

[PATCH 0/4] net-next: security: New file mode and LSM hooks for eBPF object permission control

2017-10-04 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the
existing mechanism for eBPF object access control is very limited.
Currently there are two options for granting accessing to eBPF
operations: grant access to all processes, or only CAP_SYS_ADMIN
processes. The CAP_SYS_ADMIN-only mode is not ideal because most users
do not have this capability and granting a user CAP_SYS_ADMIN grants too
many other security-sensitive permissions. It also unnecessarily allows
all CAP_SYS_ADMIN processes access to eBPF functionality. Allowing all
processes to access to eBPF objects is also undesirable since it has
potential to allow unprivileged processes to consume kernel memory, and
opens up attack surface to the kernel.

Adding LSM hooks maintains the status quo for systems which do not use
an LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here
is a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the map.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf_map { create read write};
allow netmonitor netd:fd use;
allow netmonitor netd:bpf_map read;

In this patch series, A file mode is added to bpf map to store the
accessing mode. With this file mode flags, the map can be obtained read
only, write only or read and write. With the help of this file mode,
several security hooks can be added to the eBPF syscall implementations
to do permissions checks. These LSM hooks are mainly focused on checking
the process privileges before it obtains the fd for a specific bpf
object. No matter from a file location or from a eBPF id. Besides that,
a general check hook is also implemented at the start of bpf syscalls so
that each security module can have their own implementation on the reset
of bpf object related functionalities.

In order to store the ownership and security information about eBPF
maps, a security field pointer is added to the struct bpf_map. And the
last two patch set are implementation of selinux check on these hooks
introduced, plus an additional check when eBPF object is passed between
processes using unix socket as well as binder IPC.


Chenbo Feng (4):
  Add file mode configuration into bpf maps
  Add LSM hooks for bpf object related syscall
  Add selinux check for eBPF syscall operations
  Add addtional check for bpf object file receive

 include/linux/bpf.h |  15 +++-
 include/linux/lsm_hooks.h   |  54 
 include/linux/security.h|  45 ++
 include/uapi/linux/bpf.h|   6 ++
 kernel/bpf/inode.c  |  15 ++--
 kernel/bpf/syscall.c| 112 +---
 security/security.c |  32 +++
 security/selinux/hooks.c| 168 +++-
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 +
 10 files changed, 433 insertions(+), 20 deletions(-)

-- 
2.14.2.920.gcf0c67979c-goog



[PATCH net-next 3/4] selinux: bpf: Add selinux check for eBPF syscall operations

2017-10-04 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Implement the actual checks introduced to eBPF related syscalls. This
implementation use the security field inside bpf object to store a sid that
identify the bpf object. And when processes try to access the object,
selinux will check if processes have the right privileges. The creation
of eBPF object are also checked at the general bpf check hook and new
cmd introduced to eBPF domain can also be checked there.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 security/selinux/hooks.c| 111 
 security/selinux/include/classmap.h |   2 +
 security/selinux/include/objsec.h   |   4 ++
 3 files changed, 117 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f5d304736852..41aba4e3d57c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6252,6 +6253,106 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf(int cmd, union bpf_attr *attr,
+unsigned int size)
+{
+   u32 sid = current_sid();
+   int ret;
+
+   switch (cmd) {
+   case BPF_MAP_CREATE:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF_MAP, BPF_MAP__CREATE,
+  NULL);
+   break;
+   case BPF_PROG_LOAD:
+   ret = avc_has_perm(sid, sid, SECCLASS_BPF_PROG, BPF_PROG__LOAD,
+  NULL);
+   break;
+   default:
+   ret = 0;
+   break;
+   }
+
+   return ret;
+}
+
+static u32 bpf_map_fmode_to_av(fmode_t fmode)
+{
+   u32 av = 0;
+
+   if (f_mode & FMODE_READ)
+   av |= BPF_MAP__READ;
+   if (f_mode & FMODE_WRITE)
+   av |= BPF_MAP__WRITE;
+   return av;
+}
+
+static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = map->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_MAP,
+   bpf_map_fmode_to_av(fmode), NULL);
+}
+
+static int selinux_bpf_prog(struct bpf_prog *prog)
+{
+   u32 sid = current_sid();
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = prog->aux->security;
+   return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_PROG,
+   BPF_PROG__USE, NULL);
+}
+
+static int selinux_bpf_map_alloc(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_map_free(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   map->security = NULL;
+   kfree(bpfsec);
+}
+
+static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   aux->security = bpfsec;
+
+   return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+{
+   struct bpf_security_struct *bpfsec = aux->security;
+
+   aux->security = NULL;
+   kfree(bpfsec);
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6471,6 +6572,16 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf, selinux_bpf),
+   LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
+   LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
+   LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
+   LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+   LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
+   LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index 35ffb29a69cb..7253c5eea59c 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -237,6 +237,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ &qu

[PATCH net-next 4/4] selinux: bpf: Add addtional check for bpf object file receive

2017-10-04 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a bpf object related check when sending and receiving files
through unix domain socket as well as binder. It checks if the receiving
process have privilege to read/write the bpf map or use the bpf program.
This check is necessary because the bpf maps and programs are using a
anonymous inode as their shared inode so the normal way of checking the
files and sockets when passing between processes cannot work properly on
eBPF object. This check only works when the BPF_SYSCALL is configured.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h  |  3 +++
 kernel/bpf/syscall.c |  4 ++--
 security/selinux/hooks.c | 57 +++-
 3 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index d757ea3f2228..ac8428a36d56 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -250,6 +250,9 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const 
union bpf_attr *kattr,
 #ifdef CONFIG_BPF_SYSCALL
 DECLARE_PER_CPU(int, bpf_prog_active);
 
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
 #define BPF_PROG_TYPE(_id, _ops) \
extern const struct bpf_verifier_ops _ops;
 #define BPF_MAP_TYPE(_id, _ops) \
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 58ff769d58ab..5789a5359f0a 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -313,7 +313,7 @@ static ssize_t bpf_dummy_write(struct file *filp, const 
char __user *buf,
return -EINVAL;
 }
 
-static const struct file_operations bpf_map_fops = {
+const struct file_operations bpf_map_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_map_show_fdinfo,
 #endif
@@ -965,7 +965,7 @@ static void bpf_prog_show_fdinfo(struct seq_file *m, struct 
file *filp)
 }
 #endif
 
-static const struct file_operations bpf_prog_fops = {
+const struct file_operations bpf_prog_fops = {
 #ifdef CONFIG_PROC_FS
.show_fdinfo= bpf_prog_show_fdinfo,
 #endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 41aba4e3d57c..381474ce3216 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1847,6 +1847,7 @@ static int file_has_perm(const struct cred *cred,
 
/* av is zero if only checking access to the descriptor. */
rc = 0;
+
if (av)
rc = inode_has_perm(cred, inode, av, );
 
@@ -2142,6 +2143,10 @@ static int selinux_binder_transfer_binder(struct 
task_struct *from,
NULL);
 }
 
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_fd_pass(struct file *file, u32 sid);
+#endif
+
 static int selinux_binder_transfer_file(struct task_struct *from,
struct task_struct *to,
struct file *file)
@@ -2165,6 +2170,12 @@ static int selinux_binder_transfer_file(struct 
task_struct *from,
return rc;
}
 
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, sid);
+   if (rc)
+   return rc;
+#endif
+
if (unlikely(IS_PRIVATE(d_backing_inode(dentry
return 0;
 
@@ -3735,8 +3746,18 @@ static int selinux_file_send_sigiotask(struct 
task_struct *tsk,
 static int selinux_file_receive(struct file *file)
 {
const struct cred *cred = current_cred();
+   int rc;
+
+   rc = file_has_perm(cred, file, file_to_av(file));
+   if (rc)
+   goto out;
+
+#ifdef CONFIG_BPF_SYSCALL
+   rc = bpf_fd_pass(file, cred_sid(sid));
+#endif
 
-   return file_has_perm(cred, file, file_to_av(file));
+out:
+   return rc;
 }
 
 static int selinux_file_open(struct file *file, const struct cred *cred)
@@ -6288,6 +6309,40 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
return av;
 }
 
+/* This function will check the file pass through unix socket or binder to see
+ * if it is a bpf related object. And apply correspinding checks on the bpf
+ * object based on the type. The bpf maps and programs, not like other files 
and
+ * socket, are using a shared anonymous inode inside the kernel as their inode.
+ * So checking that inode cannot identify if the process have privilege to
+ * access the bpf object and that's why we have to add this additional check in
+ * selinux_file_receive and selinux_binder_transfer_files.
+ */
+static int bpf_fd_pass(struct file *file, u32 sid)
+{
+   struct bpf_security_struct *bpfsec;
+   u32 sid = cred_sid(cred);
+   struct bpf_prog *prog;
+   struct bpf_map *map;
+   int ret;
+
+   if (file->f_op == _map_fops) {
+   map = file->private_data;
+   bpfsec = map->security;
+   ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF_MAP,
+  bpf_map_fmode_to_av(file->f_mode), NULL);
+   if (ret)
+   return r

[PATCH net-next 2/4] security: bpf: Add LSM hooks for bpf object related syscall

2017-10-04 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce several LSM hooks for the syscalls that will allow the
userspace to access to eBPF object such as eBPF programs and eBPF maps.
The security check is aimed to enforce a per object security protection
for eBPF object so only processes with the right priviliges can
read/write to a specific map or use a specific eBPF program. Besides
that, a general security hook is added before the multiplexer of bpf
syscall to check the cmd and the attribute used for the command. The
actual security module can decide which command need to be checked and
how the cmd should be checked.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Alexei Starovoitov <a...@kernel.org>
---
 include/linux/bpf.h   |  6 ++
 include/linux/lsm_hooks.h | 54 +++
 include/linux/security.h  | 45 +++
 kernel/bpf/syscall.c  | 28 ++--
 security/security.c   | 32 
 5 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index d826be859589..d757ea3f2228 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -57,6 +57,9 @@ struct bpf_map {
atomic_t usercnt;
struct bpf_map *inner_map_meta;
u8 name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
@@ -190,6 +193,9 @@ struct bpf_prog_aux {
struct user_struct *user;
u64 load_time; /* ns since boottime */
u8 name[BPF_OBJ_NAME_LEN];
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
union {
struct work_struct work;
struct rcu_head rcu;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c9258124e417..7161d8e7ee79 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1351,6 +1351,40 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf:
+ * Do a initial check for all bpf syscalls after the attribute is copied
+ * into the kernel. The actual security module can implement their own
+ * rules to check the specific cmd they need.
+ *
+ * @bpf_map:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF maps.
+ *
+ * @map: bpf map that we want to access
+ * @mask: the access flags
+ *
+ * @bpf_prog:
+ * Do a check when the kernel generate and return a file descriptor for
+ * eBPF programs.
+ *
+ * @prog: bpf prog that userspace want to use.
+ *
+ * @bpf_map_alloc_security:
+ * Initialize the security field inside bpf map.
+ *
+ * @bpf_map_free_security:
+ * Clean up the security information stored inside bpf map.
+ *
+ * @bpf_prog_alloc_security:
+ * Initialize the security field inside bpf program.
+ *
+ * @bpf_prog_free_security:
+ * Clean up the security information stored inside bpf prog.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1682,6 +1716,17 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf)(int cmd, union bpf_attr *attr,
+unsigned int size);
+   int (*bpf_map)(struct bpf_map *map, fmode_t fmode);
+   int (*bpf_prog)(struct bpf_prog *prog);
+   int (*bpf_map_alloc_security)(struct bpf_map *map);
+   void (*bpf_map_free_security)(struct bpf_map *map);
+   int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux);
+   void (*bpf_prog_free_security)(struct bpf_prog_aux *aux);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1901,6 +1946,15 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf;
+   struct list_head bpf_map;
+   struct list_head bpf_prog;
+   struct list_head bpf_map_alloc_security;
+   struct list_head bpf_map_free_security;
+   struct list_head bpf_prog_alloc_security;
+   struct list_head bpf_prog_free_security;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index ce6265960d6c..18800b0911e5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1730,6 +1731,50 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 

Re: [PATCH 1/3] security: bpf: Add eBPF LSM hooks to security module

2017-09-05 Thread Chenbo Feng
On Fri, Sep 1, 2017 at 5:50 AM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Thu, 2017-08-31 at 13:56 -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce 5 LSM hooks to provide finer granularity controls on eBPF
>> related operations including create eBPF maps, modify and read eBPF
>> maps
>> content and load eBPF programs to the kernel. Hooks use the new
>> security
>> pointer inside the eBPF map struct to store the owner's security
>> information and the different security modules can perform different
>> checks based on the information stored inside the security field.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>> ---
>>  include/linux/lsm_hooks.h | 41
>> +
>>  include/linux/security.h  | 36 
>>  security/security.c   | 28 
>>  3 files changed, 105 insertions(+)
>>
>> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
>> index ce02f76a6188..3aaf9a08a983 100644
>> --- a/include/linux/lsm_hooks.h
>> +++ b/include/linux/lsm_hooks.h
>> @@ -1353,6 +1353,32 @@
>>   *   @inode we wish to get the security context of.
>>   *   @ctx is a pointer in which to place the allocated security
>> context.
>>   *   @ctxlen points to the place to put the length of @ctx.
>> + *
>> + * Security hooks for using the eBPF maps and programs
>> functionalities through
>> + * eBPF syscalls.
>> + *
>> + * @bpf_map_create:
>> + *   Check permissions prior to creating a new bpf map.
>> + *   Return 0 if the permission is granted.
>> + *
>> + * @bpf_map_modify:
>> + *   Check permission prior to insert, update and delete map
>> content.
>> + *   @map pointer to the struct bpf_map that contains map
>> information.
>> + *   Return 0 if the permission is granted.
>> + *
>> + * @bpf_map_read:
>> + *   Check permission prior to read a bpf map content.
>> + *   @map pointer to the struct bpf_map that contains map
>> information.
>> + *   Return 0 if the permission is granted.
>> + *
>> + * @bpf_prog_load:
>> + *   Check permission prior to load eBPF program.
>> + *   Return 0 if the permission is granted.
>> + *
>> + * @bpf_post_create:
>> + *   Initialize the bpf object security field inside struct
>> bpf_maps and
>> + *   it is used for future security checks.
>> + *
>>   */
>>  union security_list_options {
>>   int (*binder_set_context_mgr)(struct task_struct *mgr);
>> @@ -1685,6 +1711,14 @@ union security_list_options {
>>   struct audit_context *actx);
>>   void (*audit_rule_free)(void *lsmrule);
>>  #endif /* CONFIG_AUDIT */
>> +
>> +#ifdef CONFIG_BPF_SYSCALL
>> + int (*bpf_map_create)(void);
>> + int (*bpf_map_read)(struct bpf_map *map);
>> + int (*bpf_map_modify)(struct bpf_map *map);
>> + int (*bpf_prog_load)(void);
>> + int (*bpf_post_create)(struct bpf_map *map);
>> +#endif /* CONFIG_BPF_SYSCALL */
>>  };
>>
>>  struct security_hook_heads {
>> @@ -1905,6 +1939,13 @@ struct security_hook_heads {
>>   struct list_head audit_rule_match;
>>   struct list_head audit_rule_free;
>>  #endif /* CONFIG_AUDIT */
>> +#ifdef CONFIG_BPF_SYSCALL
>> + struct list_head bpf_map_create;
>> + struct list_head bpf_map_read;
>> + struct list_head bpf_map_modify;
>> + struct list_head bpf_prog_load;
>> + struct list_head bpf_post_create;
>> +#endif /* CONFIG_BPF_SYSCALL */
>>  } __randomize_layout;
>>
>>  /*
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 458e24bea2d4..0656a4f74d14 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -31,6 +31,7 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>
>>  struct linux_binprm;
>>  struct cred;
>> @@ -1735,6 +1736,41 @@ static inline void securityfs_remove(struct
>> dentry *dentry)
>>
>>  #endif
>>
>> +#ifdef CONFIG_BPF_SYSCALL
>> +#ifdef CONFIG_SECURITY
>> +int security_map_create(void);
>> +int security_map_modify(struct bpf_map *map);
>> +int security_map_read(struct bpf_map *map);
>> +int security_prog_load(void);
>> +int security_post_create(struct bpf_map *map);
>> +#else
>> +static inline int security_map_create(void)
>> +{
>> + return 0;
>> +}
>>

Re: [PATCH 2/3] security: bpf: Add eBPF LSM hooks and security field to eBPF map

2017-09-05 Thread Chenbo Feng
On Thu, Aug 31, 2017 at 7:05 PM, Alexei Starovoitov
<alexei.starovoi...@gmail.com> wrote:
> On Thu, Aug 31, 2017 at 01:56:34PM -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a pointer into struct bpf_map to hold the security information
>> about the map. The actual security struct varies based on the security
>> models implemented. Place the LSM hooks before each of the unrestricted
>> eBPF operations, the map_update_elem and map_delete_elem operations are
>> checked by security_map_modify. The map_lookup_elem and map_get_next_key
>> operations are checked by securtiy_map_read.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>
> ...
>
>> @@ -410,6 +418,10 @@ static int map_lookup_elem(union bpf_attr *attr)
>>   if (IS_ERR(map))
>>   return PTR_ERR(map);
>>
>> + err = security_map_read(map);
>> + if (err)
>> + return -EACCES;
>> +
>>   key = memdup_user(ukey, map->key_size);
>>   if (IS_ERR(key)) {
>>   err = PTR_ERR(key);
>> @@ -490,6 +502,10 @@ static int map_update_elem(union bpf_attr *attr)
>>   if (IS_ERR(map))
>>   return PTR_ERR(map);
>>
>> + err = security_map_modify(map);
>
> I don't feel these extra hooks are really thought through.
> With such hook you'll disallow map_update for given map. That's it.
> The key/values etc won't be used in such security decision.
> In such case you don't need such hooks in update/lookup at all.
> Only in map_creation and object_get calls where FD can be received.
> In other words I suggest to follow standard unix practices:
> Do permissions checks in open() and allow read/write() if FD is valid.
> Same here. Do permission checks in prog_load/map_create/obj_pin/get
> and that will be enough to jail bpf subsystem.
> bpf cmds that need to be fast (like lookup and update) should not
> have security hooks.
>
Thanks for pointing out this. I agree we should only do checks on
creating and passing
the object from one processes to another. And if we can still
distinguish the read/write operation
when obtaining the file fd, that would be great. But that may require
us to add a new mode
field into bpf_map struct and change the attribute struct when doing
the bpf syscall. How do you
think about this approach? Or we can do simple checks for
bpf_obj_create and bpf_obj_use when
creating the object and passing the object respectively but this
solution cannot distinguish map modify and
read.


Re: [PATCH 2/3] security: bpf: Add eBPF LSM hooks and security field to eBPF map

2017-08-31 Thread Chenbo Feng
On Thu, Aug 31, 2017 at 3:38 PM, Daniel Borkmann <dan...@iogearbox.net> wrote:
> On 08/31/2017 10:56 PM, Chenbo Feng wrote:
>>
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a pointer into struct bpf_map to hold the security information
>> about the map. The actual security struct varies based on the security
>> models implemented. Place the LSM hooks before each of the unrestricted
>> eBPF operations, the map_update_elem and map_delete_elem operations are
>> checked by security_map_modify. The map_lookup_elem and map_get_next_key
>> operations are checked by securtiy_map_read.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>
>
> Against which tree is this by the way, net-next? There are
> changes here which require a rebase of your set.
>

This patch series is rebased on security subsystem since patch 1/3 is
a patch for
security system I assume. But I am not sure where this specific patch
should go in.
If I should submit this one to net-next, I will rebase it against
net-next and submit again.
>> ---
>>   include/linux/bpf.h  |  3 +++
>>   kernel/bpf/syscall.c | 28 
>>   2 files changed, 31 insertions(+)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index b69e7a5869ff..ca3e6ff7091d 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -53,6 +53,9 @@ struct bpf_map {
>> struct work_struct work;
>> atomic_t usercnt;
>> struct bpf_map *inner_map_meta;
>> +#ifdef CONFIG_SECURITY
>> +   void *security;
>> +#endif
>>   };
>>
>>   /* function argument constraints */
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index 045646da97cc..b15580bcf3b1 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -279,6 +279,10 @@ static int map_create(union bpf_attr *attr)
>> if (err)
>> return -EINVAL;
>>
>> +   err = security_map_create();
>
>
> Seems a bit limited to me, don't you want to be able to
> also differentiate between different map types? Same goes
> for security_prog_load() wrt prog types, no?
>
I don't want to introduce extra complexity into it if not necessary.
so I only included the
thing needed for the selinux implementation for now.  But I agree that the map
and program type information could be useful when people developing more complex
security checks. I will add a union bpf_attr *attr pointer into the
security hook functions
for future needs.
>> +   if (err)
>> +   return -EACCES;
>> +
>> /* find map type and init map: hashtable vs rbtree vs bloom vs ...
>> */
>> map = find_and_alloc_map(attr);
>> if (IS_ERR(map))
>> @@ -291,6 +295,10 @@ static int map_create(union bpf_attr *attr)
>> if (err)
>> goto free_map_nouncharge;
>>
>> +   err = security_post_create(map);
>> +   if (err < 0)
>> +   goto free_map;
>> +
>
>
> So the hook you implement in patch 3/3 does:
>
> +static int selinux_bpf_post_create(struct bpf_map *map)
> +{
> +   struct bpf_security_struct *bpfsec;
> +
> +   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
> +   if (!bpfsec)
> +   return -ENOMEM;
> +
> +   bpfsec->sid = current_sid();
> +   map->security = bpfsec;
> +
> +   return 0;
> +}
>
> Where do you kfree() bpfsec when the map gets released
> normally or in error path?
>
Will add it in next version. Thanks for point it out.
>> err = bpf_map_alloc_id(map);
>> if (err)
>> goto free_map;
>> @@ -410,6 +418,10 @@ static int map_lookup_elem(union bpf_attr *attr)
>> if (IS_ERR(map))
>> return PTR_ERR(map);
>>
>> +   err = security_map_read(map);
>> +   if (err)
>> +   return -EACCES;
>
>
> How about actually dropping ref?
>
May bad, thanks again.
>> +
>> key = memdup_user(ukey, map->key_size);
>> if (IS_ERR(key)) {
>> err = PTR_ERR(key);
>> @@ -490,6 +502,10 @@ static int map_update_elem(union bpf_attr *attr)
>> if (IS_ERR(map))
>> return PTR_ERR(map);
>>
>> +   err = security_map_modify(map);
>> +   if (err)
>> +   return -EACCES;
>
>
> Ditto ...
>
>> key = memdup_user(ukey, map->key_size);
>> if (IS_ERR(key)) {
>> err = PTR_ERR(key);
>> @@ -573,6 +58

Re: [PATCH 2/3] security: bpf: Add eBPF LSM hooks and security field to eBPF map

2017-08-31 Thread Chenbo Feng
On Thu, Aug 31, 2017 at 2:17 PM, Mimi Zohar <zo...@linux.vnet.ibm.com> wrote:
> On Thu, 2017-08-31 at 13:56 -0700, Chenbo Feng wrote:
>> From: Chenbo Feng <fe...@google.com>
>>
>> Introduce a pointer into struct bpf_map to hold the security information
>> about the map. The actual security struct varies based on the security
>> models implemented. Place the LSM hooks before each of the unrestricted
>> eBPF operations, the map_update_elem and map_delete_elem operations are
>> checked by security_map_modify. The map_lookup_elem and map_get_next_key
>> operations are checked by securtiy_map_read.
>>
>> Signed-off-by: Chenbo Feng <fe...@google.com>
>> ---
>>  include/linux/bpf.h  |  3 +++
>>  kernel/bpf/syscall.c | 28 
>>  2 files changed, 31 insertions(+)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index b69e7a5869ff..ca3e6ff7091d 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -53,6 +53,9 @@ struct bpf_map {
>>   struct work_struct work;
>>   atomic_t usercnt;
>>   struct bpf_map *inner_map_meta;
>> +#ifdef CONFIG_SECURITY
>> + void *security;
>> +#endif
>>  };
>>
>>  /* function argument constraints */
>> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
>> index 045646da97cc..b15580bcf3b1 100644
>> --- a/kernel/bpf/syscall.c
>> +++ b/kernel/bpf/syscall.c
>> @@ -279,6 +279,10 @@ static int map_create(union bpf_attr *attr)
>>   if (err)
>>   return -EINVAL;
>>
>> + err = security_map_create();
>> + if (err)
>> + return -EACCES;
>
> Any reason not to just return err?
>
> Mimi
>
Nope... return err might be better. I will fix this in next version.

Thanks
Chenbo
>> +
>>   /* find map type and init map: hashtable vs rbtree vs bloom vs ... */
>>   map = find_and_alloc_map(attr);
>>   if (IS_ERR(map))
>> @@ -291,6 +295,10 @@ static int map_create(union bpf_attr *attr)
>>   if (err)
>>   goto free_map_nouncharge;
>>
>> + err = security_post_create(map);
>> + if (err < 0)
>> + goto free_map;
>> +
>>   err = bpf_map_alloc_id(map);
>>   if (err)
>>   goto free_map;
>> @@ -410,6 +418,10 @@ static int map_lookup_elem(union bpf_attr *attr)
>>   if (IS_ERR(map))
>>   return PTR_ERR(map);
>>
>> + err = security_map_read(map);
>> + if (err)
>> + return -EACCES;
>> +
>>   key = memdup_user(ukey, map->key_size);
>>   if (IS_ERR(key)) {
>>   err = PTR_ERR(key);
>> @@ -490,6 +502,10 @@ static int map_update_elem(union bpf_attr *attr)
>>   if (IS_ERR(map))
>>   return PTR_ERR(map);
>>
>> + err = security_map_modify(map);
>> + if (err)
>> + return -EACCES;
>> +
>>   key = memdup_user(ukey, map->key_size);
>>   if (IS_ERR(key)) {
>>   err = PTR_ERR(key);
>> @@ -573,6 +589,10 @@ static int map_delete_elem(union bpf_attr *attr)
>>   if (IS_ERR(map))
>>   return PTR_ERR(map);
>>
>> + err = security_map_modify(map);
>> + if (err)
>> + return -EACCES;
>> +
>>   key = memdup_user(ukey, map->key_size);
>>   if (IS_ERR(key)) {
>>   err = PTR_ERR(key);
>> @@ -616,6 +636,10 @@ static int map_get_next_key(union bpf_attr *attr)
>>   if (IS_ERR(map))
>>   return PTR_ERR(map);
>>
>> + err = security_map_read(map);
>> + if (err)
>> + return -EACCES;
>> +
>>   if (ukey) {
>>   key = memdup_user(ukey, map->key_size);
>>   if (IS_ERR(key)) {
>> @@ -935,6 +959,10 @@ static int bpf_prog_load(union bpf_attr *attr)
>>   if (CHECK_ATTR(BPF_PROG_LOAD))
>>   return -EINVAL;
>>
>> + err = security_prog_load();
>> + if (err)
>> + return -EACCES;
>> +
>>   if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
>>   return -EINVAL;
>>
>


[PATCH 3/3] selinux: bpf: Implement the selinux checks for eBPF object

2017-08-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce 5 new selinux checks for eBPF object related operations. The
check is based on the ownership information of eBPF maps and the
capability of creating eBPF object.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 security/selinux/hooks.c| 54 +
 security/selinux/include/classmap.h |  2 ++
 security/selinux/include/objsec.h   |  4 +++
 3 files changed, 60 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 33fd061305c4..39ad7d9f335d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -85,6 +85,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "avc.h"
 #include "objsec.h"
@@ -6245,6 +6246,52 @@ static void selinux_ib_free_security(void *ib_sec)
 }
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+static int selinux_bpf_map_create(void)
+{
+   u32 sid = current_sid();
+
+   return avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, NULL);
+}
+
+static int selinux_bpf_map_modify(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   return avc_has_perm(current_sid(), bpfsec->sid, SECCLASS_BPF,
+   BPF__MAP_MODIFY, NULL);
+}
+
+static int selinux_bpf_map_read(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec = map->security;
+
+   return avc_has_perm(current_sid(), bpfsec->sid, SECCLASS_BPF,
+   BPF__MAP_READ, NULL);
+}
+
+static int selinux_bpf_prog_load(void)
+{
+   u32 sid = current_sid();
+
+   return avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, NULL);
+}
+
+static int selinux_bpf_post_create(struct bpf_map *map)
+{
+   struct bpf_security_struct *bpfsec;
+
+   bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+   if (!bpfsec)
+   return -ENOMEM;
+
+   bpfsec->sid = current_sid();
+   map->security = bpfsec;
+
+   return 0;
+}
+#endif
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6465,6 +6512,13 @@ static struct security_hook_list selinux_hooks[] 
__lsm_ro_after_init = {
LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
 #endif
+#ifdef CONFIG_BPF_SYSCALL
+   LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create),
+   LSM_HOOK_INIT(bpf_map_modify, selinux_bpf_map_modify),
+   LSM_HOOK_INIT(bpf_map_read, selinux_bpf_map_read),
+   LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load),
+   LSM_HOOK_INIT(bpf_post_create, selinux_bpf_post_create),
+#endif
 };
 
 static __init int selinux_init(void)
diff --git a/security/selinux/include/classmap.h 
b/security/selinux/include/classmap.h
index b9fe3434b036..83c880fb17b4 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -235,6 +235,8 @@ struct security_class_mapping secclass_map[] = {
  { "access", NULL } },
{ "infiniband_endport",
  { "manage_subnet", NULL } },
+   { "bpf",
+ {"map_create", "map_modify", "map_read", "prog_load" } },
{ NULL }
   };
 
diff --git a/security/selinux/include/objsec.h 
b/security/selinux/include/objsec.h
index 6ebc61e370ff..ba564f662b0d 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -150,6 +150,10 @@ struct pkey_security_struct {
u32 sid;/* SID of pkey */
 };
 
+struct bpf_security_struct {
+   u32 sid;/*SID of bpf obj creater*/
+};
+
 extern unsigned int selinux_checkreqprot;
 
 #endif /* _SELINUX_OBJSEC_H_ */
-- 
2.14.1.581.gf28d330327-goog



[PATCH 2/3] security: bpf: Add eBPF LSM hooks and security field to eBPF map

2017-08-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a pointer into struct bpf_map to hold the security information
about the map. The actual security struct varies based on the security
models implemented. Place the LSM hooks before each of the unrestricted
eBPF operations, the map_update_elem and map_delete_elem operations are
checked by security_map_modify. The map_lookup_elem and map_get_next_key
operations are checked by securtiy_map_read.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/bpf.h  |  3 +++
 kernel/bpf/syscall.c | 28 
 2 files changed, 31 insertions(+)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index b69e7a5869ff..ca3e6ff7091d 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -53,6 +53,9 @@ struct bpf_map {
struct work_struct work;
atomic_t usercnt;
struct bpf_map *inner_map_meta;
+#ifdef CONFIG_SECURITY
+   void *security;
+#endif
 };
 
 /* function argument constraints */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 045646da97cc..b15580bcf3b1 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -279,6 +279,10 @@ static int map_create(union bpf_attr *attr)
if (err)
return -EINVAL;
 
+   err = security_map_create();
+   if (err)
+   return -EACCES;
+
/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
map = find_and_alloc_map(attr);
if (IS_ERR(map))
@@ -291,6 +295,10 @@ static int map_create(union bpf_attr *attr)
if (err)
goto free_map_nouncharge;
 
+   err = security_post_create(map);
+   if (err < 0)
+   goto free_map;
+
err = bpf_map_alloc_id(map);
if (err)
goto free_map;
@@ -410,6 +418,10 @@ static int map_lookup_elem(union bpf_attr *attr)
if (IS_ERR(map))
return PTR_ERR(map);
 
+   err = security_map_read(map);
+   if (err)
+   return -EACCES;
+
key = memdup_user(ukey, map->key_size);
if (IS_ERR(key)) {
err = PTR_ERR(key);
@@ -490,6 +502,10 @@ static int map_update_elem(union bpf_attr *attr)
if (IS_ERR(map))
return PTR_ERR(map);
 
+   err = security_map_modify(map);
+   if (err)
+   return -EACCES;
+
key = memdup_user(ukey, map->key_size);
if (IS_ERR(key)) {
err = PTR_ERR(key);
@@ -573,6 +589,10 @@ static int map_delete_elem(union bpf_attr *attr)
if (IS_ERR(map))
return PTR_ERR(map);
 
+   err = security_map_modify(map);
+   if (err)
+   return -EACCES;
+
key = memdup_user(ukey, map->key_size);
if (IS_ERR(key)) {
err = PTR_ERR(key);
@@ -616,6 +636,10 @@ static int map_get_next_key(union bpf_attr *attr)
if (IS_ERR(map))
return PTR_ERR(map);
 
+   err = security_map_read(map);
+   if (err)
+   return -EACCES;
+
if (ukey) {
key = memdup_user(ukey, map->key_size);
if (IS_ERR(key)) {
@@ -935,6 +959,10 @@ static int bpf_prog_load(union bpf_attr *attr)
if (CHECK_ATTR(BPF_PROG_LOAD))
return -EINVAL;
 
+   err = security_prog_load();
+   if (err)
+   return -EACCES;
+
if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT)
return -EINVAL;
 
-- 
2.14.1.581.gf28d330327-goog



[PATCH 1/3] security: bpf: Add eBPF LSM hooks to security module

2017-08-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce 5 LSM hooks to provide finer granularity controls on eBPF
related operations including create eBPF maps, modify and read eBPF maps
content and load eBPF programs to the kernel. Hooks use the new security
pointer inside the eBPF map struct to store the owner's security
information and the different security modules can perform different
checks based on the information stored inside the security field.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/lsm_hooks.h | 41 +
 include/linux/security.h  | 36 
 security/security.c   | 28 
 3 files changed, 105 insertions(+)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index ce02f76a6188..3aaf9a08a983 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1353,6 +1353,32 @@
  * @inode we wish to get the security context of.
  * @ctx is a pointer in which to place the allocated security context.
  * @ctxlen points to the place to put the length of @ctx.
+ *
+ * Security hooks for using the eBPF maps and programs functionalities through
+ * eBPF syscalls.
+ *
+ * @bpf_map_create:
+ * Check permissions prior to creating a new bpf map.
+ * Return 0 if the permission is granted.
+ *
+ * @bpf_map_modify:
+ * Check permission prior to insert, update and delete map content.
+ * @map pointer to the struct bpf_map that contains map information.
+ * Return 0 if the permission is granted.
+ *
+ * @bpf_map_read:
+ * Check permission prior to read a bpf map content.
+ * @map pointer to the struct bpf_map that contains map information.
+ * Return 0 if the permission is granted.
+ *
+ * @bpf_prog_load:
+ * Check permission prior to load eBPF program.
+ * Return 0 if the permission is granted.
+ *
+ * @bpf_post_create:
+ * Initialize the bpf object security field inside struct bpf_maps and
+ * it is used for future security checks.
+ *
  */
 union security_list_options {
int (*binder_set_context_mgr)(struct task_struct *mgr);
@@ -1685,6 +1711,14 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+   int (*bpf_map_create)(void);
+   int (*bpf_map_read)(struct bpf_map *map);
+   int (*bpf_map_modify)(struct bpf_map *map);
+   int (*bpf_prog_load)(void);
+   int (*bpf_post_create)(struct bpf_map *map);
+#endif /* CONFIG_BPF_SYSCALL */
 };
 
 struct security_hook_heads {
@@ -1905,6 +1939,13 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
 #endif /* CONFIG_AUDIT */
+#ifdef CONFIG_BPF_SYSCALL
+   struct list_head bpf_map_create;
+   struct list_head bpf_map_read;
+   struct list_head bpf_map_modify;
+   struct list_head bpf_prog_load;
+   struct list_head bpf_post_create;
+#endif /* CONFIG_BPF_SYSCALL */
 } __randomize_layout;
 
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index 458e24bea2d4..0656a4f74d14 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct linux_binprm;
 struct cred;
@@ -1735,6 +1736,41 @@ static inline void securityfs_remove(struct dentry 
*dentry)
 
 #endif
 
+#ifdef CONFIG_BPF_SYSCALL
+#ifdef CONFIG_SECURITY
+int security_map_create(void);
+int security_map_modify(struct bpf_map *map);
+int security_map_read(struct bpf_map *map);
+int security_prog_load(void);
+int security_post_create(struct bpf_map *map);
+#else
+static inline int security_map_create(void)
+{
+   return 0;
+}
+
+static inline int security_map_read(struct bpf_map *map)
+{
+   return 0;
+}
+
+static inline int security_map_modify(struct bpf_map *map)
+{
+   return 0;
+}
+
+static inline int security_prog_load(void)
+{
+   return 0;
+}
+
+static inline int security_post_create(struct bpf_map *map)
+{
+   return 0;
+}
+#endif /* CONFIG_SECURITY */
+#endif /* CONFIG_BPF_SYSCALL */
+
 #ifdef CONFIG_SECURITY
 
 static inline char *alloc_secdata(void)
diff --git a/security/security.c b/security/security.c
index 55b5997e4b72..02272f93a89e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -12,6 +12,7 @@
  * (at your option) any later version.
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -1708,3 +1709,30 @@ int security_audit_rule_match(u32 secid, u32 field, u32 
op, void *lsmrule,
actx);
 }
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+int security_map_create(void)
+{
+   return call_int_hook(bpf_map_create, 0);
+}
+
+int security_map_modify(struct bpf_map *map)
+{
+   return call_int_hook(bpf_map_modify, 0, map);
+}
+
+int security_map_read(struct 

[PATCH 0/3] Security: add lsm hooks for checking permissions on eBPF objects

2017-08-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Much like files and sockets, eBPF objects are accessed, controlled, and
shared via a file descriptor (FD). Unlike files and sockets, the existing
mechanism for eBPF object access control is very limited. Currently there
are two options for granting accessing to eBPF operations: grant access to
all processes, or only CAP_SYS_ADMIN processes. The CAP_SYS_ADMIN-only
mode is not ideal because most users do not have this capability and
granting a user CAP_SYS_ADMIN grants too many other security-sensitive
permissions. It also unnecessarily allows all CAP_SYS_ADMIN processes
access to eBPF functionality. Allowing all processes to access to eBPF
objects is also undesirable since it has potential to allow unprivileged
processes to consume kernel memory, and opens up attack surface to the
kernel.

Adding LSM hooks maintains the status quo for systems which do not use an
LSM, preserving compatibility with userspace, while allowing security
modules to choose how best to handle permissions on eBPF objects. Here is
a possible use case for the lsm hooks with selinux module:

The network-control daemon (netd) creates and loads an eBPF object for
network packet filtering and analysis. It passes the object FD to an
unprivileged network monitor app (netmonitor), which is not allowed to
create, modify or load eBPF objects, but is allowed to read the traffic
stats from the object.

Selinux could use these hooks to grant the following permissions:
allow netd self:bpf { create modify read…};
allow netmonitor netd:bpf read;

In this patch series, 5 security hooks is added to the eBPF syscall
implementations to do permissions checks. The LSM hooks introduced to eBPF
maps and programs can be summarized as follows:

Bpf_map_create: check for the ability of creating eBPF maps.
Bpf_map_modify: check the ability of update and delete eBPF map
entries.
Bpf_map_read:   check the ability of lookup map element as well as
get map keys.
Bpf_post_create: initialize the security struct inside struct
 bpf_map
Bpf_prog_load: check the ability for loading the eBPF program.

In order to store the ownership and security information about eBPF maps,
a security field pointer is added to the struct bpf_map. And a simple
implementation of selinux check on these hooks is added in selinux
subsystem.

Chenbo Feng (3):
  security: bpf: Add eBPF LSM hooks to security module
  security: bpf: Add eBPF LSM hooks and security field to eBPF map
  selinux: bpf: Implement the selinux checks for eBPF object

 include/linux/bpf.h |  3 +++
 include/linux/lsm_hooks.h   | 41 
 include/linux/security.h| 36 +
 kernel/bpf/syscall.c| 28 +++
 security/security.c | 28 +++
 security/selinux/hooks.c| 54 +
 security/selinux/include/classmap.h |  2 ++
 security/selinux/include/objsec.h   |  4 +++
 8 files changed, 196 insertions(+)

--
2.14.1.581.gf28d330327-goog



Re: Permissions for eBPF objects

2017-08-28 Thread Chenbo Feng
On Mon, Aug 28, 2017 at 6:15 PM, Alexei Starovoitov
<alexei.starovoi...@gmail.com> wrote:
> On Mon, Aug 28, 2017 at 05:47:19PM -0700, Chenbo Feng wrote:
>> On Fri, Aug 25, 2017 at 6:03 PM, Alexei Starovoitov
>> <alexei.starovoi...@gmail.com> wrote:
>> > On Fri, Aug 25, 2017 at 10:07:27PM +0200, Daniel Borkmann wrote:
>> >> On 08/25/2017 09:52 PM, Chenbo Feng wrote:
>> >> > On Fri, Aug 25, 2017 at 12:45 PM, Jeffrey Vander Stoep 
>> >> > <je...@google.com> wrote:
>> >> > > On Fri, Aug 25, 2017 at 12:26 PM, Stephen Smalley 
>> >> > > <s...@tycho.nsa.gov> wrote:
>> >> > > > On Fri, 2017-08-25 at 11:01 -0700, Jeffrey Vander Stoep via Selinux
>> >> > > > wrote:
>> >> > > > > I’d like to get your thoughts on adding LSM permission checks on 
>> >> > > > > BPF
>> >> > > > > objects.
>> >
>> > before reinventing the wheel please take a look at landlock work.
>> > Everything that was discussed in this thread is covered by it.
>> > The patches have been in development for more than a year and most of the 
>> > early
>> > issues have been resolved.
>> > It will be presented again during security summit in LA in September.
>> >
>> I am not very familiar with landlock lsm, isn't this module also
>> depend on the lsm hooks to do
>> the landlock check? If so then adding lsm hooks for eBPF object seems
>> not conflict with the
>> work on progress.
>
> I see. I got it the other way around. What lsm checks are you proposing?
> and why unprivileged_bpf_disabled is not enough?
> you want to allow unpriv only for specific user(s) ?
>
Exactly, the proposal patch I am currently working on will add checks
before map creation,
map read,  and map modify, since all these functionalities will be
available to all users when
unprivileged_bpf_disabled is turned off. And eBPF prog_load may also
need a check as well
since loading some types of program is not restricted either.


Re: Permissions for eBPF objects

2017-08-28 Thread Chenbo Feng
On Fri, Aug 25, 2017 at 6:03 PM, Alexei Starovoitov
<alexei.starovoi...@gmail.com> wrote:
> On Fri, Aug 25, 2017 at 10:07:27PM +0200, Daniel Borkmann wrote:
>> On 08/25/2017 09:52 PM, Chenbo Feng wrote:
>> > On Fri, Aug 25, 2017 at 12:45 PM, Jeffrey Vander Stoep <je...@google.com> 
>> > wrote:
>> > > On Fri, Aug 25, 2017 at 12:26 PM, Stephen Smalley <s...@tycho.nsa.gov> 
>> > > wrote:
>> > > > On Fri, 2017-08-25 at 11:01 -0700, Jeffrey Vander Stoep via Selinux
>> > > > wrote:
>> > > > > I’d like to get your thoughts on adding LSM permission checks on BPF
>> > > > > objects.
>
> before reinventing the wheel please take a look at landlock work.
> Everything that was discussed in this thread is covered by it.
> The patches have been in development for more than a year and most of the 
> early
> issues have been resolved.
> It will be presented again during security summit in LA in September.
>
I am not very familiar with landlock lsm, isn't this module also
depend on the lsm hooks to do
the landlock check? If so then adding lsm hooks for eBPF object seems
not conflict with the
work on progress.


Re: Permissions for eBPF objects

2017-08-25 Thread Chenbo Feng
On Fri, Aug 25, 2017 at 1:40 PM, Stephen Smalley <s...@tycho.nsa.gov> wrote:
> On Fri, 2017-08-25 at 12:52 -0700, Chenbo Feng via Selinux wrote:
>> On Fri, Aug 25, 2017 at 12:45 PM, Jeffrey Vander Stoep <jeffv@google.
>> com> wrote:
>> > On Fri, Aug 25, 2017 at 12:26 PM, Stephen Smalley <s...@tycho.nsa.go
>> > v> wrote:
>> > > On Fri, 2017-08-25 at 11:01 -0700, Jeffrey Vander Stoep via
>> > > Selinux
>> > > wrote:
>> > > > I’d like to get your thoughts on adding LSM permission checks
>> > > > on BPF
>> > > > objects.
>> > > >
>> > > > By default, the ability to create and use eBPF maps/programs
>> > > > requires
>> > > > CAP_SYS_ADMIN [1]. Alternatively, all processes can be granted
>> > > > access
>> > > > to bpf() functions. This seems like poor granularity. [2]
>> > > >
>> > > > Like files and sockets, eBPF maps and programs can be passed
>> > > > between
>> > > > processes by FD and have a number of functions that map cleanly
>> > > > to
>> > > > permissions.
>> > > >
>> > > > Let me know what you think. Are there simpler alternative
>> > > > approaches
>> > > > that we haven’t considered?
>> > >
>> > > Is it possible to create the map/program in one process (with
>> > > CAP_SYS_ADMIN), pass the resulting fd to netd, and then use it
>> > > there
>> > > (without requiring CAP_SYS_ADMIN in netd itself)?
>> >
>> > That might work. Any use of bpf() requires CAP_SYS_ADMIN but netd
>> > could potentially just apply the prog_fd to a socket:
>> >
>> >setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF,
>> >   _fd, sizeof(prog_fd));
>> >
>>
>> This specific case might work. But other map and program related
>> operations can
>> only be done through syscalls. And the syscall can be set to only
>> allow
>> CAP_SYS_ADMIN processes to use it or open to all processes. So when
>> the
>> CAP_SYS_ADMIN limitation is enforced, netd will not be able to use
>> any of the
>> syscalls such as map_look_up, map_update, map_delete even if a
>> CAP_SYS_ADMIN process passed the fd to it. Here is how this
>> enforcement
>> implemented:
>> http://elixir.free-
>> electrons.com/linux/latest/source/kernel/bpf/syscall.c#L1005
>
> I guess the question is whether netd needs to perform any of those
> operations itself, or if all of that can be done by another process and
> netd can just receive the fd over a unix socket and attach it.
>
> Not opposed to adding a LSM hook to bpf() and implementing a SELinux
> check there, just not 100% sure if you need it.
>
I am afraid only attach to socket will not need CAP_SYS_ADMIN if the
sysctl_unprivileged_bpf_disabled is set. But in our current design we might
need to attach a eBPF program to cgroups. Besides, reading and updating
the eBPF maps are also necessary operations that netd need to use. And these
are all unavailable to non-CAP_SYS_ADMIN processes when the sysctl is set.
So I guess we must have unprivileged BPF enabled to let our design work. And
adding lsm hooks to eBPF could make it under better control.

>>
>> > >
>> > > What level of granularity would be useful?  Would it go beyond
>> > > just
>> > > being able to use bpf() at all?
>> >
>> > "use" might be sufficient. At least initially.
>> >
>> > I could see some others coming in handy. For example, a simple
>> > mapping
>> > of functionality to permissions gives:
>> > map_create, map_update, map_delete, map_read, prog_load, prog_use.
>> >
>> > Of course there's no sense in breaking "use" into multiple
>> > permissions if
>> > we expect the entire set to always be granted together.
>> >
>> > >
>> > > >
>> > > > Thanks!
>> > > > Jeff
>> > > >
>> > > > [1] http://man7.org/linux/man-pages/man2/bpf.2.html NOTES
>> > > > section
>> > > > [2] We are considering eBPF for network filtering by netd.
>> > > > Giving
>> > > > netd
>> > > > CAP_SYS_ADMIN would considerably increase netd’s privileges.
>> > > > Alternatively allowing all processes permission to use bpf()
>> > > > goes
>> > > > against the principle of least privilege exposing a lot of
>> > > > kernel
>> > > > attack surface to processes that do not actually need it.
>> > > >


Re: Permissions for eBPF objects

2017-08-25 Thread Chenbo Feng
On Fri, Aug 25, 2017 at 12:45 PM, Jeffrey Vander Stoep  wrote:
> On Fri, Aug 25, 2017 at 12:26 PM, Stephen Smalley  wrote:
>> On Fri, 2017-08-25 at 11:01 -0700, Jeffrey Vander Stoep via Selinux
>> wrote:
>>> I’d like to get your thoughts on adding LSM permission checks on BPF
>>> objects.
>>>
>>> By default, the ability to create and use eBPF maps/programs requires
>>> CAP_SYS_ADMIN [1]. Alternatively, all processes can be granted access
>>> to bpf() functions. This seems like poor granularity. [2]
>>>
>>> Like files and sockets, eBPF maps and programs can be passed between
>>> processes by FD and have a number of functions that map cleanly to
>>> permissions.
>>>
>>> Let me know what you think. Are there simpler alternative approaches
>>> that we haven’t considered?
>>
>> Is it possible to create the map/program in one process (with
>> CAP_SYS_ADMIN), pass the resulting fd to netd, and then use it there
>> (without requiring CAP_SYS_ADMIN in netd itself)?
>
> That might work. Any use of bpf() requires CAP_SYS_ADMIN but netd
> could potentially just apply the prog_fd to a socket:
>
>setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF,
>   _fd, sizeof(prog_fd));
>

This specific case might work. But other map and program related operations can
only be done through syscalls. And the syscall can be set to only allow
CAP_SYS_ADMIN processes to use it or open to all processes. So when the
CAP_SYS_ADMIN limitation is enforced, netd will not be able to use any of the
syscalls such as map_look_up, map_update, map_delete even if a
CAP_SYS_ADMIN process passed the fd to it. Here is how this enforcement
implemented:
http://elixir.free-electrons.com/linux/latest/source/kernel/bpf/syscall.c#L1005

>>
>> What level of granularity would be useful?  Would it go beyond just
>> being able to use bpf() at all?
>
> "use" might be sufficient. At least initially.
>
> I could see some others coming in handy. For example, a simple mapping
> of functionality to permissions gives:
> map_create, map_update, map_delete, map_read, prog_load, prog_use.
>
> Of course there's no sense in breaking "use" into multiple permissions if
> we expect the entire set to always be granted together.
>
>>
>>>
>>> Thanks!
>>> Jeff
>>>
>>> [1] http://man7.org/linux/man-pages/man2/bpf.2.html NOTES section
>>> [2] We are considering eBPF for network filtering by netd. Giving
>>> netd
>>> CAP_SYS_ADMIN would considerably increase netd’s privileges.
>>> Alternatively allowing all processes permission to use bpf() goes
>>> against the principle of least privilege exposing a lot of kernel
>>> attack surface to processes that do not actually need it.
>>>


[PATCH net-next] Add a tcp_filter hook before handle ack packet

2017-06-20 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Currently in both ipv4 and ipv6 code path, the ack packet received when
sk at TCP_NEW_SYN_RECV state is not filtered by socket filter or cgroup
filter since it is handled from tcp_child_process and never reaches the
tcp_filter inside tcp_v4_rcv or tcp_v6_rcv. Adding a tcp_filter hooks
here can make sure all the ingress tcp packet can be correctly filtered.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 net/ipv4/tcp_ipv4.c | 2 ++
 net/ipv6/tcp_ipv6.c | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1dc8c44..ca3afb0 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1675,6 +1675,8 @@ int tcp_v4_rcv(struct sk_buff *skb)
}
if (nsk == sk) {
reqsk_put(req);
+   } else if (tcp_filter(sk, skb)) {
+   goto discard_and_relse;
} else if (tcp_child_process(sk, nsk, skb)) {
tcp_v4_send_reset(nsk, skb);
goto discard_and_relse;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 84ad502..565d89b 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1451,6 +1451,8 @@ static int tcp_v6_rcv(struct sk_buff *skb)
if (nsk == sk) {
reqsk_put(req);
tcp_v6_restore_cb(skb);
+   } else if (tcp_filter(sk, skb)) {
+   goto discard_and_relse;
} else if (tcp_child_process(sk, nsk, skb)) {
tcp_v6_send_reset(nsk, skb);
goto discard_and_relse;
-- 
2.7.4



Re: [PATCH net-next] Revert "ipv6: Initial skb->dev and skb->protocol in ip6_output"

2017-06-10 Thread Chenbo Feng



On 06/10/2017 07:55 AM, Eric Dumazet wrote:

On Fri, 2017-06-09 at 12:56 -0700, Chenbo Feng wrote:

From: Chenbo Feng <fe...@google.com>

This reverts commit 97a7a37a7b7b("ipv6: Initial skb->dev and
skb->protocol in ip6_output") since it does not handles the
skb->dev assignment inside ip6_fragment() code path properly.
Need to rework and upload again

We can avoid the revert I believe the patch is fine after analysis.

Please submit this followup, thanks ! :

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 
02cd44f0953900108701895108b2fdaa9f9980e5..0d6f3b6345de26c329ae1d6f25dde652a5452d4b
 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -869,7 +869,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct 
sk_buff *skb,
if (skb->sk && dst_allfrag(skb_dst(skb)))
sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
  
-	skb->dev = skb_dst(skb)->dev;

icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
err = -EMSGSIZE;
  




Thanks for the help! Patch submitted here: 
http://patchwork.ozlabs.org/patch/774260/


[PATCH net-next] Remove the redundant skb->dev initialization in ip6_fragment

2017-06-10 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

After moves the skb->dev and skb->protocol initialization into
ip6_output, setting the skb->dev inside ip6_fragment is unnecessary.

Fixes: 97a7a37a7b7b("ipv6: Initial skb->dev and skb->protocol in ip6_output")
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 net/ipv6/ip6_output.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 02cd44f..0d6f3b6 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -869,7 +869,6 @@ int ip6_fragment(struct net *net, struct sock *sk, struct 
sk_buff *skb,
if (skb->sk && dst_allfrag(skb_dst(skb)))
sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
 
-   skb->dev = skb_dst(skb)->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
err = -EMSGSIZE;
 
-- 
2.7.4



Re: [PATCH net-next] ipv6: Initial skb->dev and skb->protocol in ip6_output

2017-06-09 Thread Chenbo Feng



On 06/09/2017 12:39 PM, David Miller wrote:

From: Chenbo Feng <chenbofeng.ker...@gmail.com>
Date: Fri, 9 Jun 2017 12:13:57 -0700



On 06/09/2017 12:08 PM, David Miller wrote:

From: Chenbo Feng <chenbofeng.ker...@gmail.com>
Date: Fri,  9 Jun 2017 12:06:07 -0700


From: Chenbo Feng <fe...@google.com>

Move the initialization of skb->dev and skb->protocol from
ip6_finish_output2 to ip6_output. This can make the skb->dev and
skb->protocol information avalaible to the CGROUP eBPF filter.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Eric Dumazet <eduma...@google.com>

Applied, thanks.

This makes ipv6 consistent with ipv4.

I am surprised this wasn't noticed, for example, in netfilter.
.


Hi David,

This patch is still under working since it may have problem with
ip_fragment() call, did you applied it already? Should I send a revert
patch to you then?

A revert is necessary or a relative fixup.

Thank you.


Hi David,

The revert is uploaded here: http://patchwork.ozlabs.org/patch/774136/

Thanks and sorry for the trouble caused

Chenbo Feng


[PATCH net-next] Revert "ipv6: Initial skb->dev and skb->protocol in ip6_output"

2017-06-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

This reverts commit 97a7a37a7b7b("ipv6: Initial skb->dev and
skb->protocol in ip6_output") since it does not handles the
skb->dev assignment inside ip6_fragment() code path properly.
Need to rework and upload again

Fixes: 97a7a37a7b7b("ipv6: Initial skb->dev and skb->protocol in ip6_output")
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 net/ipv6/ip6_output.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 02cd44f..bf8a58a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -67,6 +67,9 @@ static int ip6_finish_output2(struct net *net, struct sock 
*sk, struct sk_buff *
struct in6_addr *nexthop;
int ret;
 
+   skb->protocol = htons(ETH_P_IPV6);
+   skb->dev = dev;
+
if (ipv6_addr_is_multicast(_hdr(skb)->daddr)) {
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
@@ -151,9 +154,6 @@ int ip6_output(struct net *net, struct sock *sk, struct 
sk_buff *skb)
struct net_device *dev = skb_dst(skb)->dev;
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
-   skb->protocol = htons(ETH_P_IPV6);
-   skb->dev = dev;
-
if (unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
-- 
2.7.4



Re: [PATCH net-next] ipv6: Initial skb->dev and skb->protocol in ip6_output

2017-06-09 Thread Chenbo Feng



On 06/09/2017 12:24 PM, Bjørn Mork wrote:

Chenbo Feng <chenbofeng.ker...@gmail.com> writes:


This patch is still under working since it may have problem with
ip_fragment() call, did you applied it already? Should I send a revert
patch to you then?

It does? I initially thought so too, but looking closer I believe the
ip6_copy_metadata() calls in ip6_fragment() takes care of it.



Bjørn

At least in the fail_toobig code path of ip_fragment() call, skb->dev 
get assigned again. It seems to be redundant with this patch or it will 
rewrite the skb->dev field. I will revert this one and upload again 
after I have a proper handle for that.


[PATCH net-next] bpf: Remove duplicate tcp_filter hook in ipv6

2017-06-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

There are two tcp_filter hooks in tcp_ipv6 ingress path currently.
One is at tcp_v6_rcv and another is in tcp_v6_do_rcv. It seems the
tcp_filter() call inside tcp_v6_do_rcv is redundent and some packet
will be filtered twice in this situation. This will cause trouble
when using eBPF filters to account traffic data.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Eric Dumazet <eduma...@google.com>
---
 net/ipv6/tcp_ipv6.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 0840543..84ad502 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1249,9 +1249,6 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff 
*skb)
if (skb->protocol == htons(ETH_P_IP))
return tcp_v4_do_rcv(sk, skb);
 
-   if (tcp_filter(sk, skb))
-   goto discard;
-
/*
 *  socket locking is here for SMP purposes as backlog rcv
 *  is currently called with bh processing disabled.
-- 
2.7.4



Re: [PATCH net-next] ipv6: Initial skb->dev and skb->protocol in ip6_output

2017-06-09 Thread Chenbo Feng



On 06/09/2017 12:08 PM, David Miller wrote:

From: Chenbo Feng <chenbofeng.ker...@gmail.com>
Date: Fri,  9 Jun 2017 12:06:07 -0700


From: Chenbo Feng <fe...@google.com>

Move the initialization of skb->dev and skb->protocol from
ip6_finish_output2 to ip6_output. This can make the skb->dev and
skb->protocol information avalaible to the CGROUP eBPF filter.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Eric Dumazet <eduma...@google.com>

Applied, thanks.

This makes ipv6 consistent with ipv4.

I am surprised this wasn't noticed, for example, in netfilter.
.


Hi David,

This patch is still under working since it may have problem with 
ip_fragment() call, did you applied it already? Should I send a revert 
patch to you then?


Chenbo Feng



[PATCH net-next] ipv6: Initial skb->dev and skb->protocol in ip6_output

2017-06-09 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Move the initialization of skb->dev and skb->protocol from
ip6_finish_output2 to ip6_output. This can make the skb->dev and
skb->protocol information avalaible to the CGROUP eBPF filter.

Signed-off-by: Chenbo Feng <fe...@google.com>
Acked-by: Eric Dumazet <eduma...@google.com>
---
 net/ipv6/ip6_output.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index bf8a58a..02cd44f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -67,9 +67,6 @@ static int ip6_finish_output2(struct net *net, struct sock 
*sk, struct sk_buff *
struct in6_addr *nexthop;
int ret;
 
-   skb->protocol = htons(ETH_P_IPV6);
-   skb->dev = dev;
-
if (ipv6_addr_is_multicast(_hdr(skb)->daddr)) {
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
@@ -154,6 +151,9 @@ int ip6_output(struct net *net, struct sock *sk, struct 
sk_buff *skb)
struct net_device *dev = skb_dst(skb)->dev;
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
+   skb->protocol = htons(ETH_P_IPV6);
+   skb->dev = dev;
+
if (unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
-- 
2.7.4



Question about tcp_filter() in tcp_v6_do_rcv()

2017-06-07 Thread Chenbo Feng

Hello everybody,

I am testing eBPF programs on ipv6 and I just find out the tcp_filter() 
function (previously named sk_filter()) is called both in tcp_v6_rcv() 
and tcp_v6_do_rcv(). In contrast, it is only called by tcp_v4_rcv() in 
ipv4 layer. I guess this implementation is used to capture some corner 
cases in ipv6 ingress route but I cannot find why. Could I know why we 
need this in two similar places in ipv6 transportation layer?


I have tried to dig into the commit history and the related code path 
but I did not see any obvious reason for doing so. And my problem with 
it is when a eBPF program is attached to a socket or a cgroup in ingress 
side, the filter program will be applied on some packets twice. And it 
affect the accuracy when using eBPF program for traffic accounting.


Thanks!

Chenbo Feng



Re: [PATCH net-next v2 2/2] bpf: Remove the capability check for cgroup skb eBPF program

2017-06-06 Thread Chenbo Feng


On 06/06/2017 09:56 AM, Daniel Borkmann wrote:

On 06/02/2017 01:42 AM, Alexei Starovoitov wrote:

On Wed, May 31, 2017 at 06:16:00PM -0700, Chenbo Feng wrote:

From: Chenbo Feng <fe...@google.com>

Currently loading a cgroup skb eBPF program require a CAP_SYS_ADMIN
capability while attaching the program to a cgroup only requires the
user have CAP_NET_ADMIN privilege. We can escape the capability
check when load the program just like socket filter program to make
the capability requirement consistent.

Change since v1:
Change the code style in order to be compliant with checkpatch.pl
preference

Signed-off-by: Chenbo Feng <fe...@google.com>


as far as I can see they're indeed the same as socket filters, so
Acked-by: Alexei Starovoitov <a...@kernel.org>

but I don't quite understand how it helps, since as you said
attaching such unpriv fd to cgroup still requires root.
Do you have more patches to follow?


Hmm, when we relax this from capable(CAP_SYS_ADMIN) to unprivileged,
then we must at least also zero out the not-yet-initialized memory
for the mac header for egress case in __cgroup_bpf_run_filter_skb().



Do you mean something like:

if (type == BPF_CGROUP_INET_EGRESS) {

offset = skb_network_header(skb) - skb_mac_header(skb);

memset(skb_mac_header(skb), 0, offset)

}

And could you explain more on why we need to do this if we remove the 
CAP_SYS_ADMIN check? I thought we still cannot directly access the 
sk_buff without using bpf_skb_load_bytes helper and we still need a 
CAP_NET_ADMIN in order to attach and run the program on egress side right?


[PATCH net-next v2 1/2] bpf: Allow CGROUP_SKB eBPF program to access sk_buff

2017-05-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

This allows cgroup eBPF program to classify packet based on their
protocol or other detail information. Currently program need
CAP_NET_ADMIN privilege to attach a cgroup eBPF program, and A
process with CAP_NET_ADMIN can already see all packets on the system,
for example, by creating an iptables rules that causes the packet to
be passed to userspace via NFLOG.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 kernel/bpf/verifier.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 339c8a1..94a9bc9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2419,6 +2419,7 @@ static bool may_access_skb(enum bpf_prog_type type)
case BPF_PROG_TYPE_SOCKET_FILTER:
case BPF_PROG_TYPE_SCHED_CLS:
case BPF_PROG_TYPE_SCHED_ACT:
+   case BPF_PROG_TYPE_CGROUP_SKB:
return true;
default:
return false;
-- 
2.7.4



[PATCH net-next v2 2/2] bpf: Remove the capability check for cgroup skb eBPF program

2017-05-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Currently loading a cgroup skb eBPF program require a CAP_SYS_ADMIN
capability while attaching the program to a cgroup only requires the
user have CAP_NET_ADMIN privilege. We can escape the capability
check when load the program just like socket filter program to make
the capability requirement consistent.

Change since v1:
Change the code style in order to be compliant with checkpatch.pl
preference

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 kernel/bpf/syscall.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 265a0d8..59da103 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -815,7 +815,9 @@ static int bpf_prog_load(union bpf_attr *attr)
attr->kern_version != LINUX_VERSION_CODE)
return -EINVAL;
 
-   if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN))
+   if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
+   type != BPF_PROG_TYPE_CGROUP_SKB &&
+   !capable(CAP_SYS_ADMIN))
return -EPERM;
 
/* plain bpf_prog allocation */
-- 
2.7.4



[PATCH net-next v2] bpf: Remove the capability check for cgroup skb eBPF program

2017-05-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Currently loading a cgroup skb eBPF program require a CAP_SYS_ADMIN
capability while attaching the program to a cgroup only requires the
user have CAP_NET_ADMIN privilege. We can escape the capability
check when load the program just like socket filter program to make
the capability requirement consistent.

Change since v1:
Change the code style in order to be compliant with checkpatch.pl
preference

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 kernel/bpf/syscall.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 265a0d8..59da103 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -815,7 +815,9 @@ static int bpf_prog_load(union bpf_attr *attr)
attr->kern_version != LINUX_VERSION_CODE)
return -EINVAL;
 
-   if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN))
+   if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
+   type != BPF_PROG_TYPE_CGROUP_SKB &&
+   !capable(CAP_SYS_ADMIN))
return -EPERM;
 
/* plain bpf_prog allocation */
-- 
2.7.4



[PATCH net-next 2/2] bpf: Remove the capability check for cgroup skb eBPF program

2017-05-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Currently loading a cgroup skb eBPF program require a CAP_SYS_ADMIN
capability while attaching the program to a cgroup only requires the
user have CAP_NET_ADMIN privilege. We can escape the capability
check when load the program just like socket filter program to make
the capability requirement consistent.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 kernel/bpf/syscall.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 265a0d8..021c0b4 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -815,7 +815,9 @@ static int bpf_prog_load(union bpf_attr *attr)
attr->kern_version != LINUX_VERSION_CODE)
return -EINVAL;
 
-   if (type != BPF_PROG_TYPE_SOCKET_FILTER && !capable(CAP_SYS_ADMIN))
+   if (type != BPF_PROG_TYPE_SOCKET_FILTER
+   && type != BPF_PROG_TYPE_CGROUP_SKB
+   && !capable(CAP_SYS_ADMIN))
return -EPERM;
 
/* plain bpf_prog allocation */
-- 
2.7.4



[PATCH net-next 1/2] bpf: Allow CGROUP_SKB eBPF program to access sk_buff

2017-05-31 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

This allows cgroup eBPF program to classify packet based on their
protocol or other detail information. Currently program need
CAP_NET_ADMIN privilege to attach a cgroup eBPF program, and A
process with CAP_NET_ADMIN can already see all packets on the system,
for example, by creating an iptables rules that causes the packet to
be passed to userspace via NFLOG.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 kernel/bpf/verifier.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 339c8a1..94a9bc9 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2419,6 +2419,7 @@ static bool may_access_skb(enum bpf_prog_type type)
case BPF_PROG_TYPE_SOCKET_FILTER:
case BPF_PROG_TYPE_SCHED_CLS:
case BPF_PROG_TYPE_SCHED_ACT:
+   case BPF_PROG_TYPE_CGROUP_SKB:
return true;
default:
return false;
-- 
2.7.4



[PATCH net-next] Fix inaccurate helper function description

2017-04-26 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

The description inside uapi/linux/bpf.h about bpf_get_socket_uid
helper function is no longer valid. It returns overflowuid rather
than 0 when failed.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/uapi/linux/bpf.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index e553529..945a1f5 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -481,8 +481,7 @@ union bpf_attr {
  * u32 bpf_get_socket_uid(skb)
  * Get the owner uid of the socket stored inside sk_buff.
  * @skb: pointer to skb
- * Return: uid of the socket owner on success or 0 if the socket pointer
- * inside sk_buff is NULL
+ * Return: uid of the socket owner on success or overflowuid if failed.
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
-- 
2.7.4



[PATCH net-next v2] Add uid and cookie bpf helper to cg_skb_func_proto

2017-04-14 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

BPF helper functions get_socket_cookie and get_socket_uid can be
used for network traffic classifications, among others. Expose
them also to programs of type BPF_PROG_TYPE_CGROUP_SKB. As of
commit 8f917bba0042 ("bpf: pass sk to helper functions") the
required skb->sk function is available at both cgroup bpf ingress
and egress hooks. With these two new helper, cg_skb_func_proto is
effectively the same as sk_filter_func_proto.

Change since V1:
Instead of add the helper to cg_skb_func_proto, redirect the
cg_skb_func_proto to sk_filter_func_proto since all helper function
in sk_filter_func_proto are applicable to cg_skb_func_proto now.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 net/core/filter.c | 7 +--
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/net/core/filter.c b/net/core/filter.c
index ce2a19d..19be954 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2766,12 +2766,7 @@ xdp_func_proto(enum bpf_func_id func_id)
 static const struct bpf_func_proto *
 cg_skb_func_proto(enum bpf_func_id func_id)
 {
-   switch (func_id) {
-   case BPF_FUNC_skb_load_bytes:
-   return _skb_load_bytes_proto;
-   default:
-   return bpf_base_func_proto(func_id);
-   }
+   return sk_filter_func_proto(func_id);
 }
 
 static const struct bpf_func_proto *
-- 
2.7.4



[PATCH net-next] Add uid and cookie bpf helper to cg_skb_func_proto

2017-04-14 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

BPF helper functions get_socket_cookie and get_socket_uid can be
used for network traffic classifications, among others. Expose
them also to programs of type BPF_PROG_TYPE_CGROUP_SKB. As of
commit 8f917bba0042 ("bpf: pass sk to helper functions") the required
skb->sk function is available at both cgroup bpf ingress and egress
hooks.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 net/core/filter.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/net/core/filter.c b/net/core/filter.c
index ce2a19d..b6db9e330 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2769,6 +2769,10 @@ cg_skb_func_proto(enum bpf_func_id func_id)
switch (func_id) {
case BPF_FUNC_skb_load_bytes:
return _skb_load_bytes_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
-- 
2.7.4



[PATCH net-next 2/2] Sample program using SO_COOKIE

2017-04-05 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Added a per socket traffic monitoring option to illustrate the usage
of new getsockopt SO_COOKIE. The program is based on the socket traffic
monitoring program using xt_eBPF and in the new option the data entry
can be directly accessed using socket cookie. The cookie retrieved
allow us to lookup an element in the eBPF for a specific socket.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 samples/bpf/cookie_uid_helper_example.c  | 146 +++
 samples/bpf/run_cookie_uid_helper_example.sh |   4 +-
 2 files changed, 127 insertions(+), 23 deletions(-)
 mode change 100644 => 100755 samples/bpf/run_cookie_uid_helper_example.sh

diff --git a/samples/bpf/cookie_uid_helper_example.c 
b/samples/bpf/cookie_uid_helper_example.c
index f6e5e58..ad5afed 100644
--- a/samples/bpf/cookie_uid_helper_example.c
+++ b/samples/bpf/cookie_uid_helper_example.c
@@ -4,10 +4,11 @@
  * program into the xt_bpf match.
  *
  * TEST:
- * ./run_cookie_uid_helper_example.sh
- * Then generate some traffic in variate ways. ping 0 -c 10 would work
- * but the cookie and uid in this case could both be 0. A sample output
- * with some traffic generated by web browser is shown below:
+ * ./run_cookie_uid_helper_example.sh -option
+ * option:
+ * -t: do traffic monitoring test, the program will continuously
+ * print out network traffic happens after program started A sample
+ * output is shown below:
  *
  * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058
  * cookie: 132, uid: 0x0, Pakcet Count: 2, Bytes Count: 286
@@ -18,6 +19,10 @@
  * cookie: 0, uid: 0x0, Pakcet Count: 6, Bytes Count: 712
  * cookie: 880, uid: 0xfffe, Pakcet Count: 1, Bytes Count: 70
  *
+ * -s: do getsockopt SO_COOKIE test, the program will set up a pair of
+ * UDP sockets and send packets between them. And read out the traffic data
+ * directly from the ebpf map based on the socket cookie.
+ *
  * Clean up: if using shell script, the script file will delete the iptables
  * rule and unmount the bpf program when exit. Else the iptables rule need
  * to be deleted by hand, see run_cookie_uid_helper_example.sh for detail.
@@ -34,6 +39,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -46,6 +53,8 @@
 #include 
 #include "libbpf.h"
 
+#define PORT 
+
 struct stats {
uint32_t uid;
uint64_t packets;
@@ -54,6 +63,8 @@ struct stats {
 
 static int map_fd, prog_fd;
 
+static bool test_finish;
+
 static void maps_create(void)
 {
map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t),
@@ -164,7 +175,7 @@ static void prog_attach_iptables(char *file)
printf("file path too long: %s\n", file);
exit(1);
}
-   sprintf(rules, "iptables -A INPUT -m bpf --object-pinned %s -j ACCEPT",
+   sprintf(rules, "iptables -A OUTPUT -m bpf --object-pinned %s -j ACCEPT",
file);
ret = system(rules);
if (ret < 0) {
@@ -177,7 +188,8 @@ static void print_table(void)
 {
struct stats curEntry;
uint32_t curN = UINT32_MAX;
-   uint32_t nextN, res;
+   uint32_t nextN;
+   int res;
 
while (bpf_map_get_next_key(map_fd, , ) > -1) {
curN = nextN;
@@ -193,25 +205,117 @@ static void print_table(void)
}
 }
 
-int main(int argc, char *argv[])
+static void udp_client(void)
 {
-   if (argc > 2) {
-   printf("Too many argument provided\n");
-   return 1;
-   } else if (argc < 2) {
-   printf("Usage: %s bpfObjName\n", argv[0]);
-   return 1;
+   struct sockaddr_in si_other = {0};
+   struct sockaddr_in si_me = {0};
+   struct stats dataEntry;
+   int s_rcv, s_send, i, recv_len;
+   char message = 'a';
+   char buf;
+   uint64_t cookie;
+   int res;
+   socklen_t cookie_len = sizeof(cookie);
+   socklen_t slen = sizeof(si_other);
+
+   s_rcv = socket(PF_INET, SOCK_DGRAM, 0);
+   if (s_rcv < 0)
+   error(1, errno, "rcv socket creat failed!\n");
+   si_other.sin_family = AF_INET;
+   si_other.sin_port = htons(PORT);
+   if (inet_aton("127.0.0.1", _other.sin_addr) == 0)
+   error(1, errno, "inet_aton\n");
+   if (bind(s_rcv, (struct sockaddr *)_other, sizeof(si_other)) == -1)
+   error(1, errno, "bind\n");
+   s_send = socket(PF_INET, SOCK_DGRAM, 0);
+   if (s_send < 0)
+   error(1, errno, "send socket creat failed!\n");
+   res = getsockopt(s_send, SOL_SOCKET, SO_COOKIE, , _len);
+   if (res < 0)
+   printf("get cookie failed: %s\n", strerror(errno));
+   res = bpf_map_lookup_elem(map_fd, , );
+   if (res != -1)
+   error(1, errno, "socket stat found while

[PATCH net-next 1/2] New getsockopt option to get socket cookie

2017-04-05 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce a new getsockopt operation to retrieve the socket cookie
for a specific socket based on the socket fd.  It returns a unique
non-decreasing cookie for each socket.
Tested: https://android-review.googlesource.com/#/c/358163/

Acked-by: Willem de Bruijn <will...@google.com>
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 arch/alpha/include/uapi/asm/socket.h   | 2 ++
 arch/avr32/include/uapi/asm/socket.h   | 2 ++
 arch/frv/include/uapi/asm/socket.h | 2 ++
 arch/ia64/include/uapi/asm/socket.h| 2 ++
 arch/m32r/include/uapi/asm/socket.h| 2 ++
 arch/mips/include/uapi/asm/socket.h| 2 ++
 arch/mn10300/include/uapi/asm/socket.h | 2 ++
 arch/parisc/include/uapi/asm/socket.h  | 2 ++
 arch/powerpc/include/uapi/asm/socket.h | 2 ++
 arch/s390/include/uapi/asm/socket.h| 2 ++
 arch/sparc/include/uapi/asm/socket.h   | 2 ++
 arch/xtensa/include/uapi/asm/socket.h  | 2 ++
 include/uapi/asm-generic/socket.h  | 2 ++
 net/core/sock.c| 8 
 14 files changed, 34 insertions(+)

diff --git a/arch/alpha/include/uapi/asm/socket.h 
b/arch/alpha/include/uapi/asm/socket.h
index 1bb8cac..148d7a3 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -103,4 +103,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/avr32/include/uapi/asm/socket.h 
b/arch/avr32/include/uapi/asm/socket.h
index f824eeb..2434d08 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -96,4 +96,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _UAPI__ASM_AVR32_SOCKET_H */
diff --git a/arch/frv/include/uapi/asm/socket.h 
b/arch/frv/include/uapi/asm/socket.h
index a8ad9be..1ccf456 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -96,5 +96,7 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _ASM_SOCKET_H */
 
diff --git a/arch/ia64/include/uapi/asm/socket.h 
b/arch/ia64/include/uapi/asm/socket.h
index 6af3253..2c3f4b4 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -105,4 +105,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/m32r/include/uapi/asm/socket.h 
b/arch/m32r/include/uapi/asm/socket.h
index e98b6bb..ae6548d 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -96,4 +96,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/mips/include/uapi/asm/socket.h 
b/arch/mips/include/uapi/asm/socket.h
index ae2b62e..3418ec9 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -114,4 +114,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mn10300/include/uapi/asm/socket.h 
b/arch/mn10300/include/uapi/asm/socket.h
index e4ac184..4526e92 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -96,4 +96,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/uapi/asm/socket.h 
b/arch/parisc/include/uapi/asm/socket.h
index f754c79..5147018 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -95,4 +95,6 @@
 
 #define SO_INCOMING_NAPI_ID0x4031
 
+#define SO_COOKIE  0x4032
+
 #endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/powerpc/include/uapi/asm/socket.h 
b/arch/powerpc/include/uapi/asm/socket.h
index 5f84af7..58e2ec0 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -103,4 +103,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/s390/include/uapi/asm/socket.h 
b/arch/s390/include/uapi/asm/socket.h
index 25ac496..e8e5ecf 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -102,4 +102,6 @@
 
 #define SO_INCOMING_NAPI_ID56
 
+#define SO_COOKIE  57
+
 #endif /* _ASM_SOCKET_H */
diff --git a/arch/sparc/include/uapi/asm/socket.h 
b/arch/sparc/include/uapi/asm/socket.h
index b05513a..3f4ad19 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -92,6 +92,8 @@
 
 #define SO_INCOMING_NAPI_ID0x003a
 
+#define SO_COOKIE  0x003b
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION 0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT   0x5002
diff --git a/arch/xtensa/include/uapi/asm/socket.h 
b/arch/xtensa/include/uapi/

[PATCH net-next 0/2] New getsockopt option to retrieve socket cookie

2017-04-05 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>


In the current kernel socket cookie implementation, there is no simple
and direct way to retrieve the socket cookie based on file descriptor. A
process mat need to get it from sock fd if it want to correlate with
sock_diag output or use a bpf map with new socket cookie function.

If userspace wants to receive the socket cookie for a given socket fd,
it must send a SOCK_DIAG_BY_FAMILY dump request and look for the 5-tuple.
This is slow and can be ambiguous in the case of sockets that have the
same 5-tuple (e.g., tproxy / transparent sockets, SO_REUSEPORT sockets,
etc.).

As shown in the example program. The xt_eBPF program is using socket cookie
to record the network traffics statistics and with the socket cookie
retrieved by getsockopt. The program can directly access to a specific
socket data without scanning the whole bpf map.

Chenbo Feng (2):
  New getsockopt option to get socket cookie
  Sample program using SO_COOKIE

 arch/alpha/include/uapi/asm/socket.h |   2 +
 arch/avr32/include/uapi/asm/socket.h |   2 +
 arch/frv/include/uapi/asm/socket.h   |   2 +
 arch/ia64/include/uapi/asm/socket.h  |   2 +
 arch/m32r/include/uapi/asm/socket.h  |   2 +
 arch/mips/include/uapi/asm/socket.h  |   2 +
 arch/mn10300/include/uapi/asm/socket.h   |   2 +
 arch/parisc/include/uapi/asm/socket.h|   2 +
 arch/powerpc/include/uapi/asm/socket.h   |   2 +
 arch/s390/include/uapi/asm/socket.h  |   2 +
 arch/sparc/include/uapi/asm/socket.h |   2 +
 arch/xtensa/include/uapi/asm/socket.h|   2 +
 include/uapi/asm-generic/socket.h|   2 +
 net/core/sock.c  |   4 +
 samples/bpf/cookie_uid_helper_example.c  | 112 ++-
 samples/bpf/run_cookie_uid_helper_example.sh |   4 +-
 16 files changed, 124 insertions(+), 22 deletions(-)
 mode change 100644 => 100755 samples/bpf/run_cookie_uid_helper_example.sh

-- 
2.7.4



[PATCH net-next v8 1/3] Add a helper function to get socket cookie in eBPF

2017-03-22 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Retrieve the socket cookie generated by sock_gen_cookie() from a sk_buff
with a known socket. Generates a new cookie if one was not yet set.If
the socket pointer inside sk_buff is NULL, 0 is returned. The helper
function coud be useful in monitoring per socket networking traffic
statistics and provide a unique socket identifier per namespace.

Acked-by: Daniel Borkmann <dan...@iogearbox.net>
Acked-by: Alexei Starovoitov <a...@kernel.org>
Acked-by: Willem de Bruijn <will...@google.com>
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/sock_diag.h  |  1 +
 include/uapi/linux/bpf.h   |  9 -
 net/core/filter.c  | 17 +
 net/core/sock_diag.c   |  2 +-
 tools/include/uapi/linux/bpf.h |  3 ++-
 5 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index a0596ca0..a2f8109 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -24,6 +24,7 @@ void sock_diag_unregister(const struct sock_diag_handler *h);
 void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct 
nlmsghdr *nlh));
 void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct 
nlmsghdr *nlh));
 
+u64 sock_gen_cookie(struct sock *sk);
 int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie);
 void sock_diag_save_cookie(struct sock *sk, __u32 *cookie);
 
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0539a0c..dc81a9f 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -456,6 +456,12 @@ union bpf_attr {
  * Return:
  *   > 0 length of the string including the trailing NUL on success
  *   < 0 error
+ *
+ * u64 bpf_bpf_get_socket_cookie(skb)
+ * Get the cookie for the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: 8 Bytes non-decreasing number on success or 0 if the socket
+ * field is missing inside sk_buff
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -503,7 +509,8 @@ union bpf_attr {
FN(get_numa_node_id),   \
FN(skb_change_head),\
FN(xdp_adjust_head),\
-   FN(probe_read_str),
+   FN(probe_read_str), \
+   FN(get_socket_cookie),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index ebaeaf2..5b65ae3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2599,6 +2600,18 @@ static const struct bpf_func_proto 
bpf_xdp_event_output_proto = {
.arg5_type  = ARG_CONST_SIZE,
 };
 
+BPF_CALL_1(bpf_get_socket_cookie, struct sk_buff *, skb)
+{
+   return skb->sk ? sock_gen_cookie(skb->sk) : 0;
+}
+
+static const struct bpf_func_proto bpf_get_socket_cookie_proto = {
+   .func   = bpf_get_socket_cookie,
+   .gpl_only   = false,
+   .ret_type   = RET_INTEGER,
+   .arg1_type  = ARG_PTR_TO_CTX,
+};
+
 static const struct bpf_func_proto *
 bpf_base_func_proto(enum bpf_func_id func_id)
 {
@@ -2633,6 +2646,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
switch (func_id) {
case BPF_FUNC_skb_load_bytes:
return _skb_load_bytes_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -2692,6 +2707,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return _get_smp_processor_id_proto;
case BPF_FUNC_skb_under_cgroup:
return _skb_under_cgroup_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
default:
return bpf_base_func_proto(func_id);
}
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 6b10573..acd2a6c 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -19,7 +19,7 @@ static int (*inet_rcv_compat)(struct sk_buff *skb, struct 
nlmsghdr *nlh);
 static DEFINE_MUTEX(sock_diag_table_mutex);
 static struct workqueue_struct *broadcast_wq;
 
-static u64 sock_gen_cookie(struct sock *sk)
+u64 sock_gen_cookie(struct sock *sk)
 {
while (1) {
u64 res = atomic64_read(>sk_cookie);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0539a0c..a94bdd3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -503,7 +503,8 @@ union bpf_attr {
FN(get_numa_node_id),   \
FN(skb_change_head),\
FN(xdp_adjust_head),\
-   FN(probe_read_str),
+   FN(probe_read_str), \
+   FN(get_socket_cookie),
 

[PATCH net-next v8 2/3] Add a eBPF helper function to retrieve socket uid

2017-03-22 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Returns the owner uid of the socket inside a sk_buff. This is useful to
perform per-UID accounting of network traffic or per-UID packet
filtering. The socket need to be a fullsock otherwise overflowuid is
returned.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/uapi/linux/bpf.h   |  9 -
 net/core/filter.c  | 22 ++
 tools/include/uapi/linux/bpf.h |  3 ++-
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index dc81a9f..ff42111 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -462,6 +462,12 @@ union bpf_attr {
  * @skb: pointer to skb
  * Return: 8 Bytes non-decreasing number on success or 0 if the socket
  * field is missing inside sk_buff
+ *
+ * u32 bpf_get_socket_uid(skb)
+ * Get the owner uid of the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: uid of the socket owner on success or 0 if the socket pointer
+ * inside sk_buff is NULL
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -510,7 +516,8 @@ union bpf_attr {
FN(skb_change_head),\
FN(xdp_adjust_head),\
FN(probe_read_str), \
-   FN(get_socket_cookie),
+   FN(get_socket_cookie),  \
+   FN(get_socket_uid),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index 5b65ae3..93cc4af 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2612,6 +2612,24 @@ static const struct bpf_func_proto 
bpf_get_socket_cookie_proto = {
.arg1_type  = ARG_PTR_TO_CTX,
 };
 
+BPF_CALL_1(bpf_get_socket_uid, struct sk_buff *, skb)
+{
+   struct sock *sk = sk_to_full_sk(skb->sk);
+   kuid_t kuid;
+
+   if (!sk || !sk_fullsock(sk))
+   return overflowuid;
+   kuid = sock_net_uid(sock_net(sk), sk);
+   return from_kuid_munged(sock_net(sk)->user_ns, kuid);
+}
+
+static const struct bpf_func_proto bpf_get_socket_uid_proto = {
+   .func   = bpf_get_socket_uid,
+   .gpl_only   = false,
+   .ret_type   = RET_INTEGER,
+   .arg1_type  = ARG_PTR_TO_CTX,
+};
+
 static const struct bpf_func_proto *
 bpf_base_func_proto(enum bpf_func_id func_id)
 {
@@ -2648,6 +2666,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
return _skb_load_bytes_proto;
case BPF_FUNC_get_socket_cookie:
return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -2709,6 +2729,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return _skb_under_cgroup_proto;
case BPF_FUNC_get_socket_cookie:
return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index a94bdd3..4a2d56d 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -504,7 +504,8 @@ union bpf_attr {
FN(skb_change_head),\
FN(xdp_adjust_head),\
FN(probe_read_str), \
-   FN(get_socket_cookie),
+   FN(get_socket_cookie),  \
+   FN(get_socket_uid),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
-- 
2.7.4



[PATCH net-next v8 3/3] A Sample of using socket cookie and uid for traffic monitoring

2017-03-22 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Add a sample program to demostrate the possible usage of
get_socket_cookie and get_socket_uid helper function. The program will
store bytes and packets counting of in/out traffic monitored by iptables
and store the stats in a bpf map in per socket base. The owner uid of
the socket will be stored as part of the data entry. A shell script for
running the program is also included.

Acked-by: Alexei Starovoitov <a...@kernel.org>
Acked-by: Willem de Bruijn <will...@google.com>
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 samples/bpf/Makefile |   3 +
 samples/bpf/cookie_uid_helper_example.c  | 217 +++
 samples/bpf/libbpf.h |  10 ++
 samples/bpf/run_cookie_uid_helper_example.sh |  14 ++
 4 files changed, 244 insertions(+)
 create mode 100644 samples/bpf/cookie_uid_helper_example.c
 create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 09e9d53..f803f51 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -34,6 +34,7 @@ hostprogs-y += sampleip
 hostprogs-y += tc_l2_redirect
 hostprogs-y += lwt_len_hist
 hostprogs-y += xdp_tx_iptunnel
+hostprogs-y += per_socket_stats_example
 
 # Libbpf dependencies
 LIBBPF := ../../tools/lib/bpf/bpf.o
@@ -72,6 +73,7 @@ sampleip-objs := bpf_load.o $(LIBBPF) sampleip_user.o
 tc_l2_redirect-objs := bpf_load.o $(LIBBPF) tc_l2_redirect_user.o
 lwt_len_hist-objs := bpf_load.o $(LIBBPF) lwt_len_hist_user.o
 xdp_tx_iptunnel-objs := bpf_load.o $(LIBBPF) xdp_tx_iptunnel_user.o
+per_socket_stats_example-objs := $(LIBBPF) cookie_uid_helper_example.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -105,6 +107,7 @@ always += trace_event_kern.o
 always += sampleip_kern.o
 always += lwt_len_hist_kern.o
 always += xdp_tx_iptunnel_kern.o
+always += cookie_uid_helper_example.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 HOSTCFLAGS += -I$(srctree)/tools/lib/
diff --git a/samples/bpf/cookie_uid_helper_example.c 
b/samples/bpf/cookie_uid_helper_example.c
new file mode 100644
index 000..f6e5e58
--- /dev/null
+++ b/samples/bpf/cookie_uid_helper_example.c
@@ -0,0 +1,217 @@
+/* This test is a demo of using get_socket_uid and get_socket_cookie
+ * helper function to do per socket based network traffic monitoring.
+ * It requires iptables version higher then 1.6.1. to load pinned eBPF
+ * program into the xt_bpf match.
+ *
+ * TEST:
+ * ./run_cookie_uid_helper_example.sh
+ * Then generate some traffic in variate ways. ping 0 -c 10 would work
+ * but the cookie and uid in this case could both be 0. A sample output
+ * with some traffic generated by web browser is shown below:
+ *
+ * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058
+ * cookie: 132, uid: 0x0, Pakcet Count: 2, Bytes Count: 286
+ * cookie: 812, uid: 0x3e8, Pakcet Count: 3, Bytes Count: 1726
+ * cookie: 802, uid: 0x3e8, Pakcet Count: 2, Bytes Count: 104
+ * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058
+ * cookie: 831, uid: 0x3e8, Pakcet Count: 2, Bytes Count: 104
+ * cookie: 0, uid: 0x0, Pakcet Count: 6, Bytes Count: 712
+ * cookie: 880, uid: 0xfffe, Pakcet Count: 1, Bytes Count: 70
+ *
+ * Clean up: if using shell script, the script file will delete the iptables
+ * rule and unmount the bpf program when exit. Else the iptables rule need
+ * to be deleted by hand, see run_cookie_uid_helper_example.sh for detail.
+ */
+
+#define _GNU_SOURCE
+
+#define offsetof(type, member) __builtin_offsetof(type, member)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "libbpf.h"
+
+struct stats {
+   uint32_t uid;
+   uint64_t packets;
+   uint64_t bytes;
+};
+
+static int map_fd, prog_fd;
+
+static void maps_create(void)
+{
+   map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t),
+   sizeof(struct stats), 100, 0);
+   if (map_fd < 0)
+   error(1, errno, "map create failed!\n");
+}
+
+static void prog_load(void)
+{
+   static char log_buf[1 << 16];
+
+   struct bpf_insn prog[] = {
+   /*
+* Save sk_buff for future usage. value stored in R6 to R10 will
+* not be reset after a bpf helper function call.
+*/
+   BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+   /*
+* pc1: BPF_FUNC_get_socket_cookie takes one parameter,
+* R1: sk_buff
+*/
+   BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+   BPF_FUNC_get_socket_cookie),
+   /* pc2-4: save  to r7 for future usage*/
+   BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8)

[PATCH net-next v8 0/3] net: core: Two Helper function about socket information

2017-03-22 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce two eBpf helper function to get the socket cookie and
socket uid for each packet. The helper function is useful when
the *sk field inside sk_buff is not empty. These helper functions
can be used on socket and uid based traffic monitoring programs.

Change since V7:
* change the user namespace of uid helper function to sock_net(sk)->user_ns

Change since V6:
* change the user namespace of uid helper function back to init_user_ns
  since in some situation, for example, pinned bpf object, the current
  user namespace is not always applicable. 

Change since V5:
* Delete unnecessary blank lines in sample program.
* Refine the variable orders in get_uid helper function.

Change since V4:
* Using current user namespace to get uid instead of using init_ns.
* Add compiling setup of example program in to Makefile.
* Change the name style of the example program binaries.

Change since V3:
* Fixed some typos and incorrect comments in sample program
* replaced raw insns with BPF_STX_XADD and add it to libbpf.h
* Use a temp dir as mount point instead and added a check for
  the user input string.
* Make the get uid helper function returns the user namespace uid
  instead of kuid.
* Return a overflowuid instead of 0 when no uid information is found.

Change since V2:
* Add a sample program to demostrate the usage of the helper function.
* Moved the helper function proto invoking place.
* Add function header into tools/include
* Apply sk_to_full_sk() before getting uid.

Change since V1:
* Removed the unnecessary declarations and export command
* resolved conflict with master branch.
* Examine if the socket is a full socket before getting the uid.


Chenbo Feng (3):
  Add a helper function to get socket cookie in eBPF
  Add a eBPF helper function to retrieve socket uid
  A Sample of using socket cookie and uid for traffic monitoring

Chenbo Feng (3):
  Add a helper function to get socket cookie in eBPF
  Add a eBPF helper function to retrieve socket uid
  A Sample of using socket cookie and uid for traffic monitoring

 include/linux/sock_diag.h|   1 +
 include/uapi/linux/bpf.h |  16 +-
 net/core/filter.c|  39 +
 net/core/sock_diag.c |   2 +-
 samples/bpf/Makefile |   3 +
 samples/bpf/cookie_uid_helper_example.c  | 217 +++
 samples/bpf/libbpf.h |  10 ++
 samples/bpf/run_cookie_uid_helper_example.sh |  14 ++
 tools/include/uapi/linux/bpf.h   |   4 +-
 9 files changed, 303 insertions(+), 3 deletions(-)
 create mode 100644 samples/bpf/cookie_uid_helper_example.c
 create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh

-- 
2.7.4



[PATCH net-next v7 3/3] A Sample of using socket cookie and uid for traffic monitoring

2017-03-21 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Add a sample program to demostrate the possible usage of
get_socket_cookie and get_socket_uid helper function. The program will
store bytes and packets counting of in/out traffic monitored by iptables
and store the stats in a bpf map in per socket base. The owner uid of
the socket will be stored as part of the data entry. A shell script for
running the program is also included.

Acked-by: Alexei Starovoitov <a...@kernel.org>
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 samples/bpf/Makefile |   3 +
 samples/bpf/cookie_uid_helper_example.c  | 217 +++
 samples/bpf/libbpf.h |  10 ++
 samples/bpf/run_cookie_uid_helper_example.sh |  14 ++
 4 files changed, 244 insertions(+)
 create mode 100644 samples/bpf/cookie_uid_helper_example.c
 create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 09e9d53..f803f51 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -34,6 +34,7 @@ hostprogs-y += sampleip
 hostprogs-y += tc_l2_redirect
 hostprogs-y += lwt_len_hist
 hostprogs-y += xdp_tx_iptunnel
+hostprogs-y += per_socket_stats_example
 
 # Libbpf dependencies
 LIBBPF := ../../tools/lib/bpf/bpf.o
@@ -72,6 +73,7 @@ sampleip-objs := bpf_load.o $(LIBBPF) sampleip_user.o
 tc_l2_redirect-objs := bpf_load.o $(LIBBPF) tc_l2_redirect_user.o
 lwt_len_hist-objs := bpf_load.o $(LIBBPF) lwt_len_hist_user.o
 xdp_tx_iptunnel-objs := bpf_load.o $(LIBBPF) xdp_tx_iptunnel_user.o
+per_socket_stats_example-objs := $(LIBBPF) cookie_uid_helper_example.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -105,6 +107,7 @@ always += trace_event_kern.o
 always += sampleip_kern.o
 always += lwt_len_hist_kern.o
 always += xdp_tx_iptunnel_kern.o
+always += cookie_uid_helper_example.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 HOSTCFLAGS += -I$(srctree)/tools/lib/
diff --git a/samples/bpf/cookie_uid_helper_example.c 
b/samples/bpf/cookie_uid_helper_example.c
new file mode 100644
index 000..f6e5e58
--- /dev/null
+++ b/samples/bpf/cookie_uid_helper_example.c
@@ -0,0 +1,217 @@
+/* This test is a demo of using get_socket_uid and get_socket_cookie
+ * helper function to do per socket based network traffic monitoring.
+ * It requires iptables version higher then 1.6.1. to load pinned eBPF
+ * program into the xt_bpf match.
+ *
+ * TEST:
+ * ./run_cookie_uid_helper_example.sh
+ * Then generate some traffic in variate ways. ping 0 -c 10 would work
+ * but the cookie and uid in this case could both be 0. A sample output
+ * with some traffic generated by web browser is shown below:
+ *
+ * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058
+ * cookie: 132, uid: 0x0, Pakcet Count: 2, Bytes Count: 286
+ * cookie: 812, uid: 0x3e8, Pakcet Count: 3, Bytes Count: 1726
+ * cookie: 802, uid: 0x3e8, Pakcet Count: 2, Bytes Count: 104
+ * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058
+ * cookie: 831, uid: 0x3e8, Pakcet Count: 2, Bytes Count: 104
+ * cookie: 0, uid: 0x0, Pakcet Count: 6, Bytes Count: 712
+ * cookie: 880, uid: 0xfffe, Pakcet Count: 1, Bytes Count: 70
+ *
+ * Clean up: if using shell script, the script file will delete the iptables
+ * rule and unmount the bpf program when exit. Else the iptables rule need
+ * to be deleted by hand, see run_cookie_uid_helper_example.sh for detail.
+ */
+
+#define _GNU_SOURCE
+
+#define offsetof(type, member) __builtin_offsetof(type, member)
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "libbpf.h"
+
+struct stats {
+   uint32_t uid;
+   uint64_t packets;
+   uint64_t bytes;
+};
+
+static int map_fd, prog_fd;
+
+static void maps_create(void)
+{
+   map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t),
+   sizeof(struct stats), 100, 0);
+   if (map_fd < 0)
+   error(1, errno, "map create failed!\n");
+}
+
+static void prog_load(void)
+{
+   static char log_buf[1 << 16];
+
+   struct bpf_insn prog[] = {
+   /*
+* Save sk_buff for future usage. value stored in R6 to R10 will
+* not be reset after a bpf helper function call.
+*/
+   BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+   /*
+* pc1: BPF_FUNC_get_socket_cookie takes one parameter,
+* R1: sk_buff
+*/
+   BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+   BPF_FUNC_get_socket_cookie),
+   /* pc2-4: save  to r7 for future usage*/
+   BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
+   BPF_MOV64_REG(BPF_REG_7, BPF

[PATCH net-next v7 0/3] net: core: Two Helper function about socket information

2017-03-21 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce two eBpf helper function to get the socket cookie and
socket uid for each packet. The helper function is useful when
the *sk field inside sk_buff is not empty. These helper functions
can be used on socket and uid based traffic monitoring programs.

Change since V6:
* change the user namespace of uid helper function back to init_user_ns
  since in some situation, for example, pinned bpf object, the current
  user namespace is not always applicable. 

Change since V5:
* Delete unnecessary blank lines in sample program.
* Refine the variable orders in get_uid helper function.

Change since V4:
* Using current user namespace to get uid instead of using init_ns.
* Add compiling setup of example program in to Makefile.
* Change the name style of the example program binaries.

Change since V3:
* Fixed some typos and incorrect comments in sample program
* replaced raw insns with BPF_STX_XADD and add it to libbpf.h
* Use a temp dir as mount point instead and added a check for
  the user input string.
* Make the get uid helper function returns the user namespace uid
  instead of kuid.
* Return a overflowuid instead of 0 when no uid information is found.

Change since V2:
* Add a sample program to demostrate the usage of the helper function.
* Moved the helper function proto invoking place.
* Add function header into tools/include
* Apply sk_to_full_sk() before getting uid.

Change since V1:
* Removed the unnecessary declarations and export command
* resolved conflict with master branch.
* Examine if the socket is a full socket before getting the uid.


Chenbo Feng (3):
  Add a helper function to get socket cookie in eBPF
  Add a eBPF helper function to retrieve socket uid
  A Sample of using socket cookie and uid for traffic monitoring

 include/linux/sock_diag.h|   1 +
 include/uapi/linux/bpf.h |  16 +-
 net/core/filter.c|  39 +
 net/core/sock_diag.c |   2 +-
 samples/bpf/Makefile |   3 +
 samples/bpf/cookie_uid_helper_example.c  | 217 +++
 samples/bpf/libbpf.h |  10 ++
 samples/bpf/run_cookie_uid_helper_example.sh |  14 ++
 tools/include/uapi/linux/bpf.h   |   4 +-
 9 files changed, 303 insertions(+), 3 deletions(-)
 create mode 100644 samples/bpf/cookie_uid_helper_example.c
 create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh

-- 
2.7.4



[PATCH net-next v7 1/3] Add a helper function to get socket cookie in eBPF

2017-03-21 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Retrieve the socket cookie generated by sock_gen_cookie() from a sk_buff
with a known socket. Generates a new cookie if one was not yet set.If
the socket pointer inside sk_buff is NULL, 0 is returned. The helper
function coud be useful in monitoring per socket networking traffic
statistics and provide a unique socket identifier per namespace.

Acked-by: Alexei Starovoitov <a...@kernel.org>
Acked-by: Daniel Borkmann <dan...@iogearbox.net>
Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/sock_diag.h  |  1 +
 include/uapi/linux/bpf.h   |  9 -
 net/core/filter.c  | 17 +
 net/core/sock_diag.c   |  2 +-
 tools/include/uapi/linux/bpf.h |  3 ++-
 5 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index a0596ca0..a2f8109 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -24,6 +24,7 @@ void sock_diag_unregister(const struct sock_diag_handler *h);
 void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct 
nlmsghdr *nlh));
 void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct 
nlmsghdr *nlh));
 
+u64 sock_gen_cookie(struct sock *sk);
 int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie);
 void sock_diag_save_cookie(struct sock *sk, __u32 *cookie);
 
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0539a0c..dc81a9f 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -456,6 +456,12 @@ union bpf_attr {
  * Return:
  *   > 0 length of the string including the trailing NUL on success
  *   < 0 error
+ *
+ * u64 bpf_bpf_get_socket_cookie(skb)
+ * Get the cookie for the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: 8 Bytes non-decreasing number on success or 0 if the socket
+ * field is missing inside sk_buff
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -503,7 +509,8 @@ union bpf_attr {
FN(get_numa_node_id),   \
FN(skb_change_head),\
FN(xdp_adjust_head),\
-   FN(probe_read_str),
+   FN(probe_read_str), \
+   FN(get_socket_cookie),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index ebaeaf2..5b65ae3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2599,6 +2600,18 @@ static const struct bpf_func_proto 
bpf_xdp_event_output_proto = {
.arg5_type  = ARG_CONST_SIZE,
 };
 
+BPF_CALL_1(bpf_get_socket_cookie, struct sk_buff *, skb)
+{
+   return skb->sk ? sock_gen_cookie(skb->sk) : 0;
+}
+
+static const struct bpf_func_proto bpf_get_socket_cookie_proto = {
+   .func   = bpf_get_socket_cookie,
+   .gpl_only   = false,
+   .ret_type   = RET_INTEGER,
+   .arg1_type  = ARG_PTR_TO_CTX,
+};
+
 static const struct bpf_func_proto *
 bpf_base_func_proto(enum bpf_func_id func_id)
 {
@@ -2633,6 +2646,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
switch (func_id) {
case BPF_FUNC_skb_load_bytes:
return _skb_load_bytes_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -2692,6 +2707,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return _get_smp_processor_id_proto;
case BPF_FUNC_skb_under_cgroup:
return _skb_under_cgroup_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
default:
return bpf_base_func_proto(func_id);
}
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 6b10573..acd2a6c 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -19,7 +19,7 @@ static int (*inet_rcv_compat)(struct sk_buff *skb, struct 
nlmsghdr *nlh);
 static DEFINE_MUTEX(sock_diag_table_mutex);
 static struct workqueue_struct *broadcast_wq;
 
-static u64 sock_gen_cookie(struct sock *sk)
+u64 sock_gen_cookie(struct sock *sk)
 {
while (1) {
u64 res = atomic64_read(>sk_cookie);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0539a0c..a94bdd3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -503,7 +503,8 @@ union bpf_attr {
FN(get_numa_node_id),   \
FN(skb_change_head),\
FN(xdp_adjust_head),\
-   FN(probe_read_str),
+   FN(probe_read_str), \
+   FN(get_socket_cookie),
 
 /* integer value in 'imm' field of BPF_CALL instru

[PATCH net-next v7 2/3] Add a eBPF helper function to retrieve socket uid

2017-03-21 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Returns the owner uid of the socket inside a sk_buff. This is useful to
perform per-UID accounting of network traffic or per-UID packet
filtering. The socket need to be a fullsock otherwise overflowuid is
returned.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/uapi/linux/bpf.h   |  9 -
 net/core/filter.c  | 22 ++
 tools/include/uapi/linux/bpf.h |  3 ++-
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index dc81a9f..ff42111 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -462,6 +462,12 @@ union bpf_attr {
  * @skb: pointer to skb
  * Return: 8 Bytes non-decreasing number on success or 0 if the socket
  * field is missing inside sk_buff
+ *
+ * u32 bpf_get_socket_uid(skb)
+ * Get the owner uid of the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: uid of the socket owner on success or 0 if the socket pointer
+ * inside sk_buff is NULL
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -510,7 +516,8 @@ union bpf_attr {
FN(skb_change_head),\
FN(xdp_adjust_head),\
FN(probe_read_str), \
-   FN(get_socket_cookie),
+   FN(get_socket_cookie),  \
+   FN(get_socket_uid),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index 5b65ae3..2f022df 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2612,6 +2612,24 @@ static const struct bpf_func_proto 
bpf_get_socket_cookie_proto = {
.arg1_type  = ARG_PTR_TO_CTX,
 };
 
+BPF_CALL_1(bpf_get_socket_uid, struct sk_buff *, skb)
+{
+   struct sock *sk = sk_to_full_sk(skb->sk);
+   kuid_t kuid;
+
+   if (!sk || !sk_fullsock(sk))
+   return overflowuid;
+   kuid = sock_net_uid(sock_net(sk), sk);
+   return from_kuid_munged(_user_ns, kuid);
+}
+
+static const struct bpf_func_proto bpf_get_socket_uid_proto = {
+   .func   = bpf_get_socket_uid,
+   .gpl_only   = false,
+   .ret_type   = RET_INTEGER,
+   .arg1_type  = ARG_PTR_TO_CTX,
+};
+
 static const struct bpf_func_proto *
 bpf_base_func_proto(enum bpf_func_id func_id)
 {
@@ -2648,6 +2666,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
return _skb_load_bytes_proto;
case BPF_FUNC_get_socket_cookie:
return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -2709,6 +2729,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return _skb_under_cgroup_proto;
case BPF_FUNC_get_socket_cookie:
return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index a94bdd3..4a2d56d 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -504,7 +504,8 @@ union bpf_attr {
FN(skb_change_head),\
FN(xdp_adjust_head),\
FN(probe_read_str), \
-   FN(get_socket_cookie),
+   FN(get_socket_cookie),  \
+   FN(get_socket_uid),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
-- 
2.7.4



[PATCH net-next v6 2/3] Add a eBPF helper function to retrieve socket uid

2017-03-20 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Returns the owner uid of the socket inside a sk_buff. This is useful to
perform per-UID accounting of network traffic or per-UID packet
filtering. The socket need to be a fullsock otherwise overflowuid is
returned.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/uapi/linux/bpf.h   |  9 -
 net/core/filter.c  | 22 ++
 tools/include/uapi/linux/bpf.h |  3 ++-
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index dc81a9f..ff42111 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -462,6 +462,12 @@ union bpf_attr {
  * @skb: pointer to skb
  * Return: 8 Bytes non-decreasing number on success or 0 if the socket
  * field is missing inside sk_buff
+ *
+ * u32 bpf_get_socket_uid(skb)
+ * Get the owner uid of the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: uid of the socket owner on success or 0 if the socket pointer
+ * inside sk_buff is NULL
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -510,7 +516,8 @@ union bpf_attr {
FN(skb_change_head),\
FN(xdp_adjust_head),\
FN(probe_read_str), \
-   FN(get_socket_cookie),
+   FN(get_socket_cookie),  \
+   FN(get_socket_uid),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index 5b65ae3..2f022df 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -2612,6 +2612,24 @@ static const struct bpf_func_proto 
bpf_get_socket_cookie_proto = {
.arg1_type  = ARG_PTR_TO_CTX,
 };
 
+BPF_CALL_1(bpf_get_socket_uid, struct sk_buff *, skb)
+{
+   struct sock *sk = sk_to_full_sk(skb->sk);
+   kuid_t kuid;
+
+   if (!sk || !sk_fullsock(sk))
+   return overflowuid;
+   kuid = sock_net_uid(sock_net(sk), sk);
+   return from_kuid_munged(current_user_ns(), kuid);
+}
+
+static const struct bpf_func_proto bpf_get_socket_uid_proto = {
+   .func   = bpf_get_socket_uid,
+   .gpl_only   = false,
+   .ret_type   = RET_INTEGER,
+   .arg1_type  = ARG_PTR_TO_CTX,
+};
+
 static const struct bpf_func_proto *
 bpf_base_func_proto(enum bpf_func_id func_id)
 {
@@ -2648,6 +2666,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
return _skb_load_bytes_proto;
case BPF_FUNC_get_socket_cookie:
return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -2709,6 +2729,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return _skb_under_cgroup_proto;
case BPF_FUNC_get_socket_cookie:
return _get_socket_cookie_proto;
+   case BPF_FUNC_get_socket_uid:
+   return _get_socket_uid_proto;
default:
return bpf_base_func_proto(func_id);
}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index a94bdd3..4a2d56d 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -504,7 +504,8 @@ union bpf_attr {
FN(skb_change_head),\
FN(xdp_adjust_head),\
FN(probe_read_str), \
-   FN(get_socket_cookie),
+   FN(get_socket_cookie),  \
+   FN(get_socket_uid),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
-- 
2.7.4



[PATCH net-next v6 1/3] Add a helper function to get socket cookie in eBPF

2017-03-20 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Retrieve the socket cookie generated by sock_gen_cookie() from a sk_buff
with a known socket. Generates a new cookie if one was not yet set.If
the socket pointer inside sk_buff is NULL, 0 is returned. The helper
function coud be useful in monitoring per socket networking traffic
statistics and provide a unique socket identifier per namespace.

Signed-off-by: Chenbo Feng <fe...@google.com>
---
 include/linux/sock_diag.h  |  1 +
 include/uapi/linux/bpf.h   |  9 -
 net/core/filter.c  | 17 +
 net/core/sock_diag.c   |  2 +-
 tools/include/uapi/linux/bpf.h |  3 ++-
 5 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index a0596ca0..a2f8109 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -24,6 +24,7 @@ void sock_diag_unregister(const struct sock_diag_handler *h);
 void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct 
nlmsghdr *nlh));
 void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct 
nlmsghdr *nlh));
 
+u64 sock_gen_cookie(struct sock *sk);
 int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie);
 void sock_diag_save_cookie(struct sock *sk, __u32 *cookie);
 
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0539a0c..dc81a9f 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -456,6 +456,12 @@ union bpf_attr {
  * Return:
  *   > 0 length of the string including the trailing NUL on success
  *   < 0 error
+ *
+ * u64 bpf_bpf_get_socket_cookie(skb)
+ * Get the cookie for the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: 8 Bytes non-decreasing number on success or 0 if the socket
+ * field is missing inside sk_buff
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -503,7 +509,8 @@ union bpf_attr {
FN(get_numa_node_id),   \
FN(skb_change_head),\
FN(xdp_adjust_head),\
-   FN(probe_read_str),
+   FN(probe_read_str), \
+   FN(get_socket_cookie),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
diff --git a/net/core/filter.c b/net/core/filter.c
index ebaeaf2..5b65ae3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2599,6 +2600,18 @@ static const struct bpf_func_proto 
bpf_xdp_event_output_proto = {
.arg5_type  = ARG_CONST_SIZE,
 };
 
+BPF_CALL_1(bpf_get_socket_cookie, struct sk_buff *, skb)
+{
+   return skb->sk ? sock_gen_cookie(skb->sk) : 0;
+}
+
+static const struct bpf_func_proto bpf_get_socket_cookie_proto = {
+   .func   = bpf_get_socket_cookie,
+   .gpl_only   = false,
+   .ret_type   = RET_INTEGER,
+   .arg1_type  = ARG_PTR_TO_CTX,
+};
+
 static const struct bpf_func_proto *
 bpf_base_func_proto(enum bpf_func_id func_id)
 {
@@ -2633,6 +2646,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)
switch (func_id) {
case BPF_FUNC_skb_load_bytes:
return _skb_load_bytes_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -2692,6 +2707,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
return _get_smp_processor_id_proto;
case BPF_FUNC_skb_under_cgroup:
return _skb_under_cgroup_proto;
+   case BPF_FUNC_get_socket_cookie:
+   return _get_socket_cookie_proto;
default:
return bpf_base_func_proto(func_id);
}
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 6b10573..acd2a6c 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -19,7 +19,7 @@ static int (*inet_rcv_compat)(struct sk_buff *skb, struct 
nlmsghdr *nlh);
 static DEFINE_MUTEX(sock_diag_table_mutex);
 static struct workqueue_struct *broadcast_wq;
 
-static u64 sock_gen_cookie(struct sock *sk)
+u64 sock_gen_cookie(struct sock *sk)
 {
while (1) {
u64 res = atomic64_read(>sk_cookie);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0539a0c..a94bdd3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -503,7 +503,8 @@ union bpf_attr {
FN(get_numa_node_id),   \
FN(skb_change_head),\
FN(xdp_adjust_head),\
-   FN(probe_read_str),
+   FN(probe_read_str), \
+   FN(get_socket_cookie),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
-- 
2.7.4



[PATCH net-next v6 0/3] net: core: Two Helper function about socket information

2017-03-20 Thread Chenbo Feng
From: Chenbo Feng <fe...@google.com>

Introduce two eBpf helper function to get the socket cookie and
socket uid for each packet. The helper function is useful when
the *sk field inside sk_buff is not empty. These helper functions
can be used on socket and uid based traffic monitoring programs.

Change since V5:
* Delete unnecessary blank lines in sample program.
* Refine the variable orders in get_uid helper function.

Change since V4:
* Using current user namespace to get uid instead of using init_ns.
* Add compiling setup of example program in to Makefile.
* Change the name style of the example program binaries.

Change since V3:
* Fixed some typos and incorrect comments in sample program
* replaced raw insns with BPF_STX_XADD and add it to libbpf.h
* Use a temp dir as mount point instead and added a check for
  the user input string.
* Make the get uid helper function returns the user namespace uid
  instead of kuid.
* Return a overflowuid instead of 0 when no uid information is found.

Change since V2:
* Add a sample program to demostrate the usage of the helper function.
* Moved the helper function proto invoking place.
* Add function header into tools/include
* Apply sk_to_full_sk() before getting uid.

Change since V1:
* Removed the unnecessary declarations and export command
* resolved conflict with master branch.
* Examine if the socket is a full socket before getting the uid.


Chenbo Feng (3):
  Add a helper function to get socket cookie in eBPF
  Add a eBPF helper function to retrieve socket uid
  A Sample of using socket cookie and uid for traffic monitoring

 include/linux/sock_diag.h|   1 +
 include/uapi/linux/bpf.h |  16 +-
 net/core/filter.c|  39 +
 net/core/sock_diag.c |   2 +-
 samples/bpf/Makefile |   3 +
 samples/bpf/cookie_uid_helper_example.c  | 217 +++
 samples/bpf/libbpf.h |  10 ++
 samples/bpf/run_cookie_uid_helper_example.sh |  14 ++
 tools/include/uapi/linux/bpf.h   |   4 +-
 9 files changed, 303 insertions(+), 3 deletions(-)
 create mode 100644 samples/bpf/cookie_uid_helper_example.c
 create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh

-- 
2.7.4



  1   2   >