[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 
Cc: Kees Cook 
Cc: Alexei Starovoitov 
Cc: James Morris 
Cc: Serge E. Hallyn 
Cc: David S. Miller 
Cc: Daniel Borkmann 
---
 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 
+ *
+ * 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;
+   }
+   struct landlock_handle handle = {
+   .type = BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD,
+

[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 
Cc: Kees Cook 
Cc: Alexei Starovoitov 
Cc: James Morris 
Cc: Serge E. Hallyn 
Cc: David S. Miller 
Cc: Daniel Borkmann 
---
 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 
+ *
+ * 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;
+   }
+   struct landlock_handle handle = {
+   .type = BPF_MAP_HANDLE_TYPE_LANDLOCK_FS_FD,
+   .fd = (__u64)fd,
+   };
+
+   /* register a new LSM handle */
+   if (bpf_update_elem(map_fs, ,