mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 01:59:07 +00:00
Backport from Linux v4.11-rc3-812-gc6bf33827b7d to Linux 4.9.20: https://github.com/landlock-lsm/linux/commits/landlock-v6-linux-v4.9.20 Do not include documentation nor tests. See built documentation here: https://landlock-lsm.github.io/linux-doc/landlock-v6/security/landlock/index.html Signed-off-by: Mickaël Salaün <mic@digikod.net> Link: https://lkml.kernel.org/r/20170328234650.19695-1-mic@digikod.net
356 lines
10 KiB
Diff
356 lines
10 KiB
Diff
From 9fca752f05909f12edd32f619ec40d38a6c2b305 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= <mic@digikod.net>
|
|
Date: Wed, 29 Mar 2017 01:30:33 +0200
|
|
Subject: [PATCH 12/12] bpf: Add a Landlock sandbox example
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
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 v5:
|
|
* cosmetic fixes
|
|
* rebase
|
|
|
|
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 <mic@digikod.net>
|
|
Cc: Alexei Starovoitov <ast@kernel.org>
|
|
Cc: Andy Lutomirski <luto@amacapital.net>
|
|
Cc: Daniel Borkmann <daniel@iogearbox.net>
|
|
Cc: David S. Miller <davem@davemloft.net>
|
|
Cc: James Morris <james.l.morris@oracle.com>
|
|
Cc: Kees Cook <keescook@chromium.org>
|
|
Cc: Serge E. Hallyn <serge@hallyn.com>
|
|
(cherry picked from commit 9c5c745d4c0640a96f30f072cb835c21e7bd3ca6)
|
|
---
|
|
samples/bpf/Makefile | 4 ++
|
|
samples/bpf/bpf_load.c | 30 +++++++++++--
|
|
samples/bpf/landlock1_kern.c | 46 +++++++++++++++++++
|
|
samples/bpf/landlock1_user.c | 102 +++++++++++++++++++++++++++++++++++++++++++
|
|
4 files changed, 178 insertions(+), 4 deletions(-)
|
|
create mode 100644 samples/bpf/landlock1_kern.c
|
|
create mode 100644 samples/bpf/landlock1_user.c
|
|
|
|
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
|
|
index 72c58675973e..c9ce3b2e7a7e 100644
|
|
--- a/samples/bpf/Makefile
|
|
+++ b/samples/bpf/Makefile
|
|
@@ -28,6 +28,7 @@ hostprogs-y += test_current_task_under_cgroup
|
|
hostprogs-y += trace_event
|
|
hostprogs-y += sampleip
|
|
hostprogs-y += tc_l2_redirect
|
|
+hostprogs-y += landlock1
|
|
|
|
test_verifier-objs := test_verifier.o libbpf.o
|
|
test_maps-objs := test_maps.o libbpf.o
|
|
@@ -58,6 +59,7 @@ test_current_task_under_cgroup-objs := bpf_load.o libbpf.o \
|
|
trace_event-objs := bpf_load.o libbpf.o trace_event_user.o
|
|
sampleip-objs := bpf_load.o libbpf.o sampleip_user.o
|
|
tc_l2_redirect-objs := bpf_load.o libbpf.o tc_l2_redirect_user.o
|
|
+landlock1-objs := bpf_load.o libbpf.o landlock1_user.o
|
|
|
|
# Tell kbuild to always build the programs
|
|
always := $(hostprogs-y)
|
|
@@ -88,6 +90,7 @@ always += xdp2_kern.o
|
|
always += test_current_task_under_cgroup_kern.o
|
|
always += trace_event_kern.o
|
|
always += sampleip_kern.o
|
|
+always += landlock1_kern.o
|
|
|
|
HOSTCFLAGS += -I$(objtree)/usr/include
|
|
|
|
@@ -115,6 +118,7 @@ HOSTLOADLIBES_test_current_task_under_cgroup += -lelf
|
|
HOSTLOADLIBES_trace_event += -lelf
|
|
HOSTLOADLIBES_sampleip += -lelf
|
|
HOSTLOADLIBES_tc_l2_redirect += -l elf
|
|
+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 40cf828a37c7..1a461afb1d82 100644
|
|
--- a/samples/bpf/bpf_load.c
|
|
+++ b/samples/bpf/bpf_load.c
|
|
@@ -25,6 +25,8 @@
|
|
|
|
static char license[128];
|
|
static int kern_version;
|
|
+static union bpf_prog_subtype subtype = {};
|
|
+static bool has_subtype;
|
|
static bool processed_sec[128];
|
|
int map_fd[MAX_MAPS];
|
|
int prog_fd[MAX_PROGS];
|
|
@@ -52,6 +54,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
|
|
bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0;
|
|
bool is_xdp = strncmp(event, "xdp", 3) == 0;
|
|
bool is_perf_event = strncmp(event, "perf_event", 10) == 0;
|
|
+ bool is_landlock = strncmp(event, "landlock", 8) == 0;
|
|
enum bpf_prog_type prog_type;
|
|
char buf[256];
|
|
int fd, efd, err, id;
|
|
@@ -73,6 +76,13 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
|
|
prog_type = BPF_PROG_TYPE_XDP;
|
|
} else if (is_perf_event) {
|
|
prog_type = BPF_PROG_TYPE_PERF_EVENT;
|
|
+ } else if (is_landlock) {
|
|
+ prog_type = BPF_PROG_TYPE_LANDLOCK;
|
|
+ if (!has_subtype) {
|
|
+ printf("No subtype\n");
|
|
+ return -1;
|
|
+ }
|
|
+ st = &subtype;
|
|
} else {
|
|
printf("Unknown event '%s'\n", event);
|
|
return -1;
|
|
@@ -86,7 +96,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
|
|
|
|
prog_fd[prog_cnt++] = fd;
|
|
|
|
- if (is_xdp || is_perf_event)
|
|
+ if (is_xdp || is_perf_event || is_landlock)
|
|
return 0;
|
|
|
|
if (is_socket) {
|
|
@@ -261,6 +271,7 @@ int load_bpf_file(char *path)
|
|
kern_version = 0;
|
|
memset(license, 0, sizeof(license));
|
|
memset(processed_sec, 0, sizeof(processed_sec));
|
|
+ has_subtype = false;
|
|
|
|
if (elf_version(EV_CURRENT) == EV_NONE)
|
|
return 1;
|
|
@@ -306,6 +317,16 @@ int load_bpf_file(char *path)
|
|
processed_sec[i] = true;
|
|
if (load_maps(data->d_buf, data->d_size))
|
|
return 1;
|
|
+ } else if (strcmp(shname, "subtype") == 0) {
|
|
+ processed_sec[i] = true;
|
|
+ if (data->d_size != sizeof(union bpf_prog_subtype)) {
|
|
+ printf("invalid size of subtype section %zd\n",
|
|
+ data->d_size);
|
|
+ return 1;
|
|
+ }
|
|
+ memcpy(&subtype, data->d_buf,
|
|
+ sizeof(union bpf_prog_subtype));
|
|
+ has_subtype = true;
|
|
} else if (shdr.sh_type == SHT_SYMTAB) {
|
|
symbols = data;
|
|
}
|
|
@@ -338,14 +359,14 @@ int load_bpf_file(char *path)
|
|
memcmp(shname_prog, "tracepoint/", 11) == 0 ||
|
|
memcmp(shname_prog, "xdp", 3) == 0 ||
|
|
memcmp(shname_prog, "perf_event", 10) == 0 ||
|
|
- memcmp(shname_prog, "socket", 6) == 0)
|
|
+ memcmp(shname_prog, "socket", 6) == 0 ||
|
|
+ memcmp(shname_prog, "landlock", 8) == 0)
|
|
load_and_attach(shname_prog, insns, data_prog->d_size);
|
|
}
|
|
}
|
|
|
|
/* load programs that don't use maps */
|
|
for (i = 1; i < ehdr.e_shnum; i++) {
|
|
-
|
|
if (processed_sec[i])
|
|
continue;
|
|
|
|
@@ -357,7 +378,8 @@ int load_bpf_file(char *path)
|
|
memcmp(shname, "tracepoint/", 11) == 0 ||
|
|
memcmp(shname, "xdp", 3) == 0 ||
|
|
memcmp(shname, "perf_event", 10) == 0 ||
|
|
- memcmp(shname, "socket", 6) == 0)
|
|
+ memcmp(shname, "socket", 6) == 0 ||
|
|
+ memcmp(shname, "landlock", 8) == 0)
|
|
load_and_attach(shname, data->d_buf, data->d_size);
|
|
}
|
|
|
|
diff --git a/samples/bpf/landlock1_kern.c b/samples/bpf/landlock1_kern.c
|
|
new file mode 100644
|
|
index 000000000000..b8a9b0ca84c9
|
|
--- /dev/null
|
|
+++ b/samples/bpf/landlock1_kern.c
|
|
@@ -0,0 +1,46 @@
|
|
+/*
|
|
+ * Landlock rule - partial read-only filesystem
|
|
+ *
|
|
+ * Copyright © 2017 Mickaël Salaün <mic@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.
|
|
+ */
|
|
+
|
|
+#define KBUILD_MODNAME "foo"
|
|
+#include <uapi/linux/bpf.h>
|
|
+#include <uapi/linux/stat.h> /* S_ISCHR() */
|
|
+#include "bpf_helpers.h"
|
|
+
|
|
+SEC("landlock1")
|
|
+static int landlock_fs_prog1(struct landlock_context *ctx)
|
|
+{
|
|
+ char fmt_error[] = "landlock1: error: get_mode:%lld\n";
|
|
+ char fmt_name[] = "landlock1: syscall:%d\n";
|
|
+ long long ret;
|
|
+
|
|
+ if (!(ctx->arg2 & LANDLOCK_ACTION_FS_WRITE))
|
|
+ return 0;
|
|
+ ret = bpf_handle_fs_get_mode((void *)ctx->arg1);
|
|
+ if (ret < 0) {
|
|
+ bpf_trace_printk(fmt_error, sizeof(fmt_error), ret);
|
|
+ return 1;
|
|
+ }
|
|
+ if (S_ISCHR(ret))
|
|
+ return 0;
|
|
+ bpf_trace_printk(fmt_name, sizeof(fmt_name), ctx->syscall_nr);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+SEC("subtype")
|
|
+static union bpf_prog_subtype _subtype = {
|
|
+ .landlock_rule = {
|
|
+ .version = 1,
|
|
+ .event = LANDLOCK_SUBTYPE_EVENT_FS,
|
|
+ .ability = LANDLOCK_SUBTYPE_ABILITY_DEBUG,
|
|
+ }
|
|
+};
|
|
+
|
|
+SEC("license")
|
|
+static const char _license[] = "GPL";
|
|
diff --git a/samples/bpf/landlock1_user.c b/samples/bpf/landlock1_user.c
|
|
new file mode 100644
|
|
index 000000000000..6f79eb0ee6db
|
|
--- /dev/null
|
|
+++ b/samples/bpf/landlock1_user.c
|
|
@@ -0,0 +1,102 @@
|
|
+/*
|
|
+ * Landlock sandbox - partial read-only filesystem
|
|
+ *
|
|
+ * Copyright © 2017 Mickaël Salaün <mic@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.
|
|
+ */
|
|
+
|
|
+#include "bpf_load.h"
|
|
+#include "libbpf.h"
|
|
+
|
|
+#define _GNU_SOURCE
|
|
+#include <errno.h>
|
|
+#include <fcntl.h> /* open() */
|
|
+#include <linux/bpf.h>
|
|
+#include <linux/filter.h>
|
|
+#include <linux/prctl.h>
|
|
+#include <linux/seccomp.h>
|
|
+#include <stddef.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/prctl.h>
|
|
+#include <sys/syscall.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+#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]))
|
|
+#define MAX_ERRNO 4095
|
|
+
|
|
+
|
|
+struct landlock_rule {
|
|
+ enum landlock_subtype_event event;
|
|
+ struct bpf_insn *bpf;
|
|
+ size_t size;
|
|
+};
|
|
+
|
|
+static int apply_sandbox(int prog_fd)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ /* set up the test sandbox */
|
|
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
|
+ perror("prctl(no_new_priv)");
|
|
+ return 1;
|
|
+ }
|
|
+ if (seccomp(SECCOMP_APPEND_LANDLOCK_RULE, 0, &prog_fd)) {
|
|
+ perror("seccomp(set_hook)");
|
|
+ ret = 1;
|
|
+ }
|
|
+ close(prog_fd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int main(int argc, char * const argv[], char * const *envp)
|
|
+{
|
|
+ char filename[256];
|
|
+ char *cmd_path;
|
|
+ char * const *cmd_argv;
|
|
+
|
|
+ if (argc < 2) {
|
|
+ fprintf(stderr, "usage: %s <cmd> [args]...\n\n", argv[0]);
|
|
+ fprintf(stderr, "Launch a command in a read-only environment "
|
|
+ "(except for character devices).\n");
|
|
+ fprintf(stderr, "Display debug with: "
|
|
+ "cat /sys/kernel/debug/tracing/trace_pipe &\n");
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
|
|
+ if (load_bpf_file(filename)) {
|
|
+ printf("%s", bpf_log_buf);
|
|
+ return 1;
|
|
+ }
|
|
+ if (!prog_fd[0]) {
|
|
+ if (errno) {
|
|
+ printf("load_bpf_file: %s\n", strerror(errno));
|
|
+ } else {
|
|
+ printf("load_bpf_file: Error\n");
|
|
+ }
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (apply_sandbox(prog_fd[0]))
|
|
+ return 1;
|
|
+ cmd_path = argv[1];
|
|
+ cmd_argv = argv + 1;
|
|
+ fprintf(stderr, "Launching a new sandboxed process.\n");
|
|
+ execve(cmd_path, cmd_argv, envp);
|
|
+ perror("execve");
|
|
+ return 1;
|
|
+}
|
|
--
|
|
2.11.0
|
|
|