[PATCH net-next v4 07/11] bpf: Use bpf_map_delete_elem() from the library

2017-02-08 Thread Mickaël Salaün
Replace bpf_map_delete() with bpf_map_delete_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  2 +-
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 10 --
 tools/testing/selftests/bpf/test_lru_map.c |  6 +++---
 tools/testing/selftests/bpf/test_maps.c| 22 +++---
 5 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index b1a1f58b99e0..eab8c6bfbf8f 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -124,7 +124,7 @@ int bpf_map_lookup_elem(int fd, const void *key, void 
*value)
return sys_bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
 }
 
-int bpf_map_delete_elem(int fd, void *key)
+int bpf_map_delete_elem(int fd, const void *key)
 {
union bpf_attr attr;
 
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 171cf594f782..f559f648db45 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -37,7 +37,7 @@ int bpf_map_update_elem(int fd, const void *key, const void 
*value,
__u64 flags);
 
 int bpf_map_lookup_elem(int fd, const void *key, void *value);
-int bpf_map_delete_elem(int fd, void *key);
+int bpf_map_delete_elem(int fd, const void *key);
 int bpf_map_get_next_key(int fd, void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
 int bpf_obj_get(const char *pathname);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 0a5a6060db70..17581a42e1d9 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,16 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_delete(int fd, const void *key)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-
-   return bpf(BPF_MAP_DELETE_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_next_key(int fd, const void *key, void *next_key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 53155009bdb6..d375fac1a49c 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -318,7 +318,7 @@ static void test_lru_sanity2(int map_type, int map_flags, 
unsigned int tgt_free)
key = 1;
if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
assert(!bpf_map_update_elem(lru_map_fd, , value, 
BPF_NOEXIST));
-   assert(!bpf_map_delete(lru_map_fd, ));
+   assert(!bpf_map_delete_elem(lru_map_fd, ));
} else {
assert(bpf_map_update_elem(lru_map_fd, , value, BPF_EXIST));
}
@@ -470,8 +470,8 @@ static void test_lru_sanity4(int map_type, int map_flags, 
unsigned int tgt_free)
}
 
for (; key <= 2 * tgt_free; key++) {
-   assert(!bpf_map_delete(lru_map_fd, ));
-   assert(bpf_map_delete(lru_map_fd, ));
+   assert(!bpf_map_delete_elem(lru_map_fd, ));
+   assert(bpf_map_delete_elem(lru_map_fd, ));
}
 
end_key = key + 2 * tgt_free;
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index c73a1fbc5bcc..ae22fdc93172 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -85,7 +85,7 @@ static void test_hashmap(int task, void *data)
 
/* Check that key = 0 doesn't exist. */
key = 0;
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
assert(bpf_map_next_key(fd, , _key) == 0 &&
@@ -97,10 +97,10 @@ static void test_hashmap(int task, void *data)
 
/* Delete both elements. */
key = 1;
-   assert(bpf_map_delete(fd, ) == 0);
+   assert(bpf_map_delete_elem(fd, ) == 0);
key = 2;
-   assert(bpf_map_delete(fd, ) == 0);
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == 0);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
key = 0;
/* Check that map is empty. */
@@ -170,7 +170,7 @@ static void test_hashmap_percpu(int task, void *data)
   errno == E2BIG);
 
/* Check that key = 0 doesn't exist. */
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
while (!bpf_map_next_key(fd, , _key)) {
@@ -192,10 +192,10 @@ static void test_has

Re: [PATCH net-next v1 7/7] bpf: Always test unprivileged programs

2017-02-06 Thread Mickaël Salaün

On 06/02/2017 17:09, Alexei Starovoitov wrote:
> On 2/5/17 3:14 PM, Mickaël Salaün wrote:
>> -if (unpriv && test->prog_type)
>> -continue;
>> +if (!test->prog_type) {
>> +if (!unpriv)
>> +set_admin(false);
>> +printf("#%d/u %s ", i, test->descr);
>> +do_test_single(test, true, , );
>> +if (!unpriv)
>> +set_admin(true);
>> +}
>>
>> -printf("#%d %s ", i, test->descr);
>> -do_test_single(test, unpriv, , );
>> +if (!unpriv) {
>> +printf("#%d/p %s ", i, test->descr);
>> +do_test_single(test, false, , );
>> +}
> 
> great idea.
> Acked-by: Alexei Starovoitov <a...@kernel.org>
> 
> as far as other patches.. we need to figure out how to avoid conflicts
> between net-next and Arnaldo's tree where Joe's patches went.

A merge between this series and Arnaldo's tree works fine. The only
dependency is between patches 6 and 7.

> 
> Mickael,
> can you see some way of splitting the patch set between trees?
> Like above test_verfier.c improvement needs to go into net-next.
> The rest can go via perf
> 
> 

OK, I'll send a first series with the patches from 1 to 5 for the perf
tree and a second series with the 6th and 7th patches (touching
tools/testing/selftests/bpf only) to net-next.



signature.asc
Description: OpenPGP digital signature


Re: [PATCH net-next v1 4/7] tools: Sync {,tools/}include/uapi/linux/bpf.h

2017-02-06 Thread Mickaël Salaün
This patch only make sense in net-next, however.

On 06/02/2017 00:14, Mickaël Salaün wrote:
> The tools version of this header is out of date; update it to the latest
> version from kernel header.
> 
> Signed-off-by: Mickaël Salaün <m...@digikod.net>
> Cc: Alexei Starovoitov <a...@fb.com>
> Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
> Cc: Daniel Borkmann <dan...@iogearbox.net>
> Cc: David S. Miller <da...@davemloft.net>
> ---
>  tools/include/uapi/linux/bpf.h | 23 ++-
>  1 file changed, 22 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> index 0eb0e87dbe9f..e07fd5a324e6 100644
> --- a/tools/include/uapi/linux/bpf.h
> +++ b/tools/include/uapi/linux/bpf.h
> @@ -63,6 +63,12 @@ struct bpf_insn {
>   __s32   imm;/* signed immediate constant */
>  };
>  
> +/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
> +struct bpf_lpm_trie_key {
> + __u32   prefixlen;  /* up to 32 for AF_INET, 128 for AF_INET6 */
> + __u8data[0];/* Arbitrary size */
> +};
> +
>  /* BPF syscall commands, see bpf(2) man-page for details. */
>  enum bpf_cmd {
>   BPF_MAP_CREATE,
> @@ -89,6 +95,7 @@ enum bpf_map_type {
>   BPF_MAP_TYPE_CGROUP_ARRAY,
>   BPF_MAP_TYPE_LRU_HASH,
>   BPF_MAP_TYPE_LRU_PERCPU_HASH,
> + BPF_MAP_TYPE_LPM_TRIE,
>  };
>  
>  enum bpf_prog_type {
> @@ -430,6 +437,18 @@ union bpf_attr {
>   * @xdp_md: pointer to xdp_md
>   * @delta: An positive/negative integer to be added to xdp_md.data
>   * Return: 0 on success or negative on error
> + *
> + * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
> + * Copy a NUL terminated string from unsafe address. In case the string
> + * length is smaller than size, the target is not padded with further NUL
> + * bytes. In case the string length is larger than size, just count-1
> + * bytes are copied and the last byte is set to NUL.
> + * @dst: destination address
> + * @size: maximum number of bytes to copy, including the trailing NUL
> + * @unsafe_ptr: unsafe address
> + * Return:
> + *   > 0 length of the string including the trailing NUL on success
> + *   < 0 error
>   */
>  #define __BPF_FUNC_MAPPER(FN)\
>   FN(unspec), \
> @@ -476,7 +495,8 @@ union bpf_attr {
>   FN(set_hash_invalid),   \
>   FN(get_numa_node_id),   \
>   FN(skb_change_head),\
> - FN(xdp_adjust_head),
> + FN(xdp_adjust_head),\
> + FN(probe_read_str),
>  
>  /* integer value in 'imm' field of BPF_CALL instruction selects which helper
>   * function eBPF program intends to call
> @@ -502,6 +522,7 @@ enum bpf_func_id {
>  /* BPF_FUNC_l4_csum_replace flags. */
>  #define BPF_F_PSEUDO_HDR (1ULL << 4)
>  #define BPF_F_MARK_MANGLED_0 (1ULL << 5)
> +#define BPF_F_MARK_ENFORCE   (1ULL << 6)
>  
>  /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
>  #define BPF_F_INGRESS(1ULL << 0)
> 



signature.asc
Description: OpenPGP digital signature


Re: [PATCH net-next v1 6/7] bpf: Use the bpf_load_program() from the library

2017-02-06 Thread Mickaël Salaün

On 06/02/2017 16:30, Daniel Borkmann wrote:
> On 02/06/2017 12:14 AM, Mickaël Salaün wrote:
>> Replace bpf_prog_load() with bpf_load_program() calls.
>>
>> Use the tools include directory instead of the installed one to allow
>> builds from other kernels.
>>
>> Signed-off-by: Mickaël Salaün <m...@digikod.net>
>> Cc: Alexei Starovoitov <a...@fb.com>
>> Cc: Daniel Borkmann <dan...@iogearbox.net>
>> Cc: Shuah Khan <sh...@kernel.org>
>> ---
>>   tools/testing/selftests/bpf/Makefile|  6 +-
>>   tools/testing/selftests/bpf/bpf_sys.h   | 21 -
>>   tools/testing/selftests/bpf/test_tag.c  |  6 --
>>   tools/testing/selftests/bpf/test_verifier.c |  8 +---
>>   4 files changed, 14 insertions(+), 27 deletions(-)
> 
> No objections, but if so, can't we add the remaining missing
> pieces to bpf lib, so we can remove bpf_sys.h altogether?
> 
> Thanks,
> Daniel
> 

OK, I'll send a new patch replacing bpf_sys.h entirely.

 Mickaël



signature.asc
Description: OpenPGP digital signature


[PATCH v2 3/5] samples/bpf: Ignore already processed ELF sections

2017-02-06 Thread Mickaël Salaün
Add a missing check for the map fixup loop.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 samples/bpf/bpf_load.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 396e204888b3..e04fe09d7c2e 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -328,6 +328,8 @@ int load_bpf_file(char *path)
 
/* load programs that need map fixup (relocations) */
for (i = 1; i < ehdr.e_shnum; i++) {
+   if (processed_sec[i])
+   continue;
 
if (get_sec(elf, i, , , , ))
continue;
-- 
2.11.0



[PATCH v2 2/5] bpf: Simplify bpf_load_program() error handling in the library

2017-02-06 Thread Mickaël Salaün
Do not call a second time bpf(2) when a program load failed.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Wang Nan <wangn...@huawei.com>
---
 tools/lib/bpf/bpf.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 3ddb58a36d3c..fda3f494f1cd 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -73,7 +73,6 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn 
*insns,
 size_t insns_cnt, char *license,
 __u32 kern_version, char *log_buf, size_t log_buf_sz)
 {
-   int fd;
union bpf_attr attr;
 
bzero(, sizeof(attr));
@@ -81,20 +80,15 @@ int bpf_load_program(enum bpf_prog_type type, struct 
bpf_insn *insns,
attr.insn_cnt = (__u32)insns_cnt;
attr.insns = ptr_to_u64(insns);
attr.license = ptr_to_u64(license);
-   attr.log_buf = ptr_to_u64(NULL);
-   attr.log_size = 0;
-   attr.log_level = 0;
+   attr.log_buf = ptr_to_u64(log_buf);
+   attr.log_size = log_buf_sz;
attr.kern_version = kern_version;
 
-   fd = sys_bpf(BPF_PROG_LOAD, , sizeof(attr));
-   if (fd >= 0 || !log_buf || !log_buf_sz)
-   return fd;
+   if (log_buf && log_buf_sz > 0) {
+   attr.log_level = 1;
+   log_buf[0] = 0;
+   }
 
-   /* Try again with log */
-   attr.log_buf = ptr_to_u64(log_buf);
-   attr.log_size = log_buf_sz;
-   attr.log_level = 1;
-   log_buf[0] = 0;
return sys_bpf(BPF_PROG_LOAD, , sizeof(attr));
 }
 
-- 
2.11.0



[PATCH v2 5/5] samples/bpf: Add missing header

2017-02-06 Thread Mickaël Salaün
Include unistd.h to define __NR_getuid and __NR_getsid.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 samples/bpf/tracex5_kern.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/samples/bpf/tracex5_kern.c b/samples/bpf/tracex5_kern.c
index fd12d7154d42..7e4cf74553ff 100644
--- a/samples/bpf/tracex5_kern.c
+++ b/samples/bpf/tracex5_kern.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include "bpf_helpers.h"
 
 #define PROG(F) SEC("kprobe/"__stringify(F)) int bpf_func_##F
-- 
2.11.0



[PATCH v2 1/5] bpf: Add missing header to the library

2017-02-06 Thread Mickaël Salaün
Include stddef.h to define size_t.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Wang Nan <wangn...@huawei.com>
---
 tools/lib/bpf/bpf.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index a2f9853dd882..df6e186da788 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -22,6 +22,7 @@
 #define __BPF_BPF_H
 
 #include 
+#include 
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
   int max_entries, __u32 map_flags);
-- 
2.11.0



[PATCH v2 4/5] samples/bpf: Reset global variables

2017-02-06 Thread Mickaël Salaün
Before loading a new ELF, clean previous kernel version, license and
processed sections.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 samples/bpf/bpf_load.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index e04fe09d7c2e..b86ee54da2d1 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -277,6 +277,11 @@ int load_bpf_file(char *path)
Elf_Data *data, *data_prog, *symbols = NULL;
char *shname, *shname_prog;
 
+   /* reset global variables */
+   kern_version = 0;
+   memset(license, 0, sizeof(license));
+   memset(processed_sec, 0, sizeof(processed_sec));
+
if (elf_version(EV_CURRENT) == EV_NONE)
return 1;
 
-- 
2.11.0



[PATCH net-next v2 2/8] bpf: Use bpf_map_update_elem() from the library

2017-02-06 Thread Mickaël Salaün
Replace bpf_map_update() with bpf_map_update_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  5 +--
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 13 --
 tools/testing/selftests/bpf/test_lpm_map.c | 15 +++
 tools/testing/selftests/bpf/test_lru_map.c | 65 +++---
 tools/testing/selftests/bpf/test_maps.c| 57 +-
 6 files changed, 73 insertions(+), 84 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index e96e2a9a7742..ea3369b50321 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -97,12 +97,11 @@ int bpf_load_program(enum bpf_prog_type type, const struct 
bpf_insn *insns,
return sys_bpf(BPF_PROG_LOAD, , sizeof(attr));
 }
 
-int bpf_map_update_elem(int fd, void *key, void *value,
+int bpf_map_update_elem(int fd, const void *key, const void *value,
__u64 flags)
 {
-   union bpf_attr attr;
+   union bpf_attr attr = {};
 
-   bzero(, sizeof(attr));
attr.map_fd = fd;
attr.key = ptr_to_u64(key);
attr.value = ptr_to_u64(value);
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index bc959a2de023..2458534c8b33 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -33,7 +33,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct 
bpf_insn *insns,
 __u32 kern_version, char *log_buf,
 size_t log_buf_sz);
 
-int bpf_map_update_elem(int fd, void *key, void *value,
+int bpf_map_update_elem(int fd, const void *key, const void *value,
__u64 flags);
 
 int bpf_map_lookup_elem(int fd, void *key, void *value);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index e7bbe3e5402e..e08dec0db9e0 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -35,19 +35,6 @@ static inline int bpf_map_lookup(int fd, const void *key, 
void *value)
return bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
 }
 
-static inline int bpf_map_update(int fd, const void *key, const void *value,
-uint64_t flags)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-   attr.value = bpf_ptr_to_u64(value);
-   attr.flags = flags;
-
-   return bpf(BPF_MAP_UPDATE_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_delete(int fd, const void *key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index 26775c00273f..e29ffbcd2932 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 
+#include 
 #include "bpf_sys.h"
 #include "bpf_util.h"
 
@@ -198,7 +199,7 @@ static void test_lpm_map(int keysize)
 
key->prefixlen = value[keysize];
memcpy(key->data, value, keysize);
-   r = bpf_map_update(map, key, value, 0);
+   r = bpf_map_update_elem(map, key, value, 0);
assert(!r);
}
 
@@ -266,32 +267,32 @@ static void test_lpm_ipaddr(void)
value = 1;
key_ipv4->prefixlen = 16;
inet_pton(AF_INET, "192.168.0.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 2;
key_ipv4->prefixlen = 24;
inet_pton(AF_INET, "192.168.0.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 3;
key_ipv4->prefixlen = 24;
inet_pton(AF_INET, "192.168.128.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 5;
key_ipv4->prefixlen = 24;
inet_pton(AF_INET, "192.168.1.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 4;
key_ipv4->prefixlen = 23;
inet_pton(AF_INET, "192.168.0.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 0xdeadbeef;
key_ipv6->prefixlen = 64;
inet_pton(AF_INET6, "2a00:1450:4001:814::200e", key_ipv6->data);
-   assert(bpf_map_upda

[PATCH net-next v2 3/8] bpf: Use bpf_map_lookup_elem() from the library

2017-02-06 Thread Mickaël Salaün
Replace bpf_map_lookup() with bpf_map_lookup_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  5 ++---
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 11 ---
 tools/testing/selftests/bpf/test_lpm_map.c | 16 
 tools/testing/selftests/bpf/test_lru_map.c | 28 ++--
 tools/testing/selftests/bpf/test_maps.c| 30 +++---
 6 files changed, 40 insertions(+), 52 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index ea3369b50321..81505801fa33 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -110,11 +110,10 @@ int bpf_map_update_elem(int fd, const void *key, const 
void *value,
return sys_bpf(BPF_MAP_UPDATE_ELEM, , sizeof(attr));
 }
 
-int bpf_map_lookup_elem(int fd, void *key, void *value)
+int bpf_map_lookup_elem(int fd, const void *key, void *value)
 {
-   union bpf_attr attr;
+   union bpf_attr attr = {};
 
-   bzero(, sizeof(attr));
attr.map_fd = fd;
attr.key = ptr_to_u64(key);
attr.value = ptr_to_u64(value);
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 2458534c8b33..171cf594f782 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -36,7 +36,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct 
bpf_insn *insns,
 int bpf_map_update_elem(int fd, const void *key, const void *value,
__u64 flags);
 
-int bpf_map_lookup_elem(int fd, void *key, void *value);
+int bpf_map_lookup_elem(int fd, const void *key, void *value);
 int bpf_map_delete_elem(int fd, void *key);
 int bpf_map_get_next_key(int fd, void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index e08dec0db9e0..0a5a6060db70 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,17 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_lookup(int fd, const void *key, void *value)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-   attr.value = bpf_ptr_to_u64(value);
-
-   return bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_delete(int fd, const void *key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index e29ffbcd2932..bd08394c26cb 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -211,7 +211,7 @@ static void test_lpm_map(int keysize)
 
key->prefixlen = 8 * keysize;
memcpy(key->data, data, keysize);
-   r = bpf_map_lookup(map, key, value);
+   r = bpf_map_lookup_elem(map, key, value);
assert(!r || errno == ENOENT);
assert(!t == !!r);
 
@@ -300,32 +300,32 @@ static void test_lpm_ipaddr(void)
 
/* Test some lookups that should come back with a value */
inet_pton(AF_INET, "192.168.128.23", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == 0);
assert(value == 3);
 
inet_pton(AF_INET, "192.168.0.1", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == 0);
assert(value == 2);
 
inet_pton(AF_INET6, "2a00:1450:4001:814::", key_ipv6->data);
-   assert(bpf_map_lookup(map_fd_ipv6, key_ipv6, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, ) == 0);
assert(value == 0xdeadbeef);
 
inet_pton(AF_INET6, "2a00:1450:4001:814::1", key_ipv6->data);
-   assert(bpf_map_lookup(map_fd_ipv6, key_ipv6, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, ) == 0);
assert(value == 0xdeadbeef);
 
/* Test some lookups that should not match any entry */
inet_pton(AF_INET, "10.0.0.1", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == -1 &&
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == -1 &&
   errno == ENOENT);
 
inet_pton(AF_INET, "11.11.11.11", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == -1 &&
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == -1 &&
   errno == ENOENT);
 
inet_pton(AF_INET6, "2a00:::", key_ipv6->data);

[PATCH net-next v2 1/8] bpf: Use bpf_load_program() from the library

2017-02-06 Thread Mickaël Salaün
Replace bpf_prog_load() with bpf_load_program() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c |  9 -
 tools/lib/bpf/bpf.h |  4 ++--
 tools/testing/selftests/bpf/Makefile|  4 +++-
 tools/testing/selftests/bpf/bpf_sys.h   | 21 -
 tools/testing/selftests/bpf/test_tag.c  |  6 --
 tools/testing/selftests/bpf/test_verifier.c |  8 +---
 6 files changed, 18 insertions(+), 34 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 3ddb58a36d3c..e96e2a9a7742 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -42,7 +42,7 @@
 # endif
 #endif
 
-static __u64 ptr_to_u64(void *ptr)
+static __u64 ptr_to_u64(const void *ptr)
 {
return (__u64) (unsigned long) ptr;
 }
@@ -69,14 +69,13 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size,
return sys_bpf(BPF_MAP_CREATE, , sizeof(attr));
 }
 
-int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
-size_t insns_cnt, char *license,
+int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
+size_t insns_cnt, const char *license,
 __u32 kern_version, char *log_buf, size_t log_buf_sz)
 {
int fd;
-   union bpf_attr attr;
+   union bpf_attr attr = {};
 
-   bzero(, sizeof(attr));
attr.prog_type = type;
attr.insn_cnt = (__u32)insns_cnt;
attr.insns = ptr_to_u64(insns);
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index a2f9853dd882..bc959a2de023 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -28,8 +28,8 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, 
int value_size,
 
 /* Recommend log buffer size */
 #define BPF_LOG_BUF_SIZE 65536
-int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
-size_t insns_cnt, char *license,
+int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
+size_t insns_cnt, const char *license,
 __u32 kern_version, char *log_buf,
 size_t log_buf_sz);
 
diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index f3d65ad53494..a35f564f66a1 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -lcap -I../../../include/uapi
+CFLAGS += -Wall -O2 -lcap -I../../../include/uapi -I../../../lib
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
@@ -7,6 +7,8 @@ TEST_FILES := $(test_objs)
 
 all: $(test_objs)
 
+$(test_objs): ../../../lib/bpf/bpf.o
+
 include ../lib.mk
 
 clean:
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 6b4565f2a3f2..e7bbe3e5402e 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -84,25 +84,4 @@ static inline int bpf_map_create(enum bpf_map_type type, 
uint32_t size_key,
return bpf(BPF_MAP_CREATE, , sizeof(attr));
 }
 
-static inline int bpf_prog_load(enum bpf_prog_type type,
-   const struct bpf_insn *insns, size_t size_insns,
-   const char *license, char *log, size_t size_log)
-{
-   union bpf_attr attr = {};
-
-   attr.prog_type = type;
-   attr.insns = bpf_ptr_to_u64(insns);
-   attr.insn_cnt = size_insns / sizeof(struct bpf_insn);
-   attr.license = bpf_ptr_to_u64(license);
-
-   if (size_log > 0) {
-   attr.log_buf = bpf_ptr_to_u64(log);
-   attr.log_size = size_log;
-   attr.log_level = 1;
-   log[0] = 0;
-   }
-
-   return bpf(BPF_PROG_LOAD, , sizeof(attr));
-}
-
 #endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_tag.c 
b/tools/testing/selftests/bpf/test_tag.c
index 5f7c602f47d1..b77dc4b03e77 100644
--- a/tools/testing/selftests/bpf/test_tag.c
+++ b/tools/testing/selftests/bpf/test_tag.c
@@ -16,6 +16,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../../../include/linux/filter.h"
 
 #include "bpf_sys.h"
@@ -55,8 +57,8 @@ static int bpf_try_load_prog(int insns, int fd_map,
int fd_prog;
 
bpf_filler(insns, fd_map);
-   fd_prog = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, prog, insns *
-   sizeof(struct bpf_insn), "", NULL, 0);
+   fd_prog = bpf_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0,
+   NULL, 0);
assert(fd_prog > 0);
if (fd_map > 0)
bpf_filler(insns, 0);
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 6a82e7db2c

[PATCH net-next v2 5/8] bpf: Use bpf_map_get_next_key() from the library

2017-02-06 Thread Mickaël Salaün
Replace bpf_map_next_key() with bpf_map_get_next_key() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  5 ++---
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 11 --
 tools/testing/selftests/bpf/test_lru_map.c |  2 +-
 tools/testing/selftests/bpf/test_maps.c| 34 +++---
 5 files changed, 21 insertions(+), 33 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index ee3a87de15ba..c7c3e2b34403 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -131,11 +131,10 @@ int bpf_map_delete_elem(int fd, const void *key)
return sys_bpf(BPF_MAP_DELETE_ELEM, , sizeof(attr));
 }
 
-int bpf_map_get_next_key(int fd, void *key, void *next_key)
+int bpf_map_get_next_key(int fd, const void *key, void *next_key)
 {
-   union bpf_attr attr;
+   union bpf_attr attr = {};
 
-   bzero(, sizeof(attr));
attr.map_fd = fd;
attr.key = ptr_to_u64(key);
attr.next_key = ptr_to_u64(next_key);
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index f559f648db45..88f07c15423a 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -38,7 +38,7 @@ int bpf_map_update_elem(int fd, const void *key, const void 
*value,
 
 int bpf_map_lookup_elem(int fd, const void *key, void *value);
 int bpf_map_delete_elem(int fd, const void *key);
-int bpf_map_get_next_key(int fd, void *key, void *next_key);
+int bpf_map_get_next_key(int fd, const void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
 int bpf_obj_get(const char *pathname);
 int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 17581a42e1d9..aeff99f0a411 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,17 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_next_key(int fd, const void *key, void *next_key)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-   attr.next_key = bpf_ptr_to_u64(next_key);
-
-   return bpf(BPF_MAP_GET_NEXT_KEY, , sizeof(attr));
-}
-
 static inline int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
 uint32_t size_value, uint32_t max_elem,
 uint32_t flags)
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index d375fac1a49c..94ecd4c58d75 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -46,7 +46,7 @@ static int map_subset(int map0, int map1)
unsigned long long value0[nr_cpus], value1[nr_cpus];
int ret;
 
-   while (!bpf_map_next_key(map1, _key, _key)) {
+   while (!bpf_map_get_next_key(map1, _key, _key)) {
assert(!bpf_map_lookup_elem(map1, _key, value1));
ret = bpf_map_lookup_elem(map0, _key, value0);
if (ret) {
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index ae22fdc93172..c96f9c9661a0 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -88,11 +88,11 @@ static void test_hashmap(int task, void *data)
assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
-   assert(bpf_map_next_key(fd, , _key) == 0 &&
+   assert(bpf_map_get_next_key(fd, , _key) == 0 &&
   (next_key == 1 || next_key == 2));
-   assert(bpf_map_next_key(fd, _key, _key) == 0 &&
+   assert(bpf_map_get_next_key(fd, _key, _key) == 0 &&
   (next_key == 1 || next_key == 2));
-   assert(bpf_map_next_key(fd, _key, _key) == -1 &&
+   assert(bpf_map_get_next_key(fd, _key, _key) == -1 &&
   errno == ENOENT);
 
/* Delete both elements. */
@@ -104,7 +104,7 @@ static void test_hashmap(int task, void *data)
 
key = 0;
/* Check that map is empty. */
-   assert(bpf_map_next_key(fd, , _key) == -1 &&
+   assert(bpf_map_get_next_key(fd, , _key) == -1 &&
   errno == ENOENT);
 
close(fd);
@@ -173,7 +173,7 @@ static void test_hashmap_percpu(int task, void *data)
assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
-   while (!bpf_map_next_key(fd, , _key)) {
+   while (!bpf_map_get_next_key(fd, , _key)) {
assert((expected_key_mask & next_key) == next_key);

[PATCH net-next v2 2/3] bpf: Change the include directory for selftest

2017-02-06 Thread Mickaël Salaün
Use the tools include directory instead of the installed one to allow
builds from other kernels.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 tools/testing/selftests/bpf/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index 769a6cb42b4b..c470c7301636 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -I../../../../usr/include
+CFLAGS += -Wall -O2 -I../../../include/uapi
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
-- 
2.11.0



[PATCH net-next v2 1/3] tools: Sync {,tools/}include/uapi/linux/bpf.h

2017-02-06 Thread Mickaël Salaün
The tools version of this header is out of date; update it to the latest
version from kernel header.

Synchronize with the following commits:
* b95a5c4db09b ("bpf: add a longest prefix match trie map implementation")
* a5e8c07059d0 ("bpf: add bpf_probe_read_str helper")
* d1b662adcdb8 ("bpf: allow option for setting bpf_l4_csum_replace from 
scratch")

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Daniel Mack <dan...@zonque.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Gianluca Borello <g.bore...@gmail.com>
---
 tools/include/uapi/linux/bpf.h | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0eb0e87dbe9f..e07fd5a324e6 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -63,6 +63,12 @@ struct bpf_insn {
__s32   imm;/* signed immediate constant */
 };
 
+/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
+struct bpf_lpm_trie_key {
+   __u32   prefixlen;  /* up to 32 for AF_INET, 128 for AF_INET6 */
+   __u8data[0];/* Arbitrary size */
+};
+
 /* BPF syscall commands, see bpf(2) man-page for details. */
 enum bpf_cmd {
BPF_MAP_CREATE,
@@ -89,6 +95,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_CGROUP_ARRAY,
BPF_MAP_TYPE_LRU_HASH,
BPF_MAP_TYPE_LRU_PERCPU_HASH,
+   BPF_MAP_TYPE_LPM_TRIE,
 };
 
 enum bpf_prog_type {
@@ -430,6 +437,18 @@ union bpf_attr {
  * @xdp_md: pointer to xdp_md
  * @delta: An positive/negative integer to be added to xdp_md.data
  * Return: 0 on success or negative on error
+ *
+ * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+ * Copy a NUL terminated string from unsafe address. In case the string
+ * length is smaller than size, the target is not padded with further NUL
+ * bytes. In case the string length is larger than size, just count-1
+ * bytes are copied and the last byte is set to NUL.
+ * @dst: destination address
+ * @size: maximum number of bytes to copy, including the trailing NUL
+ * @unsafe_ptr: unsafe address
+ * Return:
+ *   > 0 length of the string including the trailing NUL on success
+ *   < 0 error
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -476,7 +495,8 @@ union bpf_attr {
FN(set_hash_invalid),   \
FN(get_numa_node_id),   \
FN(skb_change_head),\
-   FN(xdp_adjust_head),
+   FN(xdp_adjust_head),\
+   FN(probe_read_str),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
@@ -502,6 +522,7 @@ enum bpf_func_id {
 /* BPF_FUNC_l4_csum_replace flags. */
 #define BPF_F_PSEUDO_HDR   (1ULL << 4)
 #define BPF_F_MARK_MANGLED_0   (1ULL << 5)
+#define BPF_F_MARK_ENFORCE (1ULL << 6)
 
 /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
 #define BPF_F_INGRESS  (1ULL << 0)
-- 
2.11.0



[PATCH net-next v2 3/3] bpf: Always test unprivileged programs

2017-02-06 Thread Mickaël Salaün
If selftests are run as root, then execute the unprivileged checks as
well. This switch from 240 to 364 tests.

The test numbers are suffixed with "/u" when executed as unprivileged or
with "/p" when executed as privileged.

The geteuid() check is replaced with a capability check.

Handling capabilities requires the libcap dependency.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/Makefile|  2 +-
 tools/testing/selftests/bpf/test_verifier.c | 68 ++---
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index c470c7301636..f3d65ad53494 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -I../../../include/uapi
+CFLAGS += -Wall -O2 -lcap -I../../../include/uapi
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 0d0912c7f03c..6a82e7db2c20 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 
+#include 
 #include 
 
 #include 
@@ -4496,6 +4497,55 @@ static void do_test_single(struct bpf_test *test, bool 
unpriv,
goto close_fds;
 }
 
+static bool is_admin(void)
+{
+   cap_t caps;
+   cap_flag_value_t sysadmin = CAP_CLEAR;
+   const cap_value_t cap_val = CAP_SYS_ADMIN;
+
+   if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
+   perror("cap_get_flag");
+   return false;
+   }
+   caps = cap_get_proc();
+   if (!caps) {
+   perror("cap_get_proc");
+   return false;
+   }
+   if (cap_get_flag(caps, cap_val, CAP_EFFECTIVE, ))
+   perror("cap_get_flag");
+   if (cap_free(caps))
+   perror("cap_free");
+   return (sysadmin == CAP_SET);
+}
+
+static int set_admin(bool admin)
+{
+   cap_t caps;
+   const cap_value_t cap_val = CAP_SYS_ADMIN;
+   int ret = -1;
+
+   caps = cap_get_proc();
+   if (!caps) {
+   perror("cap_get_proc");
+   return -1;
+   }
+   if (cap_set_flag(caps, CAP_EFFECTIVE, 1, _val,
+   admin ? CAP_SET : CAP_CLEAR)) {
+   perror("cap_set_flag");
+   goto out;
+   }
+   if (cap_set_proc(caps)) {
+   perror("cap_set_proc");
+   goto out;
+   }
+   ret = 0;
+out:
+   if (cap_free(caps))
+   perror("cap_free");
+   return ret;
+}
+
 static int do_test(bool unpriv, unsigned int from, unsigned int to)
 {
int i, passes = 0, errors = 0;
@@ -4506,11 +4556,19 @@ static int do_test(bool unpriv, unsigned int from, 
unsigned int to)
/* Program types that are not supported by non-root we
 * skip right away.
 */
-   if (unpriv && test->prog_type)
-   continue;
+   if (!test->prog_type) {
+   if (!unpriv)
+   set_admin(false);
+   printf("#%d/u %s ", i, test->descr);
+   do_test_single(test, true, , );
+   if (!unpriv)
+   set_admin(true);
+   }
 
-   printf("#%d %s ", i, test->descr);
-   do_test_single(test, unpriv, , );
+   if (!unpriv) {
+   printf("#%d/p %s ", i, test->descr);
+   do_test_single(test, false, , );
+   }
}
 
printf("Summary: %d PASSED, %d FAILED\n", passes, errors);
@@ -4522,7 +4580,7 @@ int main(int argc, char **argv)
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
struct rlimit rlim = { 1 << 20, 1 << 20 };
unsigned int from = 0, to = ARRAY_SIZE(tests);
-   bool unpriv = geteuid() != 0;
+   bool unpriv = !is_admin();
 
if (argc == 3) {
unsigned int l = atoi(argv[argc - 2]);
-- 
2.11.0



Re: [PATCH net-next v1 6/7] bpf: Use the bpf_load_program() from the library

2017-02-06 Thread Mickaël Salaün

On 06/02/2017 20:18, Daniel Borkmann wrote:
> On 02/06/2017 08:16 PM, Mickaël Salaün wrote:
>> On 06/02/2017 16:30, Daniel Borkmann wrote:
>>> On 02/06/2017 12:14 AM, Mickaël Salaün wrote:
>>>> Replace bpf_prog_load() with bpf_load_program() calls.
>>>>
>>>> Use the tools include directory instead of the installed one to allow
>>>> builds from other kernels.
>>>>
>>>> Signed-off-by: Mickaël Salaün <m...@digikod.net>
>>>> Cc: Alexei Starovoitov <a...@fb.com>
>>>> Cc: Daniel Borkmann <dan...@iogearbox.net>
>>>> Cc: Shuah Khan <sh...@kernel.org>
>>>> ---
>>>>tools/testing/selftests/bpf/Makefile|  6 +-
>>>>tools/testing/selftests/bpf/bpf_sys.h   | 21
>>>> -
>>>>tools/testing/selftests/bpf/test_tag.c  |  6 --
>>>>tools/testing/selftests/bpf/test_verifier.c |  8 +---
>>>>4 files changed, 14 insertions(+), 27 deletions(-)
>>>
>>> No objections, but if so, can't we add the remaining missing
>>> pieces to bpf lib, so we can remove bpf_sys.h altogether?
>>
>> OK, I'll send a new patch replacing bpf_sys.h entirely.
> 
> Sounds great, thanks!
> 

Do you prefer a big patch or one for each replaced function?



signature.asc
Description: OpenPGP digital signature


Re: [PATCH net-next v1 6/7] bpf: Use the bpf_load_program() from the library

2017-02-06 Thread Mickaël Salaün


On 06/02/2017 23:44, Daniel Borkmann wrote:
> On 02/06/2017 10:30 PM, Mickaël Salaün wrote:
>> On 06/02/2017 20:18, Daniel Borkmann wrote:
>>> On 02/06/2017 08:16 PM, Mickaël Salaün wrote:
>>>> On 06/02/2017 16:30, Daniel Borkmann wrote:
>>>>> On 02/06/2017 12:14 AM, Mickaël Salaün wrote:
>>>>>> Replace bpf_prog_load() with bpf_load_program() calls.
>>>>>>
>>>>>> Use the tools include directory instead of the installed one to allow
>>>>>> builds from other kernels.
>>>>>>
>>>>>> Signed-off-by: Mickaël Salaün <m...@digikod.net>
>>>>>> Cc: Alexei Starovoitov <a...@fb.com>
>>>>>> Cc: Daniel Borkmann <dan...@iogearbox.net>
>>>>>> Cc: Shuah Khan <sh...@kernel.org>
>>>>>> ---
>>>>>> tools/testing/selftests/bpf/Makefile|  6 +-
>>>>>> tools/testing/selftests/bpf/bpf_sys.h   | 21
>>>>>> -
>>>>>> tools/testing/selftests/bpf/test_tag.c  |  6 --
>>>>>> tools/testing/selftests/bpf/test_verifier.c |  8 +---
>>>>>> 4 files changed, 14 insertions(+), 27 deletions(-)
>>>>>
>>>>> No objections, but if so, can't we add the remaining missing
>>>>> pieces to bpf lib, so we can remove bpf_sys.h altogether?
>>>>
>>>> OK, I'll send a new patch replacing bpf_sys.h entirely.
>>>
>>> Sounds great, thanks!
>>
>> Do you prefer a big patch or one for each replaced function?
> 
> I think it makes sense to split it into two: i) this patch as-is
> for the prog part, and ii) rest for maps.
> 

Hum, I already split them to ease the review. I'm going to send this
series now.



signature.asc
Description: OpenPGP digital signature


[PATCH net-next v2 6/8] bpf: Use bpf_create_map() from the library

2017-02-06 Thread Mickaël Salaün
Replace bpf_map_create() with bpf_create_map() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/bpf_sys.h   | 15 ---
 tools/testing/selftests/bpf/test_lpm_map.c  |  6 +++---
 tools/testing/selftests/bpf/test_lru_map.c  |  4 ++--
 tools/testing/selftests/bpf/test_maps.c | 14 +++---
 tools/testing/selftests/bpf/test_tag.c  |  2 +-
 tools/testing/selftests/bpf/test_verifier.c |  4 ++--
 6 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index aeff99f0a411..aa076a8a07f7 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,19 +24,4 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
-uint32_t size_value, uint32_t max_elem,
-uint32_t flags)
-{
-   union bpf_attr attr = {};
-
-   attr.map_type = type;
-   attr.key_size = size_key;
-   attr.value_size = size_value;
-   attr.max_entries = max_elem;
-   attr.map_flags = flags;
-
-   return bpf(BPF_MAP_CREATE, , sizeof(attr));
-}
-
 #endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index bd08394c26cb..3cc812cac2d7 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -183,7 +183,7 @@ static void test_lpm_map(int keysize)
key = alloca(sizeof(*key) + keysize);
memset(key, 0, sizeof(*key) + keysize);
 
-   map = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE,
+   map = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE,
 sizeof(*key) + keysize,
 keysize + 1,
 4096,
@@ -253,12 +253,12 @@ static void test_lpm_ipaddr(void)
key_ipv4 = alloca(key_size_ipv4);
key_ipv6 = alloca(key_size_ipv6);
 
-   map_fd_ipv4 = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE,
+   map_fd_ipv4 = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE,
 key_size_ipv4, sizeof(value),
 100, BPF_F_NO_PREALLOC);
assert(map_fd_ipv4 >= 0);
 
-   map_fd_ipv6 = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE,
+   map_fd_ipv6 = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE,
 key_size_ipv6, sizeof(value),
 100, BPF_F_NO_PREALLOC);
assert(map_fd_ipv6 >= 0);
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 94ecd4c58d75..20fa3df20a01 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -31,11 +31,11 @@ static int create_map(int map_type, int map_flags, unsigned 
int size)
 {
int map_fd;
 
-   map_fd = bpf_map_create(map_type, sizeof(unsigned long long),
+   map_fd = bpf_create_map(map_type, sizeof(unsigned long long),
sizeof(unsigned long long), size, map_flags);
 
if (map_fd == -1)
-   perror("bpf_map_create");
+   perror("bpf_create_map");
 
return map_fd;
 }
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index c96f9c9661a0..050a5205c78d 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -32,7 +32,7 @@ static void test_hashmap(int task, void *data)
long long key, next_key, value;
int fd;
 
-   fd = bpf_map_create(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
2, map_flags);
if (fd < 0) {
printf("Failed to create hashmap '%s'!\n", strerror(errno));
@@ -118,7 +118,7 @@ static void test_hashmap_percpu(int task, void *data)
int expected_key_mask = 0;
int fd, i;
 
-   fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
+   fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
sizeof(value[0]), 2, map_flags);
if (fd < 0) {
printf("Failed to create hashmap '%s'!\n", strerror(errno));
@@ -210,7 +210,7 @@ static void test_arraymap(int task, void *data)
int key, next_key, fd;
long long value;
 
-   fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
+   fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
2, 0);
if (fd < 0) {
   

[PATCH net-next v2 8/8] bpf: Add test_tag to .gitignore

2017-02-06 Thread Mickaël Salaün
Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/.gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/testing/selftests/bpf/.gitignore 
b/tools/testing/selftests/bpf/.gitignore
index d3b1c9bca407..541d9d7fad5a 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -2,3 +2,4 @@ test_verifier
 test_maps
 test_lru_map
 test_lpm_map
+test_tag
-- 
2.11.0



[PATCH net-next v2 4/8] bpf: Use bpf_map_delete_elem() from the library

2017-02-06 Thread Mickaël Salaün
Replace bpf_map_delete() with bpf_map_delete_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  5 ++---
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 10 --
 tools/testing/selftests/bpf/test_lru_map.c |  6 +++---
 tools/testing/selftests/bpf/test_maps.c| 22 +++---
 5 files changed, 17 insertions(+), 28 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 81505801fa33..ee3a87de15ba 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -121,11 +121,10 @@ int bpf_map_lookup_elem(int fd, const void *key, void 
*value)
return sys_bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
 }
 
-int bpf_map_delete_elem(int fd, void *key)
+int bpf_map_delete_elem(int fd, const void *key)
 {
-   union bpf_attr attr;
+   union bpf_attr attr = {};
 
-   bzero(, sizeof(attr));
attr.map_fd = fd;
attr.key = ptr_to_u64(key);
 
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 171cf594f782..f559f648db45 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -37,7 +37,7 @@ int bpf_map_update_elem(int fd, const void *key, const void 
*value,
__u64 flags);
 
 int bpf_map_lookup_elem(int fd, const void *key, void *value);
-int bpf_map_delete_elem(int fd, void *key);
+int bpf_map_delete_elem(int fd, const void *key);
 int bpf_map_get_next_key(int fd, void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
 int bpf_obj_get(const char *pathname);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 0a5a6060db70..17581a42e1d9 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,16 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_delete(int fd, const void *key)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-
-   return bpf(BPF_MAP_DELETE_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_next_key(int fd, const void *key, void *next_key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 53155009bdb6..d375fac1a49c 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -318,7 +318,7 @@ static void test_lru_sanity2(int map_type, int map_flags, 
unsigned int tgt_free)
key = 1;
if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
assert(!bpf_map_update_elem(lru_map_fd, , value, 
BPF_NOEXIST));
-   assert(!bpf_map_delete(lru_map_fd, ));
+   assert(!bpf_map_delete_elem(lru_map_fd, ));
} else {
assert(bpf_map_update_elem(lru_map_fd, , value, BPF_EXIST));
}
@@ -470,8 +470,8 @@ static void test_lru_sanity4(int map_type, int map_flags, 
unsigned int tgt_free)
}
 
for (; key <= 2 * tgt_free; key++) {
-   assert(!bpf_map_delete(lru_map_fd, ));
-   assert(bpf_map_delete(lru_map_fd, ));
+   assert(!bpf_map_delete_elem(lru_map_fd, ));
+   assert(bpf_map_delete_elem(lru_map_fd, ));
}
 
end_key = key + 2 * tgt_free;
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index c73a1fbc5bcc..ae22fdc93172 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -85,7 +85,7 @@ static void test_hashmap(int task, void *data)
 
/* Check that key = 0 doesn't exist. */
key = 0;
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
assert(bpf_map_next_key(fd, , _key) == 0 &&
@@ -97,10 +97,10 @@ static void test_hashmap(int task, void *data)
 
/* Delete both elements. */
key = 1;
-   assert(bpf_map_delete(fd, ) == 0);
+   assert(bpf_map_delete_elem(fd, ) == 0);
key = 2;
-   assert(bpf_map_delete(fd, ) == 0);
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == 0);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
key = 0;
/* Check that map is empty. */
@@ -170,7 +170,7 @@ static void test_hashmap_percpu(int task, void *data)
   errno == E2BIG);
 
/* Check that key = 0 doesn't exist. */
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOE

[PATCH net-next v2 7/8] bpf: Remove bpf_sys.h from selftests

2017-02-06 Thread Mickaël Salaün
Add require dependency headers.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c |  6 ++
 tools/testing/selftests/bpf/bpf_sys.h   | 27 ---
 tools/testing/selftests/bpf/test_lpm_map.c  |  1 -
 tools/testing/selftests/bpf/test_lru_map.c  |  1 -
 tools/testing/selftests/bpf/test_maps.c |  1 -
 tools/testing/selftests/bpf/test_tag.c  |  3 +--
 tools/testing/selftests/bpf/test_verifier.c |  3 +--
 7 files changed, 8 insertions(+), 34 deletions(-)
 delete mode 100644 tools/testing/selftests/bpf/bpf_sys.h

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index c7c3e2b34403..06a7d4ed1e11 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -50,7 +50,13 @@ static __u64 ptr_to_u64(const void *ptr)
 static int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
   unsigned int size)
 {
+#ifdef __NR_bpf
return syscall(__NR_bpf, cmd, attr, size);
+#else
+   fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
+   errno = ENOSYS;
+   return -1;
+#endif
 }
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size,
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
deleted file mode 100644
index aa076a8a07f7..
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __BPF_SYS__
-#define __BPF_SYS__
-
-#include 
-#include 
-
-#include 
-
-#include 
-
-static inline __u64 bpf_ptr_to_u64(const void *ptr)
-{
-   return (__u64)(unsigned long) ptr;
-}
-
-static inline int bpf(int cmd, union bpf_attr *attr, unsigned int size)
-{
-#ifdef __NR_bpf
-   return syscall(__NR_bpf, cmd, attr, size);
-#else
-   fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
-   errno = ENOSYS;
-   return -1;
-#endif
-}
-
-#endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index 3cc812cac2d7..e97565243d59 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -23,7 +23,6 @@
 #include 
 
 #include 
-#include "bpf_sys.h"
 #include "bpf_util.h"
 
 struct tlpm_node {
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 20fa3df20a01..5d9790ee14fb 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -19,7 +19,6 @@
 #include 
 
 #include 
-#include "bpf_sys.h"
 #include "bpf_util.h"
 
 #define LOCAL_FREE_TARGET  (128)
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index 050a5205c78d..a0090016372e 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -22,7 +22,6 @@
 #include 
 
 #include 
-#include "bpf_sys.h"
 #include "bpf_util.h"
 
 static int map_flags;
diff --git a/tools/testing/selftests/bpf/test_tag.c 
b/tools/testing/selftests/bpf/test_tag.c
index a76d695ab56e..4c7a1cc73f6c 100644
--- a/tools/testing/selftests/bpf/test_tag.c
+++ b/tools/testing/selftests/bpf/test_tag.c
@@ -1,5 +1,6 @@
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -20,8 +21,6 @@
 
 #include "../../../include/linux/filter.h"
 
-#include "bpf_sys.h"
-
 static struct bpf_insn prog[BPF_MAXINSNS];
 
 static void bpf_gen_imm_prog(unsigned int insns, int fd_map)
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 1e3cae650474..24d64e5fec50 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -9,6 +9,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -28,8 +29,6 @@
 
 #include "../../../include/linux/filter.h"
 
-#include "bpf_sys.h"
-
 #ifndef ARRAY_SIZE
 # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #endif
-- 
2.11.0



Re: [PATCH net-next v2 1/8] bpf: Use bpf_load_program() from the library

2017-02-07 Thread Mickaël Salaün
Right, it was a batch of miscellaneous patches at first but I split them
in three series. I'm going to resend this patches in two v3 series (with
cover letters): one for each tree (net-next and perf).

Thanks,
 Mickaël

On 07/02/2017 19:35, David Miller wrote:
> 
> Please post your patch series(s) with proper "[PATCH ... 0/N]" header 
> postings.
> 
> Thank you.
> 



signature.asc
Description: OpenPGP digital signature


[PATCH net-next v1 1/7] bpf: Add missing header to the library

2017-02-05 Thread Mickaël Salaün
Including stddef.h is needed to define size_t.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Wang Nan <wangn...@huawei.com>
---
 tools/lib/bpf/bpf.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index a2f9853dd882..df6e186da788 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -22,6 +22,7 @@
 #define __BPF_BPF_H
 
 #include 
+#include 
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
   int max_entries, __u32 map_flags);
-- 
2.11.0



[PATCH net-next v1 7/7] bpf: Always test unprivileged programs

2017-02-05 Thread Mickaël Salaün
If selftests are run as root, then execute the unprivileged checks as
well. This switch from 240 to 364 tests.

The test numbers are suffixed with "/u" when executed as unprivileged or
with "/p" when executed as privileged.

The geteuid() check is replaced with a capability check.

Handling capabilities require the libcap dependency.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/Makefile|  2 +-
 tools/testing/selftests/bpf/test_verifier.c | 68 ++---
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index 712861492278..30bb40261692 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -I../../../include/uapi -I../../../lib
+CFLAGS += -Wall -O2 -lcap -I../../../include/uapi -I../../../lib
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 04a549e54f61..aa42aef22b85 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 
+#include 
 #include 
 
 #include 
@@ -4498,6 +4499,55 @@ static void do_test_single(struct bpf_test *test, bool 
unpriv,
goto close_fds;
 }
 
+static bool is_admin(void)
+{
+   cap_t caps;
+   cap_flag_value_t sysadmin = CAP_CLEAR;
+   const cap_value_t cap_val = CAP_SYS_ADMIN;
+
+   if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
+   perror("cap_get_flag");
+   return false;
+   }
+   caps = cap_get_proc();
+   if (!caps) {
+   perror("cap_get_proc");
+   return false;
+   }
+   if (cap_get_flag(caps, cap_val, CAP_EFFECTIVE, ))
+   perror("cap_get_flag");
+   if (cap_free(caps) == -1)
+   perror("cap_free");
+   return (sysadmin == CAP_SET);
+}
+
+static int set_admin(bool admin)
+{
+   cap_t caps;
+   const cap_value_t cap_val = CAP_SYS_ADMIN;
+   int ret = -1;
+
+   caps = cap_get_proc();
+   if (!caps) {
+   perror("cap_get_proc");
+   return -1;
+   }
+   if (cap_set_flag(caps, CAP_EFFECTIVE, 1, _val,
+   admin ? CAP_SET : CAP_CLEAR)) {
+   perror("cap_set_flag");
+   goto out;
+   }
+   if (cap_set_proc(caps)) {
+   perror("cap_set_proc");
+   goto out;
+   }
+   ret = 0;
+out:
+   if (cap_free(caps) == -1)
+   perror("cap_free");
+   return ret;
+}
+
 static int do_test(bool unpriv, unsigned int from, unsigned int to)
 {
int i, passes = 0, errors = 0;
@@ -4508,11 +4558,19 @@ static int do_test(bool unpriv, unsigned int from, 
unsigned int to)
/* Program types that are not supported by non-root we
 * skip right away.
 */
-   if (unpriv && test->prog_type)
-   continue;
+   if (!test->prog_type) {
+   if (!unpriv)
+   set_admin(false);
+   printf("#%d/u %s ", i, test->descr);
+   do_test_single(test, true, , );
+   if (!unpriv)
+   set_admin(true);
+   }
 
-   printf("#%d %s ", i, test->descr);
-   do_test_single(test, unpriv, , );
+   if (!unpriv) {
+   printf("#%d/p %s ", i, test->descr);
+   do_test_single(test, false, , );
+   }
}
 
printf("Summary: %d PASSED, %d FAILED\n", passes, errors);
@@ -4524,7 +4582,7 @@ int main(int argc, char **argv)
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
struct rlimit rlim = { 1 << 20, 1 << 20 };
unsigned int from = 0, to = ARRAY_SIZE(tests);
-   bool unpriv = geteuid() != 0;
+   bool unpriv = !is_admin();
 
if (argc == 3) {
unsigned int l = atoi(argv[argc - 2]);
-- 
2.11.0



[PATCH net-next v1 5/7] bpf: Simplify bpf_load_program() error handling in the library

2017-02-05 Thread Mickaël Salaün
Do not call a second time bpf(2) when a program load failed.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Wang Nan <wangn...@huawei.com>
---
 tools/lib/bpf/bpf.c | 18 ++
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 3ddb58a36d3c..fda3f494f1cd 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -73,7 +73,6 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn 
*insns,
 size_t insns_cnt, char *license,
 __u32 kern_version, char *log_buf, size_t log_buf_sz)
 {
-   int fd;
union bpf_attr attr;
 
bzero(, sizeof(attr));
@@ -81,20 +80,15 @@ int bpf_load_program(enum bpf_prog_type type, struct 
bpf_insn *insns,
attr.insn_cnt = (__u32)insns_cnt;
attr.insns = ptr_to_u64(insns);
attr.license = ptr_to_u64(license);
-   attr.log_buf = ptr_to_u64(NULL);
-   attr.log_size = 0;
-   attr.log_level = 0;
+   attr.log_buf = ptr_to_u64(log_buf);
+   attr.log_size = log_buf_sz;
attr.kern_version = kern_version;
 
-   fd = sys_bpf(BPF_PROG_LOAD, , sizeof(attr));
-   if (fd >= 0 || !log_buf || !log_buf_sz)
-   return fd;
+   if (log_buf && log_buf_sz > 0) {
+   attr.log_level = 1;
+   log_buf[0] = 0;
+   }
 
-   /* Try again with log */
-   attr.log_buf = ptr_to_u64(log_buf);
-   attr.log_size = log_buf_sz;
-   attr.log_level = 1;
-   log_buf[0] = 0;
return sys_bpf(BPF_PROG_LOAD, , sizeof(attr));
 }
 
-- 
2.11.0



[PATCH net-next v1 2/7] samples/bpf: Ignore already processed ELF sections

2017-02-05 Thread Mickaël Salaün
Add a missing check for the map fixup loop.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 samples/bpf/bpf_load.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 396e204888b3..e04fe09d7c2e 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -328,6 +328,8 @@ int load_bpf_file(char *path)
 
/* load programs that need map fixup (relocations) */
for (i = 1; i < ehdr.e_shnum; i++) {
+   if (processed_sec[i])
+   continue;
 
if (get_sec(elf, i, , , , ))
continue;
-- 
2.11.0



[PATCH net-next v1 6/7] bpf: Use the bpf_load_program() from the library

2017-02-05 Thread Mickaël Salaün
Replace bpf_prog_load() with bpf_load_program() calls.

Use the tools include directory instead of the installed one to allow
builds from other kernels.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/Makefile|  6 +-
 tools/testing/selftests/bpf/bpf_sys.h   | 21 -
 tools/testing/selftests/bpf/test_tag.c  |  6 --
 tools/testing/selftests/bpf/test_verifier.c |  8 +---
 4 files changed, 14 insertions(+), 27 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index 769a6cb42b4b..712861492278 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,12 +1,16 @@
-CFLAGS += -Wall -O2 -I../../../../usr/include
+CFLAGS += -Wall -O2 -I../../../include/uapi -I../../../lib
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
 TEST_PROGS := $(test_objs) test_kmod.sh
 TEST_FILES := $(test_objs)
+LIBBPF := ../../../lib/bpf/bpf.o
 
 all: $(test_objs)
 
+test_verifier: $(LIBBPF)
+test_tag: $(LIBBPF)
+
 include ../lib.mk
 
 clean:
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 6b4565f2a3f2..e7bbe3e5402e 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -84,25 +84,4 @@ static inline int bpf_map_create(enum bpf_map_type type, 
uint32_t size_key,
return bpf(BPF_MAP_CREATE, , sizeof(attr));
 }
 
-static inline int bpf_prog_load(enum bpf_prog_type type,
-   const struct bpf_insn *insns, size_t size_insns,
-   const char *license, char *log, size_t size_log)
-{
-   union bpf_attr attr = {};
-
-   attr.prog_type = type;
-   attr.insns = bpf_ptr_to_u64(insns);
-   attr.insn_cnt = size_insns / sizeof(struct bpf_insn);
-   attr.license = bpf_ptr_to_u64(license);
-
-   if (size_log > 0) {
-   attr.log_buf = bpf_ptr_to_u64(log);
-   attr.log_size = size_log;
-   attr.log_level = 1;
-   log[0] = 0;
-   }
-
-   return bpf(BPF_PROG_LOAD, , sizeof(attr));
-}
-
 #endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_tag.c 
b/tools/testing/selftests/bpf/test_tag.c
index 5f7c602f47d1..b77dc4b03e77 100644
--- a/tools/testing/selftests/bpf/test_tag.c
+++ b/tools/testing/selftests/bpf/test_tag.c
@@ -16,6 +16,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../../../include/linux/filter.h"
 
 #include "bpf_sys.h"
@@ -55,8 +57,8 @@ static int bpf_try_load_prog(int insns, int fd_map,
int fd_prog;
 
bpf_filler(insns, fd_map);
-   fd_prog = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, prog, insns *
-   sizeof(struct bpf_insn), "", NULL, 0);
+   fd_prog = bpf_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0,
+   NULL, 0);
assert(fd_prog > 0);
if (fd_map > 0)
bpf_filler(insns, 0);
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 0d0912c7f03c..04a549e54f61 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -23,6 +23,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../../../include/linux/filter.h"
 
 #include "bpf_sys.h"
@@ -4456,9 +4458,9 @@ static void do_test_single(struct bpf_test *test, bool 
unpriv,
 
do_test_fixup(test, prog, _f1, _f2, _f3);
 
-   fd_prog = bpf_prog_load(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
-   prog, prog_len * sizeof(struct bpf_insn),
-   "GPL", bpf_vlog, sizeof(bpf_vlog));
+   fd_prog = bpf_load_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
+   prog, prog_len, "GPL", 0, bpf_vlog,
+   sizeof(bpf_vlog));
 
expected_ret = unpriv && test->result_unpriv != UNDEF ?
   test->result_unpriv : test->result;
-- 
2.11.0



[PATCH net-next v1 4/7] tools: Sync {,tools/}include/uapi/linux/bpf.h

2017-02-05 Thread Mickaël Salaün
The tools version of this header is out of date; update it to the latest
version from kernel header.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 tools/include/uapi/linux/bpf.h | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0eb0e87dbe9f..e07fd5a324e6 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -63,6 +63,12 @@ struct bpf_insn {
__s32   imm;/* signed immediate constant */
 };
 
+/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
+struct bpf_lpm_trie_key {
+   __u32   prefixlen;  /* up to 32 for AF_INET, 128 for AF_INET6 */
+   __u8data[0];/* Arbitrary size */
+};
+
 /* BPF syscall commands, see bpf(2) man-page for details. */
 enum bpf_cmd {
BPF_MAP_CREATE,
@@ -89,6 +95,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_CGROUP_ARRAY,
BPF_MAP_TYPE_LRU_HASH,
BPF_MAP_TYPE_LRU_PERCPU_HASH,
+   BPF_MAP_TYPE_LPM_TRIE,
 };
 
 enum bpf_prog_type {
@@ -430,6 +437,18 @@ union bpf_attr {
  * @xdp_md: pointer to xdp_md
  * @delta: An positive/negative integer to be added to xdp_md.data
  * Return: 0 on success or negative on error
+ *
+ * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+ * Copy a NUL terminated string from unsafe address. In case the string
+ * length is smaller than size, the target is not padded with further NUL
+ * bytes. In case the string length is larger than size, just count-1
+ * bytes are copied and the last byte is set to NUL.
+ * @dst: destination address
+ * @size: maximum number of bytes to copy, including the trailing NUL
+ * @unsafe_ptr: unsafe address
+ * Return:
+ *   > 0 length of the string including the trailing NUL on success
+ *   < 0 error
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -476,7 +495,8 @@ union bpf_attr {
FN(set_hash_invalid),   \
FN(get_numa_node_id),   \
FN(skb_change_head),\
-   FN(xdp_adjust_head),
+   FN(xdp_adjust_head),\
+   FN(probe_read_str),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
@@ -502,6 +522,7 @@ enum bpf_func_id {
 /* BPF_FUNC_l4_csum_replace flags. */
 #define BPF_F_PSEUDO_HDR   (1ULL << 4)
 #define BPF_F_MARK_MANGLED_0   (1ULL << 5)
+#define BPF_F_MARK_ENFORCE (1ULL << 6)
 
 /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
 #define BPF_F_INGRESS  (1ULL << 0)
-- 
2.11.0



[PATCH net-next v1 3/7] samples/bpf: Reset global variables

2017-02-05 Thread Mickaël Salaün
Before loading a new ELF, clean previous kernel version, license and
processed sections.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 samples/bpf/bpf_load.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index e04fe09d7c2e..b86ee54da2d1 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -277,6 +277,11 @@ int load_bpf_file(char *path)
Elf_Data *data, *data_prog, *symbols = NULL;
char *shname, *shname_prog;
 
+   /* reset global variables */
+   kern_version = 0;
+   memset(license, 0, sizeof(license));
+   memset(processed_sec, 0, sizeof(processed_sec));
+
if (elf_version(EV_CURRENT) == EV_NONE)
return 1;
 
-- 
2.11.0



[PATCH v5 08/10] seccomp: Enhance test_harness with an assert step mechanism

2017-02-21 Thread Mickaël Salaün
This is useful to return an information about the error without being
able to write to TH_LOG_STREAM.

Helpers from test_harness.h may be useful outside of the seccomp
directory.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Arnaldo Carvalho de Melo <a...@kernel.org>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Shuah Khan <sh...@kernel.org>
Cc: Will Drewry <w...@chromium.org>
---
 tools/testing/selftests/seccomp/test_harness.h | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/seccomp/test_harness.h 
b/tools/testing/selftests/seccomp/test_harness.h
index a786c69c7584..77e407663e06 100644
--- a/tools/testing/selftests/seccomp/test_harness.h
+++ b/tools/testing/selftests/seccomp/test_harness.h
@@ -397,7 +397,7 @@ struct __test_metadata {
const char *name;
void (*fn)(struct __test_metadata *);
int termsig;
-   int passed;
+   __s8 passed;
int trigger; /* extra handler after the evaluation */
struct __test_metadata *prev, *next;
 };
@@ -476,6 +476,12 @@ void __run_test(struct __test_metadata *t)
"instead of by signal (code: %d)\n",
t->name,
WEXITSTATUS(status));
+   } else if (t->passed < 0) {
+   fprintf(TH_LOG_STREAM,
+   "%s: Failed at step #%d\n",
+   t->name,
+   t->passed * -1);
+   t->passed = 0;
}
} else if (WIFSIGNALED(status)) {
t->passed = 0;
-- 
2.11.0



[PATCH v5 05/10] seccomp: Split put_seccomp_filter() with put_seccomp()

2017-02-21 Thread Mickaël Salaün
The semantic is unchanged. This will be useful for the Landlock
integration with seccomp (next commit).

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
---
 include/linux/seccomp.h |  4 ++--
 kernel/fork.c   |  2 +-
 kernel/seccomp.c| 18 +-
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index ecc296c137cd..e25aee2cdfc0 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -77,10 +77,10 @@ static inline int seccomp_mode(struct seccomp *s)
 #endif /* CONFIG_SECCOMP */
 
 #ifdef CONFIG_SECCOMP_FILTER
-extern void put_seccomp_filter(struct task_struct *tsk);
+extern void put_seccomp(struct task_struct *tsk);
 extern void get_seccomp_filter(struct task_struct *tsk);
 #else  /* CONFIG_SECCOMP_FILTER */
-static inline void put_seccomp_filter(struct task_struct *tsk)
+static inline void put_seccomp(struct task_struct *tsk)
 {
return;
 }
diff --git a/kernel/fork.c b/kernel/fork.c
index 11c5c8ab827c..a4f0d0e8aeb2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -352,7 +352,7 @@ void free_task(struct task_struct *tsk)
 #endif
rt_mutex_debug_task_free(tsk);
ftrace_graph_exit_task(tsk);
-   put_seccomp_filter(tsk);
+   put_seccomp(tsk);
arch_release_task_struct(tsk);
if (tsk->flags & PF_KTHREAD)
free_kthread_struct(tsk);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index f7ce79a46050..06f2f3ee454c 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -62,6 +62,8 @@ struct seccomp_filter {
 /* Limit any path through the tree to 256KB worth of instructions. */
 #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
 
+static void put_seccomp_filter(struct seccomp_filter *filter);
+
 /*
  * Endianness is explicitly ignored and left for BPF program authors to manage
  * as per the specific architecture.
@@ -312,7 +314,7 @@ static inline void seccomp_sync_threads(void)
 * current's path will hold a reference.  (This also
 * allows a put before the assignment.)
 */
-   put_seccomp_filter(thread);
+   put_seccomp_filter(thread->seccomp.filter);
smp_store_release(>seccomp.filter,
  caller->seccomp.filter);
 
@@ -474,10 +476,11 @@ static inline void seccomp_filter_free(struct 
seccomp_filter *filter)
}
 }
 
-/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
-void put_seccomp_filter(struct task_struct *tsk)
+/* put_seccomp_filter - decrements the ref count of a filter */
+static void put_seccomp_filter(struct seccomp_filter *filter)
 {
-   struct seccomp_filter *orig = tsk->seccomp.filter;
+   struct seccomp_filter *orig = filter;
+
/* Clean up single-reference branches iteratively. */
while (orig && atomic_dec_and_test(>usage)) {
struct seccomp_filter *freeme = orig;
@@ -486,6 +489,11 @@ void put_seccomp_filter(struct task_struct *tsk)
}
 }
 
+void put_seccomp(struct task_struct *tsk)
+{
+   put_seccomp_filter(tsk->seccomp.filter);
+}
+
 /**
  * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
  * @syscall: syscall number to send to userland
@@ -897,7 +905,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned 
long filter_off,
if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
ret = -EFAULT;
 
-   put_seccomp_filter(task);
+   put_seccomp_filter(task->seccomp.filter);
return ret;
 
 out:
-- 
2.11.0



[PATCH v5 03/10] bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()

2017-02-21 Thread Mickaël Salaün
Add an eBPF function bpf_handle_fs_get_mode(handle_fs) to get the mode
of a an abstract object wrapping either a file, a dentry, a path, or an
inode.

Changes since v4:
* use a file abstraction (handle) to wrap inode, dentry, path and file
  structs
* remove bpf_landlock_cmp_fs_beneath()
* rename the BPF helper and move it to kernel/bpf/
* tighten helpers accessible by a Landlock rule

Changes since v3:
* remove bpf_landlock_cmp_fs_prop() (suggested by Alexie Starovoitov)
* add hooks dealing with struct inode and struct path pointers:
  inode_permission and inode_getattr
* add abstraction over eBPF helper arguments thanks to wrapping structs
* add bpf_landlock_get_fs_mode() helper to check file type and mode
* merge WARN_ON() (suggested by Kees Cook)
* fix and update bpf_helpers.h
* use BPF_CALL_* for eBPF helpers (suggested by Alexie Starovoitov)
* make handle arraymap safe (RCU) and remove buggy synchronize_rcu()
* factor out the arraymay walk
* use size_t to index array (suggested by Jann Horn)

Changes since v2:
* add MNT_INTERNAL check to only add file handle from user-visible FS
  (e.g. no anonymous inode)
* replace struct file* with struct path* in map_landlock_handle
* add BPF protos
* fix bpf_landlock_cmp_fs_prop_with_struct_file()

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: Jann Horn <j...@thejh.net>
---
 include/linux/bpf.h| 33 +++
 include/uapi/linux/bpf.h   | 10 +++-
 kernel/bpf/Makefile|  2 +-
 kernel/bpf/helpers_fs.c| 52 ++
 kernel/bpf/verifier.c  |  6 +
 samples/bpf/bpf_helpers.h  |  2 ++
 security/landlock/hooks.c  |  8 ++-
 tools/include/uapi/linux/bpf.h | 10 +++-
 8 files changed, 119 insertions(+), 4 deletions(-)
 create mode 100644 kernel/bpf/helpers_fs.c

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index dd954048aa19..bc01a7388168 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -15,6 +15,11 @@
 #include 
 #include 
 
+/* FS helpers */
+#include  /* struct dentry */
+#include  /* struct file, struct inode */
+#include  /* struct path */
+
 struct perf_event;
 struct bpf_map;
 
@@ -82,6 +87,8 @@ enum bpf_arg_type {
 
ARG_PTR_TO_CTX, /* pointer to context */
ARG_ANYTHING,   /* any (initialized) argument is ok */
+
+   ARG_CONST_PTR_TO_HANDLE_FS, /* pointer to an abstract FS struct */
 };
 
 /* type of values returned from helper functions */
@@ -148,6 +155,9 @@ enum bpf_reg_type {
 * map element.
 */
PTR_TO_MAP_VALUE_ADJ,
+
+   /* FS helpers */
+   CONST_PTR_TO_HANDLE_FS,
 };
 
 struct bpf_prog;
@@ -220,6 +230,26 @@ struct bpf_event_entry {
struct rcu_head rcu;
 };
 
+/* FS helpers */
+enum bpf_handle_fs_type {
+   BPF_HANDLE_FS_TYPE_NONE,
+   BPF_HANDLE_FS_TYPE_FILE,
+   BPF_HANDLE_FS_TYPE_INODE,
+   BPF_HANDLE_FS_TYPE_PATH,
+   BPF_HANDLE_FS_TYPE_DENTRY,
+};
+
+struct bpf_handle_fs {
+   enum bpf_handle_fs_type type;
+   union {
+   struct file *file;
+   struct inode *inode;
+   const struct path *path;
+   struct dentry *dentry;
+   };
+};
+
+
 u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5);
 u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
 
@@ -358,6 +388,9 @@ extern const struct bpf_func_proto bpf_skb_vlan_push_proto;
 extern const struct bpf_func_proto bpf_skb_vlan_pop_proto;
 extern const struct bpf_func_proto bpf_get_stackid_proto;
 
+/* FS helpers */
+extern const struct bpf_func_proto bpf_handle_fs_get_mode_proto;
+
 /* Shared helpers among cBPF and eBPF. */
 void bpf_user_rnd_init_once(void);
 u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index c9c909a84f0b..ffceb42ccc4e 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -467,6 +467,13 @@ union bpf_attr {
  * Return:
  *   > 0 length of the string including the trailing NUL on success
  *   < 0 error
+ *
+ * s64 bpf_handle_fs_get_mode(handle_fs)
+ * Get the mode of a struct bpf_handle_fs
+ * fs: struct bpf_handle_fs address
+ * Return:
+ *   >= 0 file mode
+ *   < 0 error
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -514,7 +521,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), \

[PATCH v5 04/10] landlock: Add LSM hooks related to filesystem

2017-02-21 Thread Mickaël Salaün
Handle 33 filesystem-related LSM hooks for the Landlock filesystem
event: LANDLOCK_SUBTYPE_EVENT_FS.

A Landlock event wrap LSM hooks for similar kernel object types (e.g.
struct file, struct path...). Multiple LSM hooks can trigger the same
Landlock event.

Landlock handle nine coarse-grained actions: read, write, execute, new,
get, remove, ioctl, lock and fcntl. Each of them abstract LSM hook
access control in a way that can be extended in the future.

The Landlock LSM hook registration is done after other LSM to only run
actions from user-space, via eBPF programs, if the access was granted by
major (privileged) LSMs.

Changes since v4:
* add LSM hook abstraction called Landlock event
  * use the compiler type checking to verify hooks use by an event
  * handle all filesystem related LSM hooks (e.g. file_permission,
mmap_file, sb_mount...)
* register BPF programs for Landlock just after LSM hooks registration
* move hooks registration after other LSMs
* add failsafes to check if a hook is not used by the kernel
* allow partial raw value access form the context (needed for programs
  generated by LLVM)

Changes since v3:
* split commit
* add hooks dealing with struct inode and struct path pointers:
  inode_permission and inode_getattr
* add abstraction over eBPF helper arguments thanks to wrapping structs

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 include/linux/lsm_hooks.h  |   5 +
 security/landlock/Makefile |   2 +
 security/landlock/hooks.c  | 794 -
 security/security.c|   7 +-
 4 files changed, 806 insertions(+), 2 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa5c8a8..069af34301d4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1933,5 +1933,10 @@ void __init loadpin_add_hooks(void);
 #else
 static inline void loadpin_add_hooks(void) { };
 #endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void __init landlock_add_hooks(void);
+#else
+static inline void __init landlock_add_hooks(void) { }
+#endif /* CONFIG_SECURITY_LANDLOCK */
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/landlock/Makefile b/security/landlock/Makefile
index b91af42f0c32..8dc8bde660bd 100644
--- a/security/landlock/Makefile
+++ b/security/landlock/Makefile
@@ -1,3 +1,5 @@
+ccflags-$(CONFIG_SECURITY_LANDLOCK) += -Werror=unused-function
+
 obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
 
 landlock-y := hooks.o
diff --git a/security/landlock/hooks.c b/security/landlock/hooks.c
index 6c1ad0e03cfc..88ebe3f01758 100644
--- a/security/landlock/hooks.c
+++ b/security/landlock/hooks.c
@@ -21,14 +21,797 @@
 #include  /* offsetof */
 #include  /* uintptr_t */
 
+/* permissions translation */
+#include  /* MAY_* */
+#include  /* PROT_* */
+
+/* hook arguments */
+#include 
+#include  /* struct dentry */
+#include  /* struct inode, struct iattr */
+#include  /* struct vm_area_struct */
+#include  /* struct vfsmount */
+#include  /* struct path */
+#include  /* struct task_struct */
+#include  /* struct timespec */
+
+
+#include "common.h" /* get_index() */
+
 #define CTX_ARG_NB 2
 
+/* separators */
+#define SEP_COMMA() ,
+#define SEP_SPACE()
+#define SEP_AND() &&
+
+#define MAP2x1(s, m, x1, x2, ...) m(x1, x2)
+#define MAP2x2(s, m, x1, x2, ...) m(x1, x2) s() MAP2x1(s, m, __VA_ARGS__)
+#define MAP2x3(s, m, x1, x2, ...) m(x1, x2) s() MAP2x2(s, m, __VA_ARGS__)
+#define MAP2x4(s, m, x1, x2, ...) m(x1, x2) s() MAP2x3(s, m, __VA_ARGS__)
+#define MAP2x5(s, m, x1, x2, ...) m(x1, x2) s() MAP2x4(s, m, __VA_ARGS__)
+#define MAP2x6(s, m, x1, x2, ...) m(x1, x2) s() MAP2x5(s, m, __VA_ARGS__)
+#define MAP2x(n, ...) MAP2x##n(__VA_ARGS__)
+
+#define MAP1x1(s, m, x1, ...) m(x1)
+#define MAP1x2(s, m, x1, ...) m(x1) s() MAP1x1(s, m, __VA_ARGS__)
+#define MAP1x(n, ...) MAP1x##n(__VA_ARGS__)
+
+#define SKIP2x1(x1, x2, ...) __VA_ARGS__
+#define SKIP2x2(x1, x2, ...) SKIP2x1(__VA_ARGS__)
+#define SKIP2x3(x1, x2, ...) SKIP2x2(__VA_ARGS__)
+#define SKIP2x4(x1, x2, ...) SKIP2x3(__VA_ARGS__)
+#define SKIP2x5(x1, x2, ...) SKIP2x4(__VA_ARGS__)
+#define SKIP2x6(x1, x2, ...) SKIP2x5(__VA_ARGS__)
+#define SKIP2x(n, ...) SKIP2x##n(__VA_ARGS__)
+
+/* LSM hook argument helpers */
+#define MAP_HOOK_COMMA(n, ...) MAP2x(n, SEP_COMMA, __VA_ARGS__)
+
+#define GET_HOOK_TA(t, a) t a
+
+/* Landlock event argument helpers  */
+#define MAP_EVENT_COMMA(h, n, m, ...) MAP2x(n, SEP_COMMA, m, SKIP2x(h, 
__VA_ARGS__))
+#define MAP_EVENT_SPACE(h, n, m, ...) MAP2x(n, SEP_SPACE, m, SKIP2x(h, 
__VA_ARGS__))
+#define MAP_EVENT_AND(h, n, m, ...) MAP2x(n, SEP_AND, m, SKIP2x(h, 
__VA_ARGS__))
+
+#defi

[PATCH v5 10/10] landlock: Add user and kernel documentation for Landlock

2017-02-21 Thread Mickaël Salaün
This documentation can be built with the Sphinx framework.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Jonathan Corbet <cor...@lwn.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 Documentation/security/index.rst   |   1 +
 Documentation/security/landlock/index.rst  |  19 ++
 Documentation/security/landlock/kernel.rst | 132 +
 Documentation/security/landlock/user.rst   | 298 +
 4 files changed, 450 insertions(+)
 create mode 100644 Documentation/security/landlock/index.rst
 create mode 100644 Documentation/security/landlock/kernel.rst
 create mode 100644 Documentation/security/landlock/user.rst

diff --git a/Documentation/security/index.rst b/Documentation/security/index.rst
index 9bae6bb20e7f..21a5a6b6e666 100644
--- a/Documentation/security/index.rst
+++ b/Documentation/security/index.rst
@@ -5,3 +5,4 @@ Security documentation
 .. toctree::
 
tpm/index
+   landlock/index
diff --git a/Documentation/security/landlock/index.rst 
b/Documentation/security/landlock/index.rst
new file mode 100644
index ..012bb9c2e2cb
--- /dev/null
+++ b/Documentation/security/landlock/index.rst
@@ -0,0 +1,19 @@
+
+Landlock LSM
+
+
+Landlock is a stackable Linux Security Module (LSM) that makes it possible to
+create security sandboxes.  This kind of sandbox is expected to help mitigate
+the security impact of bugs or unexpected/malicious behaviors in user-space
+applications.  The current version allows only a process with the global
+CAP_SYS_ADMIN capability to create such sandboxes but the ultimate goal of
+Landlock is to empower any process, including unprivileged ones, to securely
+restrict themselves.  Landlock is inspired by seccomp-bpf but instead of
+filtering syscalls and their raw arguments, a Landlock rule can inspect the use
+of kernel objects like files and hence make a decision according to the kernel
+semantic.
+
+.. toctree::
+
+user
+kernel
diff --git a/Documentation/security/landlock/kernel.rst 
b/Documentation/security/landlock/kernel.rst
new file mode 100644
index ..d31a7d6574af
--- /dev/null
+++ b/Documentation/security/landlock/kernel.rst
@@ -0,0 +1,132 @@
+==
+Landlock: kernel documentation
+==
+
+eBPF properties
+===
+
+To get an expressive language while still being safe and small, Landlock is
+based on eBPF. Landlock should be usable by untrusted processes and must
+therefore expose a minimal attack surface. The eBPF bytecode is minimal,
+powerful, widely used and designed to be used by untrusted applications. Thus,
+reusing the eBPF support in the kernel enables a generic approach while
+minimizing new code.
+
+An eBPF program has access to an eBPF context containing some fields including
+event arguments (i.e. arg1 and arg2). These arguments can be used directly or
+passed to helper functions according to their types. It is then possible to do
+complex access checks without race conditions or inconsistent evaluation (i.e.
+`incorrect mirroring of the OS code and state
+<https://www.internetsociety.org/doc/traps-and-pitfalls-practical-problems-system-call-interposition-based-security-tools>`_).
+
+A Landlock event describes a particular access type.  For now, there is only
+one event type dedicated to filesystem related operations:
+LANDLOCK_SUBTYPE_EVENT_FS.  A Landlock rule is tied to one event type.  This
+makes it possible to statically check context accesses, potentially performed
+by such rule, and hence prevents kernel address leaks and ensure the right use
+of event arguments with eBPF functions.  Any user can add multiple Landlock
+rules per Landlock event.  They are stacked and evaluated one after the other,
+starting from the most recent rule, as seccomp-bpf does with its filters.
+Underneath, an event is an abstraction over a set of LSM hooks.
+
+
+Guiding principles
+==
+
+Unprivileged use
+
+
+* Everything potentially security sensitive which is exposed to a Landlock
+  rule, through functions or context, shall have an associated ability flag to
+  specify which kind of privilege a process must have to load such a rule.
+* Every ability flag expresses a semantic goal (e.g. debug, process
+  introspection, process modification) potentially tied to a set of
+  capabilities.
+* Landlock helpers and context should be usable by any unprivileged and
+  untrusted rule while following the system security policy enforced by other
+  access control mechanisms (e.g. DAC, LSM).
+
+
+Landlock event and context
+--
+
+* A Landlock event shall be focus

[PATCH v5 06/10] seccomp,landlock: Handle Landlock events per process hierarchy

2017-02-21 Thread Mickaël Salaün
The seccomp(2) syscall can be use to apply a Landlock rule to the
current process. As with a seccomp filter, the Landlock rule is enforced
for all its future children. An inherited rule tree can be updated
(append-only) by the owner of inherited Landlock nodes (e.g. a parent
process that create a new rule). However, an intermediate task, which
did not create a rule, will not be able to update its children's rules.

Landlock rules can be tied to a Landlock event. When such an event is
triggered, a tree of rules can be evaluated. Thisk kind of tree is
created with a first node.  This node reference a list of rules and an
optional parent node. Each rule return a 32-bit value which can
interrupt the evaluation with a non-zero value. If every rules returned
zero, the evaluation continues with the rule list of the parent node,
until the end of the tree.

Changes since v4:
* merge manager and seccomp patches
* return -EFAULT in seccomp(2) when user_bpf_fd is null to easely check
  if Landlock is supported
* only allow a process with the global CAP_SYS_ADMIN to use Landlock
  (will be lifted in the future)
* add an early check to exit as soon as possible if the current process
  does not have Landlock rules

Changes since v3:
* remove the hard link with seccomp (suggested by Andy Lutomirski and
  Kees Cook):
  * remove the cookie which could imply multiple evaluation of Landlock
rules
  * remove the origin field in struct landlock_data
* remove documentation fix (merged upstream)
* rename the new seccomp command to SECCOMP_ADD_LANDLOCK_RULE
* internal renaming
* split commit
* new design to be able to inherit on the fly the parent rules

Changes since v2:
* Landlock programs can now be run without seccomp filter but for any
  syscall (from the process) or interruption
* move Landlock related functions and structs into security/landlock/*
  (to manage cgroups as well)
* fix seccomp filter handling: run Landlock programs for each of their
  legitimate seccomp filter
* properly clean up all seccomp results
* cosmetic changes to ease the understanding
* fix some ifdef

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andrew Morton <a...@linux-foundation.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: Will Drewry <w...@chromium.org>
---
 include/linux/seccomp.h  |   8 ++
 include/uapi/linux/seccomp.h |   1 +
 kernel/fork.c|  14 +-
 kernel/seccomp.c |   8 ++
 security/landlock/Makefile   |   2 +-
 security/landlock/hooks.c|  42 +-
 security/landlock/manager.c  | 321 +++
 7 files changed, 392 insertions(+), 4 deletions(-)
 create mode 100644 security/landlock/manager.c

diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index e25aee2cdfc0..9a38de3c0e72 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -10,6 +10,10 @@
 #include 
 #include 
 
+#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_SECURITY_LANDLOCK)
+struct landlock_events;
+#endif /* CONFIG_SECCOMP_FILTER && CONFIG_SECURITY_LANDLOCK */
+
 struct seccomp_filter;
 /**
  * struct seccomp - the state of a seccomp'ed process
@@ -18,6 +22,7 @@ struct seccomp_filter;
  * system calls available to a process.
  * @filter: must always point to a valid seccomp-filter or NULL as it is
  *  accessed without locking during system call entry.
+ * @landlock_events: contains an array of Landlock rules.
  *
  *  @filter must only be accessed from the context of current as there
  *  is no read locking.
@@ -25,6 +30,9 @@ struct seccomp_filter;
 struct seccomp {
int mode;
struct seccomp_filter *filter;
+#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_SECURITY_LANDLOCK)
+   struct landlock_events *landlock_events;
+#endif /* CONFIG_SECCOMP_FILTER && CONFIG_SECURITY_LANDLOCK */
 };
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 0f238a43ff1e..56dd692cddac 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -13,6 +13,7 @@
 /* Valid operations for seccomp syscall. */
 #define SECCOMP_SET_MODE_STRICT0
 #define SECCOMP_SET_MODE_FILTER1
+#define SECCOMP_ADD_LANDLOCK_RULE  2
 
 /* Valid flags for SECCOMP_SET_MODE_FILTER */
 #define SECCOMP_FILTER_FLAG_TSYNC  1
diff --git a/kernel/fork.c b/kernel/fork.c
index a4f0d0e8aeb2..bd5c72dffe60 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -37,6 +37,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -515,7 +516,10 @@ static struct task_struct *dup_task_struct(struct 
task_struct *orig, int node)
 * the usage counts on the error path calling free_task.

[PATCH v5 09/10] bpf,landlock: Add tests for Landlock

2017-02-21 Thread Mickaël Salaün
Test basic context access and filesystem event with multiple cases.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: Shuah Khan <sh...@kernel.org>
Cc: Will Drewry <w...@chromium.org>
---
 tools/testing/selftests/Makefile   |   1 +
 tools/testing/selftests/bpf/test_verifier.c|  54 +++-
 tools/testing/selftests/landlock/.gitignore|   2 +
 tools/testing/selftests/landlock/Makefile  |  47 +++
 tools/testing/selftests/landlock/rules/Makefile|  52 +++
 tools/testing/selftests/landlock/rules/README.rst  |   1 +
 .../testing/selftests/landlock/rules/bpf_helpers.h |   1 +
 tools/testing/selftests/landlock/rules/fs1.c   |  31 ++
 tools/testing/selftests/landlock/rules/fs2.c   |  31 ++
 tools/testing/selftests/landlock/test_fs.c | 347 +
 10 files changed, 566 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/landlock/.gitignore
 create mode 100644 tools/testing/selftests/landlock/Makefile
 create mode 100644 tools/testing/selftests/landlock/rules/Makefile
 create mode 12 tools/testing/selftests/landlock/rules/README.rst
 create mode 12 tools/testing/selftests/landlock/rules/bpf_helpers.h
 create mode 100644 tools/testing/selftests/landlock/rules/fs1.c
 create mode 100644 tools/testing/selftests/landlock/rules/fs2.c
 create mode 100644 tools/testing/selftests/landlock/test_fs.c

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 831022b12848..a8dadcfa4c01 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -10,6 +10,7 @@ TARGETS += futex
 TARGETS += gpio
 TARGETS += ipc
 TARGETS += kcmp
+TARGETS += landlock
 TARGETS += lib
 TARGETS += membarrier
 TARGETS += memfd
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 15eeb79104fe..ee1d439e48e4 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -4451,7 +4451,59 @@ static struct bpf_test tests[] = {
.errstr = "R0 min value is negative, either use unsigned index 
or do a if (index >=0) check.",
.result = REJECT,
.result_unpriv = REJECT,
-   }
+   },
+   {
+   "landlock/fs: always accept",
+   .insns = {
+   BPF_MOV32_IMM(BPF_REG_0, 0),
+   BPF_EXIT_INSN(),
+   },
+   .result = ACCEPT,
+   .prog_type = BPF_PROG_TYPE_LANDLOCK,
+   .prog_subtype = {
+   .landlock_rule = {
+   .version = 1,
+   .event = LANDLOCK_SUBTYPE_EVENT_FS,
+   }
+   },
+   },
+   {
+   "landlock/fs: read context",
+   .insns = {
+   BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+   BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, status)),
+   /* test operations on raw values */
+   BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
+   BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, arch)),
+   BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
+   BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, syscall_nr)),
+   BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
+   BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, syscall_cmd)),
+   BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
+   BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, event)),
+   BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
+   BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, arg1)),
+   BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_6,
+   offsetof(struct landlock_context, arg2)),
+   BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 1),
+   BPF_MOV32_IMM(BPF_REG_0, 0),
+   BPF_EXIT_INSN(),
+   },
+   .result = ACCEPT,
+   .prog_type = BPF_PROG_TYPE_LANDLOCK,
+   .prog_subtyp

[PATCH v5 01/10] bpf: Add eBPF program subtype and is_valid_subtype() verifier

2017-02-21 Thread Mickaël Salaün
The goal of the program subtype is to be able to have different static
fine-grained verifications for a unique program type.

The struct bpf_verifier_ops gets a new optional function:
is_valid_subtype(). This new verifier is called at the beginning of the
eBPF program verification to check if the (optional) program subtype is
valid.

For now, only Landlock eBPF programs are using a program subtype (see
next commit) but this could be used by other program types in the future.

Changes since v4:
* replace the "status" field with "version" (more generic)
* replace the "access" field with "ability" (less confusing)

Changes since v3:
* remove the "origin" field
* add an "option" field
* cleanup comments

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Arnaldo Carvalho de Melo <a...@kernel.org>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Link: https://lkml.kernel.org/r/20160827205559.ga43...@ast-mbp.thefacebook.com
---
 include/linux/bpf.h |  7 +++--
 include/linux/filter.h  |  1 +
 include/uapi/linux/bpf.h| 10 ++
 kernel/bpf/syscall.c|  5 +--
 kernel/bpf/verifier.c   | 10 --
 kernel/trace/bpf_trace.c| 15 ++---
 net/core/filter.c   | 48 ++---
 samples/bpf/bpf_load.c  |  3 +-
 samples/bpf/fds_example.c   |  2 +-
 samples/bpf/sock_example.c  |  2 +-
 samples/bpf/test_cgrp2_attach.c |  2 +-
 samples/bpf/test_cgrp2_attach2.c|  2 +-
 samples/bpf/test_cgrp2_sock.c   |  2 +-
 tools/include/uapi/linux/bpf.h  | 10 ++
 tools/lib/bpf/bpf.c |  5 ++-
 tools/lib/bpf/bpf.h |  2 +-
 tools/lib/bpf/libbpf.c  |  4 +--
 tools/perf/tests/bpf.c  |  2 +-
 tools/testing/selftests/bpf/test_tag.c  |  2 +-
 tools/testing/selftests/bpf/test_verifier.c |  3 +-
 20 files changed, 95 insertions(+), 42 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 909fc033173a..dd954048aa19 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -154,19 +154,22 @@ struct bpf_prog;
 
 struct bpf_verifier_ops {
/* return eBPF function prototype for verification */
-   const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id 
func_id);
+   const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id,
+ union bpf_prog_subtype *prog_subtype);
 
/* return true if 'size' wide access at offset 'off' within bpf_context
 * with 'type' (read or write) is allowed
 */
bool (*is_valid_access)(int off, int size, enum bpf_access_type type,
-   enum bpf_reg_type *reg_type);
+   enum bpf_reg_type *reg_type,
+   union bpf_prog_subtype *prog_subtype);
int (*gen_prologue)(struct bpf_insn *insn, bool direct_write,
const struct bpf_prog *prog);
u32 (*convert_ctx_access)(enum bpf_access_type type,
  const struct bpf_insn *src,
  struct bpf_insn *dst,
  struct bpf_prog *prog);
+   bool (*is_valid_subtype)(union bpf_prog_subtype *prog_subtype);
 };
 
 struct bpf_prog_type_list {
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 0c167fdee5f7..1f49b19a87c1 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -417,6 +417,7 @@ struct bpf_prog {
enum bpf_prog_type  type;   /* Type of BPF program */
u32 len;/* Number of filter blocks */
u8  tag[BPF_TAG_SIZE];
+   union bpf_prog_subtype  subtype;/* For fine-grained 
verifications */
struct bpf_prog_aux *aux;   /* Auxiliary fields */
struct sock_fprog_kern  *orig_prog; /* Original BPF program */
unsigned int(*bpf_func)(const void *ctx,
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 0539a0ceef38..240c76f09d0d 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -145,6 +145,15 @@ enum bpf_attach_type {
  */
 #define BPF_F_NO_COMMON_LRU(1U << 1)
 
+union bpf_prog_subtype {
+   struct {
+   __u32   version; /* cf. documentation */
+   __u32   event; /* enum landlock_subtype_event */
+   __aligned_u64   ability; /* LANDLOCK_SUBTYPE_ABILITY_* */
+   __aligned_u64   option; /* LANDLOCK_SUBTYPE_OPTION_* */
+   } landlock_rul

[PATCH v5 07/10] bpf: Add a Landlock sandbox example

2017-02-21 Thread Mickaël Salaün
Add a basic sandbox tool to create a process isolated from some part of
the system. This sandbox create a read-only environment. It is only
allowed to write to a character device such as a TTY:

  # :> X
  # echo $?
  0
  # ./samples/bpf/landlock1 /bin/sh -i
  Launching a new sandboxed process.
  # :> Y
  cannot create Y: Operation not permitted

Changes since v4:
* write Landlock rule in C and compiled it with LLVM
* remove cgroup handling
* remove path handling: only handle a read-only environment
* remove errno return codes

Changes since v3:
* remove seccomp and origin field: completely free from seccomp programs
* handle more FS-related hooks
* handle inode hooks and directory traversal
* add faked but consistent view thanks to ENOENT
* add /lib64 in the example
* fix spelling
* rename some types and definitions (e.g. SECCOMP_ADD_LANDLOCK_RULE)

Changes since v2:
* use BPF_PROG_ATTACH for cgroup handling

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 samples/bpf/.gitignore   |  32 ++
 samples/bpf/Makefile |   4 ++
 samples/bpf/bpf_load.c   |  26 +--
 samples/bpf/landlock1_kern.c |  46 +++
 samples/bpf/landlock1_user.c | 102 +++
 5 files changed, 206 insertions(+), 4 deletions(-)
 create mode 100644 samples/bpf/.gitignore
 create mode 100644 samples/bpf/landlock1_kern.c
 create mode 100644 samples/bpf/landlock1_user.c

diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
new file mode 100644
index ..a7562a5ef4c2
--- /dev/null
+++ b/samples/bpf/.gitignore
@@ -0,0 +1,32 @@
+fds_example
+lathist
+lwt_len_hist
+map_perf_test
+offwaketime
+sampleip
+sockex1
+sockex2
+sockex3
+sock_example
+spintest
+tc_l2_redirect
+test_cgrp2_array_pin
+test_cgrp2_attach
+test_cgrp2_attach2
+test_cgrp2_sock
+test_cgrp2_sock2
+test_current_task_under_cgroup
+test_lru_dist
+test_overhead
+test_probe_write_user
+trace_event
+trace_output
+tracex1
+tracex2
+tracex3
+tracex4
+tracex5
+tracex6
+xdp1
+xdp2
+xdp_tx_iptunnel
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 09e9d535bd74..3d3afd709635 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 += landlock1
 
 # 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
+landlock1-objs := bpf_load.o $(LIBBPF) landlock1_user.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 += landlock1_kern.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 HOSTCFLAGS += -I$(srctree)/tools/lib/
@@ -139,6 +142,7 @@ HOSTLOADLIBES_sampleip += -lelf
 HOSTLOADLIBES_tc_l2_redirect += -l elf
 HOSTLOADLIBES_lwt_len_hist += -l elf
 HOSTLOADLIBES_xdp_tx_iptunnel += -lelf
+HOSTLOADLIBES_landlock1 += -lelf
 
 # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on 
cmdline:
 #  make samples/bpf/ LLC=~/git/llvm/build/bin/llc 
CLANG=~/git/llvm/build/bin/clang
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index d23dc13ab0f2..78df39cf8b2f 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -68,6 +68,7 @@ static int load_and_attach(const char *event, struct bpf_insn 
*prog, int size)
bool is_perf_event = strncmp(event, "perf_event", 10) == 0;
bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0;
bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0;
+   bool is_landlock = strncmp(event, "landlock", 8) == 0;
size_t insns_cnt = size / sizeof(struct bpf_insn);
enum bpf_prog_type prog_type;
char buf[256];
@@ -93,6 +94,12 @@ static int load_and_attach(const char *event, struct 
bpf_insn *prog, int size)
prog_type = BPF_PROG_TYPE_CGROUP_SKB;
} else if (is_cgroup_sk) {
prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
+   } else if (is_landlock) {
+   prog_type = BPF_PROG_TYPE_LANDLOCK;
+   if (!subtype.landlock_rule.event) {
+   printf("No subtype\n");
+   return -1;
+   }
} else {

Re: [PATCH v5 10/10] landlock: Add user and kernel documentation for Landlock

2017-02-21 Thread Mickaël Salaün

On 22/02/2017 06:21, Andy Lutomirski wrote:
> On Tue, Feb 21, 2017 at 5:26 PM, Mickaël Salaün <m...@digikod.net> wrote:
>> This documentation can be built with the Sphinx framework.
>>
>> Signed-off-by: Mickaël Salaün <m...@digikod.net>
>> Cc: Alexei Starovoitov <a...@kernel.org>
>> Cc: Andy Lutomirski <l...@amacapital.net>
>> Cc: Daniel Borkmann <dan...@iogearbox.net>
>> Cc: David S. Miller <da...@davemloft.net>
>> Cc: James Morris <james.l.mor...@oracle.com>
>> Cc: Jonathan Corbet <cor...@lwn.net>
>> Cc: Kees Cook <keesc...@chromium.org>
>> Cc: Serge E. Hallyn <se...@hallyn.com>
> 
> 
>> +
>> +Writing a rule
>> +--
>> +
>> +To enforce a security policy, a thread first needs to create a Landlock 
>> rule.
>> +The easiest way to write an eBPF program depicting a security rule is to 
>> write
>> +it in the C language.  As described in *samples/bpf/README.rst*, LLVM can
>> +compile such programs.  Files *samples/bpf/landlock1_kern.c* and those in
>> +*tools/testing/selftests/landlock/rules/* can be used as examples.  The
>> +following example is a simple rule to forbid file creation, whatever syscall
>> +may be used (e.g. open, mkdir, link...).
>> +
>> +.. code-block:: c
>> +
>> +static int deny_file_creation(struct landlock_context *ctx)
>> +{
>> +if (ctx->arg2 & LANDLOCK_ACTION_FS_NEW)
>> +return 1;
>> +return 0;
>> +}
>> +
> 
> Would it make sense to define landlock_context (or at least a prefix
> thereof) in here?  Also, can't "arg2" have a better name?

arg2 is a generic name. Its meaning depends on the Landlock event, here
it is an action bitfield (FS event).

> 
> Can you specify what the return value means?  Are 0 and 1 the only
> choices?  Would "KILL" be useful?  How about "COREDUMP"?

This is explained thereafter and in the kernel Q section. I need to
briefly introduce that here.

> 
>> +File system action types
>> +
>> +
>> +Flags are used to express actions.  This makes it possible to compose 
>> actions
>> +and leaves room for future improvements to add more fine-grained action 
>> types.
>> +
>> +.. kernel-doc:: include/uapi/linux/bpf.h
>> +:doc: landlock_action_fs
>> +
>> +.. flat-table:: FS action types availability
>> +
>> +* - flags
>> +  - since
>> +
>> +* - LANDLOCK_ACTION_FS_EXEC
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_WRITE
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_READ
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_NEW
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_GET
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_REMOVE
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_IOCTL
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_LOCK
>> +  - v1
>> +
>> +* - LANDLOCK_ACTION_FS_FCNTL
>> +  - v1
> 
> What happens if you run an old program on a new kernel?  Can you get
> unexpected action types?

The old flags will still make sense, the new ones should be ignored by
the rule.

> 
>> +
>> +
>> +Ability types
>> +-
>> +
>> +The ability of a Landlock rule describes the available features (i.e. 
>> context
>> +fields and helpers).  This is useful to abstract user-space privileges for
>> +Landlock rules, which may not need all abilities (e.g. debug).  Only the
>> +minimal set of abilities should be used (e.g. disable debug once in
>> +production).
>> +
>> +
>> +.. kernel-doc:: include/uapi/linux/bpf.h
>> +:doc: landlock_subtype_ability
>> +
>> +.. flat-table:: Ability types availability
>> +
>> +* - flags
>> +  - since
>> +  - capability
>> +
>> +* - LANDLOCK_SUBTYPE_ABILITY_WRITE
>> +  - v1
>> +  - CAP_SYS_ADMIN
>> +
>> +* - LANDLOCK_SUBTYPE_ABILITY_DEBUG
>> +  - v1
>> +  - CAP_SYS_ADMIN
>> +
> 
> What do "WRITE" and "DEBUG" mean in this context?  I'm totally lost.
> 
> Hmm.  Reading below, "WRITE" seems to mean "modify state".  Would that
> be accurate?

That is correct, but handling a state in a safe way imply more than only
the ability to "write" outside bpfland (e.g. sequential execution).

> 
>> +
>> +Helper functions
>> +
>> +
>> +See *include/uapi/linux/bpf.h* for functions documentation.
>> +
>> +.. flat-table:: Generic functions availability
>> +
> 
>> +
>> +* - bpf_get_current_comm
>> +  - v1
>> +  - LANDLOCK_SUBTYPE_ABILITY_DEBUG
> 
> What would this be used for?

To get more information about the process which trigger an action?

> 
>> +* - bpf_get_trace_printk
>> +  - v1
>> +  - LANDLOCK_SUBTYPE_ABILITY_DEBUG
>> +
> 
> This is different from the other DEBUG stuff in that it has side
> effects.  I wonder if it should have a different flag.

I think the debug flag is a clear warning to not ship a rule using this
ability. Maybe a sub-flag LANDLOCK_SUBTYPE_ABILITY_DEBUG_PRINT would fit
here?

 Mickaël



signature.asc
Description: OpenPGP digital signature


[PATCH v5 00/10] Landlock LSM: Toward unprivileged sandboxing

2017-02-21 Thread Mickaël Salaün
ause only checking in LSM hooks
  * architecture agnostic
* switch from cBPF to eBPF:
  * new eBPF program types dedicated to Landlock
  * custom functions used by the eBPF program
  * gain some new features (e.g. 10 registers, can load values of different
size, LLVM translator) but only a few functions allowed and a dedicated 
map
type
  * new context: LSM hook ID, cookie and LSM hook arguments
  * need to set the sysctl kernel.unprivileged_bpf_disable to 0 (default value)
to be able to load hook filters as unprivileged users
* smaller and simpler:
  * no more checker groups but dedicated arraymap of handles
  * simpler userland structs thanks to eBPF functions
* distinctive name: Landlock


[1] https://lkml.kernel.org/r/20161026065654.19166-1-...@digikod.net
[2] https://lkml.kernel.org/r/5828776a.1010...@digikod.net
[3] 
https://lkml.kernel.org/r/1477390454-12553-1-git-send-email-dan...@zonque.org
[4] 
https://lkml.kernel.org/r/20160829114542.GA20836@ircssh.c.rugged-nimbus-611.internal
[5] https://lkml.kernel.org/r/20161221231506.19800-1-...@digikod.net

Regards,

Mickaël Salaün (10):
  bpf: Add eBPF program subtype and is_valid_subtype() verifier
  bpf,landlock: Define an eBPF program type for Landlock
  bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()
  landlock: Add LSM hooks related to filesystem
  seccomp: Split put_seccomp_filter() with put_seccomp()
  seccomp,landlock: Handle Landlock events per process hierarchy
  bpf: Add a Landlock sandbox example
  seccomp: Enhance test_harness with an assert step mechanism
  bpf,landlock: Add tests for Landlock
  landlock: Add user and kernel documentation for Landlock

 Documentation/security/index.rst   |   1 +
 Documentation/security/landlock/index.rst  |  19 +
 Documentation/security/landlock/kernel.rst | 132 +++
 Documentation/security/landlock/user.rst   | 298 +++
 include/linux/bpf.h|  40 +-
 include/linux/filter.h |   1 +
 include/linux/landlock.h   |  80 ++
 include/linux/lsm_hooks.h  |   5 +
 include/linux/seccomp.h|  12 +-
 include/uapi/linux/bpf.h   | 125 ++-
 include/uapi/linux/seccomp.h   |   1 +
 kernel/bpf/Makefile|   2 +-
 kernel/bpf/helpers_fs.c|  52 ++
 kernel/bpf/syscall.c   |   5 +-
 kernel/bpf/verifier.c  |  16 +-
 kernel/fork.c  |  16 +-
 kernel/seccomp.c   |  26 +-
 kernel/trace/bpf_trace.c   |  15 +-
 net/core/filter.c  |  48 +-
 samples/bpf/.gitignore |  32 +
 samples/bpf/Makefile   |   4 +
 samples/bpf/bpf_helpers.h  |   2 +
 samples/bpf/bpf_load.c |  29 +-
 samples/bpf/fds_example.c  |   2 +-
 samples/bpf/landlock1_kern.c   |  46 +
 samples/bpf/landlock1_user.c   | 102 +++
 samples/bpf/sock_example.c |   2 +-
 samples/bpf/test_cgrp2_attach.c|   2 +-
 samples/bpf/test_cgrp2_attach2.c   |   2 +-
 samples/bpf/test_cgrp2_sock.c  |   2 +-
 security/Kconfig   |   1 +
 security/Makefile  |   2 +
 security/landlock/Kconfig  |  18 +
 security/landlock/Makefile |   5 +
 security/landlock/common.h |  25 +
 security/landlock/hooks.c  | 962 +
 security/landlock/manager.c| 321 +++
 security/security.c|   7 +-
 tools/include/uapi/linux/bpf.h | 125 ++-
 tools/lib/bpf/bpf.c|   5 +-
 tools/lib/bpf/bpf.h|   2 +-
 tools/lib/bpf/libbpf.c |   4 +-
 tools/perf/tests/bpf.c |   2 +-
 tools/testing/selftests/Makefile   |   1 +
 tools/testing/selftests/bpf/test_tag.c |   2 +-
 tools/testing/selftests/bpf/test_verifier.c|  57 +-
 tools/testing/selftests/landlock/.gitignore|   2 +
 tools/testing/selftests/landlock/Makefile  |  47 +
 tools/testing/selftests/landlock/rules/Makefile|  52 ++
 tools/testing/selftests/landlock/rules/README.rst  |   1 +
 .../testing/selftests/landlock/rules/bpf_helpers.h |   1 +
 tools/testing/selftests/landlock/rules/fs1.c   |  31 +
 tools/testing/selftests/landlock/rules/fs2.c   |  31 +
 tools/testing/selftests/landlock/test_fs.c | 347 
 tools/t

[PATCH v5 02/10] bpf,landlock: Define an eBPF program type for Landlock

2017-02-21 Thread Mickaël Salaün
Add a new type of eBPF program used by Landlock rules.

This new BPF program type will be registered with the Landlock LSM
initialization.

Add an initial Landlock Kconfig.

Changes since v4:
* merge a minimal (not enabled) LSM code and Kconfig in this commit

Changes since v3:
* split commit
* revamp the landlock_context:
  * add arch, syscall_nr and syscall_cmd (ioctl, fcntl…) to be able to
cross-check action with the event type
  * replace args array with dedicated fields to ease the addition of new
fields

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 include/linux/landlock.h   |  80 ++
 include/uapi/linux/bpf.h   | 105 ++
 security/Kconfig   |   1 +
 security/Makefile  |   2 +
 security/landlock/Kconfig  |  18 ++
 security/landlock/Makefile |   3 +
 security/landlock/common.h |  25 +
 security/landlock/hooks.c  | 124 +
 tools/include/uapi/linux/bpf.h | 105 ++
 9 files changed, 463 insertions(+)
 create mode 100644 include/linux/landlock.h
 create mode 100644 security/landlock/Kconfig
 create mode 100644 security/landlock/Makefile
 create mode 100644 security/landlock/common.h
 create mode 100644 security/landlock/hooks.c

diff --git a/include/linux/landlock.h b/include/linux/landlock.h
new file mode 100644
index ..6be3c02dfc7c
--- /dev/null
+++ b/include/linux/landlock.h
@@ -0,0 +1,80 @@
+/*
+ * Landlock LSM - Public headers
+ *
+ * Copyright © 2017 Mickaël Salaün <m...@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_LANDLOCK_H
+#define _LINUX_LANDLOCK_H
+#ifdef CONFIG_SECURITY_LANDLOCK
+
+#include  /* _LANDLOCK_SUBTYPE_EVENT_LAST */
+#include  /* atomic_t */
+
+/*
+ * This is not intended for the UAPI headers. Each userland software should use
+ * a static minimal version for the required features as explained in the
+ * documentation.
+ */
+#define LANDLOCK_VERSION 1
+
+struct landlock_rule {
+   atomic_t usage;
+   struct landlock_rule *prev;
+   struct bpf_prog *prog;
+};
+
+/**
+ * struct landlock_node - node in the rule hierarchy
+ *
+ * This is created when a task inserts its first rule in the Landlock rule
+ * hierarchy. The set of Landlock rules referenced by this node is then
+ * enforced for all the tasks that inherit this node. However, if a task is
+ * cloned before inserting any rule, it doesn't get a dedicated node and its
+ * children will not inherit any rules from this task.
+ *
+ * @usage: reference count to manage the node lifetime
+ * @rule: list of Landlock rules managed by this node
+ * @prev: reference the parent node
+ * @owner: reference the address of the node in the  landlock_events.
+ * This is needed to know if we need to append a rule to the current
+ * node or create a new node.
+ */
+struct landlock_node {
+   atomic_t usage;
+   struct landlock_rule *rule;
+   struct landlock_node *prev;
+   struct landlock_node **owner;
+};
+
+/**
+ * struct landlock_events - Landlock event rules enforced on a thread
+ *
+ * This is used for low performance impact when forking a process. Instead of
+ * copying the full array and incrementing the usage of each entries, only
+ * create a pointer to  landlock_events and increments its usage.
+ *
+ * @usage: reference count to manage the object lifetime. When a thread need to
+ * add Landlock rules and if @usage is greater than 1, then the thread
+ * must duplicate  landlock_events to not change the children's
+ * rules as well.
+ * @nodes: array of non-NULL  landlock_node pointers
+ */
+struct landlock_events {
+   atomic_t usage;
+   struct landlock_node *nodes[_LANDLOCK_SUBTYPE_EVENT_LAST];
+};
+
+void put_landlock_events(struct landlock_events *events);
+
+#ifdef CONFIG_SECCOMP_FILTER
+int landlock_seccomp_append_prog(unsigned int flags,
+   const char __user *user_bpf_fd);
+#endif /* CONFIG_SECCOMP_FILTER */
+
+#endif /* CONFIG_SECURITY_LANDLOCK */
+#endif /* _LINUX_LANDLOCK_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 240c76f09d0d..c9c909a84f0b 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -112,6 +112,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_LWT_IN,
BPF_PROG_TYPE_LWT_OUT,
BPF_PROG_TYPE_LWT_XMIT,
+   BPF_PROG_TYPE_LANDLOCK,
 };

Re: [PATCH v5 07/10] bpf: Add a Landlock sandbox example

2017-02-23 Thread Mickaël Salaün

On 22/02/2017 02:26, Mickaël Salaün wrote:
> Add a basic sandbox tool to create a process isolated from some part of
> the system. This sandbox create a read-only environment. It is only
> allowed to write to a character device such as a TTY:
> 
>   # :> X
>   # echo $?
>   0
>   # ./samples/bpf/landlock1 /bin/sh -i
>   Launching a new sandboxed process.
>   # :> Y
>   cannot create Y: Operation not permitted
> 
> Changes since v4:
> * write Landlock rule in C and compiled it with LLVM
> * remove cgroup handling
> * remove path handling: only handle a read-only environment
> * remove errno return codes
> 
> Changes since v3:
> * remove seccomp and origin field: completely free from seccomp programs
> * handle more FS-related hooks
> * handle inode hooks and directory traversal
> * add faked but consistent view thanks to ENOENT
> * add /lib64 in the example
> * fix spelling
> * rename some types and definitions (e.g. SECCOMP_ADD_LANDLOCK_RULE)
> 
> Changes since v2:
> * use BPF_PROG_ATTACH for cgroup handling
> 
> Signed-off-by: Mickaël Salaün <m...@digikod.net>
> Cc: Alexei Starovoitov <a...@kernel.org>
> Cc: Andy Lutomirski <l...@amacapital.net>
> Cc: Daniel Borkmann <dan...@iogearbox.net>
> Cc: David S. Miller <da...@davemloft.net>
> Cc: James Morris <james.l.mor...@oracle.com>
> Cc: Kees Cook <keesc...@chromium.org>
> Cc: Serge E. Hallyn <se...@hallyn.com>
> ---
>  samples/bpf/.gitignore   |  32 ++
>  samples/bpf/Makefile |   4 ++
>  samples/bpf/bpf_load.c   |  26 +--
>  samples/bpf/landlock1_kern.c |  46 +++
>  samples/bpf/landlock1_user.c | 102 
> +++
>  5 files changed, 206 insertions(+), 4 deletions(-)
>  create mode 100644 samples/bpf/.gitignore
>  create mode 100644 samples/bpf/landlock1_kern.c
>  create mode 100644 samples/bpf/landlock1_user.c
> 
> diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
> new file mode 100644
> index ..a7562a5ef4c2
> --- /dev/null
> +++ b/samples/bpf/.gitignore
> @@ -0,0 +1,32 @@
> +fds_example
> +lathist
> +lwt_len_hist
> +map_perf_test
> +offwaketime
> +sampleip
> +sockex1
> +sockex2
> +sockex3
> +sock_example
> +spintest
> +tc_l2_redirect
> +test_cgrp2_array_pin
> +test_cgrp2_attach
> +test_cgrp2_attach2
> +test_cgrp2_sock
> +test_cgrp2_sock2
> +test_current_task_under_cgroup
> +test_lru_dist
> +test_overhead
> +test_probe_write_user
> +trace_event
> +trace_output
> +tracex1
> +tracex2
> +tracex3
> +tracex4
> +tracex5
> +tracex6
> +xdp1
> +xdp2
> +xdp_tx_iptunnel

Please ignore this hunk, it was part of another patch series…



signature.asc
Description: OpenPGP digital signature


[PATCH net-next v1] bpf: Rebuild bpf.o for any dependency update

2017-02-11 Thread Mickaël Salaün
This is needed to force a rebuild of bpf.o when one of its dependencies
(e.g. uapi/linux/bpf.h) is updated.

Add a phony target.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: Wang Nan <wangn...@huawei.com>
---
 tools/testing/selftests/bpf/Makefile | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index a35f564f66a1..c7816fe60feb 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,13 +1,24 @@
-CFLAGS += -Wall -O2 -lcap -I../../../include/uapi -I../../../lib
+LIBDIR := ../../../lib
+BPFOBJ := $(LIBDIR)/bpf/bpf.o
+
+CFLAGS += -Wall -O2 -lcap -I../../../include/uapi -I$(LIBDIR)
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
 TEST_PROGS := $(test_objs) test_kmod.sh
 TEST_FILES := $(test_objs)
 
+.PHONY: all clean force
+
 all: $(test_objs)
 
-$(test_objs): ../../../lib/bpf/bpf.o
+# force a rebuild of BPFOBJ when its dependencies are updated
+force:
+
+$(BPFOBJ): force
+   $(MAKE) -C $(dir $(BPFOBJ))
+
+$(test_objs): $(BPFOBJ)
 
 include ../lib.mk
 
-- 
2.11.0



[PATCH net-next v1] bpf: Remove redundant ifdef

2017-02-11 Thread Mickaël Salaün
Remove a useless ifdef __NR_bpf as requested by Wang Nan.

Inline one-line static functions as it was in the bpf_sys.h file.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: Wang Nan <wangn...@huawei.com>
Link: https://lkml.kernel.org/r/828ab1ff-4dcf-53ff-c97b-074adb895...@huawei.com
---
 tools/lib/bpf/bpf.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 50e04cc5..2de9c386989a 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -42,21 +42,15 @@
 # endif
 #endif
 
-static __u64 ptr_to_u64(const void *ptr)
+static inline __u64 ptr_to_u64(const void *ptr)
 {
return (__u64) (unsigned long) ptr;
 }
 
-static int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
-  unsigned int size)
+static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
+ unsigned int size)
 {
-#ifdef __NR_bpf
return syscall(__NR_bpf, cmd, attr, size);
-#else
-   fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
-   errno = ENOSYS;
-   return -1;
-#endif
 }
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size,
-- 
2.11.0



[PATCH net-next v5 08/11] bpf: Use bpf_map_get_next_key() from the library

2017-02-09 Thread Mickaël Salaün
Replace bpf_map_next_key() with bpf_map_get_next_key() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  2 +-
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 11 --
 tools/testing/selftests/bpf/test_lru_map.c |  2 +-
 tools/testing/selftests/bpf/test_maps.c| 34 +++---
 5 files changed, 20 insertions(+), 31 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index eab8c6bfbf8f..f8a2b7fa7741 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -135,7 +135,7 @@ int bpf_map_delete_elem(int fd, const void *key)
return sys_bpf(BPF_MAP_DELETE_ELEM, , sizeof(attr));
 }
 
-int bpf_map_get_next_key(int fd, void *key, void *next_key)
+int bpf_map_get_next_key(int fd, const void *key, void *next_key)
 {
union bpf_attr attr;
 
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index f559f648db45..88f07c15423a 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -38,7 +38,7 @@ int bpf_map_update_elem(int fd, const void *key, const void 
*value,
 
 int bpf_map_lookup_elem(int fd, const void *key, void *value);
 int bpf_map_delete_elem(int fd, const void *key);
-int bpf_map_get_next_key(int fd, void *key, void *next_key);
+int bpf_map_get_next_key(int fd, const void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
 int bpf_obj_get(const char *pathname);
 int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 17581a42e1d9..aeff99f0a411 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,17 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_next_key(int fd, const void *key, void *next_key)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-   attr.next_key = bpf_ptr_to_u64(next_key);
-
-   return bpf(BPF_MAP_GET_NEXT_KEY, , sizeof(attr));
-}
-
 static inline int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
 uint32_t size_value, uint32_t max_elem,
 uint32_t flags)
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 859c940a6e41..360f7e006eb6 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -46,7 +46,7 @@ static int map_subset(int map0, int map1)
unsigned long long value0[nr_cpus], value1[nr_cpus];
int ret;
 
-   while (!bpf_map_next_key(map1, _key, _key)) {
+   while (!bpf_map_get_next_key(map1, _key, _key)) {
assert(!bpf_map_lookup_elem(map1, _key, value1));
ret = bpf_map_lookup_elem(map0, _key, value0);
if (ret) {
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index 0f9f90455375..be52c808d6cf 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -89,11 +89,11 @@ static void test_hashmap(int task, void *data)
assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
-   assert(bpf_map_next_key(fd, , _key) == 0 &&
+   assert(bpf_map_get_next_key(fd, , _key) == 0 &&
   (next_key == 1 || next_key == 2));
-   assert(bpf_map_next_key(fd, _key, _key) == 0 &&
+   assert(bpf_map_get_next_key(fd, _key, _key) == 0 &&
   (next_key == 1 || next_key == 2));
-   assert(bpf_map_next_key(fd, _key, _key) == -1 &&
+   assert(bpf_map_get_next_key(fd, _key, _key) == -1 &&
   errno == ENOENT);
 
/* Delete both elements. */
@@ -105,7 +105,7 @@ static void test_hashmap(int task, void *data)
 
key = 0;
/* Check that map is empty. */
-   assert(bpf_map_next_key(fd, , _key) == -1 &&
+   assert(bpf_map_get_next_key(fd, , _key) == -1 &&
   errno == ENOENT);
 
close(fd);
@@ -175,7 +175,7 @@ static void test_hashmap_percpu(int task, void *data)
assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
-   while (!bpf_map_next_key(fd, , _key)) {
+   while (!bpf_map_get_next_key(fd, , _key)) {
assert((expected_key_mask & next_key) == next_key);
expected_key_mask &= ~next_key;
 
@@ -201,7 +201,7 @@ static void test_hashmap_percpu(int task, void *data)
 
key = 0;
/* Check that map is empt

[PATCH net-next v5 00/11] Improve BPF selftests and use the library (net-next tree)

2017-02-09 Thread Mickaël Salaün
This series brings some fixes to selftests, add the ability to test
unprivileged BPF programs as root and replace bpf_sys.h with calls to the BPF
library.

This is intended for the net-next tree and apply on c0e4dadb3494 ("net: dsa:
mv88e6xxx: Move forward declaration to where it is needed").

Changes since v4:
* align text for function calls as requested by Daniel Borkmann
  (bpf_load_program and bpf_map_update_elem)
* rebase

Changes since v3:
* keep the bzero() calls

Changes since v2:
* use the patches from two previous series (unprivileged tests and bpf_sys.h
  replacement)
* include one more stdint.h
* rebase on net-next
* add this cover letter

Changes since v1:
* exclude patches not intended for the net-next tree

Regards,

Mickaël Salaün (11):
  tools: Sync {,tools/}include/uapi/linux/bpf.h
  bpf: Change the include directory for selftest
  bpf: Always test unprivileged programs
  bpf: Use bpf_load_program() from the library
  bpf: Use bpf_map_update_elem() from the library
  bpf: Use bpf_map_lookup_elem() from the library
  bpf: Use bpf_map_delete_elem() from the library
  bpf: Use bpf_map_get_next_key() from the library
  bpf: Use bpf_create_map() from the library
  bpf: Remove bpf_sys.h from selftests
  bpf: Add test_tag to .gitignore

 tools/include/uapi/linux/bpf.h  |  23 +++-
 tools/lib/bpf/bpf.c |  20 ++--
 tools/lib/bpf/bpf.h |  12 +--
 tools/testing/selftests/bpf/.gitignore  |   1 +
 tools/testing/selftests/bpf/Makefile|   4 +-
 tools/testing/selftests/bpf/bpf_sys.h   | 108 ---
 tools/testing/selftests/bpf/test_lpm_map.c  |  38 +++
 tools/testing/selftests/bpf/test_lru_map.c  | 138 +---
 tools/testing/selftests/bpf/test_maps.c | 162 ++--
 tools/testing/selftests/bpf/test_tag.c  |  11 +-
 tools/testing/selftests/bpf/test_verifier.c |  84 ---
 11 files changed, 301 insertions(+), 300 deletions(-)
 delete mode 100644 tools/testing/selftests/bpf/bpf_sys.h

-- 
2.11.0



[PATCH net-next v5 03/11] bpf: Always test unprivileged programs

2017-02-09 Thread Mickaël Salaün
If selftests are run as root, then execute the unprivileged checks as
well. This switch from 243 to 368 tests.

The test numbers are suffixed with "/u" when executed as unprivileged or
with "/p" when executed as privileged.

The geteuid() check is replaced with a capability check.

Handling capabilities requires the libcap dependency.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Acked-by: Alexei Starovoitov <a...@kernel.org>
Acked-by: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/Makefile|  2 +-
 tools/testing/selftests/bpf/test_verifier.c | 68 ++---
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index c470c7301636..f3d65ad53494 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -I../../../include/uapi
+CFLAGS += -Wall -O2 -lcap -I../../../include/uapi
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 71f6407cde60..878bd60da376 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 
+#include 
 #include 
 
 #include 
@@ -4574,6 +4575,55 @@ static void do_test_single(struct bpf_test *test, bool 
unpriv,
goto close_fds;
 }
 
+static bool is_admin(void)
+{
+   cap_t caps;
+   cap_flag_value_t sysadmin = CAP_CLEAR;
+   const cap_value_t cap_val = CAP_SYS_ADMIN;
+
+   if (!CAP_IS_SUPPORTED(CAP_SETFCAP)) {
+   perror("cap_get_flag");
+   return false;
+   }
+   caps = cap_get_proc();
+   if (!caps) {
+   perror("cap_get_proc");
+   return false;
+   }
+   if (cap_get_flag(caps, cap_val, CAP_EFFECTIVE, ))
+   perror("cap_get_flag");
+   if (cap_free(caps))
+   perror("cap_free");
+   return (sysadmin == CAP_SET);
+}
+
+static int set_admin(bool admin)
+{
+   cap_t caps;
+   const cap_value_t cap_val = CAP_SYS_ADMIN;
+   int ret = -1;
+
+   caps = cap_get_proc();
+   if (!caps) {
+   perror("cap_get_proc");
+   return -1;
+   }
+   if (cap_set_flag(caps, CAP_EFFECTIVE, 1, _val,
+   admin ? CAP_SET : CAP_CLEAR)) {
+   perror("cap_set_flag");
+   goto out;
+   }
+   if (cap_set_proc(caps)) {
+   perror("cap_set_proc");
+   goto out;
+   }
+   ret = 0;
+out:
+   if (cap_free(caps))
+   perror("cap_free");
+   return ret;
+}
+
 static int do_test(bool unpriv, unsigned int from, unsigned int to)
 {
int i, passes = 0, errors = 0;
@@ -4584,11 +4634,19 @@ static int do_test(bool unpriv, unsigned int from, 
unsigned int to)
/* Program types that are not supported by non-root we
 * skip right away.
 */
-   if (unpriv && test->prog_type)
-   continue;
+   if (!test->prog_type) {
+   if (!unpriv)
+   set_admin(false);
+   printf("#%d/u %s ", i, test->descr);
+   do_test_single(test, true, , );
+   if (!unpriv)
+   set_admin(true);
+   }
 
-   printf("#%d %s ", i, test->descr);
-   do_test_single(test, unpriv, , );
+   if (!unpriv) {
+   printf("#%d/p %s ", i, test->descr);
+   do_test_single(test, false, , );
+   }
}
 
printf("Summary: %d PASSED, %d FAILED\n", passes, errors);
@@ -4600,7 +4658,7 @@ int main(int argc, char **argv)
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
struct rlimit rlim = { 1 << 20, 1 << 20 };
unsigned int from = 0, to = ARRAY_SIZE(tests);
-   bool unpriv = geteuid() != 0;
+   bool unpriv = !is_admin();
 
if (argc == 3) {
unsigned int l = atoi(argv[argc - 2]);
-- 
2.11.0



[PATCH net-next v5 09/11] bpf: Use bpf_create_map() from the library

2017-02-09 Thread Mickaël Salaün
Replace bpf_map_create() with bpf_create_map() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/bpf_sys.h   | 15 ---
 tools/testing/selftests/bpf/test_lpm_map.c  |  6 +++---
 tools/testing/selftests/bpf/test_lru_map.c  |  4 ++--
 tools/testing/selftests/bpf/test_maps.c | 14 +++---
 tools/testing/selftests/bpf/test_tag.c  |  2 +-
 tools/testing/selftests/bpf/test_verifier.c |  4 ++--
 6 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index aeff99f0a411..aa076a8a07f7 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,19 +24,4 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
-uint32_t size_value, uint32_t max_elem,
-uint32_t flags)
-{
-   union bpf_attr attr = {};
-
-   attr.map_type = type;
-   attr.key_size = size_key;
-   attr.value_size = size_value;
-   attr.max_entries = max_elem;
-   attr.map_flags = flags;
-
-   return bpf(BPF_MAP_CREATE, , sizeof(attr));
-}
-
 #endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index bd08394c26cb..3cc812cac2d7 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -183,7 +183,7 @@ static void test_lpm_map(int keysize)
key = alloca(sizeof(*key) + keysize);
memset(key, 0, sizeof(*key) + keysize);
 
-   map = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE,
+   map = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE,
 sizeof(*key) + keysize,
 keysize + 1,
 4096,
@@ -253,12 +253,12 @@ static void test_lpm_ipaddr(void)
key_ipv4 = alloca(key_size_ipv4);
key_ipv6 = alloca(key_size_ipv6);
 
-   map_fd_ipv4 = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE,
+   map_fd_ipv4 = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE,
 key_size_ipv4, sizeof(value),
 100, BPF_F_NO_PREALLOC);
assert(map_fd_ipv4 >= 0);
 
-   map_fd_ipv6 = bpf_map_create(BPF_MAP_TYPE_LPM_TRIE,
+   map_fd_ipv6 = bpf_create_map(BPF_MAP_TYPE_LPM_TRIE,
 key_size_ipv6, sizeof(value),
 100, BPF_F_NO_PREALLOC);
assert(map_fd_ipv6 >= 0);
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 360f7e006eb6..48973ded1c96 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -31,11 +31,11 @@ static int create_map(int map_type, int map_flags, unsigned 
int size)
 {
int map_fd;
 
-   map_fd = bpf_map_create(map_type, sizeof(unsigned long long),
+   map_fd = bpf_create_map(map_type, sizeof(unsigned long long),
sizeof(unsigned long long), size, map_flags);
 
if (map_fd == -1)
-   perror("bpf_map_create");
+   perror("bpf_create_map");
 
return map_fd;
 }
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index be52c808d6cf..39168499f43f 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -32,7 +32,7 @@ static void test_hashmap(int task, void *data)
long long key, next_key, value;
int fd;
 
-   fd = bpf_map_create(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+   fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
2, map_flags);
if (fd < 0) {
printf("Failed to create hashmap '%s'!\n", strerror(errno));
@@ -119,7 +119,7 @@ static void test_hashmap_percpu(int task, void *data)
int expected_key_mask = 0;
int fd, i;
 
-   fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
+   fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
sizeof(value[0]), 2, map_flags);
if (fd < 0) {
printf("Failed to create hashmap '%s'!\n", strerror(errno));
@@ -212,7 +212,7 @@ static void test_arraymap(int task, void *data)
int key, next_key, fd;
long long value;
 
-   fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
+   fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
2, 0);
if (fd < 0) {
   

[PATCH net-next v5 10/11] bpf: Remove bpf_sys.h from selftests

2017-02-09 Thread Mickaël Salaün
Add require dependency headers.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c |  6 ++
 tools/testing/selftests/bpf/bpf_sys.h   | 27 ---
 tools/testing/selftests/bpf/test_lpm_map.c  |  1 -
 tools/testing/selftests/bpf/test_lru_map.c  |  1 -
 tools/testing/selftests/bpf/test_maps.c |  1 -
 tools/testing/selftests/bpf/test_tag.c  |  3 +--
 tools/testing/selftests/bpf/test_verifier.c |  4 ++--
 7 files changed, 9 insertions(+), 34 deletions(-)
 delete mode 100644 tools/testing/selftests/bpf/bpf_sys.h

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index f8a2b7fa7741..50e04cc5 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -50,7 +50,13 @@ static __u64 ptr_to_u64(const void *ptr)
 static int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
   unsigned int size)
 {
+#ifdef __NR_bpf
return syscall(__NR_bpf, cmd, attr, size);
+#else
+   fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
+   errno = ENOSYS;
+   return -1;
+#endif
 }
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size,
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
deleted file mode 100644
index aa076a8a07f7..
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __BPF_SYS__
-#define __BPF_SYS__
-
-#include 
-#include 
-
-#include 
-
-#include 
-
-static inline __u64 bpf_ptr_to_u64(const void *ptr)
-{
-   return (__u64)(unsigned long) ptr;
-}
-
-static inline int bpf(int cmd, union bpf_attr *attr, unsigned int size)
-{
-#ifdef __NR_bpf
-   return syscall(__NR_bpf, cmd, attr, size);
-#else
-   fprintf(stderr, "No bpf syscall, kernel headers too old?\n");
-   errno = ENOSYS;
-   return -1;
-#endif
-}
-
-#endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index 3cc812cac2d7..e97565243d59 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -23,7 +23,6 @@
 #include 
 
 #include 
-#include "bpf_sys.h"
 #include "bpf_util.h"
 
 struct tlpm_node {
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index 48973ded1c96..00b0aff56e2e 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -19,7 +19,6 @@
 #include 
 
 #include 
-#include "bpf_sys.h"
 #include "bpf_util.h"
 
 #define LOCAL_FREE_TARGET  (128)
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index 39168499f43f..cada17ac00b8 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -22,7 +22,6 @@
 #include 
 
 #include 
-#include "bpf_sys.h"
 #include "bpf_util.h"
 
 static int map_flags;
diff --git a/tools/testing/selftests/bpf/test_tag.c 
b/tools/testing/selftests/bpf/test_tag.c
index ae4263638cd5..de409fc50c35 100644
--- a/tools/testing/selftests/bpf/test_tag.c
+++ b/tools/testing/selftests/bpf/test_tag.c
@@ -1,3 +1,4 @@
+#include 
 #include 
 #include 
 #include 
@@ -20,8 +21,6 @@
 
 #include "../../../include/linux/filter.h"
 
-#include "bpf_sys.h"
-
 static struct bpf_insn prog[BPF_MAXINSNS];
 
 static void bpf_gen_imm_prog(unsigned int insns, int fd_map)
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 63818cbb9fb1..e1f5b9eea1e8 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -8,7 +8,9 @@
  * License as published by the Free Software Foundation.
  */
 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -28,8 +30,6 @@
 
 #include "../../../include/linux/filter.h"
 
-#include "bpf_sys.h"
-
 #ifndef ARRAY_SIZE
 # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #endif
-- 
2.11.0



[PATCH net-next v5 04/11] bpf: Use bpf_load_program() from the library

2017-02-09 Thread Mickaël Salaün
Replace bpf_prog_load() with bpf_load_program() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c |  6 +++---
 tools/lib/bpf/bpf.h |  4 ++--
 tools/testing/selftests/bpf/Makefile|  4 +++-
 tools/testing/selftests/bpf/bpf_sys.h   | 21 -
 tools/testing/selftests/bpf/test_tag.c  |  6 --
 tools/testing/selftests/bpf/test_verifier.c |  8 +---
 6 files changed, 17 insertions(+), 32 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 3ddb58a36d3c..58ce252073fa 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -42,7 +42,7 @@
 # endif
 #endif
 
-static __u64 ptr_to_u64(void *ptr)
+static __u64 ptr_to_u64(const void *ptr)
 {
return (__u64) (unsigned long) ptr;
 }
@@ -69,8 +69,8 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size,
return sys_bpf(BPF_MAP_CREATE, , sizeof(attr));
 }
 
-int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
-size_t insns_cnt, char *license,
+int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
+size_t insns_cnt, const char *license,
 __u32 kern_version, char *log_buf, size_t log_buf_sz)
 {
int fd;
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index a2f9853dd882..bc959a2de023 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -28,8 +28,8 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, 
int value_size,
 
 /* Recommend log buffer size */
 #define BPF_LOG_BUF_SIZE 65536
-int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
-size_t insns_cnt, char *license,
+int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
+size_t insns_cnt, const char *license,
 __u32 kern_version, char *log_buf,
 size_t log_buf_sz);
 
diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index f3d65ad53494..a35f564f66a1 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -lcap -I../../../include/uapi
+CFLAGS += -Wall -O2 -lcap -I../../../include/uapi -I../../../lib
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
@@ -7,6 +7,8 @@ TEST_FILES := $(test_objs)
 
 all: $(test_objs)
 
+$(test_objs): ../../../lib/bpf/bpf.o
+
 include ../lib.mk
 
 clean:
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 6b4565f2a3f2..e7bbe3e5402e 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -84,25 +84,4 @@ static inline int bpf_map_create(enum bpf_map_type type, 
uint32_t size_key,
return bpf(BPF_MAP_CREATE, , sizeof(attr));
 }
 
-static inline int bpf_prog_load(enum bpf_prog_type type,
-   const struct bpf_insn *insns, size_t size_insns,
-   const char *license, char *log, size_t size_log)
-{
-   union bpf_attr attr = {};
-
-   attr.prog_type = type;
-   attr.insns = bpf_ptr_to_u64(insns);
-   attr.insn_cnt = size_insns / sizeof(struct bpf_insn);
-   attr.license = bpf_ptr_to_u64(license);
-
-   if (size_log > 0) {
-   attr.log_buf = bpf_ptr_to_u64(log);
-   attr.log_size = size_log;
-   attr.log_level = 1;
-   log[0] = 0;
-   }
-
-   return bpf(BPF_PROG_LOAD, , sizeof(attr));
-}
-
 #endif /* __BPF_SYS__ */
diff --git a/tools/testing/selftests/bpf/test_tag.c 
b/tools/testing/selftests/bpf/test_tag.c
index 5f7c602f47d1..dc209721ffd5 100644
--- a/tools/testing/selftests/bpf/test_tag.c
+++ b/tools/testing/selftests/bpf/test_tag.c
@@ -16,6 +16,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../../../include/linux/filter.h"
 
 #include "bpf_sys.h"
@@ -55,8 +57,8 @@ static int bpf_try_load_prog(int insns, int fd_map,
int fd_prog;
 
bpf_filler(insns, fd_map);
-   fd_prog = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, prog, insns *
-   sizeof(struct bpf_insn), "", NULL, 0);
+   fd_prog = bpf_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0,
+  NULL, 0);
assert(fd_prog > 0);
if (fd_map > 0)
bpf_filler(insns, 0);
diff --git a/tools/testing/selftests/bpf/test_verifier.c 
b/tools/testing/selftests/bpf/test_verifier.c
index 878bd60da376..247830ecf68e 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -24,6 +24,8 @@
 #include 
 #include 
 
+#include 
+
 #include "../../.

[PATCH net-next v5 05/11] bpf: Use bpf_map_update_elem() from the library

2017-02-09 Thread Mickaël Salaün
Replace bpf_map_update() with bpf_map_update_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  2 +-
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 13 
 tools/testing/selftests/bpf/test_lpm_map.c | 15 ++---
 tools/testing/selftests/bpf/test_lru_map.c | 97 +-
 tools/testing/selftests/bpf/test_maps.c| 61 ++-
 6 files changed, 99 insertions(+), 91 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 58ce252073fa..1de762677a2f 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -98,7 +98,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct 
bpf_insn *insns,
return sys_bpf(BPF_PROG_LOAD, , sizeof(attr));
 }
 
-int bpf_map_update_elem(int fd, void *key, void *value,
+int bpf_map_update_elem(int fd, const void *key, const void *value,
__u64 flags)
 {
union bpf_attr attr;
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index bc959a2de023..2458534c8b33 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -33,7 +33,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct 
bpf_insn *insns,
 __u32 kern_version, char *log_buf,
 size_t log_buf_sz);
 
-int bpf_map_update_elem(int fd, void *key, void *value,
+int bpf_map_update_elem(int fd, const void *key, const void *value,
__u64 flags);
 
 int bpf_map_lookup_elem(int fd, void *key, void *value);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index e7bbe3e5402e..e08dec0db9e0 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -35,19 +35,6 @@ static inline int bpf_map_lookup(int fd, const void *key, 
void *value)
return bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
 }
 
-static inline int bpf_map_update(int fd, const void *key, const void *value,
-uint64_t flags)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-   attr.value = bpf_ptr_to_u64(value);
-   attr.flags = flags;
-
-   return bpf(BPF_MAP_UPDATE_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_delete(int fd, const void *key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index 26775c00273f..e29ffbcd2932 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 
+#include 
 #include "bpf_sys.h"
 #include "bpf_util.h"
 
@@ -198,7 +199,7 @@ static void test_lpm_map(int keysize)
 
key->prefixlen = value[keysize];
memcpy(key->data, value, keysize);
-   r = bpf_map_update(map, key, value, 0);
+   r = bpf_map_update_elem(map, key, value, 0);
assert(!r);
}
 
@@ -266,32 +267,32 @@ static void test_lpm_ipaddr(void)
value = 1;
key_ipv4->prefixlen = 16;
inet_pton(AF_INET, "192.168.0.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 2;
key_ipv4->prefixlen = 24;
inet_pton(AF_INET, "192.168.0.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 3;
key_ipv4->prefixlen = 24;
inet_pton(AF_INET, "192.168.128.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 5;
key_ipv4->prefixlen = 24;
inet_pton(AF_INET, "192.168.1.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 4;
key_ipv4->prefixlen = 23;
inet_pton(AF_INET, "192.168.0.0", key_ipv4->data);
-   assert(bpf_map_update(map_fd_ipv4, key_ipv4, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv4, key_ipv4, , 0) == 0);
 
value = 0xdeadbeef;
key_ipv6->prefixlen = 64;
inet_pton(AF_INET6, "2a00:1450:4001:814::200e", key_ipv6->data);
-   assert(bpf_map_update(map_fd_ipv6, key_ipv6, , 0) == 0);
+   assert(bpf_map_update_elem(map_fd_ipv6, key_ipv6, , 0) == 0);
 
/* Set tprefixlen to maximum for lookups */
key_ipv4->p

[PATCH net-next v5 06/11] bpf: Use bpf_map_lookup_elem() from the library

2017-02-09 Thread Mickaël Salaün
Replace bpf_map_lookup() with bpf_map_lookup_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  2 +-
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 11 ---
 tools/testing/selftests/bpf/test_lpm_map.c | 16 
 tools/testing/selftests/bpf/test_lru_map.c | 28 ++--
 tools/testing/selftests/bpf/test_maps.c| 30 +++---
 6 files changed, 39 insertions(+), 50 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 1de762677a2f..b1a1f58b99e0 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -112,7 +112,7 @@ int bpf_map_update_elem(int fd, const void *key, const void 
*value,
return sys_bpf(BPF_MAP_UPDATE_ELEM, , sizeof(attr));
 }
 
-int bpf_map_lookup_elem(int fd, void *key, void *value)
+int bpf_map_lookup_elem(int fd, const void *key, void *value)
 {
union bpf_attr attr;
 
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 2458534c8b33..171cf594f782 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -36,7 +36,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct 
bpf_insn *insns,
 int bpf_map_update_elem(int fd, const void *key, const void *value,
__u64 flags);
 
-int bpf_map_lookup_elem(int fd, void *key, void *value);
+int bpf_map_lookup_elem(int fd, const void *key, void *value);
 int bpf_map_delete_elem(int fd, void *key);
 int bpf_map_get_next_key(int fd, void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index e08dec0db9e0..0a5a6060db70 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,17 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_lookup(int fd, const void *key, void *value)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-   attr.value = bpf_ptr_to_u64(value);
-
-   return bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_delete(int fd, const void *key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lpm_map.c 
b/tools/testing/selftests/bpf/test_lpm_map.c
index e29ffbcd2932..bd08394c26cb 100644
--- a/tools/testing/selftests/bpf/test_lpm_map.c
+++ b/tools/testing/selftests/bpf/test_lpm_map.c
@@ -211,7 +211,7 @@ static void test_lpm_map(int keysize)
 
key->prefixlen = 8 * keysize;
memcpy(key->data, data, keysize);
-   r = bpf_map_lookup(map, key, value);
+   r = bpf_map_lookup_elem(map, key, value);
assert(!r || errno == ENOENT);
assert(!t == !!r);
 
@@ -300,32 +300,32 @@ static void test_lpm_ipaddr(void)
 
/* Test some lookups that should come back with a value */
inet_pton(AF_INET, "192.168.128.23", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == 0);
assert(value == 3);
 
inet_pton(AF_INET, "192.168.0.1", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == 0);
assert(value == 2);
 
inet_pton(AF_INET6, "2a00:1450:4001:814::", key_ipv6->data);
-   assert(bpf_map_lookup(map_fd_ipv6, key_ipv6, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, ) == 0);
assert(value == 0xdeadbeef);
 
inet_pton(AF_INET6, "2a00:1450:4001:814::1", key_ipv6->data);
-   assert(bpf_map_lookup(map_fd_ipv6, key_ipv6, ) == 0);
+   assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, ) == 0);
assert(value == 0xdeadbeef);
 
/* Test some lookups that should not match any entry */
inet_pton(AF_INET, "10.0.0.1", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == -1 &&
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == -1 &&
   errno == ENOENT);
 
inet_pton(AF_INET, "11.11.11.11", key_ipv4->data);
-   assert(bpf_map_lookup(map_fd_ipv4, key_ipv4, ) == -1 &&
+   assert(bpf_map_lookup_elem(map_fd_ipv4, key_ipv4, ) == -1 &&
   errno == ENOENT);
 
inet_pton(AF_INET6, "2a00:::", key_ipv6->data);
-   assert(bpf_map_lookup(map_fd_ipv6, key_ipv6, ) == -1 &&
+   assert(bpf_map_lookup_elem(map_fd_ipv6, key_ipv6, ) == -1 &&
   errno == ENOE

[PATCH net-next v5 11/11] bpf: Add test_tag to .gitignore

2017-02-09 Thread Mickaël Salaün
Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/testing/selftests/bpf/.gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/testing/selftests/bpf/.gitignore 
b/tools/testing/selftests/bpf/.gitignore
index d3b1c9bca407..541d9d7fad5a 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -2,3 +2,4 @@ test_verifier
 test_maps
 test_lru_map
 test_lpm_map
+test_tag
-- 
2.11.0



[PATCH net-next v5 01/11] tools: Sync {,tools/}include/uapi/linux/bpf.h

2017-02-09 Thread Mickaël Salaün
The tools version of this header is out of date; update it to the latest
version from kernel header.

Synchronize with the following commits:
* b95a5c4db09b ("bpf: add a longest prefix match trie map implementation")
* a5e8c07059d0 ("bpf: add bpf_probe_read_str helper")
* d1b662adcdb8 ("bpf: allow option for setting bpf_l4_csum_replace from 
scratch")

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Daniel Mack <dan...@zonque.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Gianluca Borello <g.bore...@gmail.com>
---
 tools/include/uapi/linux/bpf.h | 23 ++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0eb0e87dbe9f..e07fd5a324e6 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -63,6 +63,12 @@ struct bpf_insn {
__s32   imm;/* signed immediate constant */
 };
 
+/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
+struct bpf_lpm_trie_key {
+   __u32   prefixlen;  /* up to 32 for AF_INET, 128 for AF_INET6 */
+   __u8data[0];/* Arbitrary size */
+};
+
 /* BPF syscall commands, see bpf(2) man-page for details. */
 enum bpf_cmd {
BPF_MAP_CREATE,
@@ -89,6 +95,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_CGROUP_ARRAY,
BPF_MAP_TYPE_LRU_HASH,
BPF_MAP_TYPE_LRU_PERCPU_HASH,
+   BPF_MAP_TYPE_LPM_TRIE,
 };
 
 enum bpf_prog_type {
@@ -430,6 +437,18 @@ union bpf_attr {
  * @xdp_md: pointer to xdp_md
  * @delta: An positive/negative integer to be added to xdp_md.data
  * Return: 0 on success or negative on error
+ *
+ * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+ * Copy a NUL terminated string from unsafe address. In case the string
+ * length is smaller than size, the target is not padded with further NUL
+ * bytes. In case the string length is larger than size, just count-1
+ * bytes are copied and the last byte is set to NUL.
+ * @dst: destination address
+ * @size: maximum number of bytes to copy, including the trailing NUL
+ * @unsafe_ptr: unsafe address
+ * Return:
+ *   > 0 length of the string including the trailing NUL on success
+ *   < 0 error
  */
 #define __BPF_FUNC_MAPPER(FN)  \
FN(unspec), \
@@ -476,7 +495,8 @@ union bpf_attr {
FN(set_hash_invalid),   \
FN(get_numa_node_id),   \
FN(skb_change_head),\
-   FN(xdp_adjust_head),
+   FN(xdp_adjust_head),\
+   FN(probe_read_str),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
@@ -502,6 +522,7 @@ enum bpf_func_id {
 /* BPF_FUNC_l4_csum_replace flags. */
 #define BPF_F_PSEUDO_HDR   (1ULL << 4)
 #define BPF_F_MARK_MANGLED_0   (1ULL << 5)
+#define BPF_F_MARK_ENFORCE (1ULL << 6)
 
 /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
 #define BPF_F_INGRESS  (1ULL << 0)
-- 
2.11.0



[PATCH net-next v5 07/11] bpf: Use bpf_map_delete_elem() from the library

2017-02-09 Thread Mickaël Salaün
Replace bpf_map_delete() with bpf_map_delete_elem() calls.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Shuah Khan <sh...@kernel.org>
---
 tools/lib/bpf/bpf.c|  2 +-
 tools/lib/bpf/bpf.h|  2 +-
 tools/testing/selftests/bpf/bpf_sys.h  | 10 --
 tools/testing/selftests/bpf/test_lru_map.c |  6 +++---
 tools/testing/selftests/bpf/test_maps.c| 22 +++---
 5 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index b1a1f58b99e0..eab8c6bfbf8f 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -124,7 +124,7 @@ int bpf_map_lookup_elem(int fd, const void *key, void 
*value)
return sys_bpf(BPF_MAP_LOOKUP_ELEM, , sizeof(attr));
 }
 
-int bpf_map_delete_elem(int fd, void *key)
+int bpf_map_delete_elem(int fd, const void *key)
 {
union bpf_attr attr;
 
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 171cf594f782..f559f648db45 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -37,7 +37,7 @@ int bpf_map_update_elem(int fd, const void *key, const void 
*value,
__u64 flags);
 
 int bpf_map_lookup_elem(int fd, const void *key, void *value);
-int bpf_map_delete_elem(int fd, void *key);
+int bpf_map_delete_elem(int fd, const void *key);
 int bpf_map_get_next_key(int fd, void *key, void *next_key);
 int bpf_obj_pin(int fd, const char *pathname);
 int bpf_obj_get(const char *pathname);
diff --git a/tools/testing/selftests/bpf/bpf_sys.h 
b/tools/testing/selftests/bpf/bpf_sys.h
index 0a5a6060db70..17581a42e1d9 100644
--- a/tools/testing/selftests/bpf/bpf_sys.h
+++ b/tools/testing/selftests/bpf/bpf_sys.h
@@ -24,16 +24,6 @@ static inline int bpf(int cmd, union bpf_attr *attr, 
unsigned int size)
 #endif
 }
 
-static inline int bpf_map_delete(int fd, const void *key)
-{
-   union bpf_attr attr = {};
-
-   attr.map_fd = fd;
-   attr.key = bpf_ptr_to_u64(key);
-
-   return bpf(BPF_MAP_DELETE_ELEM, , sizeof(attr));
-}
-
 static inline int bpf_map_next_key(int fd, const void *key, void *next_key)
 {
union bpf_attr attr = {};
diff --git a/tools/testing/selftests/bpf/test_lru_map.c 
b/tools/testing/selftests/bpf/test_lru_map.c
index eccf6d96e551..859c940a6e41 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -324,7 +324,7 @@ static void test_lru_sanity2(int map_type, int map_flags, 
unsigned int tgt_free)
if (map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
assert(!bpf_map_update_elem(lru_map_fd, , value,
BPF_NOEXIST));
-   assert(!bpf_map_delete(lru_map_fd, ));
+   assert(!bpf_map_delete_elem(lru_map_fd, ));
} else {
assert(bpf_map_update_elem(lru_map_fd, , value,
   BPF_EXIST));
@@ -483,8 +483,8 @@ static void test_lru_sanity4(int map_type, int map_flags, 
unsigned int tgt_free)
}
 
for (; key <= 2 * tgt_free; key++) {
-   assert(!bpf_map_delete(lru_map_fd, ));
-   assert(bpf_map_delete(lru_map_fd, ));
+   assert(!bpf_map_delete_elem(lru_map_fd, ));
+   assert(bpf_map_delete_elem(lru_map_fd, ));
}
 
end_key = key + 2 * tgt_free;
diff --git a/tools/testing/selftests/bpf/test_maps.c 
b/tools/testing/selftests/bpf/test_maps.c
index 5db1a939af69..0f9f90455375 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -86,7 +86,7 @@ static void test_hashmap(int task, void *data)
 
/* Check that key = 0 doesn't exist. */
key = 0;
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
assert(bpf_map_next_key(fd, , _key) == 0 &&
@@ -98,10 +98,10 @@ static void test_hashmap(int task, void *data)
 
/* Delete both elements. */
key = 1;
-   assert(bpf_map_delete(fd, ) == 0);
+   assert(bpf_map_delete_elem(fd, ) == 0);
key = 2;
-   assert(bpf_map_delete(fd, ) == 0);
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == 0);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
key = 0;
/* Check that map is empty. */
@@ -172,7 +172,7 @@ static void test_hashmap_percpu(int task, void *data)
   errno == E2BIG);
 
/* Check that key = 0 doesn't exist. */
-   assert(bpf_map_delete(fd, ) == -1 && errno == ENOENT);
+   assert(bpf_map_delete_elem(fd, ) == -1 && errno == ENOENT);
 
/* Iterate over two elements. */
while (!bpf_map_nex

[PATCH net-next v5 02/11] bpf: Change the include directory for selftest

2017-02-09 Thread Mickaël Salaün
Use the tools include directory instead of the installed one to allow
builds from other kernels.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 tools/testing/selftests/bpf/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/Makefile 
b/tools/testing/selftests/bpf/Makefile
index 769a6cb42b4b..c470c7301636 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,4 +1,4 @@
-CFLAGS += -Wall -O2 -I../../../../usr/include
+CFLAGS += -Wall -O2 -I../../../include/uapi
 
 test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map
 
-- 
2.11.0



[PATCH v1] samples/bpf: Add a .gitignore for binaries

2017-02-12 Thread Mickaël Salaün
Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@fb.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Wang Nan <wangn...@huawei.com>
---
 samples/bpf/.gitignore | 32 
 1 file changed, 32 insertions(+)
 create mode 100644 samples/bpf/.gitignore

diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
new file mode 100644
index ..a7562a5ef4c2
--- /dev/null
+++ b/samples/bpf/.gitignore
@@ -0,0 +1,32 @@
+fds_example
+lathist
+lwt_len_hist
+map_perf_test
+offwaketime
+sampleip
+sockex1
+sockex2
+sockex3
+sock_example
+spintest
+tc_l2_redirect
+test_cgrp2_array_pin
+test_cgrp2_attach
+test_cgrp2_attach2
+test_cgrp2_sock
+test_cgrp2_sock2
+test_current_task_under_cgroup
+test_lru_dist
+test_overhead
+test_probe_write_user
+trace_event
+trace_output
+tracex1
+tracex2
+tracex3
+tracex4
+tracex5
+tracex6
+xdp1
+xdp2
+xdp_tx_iptunnel
-- 
2.11.0



Re: Potential issues (security and otherwise) with the current cgroup-bpf API

2017-01-18 Thread Mickaël Salaün

On 19/01/2017 01:18, Andy Lutomirski wrote:
>>> it explicitly respects the cgroup hierarchy.  It shows up in
>>> /proc/cgroups, and I had no problem mounting a cgroupfs instance with
>>> perf_event enabled.  So I'm not sure what you mean.
>>
>> That all it's doing is providing membership information.
> 
> But it's doing it wrong!  Even perf_event tests for membership in a
> given cgroup *or one of its descendents*.  This code does not.
> 
> I think the moral of the story here is that there are lots of open
> questions and design work to be done and that this feature really
> isn't ready to be stable.  For Landlock, I believe that it really
> needs to be done right and I will put my foot down and NAK any effort
> to have Landlock available in a released kernel without resolving
> these types of issues first.  Does anyone really want Landlock to work
> differently than the net hooks simply because the net hooks were in a
> rush?

About Landlock, there is two use cases:

The first is to allow unprivileged users to tie eBPF programs (rules) to
processes. This is the (final) goal. In this case, a (cgroup) hierarchy
is mandatory, otherwise it would be trivial to defeat any access rule.
This is the same issue with namespaces.

The second use case is to only allow privileged users to tie eBPF
programs to processes. As discussed, this will be the next series,
preceding the unprivileged series. In this privilege case, only root
(global CAP_SYS_ADMIN, no namespaces) may be able to use Landlock. Not
having a hierarchy is not a security issue (only a practical one).

The first/next Landlock series (in February) will focus on process
hierarchies (without cgroup), a la seccomp-bpf. It would be too
confusing to not use an inheritable hierarchy like seccomp does, even in
a privileged-only first approach. The inherited rules should then behave
similarly to the seccomp-bpf filters.

However, the following series focusing on cgroup could keep the current
cgroup-bpf behavior, without hierarchy. I don't like the non-hierarchy
approach very much because it add another (less flexible and more
confusing) way to do things (for Landlock at least), but I'm willing to
do it if needed.

Regards,
 Mickaël



signature.asc
Description: OpenPGP digital signature


Re: [PATCH v5 03/10] bpf: Define handle_fs and add a new helper bpf_handle_fs_get_mode()

2017-03-01 Thread Mickaël Salaün

On 01/03/2017 10:32, James Morris wrote:
> On Wed, 22 Feb 2017, Mickaël Salaün wrote:
> 
>> Add an eBPF function bpf_handle_fs_get_mode(handle_fs) to get the mode
>> of a an abstract object wrapping either a file, a dentry, a path, or an
>> inode.
>>
>> Changes since v4:
>> * use a file abstraction (handle) to wrap inode, dentry, path and file
>>   structs
> 
> Good to see these abstractions.  As discussed at LPC, we need to ensure 
> that we don't couple the Landlock API too closely with the LSM API, as the 
> former is an ABI exposed to userland -- we don't want to lose the ability 
> to change LSM internally due to breaking Landlock policies.

Right, it is the case now, especially with the Landlock events.

> 
>> @@ -82,6 +87,8 @@ enum bpf_arg_type {
>>  
>>  ARG_PTR_TO_CTX, /* pointer to context */
>>  ARG_ANYTHING,   /* any (initialized) argument is ok */
>> +
>> +ARG_CONST_PTR_TO_HANDLE_FS, /* pointer to an abstract FS struct */
>>  };
> 
> Extraneous whitespace?

It is on purpose, following the same rules as used for this enum.

 Mickaël



signature.asc
Description: OpenPGP digital signature


Re: [PATCH v5 06/10] seccomp,landlock: Handle Landlock events per process hierarchy

2017-03-01 Thread Mickaël Salaün


On 01/03/2017 23:20, Andy Lutomirski wrote:
> On Wed, Mar 1, 2017 at 2:14 PM, Mickaël Salaün <m...@digikod.net> wrote:
>>
>> On 28/02/2017 21:01, Andy Lutomirski wrote:
>>> On Tue, Feb 21, 2017 at 5:26 PM, Mickaël Salaün <m...@digikod.net> wrote:
>>>> The seccomp(2) syscall can be use to apply a Landlock rule to the
>>>> current process. As with a seccomp filter, the Landlock rule is enforced
>>>> for all its future children. An inherited rule tree can be updated
>>>> (append-only) by the owner of inherited Landlock nodes (e.g. a parent
>>>> process that create a new rule)
>>>
>>> Can you clarify exaclty what this type of update does?  Is it
>>> something that should be supported by normal seccomp rules as well?
>>
>> There is two main structures involved here: struct landlock_node and
>> struct landlock_rule, both defined in include/linux/landlock.h [02/10].
>>
>> Let's take an example with seccomp filter and then Landlock:
>> * seccomp filter: Process P1 creates and applies a seccomp filter F1 to
>> itself. Then it forks and creates a child P2, which inherits P1's
>> filters, hence F1. Now, if P1 add a new seccomp filter F2 to itself, P2
>> *won't get it*. The P2's filter list will still only contains F1 but not
>> F2. If P2 sets up and applies a new filter F3 to itself, its filter list
>> will contains F1 and F3.
>> * Landlock: Process P1 creates and applies a Landlock rule R1 to itself.
>> Underneath the kernel creates a new node N1 dedicated to P1, which
>> contains all its rules. Then P1 forks and creates a child P2, which
>> inherits P1's rules, hence R1. Underneath P2 inherited N1. Now, if P1
>> add a new Landlock rule R2 to itself, P2 *will get it* as well (because
>> R2 is part of N1). If P2 creates and applies a new rule R3 to itself,
>> its rules will contains R1, R2 and R3. Underneath the kernel created a
>> new node N2 for P2, which only contains R3 but inherits/links to N1.
>>
>> This design makes it possible for a process to add more constraints to
>> its children on the fly. I think it is a good feature to have and a
>> safer default inheritance mechanism, but it could be guarded by an
>> option flag if we want both mechanism to be available. The same design
>> could be used by seccomp filter too.
>>
> 
> Then let's do it right.
> 
> Currently each task has an array of seccomp filter layers.  When a
> task forks, the child inherits the layers.  All the layers are
> presently immutable.  With Landlock, a layer can logically be a
> syscall fitler layer or a Landlock layer.  This fits in to the
> existing model just fine.
> 
> If we want to have an interface to allow modification of an existing
> layer, let's make it so that, when a layer is added, you have to
> specify a flag to make the layer modifiable (by current, presumably,
> although I can imagine other policies down the road).  Then have a
> separate API that modifies a layer.
> 
> IOW, I think your patch is bad for three reasons, all fixable:
> 
> 1. The default is wrong.  A layer should be immutable to avoid an easy
> attack in which you try to sandbox *yourself* and then you just modify
> the layer to weaken it.

This is not possible, there is only an operation for now:
SECCOMP_ADD_LANDLOCK_RULE. You can only add more rules to the list (as
for seccomp filter). There is no way to weaken a sandbox. The question
is: how do we want to handle the rules *tree* (from the kernel point of
view)?

> 
> 2. The API that adds a layer should be different from the API that
> modifies a layer.

Right, but it doesn't apply now because we can only add rules.

> 
> 3. The whole modification mechanism should be a separate patch to be
> reviewed on its own merits.

For a rule *replacement*, sure!

> 
>> The current inheritance mechanism doesn't enable to only add a rule to
>> the current process. The rule will be inherited by its children
>> (starting from the children created after the first applied rule). An
>> option flag NEW_RULE_HIERARCHY (or maybe another seccomp operation)
>> could enable to create a new node for the current process, and then
>> makes it not inherited by the previous children.
> 
> I like my proposal above much better.  "Add a layer" and "change a
> layer" should be different operations.

I agree, but for now it's about how to handle immutable (but growing)
inherited rules.



signature.asc
Description: OpenPGP digital signature


[RFC v2 05/10] seccomp: Handle Landlock

2016-08-25 Thread Mickaël Salaün
A Landlock program can be triggered when a seccomp filter return
RET_LANDLOCK. Moreover, it is possible to return a 16-bit cookie which
will be readable by the Landlock programs.

Only seccomp filters loaded from the same thread and before a Landlock
program can trigger it. Multiple Landlock programs can be triggered by
one or more seccomp filters. This way, each RET_LANDLOCK (with specific
cookie) will trigger all the allowed Landlock programs once.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
Cc: Andrew Morton <a...@linux-foundation.org>
---
 include/linux/seccomp.h  |  49 +++
 include/uapi/linux/seccomp.h |   2 +
 kernel/fork.c|  39 -
 kernel/seccomp.c | 190 ++-
 4 files changed, 275 insertions(+), 5 deletions(-)

diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 29b20fe8fd4d..785ccbebf687 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -10,7 +10,33 @@
 #include 
 #include 
 
+#ifdef CONFIG_SECURITY_LANDLOCK
+#include  /* struct bpf_prog */
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 struct seccomp_filter;
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+struct seccomp_landlock_ret {
+   struct seccomp_landlock_ret *prev;
+   /* @filter points to a @landlock_filter list */
+   struct seccomp_filter *filter;
+   u16 cookie;
+   bool triggered;
+};
+
+struct seccomp_landlock_prog {
+   atomic_t usage;
+   struct seccomp_landlock_prog *prev;
+   /*
+* List of filters (through filter->landlock_prev) allowed to trigger
+* this Landlock program.
+*/
+   struct seccomp_filter *filter;
+   struct bpf_prog *prog;
+};
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 /**
  * struct seccomp - the state of a seccomp'ed process
  *
@@ -18,6 +44,10 @@ struct seccomp_filter;
  * system calls available to a process.
  * @filter: must always point to a valid seccomp-filter or NULL as it is
  *  accessed without locking during system call entry.
+ * @landlock_filter: list of filters allowed to trigger an associated
+ *Landlock hook via a RET_LANDLOCK.
+ * @landlock_ret: stored values from a RET_LANDLOCK.
+ * @landlock_prog: list of Landlock programs.
  *
  *  @filter must only be accessed from the context of current as there
  *  is no read locking.
@@ -25,6 +55,12 @@ struct seccomp_filter;
 struct seccomp {
int mode;
struct seccomp_filter *filter;
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+   struct seccomp_filter *landlock_filter;
+   struct seccomp_landlock_ret *landlock_ret;
+   struct seccomp_landlock_prog *landlock_prog;
+#endif /* CONFIG_SECURITY_LANDLOCK */
 };
 
 #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
@@ -85,6 +121,12 @@ static inline int seccomp_mode(struct seccomp *s)
 #ifdef CONFIG_SECCOMP_FILTER
 extern void put_seccomp(struct task_struct *tsk);
 extern void get_seccomp_filter(struct task_struct *tsk);
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void put_landlock_ret(struct seccomp_landlock_ret *landlock_ret);
+extern struct seccomp_landlock_ret *dup_landlock_ret(
+   struct seccomp_landlock_ret *ret_orig);
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 #else  /* CONFIG_SECCOMP_FILTER */
 static inline void put_seccomp(struct task_struct *tsk)
 {
@@ -95,6 +137,13 @@ static inline void get_seccomp_filter(struct task_struct 
*tsk)
 {
return;
 }
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+static inline void put_landlock_ret(struct seccomp_landlock_ret *landlock_ret) 
{}
+static inline struct seccomp_landlock_ret *dup_landlock_ret(
+   struct seccomp_landlock_ret *ret_orig) {}
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 #endif /* CONFIG_SECCOMP_FILTER */
 
 #if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE)
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 0f238a43ff1e..b4aab1c19b8a 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -13,6 +13,7 @@
 /* Valid operations for seccomp syscall. */
 #define SECCOMP_SET_MODE_STRICT0
 #define SECCOMP_SET_MODE_FILTER1
+#define SECCOMP_SET_LANDLOCK_HOOK  2
 
 /* Valid flags for SECCOMP_SET_MODE_FILTER */
 #define SECCOMP_FILTER_FLAG_TSYNC  1
@@ -28,6 +29,7 @@
 #define SECCOMP_RET_KILL   0xU /* kill the task immediately */
 #define SECCOMP_RET_TRAP   0x0003U /* disallow and force a SIGSYS */
 #define SECCOMP_RET_ERRNO  0x0005U /* returns an errno */
+#define SECCOMP_RET_LANDLOCK   0x0007U /* trigger LSM evaluation */
 #define SECCOMP_RET_TRACE  0x7ff0U /* pass to a tracer or disallow */
 #define SECCOMP_RET_ALLOW  0x7fffU /* allow */
 
diff --git a/kernel/fork.c b/kernel/fork.c
index b23a71ec8003..3658c1e95e0

[RFC v2 04/10] seccomp: Split put_seccomp_filter() with put_seccomp()

2016-08-25 Thread Mickaël Salaün
The semantic is unchanged. This will be useful for the Landlock
integration with seccomp (next commit).

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
---
 include/linux/seccomp.h |  5 +++--
 kernel/fork.c   |  2 +-
 kernel/seccomp.c| 18 +-
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 2296e6b2f690..29b20fe8fd4d 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -83,13 +83,14 @@ static inline int seccomp_mode(struct seccomp *s)
 #endif /* CONFIG_SECCOMP */
 
 #ifdef CONFIG_SECCOMP_FILTER
-extern void put_seccomp_filter(struct task_struct *tsk);
+extern void put_seccomp(struct task_struct *tsk);
 extern void get_seccomp_filter(struct task_struct *tsk);
 #else  /* CONFIG_SECCOMP_FILTER */
-static inline void put_seccomp_filter(struct task_struct *tsk)
+static inline void put_seccomp(struct task_struct *tsk)
 {
return;
 }
+
 static inline void get_seccomp_filter(struct task_struct *tsk)
 {
return;
diff --git a/kernel/fork.c b/kernel/fork.c
index 4a7ec0c6c88c..b23a71ec8003 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -235,7 +235,7 @@ void free_task(struct task_struct *tsk)
free_thread_stack(tsk->stack);
rt_mutex_debug_task_free(tsk);
ftrace_graph_exit_task(tsk);
-   put_seccomp_filter(tsk);
+   put_seccomp(tsk);
arch_release_task_struct(tsk);
free_task_struct(tsk);
 }
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 7002796f14a4..f1f475691c27 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -60,6 +60,8 @@ struct seccomp_filter {
struct bpf_prog *prog;
 };
 
+static void put_seccomp_filter(struct seccomp_filter *filter);
+
 /* Limit any path through the tree to 256KB worth of instructions. */
 #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
 
@@ -313,7 +315,7 @@ static inline void seccomp_sync_threads(void)
 * current's path will hold a reference.  (This also
 * allows a put before the assignment.)
 */
-   put_seccomp_filter(thread);
+   put_seccomp_filter(thread->seccomp.filter);
smp_store_release(>seccomp.filter,
  caller->seccomp.filter);
 
@@ -475,10 +477,11 @@ static inline void seccomp_filter_free(struct 
seccomp_filter *filter)
}
 }
 
-/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
-void put_seccomp_filter(struct task_struct *tsk)
+/* put_seccomp_filter - decrements the ref count of a filter */
+static void put_seccomp_filter(struct seccomp_filter *filter)
 {
-   struct seccomp_filter *orig = tsk->seccomp.filter;
+   struct seccomp_filter *orig = filter;
+
/* Clean up single-reference branches iteratively. */
while (orig && atomic_dec_and_test(>usage)) {
struct seccomp_filter *freeme = orig;
@@ -487,6 +490,11 @@ void put_seccomp_filter(struct task_struct *tsk)
}
 }
 
+void put_seccomp(struct task_struct *tsk)
+{
+   put_seccomp_filter(tsk->seccomp.filter);
+}
+
 /**
  * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
  * @syscall: syscall number to send to userland
@@ -926,7 +934,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned 
long filter_off,
if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
ret = -EFAULT;
 
-   put_seccomp_filter(task);
+   put_seccomp_filter(task->seccomp.filter);
return ret;
 
 out:
-- 
2.8.1



[RFC v2 01/10] landlock: Add Kconfig

2016-08-25 Thread Mickaël Salaün
Initial Landlock Kconfig needed to split the Landlock eBPF and seccomp
parts to ease the review.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 security/Kconfig  |  1 +
 security/landlock/Kconfig | 16 
 2 files changed, 17 insertions(+)
 create mode 100644 security/landlock/Kconfig

diff --git a/security/Kconfig b/security/Kconfig
index 176758cdfa57..be6c549dd0ca 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -124,6 +124,7 @@ source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/loadpin/Kconfig
 source security/yama/Kconfig
+source security/landlock/Kconfig
 
 source security/integrity/Kconfig
 
diff --git a/security/landlock/Kconfig b/security/landlock/Kconfig
new file mode 100644
index ..dc8328d216d7
--- /dev/null
+++ b/security/landlock/Kconfig
@@ -0,0 +1,16 @@
+config SECURITY_LANDLOCK
+   bool "Landlock sandbox support"
+   depends on SECURITY
+   select BPF_SYSCALL
+   select SECCOMP
+   default y
+   help
+ Landlock is a stacked LSM which allows any user to load a security 
policy
+ to restrict their processes (i.e. create a sandbox). The policy is a 
list
+ of stacked eBPF programs for some LSM hooks. Each program can do some
+ access comparison to check if an access request is legitimate.
+
+ Further information about eBPF can be found in
+ Documentation/networking/filter.txt
+
+ If you are unsure how to answer this question, answer Y.
-- 
2.8.1



[RFC v2 03/10] bpf,landlock: Add a new arraymap type to deal with (Landlock) handles

2016-08-25 Thread Mickaël Salaün
This new arraymap looks like a set and brings new properties:
* strong typing of entries: the eBPF functions get the array type of
  elements instead of CONST_PTR_TO_MAP (e.g.
  CONST_PTR_TO_LANDLOCK_HANDLE_FS);
* force sequential filling (i.e. replace or append-only update), which
  allow quick browsing of all entries.

This strong typing is useful to statically check if the content of a map
can be passed to an eBPF function. For example, Landlock use it to store
and manage kernel objects (e.g. struct file) instead of dealing with
userland raw data. This improve efficiency and ensure that an eBPF
program can only call functions with the right high-level arguments.

The enum bpf_map_handle_type list low-level types (e.g.
BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD) which are identified when
updating a map entry (handle). This handle types are used to infer a
high-level arraymap type which are listed in enum bpf_map_array_type
(e.g. BPF_MAP_ARRAY_TYPE_LANDLOCK_FS).

For now, this new arraymap is only used by Landlock LSM (cf. next
commits) but it could be useful for other needs.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
---
 include/linux/bpf.h  |  18 +
 include/uapi/linux/bpf.h |  18 +
 kernel/bpf/arraymap.c| 181 +++
 kernel/bpf/syscall.c |   9 ++-
 kernel/bpf/verifier.c|  12 +++-
 5 files changed, 235 insertions(+), 3 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index ca3742729ae7..9a5b388be099 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -12,6 +12,10 @@
 #include 
 #include 
 
+#ifdef CONFIG_SECURITY_LANDLOCK
+#include  /* struct file */
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 struct bpf_map;
 
 /* map is generic key/value storage optionally accesible by eBPF programs */
@@ -34,6 +38,7 @@ struct bpf_map_ops {
 struct bpf_map {
atomic_t refcnt;
enum bpf_map_type map_type;
+   enum bpf_map_array_type map_array_type;
u32 key_size;
u32 value_size;
u32 max_entries;
@@ -183,12 +188,25 @@ struct bpf_array {
 */
enum bpf_prog_type owner_prog_type;
bool owner_jited;
+#ifdef CONFIG_SECURITY_LANDLOCK
+   u32 n_entries;  /* number of entries in a handle array */
+#endif /* CONFIG_SECURITY_LANDLOCK */
union {
char value[0] __aligned(8);
void *ptrs[0] __aligned(8);
void __percpu *pptrs[0] __aligned(8);
};
 };
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+struct map_landlock_handle {
+   u32 type;
+   union {
+   struct file *file;
+   };
+};
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 #define MAX_TAIL_CALL_CNT 32
 
 u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 406459b935a2..a60eedc17d40 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -84,6 +84,15 @@ enum bpf_map_type {
BPF_MAP_TYPE_PERCPU_HASH,
BPF_MAP_TYPE_PERCPU_ARRAY,
BPF_MAP_TYPE_STACK_TRACE,
+   BPF_MAP_TYPE_LANDLOCK_ARRAY,
+};
+
+enum bpf_map_array_type {
+   BPF_MAP_ARRAY_TYPE_UNSPEC,
+};
+
+enum bpf_map_handle_type {
+   BPF_MAP_HANDLE_TYPE_UNSPEC,
 };
 
 enum bpf_prog_type {
@@ -386,4 +395,13 @@ struct bpf_tunnel_key {
__u32 tunnel_label;
 };
 
+/* Map handle entry */
+struct landlock_handle {
+   __u32 type; /* enum bpf_map_handle_type */
+   union {
+   __u32 fd;
+   __aligned_u64 glob;
+   };
+} __attribute__((aligned(8)));
+
 #endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 76d5a794e426..5938b8ee475b 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -16,6 +16,8 @@
 #include 
 #include 
 #include 
+#include  /* fput() */
+#include  /* struct file */
 
 static void bpf_array_free_percpu(struct bpf_array *array)
 {
@@ -491,3 +493,182 @@ static int __init register_perf_event_array_map(void)
return 0;
 }
 late_initcall(register_perf_event_array_map);
+
+
+#ifdef CONFIG_SECURITY_LANDLOCK
+static struct bpf_map *landlock_array_map_alloc(union bpf_attr *attr)
+{
+   if (attr->value_size != sizeof(struct landlock_handle))
+   return ERR_PTR(-EINVAL);
+   attr->value_size = sizeof(struct map_landlock_handle);
+
+   return array_map_alloc(attr);
+}
+
+static void landlock_put_handle(struct map_landlock_handle *handle)
+{
+   switch (handle->type) {
+   /* TODO: add handle types */
+   default:
+   WARN_ON(1);
+   }
+   /* safeguard */
+   handle->type = BPF_MAP_HANDLE_TYPE_UNSPEC;
+}
+
+static void landlock_array_map_free(struct 

[RFC v2 06/10] landlock: Add LSM hooks

2016-08-25 Thread Mickaël Salaün
Add LSM hooks which can be used by userland through Landlock (eBPF)
programs. This programs are limited to a whitelist of functions (cf.
next commit). The eBPF program context is depicted by the struct
landlock_data (cf. include/uapi/linux/bpf.h):
* hook: LSM hook ID (useful when using the same program for multiple LSM
  hooks);
* cookie: the 16-bit value from the seccomp filter that triggered this
  Landlock program;
* args[6]: array of LSM hook arguments.

The LSM hook arguments can contain raw values as integers or
(unleakable) pointers. The only way to use the pointers are to pass them
to an eBPF function according to their types (e.g. the
bpf_landlock_cmp_fs_beneath_with_struct_file function can use a struct
file pointer).

For now, there is three hooks for file system access control:
* file_open;
* file_permission;
* mmap_file.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 include/linux/bpf.h|   7 ++
 include/linux/lsm_hooks.h  |   5 ++
 include/uapi/linux/bpf.h   |  20 +
 kernel/bpf/syscall.c   |   3 +
 kernel/bpf/verifier.c  |   8 ++
 kernel/seccomp.c   |   7 +-
 security/Makefile  |   2 +
 security/landlock/Makefile |   3 +
 security/landlock/lsm.c| 211 +
 security/security.c|   1 +
 10 files changed, 265 insertions(+), 2 deletions(-)
 create mode 100644 security/landlock/Makefile
 create mode 100644 security/landlock/lsm.c

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 9a5b388be099..557e7efdf0cd 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -81,6 +81,9 @@ enum bpf_arg_type {
 
ARG_PTR_TO_CTX, /* pointer to context */
ARG_ANYTHING,   /* any (initialized) argument is ok */
+
+   ARG_PTR_TO_STRUCT_FILE, /* pointer to struct file */
+   ARG_PTR_TO_STRUCT_CRED, /* pointer to struct cred */
 };
 
 /* type of values returned from helper functions */
@@ -139,6 +142,10 @@ enum bpf_reg_type {
 */
PTR_TO_PACKET,
PTR_TO_PACKET_END,   /* skb->data + headlen */
+
+   /* Landlock */
+   PTR_TO_STRUCT_FILE,
+   PTR_TO_STRUCT_CRED,
 };
 
 struct bpf_prog;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7ae397669d8b..6792ae8fb53d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1898,5 +1898,10 @@ void __init loadpin_add_hooks(void);
 #else
 static inline void loadpin_add_hooks(void) { };
 #endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void __init landlock_add_hooks(void);
+#else
+static inline void __init landlock_add_hooks(void) { }
+#endif /* CONFIG_SECURITY_LANDLOCK */
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index a60eedc17d40..983d14e910ff 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -102,6 +102,9 @@ enum bpf_prog_type {
BPF_PROG_TYPE_SCHED_CLS,
BPF_PROG_TYPE_SCHED_ACT,
BPF_PROG_TYPE_TRACEPOINT,
+   BPF_PROG_TYPE_LANDLOCK_FILE_OPEN,
+   BPF_PROG_TYPE_LANDLOCK_FILE_PERMISSION,
+   BPF_PROG_TYPE_LANDLOCK_MMAP_FILE,
 };
 
 #define BPF_PSEUDO_MAP_FD  1
@@ -404,4 +407,21 @@ struct landlock_handle {
};
 } __attribute__((aligned(8)));
 
+/**
+ * struct landlock_data
+ *
+ * @hook: LSM hook ID
+ * @cookie: value set by a seccomp-filter return value RET_LANDLOCK. This come
+ *  from a trusted seccomp-bpf program: the same process that loaded
+ *  this Landlock hook program.
+ * @args: LSM hook arguments, see include/linux/lsm_hooks.h for there
+ *description and the LANDLOCK_HOOK* definitions from
+ *security/landlock/lsm.c for their types.
+ */
+struct landlock_data {
+   __u32 hook;
+   __u16 cookie;
+   __u64 args[6];
+};
+
 #endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 32a10ef4b878..6b8bfc34c751 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -719,6 +719,9 @@ static int bpf_prog_load(union bpf_attr *attr)
 
switch (type) {
case BPF_PROG_TYPE_SOCKET_FILTER:
+   case BPF_PROG_TYPE_LANDLOCK_FILE_OPEN:
+   case BPF_PROG_TYPE_LANDLOCK_FILE_PERMISSION:
+   case BPF_PROG_TYPE_LANDLOCK_MMAP_FILE:
break;
default:
if (!capable(CAP_SYS_ADMIN))
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c15f6cc28e00..2931e2efcc10 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -244,6 +244,8 @@ static const char * const 

[RFC v2 08/10] landlock: Handle file system comparisons

2016-08-25 Thread Mickaël Salaün
Add eBPF functions to compare file system access with a Landlock file
system handle:
* bpf_landlock_cmp_fs_prop_with_struct_file(prop, map, map_op, file)
  This function allows to compare the dentry, inode, device or mount
  point of the currently accessed file, with a reference handle.
* bpf_landlock_cmp_fs_beneath_with_struct_file(opt, map, map_op, file)
  This function allows an eBPF program to check if the current accessed
  file is the same or in the hierarchy of a reference handle.

The goal of file system handle is to abstract kernel objects such as a
struct file or a struct inode. Userland can create this kind of handle
thanks to the BPF_MAP_UPDATE_ELEM command. The element is a struct
landlock_handle containing the handle type (e.g.
BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD) and a file descriptor. This could
also be any descriptions able to match a struct file or a struct inode
(e.g. path or glob string).

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 include/linux/bpf.h|   4 +-
 include/uapi/linux/bpf.h   |  52 +++-
 kernel/bpf/arraymap.c  |  17 +++-
 kernel/bpf/verifier.c  |   6 ++
 security/landlock/Makefile |   2 +-
 security/landlock/checker_fs.c | 183 +
 security/landlock/checker_fs.h |  20 +
 security/landlock/lsm.c|  11 ++-
 8 files changed, 288 insertions(+), 7 deletions(-)
 create mode 100644 security/landlock/checker_fs.c
 create mode 100644 security/landlock/checker_fs.h

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 557e7efdf0cd..79014aedbea4 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -84,6 +84,7 @@ enum bpf_arg_type {
 
ARG_PTR_TO_STRUCT_FILE, /* pointer to struct file */
ARG_PTR_TO_STRUCT_CRED, /* pointer to struct cred */
+   ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS,/* pointer to Landlock FS 
handle */
 };
 
 /* type of values returned from helper functions */
@@ -146,6 +147,7 @@ enum bpf_reg_type {
/* Landlock */
PTR_TO_STRUCT_FILE,
PTR_TO_STRUCT_CRED,
+   CONST_PTR_TO_LANDLOCK_HANDLE_FS,
 };
 
 struct bpf_prog;
@@ -207,7 +209,7 @@ struct bpf_array {
 
 #ifdef CONFIG_SECURITY_LANDLOCK
 struct map_landlock_handle {
-   u32 type;
+   u32 type; /* e.g. BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD */
union {
struct file *file;
};
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 983d14e910ff..88af79dd668c 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -89,10 +89,20 @@ enum bpf_map_type {
 
 enum bpf_map_array_type {
BPF_MAP_ARRAY_TYPE_UNSPEC,
+   BPF_MAP_ARRAY_TYPE_LANDLOCK_FS,
 };
 
 enum bpf_map_handle_type {
BPF_MAP_HANDLE_TYPE_UNSPEC,
+   BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD,
+   BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_GLOB,
+};
+
+enum bpf_map_array_op {
+   BPF_MAP_ARRAY_OP_UNSPEC,
+   BPF_MAP_ARRAY_OP_OR,
+   BPF_MAP_ARRAY_OP_AND,
+   BPF_MAP_ARRAY_OP_XOR,
 };
 
 enum bpf_prog_type {
@@ -325,6 +335,35 @@ enum bpf_func_id {
 */
BPF_FUNC_skb_get_tunnel_opt,
BPF_FUNC_skb_set_tunnel_opt,
+
+   /**
+* bpf_landlock_cmp_fs_prop_with_struct_file(prop, map, map_op, file)
+* Compare file system handles with a struct file
+*
+* @prop: properties to check against (e.g. LANDLOCK_FLAG_FS_DENTRY)
+* @map: handles to compare against
+* @map_op: which elements of the map to use (e.g. BPF_MAP_ARRAY_OP_OR)
+* @file: struct file address to compare with (taken from the context)
+*
+* Return: 0 if the file match the handles, 1 otherwise, or a negative
+* value if an error occurred.
+*/
+   BPF_FUNC_landlock_cmp_fs_prop_with_struct_file,
+
+   /**
+* bpf_landlock_cmp_fs_beneath_with_struct_file(opt, map, map_op, file)
+* Check if a struct file is a leaf of file system handles
+*
+* @opt: check options (e.g. LANDLOCK_FLAG_OPT_REVERSE)
+* @map: handles to compare against
+* @map_op: which elements of the map to use (e.g. BPF_MAP_ARRAY_OP_OR)
+* @file: struct file address to compare with (taken from the context)
+*
+* Return: 0 if the file is the same or beneath the handles,
+* 1 otherwise, or a negative value if an error occurred.
+*/
+   BPF_FUNC_landlock_cmp_fs_beneath_with_struct_file,
+
__BPF_FUNC_MAX_ID,
 };
 
@@ -398,6 +437,17 @@ struct bpf_tunnel_key {
__u32 tunnel_label;
 };
 
+/* Handle check flags */
+#define LANDLOCK_FLAG_FS_DENTRY(1 << 0)
+#define LANDLOCK_FLAG_FS

[RFC v2 10/10] samples/landlock: Add sandbox example

2016-08-25 Thread Mickaël Salaün
Add a basic sandbox tool to create a process isolated from some part of
the system. This can depend of the current cgroup.

Example:

  $ mkdir /sys/fs/cgroup/sandboxed
  $ ls /home
  user1
  $ LANDLOCK_CGROUPS='/sys/fs/cgroup/sandboxed' \
  LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
  ./sandbox /bin/sh -i
  $ ls /home
  user1
  $ echo $$ > /sys/fs/cgroup/sandboxed/cgroup.procs
  $ ls /home
  ls: cannot open directory '/home': Permission denied

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 samples/Makefile|   2 +-
 samples/landlock/.gitignore |   1 +
 samples/landlock/Makefile   |  16 +++
 samples/landlock/sandbox.c  | 295 
 4 files changed, 313 insertions(+), 1 deletion(-)
 create mode 100644 samples/landlock/.gitignore
 create mode 100644 samples/landlock/Makefile
 create mode 100644 samples/landlock/sandbox.c

diff --git a/samples/Makefile b/samples/Makefile
index 2e3b523d7097..42e6a613f728 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -2,4 +2,4 @@
 
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ trace_events/ livepatch/ \
   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
-  configfs/ connector/ v4l/
+  configfs/ connector/ v4l/ landlock/
diff --git a/samples/landlock/.gitignore b/samples/landlock/.gitignore
new file mode 100644
index ..f6c6da930a30
--- /dev/null
+++ b/samples/landlock/.gitignore
@@ -0,0 +1 @@
+/sandbox
diff --git a/samples/landlock/Makefile b/samples/landlock/Makefile
new file mode 100644
index ..d1044b2afd27
--- /dev/null
+++ b/samples/landlock/Makefile
@@ -0,0 +1,16 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+hostprogs-$(CONFIG_SECURITY_LANDLOCK) := sandbox
+sandbox-objs := sandbox.o
+
+always := $(hostprogs-y)
+
+HOSTCFLAGS += -I$(objtree)/usr/include
+
+# Trick to allow make to be run from this directory
+all:
+   $(MAKE) -C ../../ $$PWD/
+
+clean:
+   $(MAKE) -C ../../ M=$$PWD clean
diff --git a/samples/landlock/sandbox.c b/samples/landlock/sandbox.c
new file mode 100644
index ..86604963c30c
--- /dev/null
+++ b/samples/landlock/sandbox.c
@@ -0,0 +1,295 @@
+/*
+ * Landlock LSM - Sandbox Example
+ *
+ * Copyright (C) 2016  Mickaël Salaün <m...@digikod.net>
+ *
+ * The code may be used by anyone for any purpose, and can serve as a starting
+ * point for developing a sandbox.
+ */
+
+#define _GNU_SOURCE
+#include 
+#include  /* open() */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "../../tools/include/linux/filter.h"
+
+#include "../bpf/libbpf.c"
+
+#ifndef seccomp
+static int seccomp(unsigned int op, unsigned int flags, void *args)
+{
+   errno = 0;
+   return syscall(__NR_seccomp, op, flags, args);
+}
+#endif
+
+#define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))
+
+static int apply_sandbox(const char **allowed_paths, int path_nb, const char 
**cgroup_paths, int cgroup_nb)
+{
+   __u32 key;
+   int i, ret = 0, map_fs = -1, map_cg = -1, offset;
+
+   /* set up the test sandbox */
+   if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+   perror("prctl(no_new_priv)");
+   return 1;
+   }
+
+   /* register a new syscall filter */
+   struct sock_filter filter0[] = {
+   /* pass a cookie containing 5 to the LSM hook filter */
+   BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LANDLOCK | 5),
+   };
+   struct sock_fprog prog0 = {
+   .len = (unsigned short)ARRAY_SIZE(filter0),
+   .filter = filter0,
+   };
+   if (seccomp(SECCOMP_SET_MODE_FILTER, 0, )) {
+   perror("seccomp(set_filter)");
+   return 1;
+   }
+
+   if (path_nb) {
+   map_fs = bpf_create_map(BPF_MAP_TYPE_LANDLOCK_ARRAY, 
sizeof(key), sizeof(struct landlock_handle), 10, 0);
+   if (map_fs < 0) {
+   fprintf(stderr, "bpf_create_map(fs");
+   perror(")");
+   return 1;
+   }
+   for (key = 0; key < path_nb; key++) {
+   int fd = open(allowed_paths[key], O_RDONLY | O_CLOEXEC);
+   if (fd < 0) {
+   fprintf(stderr, "open(fs: \"%s\"", 
allowed_paths[key]);
+   perror(")");
+   return 1;
+   

[RFC v2 00/10] Landlock LSM: Unprivileged sandboxing

2016-08-25 Thread Mickaël Salaün
itelist a set of syscalls to
reduce the kernel attack surface for a set of processes. However an
unprivileged user can't create a security policy as the root user can thanks to
SELinux and other access control LSMs. Landlock allows any unprivileged user to
protect their data from being accessed by any process they run but only an
identified subset. User tools can be created to help create such a high-level
access control policy. This policy may not be powerful enough to express the
same policies as the current access control LSMs, because of the threat an
unprivileged user can be to the system, but it should be enough for most
use-cases (e.g. blacklist or whitelist a set of file hierarchies).


## Does Landlock can limit network access or other resources?

Limiting network access is obviously in the scope of Landlock but it is not yet
implemented. The main goal now is to get feedback about the whole concept, the
API and the file access control part. More access control types could be
implemented in the future.


## Why using the seccomp(2) syscall?

Landlock use the same semantic as seccomp to apply access rule restrictions. It
add a new layer of security for the current process which is inherited by its
childs. It make sense to use an unique access-restricting syscall (that should
be allowed by seccomp-filter rules) which can only drop privileges. Moreover, a
Landlock eBPF program could come from outside a process (e.g. passed through a
UNIX socket). It is then useful to differentiate the creation/load of Landlock
eBPF programs via bpf(2), from rule enforcing via seccomp(2).


# Differences from the RFC v1

* focus on the LSM hooks, not the syscalls:
  * much more simple implementation
  * does not need audit cache tricks to avoid race conditions
  * more simple to use and more generic because using the LSM hook abstraction
directly
  * more efficient because only checking in LSM hooks
  * architecture agnostic
* switch from cBPF to eBPF:
  * new eBPF program types dedicated to Landlock
  * custom functions used by the eBPF program
  * gain some new features (e.g. 10 registers, can load values of different
size, LLVM translator) but only a few functions allowed and a dedicated 
map
type
  * new context: LSM hook ID, cookie and LSM hook arguments
  * need to set the sysctl kernel.unprivileged_bpf_disable to 0 (default value)
to be able to load hook filters as unprivileged users
* smaller and simpler:
  * no more checker groups but dedicated arraymap of handles
  * simpler userland structs thanks to eBPF functions
* distinctive name: Landlock


[1] https://lkml.kernel.org/r/1458784008-16277-1-git-send-email-...@digikod.net
[2] https://crypto.stanford.edu/cs155/papers/traps.pdf


This series can be applied on Linux 4.7 and be tested with
CONFIG_SECURITY_LANDLOCK and CONFIG_CGROUPS. I would really appreciate
constructive comments on the usability, architecture, code and userland API of
Landlock LSM.

Regards,

Mickaël Salaün (10):
  landlock: Add Kconfig
  bpf: Move u64_to_ptr() to BPF headers and inline it
  bpf,landlock: Add a new arraymap type to deal with (Landlock) handles
  seccomp: Split put_seccomp_filter() with put_seccomp()
  seccomp: Handle Landlock
  landlock: Add LSM hooks
  landlock: Add errno check
  landlock: Handle file system comparisons
  landlock: Handle cgroups
  samples/landlock: Add sandbox example

 include/linux/bpf.h   |  41 +
 include/linux/lsm_hooks.h |   5 +
 include/linux/seccomp.h   |  54 ++-
 include/uapi/asm-generic/errno-base.h |   1 +
 include/uapi/linux/bpf.h  | 103 
 include/uapi/linux/seccomp.h  |   2 +
 kernel/bpf/arraymap.c | 222 +
 kernel/bpf/syscall.c  |  18 ++-
 kernel/bpf/verifier.c |  32 +++-
 kernel/fork.c |  41 -
 kernel/seccomp.c  | 211 +++-
 samples/Makefile  |   2 +-
 samples/landlock/.gitignore   |   1 +
 samples/landlock/Makefile |  16 ++
 samples/landlock/sandbox.c| 295 ++
 security/Kconfig  |   1 +
 security/Makefile |   2 +
 security/landlock/Kconfig |  19 +++
 security/landlock/Makefile|   3 +
 security/landlock/checker_cgroup.c|  96 +++
 security/landlock/checker_cgroup.h|  18 +++
 security/landlock/checker_fs.c| 183 +
 security/landlock/checker_fs.h|  20 +++
 security/landlock/lsm.c   | 228 ++
 security/security.c   |   1 +
 25 files changed, 1592 insertions(+), 23 deletions(-)
 create mode 100644 samples/landlock/.gitignore
 create mode 100644 samples/landlock/Makefile
 create mode 100644 samples/landlock/sandbox.c
 create mode 100644 security/landlock/Kconfig
 creat

[RFC v2 09/10] landlock: Handle cgroups

2016-08-25 Thread Mickaël Salaün
Add an eBPF function bpf_landlock_cmp_cgroup_beneath(opt, map, map_op)
to compare the current process cgroup with a cgroup handle, The handle
can match the current cgroup if it is the same or a child. This allows
to make conditional rules according to the current cgroup.

A cgroup handle is a map entry created from a file descriptor referring
a cgroup directory (e.g. by opening /sys/fs/cgroup/X). In this case, the
map entry is of type BPF_MAP_HANDLE_TYPE_LANDLOCK_CGROUP_FD and the
inferred array map is of type BPF_MAP_ARRAY_TYPE_LANDLOCK_CGROUP.

An unprivileged process can create and manipulate cgroups thanks to
cgroup delegation.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 include/linux/bpf.h|  8 
 include/uapi/linux/bpf.h   | 15 ++
 kernel/bpf/arraymap.c  | 30 
 kernel/bpf/verifier.c  |  6 +++
 security/landlock/Kconfig  |  3 ++
 security/landlock/Makefile |  2 +-
 security/landlock/checker_cgroup.c | 96 ++
 security/landlock/checker_cgroup.h | 18 +++
 security/landlock/lsm.c|  8 
 9 files changed, 185 insertions(+), 1 deletion(-)
 create mode 100644 security/landlock/checker_cgroup.c
 create mode 100644 security/landlock/checker_cgroup.h

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 79014aedbea4..9e6786e7a40a 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -14,6 +14,9 @@
 
 #ifdef CONFIG_SECURITY_LANDLOCK
 #include  /* struct file */
+#ifdef CONFIG_CGROUPS
+#include  /* struct cgroup_subsys_state */
+#endif /* CONFIG_CGROUPS */
 #endif /* CONFIG_SECURITY_LANDLOCK */
 
 struct bpf_map;
@@ -85,6 +88,7 @@ enum bpf_arg_type {
ARG_PTR_TO_STRUCT_FILE, /* pointer to struct file */
ARG_PTR_TO_STRUCT_CRED, /* pointer to struct cred */
ARG_CONST_PTR_TO_LANDLOCK_HANDLE_FS,/* pointer to Landlock FS 
handle */
+   ARG_CONST_PTR_TO_LANDLOCK_HANDLE_CGROUP,/* pointer to Landlock 
cgroup handle */
 };
 
 /* type of values returned from helper functions */
@@ -148,6 +152,7 @@ enum bpf_reg_type {
PTR_TO_STRUCT_FILE,
PTR_TO_STRUCT_CRED,
CONST_PTR_TO_LANDLOCK_HANDLE_FS,
+   CONST_PTR_TO_LANDLOCK_HANDLE_CGROUP,
 };
 
 struct bpf_prog;
@@ -212,6 +217,9 @@ struct map_landlock_handle {
u32 type; /* e.g. BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD */
union {
struct file *file;
+#ifdef CONFIG_CGROUPS
+   struct cgroup_subsys_state *css;
+#endif /* CONFIG_CGROUPS */
};
 };
 #endif /* CONFIG_SECURITY_LANDLOCK */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 88af79dd668c..7f60b9fdb35c 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -90,12 +90,14 @@ enum bpf_map_type {
 enum bpf_map_array_type {
BPF_MAP_ARRAY_TYPE_UNSPEC,
BPF_MAP_ARRAY_TYPE_LANDLOCK_FS,
+   BPF_MAP_ARRAY_TYPE_LANDLOCK_CGROUP,
 };
 
 enum bpf_map_handle_type {
BPF_MAP_HANDLE_TYPE_UNSPEC,
BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD,
BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_GLOB,
+   BPF_MAP_HANDLE_TYPE_LANDLOCK_CGROUP_FD,
 };
 
 enum bpf_map_array_op {
@@ -364,6 +366,19 @@ enum bpf_func_id {
 */
BPF_FUNC_landlock_cmp_fs_beneath_with_struct_file,
 
+   /**
+* bpf_landlock_cmp_cgroup_beneath(opt, map, map_op)
+* Check if the current process is a leaf of cgroup handles
+*
+* @opt: check options (e.g. LANDLOCK_FLAG_OPT_REVERSE)
+* @map: handles to compare against
+* @map_op: which elements of the map to use (e.g. BPF_MAP_ARRAY_OP_OR)
+*
+* Return: 0 if the current cgroup is the sam or beneath the handle,
+* 1 otherwise, or a negative value if an error occurred.
+*/
+   BPF_FUNC_landlock_cmp_cgroup_beneath,
+
__BPF_FUNC_MAX_ID,
 };
 
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 6804dafd8355..050b3d8d88c8 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -19,6 +19,12 @@
 #include  /* fput() */
 #include  /* struct file */
 
+#ifdef CONFIG_SECURITY_LANDLOCK
+#ifdef CONFIG_CGROUPS
+#include  /* struct cgroup_subsys_state */
+#endif /* CONFIG_CGROUPS */
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 static void bpf_array_free_percpu(struct bpf_array *array)
 {
int i;
@@ -514,6 +520,12 @@ static void landlock_put_handle(struct map_landlock_handle 
*handle)
else
WARN_ON(1);
break;
+   case BPF_MAP_HANDLE_TYPE_LANDLOCK_CGROUP_FD:
+   if (likely(handle->css))
+

[RFC v2 07/10] landlock: Add errno check

2016-08-25 Thread Mickaël Salaün
Add a max errno value.

This is not strictly needed but should improve reliability.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Arnd Bergmann <a...@arndb.de>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
---
 include/uapi/asm-generic/errno-base.h | 1 +
 security/landlock/lsm.c   | 6 +++---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/include/uapi/asm-generic/errno-base.h 
b/include/uapi/asm-generic/errno-base.h
index 65115978510f..43407a403e72 100644
--- a/include/uapi/asm-generic/errno-base.h
+++ b/include/uapi/asm-generic/errno-base.h
@@ -35,5 +35,6 @@
 #defineEPIPE   32  /* Broken pipe */
 #defineEDOM33  /* Math argument out of domain of func 
*/
 #defineERANGE  34  /* Math result not representable */
+#define_ERRNO_LAST ERANGE
 
 #endif
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index aa9d4a64826e..322309068066 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -11,7 +11,6 @@
 #include 
 #include  /* enum bpf_reg_type, struct landlock_data */
 #include 
-#include  /* MAX_ERRNO */
 #include  /* struct bpf_prog, BPF_PROG_RUN() */
 #include  /* FIELD_SIZEOF() */
 #include 
@@ -104,8 +103,9 @@ static int landlock_run_prog(__u64 args[6])
}
}
if (!ret) {
-   if (cur_ret > MAX_ERRNO)
-   ret = MAX_ERRNO;
+   /* check errno to not mess with kernel code */
+   if (cur_ret > _ERRNO_LAST)
+   ret = EPERM;
else
ret = cur_ret;
}
-- 
2.8.1



[RFC v2 02/10] bpf: Move u64_to_ptr() to BPF headers and inline it

2016-08-25 Thread Mickaël Salaün
This helper will be useful for arraymap (next commit).

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 include/linux/bpf.h  | 6 ++
 kernel/bpf/syscall.c | 6 --
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 0de4de6dd43e..ca3742729ae7 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -251,6 +251,12 @@ static inline void bpf_long_memcpy(void *dst, const void 
*src, u32 size)
 
 /* verify correctness of eBPF program */
 int bpf_check(struct bpf_prog **fp, union bpf_attr *attr);
+
+/* helper to convert user pointers passed inside __aligned_u64 fields */
+static inline void __user *u64_to_ptr(__u64 val)
+{
+   return (void __user *) (unsigned long) val;
+}
 #else
 static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl)
 {
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 46ecce4b79ed..d305a3ce0fa7 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -247,12 +247,6 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd)
return map;
 }
 
-/* helper to convert user pointers passed inside __aligned_u64 fields */
-static void __user *u64_to_ptr(__u64 val)
-{
-   return (void __user *) (unsigned long) val;
-}
-
 int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
 {
return -ENOTSUPP;
-- 
2.8.1



Re: [RFC v2 00/10] Landlock LSM: Unprivileged sandboxing

2016-08-25 Thread Mickaël Salaün

On 25/08/2016 13:05, Andy Lutomirski wrote:
> On Thu, Aug 25, 2016 at 3:32 AM, Mickaël Salaün <m...@digikod.net> wrote:
>> Hi,
>>
>> This series is a proof of concept to fill some missing part of seccomp as the
>> ability to check syscall argument pointers or creating more dynamic security
>> policies. The goal of this new stackable Linux Security Module (LSM) called
>> Landlock is to allow any process, including unprivileged ones, to create
>> powerful security sandboxes comparable to the Seatbelt/XNU Sandbox or the
>> OpenBSD Pledge. This kind of sandbox help to mitigate the security impact of
>> bugs or unexpected/malicious behaviors in userland applications.
>>
> 
> Maybe I'm missing an obvious description, but: do you have a
> description of the eBPF API to landlock?  What function do you
> provide, when is it called, what functions can it call, what does the
> fancy new arraymap do, etc?
> 
> --Andy
> 

The eBPF context is described in "[RFC v2 06/10] landlock: Add LSM hooks".

The provided eBPF functions are described in "[RFC v2 08/10] landlock:
Handle file system comparisons"
(bpf_landlock_cmp_fs_prop_with_struct_file and
bpf_landlock_cmp_fs_beneath_with_struct_file) and "[RFC v2 09/10]
landlock: Handle cgroups" (bpf_landlock_cmp_cgroup_beneath). The
function descriptions are summarized in include/uapi/linux/bpf.h .

This functions can be called by an eBPF program of type
BPF_PROG_TYPE_LANDLOCK_FILE_OPEN, BPF_PROG_TYPE_LANDLOCK_FILE_PERMISSION
and BPF_PROG_TYPE_LANDLOCK_MMAP_FILE as described in "[RFC v2 06/10]
landlock: Add LSM hooks".

I tried to split the commits as much as possible to ease the review. The
"[RFC v2 10/10] samples/landlock: Add sandbox example" may help to see
the whole picture.

Hope this helps,
 Mickaël



signature.asc
Description: OpenPGP digital signature


Re: [RFC v2 08/10] landlock: Handle file system comparisons

2016-08-25 Thread Mickaël Salaün

On 25/08/2016 13:12, Andy Lutomirski wrote:
> On Thu, Aug 25, 2016 at 3:32 AM, Mickaël Salaün <m...@digikod.net> wrote:
>> Add eBPF functions to compare file system access with a Landlock file
>> system handle:
>> * bpf_landlock_cmp_fs_prop_with_struct_file(prop, map, map_op, file)
>>   This function allows to compare the dentry, inode, device or mount
>>   point of the currently accessed file, with a reference handle.
>> * bpf_landlock_cmp_fs_beneath_with_struct_file(opt, map, map_op, file)
>>   This function allows an eBPF program to check if the current accessed
>>   file is the same or in the hierarchy of a reference handle.
>>
>> The goal of file system handle is to abstract kernel objects such as a
>> struct file or a struct inode. Userland can create this kind of handle
>> thanks to the BPF_MAP_UPDATE_ELEM command. The element is a struct
>> landlock_handle containing the handle type (e.g.
>> BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD) and a file descriptor. This could
>> also be any descriptions able to match a struct file or a struct inode
>> (e.g. path or glob string).
> 
> This needs Eric's opinion.
> 
> Also, where do all the struct file *'s get stashed?  Are they
> preserved in the arraymap?  What prevents reference cycles or absurdly
> large numbers of struct files getting pinned?

Yes, the struct file are kept in the arraymap and dropped when there is
no more reference on them. Currently, the limitations are the maximum
number of open file descriptors referring to an arraymap and the maximum
number of eBPF Landlock programs loaded in a process
(LANDLOCK_PROG_LIST_MAX_PAGES in kernel/seccomp.c).

What kind of reference cycles have you in mind?

It probably needs another limit for kernel object references as well.
What is the best option here? Add another static limitation or use an
existing one?

 Mickaël



signature.asc
Description: OpenPGP digital signature


Re: [RFC v2 09/10] landlock: Handle cgroups

2016-08-25 Thread Mickaël Salaün

On 25/08/2016 13:09, Andy Lutomirski wrote:
> On Thu, Aug 25, 2016 at 3:32 AM, Mickaël Salaün <m...@digikod.net> wrote:
>> Add an eBPF function bpf_landlock_cmp_cgroup_beneath(opt, map, map_op)
>> to compare the current process cgroup with a cgroup handle, The handle
>> can match the current cgroup if it is the same or a child. This allows
>> to make conditional rules according to the current cgroup.
>>
>> A cgroup handle is a map entry created from a file descriptor referring
>> a cgroup directory (e.g. by opening /sys/fs/cgroup/X). In this case, the
>> map entry is of type BPF_MAP_HANDLE_TYPE_LANDLOCK_CGROUP_FD and the
>> inferred array map is of type BPF_MAP_ARRAY_TYPE_LANDLOCK_CGROUP.
> 
> Can you elaborate on why this is useful?  I.e. why not just supply
> different policies to different subtrees.

The main use case I see is to load the security policies at the start of
a user session for all processes but not enforce them right away. The
user can then keep a shell for Landlock administration tasks and lock
the other processes with a dedicated cgroup on the fly. This allows the
user to make unremovable Landlock security policies but only activate
them when needed for specific processes.

> 
> Also, how does this interact with the current cgroup v1 vs v2 mess?
> As far as I can tell, no one can even really agree on what "what
> cgroup am I in" means right now.

I tested with cgroup-v2 but indeed, it seems a bit different with
cgroup-v1 :)
Does anyone know how to handle both cases?

> 
>>
>> An unprivileged process can create and manipulate cgroups thanks to
>> cgroup delegation.
> 
> What is cgroup delegation?

This is simply the action of changing the owner of cgroup sysfs files to
allow an unprivileged user to handle them (cf. Documentation/cgroup-v2.txt)

 Mickaël



signature.asc
Description: OpenPGP digital signature


Re: [PATCH v2 0/3] Fix seccomp for UM

2016-09-06 Thread Mickaël Salaün
Hi,

It seems that some of the fixes from linux-security have landed in the
Linus' tree but some seccomp fixes are still missing. They fix bugs
introduced in Linux v4.8 and are still present in v4.8-rc5. Could you
please push this series before the final 4.8 release?

Regards,
 Mickaël

On 09/08/2016 02:35, James Morris wrote:
> On Mon, 1 Aug 2016, Mickaël Salaün wrote:
> 
>> Hi,
>>
>> This series fix the recent seccomp update for the User-mode Linux 
>> architecture
>> (32-bit and 64-bit) since commit 26703c636c1f ("um/ptrace: run seccomp after
>> ptrace") which close the hole where ptrace can change a syscall out from 
>> under
>> seccomp.
>>
>> Changes since v1:
>> * fix commit message typo [2/3]
>> * add Kees Cook's Acked-by
>> * rebased on commit 7616ac70d1bb ("apparmor: fix 
>> SECURITY_APPARMOR_HASH_DEFAULT
>>   parameter handling")
> 
> All applied to
> git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git next
> 
> 
> 



signature.asc
Description: OpenPGP digital signature


Re: [RFC v2 00/10] Landlock LSM: Unprivileged sandboxing

2016-08-30 Thread Mickaël Salaün

On 30/08/2016 18:06, Andy Lutomirski wrote:
> On Thu, Aug 25, 2016 at 3:32 AM, Mickaël Salaün <m...@digikod.net> wrote:
>> Hi,
>>
>> This series is a proof of concept to fill some missing part of seccomp as the
>> ability to check syscall argument pointers or creating more dynamic security
>> policies. The goal of this new stackable Linux Security Module (LSM) called
>> Landlock is to allow any process, including unprivileged ones, to create
>> powerful security sandboxes comparable to the Seatbelt/XNU Sandbox or the
>> OpenBSD Pledge. This kind of sandbox help to mitigate the security impact of
>> bugs or unexpected/malicious behaviors in userland applications.
> 
> Mickaël, will you be at KS and/or LPC?
> 

I won't be at KS/LPC but I will give a talk at Kernel Recipes (Paris)
for which registration will start Thursday (and will not last long). :)

 Mickaël



signature.asc
Description: OpenPGP digital signature


Re: [RFC v2 09/10] landlock: Handle cgroups (performance)

2016-08-30 Thread Mickaël Salaün


On 30/08/2016 22:23, Andy Lutomirski wrote:
> On Tue, Aug 30, 2016 at 1:20 PM, Mickaël Salaün <m...@digikod.net> wrote:
>>
>> On 30/08/2016 20:55, Andy Lutomirski wrote:
>>> On Sun, Aug 28, 2016 at 2:42 AM, Mickaël Salaün <m...@digikod.net> wrote:
>>>>
>>>>
>>>> On 28/08/2016 10:13, Andy Lutomirski wrote:
>>>>> On Aug 27, 2016 11:14 PM, "Mickaël Salaün" <m...@digikod.net> wrote:
>>>>>>
>>>>>>
>>>>>> On 27/08/2016 22:43, Alexei Starovoitov wrote:
>>>>>>> On Sat, Aug 27, 2016 at 09:35:14PM +0200, Mickaël Salaün wrote:
>>>>>>>> On 27/08/2016 20:06, Alexei Starovoitov wrote:
>>>>>>>>> On Sat, Aug 27, 2016 at 04:06:38PM +0200, Mickaël Salaün wrote:
>>>>>>>>>> As said above, Landlock will not run an eBPF programs when not 
>>>>>>>>>> strictly
>>>>>>>>>> needed. Attaching to a cgroup will have the same performance impact 
>>>>>>>>>> as
>>>>>>>>>> attaching to a process hierarchy.
>>>>>>>>>
>>>>>>>>> Having a prog per cgroup per lsm_hook is the only scalable way I
>>>>>>>>> could come up with. If you see another way, please propose.
>>>>>>>>> current->seccomp.landlock_prog is not the answer.
>>>>>>>>
>>>>>>>> Hum, I don't see the difference from a performance point of view 
>>>>>>>> between
>>>>>>>> a cgroup-based or a process hierarchy-based system.
>>>>>>>>
>>>>>>>> Maybe a better option should be to use an array of pointers with N
>>>>>>>> entries, one for each supported hook, instead of a unique pointer list?
>>>>>>>
>>>>>>> yes, clearly array dereference is faster than link list walk.
>>>>>>> Now the question is where to keep this prog_array[num_lsm_hooks] ?
>>>>>>> Since we cannot keep it inside task_struct, we have to allocate it.
>>>>>>> Every time the task is creted then. What to do on the fork? That
>>>>>>> will require changes all over. Then the obvious optimization would be
>>>>>>> to share this allocated array of prog pointers across multiple tasks...
>>>>>>> and little by little this new facility will look like cgroup.
>>>>>>> Hence the suggestion to put this array into cgroup from the start.
>>>>>>
>>>>>> I see your point :)
>>>>>>
>>>>>>>
>>>>>>>> Anyway, being able to attach an LSM hook program to a cgroup thanks to
>>>>>>>> the new BPF_PROG_ATTACH seems a good idea (while keeping the 
>>>>>>>> possibility
>>>>>>>> to use a process hierarchy). The downside will be to handle an LSM hook
>>>>>>>> program which is not triggered by a seccomp-filter, but this should be
>>>>>>>> needed anyway to handle interruptions.
>>>>>>>
>>>>>>> what do you mean 'not triggered by seccomp' ?
>>>>>>> You're not suggesting that this lsm has to enable seccomp to be 
>>>>>>> functional?
>>>>>>> imo that's non starter due to overhead.
>>>>>>
>>>>>> Yes, for now, it is triggered by a new seccomp filter return value
>>>>>> RET_LANDLOCK, which can take a 16-bit value called cookie. This must not
>>>>>> be needed but could be useful to bind a seccomp filter security policy
>>>>>> with a Landlock one. Waiting for Kees's point of view…
>>>>>>
>>>>>
>>>>> I'm not Kees, but I'd be okay with that.  I still think that doing
>>>>> this by process hierarchy a la seccomp will be easier to use and to
>>>>> understand (which is quite important for this kind of work) than doing
>>>>> it by cgroup.
>>>>>
>>>>> A feature I've wanted to add for a while is to have an fd that
>>>>> represents a seccomp layer, the idea being that you would set up your
>>>>> seccomp layer (with syscall filter, landlock hooks, etc) and then you
>>>>> would have a syscall to install that layer.  Then an unprivileged
>>>>> sandbox manage

Re: [RFC v2 06/10] landlock: Add LSM hooks

2016-08-30 Thread Mickaël Salaün

On 30/08/2016 22:18, Andy Lutomirski wrote:
> On Tue, Aug 30, 2016 at 1:10 PM, Mickaël Salaün <m...@digikod.net> wrote:
>>
>> On 30/08/2016 20:56, Andy Lutomirski wrote:
>>> On Aug 25, 2016 12:34 PM, "Mickaël Salaün" <m...@digikod.net> wrote:
>>>>
>>>> Add LSM hooks which can be used by userland through Landlock (eBPF)
>>>> programs. This programs are limited to a whitelist of functions (cf.
>>>> next commit). The eBPF program context is depicted by the struct
>>>> landlock_data (cf. include/uapi/linux/bpf.h):
>>>> * hook: LSM hook ID (useful when using the same program for multiple LSM
>>>>   hooks);
>>>> * cookie: the 16-bit value from the seccomp filter that triggered this
>>>>   Landlock program;
>>>> * args[6]: array of LSM hook arguments.
>>>>
>>>> The LSM hook arguments can contain raw values as integers or
>>>> (unleakable) pointers. The only way to use the pointers are to pass them
>>>> to an eBPF function according to their types (e.g. the
>>>> bpf_landlock_cmp_fs_beneath_with_struct_file function can use a struct
>>>> file pointer).
>>>>
>>>> For now, there is three hooks for file system access control:
>>>> * file_open;
>>>> * file_permission;
>>>> * mmap_file.
>>>>
>>>
>>> What's the purpose of exposing struct cred * to userspace?  It's
>>> primarily just an optimization to save a bit of RAM, and it's a
>>> dubious optimization at that.  What are you using it for?  Would it
>>> make more sense to use struct task_struct * or struct pid * instead?
>>>
>>> Also, exposing struct cred * has a really weird side-effect: it allows
>>> (maybe even encourages) checking for pointer equality between two
>>> struct cred * objects.  Doing so will have erratic results.
>>>
>>
>> The pointers exposed in the ePBF context are not directly readable by an
>> unprivileged eBPF program thanks to the strong typing of the Landlock
>> context and the static eBPF verification. There is no way to leak a
>> kernel pointer to userspace from an unprivileged eBPF program: pointer
>> arithmetic and comparison are prohibited. Pointers can only be pass as
>> argument to dedicated eBPF functions.
> 
> I'm not talking about leaking the value -- I'm talking about leaking
> the predicate (a == b) for two struct cred pointers.  That predicate
> shouldn't be available because it has very odd effects.

I'm pretty sure this case is covered with the impossibility of doing
pointers comparison.

> 
>>
>> For now, struct cred * is simply not used by any eBPF function and then
>> not usable at all. It only exist here because I map the LSM hook
>> arguments in a generic/automatic way to the eBPF context.
> 
> Maybe remove it from this patch set then?

Well, this is done with the LANDLOCK_HOOK* macros but I will remove it.



signature.asc
Description: OpenPGP digital signature


Re: [RFC v2 06/10] landlock: Add LSM hooks

2016-08-30 Thread Mickaël Salaün

On 30/08/2016 20:56, Andy Lutomirski wrote:
> On Aug 25, 2016 12:34 PM, "Mickaël Salaün" <m...@digikod.net> wrote:
>>
>> Add LSM hooks which can be used by userland through Landlock (eBPF)
>> programs. This programs are limited to a whitelist of functions (cf.
>> next commit). The eBPF program context is depicted by the struct
>> landlock_data (cf. include/uapi/linux/bpf.h):
>> * hook: LSM hook ID (useful when using the same program for multiple LSM
>>   hooks);
>> * cookie: the 16-bit value from the seccomp filter that triggered this
>>   Landlock program;
>> * args[6]: array of LSM hook arguments.
>>
>> The LSM hook arguments can contain raw values as integers or
>> (unleakable) pointers. The only way to use the pointers are to pass them
>> to an eBPF function according to their types (e.g. the
>> bpf_landlock_cmp_fs_beneath_with_struct_file function can use a struct
>> file pointer).
>>
>> For now, there is three hooks for file system access control:
>> * file_open;
>> * file_permission;
>> * mmap_file.
>>
> 
> What's the purpose of exposing struct cred * to userspace?  It's
> primarily just an optimization to save a bit of RAM, and it's a
> dubious optimization at that.  What are you using it for?  Would it
> make more sense to use struct task_struct * or struct pid * instead?
> 
> Also, exposing struct cred * has a really weird side-effect: it allows
> (maybe even encourages) checking for pointer equality between two
> struct cred * objects.  Doing so will have erratic results.
> 

The pointers exposed in the ePBF context are not directly readable by an
unprivileged eBPF program thanks to the strong typing of the Landlock
context and the static eBPF verification. There is no way to leak a
kernel pointer to userspace from an unprivileged eBPF program: pointer
arithmetic and comparison are prohibited. Pointers can only be pass as
argument to dedicated eBPF functions.

For now, struct cred * is simply not used by any eBPF function and then
not usable at all. It only exist here because I map the LSM hook
arguments in a generic/automatic way to the eBPF context.

I'm planning to extend the Landlock context with extra pointers,
whatever the LSM hook. We could then use task_struct, skb or any other
kernel objects, in a safe way, with dedicated functions.



signature.asc
Description: OpenPGP digital signature


Re: [RFC v2 09/10] landlock: Handle cgroups (performance)

2016-08-30 Thread Mickaël Salaün

On 30/08/2016 20:55, Andy Lutomirski wrote:
> On Sun, Aug 28, 2016 at 2:42 AM, Mickaël Salaün <m...@digikod.net> wrote:
>>
>>
>> On 28/08/2016 10:13, Andy Lutomirski wrote:
>>> On Aug 27, 2016 11:14 PM, "Mickaël Salaün" <m...@digikod.net> wrote:
>>>>
>>>>
>>>> On 27/08/2016 22:43, Alexei Starovoitov wrote:
>>>>> On Sat, Aug 27, 2016 at 09:35:14PM +0200, Mickaël Salaün wrote:
>>>>>> On 27/08/2016 20:06, Alexei Starovoitov wrote:
>>>>>>> On Sat, Aug 27, 2016 at 04:06:38PM +0200, Mickaël Salaün wrote:
>>>>>>>> As said above, Landlock will not run an eBPF programs when not strictly
>>>>>>>> needed. Attaching to a cgroup will have the same performance impact as
>>>>>>>> attaching to a process hierarchy.
>>>>>>>
>>>>>>> Having a prog per cgroup per lsm_hook is the only scalable way I
>>>>>>> could come up with. If you see another way, please propose.
>>>>>>> current->seccomp.landlock_prog is not the answer.
>>>>>>
>>>>>> Hum, I don't see the difference from a performance point of view between
>>>>>> a cgroup-based or a process hierarchy-based system.
>>>>>>
>>>>>> Maybe a better option should be to use an array of pointers with N
>>>>>> entries, one for each supported hook, instead of a unique pointer list?
>>>>>
>>>>> yes, clearly array dereference is faster than link list walk.
>>>>> Now the question is where to keep this prog_array[num_lsm_hooks] ?
>>>>> Since we cannot keep it inside task_struct, we have to allocate it.
>>>>> Every time the task is creted then. What to do on the fork? That
>>>>> will require changes all over. Then the obvious optimization would be
>>>>> to share this allocated array of prog pointers across multiple tasks...
>>>>> and little by little this new facility will look like cgroup.
>>>>> Hence the suggestion to put this array into cgroup from the start.
>>>>
>>>> I see your point :)
>>>>
>>>>>
>>>>>> Anyway, being able to attach an LSM hook program to a cgroup thanks to
>>>>>> the new BPF_PROG_ATTACH seems a good idea (while keeping the possibility
>>>>>> to use a process hierarchy). The downside will be to handle an LSM hook
>>>>>> program which is not triggered by a seccomp-filter, but this should be
>>>>>> needed anyway to handle interruptions.
>>>>>
>>>>> what do you mean 'not triggered by seccomp' ?
>>>>> You're not suggesting that this lsm has to enable seccomp to be 
>>>>> functional?
>>>>> imo that's non starter due to overhead.
>>>>
>>>> Yes, for now, it is triggered by a new seccomp filter return value
>>>> RET_LANDLOCK, which can take a 16-bit value called cookie. This must not
>>>> be needed but could be useful to bind a seccomp filter security policy
>>>> with a Landlock one. Waiting for Kees's point of view…
>>>>
>>>
>>> I'm not Kees, but I'd be okay with that.  I still think that doing
>>> this by process hierarchy a la seccomp will be easier to use and to
>>> understand (which is quite important for this kind of work) than doing
>>> it by cgroup.
>>>
>>> A feature I've wanted to add for a while is to have an fd that
>>> represents a seccomp layer, the idea being that you would set up your
>>> seccomp layer (with syscall filter, landlock hooks, etc) and then you
>>> would have a syscall to install that layer.  Then an unprivileged
>>> sandbox manager could set up its layer and still be able to inject new
>>> processes into it later on, no cgroups needed.
>>
>> A nice thing I didn't highlight about Landlock is that a process can
>> prepare a layer of rules (arraymap of handles + Landlock programs) and
>> pass the file descriptors of the Landlock programs to another process.
>> This process could then apply this programs to get sandboxed. However,
>> for now, because a Landlock program is only triggered by a seccomp
>> filter (which do not follow the Landlock programs as a FD), they will be
>> useless.
>>
>> The FD referring to an arraymap of handles can also be used to update a
>> map and change the behavior of a Landlock program. A master process can
>> then add or remove restrictions to another process hierarchy on the fly.
> 
> Maybe this could be extended a little bit.  The fd could hold the
> seccomp filter *and* the LSM hook filters.  FMODE_EXECUTE could give
> the ability to install it and FMODE_WRITE could give the ability to
> modify it.
> 

This is interesting! It should be possible to append the seccomp stack
of a source process to the seccomp stack of the target process when a
Landlock program is passed and then activated through seccomp(2).

For the FMODE_EXECUTE/FMODE_WRITE, are you suggesting to manage
permission of the eBPF program FD in a specific way?



signature.asc
Description: OpenPGP digital signature


Re: [RFC v3 03/22] bpf,landlock: Add a new arraymap type to deal with (Landlock) handles

2016-09-14 Thread Mickaël Salaün

On 14/09/2016 20:51, Alexei Starovoitov wrote:
> On Wed, Sep 14, 2016 at 09:23:56AM +0200, Mickaël Salaün wrote:
>> This new arraymap looks like a set and brings new properties:
>> * strong typing of entries: the eBPF functions get the array type of
>>   elements instead of CONST_PTR_TO_MAP (e.g.
>>   CONST_PTR_TO_LANDLOCK_HANDLE_FS);
>> * force sequential filling (i.e. replace or append-only update), which
>>   allow quick browsing of all entries.
>>
>> This strong typing is useful to statically check if the content of a map
>> can be passed to an eBPF function. For example, Landlock use it to store
>> and manage kernel objects (e.g. struct file) instead of dealing with
>> userland raw data. This improve efficiency and ensure that an eBPF
>> program can only call functions with the right high-level arguments.
>>
>> The enum bpf_map_handle_type list low-level types (e.g.
>> BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD) which are identified when
>> updating a map entry (handle). This handle types are used to infer a
>> high-level arraymap type which are listed in enum bpf_map_array_type
>> (e.g. BPF_MAP_ARRAY_TYPE_LANDLOCK_FS).
>>
>> For now, this new arraymap is only used by Landlock LSM (cf. next
>> commits) but it could be useful for other needs.
>>
>> Changes since v2:
>> * add a RLIMIT_NOFILE-based limit to the maximum number of arraymap
>>   handle entries (suggested by Andy Lutomirski)
>> * remove useless checks
>>
>> Changes since v1:
>> * arraymap of handles replace custom checker groups
>> * simpler userland API
>>
>> Signed-off-by: Mickaël Salaün <m...@digikod.net>
>> Cc: Alexei Starovoitov <a...@kernel.org>
>> Cc: Andy Lutomirski <l...@amacapital.net>
>> Cc: Daniel Borkmann <dan...@iogearbox.net>
>> Cc: David S. Miller <da...@davemloft.net>
>> Cc: Kees Cook <keesc...@chromium.org>
>> Link: 
>> https://lkml.kernel.org/r/calcetrwwtiz3kztkegow24-dvhqq6lftwexh77fd2g5o71y...@mail.gmail.com
>> ---
>>  include/linux/bpf.h  |  14 
>>  include/uapi/linux/bpf.h |  18 +
>>  kernel/bpf/arraymap.c| 203 
>> +++
>>  kernel/bpf/verifier.c|  12 ++-
>>  4 files changed, 246 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index fa9a988400d9..eae4ce4542c1 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -13,6 +13,10 @@
>>  #include 
>>  #include 
>>  
>> +#ifdef CONFIG_SECURITY_LANDLOCK
>> +#include  /* struct file */
>> +#endif /* CONFIG_SECURITY_LANDLOCK */
>> +
>>  struct perf_event;
>>  struct bpf_map;
>>  
>> @@ -38,6 +42,7 @@ struct bpf_map_ops {
>>  struct bpf_map {
>>  atomic_t refcnt;
>>  enum bpf_map_type map_type;
>> +enum bpf_map_array_type map_array_type;
>>  u32 key_size;
>>  u32 value_size;
>>  u32 max_entries;
>> @@ -187,6 +192,9 @@ struct bpf_array {
>>   */
>>  enum bpf_prog_type owner_prog_type;
>>  bool owner_jited;
>> +#ifdef CONFIG_SECURITY_LANDLOCK
>> +u32 n_entries;  /* number of entries in a handle array */
>> +#endif /* CONFIG_SECURITY_LANDLOCK */
>>  union {
>>  char value[0] __aligned(8);
>>  void *ptrs[0] __aligned(8);
>> @@ -194,6 +202,12 @@ struct bpf_array {
>>  };
>>  };
>>  
>> +#ifdef CONFIG_SECURITY_LANDLOCK
>> +struct map_landlock_handle {
>> +u32 type; /* enum bpf_map_handle_type */
>> +};
>> +#endif /* CONFIG_SECURITY_LANDLOCK */
>> +
>>  #define MAX_TAIL_CALL_CNT 32
>>  
>>  struct bpf_event_entry {
>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>> index 7cd36166f9b7..b68de57f7ab8 100644
>> --- a/include/uapi/linux/bpf.h
>> +++ b/include/uapi/linux/bpf.h
>> @@ -87,6 +87,15 @@ enum bpf_map_type {
>>  BPF_MAP_TYPE_PERCPU_ARRAY,
>>  BPF_MAP_TYPE_STACK_TRACE,P_TYPE_CGROUP_ARRAY
>>  BPF_MAP_TYPE_CGROUP_ARRAY,
>> +BPF_MAP_TYPE_LANDLOCK_ARRAY,
>> +};
>> +
>> +enum bpf_map_array_type {
>> +BPF_MAP_ARRAY_TYPE_UNSPEC,
>> +};
>> +
>> +enum bpf_map_handle_type {
>> +BPF_MAP_HANDLE_TYPE_UNSPEC,
>>  };
> 
> missing something. why it has to be special to have it's own
> fd array implementation?
> Please take a look how BPF_MAP_TYPE_PERF_EVENT_ARRAY, 
> BPF_MAP_TYPE_CGROUP_ARRAY and BPF_MAP_TYPE_PROG_ARRAY are done.
> The all store ob

Re: [RFC v3 17/22] cgroup: Add access check for cgroup_get_from_fd()

2016-09-14 Thread Mickaël Salaün

On 14/09/2016 09:24, Mickaël Salaün wrote:
> Add security access check for cgroup backed FD. The "cgroup.procs" file
> of the corresponding cgroup must be readable to identify the cgroup, and
> writable to prove that the current process can manage this cgroup (e.g.
> through delegation). This is similar to the check done by
> cgroup_procs_write_permission().
> 
> Signed-off-by: Mickaël Salaün <m...@digikod.net>
> Cc: Alexei Starovoitov <a...@kernel.org>
> Cc: Andy Lutomirski <l...@amacapital.net>
> Cc: Daniel Borkmann <dan...@iogearbox.net>
> Cc: Daniel Mack <dan...@zonque.org>
> Cc: David S. Miller <da...@davemloft.net>
> Cc: Kees Cook <keesc...@chromium.org>
> Cc: Tejun Heo <t...@kernel.org>
> ---
>  include/linux/cgroup.h |  2 +-
>  kernel/bpf/arraymap.c  |  2 +-
>  kernel/bpf/syscall.c   |  6 +++---
>  kernel/cgroup.c| 16 +++-
>  4 files changed, 20 insertions(+), 6 deletions(-)
...
> diff --git a/kernel/cgroup.c b/kernel/cgroup.c
> index 48b650a640a9..3bbaf3f02ed2 100644
> --- a/kernel/cgroup.c
> +++ b/kernel/cgroup.c
> @@ -6241,17 +6241,20 @@ EXPORT_SYMBOL_GPL(cgroup_get_from_path);
>  /**
>   * cgroup_get_from_fd - get a cgroup pointer from a fd
>   * @fd: fd obtained by open(cgroup2_dir)
> + * @access_mask: contains the permission mask
>   *
>   * Find the cgroup from a fd which should be obtained
>   * by opening a cgroup directory.  Returns a pointer to the
>   * cgroup on success. ERR_PTR is returned if the cgroup
>   * cannot be found.
>   */
> -struct cgroup *cgroup_get_from_fd(int fd)
> +struct cgroup *cgroup_get_from_fd(int fd, int access_mask)
>  {
>   struct cgroup_subsys_state *css;
>   struct cgroup *cgrp;
>   struct file *f;
> + struct inode *inode;
> + int ret;
>  
>   f = fget_raw(fd);
>   if (!f)
> @@ -6268,6 +6271,17 @@ struct cgroup *cgroup_get_from_fd(int fd)
>   return ERR_PTR(-EBADF);
>   }
>  
> + ret = -ENOMEM;
> + inode = kernfs_get_inode(f->f_path.dentry->d_sb, cgrp->procs_file.kn);

I forgot to properly move fput(f) after this line… This will be fixed.



signature.asc
Description: OpenPGP digital signature


Re: [RFC v3 18/22] cgroup,landlock: Add CGRP_NO_NEW_PRIVS to handle unprivileged hooks

2016-09-14 Thread Mickaël Salaün

On 14/09/2016 20:27, Andy Lutomirski wrote:
> On Wed, Sep 14, 2016 at 12:24 AM, Mickaël Salaün <m...@digikod.net> wrote:
>> Add a new flag CGRP_NO_NEW_PRIVS for each cgroup. This flag is initially
>> set for all cgroup except the root. The flag is clear when a new process
>> without the no_new_privs flags is attached to the cgroup.
>>
>> If a cgroup is landlocked, then any new attempt, from an unprivileged
>> process, to attach a process without no_new_privs to this cgroup will
>> be denied.
> 
> Until and unless everyone can agree on a way to properly namespace,
> delegate, etc cgroups, I think that trying to add unprivileged
> semantics to cgroups is nuts.  Given the big thread about cgroup v2,
> no-internal-tasks, etc, I just don't see how this approach can be
> viable.

As far as I can tell, the no_new_privs flag of at task is not related to
namespaces. The CGRP_NO_NEW_PRIVS flag is only a cache to quickly access
the no_new_privs property of *tasks* in a cgroup. The semantic is unchanged.

Using cgroup is optional, any task could use the seccomp-based
landlocking instead. However, for those that want/need to manage a
security policy in a more dynamic way, using cgroups may make sense.

I though cgroup delegation was OK in the v2, isn't it the case? Do you
have some links?

> 
> Can we try to make landlock work completely independently of cgroups
> so that it doesn't get stuck and so that programs can use it without
> worrying about cgroup v1 vs v2, interactions with cgroup managers,
> cgroup managers that (supposedly?) will start migrating processes
> around piecemeal and almost certainly blowing up landlock in the
> process, etc?

This RFC handle both cgroup and seccomp approaches in a similar way. I
don't see why building on top of cgroup v2 is a problem. Is there
security issues with delegation?

> 
> I have no problem with looking at prototypes for how landlock +
> cgroups would work, but I can't imagine the result being mergeable.
> 



signature.asc
Description: OpenPGP digital signature


Re: [RFC v3 19/22] landlock: Add interrupted origin

2016-09-14 Thread Mickaël Salaün

On 14/09/2016 20:29, Andy Lutomirski wrote:
> On Wed, Sep 14, 2016 at 12:24 AM, Mickaël Salaün <m...@digikod.net> wrote:
>> This third origin of hook call should cover all possible trigger paths
>> (e.g. page fault). Landlock eBPF programs can then take decisions
>> accordingly.
>>
>> Signed-off-by: Mickaël Salaün <m...@digikod.net>
>> Cc: Alexei Starovoitov <a...@kernel.org>
>> Cc: Andy Lutomirski <l...@amacapital.net>
>> Cc: Daniel Borkmann <dan...@iogearbox.net>
>> Cc: Kees Cook <keesc...@chromium.org>
>> ---
> 
> 
>>
>> +   if (unlikely(in_interrupt())) {
> 
> IMO security hooks have no business being called from interrupts.
> Aren't they all synchronous things done by tasks?  Interrupts are
> driver things.
> 
> Are you trying to check for page faults and such?

Yes, that was the idea you did put in my mind. Not sure how to deal with
this.



signature.asc
Description: OpenPGP digital signature


[RFC v3 16/22] bpf/cgroup,landlock: Handle Landlock hooks per cgroup

2016-09-14 Thread Mickaël Salaün
This allows to add new eBPF programs to Landlock hooks dedicated to a
cgroup thanks to the BPF_PROG_ATTACH command. Like for socket eBPF
programs, the Landlock hooks attached to a cgroup are propagated to the
nested cgroups. However, when a new Landlock program is attached to one
of this nested cgroup, this cgroup hierarchy fork the Landlock hooks.
This design is simple and match the current CONFIG_BPF_CGROUP
inheritance. The difference lie in the fact that Landlock programs can
only be stacked but not removed. This match the append-only seccomp
behavior. Userland is free to handle Landlock hooks attached to a cgroup
in more complicated ways (e.g. continuous inheritance), but care should
be taken to properly handle error cases (e.g. memory allocation errors).

Changes since v2:
* new design based on BPF_PROG_ATTACH (suggested by Alexei Starovoitov)

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Daniel Mack <dan...@zonque.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Tejun Heo <t...@kernel.org>
Link: https://lkml.kernel.org/r/20160826021432.ga8...@ast-mbp.thefacebook.com
Link: https://lkml.kernel.org/r/20160827204307.ga43...@ast-mbp.thefacebook.com
---
 include/linux/bpf-cgroup.h  |  7 +++
 include/linux/cgroup-defs.h |  2 ++
 include/linux/landlock.h|  9 +
 include/uapi/linux/bpf.h|  1 +
 kernel/bpf/cgroup.c | 33 ++---
 kernel/bpf/syscall.c| 11 +++
 security/landlock/lsm.c | 40 +++-
 security/landlock/manager.c | 32 
 8 files changed, 131 insertions(+), 4 deletions(-)

diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index 6cca7924ee17..439c681159e2 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -14,8 +14,15 @@ struct sk_buff;
 extern struct static_key_false cgroup_bpf_enabled_key;
 #define cgroup_bpf_enabled static_branch_unlikely(_bpf_enabled_key)
 
+#ifdef CONFIG_SECURITY_LANDLOCK
+struct landlock_hooks;
+#endif /* CONFIG_SECURITY_LANDLOCK */
+
 union bpf_object {
struct bpf_prog *prog;
+#ifdef CONFIG_SECURITY_LANDLOCK
+   struct landlock_hooks *hooks;
+#endif /* CONFIG_SECURITY_LANDLOCK */
 };
 
 struct cgroup_bpf {
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 861b4677fc5b..fe1023bf7b9d 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -301,8 +301,10 @@ struct cgroup {
/* used to schedule release agent */
struct work_struct release_agent_work;
 
+#ifdef CONFIG_CGROUP_BPF
/* used to store eBPF programs */
struct cgroup_bpf bpf;
+#endif /* CONFIG_CGROUP_BPF */
 
/* ids of the ancestors at each level including self */
int ancestor_ids[];
diff --git a/include/linux/landlock.h b/include/linux/landlock.h
index 932ae57fa70e..179a848110f3 100644
--- a/include/linux/landlock.h
+++ b/include/linux/landlock.h
@@ -19,6 +19,9 @@
 #include  /* struct seccomp_filter */
 #endif /* CONFIG_SECCOMP_FILTER */
 
+#ifdef CONFIG_CGROUP_BPF
+#include  /* struct cgroup */
+#endif /* CONFIG_CGROUP_BPF */
 
 #ifdef CONFIG_SECCOMP_FILTER
 struct landlock_seccomp_ret {
@@ -65,6 +68,7 @@ struct landlock_hooks {
 
 
 struct landlock_hooks *new_landlock_hooks(void);
+void get_landlock_hooks(struct landlock_hooks *hooks);
 void put_landlock_hooks(struct landlock_hooks *hooks);
 
 #ifdef CONFIG_SECCOMP_FILTER
@@ -73,5 +77,10 @@ int landlock_seccomp_set_hook(unsigned int flags,
const char __user *user_bpf_fd);
 #endif /* CONFIG_SECCOMP_FILTER */
 
+#ifdef CONFIG_CGROUP_BPF
+struct landlock_hooks *landlock_cgroup_set_hook(struct cgroup *cgrp,
+   struct bpf_prog *prog);
+#endif /* CONFIG_CGROUP_BPF */
+
 #endif /* CONFIG_SECURITY_LANDLOCK */
 #endif /* _LINUX_LANDLOCK_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 905dcace7255..12e61508f879 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -124,6 +124,7 @@ enum bpf_prog_type {
 enum bpf_attach_type {
BPF_CGROUP_INET_INGRESS,
BPF_CGROUP_INET_EGRESS,
+   BPF_CGROUP_LANDLOCK,
__MAX_BPF_ATTACH_TYPE
 };
 
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 7b75fa692617..1c18fe46958a 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 
 DEFINE_STATIC_KEY_FALSE(cgroup_bpf_enabled_key);
 EXPORT_SYMBOL(cgroup_bpf_enabled_key);
@@ -31,7 +32,15 @@ void cgroup_bpf_put(struct cgroup *cgrp)
union bpf_object pinned = cgrp->bpf.pinned[type];
 
if (pinned.prog) {
-   bpf_prog_put(pinned.prog);
+   switch (type) {
+ 

[RFC v3 17/22] cgroup: Add access check for cgroup_get_from_fd()

2016-09-14 Thread Mickaël Salaün
Add security access check for cgroup backed FD. The "cgroup.procs" file
of the corresponding cgroup must be readable to identify the cgroup, and
writable to prove that the current process can manage this cgroup (e.g.
through delegation). This is similar to the check done by
cgroup_procs_write_permission().

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Daniel Mack <dan...@zonque.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Tejun Heo <t...@kernel.org>
---
 include/linux/cgroup.h |  2 +-
 kernel/bpf/arraymap.c  |  2 +-
 kernel/bpf/syscall.c   |  6 +++---
 kernel/cgroup.c| 16 +++-
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index c4688742ddc4..5767d471e292 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -87,7 +87,7 @@ struct cgroup_subsys_state *css_tryget_online_from_dir(struct 
dentry *dentry,
   struct cgroup_subsys 
*ss);
 
 struct cgroup *cgroup_get_from_path(const char *path);
-struct cgroup *cgroup_get_from_fd(int fd);
+struct cgroup *cgroup_get_from_fd(int fd, int access_mask);
 
 int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
 int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index edaab4c87292..1d4de8e0ab13 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -552,7 +552,7 @@ static void *cgroup_fd_array_get_ptr(struct bpf_map *map,
 struct file *map_file /* not used */,
 int fd)
 {
-   return cgroup_get_from_fd(fd);
+   return cgroup_get_from_fd(fd, MAY_READ);
 }
 
 static void cgroup_fd_array_put_ptr(void *ptr)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index e9c5add327e6..f90225dbbb59 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 
 DEFINE_PER_CPU(int, bpf_prog_active);
 
@@ -863,7 +864,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
if (IS_ERR(prog))
return PTR_ERR(prog);
 
-   cgrp = cgroup_get_from_fd(attr->target_fd);
+   cgrp = cgroup_get_from_fd(attr->target_fd, MAY_WRITE);
if (IS_ERR(cgrp)) {
bpf_prog_put(prog);
return PTR_ERR(cgrp);
@@ -891,10 +892,9 @@ static int bpf_prog_detach(const union bpf_attr *attr)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
 
-   cgrp = cgroup_get_from_fd(attr->target_fd);
+   cgrp = cgroup_get_from_fd(attr->target_fd, MAY_WRITE);
if (IS_ERR(cgrp))
return PTR_ERR(cgrp);
-
result = cgroup_bpf_update(cgrp, NULL, attr->attach_type);
cgroup_put(cgrp);
break;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 48b650a640a9..3bbaf3f02ed2 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6241,17 +6241,20 @@ EXPORT_SYMBOL_GPL(cgroup_get_from_path);
 /**
  * cgroup_get_from_fd - get a cgroup pointer from a fd
  * @fd: fd obtained by open(cgroup2_dir)
+ * @access_mask: contains the permission mask
  *
  * Find the cgroup from a fd which should be obtained
  * by opening a cgroup directory.  Returns a pointer to the
  * cgroup on success. ERR_PTR is returned if the cgroup
  * cannot be found.
  */
-struct cgroup *cgroup_get_from_fd(int fd)
+struct cgroup *cgroup_get_from_fd(int fd, int access_mask)
 {
struct cgroup_subsys_state *css;
struct cgroup *cgrp;
struct file *f;
+   struct inode *inode;
+   int ret;
 
f = fget_raw(fd);
if (!f)
@@ -6268,6 +6271,17 @@ struct cgroup *cgroup_get_from_fd(int fd)
return ERR_PTR(-EBADF);
}
 
+   ret = -ENOMEM;
+   inode = kernfs_get_inode(f->f_path.dentry->d_sb, cgrp->procs_file.kn);
+   if (inode) {
+   ret = inode_permission(inode, access_mask);
+   iput(inode);
+   }
+   if (ret) {
+   cgroup_put(cgrp);
+   return ERR_PTR(ret);
+   }
+
return cgrp;
 }
 EXPORT_SYMBOL_GPL(cgroup_get_from_fd);
-- 
2.9.3



[RFC v3 18/22] cgroup,landlock: Add CGRP_NO_NEW_PRIVS to handle unprivileged hooks

2016-09-14 Thread Mickaël Salaün
Add a new flag CGRP_NO_NEW_PRIVS for each cgroup. This flag is initially
set for all cgroup except the root. The flag is clear when a new process
without the no_new_privs flags is attached to the cgroup.

If a cgroup is landlocked, then any new attempt, from an unprivileged
process, to attach a process without no_new_privs to this cgroup will
be denied.

This allows to safely manage Landlock rules with cgroup delegation as
with seccomp.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Daniel Mack <dan...@zonque.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Tejun Heo <t...@kernel.org>
---
 include/linux/cgroup-defs.h |  7 +++
 kernel/bpf/syscall.c|  7 ---
 kernel/cgroup.c | 44 ++--
 security/landlock/manager.c |  7 +++
 4 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index fe1023bf7b9d..ce0e4c90ae7d 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -59,6 +59,13 @@ enum {
 * specified at mount time and thus is implemented here.
 */
CGRP_CPUSET_CLONE_CHILDREN,
+   /*
+* Keep track of the no_new_privs property of processes in the cgroup.
+* This is useful to quickly check if all processes in the cgroup have
+* their no_new_privs bit on. This flag is initially set to true but
+* ANDed with every processes coming in the cgroup.
+*/
+   CGRP_NO_NEW_PRIVS,
 };
 
 /* cgroup_root->flags */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index f90225dbbb59..ff8b53a8a2a0 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -849,9 +849,10 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 
case BPF_CGROUP_LANDLOCK:
 #ifdef CONFIG_SECURITY_LANDLOCK
-   if (!capable(CAP_SYS_ADMIN))
-   return -EPERM;
-
+   /*
+* security/capability check done in landlock_cgroup_set_hook()
+* called by cgroup_bpf_update()
+*/
prog = bpf_prog_get_type(attr->attach_bpf_fd,
BPF_PROG_TYPE_LANDLOCK);
break;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 3bbaf3f02ed2..913e2d3b6d55 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -62,6 +62,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #define CREATE_TRACE_POINTS
@@ -1985,6 +1986,7 @@ static void init_cgroup_root(struct cgroup_root *root,
strcpy(root->name, opts->name);
if (opts->cpuset_clone_children)
set_bit(CGRP_CPUSET_CLONE_CHILDREN, >cgrp.flags);
+   /* no CGRP_NO_NEW_PRIVS flag for the root */
 }
 
 static int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask)
@@ -2812,14 +2814,35 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp,
LIST_HEAD(preloaded_csets);
struct task_struct *task;
int ret;
+#if defined(CONFIG_CGROUP_BPF) && defined(CONFIG_SECURITY_LANDLOCK)
+   bool no_new_privs;
+#endif /* CONFIG_CGROUP_BPF && CONFIG_SECURITY_LANDLOCK */
 
if (!cgroup_may_migrate_to(dst_cgrp))
return -EBUSY;
 
+   task = leader;
+#if defined(CONFIG_CGROUP_BPF) && defined(CONFIG_SECURITY_LANDLOCK)
+   no_new_privs = !!(dst_cgrp->flags & BIT_ULL(CGRP_NO_NEW_PRIVS));
+   do {
+   no_new_privs = no_new_privs && task_no_new_privs(task);
+   if (!no_new_privs) {
+   if (dst_cgrp->bpf.pinned[BPF_CGROUP_LANDLOCK].hooks &&
+   security_capable_noaudit(current_cred(),
+   current_user_ns(),
+   CAP_SYS_ADMIN) != 0)
+   return -EPERM;
+   clear_bit(CGRP_NO_NEW_PRIVS, _cgrp->flags);
+   break;
+   }
+   if (!threadgroup)
+   break;
+   } while_each_thread(leader, task);
+#endif /* CONFIG_CGROUP_BPF && CONFIG_SECURITY_LANDLOCK */
+
/* look up all src csets */
spin_lock_irq(_set_lock);
rcu_read_lock();
-   task = leader;
do {
cgroup_migrate_add_src(task_css_set(task), dst_cgrp,
   _csets);
@@ -4345,9 +4368,22 @@ int cgroup_transfer_tasks(struct cgroup *to, struct 
cgroup *from)
return -EBUSY;
 
mutex_lock(_mutex);
-
percpu_down_write(_threadgroup_rwsem);
 
+#if defined(CONFIG_CGROUP_BPF) && defined(CONFIG_SECU

[RFC v3 22/22] samples/landlock: Add sandbox example

2016-09-14 Thread Mickaël Salaün
Add a basic sandbox tool to create a process isolated from some part of
the system. This can depend of the current cgroup.

Example with the current process hierarchy (seccomp):

  $ ls /home
  user1
  $ LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
  ./samples/landlock/sandbox /bin/sh -i
  Launching a new sandboxed process.
  $ ls /home
  ls: cannot open directory '/home': Permission denied

Example with a cgroup:

  $ mkdir /sys/fs/cgroup/sandboxed
  $ ls /home
  user1
  $ LANDLOCK_CGROUPS='/sys/fs/cgroup/sandboxed' \
  LANDLOCK_ALLOWED='/bin:/lib:/usr:/tmp:/proc/self/fd/0' \
  ./samples/landlock/sandbox
  Ready to sandbox with cgroups.
  $ ls /home
  user1
  $ echo $$ > /sys/fs/cgroup/sandboxed/cgroup.procs
  $ ls /home
  ls: cannot open directory '/home': Permission denied

Changes since v2:
* use BPF_PROG_ATTACH for cgroup handling

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 samples/Makefile|   2 +-
 samples/landlock/.gitignore |   1 +
 samples/landlock/Makefile   |  16 +++
 samples/landlock/sandbox.c  | 307 
 4 files changed, 325 insertions(+), 1 deletion(-)
 create mode 100644 samples/landlock/.gitignore
 create mode 100644 samples/landlock/Makefile
 create mode 100644 samples/landlock/sandbox.c

diff --git a/samples/Makefile b/samples/Makefile
index 1a20169d85ac..a2dcd57ca7ac 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -2,4 +2,4 @@
 
 obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ trace_events/ livepatch/ \
   hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
-  configfs/ connector/ v4l/ trace_printk/
+  configfs/ connector/ v4l/ trace_printk/ landlock/
diff --git a/samples/landlock/.gitignore b/samples/landlock/.gitignore
new file mode 100644
index ..f6c6da930a30
--- /dev/null
+++ b/samples/landlock/.gitignore
@@ -0,0 +1 @@
+/sandbox
diff --git a/samples/landlock/Makefile b/samples/landlock/Makefile
new file mode 100644
index ..d1044b2afd27
--- /dev/null
+++ b/samples/landlock/Makefile
@@ -0,0 +1,16 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+hostprogs-$(CONFIG_SECURITY_LANDLOCK) := sandbox
+sandbox-objs := sandbox.o
+
+always := $(hostprogs-y)
+
+HOSTCFLAGS += -I$(objtree)/usr/include
+
+# Trick to allow make to be run from this directory
+all:
+   $(MAKE) -C ../../ $$PWD/
+
+clean:
+   $(MAKE) -C ../../ M=$$PWD clean
diff --git a/samples/landlock/sandbox.c b/samples/landlock/sandbox.c
new file mode 100644
index ..9d6ac00cdd23
--- /dev/null
+++ b/samples/landlock/sandbox.c
@@ -0,0 +1,307 @@
+/*
+ * Landlock LSM - Sandbox example
+ *
+ * Copyright (C) 2016  Mickaël Salaün <m...@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3, as
+ * published by the Free Software Foundation.
+ */
+
+#define _GNU_SOURCE
+#include 
+#include  /* open() */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "../../tools/include/linux/filter.h"
+
+#include "../bpf/libbpf.c"
+
+#ifndef seccomp
+static int seccomp(unsigned int op, unsigned int flags, void *args)
+{
+   errno = 0;
+   return syscall(__NR_seccomp, op, flags, args);
+}
+#endif
+
+static int landlock_prog_load(const struct bpf_insn *insns, int prog_len,
+   enum landlock_hook_id hook_id, __u64 access)
+{
+   union bpf_attr attr = {
+   .prog_type = BPF_PROG_TYPE_LANDLOCK,
+   .insns = ptr_to_u64((void *) insns),
+   .insn_cnt = prog_len / sizeof(struct bpf_insn),
+   .license = ptr_to_u64((void *) "GPL"),
+   .log_buf = ptr_to_u64(bpf_log_buf),
+   .log_size = LOG_BUF_SIZE,
+   .log_level = 1,
+   .prog_subtype.landlock_hook = {
+   .id = hook_id,
+   .origin = LANDLOCK_FLAG_ORIGIN_SECCOMP |
+   LANDLOCK_FLAG_ORIGIN_SYSCALL |
+   LANDLOCK_FLAG_ORIGIN_INTERRUPT,
+   .access = access,
+   },
+   };
+
+   /* assign one field outside of struct init to make sure any
+* padding is zero initialized
+*/
+   attr.kern_version = 0;
+
+   bpf_log_buf[0] = 0;
+
+   return syscall(__NR_bpf, BPF_PROG_LOAD, , sizeof(attr));
+}
+
+#define ARRAY_SIZE(a)  (sizeof(a) / s

[RFC v3 20/22] landlock: Add update and debug access flags

2016-09-14 Thread Mickaël Salaün
For now, the update and debug accesses are only accessible to a process
with CAP_SYS_ADMIN. This could change in the future.

The capability check is statically done when loading an eBPF program,
according to the current process. If the process has enough rights and
set the appropriate access flags, then the dedicated functions or data
will be accessible.

With the update access, the following functions are available:
* bpf_map_lookup_elem
* bpf_map_update_elem
* bpf_map_delete_elem
* bpf_tail_call

With the debug access, the following functions are available:
* bpf_trace_printk
* bpf_get_prandom_u32
* bpf_get_current_pid_tgid
* bpf_get_current_uid_gid
* bpf_get_current_comm

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Sargun Dhillon <sar...@sargun.me>
---
 include/uapi/linux/bpf.h |  4 +++-
 security/landlock/lsm.c  | 54 
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 3cc52e51357f..8cfc2de2ab76 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -584,7 +584,9 @@ enum landlock_hook_id {
 #define _LANDLOCK_FLAG_ORIGIN_MASK ((1 << 3) - 1)
 
 /* context of function access flags */
-#define _LANDLOCK_FLAG_ACCESS_MASK ((1ULL << 0) - 1)
+#define LANDLOCK_FLAG_ACCESS_UPDATE(1 << 0)
+#define LANDLOCK_FLAG_ACCESS_DEBUG (1 << 1)
+#define _LANDLOCK_FLAG_ACCESS_MASK ((1ULL << 2) - 1)
 
 /* Handle check flags */
 #define LANDLOCK_FLAG_FS_DENTRY(1 << 0)
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index 2a15839a08c8..56c45abe979c 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -202,11 +202,57 @@ static int landlock_run_prog(enum landlock_hook_id 
hook_id, __u64 args[6])
 static const struct bpf_func_proto *bpf_landlock_func_proto(
enum bpf_func_id func_id, union bpf_prog_subtype *prog_subtype)
 {
+   bool access_update = !!(prog_subtype->landlock_hook.access &
+   LANDLOCK_FLAG_ACCESS_UPDATE);
+   bool access_debug = !!(prog_subtype->landlock_hook.access &
+   LANDLOCK_FLAG_ACCESS_DEBUG);
+
switch (func_id) {
case BPF_FUNC_landlock_cmp_fs_prop_with_struct_file:
return _landlock_cmp_fs_prop_with_struct_file_proto;
case BPF_FUNC_landlock_cmp_fs_beneath_with_struct_file:
return _landlock_cmp_fs_beneath_with_struct_file_proto;
+
+   /* access_update */
+   case BPF_FUNC_map_lookup_elem:
+   if (access_update)
+   return _map_lookup_elem_proto;
+   return NULL;
+   case BPF_FUNC_map_update_elem:
+   if (access_update)
+   return _map_update_elem_proto;
+   return NULL;
+   case BPF_FUNC_map_delete_elem:
+   if (access_update)
+   return _map_delete_elem_proto;
+   return NULL;
+   case BPF_FUNC_tail_call:
+   if (access_update)
+   return _tail_call_proto;
+   return NULL;
+
+   /* access_debug */
+   case BPF_FUNC_trace_printk:
+   if (access_debug)
+   return bpf_get_trace_printk_proto();
+   return NULL;
+   case BPF_FUNC_get_prandom_u32:
+   if (access_debug)
+   return _get_prandom_u32_proto;
+   return NULL;
+   case BPF_FUNC_get_current_pid_tgid:
+   if (access_debug)
+   return _get_current_pid_tgid_proto;
+   return NULL;
+   case BPF_FUNC_get_current_uid_gid:
+   if (access_debug)
+   return _get_current_uid_gid_proto;
+   return NULL;
+   case BPF_FUNC_get_current_comm:
+   if (access_debug)
+   return _get_current_comm_proto;
+   return NULL;
+
default:
return NULL;
}
@@ -348,6 +394,14 @@ static inline bool bpf_landlock_is_valid_subtype(
if (prog_subtype->landlock_hook.access & ~_LANDLOCK_FLAG_ACCESS_MASK)
return false;
 
+   /* check access flags */
+   if (prog_subtype->landlock_hook.access & LANDLOCK_FLAG_ACCESS_UPDATE &&
+   !capable(CAP_SYS_ADMIN))
+   return false;
+   if (prog_subtype->landlock_hook.access & LANDLOCK_FLAG_ACCESS_DEBUG &&
+   !capable(CAP_SYS_ADMIN))
+   return false;
+
return true;
 }
 
-- 
2.9.3



[RFC v3 09/22] seccomp: Move struct seccomp_filter in seccomp.h

2016-09-14 Thread Mickaël Salaün
Set struct seccomp_filter public because of the next use of
the new field thread_prev added for Landlock LSM.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
---
 include/linux/seccomp.h | 27 ++-
 kernel/seccomp.c| 26 --
 2 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index ecc296c137cd..a0459a7315ce 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -10,7 +10,32 @@
 #include 
 #include 
 
-struct seccomp_filter;
+/**
+ * struct seccomp_filter - container for seccomp BPF programs
+ *
+ * @usage: reference count to manage the object lifetime.
+ * get/put helpers should be used when accessing an instance
+ * outside of a lifetime-guarded section.  In general, this
+ * is only needed for handling filters shared across tasks.
+ * @prev: points to a previously installed, or inherited, filter
+ * @prog: the BPF program to evaluate
+ *
+ * seccomp_filter objects are organized in a tree linked via the @prev
+ * pointer.  For any task, it appears to be a singly-linked list starting
+ * with current->seccomp.filter, the most recently attached or inherited 
filter.
+ * However, multiple filters may share a @prev node, by way of fork(), which
+ * results in a unidirectional tree existing in memory.  This is similar to
+ * how namespaces work.
+ *
+ * seccomp_filter objects should never be modified after being attached
+ * to a task_struct (other than @usage).
+ */
+struct seccomp_filter {
+   atomic_t usage;
+   struct seccomp_filter *prev;
+   struct bpf_prog *prog;
+};
+
 /**
  * struct seccomp - the state of a seccomp'ed process
  *
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index dccfc05cb3ec..1867bbfa7c6c 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -33,32 +33,6 @@
 #include 
 #include 
 
-/**
- * struct seccomp_filter - container for seccomp BPF programs
- *
- * @usage: reference count to manage the object lifetime.
- * get/put helpers should be used when accessing an instance
- * outside of a lifetime-guarded section.  In general, this
- * is only needed for handling filters shared across tasks.
- * @prev: points to a previously installed, or inherited, filter
- * @prog: the BPF program to evaluate
- *
- * seccomp_filter objects are organized in a tree linked via the @prev
- * pointer.  For any task, it appears to be a singly-linked list starting
- * with current->seccomp.filter, the most recently attached or inherited 
filter.
- * However, multiple filters may share a @prev node, by way of fork(), which
- * results in a unidirectional tree existing in memory.  This is similar to
- * how namespaces work.
- *
- * seccomp_filter objects should never be modified after being attached
- * to a task_struct (other than @usage).
- */
-struct seccomp_filter {
-   atomic_t usage;
-   struct seccomp_filter *prev;
-   struct bpf_prog *prog;
-};
-
 /* Limit any path through the tree to 256KB worth of instructions. */
 #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
 
-- 
2.9.3



[RFC v3 04/22] bpf: Set register type according to is_valid_access()

2016-09-14 Thread Mickaël Salaün
This fix a pointer leak when an unprivileged eBPF program read a pointer
value from the context. Even if is_valid_access() returns a pointer
type, the eBPF verifier replace it with UNKNOWN_VALUE. The register
value containing an address is then allowed to leak. Moreover, this
prevented unprivileged eBPF programs to use functions with (legitimate)
pointer arguments.

This bug was not a problem until now because the only unprivileged eBPF
program allowed is of type BPF_PROG_TYPE_SOCKET_FILTER and all the types
from its context are UNKNOWN_VALUE.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Fixes: 969bf05eb3ce ("bpf: direct packet access")
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 kernel/bpf/verifier.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c0c4a92dae8c..608cbffb0e86 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -794,10 +794,8 @@ static int check_mem_access(struct verifier_env *env, u32 
regno, int off,
}
err = check_ctx_access(env, off, size, t, _type);
if (!err && t == BPF_READ && value_regno >= 0) {
-   mark_reg_unknown_value(state->regs, value_regno);
-   if (env->allow_ptr_leaks)
-   /* note that reg.[id|off|range] == 0 */
-   state->regs[value_regno].type = reg_type;
+   /* note that reg.[id|off|range] == 0 */
+   state->regs[value_regno].type = reg_type;
}
 
} else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) {
-- 
2.9.3



[RFC v3 08/22] seccomp: Fix documentation for struct seccomp_filter

2016-09-14 Thread Mickaël Salaün
Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
---
 kernel/seccomp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 0db7c8a2afe2..dccfc05cb3ec 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -41,8 +41,7 @@
  * outside of a lifetime-guarded section.  In general, this
  * is only needed for handling filters shared across tasks.
  * @prev: points to a previously installed, or inherited, filter
- * @len: the number of instructions in the program
- * @insnsi: the BPF program instructions to evaluate
+ * @prog: the BPF program to evaluate
  *
  * seccomp_filter objects are organized in a tree linked via the @prev
  * pointer.  For any task, it appears to be a singly-linked list starting
-- 
2.9.3



[RFC v3 14/22] bpf/cgroup: Make cgroup_bpf_update() return an error code

2016-09-14 Thread Mickaël Salaün
This will be useful to support Landlock for the next commits.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Daniel Mack <dan...@zonque.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Tejun Heo <t...@kernel.org>
---
 include/linux/bpf-cgroup.h |  4 ++--
 kernel/bpf/cgroup.c|  3 ++-
 kernel/bpf/syscall.c   | 10 ++
 kernel/cgroup.c|  6 --
 4 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index 2234042d7f61..6cca7924ee17 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -31,13 +31,13 @@ struct cgroup_bpf {
 void cgroup_bpf_put(struct cgroup *cgrp);
 void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup *parent);
 
-void __cgroup_bpf_update(struct cgroup *cgrp,
+int __cgroup_bpf_update(struct cgroup *cgrp,
 struct cgroup *parent,
 struct bpf_prog *prog,
 enum bpf_attach_type type);
 
 /* Wrapper for __cgroup_bpf_update() protected by cgroup_mutex */
-void cgroup_bpf_update(struct cgroup *cgrp,
+int cgroup_bpf_update(struct cgroup *cgrp,
   struct bpf_prog *prog,
   enum bpf_attach_type type);
 
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 782878ec4f2d..7b75fa692617 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -83,7 +83,7 @@ void cgroup_bpf_inherit(struct cgroup *cgrp, struct cgroup 
*parent)
  *
  * Must be called with cgroup_mutex held.
  */
-void __cgroup_bpf_update(struct cgroup *cgrp,
+int __cgroup_bpf_update(struct cgroup *cgrp,
 struct cgroup *parent,
 struct bpf_prog *prog,
 enum bpf_attach_type type)
@@ -117,6 +117,7 @@ void __cgroup_bpf_update(struct cgroup *cgrp,
bpf_prog_put(old_pinned.prog);
static_branch_dec(_bpf_enabled_key);
}
+   return 0;
 }
 
 /**
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 45a91d59..c978f2d9a1b3 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -831,6 +831,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 {
struct bpf_prog *prog;
struct cgroup *cgrp;
+   int result;
 
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -858,10 +859,10 @@ static int bpf_prog_attach(const union bpf_attr *attr)
return PTR_ERR(cgrp);
}
 
-   cgroup_bpf_update(cgrp, prog, attr->attach_type);
+   result = cgroup_bpf_update(cgrp, prog, attr->attach_type);
cgroup_put(cgrp);
 
-   return 0;
+   return result;
 }
 
 #define BPF_PROG_DETACH_LAST_FIELD attach_type
@@ -869,6 +870,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
 static int bpf_prog_detach(const union bpf_attr *attr)
 {
struct cgroup *cgrp;
+   int result = 0;
 
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -883,7 +885,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
if (IS_ERR(cgrp))
return PTR_ERR(cgrp);
 
-   cgroup_bpf_update(cgrp, NULL, attr->attach_type);
+   result = cgroup_bpf_update(cgrp, NULL, attr->attach_type);
cgroup_put(cgrp);
break;
 
@@ -891,7 +893,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
return -EINVAL;
}
 
-   return 0;
+   return result;
 }
 #endif /* CONFIG_CGROUP_BPF */
 
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 87324ce481b1..48b650a640a9 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6450,15 +6450,17 @@ static __init int cgroup_namespaces_init(void)
 subsys_initcall(cgroup_namespaces_init);
 
 #ifdef CONFIG_CGROUP_BPF
-void cgroup_bpf_update(struct cgroup *cgrp,
+int cgroup_bpf_update(struct cgroup *cgrp,
   struct bpf_prog *prog,
   enum bpf_attach_type type)
 {
struct cgroup *parent = cgroup_parent(cgrp);
+   int result;
 
mutex_lock(_mutex);
-   __cgroup_bpf_update(cgrp, parent, prog, type);
+   result = __cgroup_bpf_update(cgrp, parent, prog, type);
mutex_unlock(_mutex);
+   return result;
 }
 #endif /* CONFIG_CGROUP_BPF */
 
-- 
2.9.3



[RFC v3 05/22] bpf,landlock: Add eBPF program subtype and is_valid_subtype() verifier

2016-09-14 Thread Mickaël Salaün
The program subtype goal is to be able to have different static
fine-grained verifications for a unique program type.

The struct bpf_verifier_ops gets a new optional function:
is_valid_subtype(). This new verifier is called at the begening of the
eBPF program verification to check if the (optional) program subtype is
valid.

For now, only Landlock eBPF programs are using a program subtype but
this could be used by other program types in the future.

Cf. the next commit to see how the subtype is used by Landlock LSM.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Link: https://lkml.kernel.org/r/20160827205559.ga43...@ast-mbp.thefacebook.com
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
---
 include/linux/bpf.h  |  8 ++--
 include/linux/filter.h   |  1 +
 include/uapi/linux/bpf.h |  9 +
 kernel/bpf/syscall.c |  5 +++--
 kernel/bpf/verifier.c|  9 +++--
 kernel/trace/bpf_trace.c | 12 
 net/core/filter.c| 21 +
 7 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index eae4ce4542c1..9aa01d9d3d80 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -149,17 +149,21 @@ struct bpf_prog;
 
 struct bpf_verifier_ops {
/* return eBPF function prototype for verification */
-   const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id 
func_id);
+   const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id,
+   union bpf_prog_subtype *prog_subtype);
 
/* return true if 'size' wide access at offset 'off' within bpf_context
 * with 'type' (read or write) is allowed
 */
bool (*is_valid_access)(int off, int size, enum bpf_access_type type,
-   enum bpf_reg_type *reg_type);
+   enum bpf_reg_type *reg_type,
+   union bpf_prog_subtype *prog_subtype);
 
u32 (*convert_ctx_access)(enum bpf_access_type type, int dst_reg,
  int src_reg, int ctx_off,
  struct bpf_insn *insn, struct bpf_prog *prog);
+
+   bool (*is_valid_subtype)(union bpf_prog_subtype *prog_subtype);
 };
 
 struct bpf_prog_type_list {
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 1f09c521adfe..88470cdd3ee1 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -406,6 +406,7 @@ struct bpf_prog {
kmemcheck_bitfield_end(meta);
u32 len;/* Number of filter blocks */
enum bpf_prog_type  type;   /* Type of BPF program */
+   union bpf_prog_subtype  subtype;/* For fine-grained 
verifications */
struct bpf_prog_aux *aux;   /* Auxiliary fields */
struct sock_fprog_kern  *orig_prog; /* Original BPF program */
unsigned int(*bpf_func)(const struct sk_buff *skb,
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index b68de57f7ab8..667b6ef3ff1e 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -127,6 +127,14 @@ enum bpf_attach_type {
 
 #define BPF_F_NO_PREALLOC  (1U << 0)
 
+union bpf_prog_subtype {
+   struct {
+   __u32   id; /* enum landlock_hook_id */
+   __u16   origin; /* LANDLOCK_FLAG_ORIGIN_* */
+   __aligned_u64   access; /* LANDLOCK_FLAG_ACCESS_* */
+   } landlock_hook;
+} __attribute__((aligned(8)));
+
 union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32   map_type;   /* one of enum bpf_map_type */
@@ -155,6 +163,7 @@ union bpf_attr {
__u32   log_size;   /* size of user buffer */
__aligned_u64   log_buf;/* user supplied buffer */
__u32   kern_version;   /* checked when 
prog_type=kprobe */
+   union bpf_prog_subtype prog_subtype;/* checked when 
prog_type=landlock */
};
 
struct { /* anonymous struct used by BPF_OBJ_* commands */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 776c752604b0..8b3f4d2b4802 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -572,7 +572,7 @@ static void fixup_bpf_calls(struct bpf_prog *prog)
continue;
}
 
-   fn = prog->aux->ops->get_func_proto(insn->imm);
+   fn = prog->aux->ops->get_func_proto(insn->imm, 
>subtype);
/* all functions that have prototype and verifier 
allowed
 * programs to call them, must be real in-kernel 
functions
 */
@@ -710,7 +710,7 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum 

[RFC v3 19/22] landlock: Add interrupted origin

2016-09-14 Thread Mickaël Salaün
This third origin of hook call should cover all possible trigger paths
(e.g. page fault). Landlock eBPF programs can then take decisions
accordingly.

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: Kees Cook <keesc...@chromium.org>
---
 include/uapi/linux/bpf.h |  3 ++-
 security/landlock/lsm.c  | 17 +++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 12e61508f879..3cc52e51357f 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -580,7 +580,8 @@ enum landlock_hook_id {
 /* Trigger type */
 #define LANDLOCK_FLAG_ORIGIN_SYSCALL   (1 << 0)
 #define LANDLOCK_FLAG_ORIGIN_SECCOMP   (1 << 1)
-#define _LANDLOCK_FLAG_ORIGIN_MASK ((1 << 2) - 1)
+#define LANDLOCK_FLAG_ORIGIN_INTERRUPT (1 << 2)
+#define _LANDLOCK_FLAG_ORIGIN_MASK ((1 << 3) - 1)
 
 /* context of function access flags */
 #define _LANDLOCK_FLAG_ACCESS_MASK ((1ULL << 0) - 1)
diff --git a/security/landlock/lsm.c b/security/landlock/lsm.c
index 000dd0c7ec3d..2a15839a08c8 100644
--- a/security/landlock/lsm.c
+++ b/security/landlock/lsm.c
@@ -17,6 +17,7 @@
 #include  /* FIELD_SIZEOF() */
 #include 
 #include 
+#include  /* in_interrupt() */
 #include  /* struct seccomp_* */
 #include  /* uintptr_t */
 
@@ -109,6 +110,7 @@ static int landlock_run_prog(enum landlock_hook_id hook_id, 
__u64 args[6])
 #endif /* CONFIG_CGROUP_BPF */
struct landlock_rule *rule;
u32 hook_idx = get_index(hook_id);
+   u16 current_call;
 
struct landlock_data ctx = {
.hook = hook_id,
@@ -128,6 +130,16 @@ static int landlock_run_prog(enum landlock_hook_id 
hook_id, __u64 args[6])
 * prioritize fine-grained policies (i.e. per thread), and return early.
 */
 
+   if (unlikely(in_interrupt())) {
+   current_call = LANDLOCK_FLAG_ORIGIN_INTERRUPT;
+#ifdef CONFIG_SECCOMP_FILTER
+   /* bypass landlock_ret evaluation */
+   goto seccomp_int;
+#endif /* CONFIG_SECCOMP_FILTER */
+   } else {
+   current_call = LANDLOCK_FLAG_ORIGIN_SYSCALL;
+   }
+
 #ifdef CONFIG_SECCOMP_FILTER
/* seccomp triggers and landlock_ret cleanup */
ctx.origin = LANDLOCK_FLAG_ORIGIN_SECCOMP;
@@ -164,8 +176,9 @@ static int landlock_run_prog(enum landlock_hook_id hook_id, 
__u64 args[6])
return -ret;
ctx.cookie = 0;
 
+seccomp_int:
/* syscall trigger */
-   ctx.origin = LANDLOCK_FLAG_ORIGIN_SYSCALL;
+   ctx.origin = current_call;
ret = landlock_run_prog_for_syscall(hook_idx, ,
current->seccomp.landlock_hooks);
if (ret)
@@ -175,7 +188,7 @@ static int landlock_run_prog(enum landlock_hook_id hook_id, 
__u64 args[6])
 #ifdef CONFIG_CGROUP_BPF
/* syscall trigger */
if (cgroup_bpf_enabled) {
-   ctx.origin = LANDLOCK_FLAG_ORIGIN_SYSCALL;
+   ctx.origin = current_call;
/* get the default cgroup associated with the current thread */
cgrp = task_css_set(current)->dfl_cgrp;
ret = landlock_run_prog_for_syscall(hook_idx, ,
-- 
2.9.3



[RFC v3 02/22] bpf: Move u64_to_ptr() to BPF headers and inline it

2016-09-14 Thread Mickaël Salaün
This helper will be useful for arraymap (next commit).

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: David S. Miller <da...@davemloft.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
---
 include/linux/bpf.h  | 6 ++
 kernel/bpf/syscall.c | 6 --
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 9a904f63f8c1..fa9a988400d9 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -274,6 +274,12 @@ static inline void bpf_long_memcpy(void *dst, const void 
*src, u32 size)
 
 /* verify correctness of eBPF program */
 int bpf_check(struct bpf_prog **fp, union bpf_attr *attr);
+
+/* helper to convert user pointers passed inside __aligned_u64 fields */
+static inline void __user *u64_to_ptr(__u64 val)
+{
+   return (void __user *) (unsigned long) val;
+}
 #else
 static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl)
 {
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 1a8592a082ce..776c752604b0 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -252,12 +252,6 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd)
return map;
 }
 
-/* helper to convert user pointers passed inside __aligned_u64 fields */
-static void __user *u64_to_ptr(__u64 val)
-{
-   return (void __user *) (unsigned long) val;
-}
-
 int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
 {
return -ENOTSUPP;
-- 
2.9.3



[RFC v3 06/22] landlock: Add LSM hooks

2016-09-14 Thread Mickaël Salaün
Add LSM hooks which can be used by userland through Landlock (eBPF)
programs. This programs are limited to a whitelist of functions (cf.
next commit). The eBPF program context is depicted by the struct
landlock_data (cf. include/uapi/linux/bpf.h):
* hook: LSM hook ID
* origin: what triggered this Landlock program (syscall, dedicated
  seccomp return or interruption)
* cookie: the 16-bit value from the seccomp filter that triggered this
  Landlock program
* args[6]: array of some LSM hook arguments

The LSM hook arguments can contain raw values as integers or
(unleakable) pointers. The only way to use the pointers are to pass them
to an eBPF function according to their types (e.g. the
bpf_landlock_cmp_fs_beneath_with_struct_file function can use a struct
file pointer).

For each Landlock program, the subtype allows to specify for which LSM
hook the program is dedicated thanks to the "id" field. The "origin"
field must contains each triggers for which the Landlock program will
be called (e.g. every syscall or/and seccomp filters returning
RET_LANDLOCK). The "access" bitfield can be used to allow a program to
access a specific feature from a Landlock hook (i.e. context value or
function). The flag guarding this feature may only be enabled according
to the capabilities of the process loading the program.

For now, there is three hooks for file system access control:
* file_open
* file_permission
* mmap_file

Changes since v2:
* use subtypes instead of dedicated eBPF program types for each hook
  (suggested by Alexei Starovoitov)
* replace convert_ctx_access() with subtype check
* use an array of Landlock program list instead of a single list
* handle running Landlock programs without needing a seccomp filter
* use, check and expose "origin" to Landlock programs
* mask the unused struct cred * (suggested by Andy Lutomirski)

Changes since v1:
* revamp access control from a syscall-based to a LSM hooks-based
* do not use audit cache
* no race conditions by design
* architecture agnostic
* switch from cBPF to eBPF (suggested by Daniel Borkmann)
* new BPF context

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Alexei Starovoitov <a...@kernel.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David S. Miller <da...@davemloft.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
Cc: Will Drewry <w...@chromium.org>
Link: https://lkml.kernel.org/r/20160827205559.ga43...@ast-mbp.thefacebook.com
Link: https://lkml.kernel.org/r/20160827180642.ga38...@ast-mbp.thefacebook.com
Link: 
https://lkml.kernel.org/r/CALCETrUK1umtXMEXXKzMAccNQCVTPA8_XNDf01B5=gazujw...@mail.gmail.com
Link: https://lkml.kernel.org/r/20160827204307.ga43...@ast-mbp.thefacebook.com
---
 include/linux/bpf.h|   5 +
 include/linux/lsm_hooks.h  |   5 +
 include/uapi/linux/bpf.h   |  37 
 kernel/bpf/syscall.c   |  10 +-
 kernel/bpf/verifier.c  |   6 ++
 security/Makefile  |   2 +
 security/landlock/Makefile |   3 +
 security/landlock/lsm.c| 222 +
 security/security.c|   1 +
 9 files changed, 289 insertions(+), 2 deletions(-)
 create mode 100644 security/landlock/Makefile
 create mode 100644 security/landlock/lsm.c

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 9aa01d9d3d80..36c3e482239c 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -85,6 +85,8 @@ enum bpf_arg_type {
 
ARG_PTR_TO_CTX, /* pointer to context */
ARG_ANYTHING,   /* any (initialized) argument is ok */
+
+   ARG_PTR_TO_STRUCT_FILE, /* pointer to struct file */
 };
 
 /* type of values returned from helper functions */
@@ -143,6 +145,9 @@ enum bpf_reg_type {
 */
PTR_TO_PACKET,
PTR_TO_PACKET_END,   /* skb->data + headlen */
+
+   /* Landlock */
+   PTR_TO_STRUCT_FILE,
 };
 
 struct bpf_prog;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 558adfa5c8a8..069af34301d4 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1933,5 +1933,10 @@ void __init loadpin_add_hooks(void);
 #else
 static inline void loadpin_add_hooks(void) { };
 #endif
+#ifdef CONFIG_SECURITY_LANDLOCK
+extern void __init landlock_add_hooks(void);
+#else
+static inline void __init landlock_add_hooks(void) { }
+#endif /* CONFIG_SECURITY_LANDLOCK */
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 667b6ef3ff1e..ad87003fe892 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -108,6 +108,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_XDP,
BPF_PROG_TYPE_PERF_EVENT,
BPF_PROG_TYPE_CGROUP_SOCKET,
+   BPF_PROG_TYPE_LANDLOCK,
 };
 
 enum bpf_attach_type {
@@ -528,6

[RFC v3 10/22] seccomp: Split put_seccomp_filter() with put_seccomp()

2016-09-14 Thread Mickaël Salaün
The semantic is unchanged. This will be useful for the Landlock
integration with seccomp (next commit).

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Andy Lutomirski <l...@amacapital.net>
Cc: Will Drewry <w...@chromium.org>
---
 include/linux/seccomp.h |  5 +++--
 kernel/fork.c   |  2 +-
 kernel/seccomp.c| 18 +-
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index a0459a7315ce..ffdab7cdd162 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -102,13 +102,14 @@ static inline int seccomp_mode(struct seccomp *s)
 #endif /* CONFIG_SECCOMP */
 
 #ifdef CONFIG_SECCOMP_FILTER
-extern void put_seccomp_filter(struct task_struct *tsk);
+extern void put_seccomp(struct task_struct *tsk);
 extern void get_seccomp_filter(struct task_struct *tsk);
 #else  /* CONFIG_SECCOMP_FILTER */
-static inline void put_seccomp_filter(struct task_struct *tsk)
+static inline void put_seccomp(struct task_struct *tsk)
 {
return;
 }
+
 static inline void get_seccomp_filter(struct task_struct *tsk)
 {
return;
diff --git a/kernel/fork.c b/kernel/fork.c
index 3584f521e3a6..99df46f157cf 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -276,7 +276,7 @@ void free_task(struct task_struct *tsk)
free_thread_stack(tsk);
rt_mutex_debug_task_free(tsk);
ftrace_graph_exit_task(tsk);
-   put_seccomp_filter(tsk);
+   put_seccomp(tsk);
arch_release_task_struct(tsk);
free_task_struct(tsk);
 }
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 1867bbfa7c6c..92b15083b1b2 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -36,6 +36,8 @@
 /* Limit any path through the tree to 256KB worth of instructions. */
 #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
 
+static void put_seccomp_filter(struct seccomp_filter *filter);
+
 /*
  * Endianness is explicitly ignored and left for BPF program authors to manage
  * as per the specific architecture.
@@ -286,7 +288,7 @@ static inline void seccomp_sync_threads(void)
 * current's path will hold a reference.  (This also
 * allows a put before the assignment.)
 */
-   put_seccomp_filter(thread);
+   put_seccomp_filter(thread->seccomp.filter);
smp_store_release(>seccomp.filter,
  caller->seccomp.filter);
 
@@ -448,10 +450,11 @@ static inline void seccomp_filter_free(struct 
seccomp_filter *filter)
}
 }
 
-/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
-void put_seccomp_filter(struct task_struct *tsk)
+/* put_seccomp_filter - decrements the ref count of a filter */
+static void put_seccomp_filter(struct seccomp_filter *filter)
 {
-   struct seccomp_filter *orig = tsk->seccomp.filter;
+   struct seccomp_filter *orig = filter;
+
/* Clean up single-reference branches iteratively. */
while (orig && atomic_dec_and_test(>usage)) {
struct seccomp_filter *freeme = orig;
@@ -460,6 +463,11 @@ void put_seccomp_filter(struct task_struct *tsk)
}
 }
 
+void put_seccomp(struct task_struct *tsk)
+{
+   put_seccomp_filter(tsk->seccomp.filter);
+}
+
 /**
  * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
  * @syscall: syscall number to send to userland
@@ -871,7 +879,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned 
long filter_off,
if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
ret = -EFAULT;
 
-   put_seccomp_filter(task);
+   put_seccomp_filter(task->seccomp.filter);
return ret;
 
 out:
-- 
2.9.3



[RFC v3 01/22] landlock: Add Kconfig

2016-09-14 Thread Mickaël Salaün
Initial Landlock Kconfig needed to split the Landlock eBPF and seccomp
parts to ease the review.

Changes from v2:
* add seccomp filter or cgroups (with eBPF programs attached support)
  dependencies

Signed-off-by: Mickaël Salaün <m...@digikod.net>
Cc: James Morris <james.l.mor...@oracle.com>
Cc: Kees Cook <keesc...@chromium.org>
Cc: Serge E. Hallyn <se...@hallyn.com>
---
 security/Kconfig  |  1 +
 security/landlock/Kconfig | 23 +++
 2 files changed, 24 insertions(+)
 create mode 100644 security/landlock/Kconfig

diff --git a/security/Kconfig b/security/Kconfig
index 118f4549404e..c63194c561c5 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -164,6 +164,7 @@ source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/loadpin/Kconfig
 source security/yama/Kconfig
+source security/landlock/Kconfig
 
 source security/integrity/Kconfig
 
diff --git a/security/landlock/Kconfig b/security/landlock/Kconfig
new file mode 100644
index ..dec64270b06d
--- /dev/null
+++ b/security/landlock/Kconfig
@@ -0,0 +1,23 @@
+config SECURITY_LANDLOCK
+   bool "Landlock sandbox support"
+   depends on SECURITY
+   depends on BPF_SYSCALL
+   depends on SECCOMP_FILTER || CGROUP_BPF
+   default y
+   help
+ Landlock is a stacked LSM which allows any user to load a security
+ policy to restrict their processes (i.e. create a sandbox). The
+ policy is a list of stacked eBPF programs for some LSM hooks. Each
+ program can do some access comparison to check if an access request
+ is legitimate.
+
+ You need to enable seccomp filter and/or cgroups (with eBPF programs
+ attached support) to apply a security policy to either a process
+ hierarchy (e.g. application with built-in sandboxing) or a group of
+ processes (e.g. container sandboxing). It is recommended to enable
+ both seccomp filter and cgroups.
+
+ Further information about eBPF can be found in
+ Documentation/networking/filter.txt
+
+ If you are unsure how to answer this question, answer Y.
-- 
2.9.3



<    1   2   3   4   5   6   7   8   9   10   >