2019-12-20 15:44:27

by KP Singh

[permalink] [raw]
Subject: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

From: KP Singh <[email protected]>

This patch series is a continuation of the KRSI RFC
(https://lore.kernel.org/bpf/[email protected]/)

# Motivation

Google does rich analysis of runtime security data collected from
internal Linux deployments (corporate devices and servers) to detect and
thwart threats in real-time. Currently, this is done in custom kernel
modules but we would like to replace this with something that's upstream
and useful to others.

The current kernel infrastructure for providing telemetry (Audit, Perf
etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
information provided by audit requires kernel changes to audit, its
policy language and user-space components. Furthermore, building a MAC
policy based on the newly added telemetry data requires changes to
various LSMs and their respective policy languages.

This patchset proposes a new stackable and privileged LSM which allows
the LSM hooks to be implemented using eBPF. This facilitates a unified
and dynamic (not requiring re-compilation of the kernel) audit and MAC
policy.

# Why an LSM?

Linux Security Modules target security behaviours rather than the
kernel's API. For example, it's easy to miss out a newly added system
call for executing processes (eg. execve, execveat etc.) but the LSM
framework ensures that all process executions trigger the relevant hooks
irrespective of how the process was executed.

Allowing users to implement LSM hooks at runtime also benefits the LSM
eco-system by enabling a quick feedback loop from the security community
about the kind of behaviours that the LSM Framework should be targeting.

# How does it work?

The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
hook. All LSM hooks are exposed as files in securityfs. Attachment
requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
modifying MAC policies.

The eBPF programs are passed the same arguments as the LSM hooks and
executed in the body of the hook. If any of the eBPF programs returns an
error (like ENOPERM), the behaviour represented by the hook is denied.

Audit logs can be written using a format chosen by the eBPF program to
the perf events buffer and can be further processed in user-space.

# Limitations of RFC v1

In the previous design
(https://lore.kernel.org/bpf/[email protected]/),
the BPF programs received a context which could be queried to retrieve
specific pieces of information using specific helpers.

For example, a program that attaches to the file_mprotect LSM hook and
queries the VMA region could have had the following context:

// Special context for the hook.
struct bpf_mprotect_ctx {
struct vm_area_struct *vma;
};

and accessed the fields using a hypothetical helper
"bpf_mprotect_vma_get_start:

SEC("lsm/file_mprotect")
int mprotect_audit(bpf_mprotect_ctx *ctx)
{
unsigned long vm_start = bpf_mprotect_vma_get_start(ctx);
return 0;
}

or directly read them from the context by updating the verifier to allow
accessing the fields:

int mprotect_audit(bpf_mprotect_ctx *ctx)
{
unsigned long vm_start = ctx->vma->vm_start;
return 0;
}

As we prototyped policies based on this design, we realized that this
approach is not general enough. Adding helpers or verifier code for all
usages would imply a high maintenance cost while severely restricting
the instrumentation capabilities which is the key value add of our
eBPF-based LSM.

Feedback from the BPF maintainers at Linux Plumbers also pushed us
towards the following, more general, approach.

# BTF Based Design

The current design uses BTF
(https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html,
https://lwn.net/Articles/803258/) which allows verifiable read-only
structure accesses by field names rather than fixed offsets. This allows
accessing the hook parameters using a dynamically created context which
provides a certain degree of ABI stability:

/* Clang builtin to handle field accesses. */
#define _(P) (__builtin_preserve_access_index(P))

// Only declare the structure and fields intended to be used
// in the program
struct vm_area_struct {
unsigned long vm_start;
};

// Declare the eBPF program mprotect_audit which attaches to
// to the file_mprotect LSM hook and accepts three arguments.
BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
struct vm_area_struct *, vma,
unsigned long, reqprot, unsigned long, prot
{
unsigned long vm_start = _(vma->vm_start);
return 0;
}

By relocating field offsets, BTF makes a large portion of kernel data
structures readily accessible across kernel versions without requiring a
large corpus of BPF helper functions and requiring recompilation with
every kernel version. The limitations of BTF compatibility are described
in BPF Co-Re (http://vger.kernel.org/bpfconf2019_talks/bpf-core.pdf,
i.e. field renames, #defines and changes to the signature of LSM hooks).

This design imposes that the MAC policy (eBPF programs) be updated when
the inspected kernel structures change outside of BTF compatibility
guarantees. In practice, this is only required when a structure field
used by a current policy is removed (or renamed) or when the used LSM
hooks change. We expect the maintenance cost of these changes to be
acceptable as compared to the previous design
(https://lore.kernel.org/bpf/[email protected]/).

# Distinction from Landlock

We believe there exist two distinct use-cases with distinct set of users:

* Unprivileged processes voluntarily relinquishing privileges with the
primary users being software developers.

* Flexible privileged (CAP_MAC_ADMIN, CAP_SYS_ADMIN) MAC and Audit with
the primary users being system policy admins.

These use-cases imply different APIs and trade-offs:

* The unprivileged use case requires defining more stable and custom APIs
(through opaque contexts and precise helpers).

* Privileged Audit and MAC requires deeper introspection of the kernel
data structures to maximise the flexibility that can be achieved without
kernel modification.

Landlock has demonstrated filesystem sandboxes and now Ptrace access
control in its patches which are excellent use cases for an unprivileged
process voluntarily relinquishing privileges.

However, Landlock has expanded its original goal, "towards unprivileged
sandboxing", to being a "low-level framework to build
access-control/audit systems" (https://landlock.io). We feel that the
design and implementation are still driven by the constraints and
trade-offs of the former use-case, and do not provide a satisfactory
solution to the latter.

We also believe that our approach, direct access to common kernel data
structures as with BTF, is inappropriate for unprivileged processes and
probably not a good option for Landlock.

In conclusion, we feel that the design for a privileged LSM and
unprivileged LSM are mutually exclusive and that one cannot be built
"on-top-of" the other. Doing so would limit the capabilities of what can
be done for an LSM that provides flexible audit and MAC capabilities or
provide in-appropriate access to kernel internals to an unprivileged
process.

Furthermore, the Landlock design supports its historical use-case only
when unprivileged eBPF is allowed. This is something that warrants
discussion before an unprivileged LSM that uses eBPF is upstreamed.

# Why not tracepoints or kprobes?

In order to do MAC with tracepoints or kprobes, we would need to
override the return value of the security hook. This is not possible
with tracepoints or call-site kprobes.

Attaching to the return boundary (kretprobe) implies that BPF programs
would always get called after all the other LSM hooks are called and
clobber the pre-existing LSM semantics.

Enforcing MAC policy with an actual LSM helps leverage the verified
semantics of the framework.

# Usage Examples

A simple example and some documentation is included in the patchset.

In order to better illustrate the capabilities of the framework some
more advanced prototype code has also been published separately:

* Logging execution events (including environment variables and arguments):
https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
* Detecting deletion of running executables:
https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
* Detection of writes to /proc/<pid>/mem:
https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c

We have updated Google's internal telemetry infrastructure and have
started deploying this LSM on our Linux Workstations. This gives us more
confidence in the real-world applications of such a system.

KP Singh (13):
bpf: Refactor BPF_EVENT context macros to its own header.
bpf: lsm: Add a skeleton and config options
bpf: lsm: Introduce types for eBPF based LSM
bpf: lsm: Allow btf_id based attachment for LSM hooks
tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
bpf: lsm: Init Hooks and create files in securityfs
bpf: lsm: Implement attach, detach and execution.
bpf: lsm: Show attached program names in hook read handler.
bpf: lsm: Add a helper function bpf_lsm_event_output
bpf: lsm: Handle attachment of the same program
tools/libbpf: Add bpf_program__attach_lsm
bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
bpf: lsm: Add Documentation

Documentation/security/bpf.rst | 164 +++
Documentation/security/index.rst | 1 +
MAINTAINERS | 11 +
include/linux/bpf_event.h | 78 ++
include/linux/bpf_lsm.h | 25 +
include/linux/bpf_types.h | 4 +
include/trace/bpf_probe.h | 30 +-
include/uapi/linux/bpf.h | 12 +-
kernel/bpf/syscall.c | 10 +
kernel/bpf/verifier.c | 84 +-
kernel/trace/bpf_trace.c | 24 +-
security/Kconfig | 11 +-
security/Makefile | 2 +
security/bpf/Kconfig | 25 +
security/bpf/Makefile | 7 +
security/bpf/include/bpf_lsm.h | 63 +
security/bpf/include/fs.h | 23 +
security/bpf/include/hooks.h | 1015 +++++++++++++++++
security/bpf/lsm.c | 160 +++
security/bpf/lsm_fs.c | 176 +++
security/bpf/ops.c | 224 ++++
tools/include/uapi/linux/bpf.h | 12 +-
tools/lib/bpf/bpf.c | 2 +-
tools/lib/bpf/bpf.h | 6 +
tools/lib/bpf/libbpf.c | 163 ++-
tools/lib/bpf/libbpf.h | 4 +
tools/lib/bpf/libbpf.map | 7 +
tools/lib/bpf/libbpf_probes.c | 1 +
.../bpf/prog_tests/lsm_mprotect_audit.c | 129 +++
.../selftests/bpf/progs/lsm_mprotect_audit.c | 58 +
30 files changed, 2451 insertions(+), 80 deletions(-)
create mode 100644 Documentation/security/bpf.rst
create mode 100644 include/linux/bpf_event.h
create mode 100644 include/linux/bpf_lsm.h
create mode 100644 security/bpf/Kconfig
create mode 100644 security/bpf/Makefile
create mode 100644 security/bpf/include/bpf_lsm.h
create mode 100644 security/bpf/include/fs.h
create mode 100644 security/bpf/include/hooks.h
create mode 100644 security/bpf/lsm.c
create mode 100644 security/bpf/lsm_fs.c
create mode 100644 security/bpf/ops.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
create mode 100644 tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c

--
2.20.1


2019-12-20 15:45:00

by KP Singh

[permalink] [raw]
Subject: [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM

From: KP Singh <[email protected]>

Update the libbpf library with functionality to load and
attach a program type BPF_PROG_TYPE_LSM, currently with
only one expected attach type BPF_LSM_MAC.

Signed-off-by: KP Singh <[email protected]>
---
tools/lib/bpf/bpf.c | 2 +-
tools/lib/bpf/bpf.h | 6 +++++
tools/lib/bpf/libbpf.c | 44 +++++++++++++++++++++--------------
tools/lib/bpf/libbpf.h | 2 ++
tools/lib/bpf/libbpf.map | 6 +++++
tools/lib/bpf/libbpf_probes.c | 1 +
6 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 98596e15390f..9c6fb083f7de 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -228,7 +228,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
memset(&attr, 0, sizeof(attr));
attr.prog_type = load_attr->prog_type;
attr.expected_attach_type = load_attr->expected_attach_type;
- if (attr.prog_type == BPF_PROG_TYPE_TRACING) {
+ if (needs_btf_attach(attr.prog_type)) {
attr.attach_btf_id = load_attr->attach_btf_id;
attr.attach_prog_fd = load_attr->attach_prog_fd;
} else {
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 3c791fa8e68e..df2a00ff349f 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -177,6 +177,12 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
__u64 *probe_offset, __u64 *probe_addr);

+static inline bool needs_btf_attach(enum bpf_prog_type prog_type)
+{
+ return (prog_type == BPF_PROG_TYPE_TRACING ||
+ prog_type == BPF_PROG_TYPE_LSM);
+}
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b20f82e58989..b0b27d8e5a37 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3738,7 +3738,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
load_attr.insns = insns;
load_attr.insns_cnt = insns_cnt;
load_attr.license = license;
- if (prog->type == BPF_PROG_TYPE_TRACING) {
+ if (needs_btf_attach(prog->type)) {
load_attr.attach_prog_fd = prog->attach_prog_fd;
load_attr.attach_btf_id = prog->attach_btf_id;
} else {
@@ -3983,7 +3983,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,

bpf_program__set_type(prog, prog_type);
bpf_program__set_expected_attach_type(prog, attach_type);
- if (prog_type == BPF_PROG_TYPE_TRACING) {
+ if (needs_btf_attach(prog_type)) {
err = libbpf_find_attach_btf_id(prog->section_name,
attach_type,
attach_prog_fd);
@@ -4933,6 +4933,7 @@ bool bpf_program__is_##NAME(const struct bpf_program *prog) \
} \

BPF_PROG_TYPE_FNS(socket_filter, BPF_PROG_TYPE_SOCKET_FILTER);
+BPF_PROG_TYPE_FNS(lsm, BPF_PROG_TYPE_LSM);
BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);
BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);
BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);
@@ -5009,6 +5010,8 @@ static const struct {
BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
+ BPF_PROG_BTF("lsm/", BPF_PROG_TYPE_LSM,
+ BPF_LSM_MAC),
BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB,
BPF_CGROUP_INET_INGRESS),
BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB,
@@ -5119,32 +5122,39 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
return -ESRCH;
}

-#define BTF_PREFIX "btf_trace_"
+static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name,
+ const char *prefix)
+{
+
+ size_t prefix_len = strlen(prefix);
+ char btf_type_name[128];
+
+ strcpy(btf_type_name, prefix);
+ strncat(btf_type_name, name, sizeof(btf_type_name) - (prefix_len + 1));
+ return btf__find_by_name_kind(btf, btf_type_name, BTF_KIND_TYPEDEF);
+}
+
+#define BTF_TRACE_PREFIX "btf_trace_"
+#define BTF_LSM_PREFIX "lsm_btf_"
+
int libbpf_find_vmlinux_btf_id(const char *name,
enum bpf_attach_type attach_type)
{
struct btf *btf = bpf_core_find_kernel_btf();
- char raw_tp_btf[128] = BTF_PREFIX;
- char *dst = raw_tp_btf + sizeof(BTF_PREFIX) - 1;
- const char *btf_name;
int err = -EINVAL;
- __u32 kind;

if (IS_ERR(btf)) {
pr_warn("vmlinux BTF is not found\n");
return -EINVAL;
}

- if (attach_type == BPF_TRACE_RAW_TP) {
- /* prepend "btf_trace_" prefix per kernel convention */
- strncat(dst, name, sizeof(raw_tp_btf) - sizeof(BTF_PREFIX));
- btf_name = raw_tp_btf;
- kind = BTF_KIND_TYPEDEF;
- } else {
- btf_name = name;
- kind = BTF_KIND_FUNC;
- }
- err = btf__find_by_name_kind(btf, btf_name, kind);
+ if (attach_type == BPF_TRACE_RAW_TP)
+ err = __btf__typdef_with_prefix(btf, name, BTF_TRACE_PREFIX);
+ else if (attach_type == BPF_LSM_MAC)
+ err = __btf__typdef_with_prefix(btf, name, BTF_LSM_PREFIX);
+ else
+ err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
+
btf__free(btf);
return err;
}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 0dbf4bfba0c4..9cd69d602c82 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -332,6 +332,7 @@ LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog);
LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog);
LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog);
LIBBPF_API int bpf_program__set_tracing(struct bpf_program *prog);
+LIBBPF_API int bpf_program__set_lsm(struct bpf_program *prog);

LIBBPF_API enum bpf_prog_type bpf_program__get_type(struct bpf_program *prog);
LIBBPF_API void bpf_program__set_type(struct bpf_program *prog,
@@ -352,6 +353,7 @@ LIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);
LIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);
LIBBPF_API bool bpf_program__is_perf_event(const struct bpf_program *prog);
LIBBPF_API bool bpf_program__is_tracing(const struct bpf_program *prog);
+LIBBPF_API bool bpf_program__is_lsm(const struct bpf_program *prog);

/*
* No need for __attribute__((packed)), all members of 'bpf_map_def'
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 8ddc2c40e482..3d396149755d 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -208,3 +208,9 @@ LIBBPF_0.0.6 {
btf__find_by_name_kind;
libbpf_find_vmlinux_btf_id;
} LIBBPF_0.0.5;
+
+LIBBPF_0.0.7 {
+ global:
+ bpf_program__is_lsm;
+ bpf_program__set_lsm;
+} LIBBPF_0.0.6;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index a9eb8b322671..203b4ecf7a0b 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -103,6 +103,7 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
case BPF_PROG_TYPE_CGROUP_SYSCTL:
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
case BPF_PROG_TYPE_TRACING:
+ case BPF_PROG_TYPE_LSM:
default:
break;
}
--
2.20.1

2019-12-20 15:45:06

by KP Singh

[permalink] [raw]
Subject: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

From: KP Singh <[email protected]>

The LSM creates files in securityfs for each hook registered with the
LSM.

/sys/kernel/security/bpf/<h_name>

The list of LSM hooks are maintained in an internal header "hooks.h"
Eventually, this list should either be defined collectively in
include/linux/lsm_hooks.h or auto-generated from it.

* Creation of a file for the hook in the securityfs.
* Allocation of a bpf_lsm_hook data structure which stores
a pointer to the dentry of the newly created file in securityfs.
* Creation of a typedef for the hook so that BTF information
can be generated for the LSM hooks to:

- Make them "Compile Once, Run Everywhere".
- Pass the right arguments when the attached programs are run.
- Verify the accesses made by the program by using the BTF
information.

Signed-off-by: KP Singh <[email protected]>
---
include/linux/bpf_lsm.h | 12 +
security/bpf/Makefile | 4 +-
security/bpf/include/bpf_lsm.h | 63 ++
security/bpf/include/fs.h | 23 +
security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
security/bpf/lsm.c | 138 ++++-
security/bpf/lsm_fs.c | 82 +++
7 files changed, 1333 insertions(+), 4 deletions(-)
create mode 100644 include/linux/bpf_lsm.h
create mode 100644 security/bpf/include/bpf_lsm.h
create mode 100644 security/bpf/include/fs.h
create mode 100644 security/bpf/include/hooks.h
create mode 100644 security/bpf/lsm_fs.c

diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
new file mode 100644
index 000000000000..76f81e642dc2
--- /dev/null
+++ b/include/linux/bpf_lsm.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_BPF_LSM_H
+#define _LINUX_BPF_LSM_H
+
+#include <linux/bpf.h>
+
+#ifdef CONFIG_SECURITY_BPF
+extern int bpf_lsm_fs_initialized;
+#endif /* CONFIG_SECURITY_BPF */
+
+#endif /* _LINUX_BPF_LSM_H */
diff --git a/security/bpf/Makefile b/security/bpf/Makefile
index c78a8a056e7e..8bb5bfc936ee 100644
--- a/security/bpf/Makefile
+++ b/security/bpf/Makefile
@@ -2,4 +2,6 @@
#
# Copyright 2019 Google LLC.

-obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o
+obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o lsm_fs.o
+
+ccflags-y := -I$(srctree)/security/bpf -I$(srctree)/security/bpf/include
diff --git a/security/bpf/include/bpf_lsm.h b/security/bpf/include/bpf_lsm.h
new file mode 100644
index 000000000000..f2409d75d932
--- /dev/null
+++ b/security/bpf/include/bpf_lsm.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _BPF_LSM_H
+#define _BPF_LSM_H
+
+#include <linux/bpf_event.h>
+#include <linux/filter.h>
+#include <linux/bpf.h>
+#include "fs.h"
+
+/*
+ * This enum indexes one of the LSM hooks defined in hooks.h.
+ * Each value of the enum is defined as <hook>_type.
+ */
+enum lsm_hook_type {
+ #define BPF_LSM_HOOK(hook, ...) hook##_type,
+ #include "hooks.h"
+ #undef BPF_LSM_HOOK
+ __MAX_LSM_HOOK_TYPE,
+};
+
+/*
+ * This data structure contains all the information required by the LSM for a
+ * a hook.
+ */
+struct bpf_lsm_hook {
+ /*
+ * The name of the security hook, a file with this name will be created
+ * in the securityfs.
+ */
+ const char *name;
+ /*
+ * The type of the LSM hook, the LSM uses this to index the list of the
+ * hooks to run the eBPF programs that may have been attached.
+ */
+ enum lsm_hook_type h_type;
+ /*
+ * The dentry of the file created in securityfs.
+ */
+ struct dentry *h_dentry;
+ /*
+ * The mutex must be held when updating the progs attached to the hook.
+ */
+ struct mutex mutex;
+ /*
+ * The eBPF programs that are attached to this hook.
+ */
+ struct bpf_prog_array __rcu *progs;
+ /*
+ * The actual implementation of the hook. This also ensures that
+ * BTF information is generated for the hook.
+ */
+ void *btf_hook_func;
+};
+
+extern struct bpf_lsm_hook bpf_lsm_hooks_list[];
+
+#define lsm_for_each_hook(hook) \
+ for ((hook) = &bpf_lsm_hooks_list[0]; \
+ (hook) < &bpf_lsm_hooks_list[__MAX_LSM_HOOK_TYPE]; \
+ (hook)++)
+
+#endif /* _BPF_LSM_H */
diff --git a/security/bpf/include/fs.h b/security/bpf/include/fs.h
new file mode 100644
index 000000000000..9d87a0b2bf41
--- /dev/null
+++ b/security/bpf/include/fs.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#ifndef _BPF_LSM_FS_H
+#define _BPF_LSM_FS_H
+
+#include <linux/bpf.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+
+bool is_bpf_lsm_hook_file(struct file *f);
+
+/*
+ * The name of the directory created in securityfs
+ *
+ * /sys/kernel/security/<dir_name>
+ */
+#define BPF_LSM_SFS_NAME "bpf"
+
+#endif /* _BPF_LSM_FS_H */
diff --git a/security/bpf/include/hooks.h b/security/bpf/include/hooks.h
new file mode 100644
index 000000000000..c91c6fae8058
--- /dev/null
+++ b/security/bpf/include/hooks.h
@@ -0,0 +1,1015 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * The hooks for the KRSI LSM are declared in this file.
+ *
+ * This header MUST NOT be included directly and is included inline
+ * for generating various data structurs for the hooks using the
+ * following pattern:
+ *
+ * #define BPF_LSM_HOOK RET NAME(PROTO);
+ * #include "hooks.h"
+ * #undef BPF_LSM_HOOK
+ *
+ * Format:
+ *
+ * BPF_LSM_HOOK(NAME, RET, PROTO, ARGS)
+ *
+ */
+#define BPF_LSM_ARGS(args...) args
+
+BPF_LSM_HOOK(binder_set_context_mgr,
+ int,
+ BPF_LSM_ARGS(struct task_struct *mgr),
+ BPF_LSM_ARGS(mgr))
+BPF_LSM_HOOK(binder_transaction,
+ int,
+ BPF_LSM_ARGS(struct task_struct *from, struct task_struct *to),
+ BPF_LSM_ARGS(from, to))
+BPF_LSM_HOOK(binder_transfer_binder,
+ int,
+ BPF_LSM_ARGS(struct task_struct *from, struct task_struct *to),
+ BPF_LSM_ARGS(from, to))
+BPF_LSM_HOOK(binder_transfer_file,
+ int,
+ BPF_LSM_ARGS(struct task_struct *from, struct task_struct *to,
+ struct file *file),
+ BPF_LSM_ARGS(from, to, file))
+BPF_LSM_HOOK(ptrace_access_check,
+ int,
+ BPF_LSM_ARGS(struct task_struct *child, unsigned int mode),
+ BPF_LSM_ARGS(child, mode))
+BPF_LSM_HOOK(ptrace_traceme,
+ int,
+ BPF_LSM_ARGS(struct task_struct *parent),
+ BPF_LSM_ARGS(parent))
+BPF_LSM_HOOK(capget,
+ int,
+ BPF_LSM_ARGS(struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted),
+ BPF_LSM_ARGS(target, effective, inheritable, permitted))
+BPF_LSM_HOOK(capset,
+ int,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted),
+ BPF_LSM_ARGS(new, old, effective, inheritable, permitted))
+BPF_LSM_HOOK(capable,
+ int,
+ BPF_LSM_ARGS(const struct cred *cred, struct user_namespace *ns,
+ int cap, unsigned int opts),
+ BPF_LSM_ARGS(cred, ns, cap, opts))
+BPF_LSM_HOOK(quotactl,
+ int,
+ BPF_LSM_ARGS(int cmds, int type, int id, struct super_block *sb),
+ BPF_LSM_ARGS(cmds, type, id, sb))
+BPF_LSM_HOOK(quota_on,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(syslog,
+ int,
+ BPF_LSM_ARGS(int type),
+ BPF_LSM_ARGS(type))
+BPF_LSM_HOOK(settime,
+ int,
+ BPF_LSM_ARGS(const struct timespec64 *ts,
+ const struct timezone *tz),
+ BPF_LSM_ARGS(ts, tz))
+BPF_LSM_HOOK(vm_enough_memory,
+ int,
+ BPF_LSM_ARGS(struct mm_struct *mm, long pages),
+ BPF_LSM_ARGS(mm, pages))
+BPF_LSM_HOOK(bprm_set_creds,
+ int,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(bprm_check_security,
+ int,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(bprm_committing_creds,
+ void,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(bprm_committed_creds,
+ void,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(fs_context_dup,
+ int,
+ BPF_LSM_ARGS(struct fs_context *fc, struct fs_context *src_sc),
+ BPF_LSM_ARGS(fc, src_sc))
+BPF_LSM_HOOK(fs_context_parse_param,
+ int,
+ BPF_LSM_ARGS(struct fs_context *fc, struct fs_parameter *param),
+ BPF_LSM_ARGS(fc, param))
+BPF_LSM_HOOK(sb_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb),
+ BPF_LSM_ARGS(sb))
+BPF_LSM_HOOK(sb_free_security,
+ void,
+ BPF_LSM_ARGS(struct super_block *sb),
+ BPF_LSM_ARGS(sb))
+BPF_LSM_HOOK(sb_free_mnt_opts,
+ void,
+ BPF_LSM_ARGS(void *mnt_opts),
+ BPF_LSM_ARGS(mnt_opts))
+BPF_LSM_HOOK(sb_eat_lsm_opts,
+ int,
+ BPF_LSM_ARGS(char *orig, void **mnt_opts),
+ BPF_LSM_ARGS(orig, mnt_opts))
+BPF_LSM_HOOK(sb_remount,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb, void *mnt_opts),
+ BPF_LSM_ARGS(sb, mnt_opts))
+BPF_LSM_HOOK(sb_kern_mount,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb),
+ BPF_LSM_ARGS(sb))
+BPF_LSM_HOOK(sb_show_options,
+ int,
+ BPF_LSM_ARGS(struct seq_file *m, struct super_block *sb),
+ BPF_LSM_ARGS(m, sb))
+BPF_LSM_HOOK(sb_statfs,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(sb_mount,
+ int,
+ BPF_LSM_ARGS(const char *dev_name, const struct path *path,
+ const char *type, unsigned long flags, void *data),
+ BPF_LSM_ARGS(dev_name, path, type, flags, data))
+BPF_LSM_HOOK(sb_umount,
+ int,
+ BPF_LSM_ARGS(struct vfsmount *mnt, int flags),
+ BPF_LSM_ARGS(mnt, flags))
+BPF_LSM_HOOK(sb_pivotroot,
+ int,
+ BPF_LSM_ARGS(const struct path *old_path,
+ const struct path *new_path),
+ BPF_LSM_ARGS(old_path, new_path))
+BPF_LSM_HOOK(sb_set_mnt_opts,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb, void *mnt_opts,
+ unsigned long kern_flags, unsigned long *set_kern_flags),
+ BPF_LSM_ARGS(sb, mnt_opts, kern_flags, set_kern_flags))
+BPF_LSM_HOOK(sb_clone_mnt_opts,
+ int,
+ BPF_LSM_ARGS(const struct super_block *oldsb,
+ struct super_block *newsb, unsigned long kern_flags,
+ unsigned long *set_kern_flags),
+ BPF_LSM_ARGS(oldsb, newsb, kern_flags, set_kern_flags))
+BPF_LSM_HOOK(sb_add_mnt_opt,
+ int,
+ BPF_LSM_ARGS(const char *option, const char *val, int len,
+ void **mnt_opts),
+ BPF_LSM_ARGS(option, val, len, mnt_opts))
+BPF_LSM_HOOK(move_mount,
+ int,
+ BPF_LSM_ARGS(const struct path *from_path,
+ const struct path *to_path),
+ BPF_LSM_ARGS(from_path, to_path))
+BPF_LSM_HOOK(dentry_init_security,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, int mode,
+ const struct qstr *name,
+ void **ctx, u32 *ctxlen),
+ BPF_LSM_ARGS(dentry, mode, name, ctx, ctxlen))
+BPF_LSM_HOOK(dentry_create_files_as,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, int mode, struct qstr *name,
+ const struct cred *old, struct cred *new),
+ BPF_LSM_ARGS(dentry, mode, name, old, new))
+
+#ifdef CONFIG_SECURITY_PATH
+BPF_LSM_HOOK(path_unlink,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(path_mkdir,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry,
+ umode_t mode),
+ BPF_LSM_ARGS(dir, dentry, mode))
+BPF_LSM_HOOK(path_rmdir,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(path_mknod,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry,
+ umode_t mode,
+ unsigned int dev),
+ BPF_LSM_ARGS(dir, dentry, mode, dev))
+BPF_LSM_HOOK(path_truncate,
+ int,
+ BPF_LSM_ARGS(const struct path *path),
+ BPF_LSM_ARGS(path))
+BPF_LSM_HOOK(path_symlink,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry,
+ const char *old_name),
+ BPF_LSM_ARGS(dir, dentry, old_name))
+BPF_LSM_HOOK(path_link,
+ int,
+ BPF_LSM_ARGS(struct dentry *old_dentry, const struct path *new_dir,
+ struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dentry, new_dir, new_dentry))
+BPF_LSM_HOOK(path_rename,
+ int,
+ BPF_LSM_ARGS(const struct path *old_dir, struct dentry *old_dentry,
+ const struct path *new_dir, struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dir, old_dentry, new_dir, new_dentry))
+BPF_LSM_HOOK(path_chmod,
+ int,
+ BPF_LSM_ARGS(const struct path *path, umode_t mode),
+ BPF_LSM_ARGS(path, mode))
+BPF_LSM_HOOK(path_chown,
+ int,
+ BPF_LSM_ARGS(const struct path *path, kuid_t uid, kgid_t gid),
+ BPF_LSM_ARGS(path, uid, gid))
+BPF_LSM_HOOK(path_chroot,
+ int,
+ BPF_LSM_ARGS(const struct path *path),
+ BPF_LSM_ARGS(path))
+#endif /* CONFIG_SECURITY_PATH */
+
+BPF_LSM_HOOK(path_notify,
+ int,
+ BPF_LSM_ARGS(const struct path *path, u64 mask,
+ unsigned int obj_type),
+ BPF_LSM_ARGS(path, mask, obj_type))
+BPF_LSM_HOOK(inode_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct inode *inode),
+ BPF_LSM_ARGS(inode))
+BPF_LSM_HOOK(inode_free_security,
+ void,
+ BPF_LSM_ARGS(struct inode *inode),
+ BPF_LSM_ARGS(inode))
+BPF_LSM_HOOK(inode_init_security,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, struct inode *dir,
+ const struct qstr *qstr, const char **name, void **value,
+ size_t *len),
+ BPF_LSM_ARGS(inode, dir, qstr, name, value, len))
+BPF_LSM_HOOK(inode_create,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ umode_t mode),
+ BPF_LSM_ARGS(dir, dentry, mode))
+BPF_LSM_HOOK(inode_link,
+ int,
+ BPF_LSM_ARGS(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dentry, dir, new_dentry))
+BPF_LSM_HOOK(inode_unlink,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(inode_symlink,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ const char *old_name),
+ BPF_LSM_ARGS(dir, dentry, old_name))
+BPF_LSM_HOOK(inode_mkdir,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ umode_t mode),
+ BPF_LSM_ARGS(dir, dentry, mode))
+BPF_LSM_HOOK(inode_rmdir,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(inode_mknod,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ umode_t mode,
+ dev_t dev),
+ BPF_LSM_ARGS(dir, dentry, mode, dev))
+BPF_LSM_HOOK(inode_rename,
+ int,
+ BPF_LSM_ARGS(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dir, old_dentry, new_dir, new_dentry))
+BPF_LSM_HOOK(inode_readlink,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_follow_link,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, struct inode *inode, bool rcu),
+ BPF_LSM_ARGS(dentry, inode, rcu))
+BPF_LSM_HOOK(inode_permission,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, int mask),
+ BPF_LSM_ARGS(inode, mask))
+BPF_LSM_HOOK(inode_setattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, struct iattr *attr),
+ BPF_LSM_ARGS(dentry, attr))
+BPF_LSM_HOOK(inode_getattr,
+ int,
+ BPF_LSM_ARGS(const struct path *path),
+ BPF_LSM_ARGS(path))
+BPF_LSM_HOOK(inode_setxattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name,
+ const void *value,
+ size_t size, int flags),
+ BPF_LSM_ARGS(dentry, name, value, size, flags))
+BPF_LSM_HOOK(inode_post_setxattr,
+ void,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name,
+ const void *value,
+ size_t size, int flags),
+ BPF_LSM_ARGS(dentry, name, value, size, flags))
+BPF_LSM_HOOK(inode_getxattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name),
+ BPF_LSM_ARGS(dentry, name))
+BPF_LSM_HOOK(inode_listxattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_removexattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name),
+ BPF_LSM_ARGS(dentry, name))
+BPF_LSM_HOOK(inode_need_killpriv,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_killpriv,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_getsecurity,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, const char *name, void **buffer,
+ bool alloc),
+ BPF_LSM_ARGS(inode, name, buffer, alloc))
+BPF_LSM_HOOK(inode_setsecurity,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, const char *name,
+ const void *value,
+ size_t size, int flags),
+ BPF_LSM_ARGS(inode, name, value, size, flags))
+BPF_LSM_HOOK(inode_listsecurity,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, char *buffer,
+ size_t buffer_size),
+ BPF_LSM_ARGS(inode, buffer, buffer_size))
+BPF_LSM_HOOK(inode_getsecid,
+ void,
+ BPF_LSM_ARGS(struct inode *inode, u32 *secid),
+ BPF_LSM_ARGS(inode, secid))
+BPF_LSM_HOOK(inode_copy_up,
+ int,
+ BPF_LSM_ARGS(struct dentry *src, struct cred **new),
+ BPF_LSM_ARGS(src, new))
+BPF_LSM_HOOK(inode_copy_up_xattr,
+ int,
+ BPF_LSM_ARGS(const char *name),
+ BPF_LSM_ARGS(name))
+BPF_LSM_HOOK(kernfs_init_security,
+ int,
+ BPF_LSM_ARGS(struct kernfs_node *kn_dir, struct kernfs_node *kn),
+ BPF_LSM_ARGS(kn_dir, kn))
+BPF_LSM_HOOK(file_permission,
+ int,
+ BPF_LSM_ARGS(struct file *file, int mask),
+ BPF_LSM_ARGS(file, mask))
+BPF_LSM_HOOK(file_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_free_security,
+ void,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_ioctl,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned int cmd,
+ unsigned long arg),
+ BPF_LSM_ARGS(file, cmd, arg))
+BPF_LSM_HOOK(mmap_addr,
+ int,
+ BPF_LSM_ARGS(unsigned long addr),
+ BPF_LSM_ARGS(addr))
+BPF_LSM_HOOK(mmap_file,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags),
+ BPF_LSM_ARGS(file, reqprot, prot, flags))
+BPF_LSM_HOOK(file_mprotect,
+ int,
+ BPF_LSM_ARGS(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot),
+ BPF_LSM_ARGS(vma, reqprot, prot))
+BPF_LSM_HOOK(file_lock,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned int cmd),
+ BPF_LSM_ARGS(file, cmd))
+BPF_LSM_HOOK(file_fcntl,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned int cmd,
+ unsigned long arg),
+ BPF_LSM_ARGS(file, cmd, arg))
+BPF_LSM_HOOK(file_set_fowner,
+ void,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_send_sigiotask,
+ int,
+ BPF_LSM_ARGS(struct task_struct *tsk, struct fown_struct *fown,
+ int sig),
+ BPF_LSM_ARGS(tsk, fown, sig))
+BPF_LSM_HOOK(file_receive,
+ int,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_open,
+ int,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(task_alloc,
+ int,
+ BPF_LSM_ARGS(struct task_struct *task, unsigned long clone_flags),
+ BPF_LSM_ARGS(task, clone_flags))
+BPF_LSM_HOOK(task_free,
+ void,
+ BPF_LSM_ARGS(struct task_struct *task),
+ BPF_LSM_ARGS(task))
+BPF_LSM_HOOK(cred_alloc_blank,
+ int,
+ BPF_LSM_ARGS(struct cred *cred, gfp_t gfp),
+ BPF_LSM_ARGS(cred, gfp))
+BPF_LSM_HOOK(cred_free,
+ void,
+ BPF_LSM_ARGS(struct cred *cred),
+ BPF_LSM_ARGS(cred))
+BPF_LSM_HOOK(cred_prepare,
+ int,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old, gfp_t gfp),
+ BPF_LSM_ARGS(new, old, gfp))
+BPF_LSM_HOOK(cred_transfer,
+ void,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old),
+ BPF_LSM_ARGS(new, old))
+BPF_LSM_HOOK(cred_getsecid,
+ void,
+ BPF_LSM_ARGS(const struct cred *c, u32 *secid),
+ BPF_LSM_ARGS(c, secid))
+BPF_LSM_HOOK(kernel_act_as,
+ int,
+ BPF_LSM_ARGS(struct cred *new, u32 secid),
+ BPF_LSM_ARGS(new, secid))
+BPF_LSM_HOOK(kernel_create_files_as,
+ int,
+ BPF_LSM_ARGS(struct cred *new, struct inode *inode),
+ BPF_LSM_ARGS(new, inode))
+BPF_LSM_HOOK(kernel_module_request,
+ int,
+ BPF_LSM_ARGS(char *kmod_name),
+ BPF_LSM_ARGS(kmod_name))
+BPF_LSM_HOOK(kernel_load_data,
+ int,
+ BPF_LSM_ARGS(enum kernel_load_data_id id),
+ BPF_LSM_ARGS(id))
+BPF_LSM_HOOK(kernel_read_file,
+ int,
+ BPF_LSM_ARGS(struct file *file, enum kernel_read_file_id id),
+ BPF_LSM_ARGS(file, id))
+BPF_LSM_HOOK(kernel_post_read_file,
+ int,
+ BPF_LSM_ARGS(struct file *file, char *buf, loff_t size,
+ enum kernel_read_file_id id),
+ BPF_LSM_ARGS(file, buf, size, id))
+BPF_LSM_HOOK(task_fix_setuid,
+ int,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old, int flags),
+ BPF_LSM_ARGS(new, old, flags))
+BPF_LSM_HOOK(task_setpgid,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, pid_t pgid),
+ BPF_LSM_ARGS(p, pgid))
+BPF_LSM_HOOK(task_getpgid,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_getsid,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_getsecid,
+ void,
+ BPF_LSM_ARGS(struct task_struct *p, u32 *secid),
+ BPF_LSM_ARGS(p, secid))
+BPF_LSM_HOOK(task_setnice,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, int nice),
+ BPF_LSM_ARGS(p, nice))
+BPF_LSM_HOOK(task_setioprio,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, int ioprio),
+ BPF_LSM_ARGS(p, ioprio))
+BPF_LSM_HOOK(task_getioprio,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_prlimit,
+ int,
+ BPF_LSM_ARGS(const struct cred *cred, const struct cred *tcred,
+ unsigned int flags),
+ BPF_LSM_ARGS(cred, tcred, flags))
+BPF_LSM_HOOK(task_setrlimit,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim),
+ BPF_LSM_ARGS(p, resource, new_rlim))
+BPF_LSM_HOOK(task_setscheduler,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_getscheduler,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_movememory,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_kill,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, struct kernel_siginfo *info,
+ int sig,
+ const struct cred *cred),
+ BPF_LSM_ARGS(p, info, sig, cred))
+BPF_LSM_HOOK(task_prctl,
+ int,
+ BPF_LSM_ARGS(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5),
+ BPF_LSM_ARGS(option, arg2, arg3, arg4, arg5))
+BPF_LSM_HOOK(task_to_inode,
+ void,
+ BPF_LSM_ARGS(struct task_struct *p, struct inode *inode),
+ BPF_LSM_ARGS(p, inode))
+BPF_LSM_HOOK(ipc_permission,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *ipcp, short flag),
+ BPF_LSM_ARGS(ipcp, flag))
+BPF_LSM_HOOK(ipc_getsecid,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *ipcp, u32 *secid),
+ BPF_LSM_ARGS(ipcp, secid))
+BPF_LSM_HOOK(msg_msg_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct msg_msg *msg),
+ BPF_LSM_ARGS(msg))
+BPF_LSM_HOOK(msg_msg_free_security,
+ void,
+ BPF_LSM_ARGS(struct msg_msg *msg),
+ BPF_LSM_ARGS(msg))
+BPF_LSM_HOOK(msg_queue_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(msg_queue_free_security,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(msg_queue_associate,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int msqflg),
+ BPF_LSM_ARGS(perm, msqflg))
+BPF_LSM_HOOK(msg_queue_msgctl,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int cmd),
+ BPF_LSM_ARGS(perm, cmd))
+BPF_LSM_HOOK(msg_queue_msgsnd,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, struct msg_msg *msg,
+ int msqflg),
+ BPF_LSM_ARGS(perm, msg, msqflg))
+BPF_LSM_HOOK(msg_queue_msgrcv,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, struct msg_msg *msg,
+ struct task_struct *target, long type, int mode),
+ BPF_LSM_ARGS(perm, msg, target, type, mode))
+BPF_LSM_HOOK(shm_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(shm_free_security,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(shm_associate,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int shmflg),
+ BPF_LSM_ARGS(perm, shmflg))
+BPF_LSM_HOOK(shm_shmctl,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int cmd),
+ BPF_LSM_ARGS(perm, cmd))
+BPF_LSM_HOOK(shm_shmat,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, char __user *shmaddr,
+ int shmflg),
+ BPF_LSM_ARGS(perm, shmaddr, shmflg))
+BPF_LSM_HOOK(sem_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(sem_free_security,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(sem_associate,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int semflg),
+ BPF_LSM_ARGS(perm, semflg))
+BPF_LSM_HOOK(sem_semctl,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int cmd),
+ BPF_LSM_ARGS(perm, cmd))
+BPF_LSM_HOOK(sem_semop,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, struct sembuf *sops,
+ unsigned nsops, int alter),
+ BPF_LSM_ARGS(perm, sops, nsops, alter))
+BPF_LSM_HOOK(netlink_send,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb),
+ BPF_LSM_ARGS(sk, skb))
+BPF_LSM_HOOK(d_instantiate,
+ void,
+ BPF_LSM_ARGS(struct dentry *dentry, struct inode *inode),
+ BPF_LSM_ARGS(dentry, inode))
+BPF_LSM_HOOK(getprocattr,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, char *name, char **value),
+ BPF_LSM_ARGS(p, name, value))
+BPF_LSM_HOOK(setprocattr,
+ int,
+ BPF_LSM_ARGS(const char *name, void *value, size_t size),
+ BPF_LSM_ARGS(name, value, size))
+BPF_LSM_HOOK(ismaclabel,
+ int,
+ BPF_LSM_ARGS(const char *name),
+ BPF_LSM_ARGS(name))
+BPF_LSM_HOOK(secid_to_secctx,
+ int,
+ BPF_LSM_ARGS(u32 secid, char **secdata, u32 *seclen),
+ BPF_LSM_ARGS(secid, secdata, seclen))
+BPF_LSM_HOOK(secctx_to_secid,
+ int,
+ BPF_LSM_ARGS(const char *secdata, u32 seclen, u32 *secid),
+ BPF_LSM_ARGS(secdata, seclen, secid))
+BPF_LSM_HOOK(release_secctx,
+ void,
+ BPF_LSM_ARGS(char *secdata, u32 seclen),
+ BPF_LSM_ARGS(secdata, seclen))
+BPF_LSM_HOOK(inode_invalidate_secctx,
+ void,
+ BPF_LSM_ARGS(struct inode *inode),
+ BPF_LSM_ARGS(inode))
+BPF_LSM_HOOK(inode_notifysecctx,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, void *ctx, u32 ctxlen),
+ BPF_LSM_ARGS(inode, ctx, ctxlen))
+BPF_LSM_HOOK(inode_setsecctx,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, void *ctx, u32 ctxlen),
+ BPF_LSM_ARGS(dentry, ctx, ctxlen))
+BPF_LSM_HOOK(inode_getsecctx,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, void **ctx, u32 *ctxlen),
+ BPF_LSM_ARGS(inode, ctx, ctxlen))
+
+#ifdef CONFIG_SECURITY_NETWORK
+BPF_LSM_HOOK(unix_stream_connect,
+ int,
+ BPF_LSM_ARGS(struct sock *sock, struct sock *other,
+ struct sock *newsk),
+ BPF_LSM_ARGS(sock, other, newsk))
+BPF_LSM_HOOK(unix_may_send,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct socket *other),
+ BPF_LSM_ARGS(sock, other))
+BPF_LSM_HOOK(socket_create,
+ int,
+ BPF_LSM_ARGS(int family, int type, int protocol, int kern),
+ BPF_LSM_ARGS(family, type, protocol, kern))
+BPF_LSM_HOOK(socket_post_create,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int family, int type,
+ int protocol,
+ int kern),
+ BPF_LSM_ARGS(sock, family, type, protocol, kern))
+BPF_LSM_HOOK(socket_socketpair,
+ int,
+ BPF_LSM_ARGS(struct socket *socka, struct socket *sockb),
+ BPF_LSM_ARGS(socka, sockb))
+BPF_LSM_HOOK(socket_bind,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct sockaddr *address,
+ int addrlen),
+ BPF_LSM_ARGS(sock, address, addrlen))
+BPF_LSM_HOOK(socket_connect,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct sockaddr *address,
+ int addrlen),
+ BPF_LSM_ARGS(sock, address, addrlen))
+BPF_LSM_HOOK(socket_listen,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int backlog),
+ BPF_LSM_ARGS(sock, backlog))
+BPF_LSM_HOOK(socket_accept,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct socket *newsock),
+ BPF_LSM_ARGS(sock, newsock))
+BPF_LSM_HOOK(socket_sendmsg,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct msghdr *msg, int size),
+ BPF_LSM_ARGS(sock, msg, size))
+BPF_LSM_HOOK(socket_recvmsg,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct msghdr *msg, int size,
+ int flags),
+ BPF_LSM_ARGS(sock, msg, size, flags))
+BPF_LSM_HOOK(socket_getsockname,
+ int,
+ BPF_LSM_ARGS(struct socket *sock),
+ BPF_LSM_ARGS(sock))
+BPF_LSM_HOOK(socket_getpeername,
+ int,
+ BPF_LSM_ARGS(struct socket *sock),
+ BPF_LSM_ARGS(sock))
+BPF_LSM_HOOK(socket_getsockopt,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int level, int optname),
+ BPF_LSM_ARGS(sock, level, optname))
+BPF_LSM_HOOK(socket_setsockopt,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int level, int optname),
+ BPF_LSM_ARGS(sock, level, optname))
+BPF_LSM_HOOK(socket_shutdown,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int how),
+ BPF_LSM_ARGS(sock, how))
+BPF_LSM_HOOK(socket_sock_rcv_skb,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb),
+ BPF_LSM_ARGS(sk, skb))
+BPF_LSM_HOOK(socket_getpeersec_stream,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, char __user *optval,
+ int __user *optlen, unsigned len),
+ BPF_LSM_ARGS(sock, optval, optlen, len))
+BPF_LSM_HOOK(socket_getpeersec_dgram,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct sk_buff *skb, u32 *secid),
+ BPF_LSM_ARGS(sock, skb, secid))
+BPF_LSM_HOOK(sk_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, int family, gfp_t priority),
+ BPF_LSM_ARGS(sk, family, priority))
+BPF_LSM_HOOK(sk_free_security,
+ void,
+ BPF_LSM_ARGS(struct sock *sk),
+ BPF_LSM_ARGS(sk))
+BPF_LSM_HOOK(sk_clone_security,
+ void,
+ BPF_LSM_ARGS(const struct sock *sk, struct sock *newsk),
+ BPF_LSM_ARGS(sk, newsk))
+BPF_LSM_HOOK(sk_getsecid,
+ void,
+ BPF_LSM_ARGS(struct sock *sk, u32 *secid),
+ BPF_LSM_ARGS(sk, secid))
+BPF_LSM_HOOK(sock_graft,
+ void,
+ BPF_LSM_ARGS(struct sock *sk, struct socket *parent),
+ BPF_LSM_ARGS(sk, parent))
+BPF_LSM_HOOK(inet_conn_request,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req),
+ BPF_LSM_ARGS(sk, skb, req))
+BPF_LSM_HOOK(inet_csk_clone,
+ void,
+ BPF_LSM_ARGS(struct sock *newsk, const struct request_sock *req),
+ BPF_LSM_ARGS(newsk, req))
+BPF_LSM_HOOK(inet_conn_established,
+ void,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb),
+ BPF_LSM_ARGS(sk, skb))
+BPF_LSM_HOOK(secmark_relabel_packet,
+ int,
+ BPF_LSM_ARGS(u32 secid),
+ BPF_LSM_ARGS(secid))
+BPF_LSM_HOOK(secmark_refcount_inc,
+ void,
+ BPF_LSM_ARGS(void),
+ BPF_LSM_ARGS())
+BPF_LSM_HOOK(secmark_refcount_dec,
+ void,
+ BPF_LSM_ARGS(void),
+ BPF_LSM_ARGS())
+BPF_LSM_HOOK(req_classify_flow,
+ void,
+ BPF_LSM_ARGS(const struct request_sock *req, struct flowi *fl),
+ BPF_LSM_ARGS(req, fl))
+BPF_LSM_HOOK(tun_dev_alloc_security,
+ int,
+ BPF_LSM_ARGS(void **security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(tun_dev_free_security,
+ void,
+ BPF_LSM_ARGS(void *security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(tun_dev_create,
+ int,
+ BPF_LSM_ARGS(void),
+ BPF_LSM_ARGS())
+BPF_LSM_HOOK(tun_dev_attach_queue,
+ int,
+ BPF_LSM_ARGS(void *security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(tun_dev_attach,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, void *security),
+ BPF_LSM_ARGS(sk, security))
+BPF_LSM_HOOK(tun_dev_open,
+ int,
+ BPF_LSM_ARGS(void *security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(sctp_assoc_request,
+ int,
+ BPF_LSM_ARGS(struct sctp_endpoint *ep, struct sk_buff *skb),
+ BPF_LSM_ARGS(ep, skb))
+BPF_LSM_HOOK(sctp_bind_connect,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, int optname,
+ struct sockaddr *address,
+ int addrlen),
+ BPF_LSM_ARGS(sk, optname, address, addrlen))
+BPF_LSM_HOOK(sctp_sk_clone,
+ void,
+ BPF_LSM_ARGS(struct sctp_endpoint *ep, struct sock *sk,
+ struct sock *newsk),
+ BPF_LSM_ARGS(ep, sk, newsk))
+#endif /* CONFIG_SECURITY_NETWORK */
+
+#ifdef CONFIG_SECURITY_INFINIBAND
+BPF_LSM_HOOK(ib_pkey_access,
+ int,
+ BPF_LSM_ARGS(void *sec, u64 subnet_prefix, u16 pkey),
+ BPF_LSM_ARGS(sec, subnet_prefix, pkey))
+BPF_LSM_HOOK(ib_endport_manage_subnet,
+ int,
+ BPF_LSM_ARGS(void *sec, const char *dev_name, u8 port_num),
+ BPF_LSM_ARGS(sec, dev_name, port_num))
+BPF_LSM_HOOK(ib_alloc_security,
+ int,
+ BPF_LSM_ARGS(void **sec),
+ BPF_LSM_ARGS(sec))
+BPF_LSM_HOOK(ib_free_security,
+ void,
+ BPF_LSM_ARGS(void *sec),
+ BPF_LSM_ARGS(sec))
+#endif /* CONFIG_SECURITY_INFINIBAND */
+
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+BPF_LSM_HOOK(xfrm_policy_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx **ctxp,
+ struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp),
+ BPF_LSM_ARGS(ctxp, sec_ctx, gfp))
+BPF_LSM_HOOK(xfrm_policy_clone_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *old_ctx,
+ struct xfrm_sec_ctx **new_ctx),
+ BPF_LSM_ARGS(old_ctx, new_ctx))
+BPF_LSM_HOOK(xfrm_policy_free_security,
+ void,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *ctx),
+ BPF_LSM_ARGS(ctx))
+BPF_LSM_HOOK(xfrm_policy_delete_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *ctx),
+ BPF_LSM_ARGS(ctx))
+BPF_LSM_HOOK(xfrm_state_alloc,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x,
+ struct xfrm_user_sec_ctx *sec_ctx),
+ BPF_LSM_ARGS(x, sec_ctx))
+BPF_LSM_HOOK(xfrm_state_alloc_acquire,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x, struct xfrm_sec_ctx *polsec,
+ u32 secid),
+ BPF_LSM_ARGS(x, polsec, secid))
+BPF_LSM_HOOK(xfrm_state_free_security,
+ void,
+ BPF_LSM_ARGS(struct xfrm_state *x),
+ BPF_LSM_ARGS(x))
+BPF_LSM_HOOK(xfrm_state_delete_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x),
+ BPF_LSM_ARGS(x))
+BPF_LSM_HOOK(xfrm_policy_lookup,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir),
+ BPF_LSM_ARGS(ctx, fl_secid, dir))
+BPF_LSM_HOOK(xfrm_state_pol_flow_match,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x, struct xfrm_policy *xp,
+ const struct flowi *fl),
+ BPF_LSM_ARGS(x, xp, fl))
+BPF_LSM_HOOK(xfrm_decode_session,
+ int,
+ BPF_LSM_ARGS(struct sk_buff *skb, u32 *secid, int ckall),
+ BPF_LSM_ARGS(skb, secid, ckall))
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+
+#ifdef CONFIG_KEYS
+BPF_LSM_HOOK(key_alloc,
+ int,
+ BPF_LSM_ARGS(struct key *key, const struct cred *cred,
+ unsigned long flags),
+ BPF_LSM_ARGS(key, cred, flags))
+BPF_LSM_HOOK(key_free,
+ void,
+ BPF_LSM_ARGS(struct key *key),
+ BPF_LSM_ARGS(key))
+BPF_LSM_HOOK(key_permission,
+ int,
+ BPF_LSM_ARGS(key_ref_t key_ref, const struct cred *cred,
+ unsigned perm),
+ BPF_LSM_ARGS(key_ref, cred, perm))
+BPF_LSM_HOOK(key_getsecurity,
+ int,
+ BPF_LSM_ARGS(struct key *key, char **_buffer),
+ BPF_LSM_ARGS(key, _buffer))
+#endif /* CONFIG_KEYS */
+
+#ifdef CONFIG_AUDIT
+BPF_LSM_HOOK(audit_rule_init,
+ int,
+ BPF_LSM_ARGS(u32 field, u32 op, char *rulestr, void **lsmrule),
+ BPF_LSM_ARGS(field, op, rulestr, lsmrule))
+BPF_LSM_HOOK(audit_rule_known,
+ int,
+ BPF_LSM_ARGS(struct audit_krule *krule),
+ BPF_LSM_ARGS(krule))
+BPF_LSM_HOOK(audit_rule_match,
+ int,
+ BPF_LSM_ARGS(u32 secid, u32 field, u32 op, void *lsmrule),
+ BPF_LSM_ARGS(secid, field, op, lsmrule))
+BPF_LSM_HOOK(audit_rule_free,
+ void,
+ BPF_LSM_ARGS(void *lsmrule),
+ BPF_LSM_ARGS(lsmrule))
+#endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+BPF_LSM_HOOK(bpf,
+ int,
+ BPF_LSM_ARGS(int cmd, union bpf_attr *attr, unsigned int size),
+ BPF_LSM_ARGS(cmd, attr, size))
+BPF_LSM_HOOK(bpf_map,
+ int,
+ BPF_LSM_ARGS(struct bpf_map *map, fmode_t fmode),
+ BPF_LSM_ARGS(map, fmode))
+BPF_LSM_HOOK(bpf_prog,
+ int,
+ BPF_LSM_ARGS(struct bpf_prog *prog),
+ BPF_LSM_ARGS(prog))
+BPF_LSM_HOOK(bpf_map_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct bpf_map *map),
+ BPF_LSM_ARGS(map))
+BPF_LSM_HOOK(bpf_map_free_security,
+ void,
+ BPF_LSM_ARGS(struct bpf_map *map),
+ BPF_LSM_ARGS(map))
+BPF_LSM_HOOK(bpf_prog_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct bpf_prog_aux *aux),
+ BPF_LSM_ARGS(aux))
+BPF_LSM_HOOK(bpf_prog_free_security,
+ void,
+ BPF_LSM_ARGS(struct bpf_prog_aux *aux),
+ BPF_LSM_ARGS(aux))
+#endif /* CONFIG_BPF_SYSCALL */
+
+BPF_LSM_HOOK(locked_down,
+ int,
+ BPF_LSM_ARGS(enum lockdown_reason what),
+ BPF_LSM_ARGS(what))
diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c
index fe5c65bbdd45..8586ddfe8cda 100644
--- a/security/bpf/lsm.c
+++ b/security/bpf/lsm.c
@@ -5,14 +5,146 @@
*/

#include <linux/lsm_hooks.h>
+#include <linux/bpf_lsm.h>

-static int process_execution(struct linux_binprm *bprm)
+#include "bpf_lsm.h"
+
+/*
+ * Run the eBPF programs of the hook indexed by the type t with the arguments
+ * packed into an array of u64 integers as the context.
+ */
+static inline int __run_progs(enum lsm_hook_type t, u64 *args)
{
- return 0;
+ struct bpf_lsm_hook *h = &bpf_lsm_hooks_list[t];
+ struct bpf_prog_array_item *item;
+ struct bpf_prog_array *array;
+ int ret, retval = 0;
+
+ /*
+ * Some hooks might get called before the securityFS is initialized,
+ * this will result in a NULL pointer exception.
+ */
+ if (!bpf_lsm_fs_initialized)
+ return 0;
+
+ preempt_disable();
+ rcu_read_lock();
+
+ array = rcu_dereference(h->progs);
+ if (!array)
+ goto out;
+
+ for (item = array->items; item->prog; item++) {
+ ret = BPF_PROG_RUN(item->prog, args);
+ if (ret < 0) {
+ retval = ret;
+ break;
+ }
+ }
+out:
+ rcu_read_unlock();
+ preempt_enable();
+ return IS_ENABLED(CONFIG_SECURITY_BPF_ENFORCE) ? retval : 0;
+}
+
+/*
+ * This macro creates a bpf_lsm_run_progs_<x> function which accepts a known
+ * number of arguments and packs them into an array of u64 integers. The array
+ * is used as a context to run the BPF programs attached to the hook.
+ */
+#define DEFINE_LSM_RUN_PROGS_x(x) \
+ static int bpf_lsm_run_progs##x(enum lsm_hook_type t, \
+ REPEAT(x, SARG, __DL_COM, __SEQ_0_11)) \
+ { \
+ u64 args[x]; \
+ REPEAT(x, COPY, __DL_SEM, __SEQ_0_11); \
+ return __run_progs(t, args); \
+ }
+
+/*
+ * There are some hooks that have no arguments, so there's nothing to pack and
+ * the attached BPF programs get a NULL context.
+ */
+int bpf_lsm_run_progs0(enum lsm_hook_type t, u64 args)
+{
+ return __run_progs(t, NULL);
+}
+
+/*
+ * The largest number of args accepted by an LSM hook is currently 6. Define
+ * bpf_lsm_run_progs_1 to bpf_lsm_run_progs_6.
+ */
+DEFINE_LSM_RUN_PROGS_x(1);
+DEFINE_LSM_RUN_PROGS_x(2);
+DEFINE_LSM_RUN_PROGS_x(3);
+DEFINE_LSM_RUN_PROGS_x(4);
+DEFINE_LSM_RUN_PROGS_x(5);
+DEFINE_LSM_RUN_PROGS_x(6);
+
+/*
+ * This macro calls one of the bpf_lsm_args_<x> functions based on the number of
+ * arguments of the variadic macro. Each argument is casted to a u64 bit integer
+ * as expected by BTF.
+ */
+#define LSM_RUN_PROGS(T, args...) \
+ CONCATENATE(bpf_lsm_run_progs, COUNT_ARGS(args))(T, CAST_TO_U64(args))
+
+/*
+ * The hooks can have an int or void return type, these macros allow having a
+ * single implementation of DEFINE_LSM_HOOK irrespective of the return type.
+ */
+#define LSM_HOOK_RET(ret, x) LSM_HOOK_RET_##ret(x)
+#define LSM_HOOK_RET_int(x) x
+#define LSM_HOOK_RET_void(x)
+
+/*
+ * This macro defines the body of a LSM hook which runs the eBPF programs that
+ * are attached to the hook and returns the error code from the eBPF programs if
+ * the return type of the hook is int.
+ */
+#define DEFINE_LSM_HOOK(hook, ret, proto, args) \
+typedef ret (*lsm_btf_##hook)(proto); \
+static ret bpf_lsm_##hook(proto) \
+{ \
+ return LSM_HOOK_RET(ret, LSM_RUN_PROGS(hook##_type, args)); \
}

+/*
+ * Define the body of each of the LSM hooks defined in hooks.h.
+ */
+#define BPF_LSM_HOOK(hook, ret, args, proto) \
+ DEFINE_LSM_HOOK(hook, ret, BPF_LSM_ARGS(args), BPF_LSM_ARGS(proto))
+#include "hooks.h"
+#undef BPF_LSM_HOOK
+#undef DEFINE_LSM_HOOK
+
+/*
+ * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
+ * The list contains information for each of the hook and can be indexed by the
+ * its type to initialize security FS, attach, detach and execute eBPF programs
+ * for the hook.
+ */
+struct bpf_lsm_hook bpf_lsm_hooks_list[] = {
+ #define BPF_LSM_HOOK(h, ...) \
+ [h##_type] = { \
+ .h_type = h##_type, \
+ .mutex = __MUTEX_INITIALIZER( \
+ bpf_lsm_hooks_list[h##_type].mutex), \
+ .name = #h, \
+ .btf_hook_func = \
+ (void *)(lsm_btf_##h)(bpf_lsm_##h), \
+ },
+ #include "hooks.h"
+ #undef BPF_LSM_HOOK
+};
+
+/*
+ * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
+ */
static struct security_hook_list lsm_hooks[] __lsm_ro_after_init = {
- LSM_HOOK_INIT(bprm_check_security, process_execution),
+ #define BPF_LSM_HOOK(h, ...) LSM_HOOK_INIT(h, bpf_lsm_##h),
+ #include "hooks.h"
+ #undef BPF_LSM_HOOK
};

static int __init lsm_init(void)
diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c
new file mode 100644
index 000000000000..49165394ef7d
--- /dev/null
+++ b/security/bpf/lsm_fs.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/security.h>
+#include <linux/bpf_lsm.h>
+
+#include "fs.h"
+#include "bpf_lsm.h"
+
+static struct dentry *bpf_lsm_dir;
+
+static const struct file_operations hook_ops = {};
+
+int bpf_lsm_fs_initialized;
+
+bool is_bpf_lsm_hook_file(struct file *f)
+{
+ return f->f_op == &hook_ops;
+}
+
+static void __init free_hook(struct bpf_lsm_hook *h)
+{
+ securityfs_remove(h->h_dentry);
+ h->h_dentry = NULL;
+}
+
+static int __init init_hook(struct bpf_lsm_hook *h, struct dentry *parent)
+{
+ struct dentry *h_dentry;
+
+ h_dentry = securityfs_create_file(h->name, 0600, parent,
+ NULL, &hook_ops);
+ if (IS_ERR(h_dentry))
+ return PTR_ERR(h_dentry);
+
+ h_dentry->d_fsdata = h;
+ h->h_dentry = h_dentry;
+ return 0;
+}
+
+static int __init bpf_lsm_fs_init(void)
+{
+ struct bpf_lsm_hook *hook;
+ int ret;
+
+ bpf_lsm_dir = securityfs_create_dir(BPF_LSM_SFS_NAME, NULL);
+ if (IS_ERR(bpf_lsm_dir)) {
+ ret = PTR_ERR(bpf_lsm_dir);
+ pr_err("BPF LSM: Unable to create sysfs dir: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * If there is an error in initializing a hook, the initialization
+ * logic makes sure that it has been freed, but this means that
+ * cleanup should be called for all the other hooks. The cleanup
+ * logic handles uninitialized data.
+ */
+ lsm_for_each_hook(hook) {
+ ret = init_hook(hook, bpf_lsm_dir);
+ if (ret < 0)
+ goto error;
+ }
+
+ bpf_lsm_fs_initialized = 1;
+ return 0;
+error:
+ lsm_for_each_hook(hook)
+ free_hook(hook);
+ securityfs_remove(bpf_lsm_dir);
+ return ret;
+}
+
+late_initcall(bpf_lsm_fs_init);
--
2.20.1

2019-12-20 17:18:37

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 12/20/2019 7:41 AM, KP Singh wrote:
> From: KP Singh <[email protected]>
>
> This patch series is a continuation of the KRSI RFC
> (https://lore.kernel.org/bpf/[email protected]/)
>
> # Motivation
>
> Google does rich analysis of runtime security data collected from
> internal Linux deployments (corporate devices and servers) to detect and
> thwart threats in real-time. Currently, this is done in custom kernel
> modules but we would like to replace this with something that's upstream
> and useful to others.
>
> The current kernel infrastructure for providing telemetry (Audit, Perf
> etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
> information provided by audit requires kernel changes to audit, its
> policy language and user-space components. Furthermore, building a MAC
> policy based on the newly added telemetry data requires changes to
> various LSMs and their respective policy languages.
>
> This patchset proposes a new stackable and privileged LSM which allows
> the LSM hooks to be implemented using eBPF. This facilitates a unified
> and dynamic (not requiring re-compilation of the kernel) audit and MAC
> policy.
>
> # Why an LSM?
>
> Linux Security Modules target security behaviours rather than the
> kernel's API. For example, it's easy to miss out a newly added system
> call for executing processes (eg. execve, execveat etc.) but the LSM
> framework ensures that all process executions trigger the relevant hooks
> irrespective of how the process was executed.
>
> Allowing users to implement LSM hooks at runtime also benefits the LSM
> eco-system by enabling a quick feedback loop from the security community
> about the kind of behaviours that the LSM Framework should be targeting.
>
> # How does it work?
>
> The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
> program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
> hook. All LSM hooks are exposed as files in securityfs. Attachment
> requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
> modifying MAC policies.
>
> The eBPF programs are passed the same arguments as the LSM hooks and
> executed in the body of the hook.

This effectively exposes the LSM hooks as external APIs.
It would mean that we can't change or delete them. That
would be bad.


> If any of the eBPF programs returns an
> error (like ENOPERM), the behaviour represented by the hook is denied.
>
> Audit logs can be written using a format chosen by the eBPF program to
> the perf events buffer and can be further processed in user-space.
>
> # Limitations of RFC v1
>
> In the previous design
> (https://lore.kernel.org/bpf/[email protected]/),
> the BPF programs received a context which could be queried to retrieve
> specific pieces of information using specific helpers.
>
> For example, a program that attaches to the file_mprotect LSM hook and
> queries the VMA region could have had the following context:
>
> // Special context for the hook.
> struct bpf_mprotect_ctx {
> struct vm_area_struct *vma;
> };
>
> and accessed the fields using a hypothetical helper
> "bpf_mprotect_vma_get_start:
>
> SEC("lsm/file_mprotect")
> int mprotect_audit(bpf_mprotect_ctx *ctx)
> {
> unsigned long vm_start = bpf_mprotect_vma_get_start(ctx);
> return 0;
> }
>
> or directly read them from the context by updating the verifier to allow
> accessing the fields:
>
> int mprotect_audit(bpf_mprotect_ctx *ctx)
> {
> unsigned long vm_start = ctx->vma->vm_start;
> return 0;
> }
>
> As we prototyped policies based on this design, we realized that this
> approach is not general enough. Adding helpers or verifier code for all
> usages would imply a high maintenance cost while severely restricting
> the instrumentation capabilities which is the key value add of our
> eBPF-based LSM.
>
> Feedback from the BPF maintainers at Linux Plumbers also pushed us
> towards the following, more general, approach.
>
> # BTF Based Design
>
> The current design uses BTF
> (https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html,
> https://lwn.net/Articles/803258/) which allows verifiable read-only
> structure accesses by field names rather than fixed offsets. This allows
> accessing the hook parameters using a dynamically created context which
> provides a certain degree of ABI stability:
>
> /* Clang builtin to handle field accesses. */
> #define _(P) (__builtin_preserve_access_index(P))
>
> // Only declare the structure and fields intended to be used
> // in the program
> struct vm_area_struct {
> unsigned long vm_start;
> };
>
> // Declare the eBPF program mprotect_audit which attaches to
> // to the file_mprotect LSM hook and accepts three arguments.
> BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> struct vm_area_struct *, vma,
> unsigned long, reqprot, unsigned long, prot
> {
> unsigned long vm_start = _(vma->vm_start);
> return 0;
> }
>
> By relocating field offsets, BTF makes a large portion of kernel data
> structures readily accessible across kernel versions without requiring a
> large corpus of BPF helper functions and requiring recompilation with
> every kernel version. The limitations of BTF compatibility are described
> in BPF Co-Re (http://vger.kernel.org/bpfconf2019_talks/bpf-core.pdf,
> i.e. field renames, #defines and changes to the signature of LSM hooks).
>
> This design imposes that the MAC policy (eBPF programs) be updated when
> the inspected kernel structures change outside of BTF compatibility
> guarantees. In practice, this is only required when a structure field
> used by a current policy is removed (or renamed) or when the used LSM
> hooks change. We expect the maintenance cost of these changes to be
> acceptable as compared to the previous design
> (https://lore.kernel.org/bpf/[email protected]/).
>
> # Distinction from Landlock
>
> We believe there exist two distinct use-cases with distinct set of users:
>
> * Unprivileged processes voluntarily relinquishing privileges with the
> primary users being software developers.
>
> * Flexible privileged (CAP_MAC_ADMIN, CAP_SYS_ADMIN) MAC and Audit with
> the primary users being system policy admins.
>
> These use-cases imply different APIs and trade-offs:
>
> * The unprivileged use case requires defining more stable and custom APIs
> (through opaque contexts and precise helpers).
>
> * Privileged Audit and MAC requires deeper introspection of the kernel
> data structures to maximise the flexibility that can be achieved without
> kernel modification.
>
> Landlock has demonstrated filesystem sandboxes and now Ptrace access
> control in its patches which are excellent use cases for an unprivileged
> process voluntarily relinquishing privileges.
>
> However, Landlock has expanded its original goal, "towards unprivileged
> sandboxing", to being a "low-level framework to build
> access-control/audit systems" (https://landlock.io). We feel that the
> design and implementation are still driven by the constraints and
> trade-offs of the former use-case, and do not provide a satisfactory
> solution to the latter.
>
> We also believe that our approach, direct access to common kernel data
> structures as with BTF, is inappropriate for unprivileged processes and
> probably not a good option for Landlock.
>
> In conclusion, we feel that the design for a privileged LSM and
> unprivileged LSM are mutually exclusive and that one cannot be built
> "on-top-of" the other. Doing so would limit the capabilities of what can
> be done for an LSM that provides flexible audit and MAC capabilities or
> provide in-appropriate access to kernel internals to an unprivileged
> process.
>
> Furthermore, the Landlock design supports its historical use-case only
> when unprivileged eBPF is allowed. This is something that warrants
> discussion before an unprivileged LSM that uses eBPF is upstreamed.
>
> # Why not tracepoints or kprobes?
>
> In order to do MAC with tracepoints or kprobes, we would need to
> override the return value of the security hook. This is not possible
> with tracepoints or call-site kprobes.
>
> Attaching to the return boundary (kretprobe) implies that BPF programs
> would always get called after all the other LSM hooks are called and
> clobber the pre-existing LSM semantics.
>
> Enforcing MAC policy with an actual LSM helps leverage the verified
> semantics of the framework.
>
> # Usage Examples
>
> A simple example and some documentation is included in the patchset.
>
> In order to better illustrate the capabilities of the framework some
> more advanced prototype code has also been published separately:
>
> * Logging execution events (including environment variables and arguments):
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> * Detecting deletion of running executables:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> * Detection of writes to /proc/<pid>/mem:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
>
> We have updated Google's internal telemetry infrastructure and have
> started deploying this LSM on our Linux Workstations. This gives us more
> confidence in the real-world applications of such a system.
>
> KP Singh (13):
> bpf: Refactor BPF_EVENT context macros to its own header.
> bpf: lsm: Add a skeleton and config options
> bpf: lsm: Introduce types for eBPF based LSM
> bpf: lsm: Allow btf_id based attachment for LSM hooks
> tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
> bpf: lsm: Init Hooks and create files in securityfs
> bpf: lsm: Implement attach, detach and execution.
> bpf: lsm: Show attached program names in hook read handler.
> bpf: lsm: Add a helper function bpf_lsm_event_output
> bpf: lsm: Handle attachment of the same program
> tools/libbpf: Add bpf_program__attach_lsm
> bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
> bpf: lsm: Add Documentation
>
> Documentation/security/bpf.rst | 164 +++
> Documentation/security/index.rst | 1 +
> MAINTAINERS | 11 +
> include/linux/bpf_event.h | 78 ++
> include/linux/bpf_lsm.h | 25 +
> include/linux/bpf_types.h | 4 +
> include/trace/bpf_probe.h | 30 +-
> include/uapi/linux/bpf.h | 12 +-
> kernel/bpf/syscall.c | 10 +
> kernel/bpf/verifier.c | 84 +-
> kernel/trace/bpf_trace.c | 24 +-
> security/Kconfig | 11 +-
> security/Makefile | 2 +
> security/bpf/Kconfig | 25 +
> security/bpf/Makefile | 7 +
> security/bpf/include/bpf_lsm.h | 63 +
> security/bpf/include/fs.h | 23 +
> security/bpf/include/hooks.h | 1015 +++++++++++++++++
> security/bpf/lsm.c | 160 +++
> security/bpf/lsm_fs.c | 176 +++
> security/bpf/ops.c | 224 ++++
> tools/include/uapi/linux/bpf.h | 12 +-
> tools/lib/bpf/bpf.c | 2 +-
> tools/lib/bpf/bpf.h | 6 +
> tools/lib/bpf/libbpf.c | 163 ++-
> tools/lib/bpf/libbpf.h | 4 +
> tools/lib/bpf/libbpf.map | 7 +
> tools/lib/bpf/libbpf_probes.c | 1 +
> .../bpf/prog_tests/lsm_mprotect_audit.c | 129 +++
> .../selftests/bpf/progs/lsm_mprotect_audit.c | 58 +
> 30 files changed, 2451 insertions(+), 80 deletions(-)
> create mode 100644 Documentation/security/bpf.rst
> create mode 100644 include/linux/bpf_event.h
> create mode 100644 include/linux/bpf_lsm.h
> create mode 100644 security/bpf/Kconfig
> create mode 100644 security/bpf/Makefile
> create mode 100644 security/bpf/include/bpf_lsm.h
> create mode 100644 security/bpf/include/fs.h
> create mode 100644 security/bpf/include/hooks.h
> create mode 100644 security/bpf/lsm.c
> create mode 100644 security/bpf/lsm_fs.c
> create mode 100644 security/bpf/ops.c
> create mode 100644 tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
> create mode 100644 tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
>

2019-12-20 17:40:18

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

Hi Casey,

Thanks for taking a look!

On Fri, Dec 20, 2019 at 6:17 PM Casey Schaufler <[email protected]> wrote:
>
> On 12/20/2019 7:41 AM, KP Singh wrote:
> > From: KP Singh <[email protected]>
> >
> > This patch series is a continuation of the KRSI RFC
> > (https://lore.kernel.org/bpf/[email protected]/)
> >
> > # Motivation
> >
> > Google does rich analysis of runtime security data collected from
> > internal Linux deployments (corporate devices and servers) to detect and
> > thwart threats in real-time. Currently, this is done in custom kernel
> > modules but we would like to replace this with something that's upstream
> > and useful to others.
> >
> > The current kernel infrastructure for providing telemetry (Audit, Perf
> > etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
> > information provided by audit requires kernel changes to audit, its
> > policy language and user-space components. Furthermore, building a MAC
> > policy based on the newly added telemetry data requires changes to
> > various LSMs and their respective policy languages.
> >
> > This patchset proposes a new stackable and privileged LSM which allows
> > the LSM hooks to be implemented using eBPF. This facilitates a unified
> > and dynamic (not requiring re-compilation of the kernel) audit and MAC
> > policy.
> >
> > # Why an LSM?
> >
> > Linux Security Modules target security behaviours rather than the
> > kernel's API. For example, it's easy to miss out a newly added system
> > call for executing processes (eg. execve, execveat etc.) but the LSM
> > framework ensures that all process executions trigger the relevant hooks
> > irrespective of how the process was executed.
> >
> > Allowing users to implement LSM hooks at runtime also benefits the LSM
> > eco-system by enabling a quick feedback loop from the security community
> > about the kind of behaviours that the LSM Framework should be targeting.
> >
> > # How does it work?
> >
> > The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
> > program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
> > hook. All LSM hooks are exposed as files in securityfs. Attachment
> > requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
> > modifying MAC policies.
> >
> > The eBPF programs are passed the same arguments as the LSM hooks and
> > executed in the body of the hook.
>
> This effectively exposes the LSM hooks as external APIs.
> It would mean that we can't change or delete them. That
> would be bad.

Perhaps this should have been clearer, we *do not* want to make LSM hooks
a stable API and expect the eBPF programs to adapt when such changes occur.

Based on our comparison with the previous approach, this still ends up
being a better trade-off (w.r.t. maintenance) when compared to adding
specific helpers or verifier logic for each new hook or field that
needs to be exposed.

- KP

>
>
> > If any of the eBPF programs returns an
> > error (like ENOPERM), the behaviour represented by the hook is denied.
> >
> > Audit logs can be written using a format chosen by the eBPF program to
> > the perf events buffer and can be further processed in user-space.
> >
> > # Limitations of RFC v1
> >
> > In the previous design
> > (https://lore.kernel.org/bpf/[email protected]/),
> > the BPF programs received a context which could be queried to retrieve
> > specific pieces of information using specific helpers.
> >
> > For example, a program that attaches to the file_mprotect LSM hook and
> > queries the VMA region could have had the following context:
> >
> > // Special context for the hook.
> > struct bpf_mprotect_ctx {
> > struct vm_area_struct *vma;
> > };
> >
> > and accessed the fields using a hypothetical helper
> > "bpf_mprotect_vma_get_start:
> >
> > SEC("lsm/file_mprotect")
> > int mprotect_audit(bpf_mprotect_ctx *ctx)
> > {
> > unsigned long vm_start = bpf_mprotect_vma_get_start(ctx);
> > return 0;
> > }
> >
> > or directly read them from the context by updating the verifier to allow
> > accessing the fields:
> >
> > int mprotect_audit(bpf_mprotect_ctx *ctx)
> > {
> > unsigned long vm_start = ctx->vma->vm_start;
> > return 0;
> > }
> >
> > As we prototyped policies based on this design, we realized that this
> > approach is not general enough. Adding helpers or verifier code for all
> > usages would imply a high maintenance cost while severely restricting
> > the instrumentation capabilities which is the key value add of our
> > eBPF-based LSM.
> >
> > Feedback from the BPF maintainers at Linux Plumbers also pushed us
> > towards the following, more general, approach.
> >
> > # BTF Based Design
> >
> > The current design uses BTF
> > (https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html,
> > https://lwn.net/Articles/803258/) which allows verifiable read-only
> > structure accesses by field names rather than fixed offsets. This allows
> > accessing the hook parameters using a dynamically created context which
> > provides a certain degree of ABI stability:
> >
> > /* Clang builtin to handle field accesses. */
> > #define _(P) (__builtin_preserve_access_index(P))
> >
> > // Only declare the structure and fields intended to be used
> > // in the program
> > struct vm_area_struct {
> > unsigned long vm_start;
> > };
> >
> > // Declare the eBPF program mprotect_audit which attaches to
> > // to the file_mprotect LSM hook and accepts three arguments.
> > BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> > struct vm_area_struct *, vma,
> > unsigned long, reqprot, unsigned long, prot
> > {
> > unsigned long vm_start = _(vma->vm_start);
> > return 0;
> > }
> >
> > By relocating field offsets, BTF makes a large portion of kernel data
> > structures readily accessible across kernel versions without requiring a
> > large corpus of BPF helper functions and requiring recompilation with
> > every kernel version. The limitations of BTF compatibility are described
> > in BPF Co-Re (http://vger.kernel.org/bpfconf2019_talks/bpf-core.pdf,
> > i.e. field renames, #defines and changes to the signature of LSM hooks).
> >
> > This design imposes that the MAC policy (eBPF programs) be updated when
> > the inspected kernel structures change outside of BTF compatibility
> > guarantees. In practice, this is only required when a structure field
> > used by a current policy is removed (or renamed) or when the used LSM
> > hooks change. We expect the maintenance cost of these changes to be
> > acceptable as compared to the previous design
> > (https://lore.kernel.org/bpf/[email protected]/).
> >
> > # Distinction from Landlock
> >
> > We believe there exist two distinct use-cases with distinct set of users:
> >
> > * Unprivileged processes voluntarily relinquishing privileges with the
> > primary users being software developers.
> >
> > * Flexible privileged (CAP_MAC_ADMIN, CAP_SYS_ADMIN) MAC and Audit with
> > the primary users being system policy admins.
> >
> > These use-cases imply different APIs and trade-offs:
> >
> > * The unprivileged use case requires defining more stable and custom APIs
> > (through opaque contexts and precise helpers).
> >
> > * Privileged Audit and MAC requires deeper introspection of the kernel
> > data structures to maximise the flexibility that can be achieved without
> > kernel modification.
> >
> > Landlock has demonstrated filesystem sandboxes and now Ptrace access
> > control in its patches which are excellent use cases for an unprivileged
> > process voluntarily relinquishing privileges.
> >
> > However, Landlock has expanded its original goal, "towards unprivileged
> > sandboxing", to being a "low-level framework to build
> > access-control/audit systems" (https://landlock.io). We feel that the
> > design and implementation are still driven by the constraints and
> > trade-offs of the former use-case, and do not provide a satisfactory
> > solution to the latter.
> >
> > We also believe that our approach, direct access to common kernel data
> > structures as with BTF, is inappropriate for unprivileged processes and
> > probably not a good option for Landlock.
> >
> > In conclusion, we feel that the design for a privileged LSM and
> > unprivileged LSM are mutually exclusive and that one cannot be built
> > "on-top-of" the other. Doing so would limit the capabilities of what can
> > be done for an LSM that provides flexible audit and MAC capabilities or
> > provide in-appropriate access to kernel internals to an unprivileged
> > process.
> >
> > Furthermore, the Landlock design supports its historical use-case only
> > when unprivileged eBPF is allowed. This is something that warrants
> > discussion before an unprivileged LSM that uses eBPF is upstreamed.
> >
> > # Why not tracepoints or kprobes?
> >
> > In order to do MAC with tracepoints or kprobes, we would need to
> > override the return value of the security hook. This is not possible
> > with tracepoints or call-site kprobes.
> >
> > Attaching to the return boundary (kretprobe) implies that BPF programs
> > would always get called after all the other LSM hooks are called and
> > clobber the pre-existing LSM semantics.
> >
> > Enforcing MAC policy with an actual LSM helps leverage the verified
> > semantics of the framework.
> >
> > # Usage Examples
> >
> > A simple example and some documentation is included in the patchset.
> >
> > In order to better illustrate the capabilities of the framework some
> > more advanced prototype code has also been published separately:
> >
> > * Logging execution events (including environment variables and arguments):
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> > * Detecting deletion of running executables:
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> > * Detection of writes to /proc/<pid>/mem:
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> >
> > We have updated Google's internal telemetry infrastructure and have
> > started deploying this LSM on our Linux Workstations. This gives us more
> > confidence in the real-world applications of such a system.
> >
> > KP Singh (13):
> > bpf: Refactor BPF_EVENT context macros to its own header.
> > bpf: lsm: Add a skeleton and config options
> > bpf: lsm: Introduce types for eBPF based LSM
> > bpf: lsm: Allow btf_id based attachment for LSM hooks
> > tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
> > bpf: lsm: Init Hooks and create files in securityfs
> > bpf: lsm: Implement attach, detach and execution.
> > bpf: lsm: Show attached program names in hook read handler.
> > bpf: lsm: Add a helper function bpf_lsm_event_output
> > bpf: lsm: Handle attachment of the same program
> > tools/libbpf: Add bpf_program__attach_lsm
> > bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
> > bpf: lsm: Add Documentation
> >
> > Documentation/security/bpf.rst | 164 +++
> > Documentation/security/index.rst | 1 +
> > MAINTAINERS | 11 +
> > include/linux/bpf_event.h | 78 ++
> > include/linux/bpf_lsm.h | 25 +
> > include/linux/bpf_types.h | 4 +
> > include/trace/bpf_probe.h | 30 +-
> > include/uapi/linux/bpf.h | 12 +-
> > kernel/bpf/syscall.c | 10 +
> > kernel/bpf/verifier.c | 84 +-
> > kernel/trace/bpf_trace.c | 24 +-
> > security/Kconfig | 11 +-
> > security/Makefile | 2 +
> > security/bpf/Kconfig | 25 +
> > security/bpf/Makefile | 7 +
> > security/bpf/include/bpf_lsm.h | 63 +
> > security/bpf/include/fs.h | 23 +
> > security/bpf/include/hooks.h | 1015 +++++++++++++++++
> > security/bpf/lsm.c | 160 +++
> > security/bpf/lsm_fs.c | 176 +++
> > security/bpf/ops.c | 224 ++++
> > tools/include/uapi/linux/bpf.h | 12 +-
> > tools/lib/bpf/bpf.c | 2 +-
> > tools/lib/bpf/bpf.h | 6 +
> > tools/lib/bpf/libbpf.c | 163 ++-
> > tools/lib/bpf/libbpf.h | 4 +
> > tools/lib/bpf/libbpf.map | 7 +
> > tools/lib/bpf/libbpf_probes.c | 1 +
> > .../bpf/prog_tests/lsm_mprotect_audit.c | 129 +++
> > .../selftests/bpf/progs/lsm_mprotect_audit.c | 58 +
> > 30 files changed, 2451 insertions(+), 80 deletions(-)
> > create mode 100644 Documentation/security/bpf.rst
> > create mode 100644 include/linux/bpf_event.h
> > create mode 100644 include/linux/bpf_lsm.h
> > create mode 100644 security/bpf/Kconfig
> > create mode 100644 security/bpf/Makefile
> > create mode 100644 security/bpf/include/bpf_lsm.h
> > create mode 100644 security/bpf/include/fs.h
> > create mode 100644 security/bpf/include/hooks.h
> > create mode 100644 security/bpf/lsm.c
> > create mode 100644 security/bpf/lsm_fs.c
> > create mode 100644 security/bpf/ops.c
> > create mode 100644 tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
> > create mode 100644 tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
> >
>

2019-12-20 22:56:53

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)


On 20/12/2019 16:41, KP Singh wrote:
> From: KP Singh <[email protected]>
>
> This patch series is a continuation of the KRSI RFC
> (https://lore.kernel.org/bpf/[email protected]/)
>
> # Motivation
>
> Google does rich analysis of runtime security data collected from
> internal Linux deployments (corporate devices and servers) to detect and
> thwart threats in real-time. Currently, this is done in custom kernel
> modules but we would like to replace this with something that's upstream
> and useful to others.
>
> The current kernel infrastructure for providing telemetry (Audit, Perf
> etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
> information provided by audit requires kernel changes to audit, its
> policy language and user-space components. Furthermore, building a MAC
> policy based on the newly added telemetry data requires changes to
> various LSMs and their respective policy languages.
>
> This patchset proposes a new stackable and privileged LSM which allows
> the LSM hooks to be implemented using eBPF. This facilitates a unified
> and dynamic (not requiring re-compilation of the kernel) audit and MAC
> policy.
>
> # Why an LSM?
>
> Linux Security Modules target security behaviours rather than the
> kernel's API. For example, it's easy to miss out a newly added system
> call for executing processes (eg. execve, execveat etc.) but the LSM
> framework ensures that all process executions trigger the relevant hooks
> irrespective of how the process was executed.
>
> Allowing users to implement LSM hooks at runtime also benefits the LSM
> eco-system by enabling a quick feedback loop from the security community
> about the kind of behaviours that the LSM Framework should be targeting.
>
> # How does it work?
>
> The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
> program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
> hook. All LSM hooks are exposed as files in securityfs. Attachment
> requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
> modifying MAC policies.
>
> The eBPF programs are passed the same arguments as the LSM hooks and
> executed in the body of the hook. If any of the eBPF programs returns an
> error (like ENOPERM), the behaviour represented by the hook is denied.
>
> Audit logs can be written using a format chosen by the eBPF program to
> the perf events buffer and can be further processed in user-space.
>
> # Limitations of RFC v1
>
> In the previous design
> (https://lore.kernel.org/bpf/[email protected]/),
> the BPF programs received a context which could be queried to retrieve
> specific pieces of information using specific helpers.
>
> For example, a program that attaches to the file_mprotect LSM hook and
> queries the VMA region could have had the following context:
>
> // Special context for the hook.
> struct bpf_mprotect_ctx {
> struct vm_area_struct *vma;
> };
>
> and accessed the fields using a hypothetical helper
> "bpf_mprotect_vma_get_start:
>
> SEC("lsm/file_mprotect")
> int mprotect_audit(bpf_mprotect_ctx *ctx)
> {
> unsigned long vm_start = bpf_mprotect_vma_get_start(ctx);
> return 0;
> }
>
> or directly read them from the context by updating the verifier to allow
> accessing the fields:
>
> int mprotect_audit(bpf_mprotect_ctx *ctx)
> {
> unsigned long vm_start = ctx->vma->vm_start;
> return 0;
> }
>
> As we prototyped policies based on this design, we realized that this
> approach is not general enough. Adding helpers or verifier code for all
> usages would imply a high maintenance cost while severely restricting
> the instrumentation capabilities which is the key value add of our
> eBPF-based LSM.
>
> Feedback from the BPF maintainers at Linux Plumbers also pushed us
> towards the following, more general, approach.
>
> # BTF Based Design
>
> The current design uses BTF
> (https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html,
> https://lwn.net/Articles/803258/) which allows verifiable read-only
> structure accesses by field names rather than fixed offsets. This allows
> accessing the hook parameters using a dynamically created context which
> provides a certain degree of ABI stability:
>
> /* Clang builtin to handle field accesses. */
> #define _(P) (__builtin_preserve_access_index(P))
>
> // Only declare the structure and fields intended to be used
> // in the program
> struct vm_area_struct {
> unsigned long vm_start;
> };
>
> // Declare the eBPF program mprotect_audit which attaches to
> // to the file_mprotect LSM hook and accepts three arguments.
> BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> struct vm_area_struct *, vma,
> unsigned long, reqprot, unsigned long, prot
> {
> unsigned long vm_start = _(vma->vm_start);
> return 0;
> }
>
> By relocating field offsets, BTF makes a large portion of kernel data
> structures readily accessible across kernel versions without requiring a
> large corpus of BPF helper functions and requiring recompilation with
> every kernel version. The limitations of BTF compatibility are described
> in BPF Co-Re (http://vger.kernel.org/bpfconf2019_talks/bpf-core.pdf,
> i.e. field renames, #defines and changes to the signature of LSM hooks).
>
> This design imposes that the MAC policy (eBPF programs) be updated when
> the inspected kernel structures change outside of BTF compatibility
> guarantees. In practice, this is only required when a structure field
> used by a current policy is removed (or renamed) or when the used LSM
> hooks change. We expect the maintenance cost of these changes to be
> acceptable as compared to the previous design
> (https://lore.kernel.org/bpf/[email protected]/).
>
> # Distinction from Landlock
>
> We believe there exist two distinct use-cases with distinct set of users:
>
> * Unprivileged processes voluntarily relinquishing privileges with the
> primary users being software developers.
>
> * Flexible privileged (CAP_MAC_ADMIN, CAP_SYS_ADMIN) MAC and Audit with
> the primary users being system policy admins.
>
> These use-cases imply different APIs and trade-offs:
>
> * The unprivileged use case requires defining more stable and custom APIs
> (through opaque contexts and precise helpers).
>
> * Privileged Audit and MAC requires deeper introspection of the kernel
> data structures to maximise the flexibility that can be achieved without
> kernel modification.
>
> Landlock has demonstrated filesystem sandboxes and now Ptrace access
> control in its patches which are excellent use cases for an unprivileged
> process voluntarily relinquishing privileges.
>
> However, Landlock has expanded its original goal, "towards unprivileged
> sandboxing", to being a "low-level framework to build
> access-control/audit systems" (https://landlock.io). We feel that the
> design and implementation are still driven by the constraints and
> trade-offs of the former use-case, and do not provide a satisfactory
> solution to the latter.
>
> We also believe that our approach, direct access to common kernel data
> structures as with BTF, is inappropriate for unprivileged processes and
> probably not a good option for Landlock.
>
> In conclusion, we feel that the design for a privileged LSM and
> unprivileged LSM are mutually exclusive and that one cannot be built
> "on-top-of" the other. Doing so would limit the capabilities of what can
> be done for an LSM that provides flexible audit and MAC capabilities or
> provide in-appropriate access to kernel internals to an unprivileged
> process.

I don't think that the design for a privileged LSM and an unprivileged
LSM are necessarily mutually exclusive, however I do agree that the
design of an *introspection* LSM like this version of KRSI, and an
unprivileged LSM are mutually exclusive.

>
> Furthermore, the Landlock design supports its historical use-case only
> when unprivileged eBPF is allowed. This is something that warrants
> discussion before an unprivileged LSM that uses eBPF is upstreamed.

Because of seccomp-bpf, on which the first version of Landlock was based
on, I then used eBPF as a way to define a security policy which could be
updated on the fly (thanks to eBPF maps) and evolves over time. The main
goal of Landlock was and still is to bring sandboxing features to all
users, which means to have an unprivileged access-control. However, I've
reach a similar conclusion about eBPF for unprivileged access-control,
but for slightly different reasons.

eBPF is very powerful and I proved with Landlock that it is possible to
implement an access-control with it. However, a programmatic
access-control does not fit well with unprivileged principles (i.e.
innocuous composability). First, it can be used for side-channel attacks
against (other) access-controls. Second, composability of eBPF programs
imply to execute a stack of programs, which does not scale well. Third,
as shown by multiple attacks, it is quite challenging to safely expose
eBPF to malicious processes.

I'm working on a version of Landlock without eBPF, but still with the
initial sought properties: safe unprivileged composability, modularity,
and dynamic update. I'll send this version soon.

I hope that the work and experience from Landlock to bring eBPF to LSM
will continue to be used through KRSI. Landlock will now focus on the
unprivileged sandboxing part, without eBPF. Stay tuned!


>
> # Why not tracepoints or kprobes?
>
> In order to do MAC with tracepoints or kprobes, we would need to
> override the return value of the security hook. This is not possible
> with tracepoints or call-site kprobes.
>
> Attaching to the return boundary (kretprobe) implies that BPF programs
> would always get called after all the other LSM hooks are called and
> clobber the pre-existing LSM semantics.
>
> Enforcing MAC policy with an actual LSM helps leverage the verified
> semantics of the framework.
>
> # Usage Examples
>
> A simple example and some documentation is included in the patchset.
>
> In order to better illustrate the capabilities of the framework some
> more advanced prototype code has also been published separately:
>
> * Logging execution events (including environment variables and arguments):
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> * Detecting deletion of running executables:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> * Detection of writes to /proc/<pid>/mem:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
>
> We have updated Google's internal telemetry infrastructure and have
> started deploying this LSM on our Linux Workstations. This gives us more
> confidence in the real-world applications of such a system.
>
> KP Singh (13):
> bpf: Refactor BPF_EVENT context macros to its own header.
> bpf: lsm: Add a skeleton and config options
> bpf: lsm: Introduce types for eBPF based LSM
> bpf: lsm: Allow btf_id based attachment for LSM hooks
> tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
> bpf: lsm: Init Hooks and create files in securityfs
> bpf: lsm: Implement attach, detach and execution.
> bpf: lsm: Show attached program names in hook read handler.
> bpf: lsm: Add a helper function bpf_lsm_event_output
> bpf: lsm: Handle attachment of the same program
> tools/libbpf: Add bpf_program__attach_lsm
> bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
> bpf: lsm: Add Documentation
>
> Documentation/security/bpf.rst | 164 +++
> Documentation/security/index.rst | 1 +
> MAINTAINERS | 11 +
> include/linux/bpf_event.h | 78 ++
> include/linux/bpf_lsm.h | 25 +
> include/linux/bpf_types.h | 4 +
> include/trace/bpf_probe.h | 30 +-
> include/uapi/linux/bpf.h | 12 +-
> kernel/bpf/syscall.c | 10 +
> kernel/bpf/verifier.c | 84 +-
> kernel/trace/bpf_trace.c | 24 +-
> security/Kconfig | 11 +-
> security/Makefile | 2 +
> security/bpf/Kconfig | 25 +
> security/bpf/Makefile | 7 +
> security/bpf/include/bpf_lsm.h | 63 +
> security/bpf/include/fs.h | 23 +
> security/bpf/include/hooks.h | 1015 +++++++++++++++++
> security/bpf/lsm.c | 160 +++
> security/bpf/lsm_fs.c | 176 +++
> security/bpf/ops.c | 224 ++++
> tools/include/uapi/linux/bpf.h | 12 +-
> tools/lib/bpf/bpf.c | 2 +-
> tools/lib/bpf/bpf.h | 6 +
> tools/lib/bpf/libbpf.c | 163 ++-
> tools/lib/bpf/libbpf.h | 4 +
> tools/lib/bpf/libbpf.map | 7 +
> tools/lib/bpf/libbpf_probes.c | 1 +
> .../bpf/prog_tests/lsm_mprotect_audit.c | 129 +++
> .../selftests/bpf/progs/lsm_mprotect_audit.c | 58 +
> 30 files changed, 2451 insertions(+), 80 deletions(-)
> create mode 100644 Documentation/security/bpf.rst
> create mode 100644 include/linux/bpf_event.h
> create mode 100644 include/linux/bpf_lsm.h
> create mode 100644 security/bpf/Kconfig
> create mode 100644 security/bpf/Makefile
> create mode 100644 security/bpf/include/bpf_lsm.h
> create mode 100644 security/bpf/include/fs.h
> create mode 100644 security/bpf/include/hooks.h
> create mode 100644 security/bpf/lsm.c
> create mode 100644 security/bpf/lsm_fs.c
> create mode 100644 security/bpf/ops.c
> create mode 100644 tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
> create mode 100644 tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
>

2019-12-22 01:36:08

by Alexei Starovoitov

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, Dec 20, 2019 at 04:41:55PM +0100, KP Singh wrote:
> // Declare the eBPF program mprotect_audit which attaches to
> // to the file_mprotect LSM hook and accepts three arguments.
> BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> struct vm_area_struct *, vma,
> unsigned long, reqprot, unsigned long, prot
> {
> unsigned long vm_start = _(vma->vm_start);
> return 0;
> }

I think the only sore point of the patchset is:
security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
With bpf trampoline this type of 'kernel types -> bpf types' converters
are no longer necessary. Please take a look at tcp-congestion-control patchset:
https://patchwork.ozlabs.org/cover/1214417/
Instead of doing similar thing (like your patch 1 plus patch 6) it's using
trampoline to provide bpf based congestion control callbacks into tcp stack.
The same trampoline-based mechanism can be reused by bpf_lsm.
Then all manual work of doing BPF_LSM_HOOK(...) for every hook won't be
necessary. It will also prove the point that attaching BPF to raw LSM hooks
doesn't freeze them into stable abi.
The programs can keep the same syntax as in your examples:
BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
libbpf will find file_mprotect's btf_id in kernel vmlinux and pass it to
the kernel for attaching. Just like fentry/fexit bpf progs are doing
and just like bpf-based cc is doing as well.

> In order to better illustrate the capabilities of the framework some
> more advanced prototype code has also been published separately:
>
> * Logging execution events (including environment variables and arguments):
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> * Detecting deletion of running executables:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> * Detection of writes to /proc/<pid>/mem:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c

Thank you for sharing these examples. That definitely helps to see more
complete picture. I noticed that the examples are using the pattern:
u32 map_id = 0;
env = bpf_map_lookup_elem(&env_map, &map_id);
Essentially they're global variables. libbpf already supports them.
bpf prog can use them as:
struct env_value env;
int bpf_prog(..)
{
env.name... env.value..
}
That will make progs a bit easier to read and faster too.
Accesing global vars from user space is also trivial with skeleton work:
lsm_audit_env_skel->bss->env.name... env.value.
Both bpf side and user side can access globals as normal C variables.

There is a small issue in the patches 8 and 10.
bpf program names are not unique and bpf-lsm should not require them to be different.
bpf_attr->prog_name is also short at 16 bytes. It's for introspection only.
Longer program names are supplied via btf's func_info.
It feels that:
cat /sys/kernel/security/bpf/process_execution
env_dumper__v2
is reinventing the wheel. bpftool is the main introspection tool.
It can print progs attached to perf, cgroup, networking. I think it's better to
stay consistent and do the same with bpf-lsm.

Another issue is in proposed attaching method:
hook_fd = open("/sys/kernel/security/bpf/process_execution");
sys_bpf(attach, prog_fd, hook_fd);
With bpf tracing we moved to FD-based attaching, because permanent attaching is
problematic in production. We're going to provide FD-based api to attach to
networking as well, because xdp/tc/cgroup prog attaching suffers from the same
production issues. Mainly with permanent attaching there is no ownership of
attachment. Everything is global and permanent. It's not clear what
process/script suppose to detach/cleanup. I suggest bpf-lsm use FD-based
attaching from the beginning. Take a look at raw_tp/tp_btf/fentry/fexit style
of attaching. All of them return FD which represents what libbpf calls
'bpf_link' concept. Once refcnt of that FD goes to zero that link (attachment)
is destroyed and program is detached _by the kernel_. To make such links
permanent the application can pin them in bpffs. The pinning patches haven't
landed yet, but the concept of the link is quite powerful and much more
production friendly than permanent attaching.
bpf-lsm will still be able to attach multiple progs to the same hook and
see what is attached via bpftool.

The rest looks good. Thank you for working on it.

2019-12-24 00:09:17

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM

On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
>
> From: KP Singh <[email protected]>
>
> Update the libbpf library with functionality to load and
> attach a program type BPF_PROG_TYPE_LSM, currently with
> only one expected attach type BPF_LSM_MAC.
>
> Signed-off-by: KP Singh <[email protected]>
> ---
> tools/lib/bpf/bpf.c | 2 +-
> tools/lib/bpf/bpf.h | 6 +++++
> tools/lib/bpf/libbpf.c | 44 +++++++++++++++++++++--------------
> tools/lib/bpf/libbpf.h | 2 ++
> tools/lib/bpf/libbpf.map | 6 +++++
> tools/lib/bpf/libbpf_probes.c | 1 +
> 6 files changed, 43 insertions(+), 18 deletions(-)
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 98596e15390f..9c6fb083f7de 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -228,7 +228,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
> memset(&attr, 0, sizeof(attr));
> attr.prog_type = load_attr->prog_type;
> attr.expected_attach_type = load_attr->expected_attach_type;
> - if (attr.prog_type == BPF_PROG_TYPE_TRACING) {
> + if (needs_btf_attach(attr.prog_type)) {
> attr.attach_btf_id = load_attr->attach_btf_id;
> attr.attach_prog_fd = load_attr->attach_prog_fd;
> } else {
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 3c791fa8e68e..df2a00ff349f 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -177,6 +177,12 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
> __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
> __u64 *probe_offset, __u64 *probe_addr);
>
> +static inline bool needs_btf_attach(enum bpf_prog_type prog_type)
> +{
> + return (prog_type == BPF_PROG_TYPE_TRACING ||
> + prog_type == BPF_PROG_TYPE_LSM);
> +}
> +

This doesn't have to be a public API, right? It also doesn't follow
naming conventions of libbpf APIs. Let's just move it into
libbpf_internal.h, given it's used in few files.

Also, Martin's patches add STRUCT_OPS, which do need btf_attach, but
don't set attach_prog_fd. So maybe something like
libbpf_need_attach_prog_btf() for a name to be a bit more specific?


> #ifdef __cplusplus
> } /* extern "C" */
> #endif
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index b20f82e58989..b0b27d8e5a37 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -3738,7 +3738,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
> load_attr.insns = insns;
> load_attr.insns_cnt = insns_cnt;
> load_attr.license = license;
> - if (prog->type == BPF_PROG_TYPE_TRACING) {
> + if (needs_btf_attach(prog->type)) {
> load_attr.attach_prog_fd = prog->attach_prog_fd;
> load_attr.attach_btf_id = prog->attach_btf_id;
> } else {
> @@ -3983,7 +3983,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
>
> bpf_program__set_type(prog, prog_type);
> bpf_program__set_expected_attach_type(prog, attach_type);
> - if (prog_type == BPF_PROG_TYPE_TRACING) {
> + if (needs_btf_attach(prog_type)) {
> err = libbpf_find_attach_btf_id(prog->section_name,
> attach_type,
> attach_prog_fd);
> @@ -4933,6 +4933,7 @@ bool bpf_program__is_##NAME(const struct bpf_program *prog) \
> } \
>
> BPF_PROG_TYPE_FNS(socket_filter, BPF_PROG_TYPE_SOCKET_FILTER);
> +BPF_PROG_TYPE_FNS(lsm, BPF_PROG_TYPE_LSM);
> BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);
> BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);
> BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);
> @@ -5009,6 +5010,8 @@ static const struct {
> BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
> BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
> BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
> + BPF_PROG_BTF("lsm/", BPF_PROG_TYPE_LSM,
> + BPF_LSM_MAC),

Is is supposed to be attachable same as BPF_PROG_TYPE_TRACING
programs? If yes, please define auto-attaching function, similar to
SEC_DEF("raw_tp") few lines below this one.

> BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB,
> BPF_CGROUP_INET_INGRESS),
> BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB,
> @@ -5119,32 +5122,39 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
> return -ESRCH;
> }
>
> -#define BTF_PREFIX "btf_trace_"
> +static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name,

typo: typdef -> typedef

But actually let's generalize it to pass BTF_KIND as another param, I
think I have a need for this (we might want to do that for structs,
not just typedef->func_proto).
Following btf__find_by_name_kind() naming, it probably should be
called btf__find_by_prefix_kind()?

> + const char *prefix)
> +{
> +
> + size_t prefix_len = strlen(prefix);
> + char btf_type_name[128];
> +
> + strcpy(btf_type_name, prefix);
> + strncat(btf_type_name, name, sizeof(btf_type_name) - (prefix_len + 1));

at this point snprintf(btf_type_name, "%s%.*%s", prefix,
sizeof(btf_type_name) - prefix_len - 1, name) looks like a better and
cleaner alternative.

> + return btf__find_by_name_kind(btf, btf_type_name, BTF_KIND_TYPEDEF);
> +}
> +
> +#define BTF_TRACE_PREFIX "btf_trace_"
> +#define BTF_LSM_PREFIX "lsm_btf_"
> +

[...]

2019-12-24 00:10:22

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM

On Mon, Dec 23, 2019 at 4:07 PM Andrii Nakryiko
<[email protected]> wrote:
>
> On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
> >
> > From: KP Singh <[email protected]>
> >
> > Update the libbpf library with functionality to load and
> > attach a program type BPF_PROG_TYPE_LSM, currently with
> > only one expected attach type BPF_LSM_MAC.
> >
> > Signed-off-by: KP Singh <[email protected]>
> > ---
> > tools/lib/bpf/bpf.c | 2 +-
> > tools/lib/bpf/bpf.h | 6 +++++
> > tools/lib/bpf/libbpf.c | 44 +++++++++++++++++++++--------------
> > tools/lib/bpf/libbpf.h | 2 ++
> > tools/lib/bpf/libbpf.map | 6 +++++
> > tools/lib/bpf/libbpf_probes.c | 1 +
> > 6 files changed, 43 insertions(+), 18 deletions(-)
> >
> > diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> > index 98596e15390f..9c6fb083f7de 100644
> > --- a/tools/lib/bpf/bpf.c
> > +++ b/tools/lib/bpf/bpf.c
> > @@ -228,7 +228,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
> > memset(&attr, 0, sizeof(attr));
> > attr.prog_type = load_attr->prog_type;
> > attr.expected_attach_type = load_attr->expected_attach_type;
> > - if (attr.prog_type == BPF_PROG_TYPE_TRACING) {
> > + if (needs_btf_attach(attr.prog_type)) {
> > attr.attach_btf_id = load_attr->attach_btf_id;
> > attr.attach_prog_fd = load_attr->attach_prog_fd;
> > } else {
> > diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> > index 3c791fa8e68e..df2a00ff349f 100644
> > --- a/tools/lib/bpf/bpf.h
> > +++ b/tools/lib/bpf/bpf.h
> > @@ -177,6 +177,12 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
> > __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
> > __u64 *probe_offset, __u64 *probe_addr);
> >
> > +static inline bool needs_btf_attach(enum bpf_prog_type prog_type)
> > +{
> > + return (prog_type == BPF_PROG_TYPE_TRACING ||
> > + prog_type == BPF_PROG_TYPE_LSM);
> > +}
> > +
>
> This doesn't have to be a public API, right? It also doesn't follow
> naming conventions of libbpf APIs. Let's just move it into
> libbpf_internal.h, given it's used in few files.
>
> Also, Martin's patches add STRUCT_OPS, which do need btf_attach, but
> don't set attach_prog_fd. So maybe something like
> libbpf_need_attach_prog_btf() for a name to be a bit more specific?
>
>
> > #ifdef __cplusplus
> > } /* extern "C" */
> > #endif
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index b20f82e58989..b0b27d8e5a37 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -3738,7 +3738,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
> > load_attr.insns = insns;
> > load_attr.insns_cnt = insns_cnt;
> > load_attr.license = license;
> > - if (prog->type == BPF_PROG_TYPE_TRACING) {
> > + if (needs_btf_attach(prog->type)) {
> > load_attr.attach_prog_fd = prog->attach_prog_fd;
> > load_attr.attach_btf_id = prog->attach_btf_id;
> > } else {
> > @@ -3983,7 +3983,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
> >
> > bpf_program__set_type(prog, prog_type);
> > bpf_program__set_expected_attach_type(prog, attach_type);
> > - if (prog_type == BPF_PROG_TYPE_TRACING) {
> > + if (needs_btf_attach(prog_type)) {
> > err = libbpf_find_attach_btf_id(prog->section_name,
> > attach_type,
> > attach_prog_fd);
> > @@ -4933,6 +4933,7 @@ bool bpf_program__is_##NAME(const struct bpf_program *prog) \
> > } \
> >
> > BPF_PROG_TYPE_FNS(socket_filter, BPF_PROG_TYPE_SOCKET_FILTER);
> > +BPF_PROG_TYPE_FNS(lsm, BPF_PROG_TYPE_LSM);
> > BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);
> > BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);
> > BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);
> > @@ -5009,6 +5010,8 @@ static const struct {
> > BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
> > BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
> > BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
> > + BPF_PROG_BTF("lsm/", BPF_PROG_TYPE_LSM,
> > + BPF_LSM_MAC),
>
> Is is supposed to be attachable same as BPF_PROG_TYPE_TRACING
> programs? If yes, please define auto-attaching function, similar to
> SEC_DEF("raw_tp") few lines below this one.
>

ah, haven't gotten to patch 11 yet, disregard this.

> > BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB,
> > BPF_CGROUP_INET_INGRESS),
> > BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB,
> > @@ -5119,32 +5122,39 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
> > return -ESRCH;
> > }
> >
> > -#define BTF_PREFIX "btf_trace_"
> > +static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name,
>
> typo: typdef -> typedef
>
> But actually let's generalize it to pass BTF_KIND as another param, I
> think I have a need for this (we might want to do that for structs,
> not just typedef->func_proto).
> Following btf__find_by_name_kind() naming, it probably should be
> called btf__find_by_prefix_kind()?
>
> > + const char *prefix)
> > +{
> > +
> > + size_t prefix_len = strlen(prefix);
> > + char btf_type_name[128];
> > +
> > + strcpy(btf_type_name, prefix);
> > + strncat(btf_type_name, name, sizeof(btf_type_name) - (prefix_len + 1));
>
> at this point snprintf(btf_type_name, "%s%.*%s", prefix,
> sizeof(btf_type_name) - prefix_len - 1, name) looks like a better and
> cleaner alternative.
>
> > + return btf__find_by_name_kind(btf, btf_type_name, BTF_KIND_TYPEDEF);
> > +}
> > +
> > +#define BTF_TRACE_PREFIX "btf_trace_"
> > +#define BTF_LSM_PREFIX "lsm_btf_"
> > +
>
> [...]

2019-12-24 06:29:34

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
>
> From: KP Singh <[email protected]>
>
> The LSM creates files in securityfs for each hook registered with the
> LSM.
>
> /sys/kernel/security/bpf/<h_name>
>
> The list of LSM hooks are maintained in an internal header "hooks.h"
> Eventually, this list should either be defined collectively in
> include/linux/lsm_hooks.h or auto-generated from it.
>
> * Creation of a file for the hook in the securityfs.
> * Allocation of a bpf_lsm_hook data structure which stores
> a pointer to the dentry of the newly created file in securityfs.
> * Creation of a typedef for the hook so that BTF information
> can be generated for the LSM hooks to:
>
> - Make them "Compile Once, Run Everywhere".
> - Pass the right arguments when the attached programs are run.
> - Verify the accesses made by the program by using the BTF
> information.
>
> Signed-off-by: KP Singh <[email protected]>
> ---
> include/linux/bpf_lsm.h | 12 +
> security/bpf/Makefile | 4 +-
> security/bpf/include/bpf_lsm.h | 63 ++
> security/bpf/include/fs.h | 23 +
> security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
> security/bpf/lsm.c | 138 ++++-
> security/bpf/lsm_fs.c | 82 +++
> 7 files changed, 1333 insertions(+), 4 deletions(-)
> create mode 100644 include/linux/bpf_lsm.h
> create mode 100644 security/bpf/include/bpf_lsm.h
> create mode 100644 security/bpf/include/fs.h
> create mode 100644 security/bpf/include/hooks.h
> create mode 100644 security/bpf/lsm_fs.c
>

[...]

> +
> +/*
> + * The hooks can have an int or void return type, these macros allow having a
> + * single implementation of DEFINE_LSM_HOOK irrespective of the return type.
> + */
> +#define LSM_HOOK_RET(ret, x) LSM_HOOK_RET_##ret(x)
> +#define LSM_HOOK_RET_int(x) x
> +#define LSM_HOOK_RET_void(x)
> +
> +/*
> + * This macro defines the body of a LSM hook which runs the eBPF programs that
> + * are attached to the hook and returns the error code from the eBPF programs if
> + * the return type of the hook is int.
> + */
> +#define DEFINE_LSM_HOOK(hook, ret, proto, args) \
> +typedef ret (*lsm_btf_##hook)(proto); \
> +static ret bpf_lsm_##hook(proto) \
> +{ \
> + return LSM_HOOK_RET(ret, LSM_RUN_PROGS(hook##_type, args)); \
> }

I'm probably missing something, but according to LSM_HOOK_RET
definition for when ret==void, bpf_lsm_##hook will be a noop and won't
call any BPF program. Did I miss some additional macro magic?

>
> +/*
> + * Define the body of each of the LSM hooks defined in hooks.h.
> + */
> +#define BPF_LSM_HOOK(hook, ret, args, proto) \
> + DEFINE_LSM_HOOK(hook, ret, BPF_LSM_ARGS(args), BPF_LSM_ARGS(proto))
> +#include "hooks.h"
> +#undef BPF_LSM_HOOK
> +#undef DEFINE_LSM_HOOK
> +
> +/*
> + * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
> + * The list contains information for each of the hook and can be indexed by the
> + * its type to initialize security FS, attach, detach and execute eBPF programs
> + * for the hook.
> + */
> +struct bpf_lsm_hook bpf_lsm_hooks_list[] = {
> + #define BPF_LSM_HOOK(h, ...) \
> + [h##_type] = { \
> + .h_type = h##_type, \
> + .mutex = __MUTEX_INITIALIZER( \
> + bpf_lsm_hooks_list[h##_type].mutex), \
> + .name = #h, \
> + .btf_hook_func = \
> + (void *)(lsm_btf_##h)(bpf_lsm_##h), \

this btf_hook_func, is it assigned just so that type information for
bpf_lsm_xxx typedefs are preserved, is that right? It doesn't seem to
be ever called or read. If I'm not missing anything, check out
Martin's latest STRUCT_OPS patch set. He defines EMIT_TYPE_INFO(type)
macro, which will ensure that BTF for specified type is emitted into
vmlinux BTF, without actually using any extra space, defining extra
fields or static variables, etc. I suggest using the same for the
cleanest result.

One more thing regarding lsm_bpf_ typedefs. Currently you are defining
them as a pointer to func_proto, matching LSM hook. There is an
alternative approach, which has few benefits over using func_proto. If
instead you define a struct, where each argument of func prototype is
represented as 8-byte aligned field, this will contain all the
necessary information for BPF verifier to do its job (just like
func_proto). But in addition to that, when vmlinux.h is generated, it
will contain a nice struct bpf_lsm_<hook_name> with correct structure
to be used **directly** in BPF program, as a single context argument.
So with vmlinux.h, users won't have to re-define all the argument
types and names in their BPF_TRACE_x definition. Let me provide
concrete example from your cover letter. This is what you provide as
an example:

BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
struct vm_area_struct *, vma,
unsigned long, reqprot, unsigned long, prot) {...}

on kernel side, you'll have:

typedef int (*bpf_lsm_file_mprotect)(struct vm_area_struct *vma,
unsigned long reqprot,
unsigned long prot);

So you can see that user has to go and copy/paste all the arguments
and their types and paste them in this verbose BPF_TRACE_3 macro to
define correct BPF program.

Now, imagine that instead of typedef above, we define equivalent struct:

struct bpf_lsm_file_mprotect {
struct vm_area_struct *vma;
unsigned long reqprot;
unsigned long prot;
};

This type will get dumped into vmlinux.h, which can be used from BPF
user code as such:

SEC("lsm/file_mprotect")
int mprotect_audito(struct bpf_lsm_file_mprotect *ctx)
{
... here you can use ctx->vma, ctx->reqprot, ctx->prot ...
}


Meanwhile, there will be just minimal changes to BPF verifier to use
such struct instead of func_proto for verification of LSM programs.

We currently have similar issue with raw_tp programs and I've been
thinking about switching that to structs instead of func_proto, so we
might as well coordinate that and reuse the same logic in BPF
verifier.

Thoughts?



> + },
> + #include "hooks.h"
> + #undef BPF_LSM_HOOK
> +};
> +

[...]

2019-12-24 06:52:49

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, Dec 20, 2019 at 7:42 AM KP Singh <[email protected]> wrote:
>
> From: KP Singh <[email protected]>
>
> This patch series is a continuation of the KRSI RFC
> (https://lore.kernel.org/bpf/[email protected]/)
>

[...]

> # Usage Examples
>
> A simple example and some documentation is included in the patchset.
>
> In order to better illustrate the capabilities of the framework some
> more advanced prototype code has also been published separately:
>
> * Logging execution events (including environment variables and arguments):
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> * Detecting deletion of running executables:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> * Detection of writes to /proc/<pid>/mem:
> https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c

Are you planning on submitting these examples for inclusion into
samples/bpf or selftests/bpf? It would be great to have more examples
and we can review and suggest nicer ways to go about writing them
(e.g., BPF skeleton and global data Alexei mentioned earlier).

>
> We have updated Google's internal telemetry infrastructure and have
> started deploying this LSM on our Linux Workstations. This gives us more
> confidence in the real-world applications of such a system.
>
> KP Singh (13):
> bpf: Refactor BPF_EVENT context macros to its own header.
> bpf: lsm: Add a skeleton and config options
> bpf: lsm: Introduce types for eBPF based LSM
> bpf: lsm: Allow btf_id based attachment for LSM hooks
> tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
> bpf: lsm: Init Hooks and create files in securityfs
> bpf: lsm: Implement attach, detach and execution.
> bpf: lsm: Show attached program names in hook read handler.
> bpf: lsm: Add a helper function bpf_lsm_event_output
> bpf: lsm: Handle attachment of the same program
> tools/libbpf: Add bpf_program__attach_lsm
> bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
> bpf: lsm: Add Documentation
>

[...]

2019-12-30 14:59:45

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 21-Dez 17:27, Alexei Starovoitov wrote:
> On Fri, Dec 20, 2019 at 04:41:55PM +0100, KP Singh wrote:
> > // Declare the eBPF program mprotect_audit which attaches to
> > // to the file_mprotect LSM hook and accepts three arguments.
> > BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> > struct vm_area_struct *, vma,
> > unsigned long, reqprot, unsigned long, prot
> > {
> > unsigned long vm_start = _(vma->vm_start);
> > return 0;
> > }
>

Hi Alexei,

Thanks for the feedback. This is really helpful!

> I think the only sore point of the patchset is:
> security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
> With bpf trampoline this type of 'kernel types -> bpf types' converters
> are no longer necessary. Please take a look at tcp-congestion-control patchset:
> https://patchwork.ozlabs.org/cover/1214417/
> Instead of doing similar thing (like your patch 1 plus patch 6) it's using
> trampoline to provide bpf based congestion control callbacks into tcp stack.
> The same trampoline-based mechanism can be reused by bpf_lsm.
> Then all manual work of doing BPF_LSM_HOOK(...) for every hook won't be
> necessary. It will also prove the point that attaching BPF to raw LSM hooks
> doesn't freeze them into stable abi.

Really cool!

I looked into how BPF trampolines are being used in tracing and the
new STRUCT_OPS patchset and was able protoype
(https://github.com/sinkap/linux-krsi/tree/patch/v1/trampoline_prototype,
not ready for review yet) which:

* Gets rid of security/bpf/include/hooks.h and all of the static
macro magic essentially making the LSM ~truly instrumentable~ at
runtime.
* Gets rid of the generation of any new types as we already have
all the BTF information in the kernel in the following two types:

struct security_hook_heads {
.
.
struct hlist_head file_mprotect; <- Append the callback at this offset
.
.
};

and

union security_list_options {
int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot);
};

Which is the same type as the typedef that's currently being generated
, i.e. lsm_btf_file_mprotect

In the current prototype, libbpf converts the name of the hook into an
offset into the security_hook_heads and the verifier does the
following when a program is loaded:

* Verifies the offset and the type at the offset (struct hlist_head).
* Resolves the func_proto (by looking up the type in
security_list_options) and updates prog->aux with the name and
func_proto which are then verified similar to raw_tp programs with
btf_ctx_access.

On attachment:

* A trampoline is created and appended to the security_hook_heads
for the BPF LSM.
* An anonymous FD is returned and the attachment is conditional on the
references to FD (as suggested and similar to fentry/fexit tracing
programs).

This implies that the BPF programs are "the LSM hook" as opposed to
being executed inside a statically defined hook body which requires
mutable LSM hooks for which I was able to re-use some of ideas in
Sargun's patch:

https://lore.kernel.org/lkml/[email protected]/

to maintain a separate security_hook_heads struct for dynamically
added LSM hooks by the BPF LSM which are executed after all the
statically defined hooks.

> Longer program names are supplied via btf's func_info.
> It feels that:
> cat /sys/kernel/security/bpf/process_execution
> env_dumper__v2
> is reinventing the wheel. bpftool is the main introspection tool.
> It can print progs attached to perf, cgroup, networking. I think it's better to
> stay consistent and do the same with bpf-lsm.

I agree, based on the new feedback, I don't think we need securityFS
attachment points anymore. I was able to get rid of it completely.

>
> Another issue is in proposed attaching method:
> hook_fd = open("/sys/kernel/security/bpf/process_execution");
> sys_bpf(attach, prog_fd, hook_fd);
> With bpf tracing we moved to FD-based attaching, because permanent attaching is
> problematic in production. We're going to provide FD-based api to attach to
> networking as well, because xdp/tc/cgroup prog attaching suffers from the same
> production issues. Mainly with permanent attaching there is no ownership of
> attachment. Everything is global and permanent. It's not clear what
> process/script suppose to detach/cleanup. I suggest bpf-lsm use FD-based
> attaching from the beginning. Take a look at raw_tp/tp_btf/fentry/fexit style
> of attaching. All of them return FD which represents what libbpf calls
> 'bpf_link' concept. Once refcnt of that FD goes to zero that link (attachment)
> is destroyed and program is detached _by the kernel_. To make such links
> permanent the application can pin them in bpffs. The pinning patches haven't
> landed yet, but the concept of the link is quite powerful and much more
> production friendly than permanent attaching.

I like this. This also means we don't immediately need the handling of
duplicate names so I dropped that bit of the patch as well and updated
the attachment to use this mechanism.

> bpf-lsm will still be able to attach multiple progs to the same hook and
> see what is attached via bpftool.
>
> The rest looks good. Thank you for working on it.

There are some choices we need to make here from an API perspective:

* Should we "repurpose" attr->attach_btf_id and use it as an offset
into security_hook_heads or add a new attribute
(e.g lsm_hook_offset) for the offset or use name of the LSM hook
(e.g. lsm_hook_name).
* Since we don't have the files in securityFS, the attachment does not
have a target_fd. Should we add a new type of BPF command?
e.g. LSM_HOOK_OPEN?

I will clean up the prototype, incorporate some of the other feedback
received, and send a v2.

Wishing everyone a very Happy New Year!

- KP

2019-12-30 15:05:28

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 23-Dec 22:51, Andrii Nakryiko wrote:
> On Fri, Dec 20, 2019 at 7:42 AM KP Singh <[email protected]> wrote:
> >
> > From: KP Singh <[email protected]>
> >
> > This patch series is a continuation of the KRSI RFC
> > (https://lore.kernel.org/bpf/[email protected]/)
> >
>
> [...]
>
> > # Usage Examples
> >
> > A simple example and some documentation is included in the patchset.
> >
> > In order to better illustrate the capabilities of the framework some
> > more advanced prototype code has also been published separately:
> >
> > * Logging execution events (including environment variables and arguments):
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> > * Detecting deletion of running executables:
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> > * Detection of writes to /proc/<pid>/mem:
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
>
> Are you planning on submitting these examples for inclusion into
> samples/bpf or selftests/bpf? It would be great to have more examples
> and we can review and suggest nicer ways to go about writing them
> (e.g., BPF skeleton and global data Alexei mentioned earlier).

Eventually, yes and in selftest/bpf.

But these examples depend on using security blobs and some non-atomic
calls in the BPF helpers which are not handled as a part of the
initial patch-set.

Once we have the initial framework finalized, I will update the
examples and the helpers they are based on and send these separate
patch-sets on the list for review.

- KP

>
> >
> > We have updated Google's internal telemetry infrastructure and have
> > started deploying this LSM on our Linux Workstations. This gives us more
> > confidence in the real-world applications of such a system.
> >
> > KP Singh (13):
> > bpf: Refactor BPF_EVENT context macros to its own header.
> > bpf: lsm: Add a skeleton and config options
> > bpf: lsm: Introduce types for eBPF based LSM
> > bpf: lsm: Allow btf_id based attachment for LSM hooks
> > tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
> > bpf: lsm: Init Hooks and create files in securityfs
> > bpf: lsm: Implement attach, detach and execution.
> > bpf: lsm: Show attached program names in hook read handler.
> > bpf: lsm: Add a helper function bpf_lsm_event_output
> > bpf: lsm: Handle attachment of the same program
> > tools/libbpf: Add bpf_program__attach_lsm
> > bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
> > bpf: lsm: Add Documentation
> >
>
> [...]

2019-12-30 15:38:10

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

On 23-Dec 22:28, Andrii Nakryiko wrote:
> On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
> >
> > From: KP Singh <[email protected]>
> >
> > The LSM creates files in securityfs for each hook registered with the
> > LSM.
> >
> > /sys/kernel/security/bpf/<h_name>
> >
> > The list of LSM hooks are maintained in an internal header "hooks.h"
> > Eventually, this list should either be defined collectively in
> > include/linux/lsm_hooks.h or auto-generated from it.
> >
> > * Creation of a file for the hook in the securityfs.
> > * Allocation of a bpf_lsm_hook data structure which stores
> > a pointer to the dentry of the newly created file in securityfs.
> > * Creation of a typedef for the hook so that BTF information
> > can be generated for the LSM hooks to:
> >
> > - Make them "Compile Once, Run Everywhere".
> > - Pass the right arguments when the attached programs are run.
> > - Verify the accesses made by the program by using the BTF
> > information.
> >
> > Signed-off-by: KP Singh <[email protected]>
> > ---
> > include/linux/bpf_lsm.h | 12 +
> > security/bpf/Makefile | 4 +-
> > security/bpf/include/bpf_lsm.h | 63 ++
> > security/bpf/include/fs.h | 23 +
> > security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
> > security/bpf/lsm.c | 138 ++++-
> > security/bpf/lsm_fs.c | 82 +++
> > 7 files changed, 1333 insertions(+), 4 deletions(-)
> > create mode 100644 include/linux/bpf_lsm.h
> > create mode 100644 security/bpf/include/bpf_lsm.h
> > create mode 100644 security/bpf/include/fs.h
> > create mode 100644 security/bpf/include/hooks.h
> > create mode 100644 security/bpf/lsm_fs.c
> >
>
> [...]
>
> > +
> > +/*
> > + * The hooks can have an int or void return type, these macros allow having a
> > + * single implementation of DEFINE_LSM_HOOK irrespective of the return type.
> > + */
> > +#define LSM_HOOK_RET(ret, x) LSM_HOOK_RET_##ret(x)
> > +#define LSM_HOOK_RET_int(x) x
> > +#define LSM_HOOK_RET_void(x)
> > +
> > +/*
> > + * This macro defines the body of a LSM hook which runs the eBPF programs that
> > + * are attached to the hook and returns the error code from the eBPF programs if
> > + * the return type of the hook is int.
> > + */
> > +#define DEFINE_LSM_HOOK(hook, ret, proto, args) \
> > +typedef ret (*lsm_btf_##hook)(proto); \
> > +static ret bpf_lsm_##hook(proto) \
> > +{ \
> > + return LSM_HOOK_RET(ret, LSM_RUN_PROGS(hook##_type, args)); \
> > }
>
> I'm probably missing something, but according to LSM_HOOK_RET
> definition for when ret==void, bpf_lsm_##hook will be a noop and won't
> call any BPF program. Did I miss some additional macro magic?
>

Good catch! You're right. These macros will not be there in v2 as
we move to using trampolines based callbacks.

> >
> > +/*
> > + * Define the body of each of the LSM hooks defined in hooks.h.
> > + */
> > +#define BPF_LSM_HOOK(hook, ret, args, proto) \
> > + DEFINE_LSM_HOOK(hook, ret, BPF_LSM_ARGS(args), BPF_LSM_ARGS(proto))
> > +#include "hooks.h"
> > +#undef BPF_LSM_HOOK
> > +#undef DEFINE_LSM_HOOK
> > +
> > +/*
> > + * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
> > + * The list contains information for each of the hook and can be indexed by the
> > + * its type to initialize security FS, attach, detach and execute eBPF programs
> > + * for the hook.
> > + */
> > +struct bpf_lsm_hook bpf_lsm_hooks_list[] = {
> > + #define BPF_LSM_HOOK(h, ...) \
> > + [h##_type] = { \
> > + .h_type = h##_type, \
> > + .mutex = __MUTEX_INITIALIZER( \
> > + bpf_lsm_hooks_list[h##_type].mutex), \
> > + .name = #h, \
> > + .btf_hook_func = \
> > + (void *)(lsm_btf_##h)(bpf_lsm_##h), \
>
> this btf_hook_func, is it assigned just so that type information for
> bpf_lsm_xxx typedefs are preserved, is that right? It doesn't seem to
> be ever called or read. If I'm not missing anything, check out
> Martin's latest STRUCT_OPS patch set. He defines EMIT_TYPE_INFO(type)
> macro, which will ensure that BTF for specified type is emitted into
> vmlinux BTF, without actually using any extra space, defining extra
> fields or static variables, etc. I suggest using the same for the
> cleanest result.
>
> One more thing regarding lsm_bpf_ typedefs. Currently you are defining
> them as a pointer to func_proto, matching LSM hook. There is an
> alternative approach, which has few benefits over using func_proto. If
> instead you define a struct, where each argument of func prototype is
> represented as 8-byte aligned field, this will contain all the
> necessary information for BPF verifier to do its job (just like
> func_proto). But in addition to that, when vmlinux.h is generated, it
> will contain a nice struct bpf_lsm_<hook_name> with correct structure
> to be used **directly** in BPF program, as a single context argument.
> So with vmlinux.h, users won't have to re-define all the argument
> types and names in their BPF_TRACE_x definition. Let me provide
> concrete example from your cover letter. This is what you provide as
> an example:

Is this also doable for the new approach suggsted by Alexei
and prototyped in?

https://lore.kernel.org/bpf/CAEf4BzYiUZtSJKh-UBL0jwyo6d=Cne2YtEyGU8ONykmSUSsuNA@mail.gmail.com/T/#m7c7ec0e7d8e803c6c357495d9eea59028a67cac6

which uses trampolines. The new approach gets rid of any type
generation and macros in security/bpf/lsm_hooks.h. Maybe the
btf_vmlinux can be augmented at runtime to generate context struct
upon attachment?

>
> BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> struct vm_area_struct *, vma,
> unsigned long, reqprot, unsigned long, prot) {...}
>
> on kernel side, you'll have:
>
> typedef int (*bpf_lsm_file_mprotect)(struct vm_area_struct *vma,
> unsigned long reqprot,
> unsigned long prot);
>
> So you can see that user has to go and copy/paste all the arguments
> and their types and paste them in this verbose BPF_TRACE_3 macro to
> define correct BPF program.
>
> Now, imagine that instead of typedef above, we define equivalent struct:
>
> struct bpf_lsm_file_mprotect {
> struct vm_area_struct *vma;
> unsigned long reqprot;
> unsigned long prot;
> };
>
> This type will get dumped into vmlinux.h, which can be used from BPF
> user code as such:
>
> SEC("lsm/file_mprotect")
> int mprotect_audito(struct bpf_lsm_file_mprotect *ctx)
> {
> ... here you can use ctx->vma, ctx->reqprot, ctx->prot ...
> }
>
>
> Meanwhile, there will be just minimal changes to BPF verifier to use
> such struct instead of func_proto for verification of LSM programs.
>
> We currently have similar issue with raw_tp programs and I've been
> thinking about switching that to structs instead of func_proto, so we
> might as well coordinate that and reuse the same logic in BPF
> verifier.
>
> Thoughts?

Thanks for the explanation!

Using structs is definitely better if we chose to go with static type
generation.

- KP

>
>
>
> > + },
> > + #include "hooks.h"
> > + #undef BPF_LSM_HOOK
> > +};
> > +
>
> [...]

2019-12-30 18:54:58

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

On Mon, Dec 30, 2019 at 7:37 AM KP Singh <[email protected]> wrote:
>
> On 23-Dec 22:28, Andrii Nakryiko wrote:
> > On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
> > >
> > > From: KP Singh <[email protected]>
> > >
> > > The LSM creates files in securityfs for each hook registered with the
> > > LSM.
> > >
> > > /sys/kernel/security/bpf/<h_name>
> > >
> > > The list of LSM hooks are maintained in an internal header "hooks.h"
> > > Eventually, this list should either be defined collectively in
> > > include/linux/lsm_hooks.h or auto-generated from it.
> > >
> > > * Creation of a file for the hook in the securityfs.
> > > * Allocation of a bpf_lsm_hook data structure which stores
> > > a pointer to the dentry of the newly created file in securityfs.
> > > * Creation of a typedef for the hook so that BTF information
> > > can be generated for the LSM hooks to:
> > >
> > > - Make them "Compile Once, Run Everywhere".
> > > - Pass the right arguments when the attached programs are run.
> > > - Verify the accesses made by the program by using the BTF
> > > information.
> > >
> > > Signed-off-by: KP Singh <[email protected]>
> > > ---
> > > include/linux/bpf_lsm.h | 12 +
> > > security/bpf/Makefile | 4 +-
> > > security/bpf/include/bpf_lsm.h | 63 ++
> > > security/bpf/include/fs.h | 23 +
> > > security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
> > > security/bpf/lsm.c | 138 ++++-
> > > security/bpf/lsm_fs.c | 82 +++
> > > 7 files changed, 1333 insertions(+), 4 deletions(-)
> > > create mode 100644 include/linux/bpf_lsm.h
> > > create mode 100644 security/bpf/include/bpf_lsm.h
> > > create mode 100644 security/bpf/include/fs.h
> > > create mode 100644 security/bpf/include/hooks.h
> > > create mode 100644 security/bpf/lsm_fs.c
> > >
> >
> > [...]
> >
> > > +
> > > +/*
> > > + * The hooks can have an int or void return type, these macros allow having a
> > > + * single implementation of DEFINE_LSM_HOOK irrespective of the return type.
> > > + */
> > > +#define LSM_HOOK_RET(ret, x) LSM_HOOK_RET_##ret(x)
> > > +#define LSM_HOOK_RET_int(x) x
> > > +#define LSM_HOOK_RET_void(x)
> > > +
> > > +/*
> > > + * This macro defines the body of a LSM hook which runs the eBPF programs that
> > > + * are attached to the hook and returns the error code from the eBPF programs if
> > > + * the return type of the hook is int.
> > > + */
> > > +#define DEFINE_LSM_HOOK(hook, ret, proto, args) \
> > > +typedef ret (*lsm_btf_##hook)(proto); \
> > > +static ret bpf_lsm_##hook(proto) \
> > > +{ \
> > > + return LSM_HOOK_RET(ret, LSM_RUN_PROGS(hook##_type, args)); \
> > > }
> >
> > I'm probably missing something, but according to LSM_HOOK_RET
> > definition for when ret==void, bpf_lsm_##hook will be a noop and won't
> > call any BPF program. Did I miss some additional macro magic?
> >
>
> Good catch! You're right. These macros will not be there in v2 as
> we move to using trampolines based callbacks.

Cool, no worries.

>
> > >
> > > +/*
> > > + * Define the body of each of the LSM hooks defined in hooks.h.
> > > + */
> > > +#define BPF_LSM_HOOK(hook, ret, args, proto) \
> > > + DEFINE_LSM_HOOK(hook, ret, BPF_LSM_ARGS(args), BPF_LSM_ARGS(proto))
> > > +#include "hooks.h"
> > > +#undef BPF_LSM_HOOK
> > > +#undef DEFINE_LSM_HOOK
> > > +
> > > +/*
> > > + * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
> > > + * The list contains information for each of the hook and can be indexed by the
> > > + * its type to initialize security FS, attach, detach and execute eBPF programs
> > > + * for the hook.
> > > + */
> > > +struct bpf_lsm_hook bpf_lsm_hooks_list[] = {
> > > + #define BPF_LSM_HOOK(h, ...) \
> > > + [h##_type] = { \
> > > + .h_type = h##_type, \
> > > + .mutex = __MUTEX_INITIALIZER( \
> > > + bpf_lsm_hooks_list[h##_type].mutex), \
> > > + .name = #h, \
> > > + .btf_hook_func = \
> > > + (void *)(lsm_btf_##h)(bpf_lsm_##h), \
> >
> > this btf_hook_func, is it assigned just so that type information for
> > bpf_lsm_xxx typedefs are preserved, is that right? It doesn't seem to
> > be ever called or read. If I'm not missing anything, check out
> > Martin's latest STRUCT_OPS patch set. He defines EMIT_TYPE_INFO(type)
> > macro, which will ensure that BTF for specified type is emitted into
> > vmlinux BTF, without actually using any extra space, defining extra
> > fields or static variables, etc. I suggest using the same for the
> > cleanest result.
> >
> > One more thing regarding lsm_bpf_ typedefs. Currently you are defining
> > them as a pointer to func_proto, matching LSM hook. There is an
> > alternative approach, which has few benefits over using func_proto. If
> > instead you define a struct, where each argument of func prototype is
> > represented as 8-byte aligned field, this will contain all the
> > necessary information for BPF verifier to do its job (just like
> > func_proto). But in addition to that, when vmlinux.h is generated, it
> > will contain a nice struct bpf_lsm_<hook_name> with correct structure
> > to be used **directly** in BPF program, as a single context argument.
> > So with vmlinux.h, users won't have to re-define all the argument
> > types and names in their BPF_TRACE_x definition. Let me provide
> > concrete example from your cover letter. This is what you provide as
> > an example:
>
> Is this also doable for the new approach suggsted by Alexei
> and prototyped in?
>
> https://lore.kernel.org/bpf/CAEf4BzYiUZtSJKh-UBL0jwyo6d=Cne2YtEyGU8ONykmSUSsuNA@mail.gmail.com/T/#m7c7ec0e7d8e803c6c357495d9eea59028a67cac6
>
> which uses trampolines. The new approach gets rid of any type
> generation and macros in security/bpf/lsm_hooks.h. Maybe the
> btf_vmlinux can be augmented at runtime to generate context struct
> upon attachment?

If it doesn't generate "controllable" types (and seems like existing
types are not readily usable as well), then we can't use vmlinux's BTF
as is. But we can augment vmlinux.h header during generation time,
based on naming convention and extra post-processing of vmlinux BTF.
That's sort of a point of special `format core` mode in bpftool, which
we currently discuss on mailing list as well, see [0].

[0] https://lore.kernel.org/bpf/CAEf4BzY4ffWaeFckPuqNGNAU1uBG3TmTK+CjY1LVa2G+RGz=cA@mail.gmail.com/T/#u


>
> >
> > BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> > struct vm_area_struct *, vma,
> > unsigned long, reqprot, unsigned long, prot) {...}
> >
> > on kernel side, you'll have:
> >
> > typedef int (*bpf_lsm_file_mprotect)(struct vm_area_struct *vma,
> > unsigned long reqprot,
> > unsigned long prot);
> >
> > So you can see that user has to go and copy/paste all the arguments
> > and their types and paste them in this verbose BPF_TRACE_3 macro to
> > define correct BPF program.
> >
> > Now, imagine that instead of typedef above, we define equivalent struct:
> >
> > struct bpf_lsm_file_mprotect {
> > struct vm_area_struct *vma;
> > unsigned long reqprot;
> > unsigned long prot;
> > };
> >
> > This type will get dumped into vmlinux.h, which can be used from BPF
> > user code as such:
> >
> > SEC("lsm/file_mprotect")
> > int mprotect_audito(struct bpf_lsm_file_mprotect *ctx)
> > {
> > ... here you can use ctx->vma, ctx->reqprot, ctx->prot ...
> > }
> >
> >
> > Meanwhile, there will be just minimal changes to BPF verifier to use
> > such struct instead of func_proto for verification of LSM programs.
> >
> > We currently have similar issue with raw_tp programs and I've been
> > thinking about switching that to structs instead of func_proto, so we
> > might as well coordinate that and reuse the same logic in BPF
> > verifier.
> >
> > Thoughts?
>
> Thanks for the explanation!
>
> Using structs is definitely better if we chose to go with static type
> generation.
>

Yes, that's what I think is preferable for tp_btf programs as well.

> - KP
>
> >
> >
> >
> > > + },
> > > + #include "hooks.h"
> > > + #undef BPF_LSM_HOOK
> > > +};
> > > +
> >
> > [...]

2019-12-30 19:00:41

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Mon, Dec 30, 2019 at 7:04 AM KP Singh <[email protected]> wrote:
>
> On 23-Dec 22:51, Andrii Nakryiko wrote:
> > On Fri, Dec 20, 2019 at 7:42 AM KP Singh <[email protected]> wrote:
> > >
> > > From: KP Singh <[email protected]>
> > >
> > > This patch series is a continuation of the KRSI RFC
> > > (https://lore.kernel.org/bpf/[email protected]/)
> > >
> >
> > [...]
> >
> > > # Usage Examples
> > >
> > > A simple example and some documentation is included in the patchset.
> > >
> > > In order to better illustrate the capabilities of the framework some
> > > more advanced prototype code has also been published separately:
> > >
> > > * Logging execution events (including environment variables and arguments):
> > > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> > > * Detecting deletion of running executables:
> > > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
> > > * Detection of writes to /proc/<pid>/mem:
> > > https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
> >
> > Are you planning on submitting these examples for inclusion into
> > samples/bpf or selftests/bpf? It would be great to have more examples
> > and we can review and suggest nicer ways to go about writing them
> > (e.g., BPF skeleton and global data Alexei mentioned earlier).
>
> Eventually, yes and in selftest/bpf.
>
> But these examples depend on using security blobs and some non-atomic
> calls in the BPF helpers which are not handled as a part of the
> initial patch-set.
>
> Once we have the initial framework finalized, I will update the
> examples and the helpers they are based on and send these separate
> patch-sets on the list for review.

Great! The reason I was asking is that once they are in selftests, it
would be nice to switch them to use all the latest BPF usability
improvements to make code cleaner and have it as another good example
of modern BPF program. Like use BTF-defined maps, BPF skeleton,
vmlinux.h, etc. We can go over this when the time comes, though :)


>
> - KP
>
> >
> > >
> > > We have updated Google's internal telemetry infrastructure and have
> > > started deploying this LSM on our Linux Workstations. This gives us more
> > > confidence in the real-world applications of such a system.
> > >
> > > KP Singh (13):
> > > bpf: Refactor BPF_EVENT context macros to its own header.
> > > bpf: lsm: Add a skeleton and config options
> > > bpf: lsm: Introduce types for eBPF based LSM
> > > bpf: lsm: Allow btf_id based attachment for LSM hooks
> > > tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
> > > bpf: lsm: Init Hooks and create files in securityfs
> > > bpf: lsm: Implement attach, detach and execution.
> > > bpf: lsm: Show attached program names in hook read handler.
> > > bpf: lsm: Add a helper function bpf_lsm_event_output
> > > bpf: lsm: Handle attachment of the same program
> > > tools/libbpf: Add bpf_program__attach_lsm
> > > bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
> > > bpf: lsm: Add Documentation
> > >
> >
> > [...]

2019-12-30 19:15:33

by Andrii Nakryiko

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Mon, Dec 30, 2019 at 6:59 AM KP Singh <[email protected]> wrote:
>
> On 21-Dez 17:27, Alexei Starovoitov wrote:
> > On Fri, Dec 20, 2019 at 04:41:55PM +0100, KP Singh wrote:
> > > // Declare the eBPF program mprotect_audit which attaches to
> > > // to the file_mprotect LSM hook and accepts three arguments.
> > > BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
> > > struct vm_area_struct *, vma,
> > > unsigned long, reqprot, unsigned long, prot
> > > {
> > > unsigned long vm_start = _(vma->vm_start);
> > > return 0;
> > > }
> >
>
> Hi Alexei,
>
> Thanks for the feedback. This is really helpful!
>
> > I think the only sore point of the patchset is:
> > security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
> > With bpf trampoline this type of 'kernel types -> bpf types' converters
> > are no longer necessary. Please take a look at tcp-congestion-control patchset:
> > https://patchwork.ozlabs.org/cover/1214417/
> > Instead of doing similar thing (like your patch 1 plus patch 6) it's using
> > trampoline to provide bpf based congestion control callbacks into tcp stack.
> > The same trampoline-based mechanism can be reused by bpf_lsm.
> > Then all manual work of doing BPF_LSM_HOOK(...) for every hook won't be
> > necessary. It will also prove the point that attaching BPF to raw LSM hooks
> > doesn't freeze them into stable abi.
>
> Really cool!
>
> I looked into how BPF trampolines are being used in tracing and the
> new STRUCT_OPS patchset and was able protoype
> (https://github.com/sinkap/linux-krsi/tree/patch/v1/trampoline_prototype,
> not ready for review yet) which:
>
> * Gets rid of security/bpf/include/hooks.h and all of the static
> macro magic essentially making the LSM ~truly instrumentable~ at
> runtime.
> * Gets rid of the generation of any new types as we already have
> all the BTF information in the kernel in the following two types:
>
> struct security_hook_heads {
> .
> .
> struct hlist_head file_mprotect; <- Append the callback at this offset
> .
> .
> };
>
> and
>
> union security_list_options {
> int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot,
> unsigned long prot);
> };
>
> Which is the same type as the typedef that's currently being generated
> , i.e. lsm_btf_file_mprotect
>
> In the current prototype, libbpf converts the name of the hook into an
> offset into the security_hook_heads and the verifier does the
> following when a program is loaded:
>
> * Verifies the offset and the type at the offset (struct hlist_head).
> * Resolves the func_proto (by looking up the type in
> security_list_options) and updates prog->aux with the name and
> func_proto which are then verified similar to raw_tp programs with
> btf_ctx_access.
>
> On attachment:
>
> * A trampoline is created and appended to the security_hook_heads
> for the BPF LSM.
> * An anonymous FD is returned and the attachment is conditional on the
> references to FD (as suggested and similar to fentry/fexit tracing
> programs).
>
> This implies that the BPF programs are "the LSM hook" as opposed to
> being executed inside a statically defined hook body which requires
> mutable LSM hooks for which I was able to re-use some of ideas in
> Sargun's patch:
>
> https://lore.kernel.org/lkml/[email protected]/
>
> to maintain a separate security_hook_heads struct for dynamically
> added LSM hooks by the BPF LSM which are executed after all the
> statically defined hooks.
>
> > Longer program names are supplied via btf's func_info.
> > It feels that:
> > cat /sys/kernel/security/bpf/process_execution
> > env_dumper__v2
> > is reinventing the wheel. bpftool is the main introspection tool.
> > It can print progs attached to perf, cgroup, networking. I think it's better to
> > stay consistent and do the same with bpf-lsm.
>
> I agree, based on the new feedback, I don't think we need securityFS
> attachment points anymore. I was able to get rid of it completely.
>
> >
> > Another issue is in proposed attaching method:
> > hook_fd = open("/sys/kernel/security/bpf/process_execution");
> > sys_bpf(attach, prog_fd, hook_fd);
> > With bpf tracing we moved to FD-based attaching, because permanent attaching is
> > problematic in production. We're going to provide FD-based api to attach to
> > networking as well, because xdp/tc/cgroup prog attaching suffers from the same
> > production issues. Mainly with permanent attaching there is no ownership of
> > attachment. Everything is global and permanent. It's not clear what
> > process/script suppose to detach/cleanup. I suggest bpf-lsm use FD-based
> > attaching from the beginning. Take a look at raw_tp/tp_btf/fentry/fexit style
> > of attaching. All of them return FD which represents what libbpf calls
> > 'bpf_link' concept. Once refcnt of that FD goes to zero that link (attachment)
> > is destroyed and program is detached _by the kernel_. To make such links
> > permanent the application can pin them in bpffs. The pinning patches haven't
> > landed yet, but the concept of the link is quite powerful and much more
> > production friendly than permanent attaching.
>
> I like this. This also means we don't immediately need the handling of
> duplicate names so I dropped that bit of the patch as well and updated
> the attachment to use this mechanism.
>
> > bpf-lsm will still be able to attach multiple progs to the same hook and
> > see what is attached via bpftool.
> >
> > The rest looks good. Thank you for working on it.
>
> There are some choices we need to make here from an API perspective:
>
> * Should we "repurpose" attr->attach_btf_id and use it as an offset
> into security_hook_heads or add a new attribute
> (e.g lsm_hook_offset) for the offset or use name of the LSM hook
> (e.g. lsm_hook_name).

I think setting this to member index inside union
security_list_options will be better? Or member index inside struct
security_hook_heads. Seems like kernel will have to "join" those two
anyways, right (one for type info, another for trampoline)? Offset is
less convenient either way.

> * Since we don't have the files in securityFS, the attachment does not
> have a target_fd. Should we add a new type of BPF command?
> e.g. LSM_HOOK_OPEN?

Semantics of LSM program seems closer to fentry/fexit/raw_tp, so maybe
instead use BPF_RAW_TRACEPOINT_OPEN command? On libbpf side it's all
going to be abstracted behind bpf_program__attach() anyways.

>
> I will clean up the prototype, incorporate some of the other feedback
> received, and send a v2.
>
> Wishing everyone a very Happy New Year!

Thanks, you too!

>
> - KP
>

2019-12-30 19:17:31

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, Dec 20, 2019 at 06:38:45PM +0100, KP Singh wrote:
> Hi Casey,
>
> Thanks for taking a look!
>
> On Fri, Dec 20, 2019 at 6:17 PM Casey Schaufler <[email protected]> wrote:
> >
> > On 12/20/2019 7:41 AM, KP Singh wrote:
> > > From: KP Singh <[email protected]>
> > >
> > > This patch series is a continuation of the KRSI RFC
> > > (https://lore.kernel.org/bpf/[email protected]/)
> > >
> > > # Motivation
> > >
> > > Google does rich analysis of runtime security data collected from
> > > internal Linux deployments (corporate devices and servers) to detect and
> > > thwart threats in real-time. Currently, this is done in custom kernel
> > > modules but we would like to replace this with something that's upstream
> > > and useful to others.
> > >
> > > The current kernel infrastructure for providing telemetry (Audit, Perf
> > > etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
> > > information provided by audit requires kernel changes to audit, its
> > > policy language and user-space components. Furthermore, building a MAC
> > > policy based on the newly added telemetry data requires changes to
> > > various LSMs and their respective policy languages.
> > >
> > > This patchset proposes a new stackable and privileged LSM which allows
> > > the LSM hooks to be implemented using eBPF. This facilitates a unified
> > > and dynamic (not requiring re-compilation of the kernel) audit and MAC
> > > policy.
> > >
> > > # Why an LSM?
> > >
> > > Linux Security Modules target security behaviours rather than the
> > > kernel's API. For example, it's easy to miss out a newly added system
> > > call for executing processes (eg. execve, execveat etc.) but the LSM
> > > framework ensures that all process executions trigger the relevant hooks
> > > irrespective of how the process was executed.
> > >
> > > Allowing users to implement LSM hooks at runtime also benefits the LSM
> > > eco-system by enabling a quick feedback loop from the security community
> > > about the kind of behaviours that the LSM Framework should be targeting.
> > >
> > > # How does it work?
> > >
> > > The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
> > > program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
> > > hook. All LSM hooks are exposed as files in securityfs. Attachment
> > > requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
> > > modifying MAC policies.
> > >
> > > The eBPF programs are passed the same arguments as the LSM hooks and
> > > executed in the body of the hook.
> >
> > This effectively exposes the LSM hooks as external APIs.
> > It would mean that we can't change or delete them. That
> > would be bad.
>
> Perhaps this should have been clearer, we *do not* want to make LSM hooks
> a stable API and expect the eBPF programs to adapt when such changes occur.
>
> Based on our comparison with the previous approach, this still ends up
> being a better trade-off (w.r.t. maintenance) when compared to adding
> specific helpers or verifier logic for each new hook or field that
> needs to be exposed.

Given the discussion around tracing and stable ABI at the last kernel
summit, Linus's mandate is mainly around "every day users" and not
around these system-builder-sensitive cases where everyone has a strong
expectation to rebuild their policy when the kernel changes. i.e. it's
not "powertop", which was Linus's example of "and then everyone running
Fedora breaks".

So, while I know we've tried in the past to follow the letter of the
law, it seems Linus really expects this only to be followed when it will
have "real world" impact on unsuspecting end users.

Obviously James Morris has the final say here, but as I understand it,
it is fine to expose these here for the same reasons it's fine to expose
the (ever changing) tracepoints and BPF hooks.

-Kees

--
Kees Cook

2019-12-30 19:21:34

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

On Mon, Dec 30, 2019 at 04:37:11PM +0100, KP Singh wrote:
> On 23-Dec 22:28, Andrii Nakryiko wrote:
> > On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
> > [...]
>
> Good catch! You're right. These macros will not be there in v2 as
> we move to using trampolines based callbacks.

Speaking of which -- is the BPF trampoline code correctly designed to be
W^X?

--
Kees Cook

2019-12-30 19:31:11

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, Dec 20, 2019 at 11:46:47PM +0100, Micka?l Sala?n wrote:
> I'm working on a version of Landlock without eBPF, but still with the
> initial sought properties: safe unprivileged composability, modularity, and
> dynamic update. I'll send this version soon.
>
> I hope that the work and experience from Landlock to bring eBPF to LSM will
> continue to be used through KRSI. Landlock will now focus on the
> unprivileged sandboxing part, without eBPF. Stay tuned!

Will it end up looking at all like pledge? I'm still struggling to come
up with a sensible pledge-like design on top of seccomp, especially
given the need to have it very closely tied to the running libc...

--
Kees Cook

2019-12-31 12:14:16

by Mickaël Salaün

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)


On 30/12/2019 20:30, Kees Cook wrote:
> On Fri, Dec 20, 2019 at 11:46:47PM +0100, Micka?l Sala?n wrote:
>> I'm working on a version of Landlock without eBPF, but still with the
>> initial sought properties: safe unprivileged composability, modularity, and
>> dynamic update. I'll send this version soon.
>>
>> I hope that the work and experience from Landlock to bring eBPF to LSM will
>> continue to be used through KRSI. Landlock will now focus on the
>> unprivileged sandboxing part, without eBPF. Stay tuned!
>
> Will it end up looking at all like pledge? I'm still struggling to come
> up with a sensible pledge-like design on top of seccomp, especially
> given the need to have it very closely tied to the running libc...
>

Yes, it's similar to Pledge/Unveil but with fine-grained control (and a
more flexible design). And because it is not tied to syscall, there is
no similar issues than with seccomp and libc. In fact, there is no more
relationship with seccomp neither. The version I'm working on is similar
in principle to the patch series v10 [1], without the usage complexity
brought by eBPF, but with a more polished file-based access-control. The
demo from LSS 2018 [2] gives an overview of the possibilities.

[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://landlock.io/talks/2018-08-27_landlock-lss_demo-1-web.mkv

2020-01-03 23:53:55

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

On 30-Dez 11:20, Kees Cook wrote:
> On Mon, Dec 30, 2019 at 04:37:11PM +0100, KP Singh wrote:
> > On 23-Dec 22:28, Andrii Nakryiko wrote:
> > > On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
> > > [...]
> >
> > Good catch! You're right. These macros will not be there in v2 as
> > we move to using trampolines based callbacks.
>
> Speaking of which -- is the BPF trampoline code correctly designed to be
> W^X?

Thanks for pointing this out!

I don't think this is the case as of now.

The dispatcher logic and the tracing programs allocate one page where
one half of it is used for the active trampoline and the other half is
used as a staging area for a future replacement. I sent a patch as an
attempt to fix this:

https://lore.kernel.org/bpf/[email protected]/T/#u

- KP

>
> --
> Kees Cook

2020-01-04 00:01:34

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM

On 23-Dez 16:07, Andrii Nakryiko wrote:
> On Fri, Dec 20, 2019 at 7:43 AM KP Singh <[email protected]> wrote:
> >
> > From: KP Singh <[email protected]>
> >
> > Update the libbpf library with functionality to load and
> > attach a program type BPF_PROG_TYPE_LSM, currently with
> > only one expected attach type BPF_LSM_MAC.
> >
> > Signed-off-by: KP Singh <[email protected]>
> > ---
> > tools/lib/bpf/bpf.c | 2 +-
> > tools/lib/bpf/bpf.h | 6 +++++
> > tools/lib/bpf/libbpf.c | 44 +++++++++++++++++++++--------------
> > tools/lib/bpf/libbpf.h | 2 ++
> > tools/lib/bpf/libbpf.map | 6 +++++
> > tools/lib/bpf/libbpf_probes.c | 1 +
> > 6 files changed, 43 insertions(+), 18 deletions(-)
> >
> > diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> > index 98596e15390f..9c6fb083f7de 100644
> > --- a/tools/lib/bpf/bpf.c
> > +++ b/tools/lib/bpf/bpf.c
> > @@ -228,7 +228,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
> > memset(&attr, 0, sizeof(attr));
> > attr.prog_type = load_attr->prog_type;
> > attr.expected_attach_type = load_attr->expected_attach_type;
> > - if (attr.prog_type == BPF_PROG_TYPE_TRACING) {
> > + if (needs_btf_attach(attr.prog_type)) {
> > attr.attach_btf_id = load_attr->attach_btf_id;
> > attr.attach_prog_fd = load_attr->attach_prog_fd;
> > } else {
> > diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> > index 3c791fa8e68e..df2a00ff349f 100644
> > --- a/tools/lib/bpf/bpf.h
> > +++ b/tools/lib/bpf/bpf.h
> > @@ -177,6 +177,12 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
> > __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
> > __u64 *probe_offset, __u64 *probe_addr);
> >
> > +static inline bool needs_btf_attach(enum bpf_prog_type prog_type)
> > +{
> > + return (prog_type == BPF_PROG_TYPE_TRACING ||
> > + prog_type == BPF_PROG_TYPE_LSM);
> > +}
> > +
>
> This doesn't have to be a public API, right? It also doesn't follow
> naming conventions of libbpf APIs. Let's just move it into
> libbpf_internal.h, given it's used in few files.
>
> Also, Martin's patches add STRUCT_OPS, which do need btf_attach, but
> don't set attach_prog_fd. So maybe something like
> libbpf_need_attach_prog_btf() for a name to be a bit more specific?

Updated for the next revision. Thanks!

>
>
> > #ifdef __cplusplus
> > } /* extern "C" */
> > #endif
> > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > index b20f82e58989..b0b27d8e5a37 100644
> > --- a/tools/lib/bpf/libbpf.c
> > +++ b/tools/lib/bpf/libbpf.c
> > @@ -3738,7 +3738,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
> > load_attr.insns = insns;
> > load_attr.insns_cnt = insns_cnt;
> > load_attr.license = license;
> > - if (prog->type == BPF_PROG_TYPE_TRACING) {
> > + if (needs_btf_attach(prog->type)) {
> > load_attr.attach_prog_fd = prog->attach_prog_fd;
> > load_attr.attach_btf_id = prog->attach_btf_id;
> > } else {
> > @@ -3983,7 +3983,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
> >
> > bpf_program__set_type(prog, prog_type);
> > bpf_program__set_expected_attach_type(prog, attach_type);
> > - if (prog_type == BPF_PROG_TYPE_TRACING) {
> > + if (needs_btf_attach(prog_type)) {
> > err = libbpf_find_attach_btf_id(prog->section_name,
> > attach_type,
> > attach_prog_fd);
> > @@ -4933,6 +4933,7 @@ bool bpf_program__is_##NAME(const struct bpf_program *prog) \
> > } \
> >
> > BPF_PROG_TYPE_FNS(socket_filter, BPF_PROG_TYPE_SOCKET_FILTER);
> > +BPF_PROG_TYPE_FNS(lsm, BPF_PROG_TYPE_LSM);
> > BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);
> > BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);
> > BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);
> > @@ -5009,6 +5010,8 @@ static const struct {
> > BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
> > BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
> > BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
> > + BPF_PROG_BTF("lsm/", BPF_PROG_TYPE_LSM,
> > + BPF_LSM_MAC),
>
> Is is supposed to be attachable same as BPF_PROG_TYPE_TRACING
> programs? If yes, please define auto-attaching function, similar to
> SEC_DEF("raw_tp") few lines below this one.

Nice! rebased and updated.

>
> > BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB,
> > BPF_CGROUP_INET_INGRESS),
> > BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB,
> > @@ -5119,32 +5122,39 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
> > return -ESRCH;
> > }
> >
> > -#define BTF_PREFIX "btf_trace_"
> > +static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name,
>
> typo: typdef -> typedef
>
> But actually let's generalize it to pass BTF_KIND as another param, I
> think I have a need for this (we might want to do that for structs,
> not just typedef->func_proto).
> Following btf__find_by_name_kind() naming, it probably should be
> called btf__find_by_prefix_kind()?

Thanks! Good idea, updated. Should this be moved to btf.c?

>
> > + const char *prefix)
> > +{
> > +
> > + size_t prefix_len = strlen(prefix);
> > + char btf_type_name[128];
> > +
> > + strcpy(btf_type_name, prefix);
> > + strncat(btf_type_name, name, sizeof(btf_type_name) - (prefix_len + 1));
>
> at this point snprintf(btf_type_name, "%s%.*%s", prefix,
> sizeof(btf_type_name) - prefix_len - 1, name) looks like a better and
> cleaner alternative.

I just changed it to:

snprintf(btf_type_name, sizeof(btf_type_name), "%s%s", prefix, name);

- KP

>
> > + return btf__find_by_name_kind(btf, btf_type_name, BTF_KIND_TYPEDEF);
> > +}
> > +
> > +#define BTF_TRACE_PREFIX "btf_trace_"
> > +#define BTF_LSM_PREFIX "lsm_btf_"
> > +
>
> [...]

2020-01-07 21:24:13

by James Morris

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs

On Fri, 20 Dec 2019, KP Singh wrote:

> From: KP Singh <[email protected]>
>
> The LSM creates files in securityfs for each hook registered with the
> LSM.
>
> /sys/kernel/security/bpf/<h_name>
>
> The list of LSM hooks are maintained in an internal header "hooks.h"
> Eventually, this list should either be defined collectively in
> include/linux/lsm_hooks.h or auto-generated from it.
>
> * Creation of a file for the hook in the securityfs.
> * Allocation of a bpf_lsm_hook data structure which stores
> a pointer to the dentry of the newly created file in securityfs.
> * Creation of a typedef for the hook so that BTF information
> can be generated for the LSM hooks to:
>
> - Make them "Compile Once, Run Everywhere".
> - Pass the right arguments when the attached programs are run.
> - Verify the accesses made by the program by using the BTF
> information.
>
> Signed-off-by: KP Singh <[email protected]>


Reviewed-by: James Morris <[email protected]>


--
James Morris
<[email protected]>

2020-01-08 15:27:26

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 12/30/19 2:15 PM, Kees Cook wrote:
> On Fri, Dec 20, 2019 at 06:38:45PM +0100, KP Singh wrote:
>> Hi Casey,
>>
>> Thanks for taking a look!
>>
>> On Fri, Dec 20, 2019 at 6:17 PM Casey Schaufler <[email protected]> wrote:
>>>
>>> On 12/20/2019 7:41 AM, KP Singh wrote:
>>>> From: KP Singh <[email protected]>
>>>>
>>>> This patch series is a continuation of the KRSI RFC
>>>> (https://lore.kernel.org/bpf/[email protected]/)
>>>>
>>>> # Motivation
>>>>
>>>> Google does rich analysis of runtime security data collected from
>>>> internal Linux deployments (corporate devices and servers) to detect and
>>>> thwart threats in real-time. Currently, this is done in custom kernel
>>>> modules but we would like to replace this with something that's upstream
>>>> and useful to others.
>>>>
>>>> The current kernel infrastructure for providing telemetry (Audit, Perf
>>>> etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
>>>> information provided by audit requires kernel changes to audit, its
>>>> policy language and user-space components. Furthermore, building a MAC
>>>> policy based on the newly added telemetry data requires changes to
>>>> various LSMs and their respective policy languages.
>>>>
>>>> This patchset proposes a new stackable and privileged LSM which allows
>>>> the LSM hooks to be implemented using eBPF. This facilitates a unified
>>>> and dynamic (not requiring re-compilation of the kernel) audit and MAC
>>>> policy.
>>>>
>>>> # Why an LSM?
>>>>
>>>> Linux Security Modules target security behaviours rather than the
>>>> kernel's API. For example, it's easy to miss out a newly added system
>>>> call for executing processes (eg. execve, execveat etc.) but the LSM
>>>> framework ensures that all process executions trigger the relevant hooks
>>>> irrespective of how the process was executed.
>>>>
>>>> Allowing users to implement LSM hooks at runtime also benefits the LSM
>>>> eco-system by enabling a quick feedback loop from the security community
>>>> about the kind of behaviours that the LSM Framework should be targeting.
>>>>
>>>> # How does it work?
>>>>
>>>> The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
>>>> program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
>>>> hook. All LSM hooks are exposed as files in securityfs. Attachment
>>>> requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
>>>> modifying MAC policies.
>>>>
>>>> The eBPF programs are passed the same arguments as the LSM hooks and
>>>> executed in the body of the hook.
>>>
>>> This effectively exposes the LSM hooks as external APIs.
>>> It would mean that we can't change or delete them. That
>>> would be bad.
>>
>> Perhaps this should have been clearer, we *do not* want to make LSM hooks
>> a stable API and expect the eBPF programs to adapt when such changes occur.
>>
>> Based on our comparison with the previous approach, this still ends up
>> being a better trade-off (w.r.t. maintenance) when compared to adding
>> specific helpers or verifier logic for each new hook or field that
>> needs to be exposed.
>
> Given the discussion around tracing and stable ABI at the last kernel
> summit, Linus's mandate is mainly around "every day users" and not
> around these system-builder-sensitive cases where everyone has a strong
> expectation to rebuild their policy when the kernel changes. i.e. it's
> not "powertop", which was Linus's example of "and then everyone running
> Fedora breaks".
>
> So, while I know we've tried in the past to follow the letter of the
> law, it seems Linus really expects this only to be followed when it will
> have "real world" impact on unsuspecting end users.
>
> Obviously James Morris has the final say here, but as I understand it,
> it is fine to expose these here for the same reasons it's fine to expose
> the (ever changing) tracepoints and BPF hooks.

This appears to impose a very different standard to this eBPF-based LSM
than has been applied to the existing LSMs, e.g. we are required to
preserve SELinux policy compatibility all the way back to Linux 2.6.0
such that new kernel with old policy does not break userspace. If that
standard isn't being applied to the eBPF-based LSM, it seems to inhibit
its use in major Linux distros, since otherwise users will in fact start
experiencing breakage on the first such incompatible change. Not
arguing for or against, just trying to make sure I understand correctly...



2020-01-08 19:47:09

by James Morris

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Mon, 30 Dec 2019, Kees Cook wrote:

>
> Given the discussion around tracing and stable ABI at the last kernel
> summit, Linus's mandate is mainly around "every day users" and not
> around these system-builder-sensitive cases where everyone has a strong
> expectation to rebuild their policy when the kernel changes. i.e. it's
> not "powertop", which was Linus's example of "and then everyone running
> Fedora breaks".
>
> So, while I know we've tried in the past to follow the letter of the
> law, it seems Linus really expects this only to be followed when it will
> have "real world" impact on unsuspecting end users.
>
> Obviously James Morris has the final say here, but as I understand it,
> it is fine to expose these here for the same reasons it's fine to expose
> the (ever changing) tracepoints and BPF hooks.

Agreed. This API should be seen in the same light as tracing / debugging,
and it should not be exposed by users directly to general purpose
applications.


--
James Morris
<[email protected]>

2020-01-08 19:48:29

by James Morris

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Wed, 8 Jan 2020, Stephen Smalley wrote:

> This appears to impose a very different standard to this eBPF-based LSM than
> has been applied to the existing LSMs, e.g. we are required to preserve
> SELinux policy compatibility all the way back to Linux 2.6.0 such that new
> kernel with old policy does not break userspace. If that standard isn't being
> applied to the eBPF-based LSM, it seems to inhibit its use in major Linux
> distros, since otherwise users will in fact start experiencing breakage on the
> first such incompatible change. Not arguing for or against, just trying to
> make sure I understand correctly...

A different standard would be applied here vs. a standard LSM like
SELinux, which are retrofitted access control systems.

I see KRSI as being more of a debugging / analytical API, rather than an
access control system. You could of course build such a system with KRSI
but it would need to provide a layer of abstraction for general purpose
users.

So yes this would be a special case, as its real value is in being a
special case, i.e. dynamic security telemetry.


--
James Morris
<[email protected]>

2020-01-08 20:01:17

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 1/8/20 1:58 PM, James Morris wrote:
> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>
>> This appears to impose a very different standard to this eBPF-based LSM than
>> has been applied to the existing LSMs, e.g. we are required to preserve
>> SELinux policy compatibility all the way back to Linux 2.6.0 such that new
>> kernel with old policy does not break userspace. If that standard isn't being
>> applied to the eBPF-based LSM, it seems to inhibit its use in major Linux
>> distros, since otherwise users will in fact start experiencing breakage on the
>> first such incompatible change. Not arguing for or against, just trying to
>> make sure I understand correctly...
>
> A different standard would be applied here vs. a standard LSM like
> SELinux, which are retrofitted access control systems.
>
> I see KRSI as being more of a debugging / analytical API, rather than an
> access control system. You could of course build such a system with KRSI
> but it would need to provide a layer of abstraction for general purpose
> users.
>
> So yes this would be a special case, as its real value is in being a
> special case, i.e. dynamic security telemetry.

The cover letter subject line and the Kconfig help text refer to it as a
BPF-based "MAC and Audit policy". It has an enforce config option that
enables the bpf programs to deny access, providing access control. IIRC,
in the earlier discussion threads, the BPF maintainers suggested that
Smack and other LSMs could be entirely re-implemented via it in the
future, and that such an implementation would be more optimal.

Again, not arguing for or against, but wondering if people fully
understand the implications. If it ends up being useful, people will
build access control systems with it, and it directly exposes a lot of
kernel internals to userspace. There was a lot of concern originally
about the LSM hook interface becoming a stable ABI and/or about it being
misused. Exposing that interface along with every kernel data structure
exposed through it to userspace seems like a major leap. Even if the
mainline kernel doesn't worry about any kind of stable interface
guarantees for it, the distros might be forced to provide some kABI
guarantees for it to appease ISVs and users...

2020-01-09 20:41:57

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, Jan 10, 2020 at 05:11:38AM +1100, James Morris wrote:
> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>
> > The cover letter subject line and the Kconfig help text refer to it as a
> > BPF-based "MAC and Audit policy". It has an enforce config option that
> > enables the bpf programs to deny access, providing access control. IIRC, in
> > the earlier discussion threads, the BPF maintainers suggested that Smack and
> > other LSMs could be entirely re-implemented via it in the future, and that
> > such an implementation would be more optimal.
>
> In this case, the eBPF code is similar to a kernel module, rather than a
> loadable policy file. It's a loadable mechanism, rather than a policy, in
> my view.
>
> This would be similar to the difference between iptables rules and
> loadable eBPF networking code. I'd be interested to know how the
> eBPF networking scenarios are handled wrt kernel ABI.

I already know of some people who pre-compile ebpf programs based on a
number of "supported" kernel versions and then load the needed one at
runtime.

Messy, yes, but you are right, ebpf code is much more similiar to a
kernel module than userspace code at the moment.

thanks,

greg k-h

2020-01-09 20:43:25

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 1/9/20 1:11 PM, James Morris wrote:
> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>
>> The cover letter subject line and the Kconfig help text refer to it as a
>> BPF-based "MAC and Audit policy". It has an enforce config option that
>> enables the bpf programs to deny access, providing access control. IIRC, in
>> the earlier discussion threads, the BPF maintainers suggested that Smack and
>> other LSMs could be entirely re-implemented via it in the future, and that
>> such an implementation would be more optimal.
>
> In this case, the eBPF code is similar to a kernel module, rather than a
> loadable policy file. It's a loadable mechanism, rather than a policy, in
> my view.

I thought you frowned on dynamically loadable LSMs for both security and
correctness reasons? And a traditional security module would necessarily
fall under GPL; is the eBPF code required to be likewise? If not, KRSI
is a gateway for proprietary LSMs...

> This would be similar to the difference between iptables rules and
> loadable eBPF networking code. I'd be interested to know how the
> eBPF networking scenarios are handled wrt kernel ABI.
>
>
>> Again, not arguing for or against, but wondering if people fully understand
>> the implications. If it ends up being useful, people will build access
>> control systems with it, and it directly exposes a lot of kernel internals to
>> userspace. There was a lot of concern originally about the LSM hook interface
>> becoming a stable ABI and/or about it being misused. Exposing that interface
>> along with every kernel data structure exposed through it to userspace seems
>> like a major leap.
>
> Agreed this is a leap, although I'm not sure I'd characterize it as
> exposure to userspace -- it allows dynamic extension of the LSM API from
> userland, but the code is executed in the kernel.
>
> KP: One thing I'd like to understand better is the attack surface
> introduced by this. IIUC, the BTF fields are read only, so the eBPF code
> should not be able to modify any LSM parameters, correct?
>
>
>> Even if the mainline kernel doesn't worry about any kind
>> of stable interface guarantees for it, the distros might be forced to provide
>> some kABI guarantees for it to appease ISVs and users...
>
> How is this handled currently for other eBPF use-cases?
>

2020-01-09 20:44:41

by James Morris

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Thu, 9 Jan 2020, Stephen Smalley wrote:

> On 1/9/20 1:11 PM, James Morris wrote:
> > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> >
> > > The cover letter subject line and the Kconfig help text refer to it as a
> > > BPF-based "MAC and Audit policy". It has an enforce config option that
> > > enables the bpf programs to deny access, providing access control. IIRC,
> > > in
> > > the earlier discussion threads, the BPF maintainers suggested that Smack
> > > and
> > > other LSMs could be entirely re-implemented via it in the future, and that
> > > such an implementation would be more optimal.
> >
> > In this case, the eBPF code is similar to a kernel module, rather than a
> > loadable policy file. It's a loadable mechanism, rather than a policy, in
> > my view.
>
> I thought you frowned on dynamically loadable LSMs for both security and
> correctness reasons?

Evaluating the security impact of this is the next step. My understanding
is that eBPF via BTF is constrained to read only access to hook
parameters, and that its behavior would be entirely restrictive.

I'd like to understand the security impact more fully, though. Can the
eBPF code make arbitrary writes to the kernel, or read anything other than
the correctly bounded LSM hook parameters?

> And a traditional security module would necessarily fall
> under GPL; is the eBPF code required to be likewise? If not, KRSI is a
> gateway for proprietary LSMs...

Right, we do not want this to be a GPL bypass.

If these issues can be resolved, this may be a "safe" way to support
loadable LSM applications.

Again, I'd be interested in knowing how this is is handled in the
networking stack (keeping in mind that LSM is a much more invasive API,
and may not be directly comparable).

--
James Morris
<[email protected]>

2020-01-09 20:51:32

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 10-Jan 06:07, James Morris wrote:
> On Thu, 9 Jan 2020, Stephen Smalley wrote:
>
> > On 1/9/20 1:11 PM, James Morris wrote:
> > > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> > >
> > > > The cover letter subject line and the Kconfig help text refer to it as a
> > > > BPF-based "MAC and Audit policy". It has an enforce config option that
> > > > enables the bpf programs to deny access, providing access control. IIRC,
> > > > in
> > > > the earlier discussion threads, the BPF maintainers suggested that Smack
> > > > and
> > > > other LSMs could be entirely re-implemented via it in the future, and that
> > > > such an implementation would be more optimal.
> > >
> > > In this case, the eBPF code is similar to a kernel module, rather than a
> > > loadable policy file. It's a loadable mechanism, rather than a policy, in
> > > my view.
> >
> > I thought you frowned on dynamically loadable LSMs for both security and
> > correctness reasons?

Based on the feedback from the lists we've updated the design for v2.

In v2, LSM hook callbacks are allocated dynamically using BPF
trampolines, appended to a separate security_hook_heads and run
only after the statically allocated hooks.

The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
still remains __lsm_ro_after_init and cannot be modified. We are still
working on v2 (not ready for review yet) but the general idea can be
seen here:

https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c

>
> Evaluating the security impact of this is the next step. My understanding
> is that eBPF via BTF is constrained to read only access to hook
> parameters, and that its behavior would be entirely restrictive.
>
> I'd like to understand the security impact more fully, though. Can the
> eBPF code make arbitrary writes to the kernel, or read anything other than
> the correctly bounded LSM hook parameters?
>

As mentioned, the BPF verifier does not allow writes to BTF types.

> > And a traditional security module would necessarily fall
> > under GPL; is the eBPF code required to be likewise? If not, KRSI is a
> > gateway for proprietary LSMs...
>
> Right, we do not want this to be a GPL bypass.

This is not intended to be a GPL bypass and the BPF verifier checks
for license compatibility of the loaded program with GPL.

- KP

>
> If these issues can be resolved, this may be a "safe" way to support
> loadable LSM applications.
>
> Again, I'd be interested in knowing how this is is handled in the
> networking stack (keeping in mind that LSM is a much more invasive API,
> and may not be directly comparable).
>
> --
> James Morris
> <[email protected]>
>

2020-01-09 21:01:51

by James Morris

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Wed, 8 Jan 2020, Stephen Smalley wrote:

> The cover letter subject line and the Kconfig help text refer to it as a
> BPF-based "MAC and Audit policy". It has an enforce config option that
> enables the bpf programs to deny access, providing access control. IIRC, in
> the earlier discussion threads, the BPF maintainers suggested that Smack and
> other LSMs could be entirely re-implemented via it in the future, and that
> such an implementation would be more optimal.

In this case, the eBPF code is similar to a kernel module, rather than a
loadable policy file. It's a loadable mechanism, rather than a policy, in
my view.

This would be similar to the difference between iptables rules and
loadable eBPF networking code. I'd be interested to know how the
eBPF networking scenarios are handled wrt kernel ABI.


> Again, not arguing for or against, but wondering if people fully understand
> the implications. If it ends up being useful, people will build access
> control systems with it, and it directly exposes a lot of kernel internals to
> userspace. There was a lot of concern originally about the LSM hook interface
> becoming a stable ABI and/or about it being misused. Exposing that interface
> along with every kernel data structure exposed through it to userspace seems
> like a major leap.

Agreed this is a leap, although I'm not sure I'd characterize it as
exposure to userspace -- it allows dynamic extension of the LSM API from
userland, but the code is executed in the kernel.

KP: One thing I'd like to understand better is the attack surface
introduced by this. IIUC, the BTF fields are read only, so the eBPF code
should not be able to modify any LSM parameters, correct?


> Even if the mainline kernel doesn't worry about any kind
> of stable interface guarantees for it, the distros might be forced to provide
> some kABI guarantees for it to appease ISVs and users...

How is this handled currently for other eBPF use-cases?

--
James Morris
<[email protected]>

2020-01-09 21:03:11

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 10-Jan 05:11, James Morris wrote:
> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>
> > The cover letter subject line and the Kconfig help text refer to it as a
> > BPF-based "MAC and Audit policy". It has an enforce config option that
> > enables the bpf programs to deny access, providing access control. IIRC, in
> > the earlier discussion threads, the BPF maintainers suggested that Smack and
> > other LSMs could be entirely re-implemented via it in the future, and that
> > such an implementation would be more optimal.
>
> In this case, the eBPF code is similar to a kernel module, rather than a
> loadable policy file. It's a loadable mechanism, rather than a policy, in
> my view.
>
> This would be similar to the difference between iptables rules and
> loadable eBPF networking code. I'd be interested to know how the
> eBPF networking scenarios are handled wrt kernel ABI.
>
>
> > Again, not arguing for or against, but wondering if people fully understand
> > the implications. If it ends up being useful, people will build access
> > control systems with it, and it directly exposes a lot of kernel internals to
> > userspace. There was a lot of concern originally about the LSM hook interface
> > becoming a stable ABI and/or about it being misused. Exposing that interface
> > along with every kernel data structure exposed through it to userspace seems
> > like a major leap.
>
> Agreed this is a leap, although I'm not sure I'd characterize it as
> exposure to userspace -- it allows dynamic extension of the LSM API from
> userland, but the code is executed in the kernel.
>
> KP: One thing I'd like to understand better is the attack surface
> introduced by this. IIUC, the BTF fields are read only, so the eBPF code
> should not be able to modify any LSM parameters, correct?
>

That's correct, the verifier does not allow writes to BTF types:

from kernel/bpf/verifier.c:

case PTR_TO_BTF_ID:
if (type == BPF_WRITE) {
verbose(env, "Writes through BTF pointers are not allowed\n");
return -EINVAL;
}

We can also add additional checks on top of those added by the
verifier using the verifier_ops that each BPF program type can define.

- KP

>
> > Even if the mainline kernel doesn't worry about any kind
> > of stable interface guarantees for it, the distros might be forced to provide
> > some kABI guarantees for it to appease ISVs and users...
>
> How is this handled currently for other eBPF use-cases?
>
> --
> James Morris
> <[email protected]>
>

2020-01-09 21:04:23

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 1/9/20 2:43 PM, KP Singh wrote:
> On 10-Jan 06:07, James Morris wrote:
>> On Thu, 9 Jan 2020, Stephen Smalley wrote:
>>
>>> On 1/9/20 1:11 PM, James Morris wrote:
>>>> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>>>>
>>>>> The cover letter subject line and the Kconfig help text refer to it as a
>>>>> BPF-based "MAC and Audit policy". It has an enforce config option that
>>>>> enables the bpf programs to deny access, providing access control. IIRC,
>>>>> in
>>>>> the earlier discussion threads, the BPF maintainers suggested that Smack
>>>>> and
>>>>> other LSMs could be entirely re-implemented via it in the future, and that
>>>>> such an implementation would be more optimal.
>>>>
>>>> In this case, the eBPF code is similar to a kernel module, rather than a
>>>> loadable policy file. It's a loadable mechanism, rather than a policy, in
>>>> my view.
>>>
>>> I thought you frowned on dynamically loadable LSMs for both security and
>>> correctness reasons?
>
> Based on the feedback from the lists we've updated the design for v2.
>
> In v2, LSM hook callbacks are allocated dynamically using BPF
> trampolines, appended to a separate security_hook_heads and run
> only after the statically allocated hooks.
>
> The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
> still remains __lsm_ro_after_init and cannot be modified. We are still
> working on v2 (not ready for review yet) but the general idea can be
> seen here:
>
> https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
>
>>
>> Evaluating the security impact of this is the next step. My understanding
>> is that eBPF via BTF is constrained to read only access to hook
>> parameters, and that its behavior would be entirely restrictive.
>>
>> I'd like to understand the security impact more fully, though. Can the
>> eBPF code make arbitrary writes to the kernel, or read anything other than
>> the correctly bounded LSM hook parameters?
>>
>
> As mentioned, the BPF verifier does not allow writes to BTF types.
>
>>> And a traditional security module would necessarily fall
>>> under GPL; is the eBPF code required to be likewise? If not, KRSI is a
>>> gateway for proprietary LSMs...
>>
>> Right, we do not want this to be a GPL bypass.
>
> This is not intended to be a GPL bypass and the BPF verifier checks
> for license compatibility of the loaded program with GPL.

IIUC, it checks that the program is GPL compatible if it uses a function
marked GPL-only. But what specifically is marked GPL-only that is
required for eBPF programs using KRSI?

>
> - KP
>
>>
>> If these issues can be resolved, this may be a "safe" way to support
>> loadable LSM applications.
>>
>> Again, I'd be interested in knowing how this is is handled in the
>> networking stack (keeping in mind that LSM is a much more invasive API,
>> and may not be directly comparable).
>>
>> --
>> James Morris
>> <[email protected]>
>>

2020-01-10 15:30:40

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 09-Jan 14:47, Stephen Smalley wrote:
> On 1/9/20 2:43 PM, KP Singh wrote:
> > On 10-Jan 06:07, James Morris wrote:
> > > On Thu, 9 Jan 2020, Stephen Smalley wrote:
> > >
> > > > On 1/9/20 1:11 PM, James Morris wrote:
> > > > > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> > > > >
> > > > > > The cover letter subject line and the Kconfig help text refer to it as a
> > > > > > BPF-based "MAC and Audit policy". It has an enforce config option that
> > > > > > enables the bpf programs to deny access, providing access control. IIRC,
> > > > > > in
> > > > > > the earlier discussion threads, the BPF maintainers suggested that Smack
> > > > > > and
> > > > > > other LSMs could be entirely re-implemented via it in the future, and that
> > > > > > such an implementation would be more optimal.
> > > > >
> > > > > In this case, the eBPF code is similar to a kernel module, rather than a
> > > > > loadable policy file. It's a loadable mechanism, rather than a policy, in
> > > > > my view.
> > > >
> > > > I thought you frowned on dynamically loadable LSMs for both security and
> > > > correctness reasons?
> >
> > Based on the feedback from the lists we've updated the design for v2.
> >
> > In v2, LSM hook callbacks are allocated dynamically using BPF
> > trampolines, appended to a separate security_hook_heads and run
> > only after the statically allocated hooks.
> >
> > The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
> > still remains __lsm_ro_after_init and cannot be modified. We are still
> > working on v2 (not ready for review yet) but the general idea can be
> > seen here:
> >
> > https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
> >
> > >
> > > Evaluating the security impact of this is the next step. My understanding
> > > is that eBPF via BTF is constrained to read only access to hook
> > > parameters, and that its behavior would be entirely restrictive.
> > >
> > > I'd like to understand the security impact more fully, though. Can the
> > > eBPF code make arbitrary writes to the kernel, or read anything other than
> > > the correctly bounded LSM hook parameters?
> > >
> >
> > As mentioned, the BPF verifier does not allow writes to BTF types.
> >
> > > > And a traditional security module would necessarily fall
> > > > under GPL; is the eBPF code required to be likewise? If not, KRSI is a
> > > > gateway for proprietary LSMs...
> > >
> > > Right, we do not want this to be a GPL bypass.
> >
> > This is not intended to be a GPL bypass and the BPF verifier checks
> > for license compatibility of the loaded program with GPL.
>
> IIUC, it checks that the program is GPL compatible if it uses a function
> marked GPL-only. But what specifically is marked GPL-only that is required
> for eBPF programs using KRSI?

Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
specific verification for the v2 of the patch-set which would require
all BPF-LSM programs to be GPL.

- KP

>
> >
> > - KP
> >
> > >
> > > If these issues can be resolved, this may be a "safe" way to support
> > > loadable LSM applications.
> > >
> > > Again, I'd be interested in knowing how this is is handled in the
> > > networking stack (keeping in mind that LSM is a much more invasive API,
> > > and may not be directly comparable).
> > >
> > > --
> > > James Morris
> > > <[email protected]>
> > >
>

2020-01-10 17:51:11

by James Morris

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, 10 Jan 2020, KP Singh wrote:

>
> Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
> specific verification for the v2 of the patch-set which would require
> all BPF-LSM programs to be GPL.

Sounds good to me.

--
James Morris
<[email protected]>

2020-01-10 17:54:21

by Alexei Starovoitov

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
> On 09-Jan 14:47, Stephen Smalley wrote:
> > On 1/9/20 2:43 PM, KP Singh wrote:
> > > On 10-Jan 06:07, James Morris wrote:
> > > > On Thu, 9 Jan 2020, Stephen Smalley wrote:
> > > >
> > > > > On 1/9/20 1:11 PM, James Morris wrote:
> > > > > > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> > > > > >
> > > > > > > The cover letter subject line and the Kconfig help text refer to it as a
> > > > > > > BPF-based "MAC and Audit policy". It has an enforce config option that
> > > > > > > enables the bpf programs to deny access, providing access control. IIRC,
> > > > > > > in
> > > > > > > the earlier discussion threads, the BPF maintainers suggested that Smack
> > > > > > > and
> > > > > > > other LSMs could be entirely re-implemented via it in the future, and that
> > > > > > > such an implementation would be more optimal.
> > > > > >
> > > > > > In this case, the eBPF code is similar to a kernel module, rather than a
> > > > > > loadable policy file. It's a loadable mechanism, rather than a policy, in
> > > > > > my view.
> > > > >
> > > > > I thought you frowned on dynamically loadable LSMs for both security and
> > > > > correctness reasons?
> > >
> > > Based on the feedback from the lists we've updated the design for v2.
> > >
> > > In v2, LSM hook callbacks are allocated dynamically using BPF
> > > trampolines, appended to a separate security_hook_heads and run
> > > only after the statically allocated hooks.
> > >
> > > The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
> > > still remains __lsm_ro_after_init and cannot be modified. We are still
> > > working on v2 (not ready for review yet) but the general idea can be
> > > seen here:
> > >
> > > https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
> > >
> > > >
> > > > Evaluating the security impact of this is the next step. My understanding
> > > > is that eBPF via BTF is constrained to read only access to hook
> > > > parameters, and that its behavior would be entirely restrictive.
> > > >
> > > > I'd like to understand the security impact more fully, though. Can the
> > > > eBPF code make arbitrary writes to the kernel, or read anything other than
> > > > the correctly bounded LSM hook parameters?
> > > >
> > >
> > > As mentioned, the BPF verifier does not allow writes to BTF types.
> > >
> > > > > And a traditional security module would necessarily fall
> > > > > under GPL; is the eBPF code required to be likewise? If not, KRSI is a
> > > > > gateway for proprietary LSMs...
> > > >
> > > > Right, we do not want this to be a GPL bypass.
> > >
> > > This is not intended to be a GPL bypass and the BPF verifier checks
> > > for license compatibility of the loaded program with GPL.
> >
> > IIUC, it checks that the program is GPL compatible if it uses a function
> > marked GPL-only. But what specifically is marked GPL-only that is required
> > for eBPF programs using KRSI?
>
> Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
> specific verification for the v2 of the patch-set which would require
> all BPF-LSM programs to be GPL.

I don't think it's a good idea to enforce license on the program.
The kernel doesn't do it for modules.
For years all of BPF tracing progs were GPL because they have to use
GPL-ed helpers to do anything meaningful.
So for KRSI just make sure that all helpers are GPL-ed as well.

2020-01-14 17:36:35

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 1/10/20 12:53 PM, Alexei Starovoitov wrote:
> On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
>> On 09-Jan 14:47, Stephen Smalley wrote:
>>> On 1/9/20 2:43 PM, KP Singh wrote:
>>>> On 10-Jan 06:07, James Morris wrote:
>>>>> On Thu, 9 Jan 2020, Stephen Smalley wrote:
>>>>>
>>>>>> On 1/9/20 1:11 PM, James Morris wrote:
>>>>>>> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>>>>>>>
>>>>>>>> The cover letter subject line and the Kconfig help text refer to it as a
>>>>>>>> BPF-based "MAC and Audit policy". It has an enforce config option that
>>>>>>>> enables the bpf programs to deny access, providing access control. IIRC,
>>>>>>>> in
>>>>>>>> the earlier discussion threads, the BPF maintainers suggested that Smack
>>>>>>>> and
>>>>>>>> other LSMs could be entirely re-implemented via it in the future, and that
>>>>>>>> such an implementation would be more optimal.
>>>>>>>
>>>>>>> In this case, the eBPF code is similar to a kernel module, rather than a
>>>>>>> loadable policy file. It's a loadable mechanism, rather than a policy, in
>>>>>>> my view.
>>>>>>
>>>>>> I thought you frowned on dynamically loadable LSMs for both security and
>>>>>> correctness reasons?
>>>>
>>>> Based on the feedback from the lists we've updated the design for v2.
>>>>
>>>> In v2, LSM hook callbacks are allocated dynamically using BPF
>>>> trampolines, appended to a separate security_hook_heads and run
>>>> only after the statically allocated hooks.
>>>>
>>>> The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
>>>> still remains __lsm_ro_after_init and cannot be modified. We are still
>>>> working on v2 (not ready for review yet) but the general idea can be
>>>> seen here:
>>>>
>>>> https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
>>>>
>>>>>
>>>>> Evaluating the security impact of this is the next step. My understanding
>>>>> is that eBPF via BTF is constrained to read only access to hook
>>>>> parameters, and that its behavior would be entirely restrictive.
>>>>>
>>>>> I'd like to understand the security impact more fully, though. Can the
>>>>> eBPF code make arbitrary writes to the kernel, or read anything other than
>>>>> the correctly bounded LSM hook parameters?
>>>>>
>>>>
>>>> As mentioned, the BPF verifier does not allow writes to BTF types.
>>>>
>>>>>> And a traditional security module would necessarily fall
>>>>>> under GPL; is the eBPF code required to be likewise? If not, KRSI is a
>>>>>> gateway for proprietary LSMs...
>>>>>
>>>>> Right, we do not want this to be a GPL bypass.
>>>>
>>>> This is not intended to be a GPL bypass and the BPF verifier checks
>>>> for license compatibility of the loaded program with GPL.
>>>
>>> IIUC, it checks that the program is GPL compatible if it uses a function
>>> marked GPL-only. But what specifically is marked GPL-only that is required
>>> for eBPF programs using KRSI?
>>
>> Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
>> specific verification for the v2 of the patch-set which would require
>> all BPF-LSM programs to be GPL.
>
> I don't think it's a good idea to enforce license on the program.
> The kernel doesn't do it for modules.
> For years all of BPF tracing progs were GPL because they have to use
> GPL-ed helpers to do anything meaningful.
> So for KRSI just make sure that all helpers are GPL-ed as well.

IIUC, the example eBPF code included in this patch series showed a
program that used a GPL-only helper for the purpose of reporting event
output to userspace. But it could have just as easily omitted the use of
that helper and still implemented its own arbitrary access control model
on the LSM hooks to which it attached. It seems like the question is
whether the kernel developers are ok with exposing the entire LSM hook
interface and all the associated data structures to non-GPLd code,
irrespective of what helpers it may or may not use.


2020-01-14 17:43:05

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 1/14/20 11:54 AM, Stephen Smalley wrote:
> On 1/10/20 12:53 PM, Alexei Starovoitov wrote:
>> On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
>>> On 09-Jan 14:47, Stephen Smalley wrote:
>>>> On 1/9/20 2:43 PM, KP Singh wrote:
>>>>> On 10-Jan 06:07, James Morris wrote:
>>>>>> On Thu, 9 Jan 2020, Stephen Smalley wrote:
>>>>>>
>>>>>>> On 1/9/20 1:11 PM, James Morris wrote:
>>>>>>>> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>>>>>>>>
>>>>>>>>> The cover letter subject line and the Kconfig help text refer
>>>>>>>>> to it as a
>>>>>>>>> BPF-based "MAC and Audit policy".  It has an enforce config
>>>>>>>>> option that
>>>>>>>>> enables the bpf programs to deny access, providing access
>>>>>>>>> control. IIRC,
>>>>>>>>> in
>>>>>>>>> the earlier discussion threads, the BPF maintainers suggested
>>>>>>>>> that Smack
>>>>>>>>> and
>>>>>>>>> other LSMs could be entirely re-implemented via it in the
>>>>>>>>> future, and that
>>>>>>>>> such an implementation would be more optimal.
>>>>>>>>
>>>>>>>> In this case, the eBPF code is similar to a kernel module,
>>>>>>>> rather than a
>>>>>>>> loadable policy file.  It's a loadable mechanism, rather than a
>>>>>>>> policy, in
>>>>>>>> my view.
>>>>>>>
>>>>>>> I thought you frowned on dynamically loadable LSMs for both
>>>>>>> security and
>>>>>>> correctness reasons?
>>>>>
>>>>> Based on the feedback from the lists we've updated the design for v2.
>>>>>
>>>>> In v2, LSM hook callbacks are allocated dynamically using BPF
>>>>> trampolines, appended to a separate security_hook_heads and run
>>>>> only after the statically allocated hooks.
>>>>>
>>>>> The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
>>>>> still remains __lsm_ro_after_init and cannot be modified. We are still
>>>>> working on v2 (not ready for review yet) but the general idea can be
>>>>> seen here:
>>>>>
>>>>>
>>>>> https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
>>>>>
>>>>>
>>>>>>
>>>>>> Evaluating the security impact of this is the next step. My
>>>>>> understanding
>>>>>> is that eBPF via BTF is constrained to read only access to hook
>>>>>> parameters, and that its behavior would be entirely restrictive.
>>>>>>
>>>>>> I'd like to understand the security impact more fully, though.
>>>>>> Can the
>>>>>> eBPF code make arbitrary writes to the kernel, or read anything
>>>>>> other than
>>>>>> the correctly bounded LSM hook parameters?
>>>>>>
>>>>>
>>>>> As mentioned, the BPF verifier does not allow writes to BTF types.
>>>>>
>>>>>>> And a traditional security module would necessarily fall
>>>>>>> under GPL; is the eBPF code required to be likewise?  If not,
>>>>>>> KRSI is a
>>>>>>> gateway for proprietary LSMs...
>>>>>>
>>>>>> Right, we do not want this to be a GPL bypass.
>>>>>
>>>>> This is not intended to be a GPL bypass and the BPF verifier checks
>>>>> for license compatibility of the loaded program with GPL.
>>>>
>>>> IIUC, it checks that the program is GPL compatible if it uses a
>>>> function
>>>> marked GPL-only.  But what specifically is marked GPL-only that is
>>>> required
>>>> for eBPF programs using KRSI?
>>>
>>> Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
>>> specific verification for the v2 of the patch-set which would require
>>> all BPF-LSM programs to be GPL.
>>
>> I don't think it's a good idea to enforce license on the program.
>> The kernel doesn't do it for modules.
>> For years all of BPF tracing progs were GPL because they have to use
>> GPL-ed helpers to do anything meaningful.
>> So for KRSI just make sure that all helpers are GPL-ed as well.
>
> IIUC, the example eBPF code included in this patch series showed a
> program that used a GPL-only helper for the purpose of reporting event
> output to userspace. But it could have just as easily omitted the use of
> that helper and still implemented its own arbitrary access control model
> on the LSM hooks to which it attached.  It seems like the question is
> whether the kernel developers are ok with exposing the entire LSM hook
> interface and all the associated data structures to non-GPLd code,
> irrespective of what helpers it may or may not use.

Also, to be clear, while kernel modules aren't necessarily GPL, prior to
this patch series, all Linux security modules were necessarily GPLd in
order to use the LSM interface. So allowing non-GPL eBPF-based LSMs
would be a change.

2020-01-15 02:49:37

by Alexei Starovoitov

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Tue, Jan 14, 2020 at 12:42:22PM -0500, Stephen Smalley wrote:
> On 1/14/20 11:54 AM, Stephen Smalley wrote:
> > On 1/10/20 12:53 PM, Alexei Starovoitov wrote:
> > > On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
> > > > On 09-Jan 14:47, Stephen Smalley wrote:
> > > > > On 1/9/20 2:43 PM, KP Singh wrote:
> > > > > > On 10-Jan 06:07, James Morris wrote:
> > > > > > > On Thu, 9 Jan 2020, Stephen Smalley wrote:
> > > > > > >
> > > > > > > > On 1/9/20 1:11 PM, James Morris wrote:
> > > > > > > > > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> > > > > > > > >
> > > > > > > > > > The cover letter subject line and the
> > > > > > > > > > Kconfig help text refer to it as a
> > > > > > > > > > BPF-based "MAC and Audit policy".? It
> > > > > > > > > > has an enforce config option that
> > > > > > > > > > enables the bpf programs to deny access,
> > > > > > > > > > providing access control. IIRC,
> > > > > > > > > > in
> > > > > > > > > > the earlier discussion threads, the BPF
> > > > > > > > > > maintainers suggested that Smack
> > > > > > > > > > and
> > > > > > > > > > other LSMs could be entirely
> > > > > > > > > > re-implemented via it in the future, and
> > > > > > > > > > that
> > > > > > > > > > such an implementation would be more optimal.
> > > > > > > > >
> > > > > > > > > In this case, the eBPF code is similar to a
> > > > > > > > > kernel module, rather than a
> > > > > > > > > loadable policy file.? It's a loadable
> > > > > > > > > mechanism, rather than a policy, in
> > > > > > > > > my view.
> > > > > > > >
> > > > > > > > I thought you frowned on dynamically loadable
> > > > > > > > LSMs for both security and
> > > > > > > > correctness reasons?
> > > > > >
> > > > > > Based on the feedback from the lists we've updated the design for v2.
> > > > > >
> > > > > > In v2, LSM hook callbacks are allocated dynamically using BPF
> > > > > > trampolines, appended to a separate security_hook_heads and run
> > > > > > only after the statically allocated hooks.
> > > > > >
> > > > > > The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
> > > > > > still remains __lsm_ro_after_init and cannot be modified. We are still
> > > > > > working on v2 (not ready for review yet) but the general idea can be
> > > > > > seen here:
> > > > > >
> > > > > > https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
> > > > > >
> > > > > >
> > > > > > >
> > > > > > > Evaluating the security impact of this is the next
> > > > > > > step. My understanding
> > > > > > > is that eBPF via BTF is constrained to read only access to hook
> > > > > > > parameters, and that its behavior would be entirely restrictive.
> > > > > > >
> > > > > > > I'd like to understand the security impact more
> > > > > > > fully, though. Can the
> > > > > > > eBPF code make arbitrary writes to the kernel, or
> > > > > > > read anything other than
> > > > > > > the correctly bounded LSM hook parameters?
> > > > > > >
> > > > > >
> > > > > > As mentioned, the BPF verifier does not allow writes to BTF types.
> > > > > >
> > > > > > > > And a traditional security module would necessarily fall
> > > > > > > > under GPL; is the eBPF code required to be
> > > > > > > > likewise?? If not, KRSI is a
> > > > > > > > gateway for proprietary LSMs...
> > > > > > >
> > > > > > > Right, we do not want this to be a GPL bypass.
> > > > > >
> > > > > > This is not intended to be a GPL bypass and the BPF verifier checks
> > > > > > for license compatibility of the loaded program with GPL.
> > > > >
> > > > > IIUC, it checks that the program is GPL compatible if it
> > > > > uses a function
> > > > > marked GPL-only.? But what specifically is marked GPL-only
> > > > > that is required
> > > > > for eBPF programs using KRSI?
> > > >
> > > > Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
> > > > specific verification for the v2 of the patch-set which would require
> > > > all BPF-LSM programs to be GPL.
> > >
> > > I don't think it's a good idea to enforce license on the program.
> > > The kernel doesn't do it for modules.
> > > For years all of BPF tracing progs were GPL because they have to use
> > > GPL-ed helpers to do anything meaningful.
> > > So for KRSI just make sure that all helpers are GPL-ed as well.
> >
> > IIUC, the example eBPF code included in this patch series showed a
> > program that used a GPL-only helper for the purpose of reporting event
> > output to userspace. But it could have just as easily omitted the use of
> > that helper and still implemented its own arbitrary access control model
> > on the LSM hooks to which it attached.? It seems like the question is
> > whether the kernel developers are ok with exposing the entire LSM hook
> > interface and all the associated data structures to non-GPLd code,
> > irrespective of what helpers it may or may not use.
>
> Also, to be clear, while kernel modules aren't necessarily GPL, prior to
> this patch series, all Linux security modules were necessarily GPLd in order
> to use the LSM interface.

Because they use securityfs_create_file() GPL-ed api, right?
but not because module license is enforced.

> So allowing non-GPL eBPF-based LSMs would be a
> change.

I don't see it this way. seccomp progs technically unlicensed. Yet they can
disallow any syscall. Primitive KRSI progs like
int bpf-prog(void*) { return REJECT; }
would be able to do selectively disable a syscall with an overhead acceptable
in production systems (unlike seccomp). I want this use case to be available to
people. It's a bait, because to do real progs people would need to GPL them.
Key helpers bpf_perf_event_output, bpf_ktime_get_ns, bpf_trace_printk are all
GPL-ed. It may look that most networking helpers are not-GPL, but real life is
different. To debug programs bpf_trace_printk() is necessary. To have
communication with user space bpf_perf_event_output() is necssary. To measure
anything or implement timestamps bpf_ktime_get_ns() is necessary. So today all
meaninful bpf programs are GPL. Those that are not GPL probably exist, but
they're toy programs. Hence I have zero concerns about GPL bypass coming from
tracing, networking, and, in the future, KRSI progs too.

2020-01-15 13:59:53

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On 1/14/20 9:48 PM, Alexei Starovoitov wrote:
> On Tue, Jan 14, 2020 at 12:42:22PM -0500, Stephen Smalley wrote:
>> On 1/14/20 11:54 AM, Stephen Smalley wrote:
>>> On 1/10/20 12:53 PM, Alexei Starovoitov wrote:
>>>> On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
>>>>> On 09-Jan 14:47, Stephen Smalley wrote:
>>>>>> On 1/9/20 2:43 PM, KP Singh wrote:
>>>>>>> On 10-Jan 06:07, James Morris wrote:
>>>>>>>> On Thu, 9 Jan 2020, Stephen Smalley wrote:
>>>>>>>>
>>>>>>>>> On 1/9/20 1:11 PM, James Morris wrote:
>>>>>>>>>> On Wed, 8 Jan 2020, Stephen Smalley wrote:
>>>>>>>>>>
>>>>>>>>>>> The cover letter subject line and the
>>>>>>>>>>> Kconfig help text refer to it as a
>>>>>>>>>>> BPF-based "MAC and Audit policy".  It
>>>>>>>>>>> has an enforce config option that
>>>>>>>>>>> enables the bpf programs to deny access,
>>>>>>>>>>> providing access control. IIRC,
>>>>>>>>>>> in
>>>>>>>>>>> the earlier discussion threads, the BPF
>>>>>>>>>>> maintainers suggested that Smack
>>>>>>>>>>> and
>>>>>>>>>>> other LSMs could be entirely
>>>>>>>>>>> re-implemented via it in the future, and
>>>>>>>>>>> that
>>>>>>>>>>> such an implementation would be more optimal.
>>>>>>>>>>
>>>>>>>>>> In this case, the eBPF code is similar to a
>>>>>>>>>> kernel module, rather than a
>>>>>>>>>> loadable policy file.  It's a loadable
>>>>>>>>>> mechanism, rather than a policy, in
>>>>>>>>>> my view.
>>>>>>>>>
>>>>>>>>> I thought you frowned on dynamically loadable
>>>>>>>>> LSMs for both security and
>>>>>>>>> correctness reasons?
>>>>>>>
>>>>>>> Based on the feedback from the lists we've updated the design for v2.
>>>>>>>
>>>>>>> In v2, LSM hook callbacks are allocated dynamically using BPF
>>>>>>> trampolines, appended to a separate security_hook_heads and run
>>>>>>> only after the statically allocated hooks.
>>>>>>>
>>>>>>> The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
>>>>>>> still remains __lsm_ro_after_init and cannot be modified. We are still
>>>>>>> working on v2 (not ready for review yet) but the general idea can be
>>>>>>> seen here:
>>>>>>>
>>>>>>> https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> Evaluating the security impact of this is the next
>>>>>>>> step. My understanding
>>>>>>>> is that eBPF via BTF is constrained to read only access to hook
>>>>>>>> parameters, and that its behavior would be entirely restrictive.
>>>>>>>>
>>>>>>>> I'd like to understand the security impact more
>>>>>>>> fully, though. Can the
>>>>>>>> eBPF code make arbitrary writes to the kernel, or
>>>>>>>> read anything other than
>>>>>>>> the correctly bounded LSM hook parameters?
>>>>>>>>
>>>>>>>
>>>>>>> As mentioned, the BPF verifier does not allow writes to BTF types.
>>>>>>>
>>>>>>>>> And a traditional security module would necessarily fall
>>>>>>>>> under GPL; is the eBPF code required to be
>>>>>>>>> likewise?  If not, KRSI is a
>>>>>>>>> gateway for proprietary LSMs...
>>>>>>>>
>>>>>>>> Right, we do not want this to be a GPL bypass.
>>>>>>>
>>>>>>> This is not intended to be a GPL bypass and the BPF verifier checks
>>>>>>> for license compatibility of the loaded program with GPL.
>>>>>>
>>>>>> IIUC, it checks that the program is GPL compatible if it
>>>>>> uses a function
>>>>>> marked GPL-only.  But what specifically is marked GPL-only
>>>>>> that is required
>>>>>> for eBPF programs using KRSI?
>>>>>
>>>>> Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
>>>>> specific verification for the v2 of the patch-set which would require
>>>>> all BPF-LSM programs to be GPL.
>>>>
>>>> I don't think it's a good idea to enforce license on the program.
>>>> The kernel doesn't do it for modules.
>>>> For years all of BPF tracing progs were GPL because they have to use
>>>> GPL-ed helpers to do anything meaningful.
>>>> So for KRSI just make sure that all helpers are GPL-ed as well.
>>>
>>> IIUC, the example eBPF code included in this patch series showed a
>>> program that used a GPL-only helper for the purpose of reporting event
>>> output to userspace. But it could have just as easily omitted the use of
>>> that helper and still implemented its own arbitrary access control model
>>> on the LSM hooks to which it attached.  It seems like the question is
>>> whether the kernel developers are ok with exposing the entire LSM hook
>>> interface and all the associated data structures to non-GPLd code,
>>> irrespective of what helpers it may or may not use.
>>
>> Also, to be clear, while kernel modules aren't necessarily GPL, prior to
>> this patch series, all Linux security modules were necessarily GPLd in order
>> to use the LSM interface.
>
> Because they use securityfs_create_file() GPL-ed api, right?
> but not because module license is enforced.

No, securityfs was a later addition and is not required by all LSMs
either. Originally LSMs had to register their hooks via
register_security(), which was intentionally EXPORT_SYMBOL_GPL() to
avoid exposing the LSM interface to non-GPLd modules because there were
significant concerns with doing so when LSM was first merged. Then in
20510f2f4e2dabb0ff6c13901807627ec9452f98 ("security: Convert LSM into a
static interface"), the ability for loadable modules to use
register_security() at all was removed, limiting its use to built-in
modules. In commit b1d9e6b0646d0e5ee5d9050bd236b6c65d66faef ("LSM:
Switch to lists of hooks"), register_security() was replaced by
security_add_hooks(), but this was likewise not exported for use by
modules and could only be used by built-in code. The bpf LSM is
providing a shim that allows eBPF code to attach to these hooks that
would otherwise not be exposed to non-GPLd code, so if the bpf LSM does
not require the eBPF programs to also be GPLd, then that is a change
from current practice.

>> So allowing non-GPL eBPF-based LSMs would be a
>> change.
>
> I don't see it this way. seccomp progs technically unlicensed. Yet they can
> disallow any syscall. Primitive KRSI progs like
> int bpf-prog(void*) { return REJECT; }
> would be able to do selectively disable a syscall with an overhead acceptable
> in production systems (unlike seccomp). I want this use case to be available to
> people. It's a bait, because to do real progs people would need to GPL them.
> Key helpers bpf_perf_event_output, bpf_ktime_get_ns, bpf_trace_printk are all
> GPL-ed. It may look that most networking helpers are not-GPL, but real life is
> different. To debug programs bpf_trace_printk() is necessary. To have
> communication with user space bpf_perf_event_output() is necssary. To measure
> anything or implement timestamps bpf_ktime_get_ns() is necessary. So today all
> meaninful bpf programs are GPL. Those that are not GPL probably exist, but
> they're toy programs. Hence I have zero concerns about GPL bypass coming from
> tracing, networking, and, in the future, KRSI progs too.

You have more confidence than I do about that. I would anticipate
developers of out-of-tree LSMs latching onto this bpf LSM and using it
to avoid GPL. I don't see that any of those helpers are truly needed to
implement an access control model.

2020-01-15 14:11:24

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Wed, Jan 15, 2020 at 08:59:08AM -0500, Stephen Smalley wrote:
> On 1/14/20 9:48 PM, Alexei Starovoitov wrote:
> > On Tue, Jan 14, 2020 at 12:42:22PM -0500, Stephen Smalley wrote:
> > > On 1/14/20 11:54 AM, Stephen Smalley wrote:
> > > > On 1/10/20 12:53 PM, Alexei Starovoitov wrote:
> > > > > On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
> > > > > > On 09-Jan 14:47, Stephen Smalley wrote:
> > > > > > > On 1/9/20 2:43 PM, KP Singh wrote:
> > > > > > > > On 10-Jan 06:07, James Morris wrote:
> > > > > > > > > On Thu, 9 Jan 2020, Stephen Smalley wrote:
> > > > > > > > >
> > > > > > > > > > On 1/9/20 1:11 PM, James Morris wrote:
> > > > > > > > > > > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> > > > > > > > > > >
> > > > > > > > > > > > The cover letter subject line and the
> > > > > > > > > > > > Kconfig help text refer to it as a
> > > > > > > > > > > > BPF-based "MAC and Audit policy".? It
> > > > > > > > > > > > has an enforce config option that
> > > > > > > > > > > > enables the bpf programs to deny access,
> > > > > > > > > > > > providing access control. IIRC,
> > > > > > > > > > > > in
> > > > > > > > > > > > the earlier discussion threads, the BPF
> > > > > > > > > > > > maintainers suggested that Smack
> > > > > > > > > > > > and
> > > > > > > > > > > > other LSMs could be entirely
> > > > > > > > > > > > re-implemented via it in the future, and
> > > > > > > > > > > > that
> > > > > > > > > > > > such an implementation would be more optimal.
> > > > > > > > > > >
> > > > > > > > > > > In this case, the eBPF code is similar to a
> > > > > > > > > > > kernel module, rather than a
> > > > > > > > > > > loadable policy file.? It's a loadable
> > > > > > > > > > > mechanism, rather than a policy, in
> > > > > > > > > > > my view.
> > > > > > > > > >
> > > > > > > > > > I thought you frowned on dynamically loadable
> > > > > > > > > > LSMs for both security and
> > > > > > > > > > correctness reasons?
> > > > > > > >
> > > > > > > > Based on the feedback from the lists we've updated the design for v2.
> > > > > > > >
> > > > > > > > In v2, LSM hook callbacks are allocated dynamically using BPF
> > > > > > > > trampolines, appended to a separate security_hook_heads and run
> > > > > > > > only after the statically allocated hooks.
> > > > > > > >
> > > > > > > > The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
> > > > > > > > still remains __lsm_ro_after_init and cannot be modified. We are still
> > > > > > > > working on v2 (not ready for review yet) but the general idea can be
> > > > > > > > seen here:
> > > > > > > >
> > > > > > > > https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
> > > > > > > >
> > > > > > > >
> > > > > > > > >
> > > > > > > > > Evaluating the security impact of this is the next
> > > > > > > > > step. My understanding
> > > > > > > > > is that eBPF via BTF is constrained to read only access to hook
> > > > > > > > > parameters, and that its behavior would be entirely restrictive.
> > > > > > > > >
> > > > > > > > > I'd like to understand the security impact more
> > > > > > > > > fully, though. Can the
> > > > > > > > > eBPF code make arbitrary writes to the kernel, or
> > > > > > > > > read anything other than
> > > > > > > > > the correctly bounded LSM hook parameters?
> > > > > > > > >
> > > > > > > >
> > > > > > > > As mentioned, the BPF verifier does not allow writes to BTF types.
> > > > > > > >
> > > > > > > > > > And a traditional security module would necessarily fall
> > > > > > > > > > under GPL; is the eBPF code required to be
> > > > > > > > > > likewise?? If not, KRSI is a
> > > > > > > > > > gateway for proprietary LSMs...
> > > > > > > > >
> > > > > > > > > Right, we do not want this to be a GPL bypass.
> > > > > > > >
> > > > > > > > This is not intended to be a GPL bypass and the BPF verifier checks
> > > > > > > > for license compatibility of the loaded program with GPL.
> > > > > > >
> > > > > > > IIUC, it checks that the program is GPL compatible if it
> > > > > > > uses a function
> > > > > > > marked GPL-only.? But what specifically is marked GPL-only
> > > > > > > that is required
> > > > > > > for eBPF programs using KRSI?
> > > > > >
> > > > > > Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
> > > > > > specific verification for the v2 of the patch-set which would require
> > > > > > all BPF-LSM programs to be GPL.
> > > > >
> > > > > I don't think it's a good idea to enforce license on the program.
> > > > > The kernel doesn't do it for modules.
> > > > > For years all of BPF tracing progs were GPL because they have to use
> > > > > GPL-ed helpers to do anything meaningful.
> > > > > So for KRSI just make sure that all helpers are GPL-ed as well.
> > > >
> > > > IIUC, the example eBPF code included in this patch series showed a
> > > > program that used a GPL-only helper for the purpose of reporting event
> > > > output to userspace. But it could have just as easily omitted the use of
> > > > that helper and still implemented its own arbitrary access control model
> > > > on the LSM hooks to which it attached.? It seems like the question is
> > > > whether the kernel developers are ok with exposing the entire LSM hook
> > > > interface and all the associated data structures to non-GPLd code,
> > > > irrespective of what helpers it may or may not use.
> > >
> > > Also, to be clear, while kernel modules aren't necessarily GPL, prior to
> > > this patch series, all Linux security modules were necessarily GPLd in order
> > > to use the LSM interface.
> >
> > Because they use securityfs_create_file() GPL-ed api, right?
> > but not because module license is enforced.
>
> No, securityfs was a later addition and is not required by all LSMs either.
> Originally LSMs had to register their hooks via register_security(), which
> was intentionally EXPORT_SYMBOL_GPL() to avoid exposing the LSM interface to
> non-GPLd modules because there were significant concerns with doing so when
> LSM was first merged. Then in 20510f2f4e2dabb0ff6c13901807627ec9452f98
> ("security: Convert LSM into a static interface"), the ability for loadable
> modules to use register_security() at all was removed, limiting its use to
> built-in modules. In commit b1d9e6b0646d0e5ee5d9050bd236b6c65d66faef ("LSM:
> Switch to lists of hooks"), register_security() was replaced by
> security_add_hooks(), but this was likewise not exported for use by modules
> and could only be used by built-in code. The bpf LSM is providing a shim
> that allows eBPF code to attach to these hooks that would otherwise not be
> exposed to non-GPLd code, so if the bpf LSM does not require the eBPF
> programs to also be GPLd, then that is a change from current practice.
>
> > > So allowing non-GPL eBPF-based LSMs would be a
> > > change.
> >
> > I don't see it this way. seccomp progs technically unlicensed. Yet they can
> > disallow any syscall. Primitive KRSI progs like
> > int bpf-prog(void*) { return REJECT; }
> > would be able to do selectively disable a syscall with an overhead acceptable
> > in production systems (unlike seccomp). I want this use case to be available to
> > people. It's a bait, because to do real progs people would need to GPL them.
> > Key helpers bpf_perf_event_output, bpf_ktime_get_ns, bpf_trace_printk are all
> > GPL-ed. It may look that most networking helpers are not-GPL, but real life is
> > different. To debug programs bpf_trace_printk() is necessary. To have
> > communication with user space bpf_perf_event_output() is necssary. To measure
> > anything or implement timestamps bpf_ktime_get_ns() is necessary. So today all
> > meaninful bpf programs are GPL. Those that are not GPL probably exist, but
> > they're toy programs. Hence I have zero concerns about GPL bypass coming from
> > tracing, networking, and, in the future, KRSI progs too.
>
> You have more confidence than I do about that. I would anticipate
> developers of out-of-tree LSMs latching onto this bpf LSM and using it to
> avoid GPL. I don't see that any of those helpers are truly needed to
> implement an access control model.

Yeah, I'm with Stephen here, this should be explicitly marked for
GPL-only bpf code to prevent anyone from trying to route around the LSM
apis we have today. We have enough problem with companies trying to do
that as-is, let's not give them any other ways to abuse our license.

thanks,

greg k-h

2020-01-15 22:27:32

by Alexei Starovoitov

[permalink] [raw]
Subject: Re: [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)

On Wed, Jan 15, 2020 at 03:09:53PM +0100, Greg Kroah-Hartman wrote:
> On Wed, Jan 15, 2020 at 08:59:08AM -0500, Stephen Smalley wrote:
> > On 1/14/20 9:48 PM, Alexei Starovoitov wrote:
> > > On Tue, Jan 14, 2020 at 12:42:22PM -0500, Stephen Smalley wrote:
> > > > On 1/14/20 11:54 AM, Stephen Smalley wrote:
> > > > > On 1/10/20 12:53 PM, Alexei Starovoitov wrote:
> > > > > > On Fri, Jan 10, 2020 at 04:27:58PM +0100, KP Singh wrote:
> > > > > > > On 09-Jan 14:47, Stephen Smalley wrote:
> > > > > > > > On 1/9/20 2:43 PM, KP Singh wrote:
> > > > > > > > > On 10-Jan 06:07, James Morris wrote:
> > > > > > > > > > On Thu, 9 Jan 2020, Stephen Smalley wrote:
> > > > > > > > > >
> > > > > > > > > > > On 1/9/20 1:11 PM, James Morris wrote:
> > > > > > > > > > > > On Wed, 8 Jan 2020, Stephen Smalley wrote:
> > > > > > > > > > > >
> > > > > > > > > > > > > The cover letter subject line and the
> > > > > > > > > > > > > Kconfig help text refer to it as a
> > > > > > > > > > > > > BPF-based "MAC and Audit policy".? It
> > > > > > > > > > > > > has an enforce config option that
> > > > > > > > > > > > > enables the bpf programs to deny access,
> > > > > > > > > > > > > providing access control. IIRC,
> > > > > > > > > > > > > in
> > > > > > > > > > > > > the earlier discussion threads, the BPF
> > > > > > > > > > > > > maintainers suggested that Smack
> > > > > > > > > > > > > and
> > > > > > > > > > > > > other LSMs could be entirely
> > > > > > > > > > > > > re-implemented via it in the future, and
> > > > > > > > > > > > > that
> > > > > > > > > > > > > such an implementation would be more optimal.
> > > > > > > > > > > >
> > > > > > > > > > > > In this case, the eBPF code is similar to a
> > > > > > > > > > > > kernel module, rather than a
> > > > > > > > > > > > loadable policy file.? It's a loadable
> > > > > > > > > > > > mechanism, rather than a policy, in
> > > > > > > > > > > > my view.
> > > > > > > > > > >
> > > > > > > > > > > I thought you frowned on dynamically loadable
> > > > > > > > > > > LSMs for both security and
> > > > > > > > > > > correctness reasons?
> > > > > > > > >
> > > > > > > > > Based on the feedback from the lists we've updated the design for v2.
> > > > > > > > >
> > > > > > > > > In v2, LSM hook callbacks are allocated dynamically using BPF
> > > > > > > > > trampolines, appended to a separate security_hook_heads and run
> > > > > > > > > only after the statically allocated hooks.
> > > > > > > > >
> > > > > > > > > The security_hook_heads for all the other LSMs (SELinux, AppArmor etc)
> > > > > > > > > still remains __lsm_ro_after_init and cannot be modified. We are still
> > > > > > > > > working on v2 (not ready for review yet) but the general idea can be
> > > > > > > > > seen here:
> > > > > > > > >
> > > > > > > > > https://github.com/sinkap/linux-krsi/blob/patch/v1/trampoline_prototype/security/bpf/lsm.c
> > > > > > > > >
> > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Evaluating the security impact of this is the next
> > > > > > > > > > step. My understanding
> > > > > > > > > > is that eBPF via BTF is constrained to read only access to hook
> > > > > > > > > > parameters, and that its behavior would be entirely restrictive.
> > > > > > > > > >
> > > > > > > > > > I'd like to understand the security impact more
> > > > > > > > > > fully, though. Can the
> > > > > > > > > > eBPF code make arbitrary writes to the kernel, or
> > > > > > > > > > read anything other than
> > > > > > > > > > the correctly bounded LSM hook parameters?
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > As mentioned, the BPF verifier does not allow writes to BTF types.
> > > > > > > > >
> > > > > > > > > > > And a traditional security module would necessarily fall
> > > > > > > > > > > under GPL; is the eBPF code required to be
> > > > > > > > > > > likewise?? If not, KRSI is a
> > > > > > > > > > > gateway for proprietary LSMs...
> > > > > > > > > >
> > > > > > > > > > Right, we do not want this to be a GPL bypass.
> > > > > > > > >
> > > > > > > > > This is not intended to be a GPL bypass and the BPF verifier checks
> > > > > > > > > for license compatibility of the loaded program with GPL.
> > > > > > > >
> > > > > > > > IIUC, it checks that the program is GPL compatible if it
> > > > > > > > uses a function
> > > > > > > > marked GPL-only.? But what specifically is marked GPL-only
> > > > > > > > that is required
> > > > > > > > for eBPF programs using KRSI?
> > > > > > >
> > > > > > > Good point! If no-one objects, I can add it to the BPF_PROG_TYPE_LSM
> > > > > > > specific verification for the v2 of the patch-set which would require
> > > > > > > all BPF-LSM programs to be GPL.
> > > > > >
> > > > > > I don't think it's a good idea to enforce license on the program.
> > > > > > The kernel doesn't do it for modules.
> > > > > > For years all of BPF tracing progs were GPL because they have to use
> > > > > > GPL-ed helpers to do anything meaningful.
> > > > > > So for KRSI just make sure that all helpers are GPL-ed as well.
> > > > >
> > > > > IIUC, the example eBPF code included in this patch series showed a
> > > > > program that used a GPL-only helper for the purpose of reporting event
> > > > > output to userspace. But it could have just as easily omitted the use of
> > > > > that helper and still implemented its own arbitrary access control model
> > > > > on the LSM hooks to which it attached.? It seems like the question is
> > > > > whether the kernel developers are ok with exposing the entire LSM hook
> > > > > interface and all the associated data structures to non-GPLd code,
> > > > > irrespective of what helpers it may or may not use.
> > > >
> > > > Also, to be clear, while kernel modules aren't necessarily GPL, prior to
> > > > this patch series, all Linux security modules were necessarily GPLd in order
> > > > to use the LSM interface.
> > >
> > > Because they use securityfs_create_file() GPL-ed api, right?
> > > but not because module license is enforced.
> >
> > No, securityfs was a later addition and is not required by all LSMs either.
> > Originally LSMs had to register their hooks via register_security(), which
> > was intentionally EXPORT_SYMBOL_GPL() to avoid exposing the LSM interface to
> > non-GPLd modules because there were significant concerns with doing so when
> > LSM was first merged. Then in 20510f2f4e2dabb0ff6c13901807627ec9452f98
> > ("security: Convert LSM into a static interface"), the ability for loadable
> > modules to use register_security() at all was removed, limiting its use to
> > built-in modules. In commit b1d9e6b0646d0e5ee5d9050bd236b6c65d66faef ("LSM:
> > Switch to lists of hooks"), register_security() was replaced by
> > security_add_hooks(), but this was likewise not exported for use by modules
> > and could only be used by built-in code. The bpf LSM is providing a shim
> > that allows eBPF code to attach to these hooks that would otherwise not be
> > exposed to non-GPLd code, so if the bpf LSM does not require the eBPF
> > programs to also be GPLd, then that is a change from current practice.
> >
> > > > So allowing non-GPL eBPF-based LSMs would be a
> > > > change.
> > >
> > > I don't see it this way. seccomp progs technically unlicensed. Yet they can
> > > disallow any syscall. Primitive KRSI progs like
> > > int bpf-prog(void*) { return REJECT; }
> > > would be able to do selectively disable a syscall with an overhead acceptable
> > > in production systems (unlike seccomp). I want this use case to be available to
> > > people. It's a bait, because to do real progs people would need to GPL them.
> > > Key helpers bpf_perf_event_output, bpf_ktime_get_ns, bpf_trace_printk are all
> > > GPL-ed. It may look that most networking helpers are not-GPL, but real life is
> > > different. To debug programs bpf_trace_printk() is necessary. To have
> > > communication with user space bpf_perf_event_output() is necssary. To measure
> > > anything or implement timestamps bpf_ktime_get_ns() is necessary. So today all
> > > meaninful bpf programs are GPL. Those that are not GPL probably exist, but
> > > they're toy programs. Hence I have zero concerns about GPL bypass coming from
> > > tracing, networking, and, in the future, KRSI progs too.
> >
> > You have more confidence than I do about that. I would anticipate
> > developers of out-of-tree LSMs latching onto this bpf LSM and using it to
> > avoid GPL. I don't see that any of those helpers are truly needed to
> > implement an access control model.
>
> Yeah, I'm with Stephen here, this should be explicitly marked for
> GPL-only bpf code to prevent anyone from trying to route around the LSM
> apis we have today. We have enough problem with companies trying to do
> that as-is, let's not give them any other ways to abuse our license.

Fine. Let's do per prog type check. We can undo it later when this early
concerns prove to be overblown.