[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20191104172146.30797-5-mic@digikod.net>
Date: Mon, 4 Nov 2019 18:21:43 +0100
From: Mickaël Salaün <mic@...ikod.net>
To: linux-kernel@...r.kernel.org
Cc: Mickaël Salaün <mic@...ikod.net>,
Alexei Starovoitov <ast@...nel.org>,
Andy Lutomirski <luto@...capital.net>,
Casey Schaufler <casey@...aufler-ca.com>,
Daniel Borkmann <daniel@...earbox.net>,
David Drysdale <drysdale@...gle.com>,
Florent Revest <revest@...omium.org>,
James Morris <jmorris@...ei.org>, Jann Horn <jann@...jh.net>,
John Johansen <john.johansen@...onical.com>,
Jonathan Corbet <corbet@....net>,
Kees Cook <keescook@...omium.org>,
KP Singh <kpsingh@...omium.org>,
Michael Kerrisk <mtk.manpages@...il.com>,
Mickaël Salaün <mickael.salaun@....gouv.fr>,
Paul Moore <paul@...l-moore.com>,
Sargun Dhillon <sargun@...gun.me>,
"Serge E . Hallyn" <serge@...lyn.com>,
Shuah Khan <shuah@...nel.org>,
Stephen Smalley <sds@...ho.nsa.gov>, Tejun Heo <tj@...nel.org>,
Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>,
Tycho Andersen <tycho@...ho.ws>,
Will Drewry <wad@...omium.org>, bpf@...r.kernel.org,
kernel-hardening@...ts.openwall.com, linux-api@...r.kernel.org,
linux-security-module@...r.kernel.org, netdev@...r.kernel.org
Subject: [PATCH bpf-next v13 4/7] landlock: Add ptrace LSM hooks
Add a first Landlock hook that can be used to enforce a security policy
or to audit some process activities. For a sandboxing use-case, it is
needed to inform the kernel if a task can legitimately debug another.
ptrace(2) can also be used by an attacker to impersonate another task
and remain undetected while performing malicious activities.
Using ptrace(2) and related features on a target process can lead to a
privilege escalation. A sandboxed task must then be able to tell the
kernel if another task is more privileged, via ptrace_may_access().
Signed-off-by: Mickaël Salaün <mic@...ikod.net>
Cc: Alexei Starovoitov <ast@...nel.org>
Cc: Andy Lutomirski <luto@...capital.net>
Cc: Daniel Borkmann <daniel@...earbox.net>
Cc: James Morris <jmorris@...ei.org>
Cc: Kees Cook <keescook@...omium.org>
Cc: Serge E. Hallyn <serge@...lyn.com>
Cc: Will Drewry <wad@...omium.org>
---
Changes since v12:
* ensure preemption is disabled before running BPF programs, cf. commit
568f196756ad ("bpf: check that BPF programs run with preemption
disabled")
Changes since v10:
* revamp and replace the static policy with a Landlock hook which may be
used by the corresponding BPF_LANDLOCK_PTRACE program (attach) type
and a dedicated process_cmp_landlock_ptrace() BPF helper
* check prog return value against LANDLOCK_RET_DENY (ret is a bitmask)
Changes since v6:
* factor out ptrace check
* constify pointers
* cleanup headers
* use the new security_add_hooks()
---
security/landlock/Makefile | 4 +-
security/landlock/bpf_run.c | 65 ++++++++++++++++++
security/landlock/bpf_run.h | 25 +++++++
security/landlock/hooks_ptrace.c | 114 +++++++++++++++++++++++++++++++
security/landlock/hooks_ptrace.h | 19 ++++++
security/landlock/init.c | 2 +
6 files changed, 227 insertions(+), 2 deletions(-)
create mode 100644 security/landlock/bpf_run.c
create mode 100644 security/landlock/bpf_run.h
create mode 100644 security/landlock/hooks_ptrace.c
create mode 100644 security/landlock/hooks_ptrace.h
diff --git a/security/landlock/Makefile b/security/landlock/Makefile
index 0b291f2c027c..93e4c2f31c8a 100644
--- a/security/landlock/Makefile
+++ b/security/landlock/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
landlock-y := init.o \
- bpf_verify.o bpf_ptrace.o \
+ bpf_verify.o bpf_run.o bpf_ptrace.o \
domain_manage.o domain_syscall.o \
- hooks_cred.o
+ hooks_cred.o hooks_ptrace.o
diff --git a/security/landlock/bpf_run.c b/security/landlock/bpf_run.c
new file mode 100644
index 000000000000..454cd4b6e99b
--- /dev/null
+++ b/security/landlock/bpf_run.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Landlock LSM - eBPF program evaluation
+ *
+ * Copyright © 2016-2019 Mickaël Salaün <mic@...ikod.net>
+ * Copyright © 2018-2019 ANSSI
+ */
+
+#include <asm/current.h>
+#include <linux/bpf.h>
+#include <linux/errno.h>
+#include <linux/filter.h>
+#include <linux/preempt.h>
+#include <linux/rculist.h>
+#include <uapi/linux/landlock.h>
+
+#include "bpf_run.h"
+#include "common.h"
+#include "hooks_ptrace.h"
+
+static const void *get_prog_ctx(struct landlock_hook_ctx *hook_ctx)
+{
+ switch (hook_ctx->type) {
+ case LANDLOCK_HOOK_PTRACE:
+ return landlock_get_ctx_ptrace(hook_ctx->ctx_ptrace);
+ }
+ WARN_ON(1);
+ return NULL;
+}
+
+/**
+ * landlock_access_denied - run Landlock programs tied to a hook
+ *
+ * @domain: Landlock domain pointer
+ * @hook_ctx: non-NULL valid eBPF context pointer
+ *
+ * Return true if at least one program return deny, false otherwise.
+ */
+bool landlock_access_denied(struct landlock_domain *domain,
+ struct landlock_hook_ctx *hook_ctx)
+{
+ struct landlock_prog_list *prog_list;
+ const size_t hook = get_hook_index(hook_ctx->type);
+
+ if (!domain)
+ return false;
+
+ for (prog_list = domain->programs[hook]; prog_list;
+ prog_list = prog_list->prev) {
+ u32 ret;
+ const void *prog_ctx;
+
+ prog_ctx = get_prog_ctx(hook_ctx);
+ if (!prog_ctx || WARN_ON(IS_ERR(prog_ctx)))
+ return true;
+ preempt_disable();
+ rcu_read_lock();
+ ret = BPF_PROG_RUN(prog_list->prog, prog_ctx);
+ rcu_read_unlock();
+ preempt_enable();
+ if (ret & LANDLOCK_RET_DENY)
+ return true;
+ }
+ return false;
+}
diff --git a/security/landlock/bpf_run.h b/security/landlock/bpf_run.h
new file mode 100644
index 000000000000..3461cbb8ec12
--- /dev/null
+++ b/security/landlock/bpf_run.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Landlock LSM - eBPF program evaluation headers
+ *
+ * Copyright © 2016-2019 Mickaël Salaün <mic@...ikod.net>
+ * Copyright © 2018-2019 ANSSI
+ */
+
+#ifndef _SECURITY_LANDLOCK_BPF_RUN_H
+#define _SECURITY_LANDLOCK_BPF_RUN_H
+
+#include "common.h"
+#include "hooks_ptrace.h"
+
+struct landlock_hook_ctx {
+ enum landlock_hook_type type;
+ union {
+ struct landlock_hook_ctx_ptrace *ctx_ptrace;
+ };
+};
+
+bool landlock_access_denied(struct landlock_domain *domain,
+ struct landlock_hook_ctx *hook_ctx);
+
+#endif /* _SECURITY_LANDLOCK_BPF_RUN_H */
diff --git a/security/landlock/hooks_ptrace.c b/security/landlock/hooks_ptrace.c
new file mode 100644
index 000000000000..8e518a472d04
--- /dev/null
+++ b/security/landlock/hooks_ptrace.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Landlock LSM - ptrace hooks
+ *
+ * Copyright © 2017-2019 Mickaël Salaün <mic@...ikod.net>
+ * Copyright © 2019 ANSSI
+ */
+
+#include <asm/current.h>
+#include <linux/cred.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/lsm_hooks.h>
+#include <linux/sched.h>
+#include <uapi/linux/landlock.h>
+
+#include "bpf_run.h"
+#include "common.h"
+#include "hooks_ptrace.h"
+
+struct landlock_hook_ctx_ptrace {
+ struct landlock_context_ptrace prog_ctx;
+};
+
+const struct landlock_context_ptrace *landlock_get_ctx_ptrace(
+ const struct landlock_hook_ctx_ptrace *hook_ctx)
+{
+ if (WARN_ON(!hook_ctx))
+ return NULL;
+
+ return &hook_ctx->prog_ctx;
+}
+
+static int check_ptrace(struct landlock_domain *domain,
+ struct task_struct *tracer, struct task_struct *tracee)
+{
+ struct landlock_hook_ctx_ptrace ctx_ptrace = {
+ .prog_ctx = {
+ .tracer = (uintptr_t)tracer,
+ .tracee = (uintptr_t)tracee,
+ },
+ };
+ struct landlock_hook_ctx hook_ctx = {
+ .type = LANDLOCK_HOOK_PTRACE,
+ .ctx_ptrace = &ctx_ptrace,
+ };
+
+ return landlock_access_denied(domain, &hook_ctx) ? -EPERM : 0;
+}
+
+/**
+ * hook_ptrace_access_check - determine whether the current process may access
+ * another
+ *
+ * @child: the process to be accessed
+ * @mode: the mode of attachment
+ *
+ * If the current task (i.e. tracer) has one or multiple BPF_LANDLOCK_PTRACE
+ * programs, then run them with the `struct landlock_context_ptrace` context.
+ * If one of these programs return LANDLOCK_RET_DENY, then deny access with
+ * -EPERM, else allow it by returning 0.
+ */
+static int hook_ptrace_access_check(struct task_struct *child,
+ unsigned int mode)
+{
+ struct landlock_domain *dom_current;
+ const size_t hook = get_hook_index(LANDLOCK_HOOK_PTRACE);
+
+ dom_current = landlock_cred(current_cred())->domain;
+ if (!(dom_current && dom_current->programs[hook]))
+ return 0;
+ return check_ptrace(dom_current, current, child);
+}
+
+/**
+ * hook_ptrace_traceme - determine whether another process may trace the
+ * current one
+ *
+ * @parent: the task proposed to be the tracer
+ *
+ * If the parent task (i.e. tracer) has one or multiple BPF_LANDLOCK_PTRACE
+ * programs, then run them with the `struct landlock_context_ptrace` context.
+ * If one of these programs return LANDLOCK_RET_DENY, then deny access with
+ * -EPERM, else allow it by returning 0.
+ */
+static int hook_ptrace_traceme(struct task_struct *parent)
+{
+ struct landlock_domain *dom_parent;
+ const size_t hook = get_hook_index(LANDLOCK_HOOK_PTRACE);
+ int ret;
+
+ rcu_read_lock();
+ dom_parent = landlock_cred(__task_cred(parent))->domain;
+ if (!(dom_parent && dom_parent->programs[hook])) {
+ ret = 0;
+ goto put_rcu;
+ }
+ ret = check_ptrace(dom_parent, parent, current);
+
+put_rcu:
+ rcu_read_unlock();
+ return ret;
+}
+
+static struct security_hook_list landlock_hooks[] = {
+ LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check),
+ LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme),
+};
+
+__init void landlock_add_hooks_ptrace(void)
+{
+ security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
+ LANDLOCK_NAME);
+}
diff --git a/security/landlock/hooks_ptrace.h b/security/landlock/hooks_ptrace.h
new file mode 100644
index 000000000000..53fe651bdb3e
--- /dev/null
+++ b/security/landlock/hooks_ptrace.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Landlock LSM - ptrace hooks headers
+ *
+ * Copyright © 2017-2019 Mickaël Salaün <mic@...ikod.net>
+ * Copyright © 2019 ANSSI
+ */
+
+#ifndef _SECURITY_LANDLOCK_HOOKS_PTRACE_H
+#define _SECURITY_LANDLOCK_HOOKS_PTRACE_H
+
+struct landlock_hook_ctx_ptrace;
+
+const struct landlock_context_ptrace *landlock_get_ctx_ptrace(
+ const struct landlock_hook_ctx_ptrace *hook_ctx);
+
+__init void landlock_add_hooks_ptrace(void);
+
+#endif /* _SECURITY_LANDLOCK_HOOKS_PTRACE_H */
diff --git a/security/landlock/init.c b/security/landlock/init.c
index 8836ec4defd3..541aad17418e 100644
--- a/security/landlock/init.c
+++ b/security/landlock/init.c
@@ -10,11 +10,13 @@
#include "common.h"
#include "hooks_cred.h"
+#include "hooks_ptrace.h"
static int __init landlock_init(void)
{
pr_info(LANDLOCK_NAME ": Registering hooks\n");
landlock_add_hooks_cred();
+ landlock_add_hooks_ptrace();
return 0;
}
--
2.23.0
Powered by blists - more mailing lists