From patchwork Fri Dec 20 15:41:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305831 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DAF516C1 for ; Fri, 20 Dec 2019 15:43:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AF04724680 for ; Fri, 20 Dec 2019 15:43:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="UWPjWjNk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727414AbfLTPnI (ORCPT ); Fri, 20 Dec 2019 10:43:08 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:45678 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727403AbfLTPmH (ORCPT ); Fri, 20 Dec 2019 10:42:07 -0500 Received: by mail-wr1-f68.google.com with SMTP id j42so9806974wrj.12 for ; Fri, 20 Dec 2019 07:42:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=SY0ttQjEzQPvjvG8/HqwJhfFR6ICOMlRVz/9vg/M7EA=; b=UWPjWjNkk3ZwL4zfuKwzD7wzxugsutarPfj0LeFqtbIXiZgJJOW1P3MOcYslXxorPk nAQY96DB9dWRcMoEyI6QZWz4Cz+kt2H22MewO8uKIJqlKeA0e6oSySc3nTN3PgHriCS9 cKqgMmJVlPMkgu8RfEumk+6mn2FmDiWKzUbq4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=SY0ttQjEzQPvjvG8/HqwJhfFR6ICOMlRVz/9vg/M7EA=; b=iXeHwt5/YbrfYOGu6h/Wji+IqK0e9YzclMURBLzjjvgcRBFjlIF5dN4rbMXX5mYWiF KDecg9+yGqJKtjtaI8CaC+zf184YSVQLm0MEYeiK+V8lE2B1oFjeU0GA0w+HfJztVqS2 dtYp7ml7saiL4+HyP1ho5Zn/mJ0GmUJh5noiMnFgjRGG8SxIFDfsLUInMug2b6NQOMoq RVQG7lBUkYpZu54hnXgqgzkYRyI3/ud5Yh/07T+mie5BW4vRpRcDy1gTx8z1BA4sGHka WQ8SUsSikqQ1Fa8vXAsUBKM5i4HJIR6b4ywbMEvgQxEhH2pSch3hbmdai7LdwFxWN65O 6nsg== X-Gm-Message-State: APjAAAX+J5BYv9CggY5aOmuimamivtRcUytPVffyViAxTeRA70BkmW+V JZOvjFPSWY/FS3k+VThaxZn0gg== X-Google-Smtp-Source: APXvYqxXhdI++uWPW1rc4/x3ev8WEpbY3c9lyzxIBUVouN9hKWxxY/RHbhhyvPJNvVFpgXkGqOONXw== X-Received: by 2002:a5d:5283:: with SMTP id c3mr16600716wrv.148.1576856524700; Fri, 20 Dec 2019 07:42:04 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:04 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 01/13] bpf: Refactor BPF_EVENT context macros to its own header. Date: Fri, 20 Dec 2019 16:41:56 +0100 Message-Id: <20191220154208.15895-2-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh These macros are useful for other program types than tracing. i.e. KRSI (an upccoming BPF based LSM) which does not use BPF_PROG_TYPE_TRACE but uses verifiable BTF accesses similar to raw tracepoints. Signed-off-by: KP Singh --- include/linux/bpf_event.h | 78 +++++++++++++++++++++++++++++++++++++++ include/trace/bpf_probe.h | 30 +-------------- kernel/trace/bpf_trace.c | 24 +----------- 3 files changed, 81 insertions(+), 51 deletions(-) create mode 100644 include/linux/bpf_event.h diff --git a/include/linux/bpf_event.h b/include/linux/bpf_event.h new file mode 100644 index 000000000000..353eb1f5a3d0 --- /dev/null +++ b/include/linux/bpf_event.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + + +/* + * Copyright (c) 2018 Facebook + * Copyright 2019 Google LLC. + */ + +#ifndef _LINUX_BPF_EVENT_H +#define _LINUX_BPF_EVENT_H + +#ifdef CONFIG_BPF_EVENTS + +/* cast any integer, pointer, or small struct to u64 */ +#define UINTTYPE(size) \ + __typeof__(__builtin_choose_expr(size == 1, (u8)1, \ + __builtin_choose_expr(size == 2, (u16)2, \ + __builtin_choose_expr(size == 4, (u32)3, \ + __builtin_choose_expr(size == 8, (u64)4, \ + (void)5))))) +#define __CAST_TO_U64(x) ({ \ + typeof(x) __src = (x); \ + UINTTYPE(sizeof(x)) __dst; \ + memcpy(&__dst, &__src, sizeof(__dst)); \ + (u64)__dst; }) + +#define __CAST0(...) 0 +#define __CAST1(a, ...) __CAST_TO_U64(a) +#define __CAST2(a, ...) __CAST_TO_U64(a), __CAST1(__VA_ARGS__) +#define __CAST3(a, ...) __CAST_TO_U64(a), __CAST2(__VA_ARGS__) +#define __CAST4(a, ...) __CAST_TO_U64(a), __CAST3(__VA_ARGS__) +#define __CAST5(a, ...) __CAST_TO_U64(a), __CAST4(__VA_ARGS__) +#define __CAST6(a, ...) __CAST_TO_U64(a), __CAST5(__VA_ARGS__) +#define __CAST7(a, ...) __CAST_TO_U64(a), __CAST6(__VA_ARGS__) +#define __CAST8(a, ...) __CAST_TO_U64(a), __CAST7(__VA_ARGS__) +#define __CAST9(a, ...) __CAST_TO_U64(a), __CAST8(__VA_ARGS__) +#define __CAST10(a ,...) __CAST_TO_U64(a), __CAST9(__VA_ARGS__) +#define __CAST11(a, ...) __CAST_TO_U64(a), __CAST10(__VA_ARGS__) +#define __CAST12(a, ...) __CAST_TO_U64(a), __CAST11(__VA_ARGS__) +/* tracepoints with more than 12 arguments will hit build error */ +#define CAST_TO_U64(...) CONCATENATE(__CAST, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__) + +#define UINTTYPE(size) \ + __typeof__(__builtin_choose_expr(size == 1, (u8)1, \ + __builtin_choose_expr(size == 2, (u16)2, \ + __builtin_choose_expr(size == 4, (u32)3, \ + __builtin_choose_expr(size == 8, (u64)4, \ + (void)5))))) + +#define UNPACK(...) __VA_ARGS__ +#define REPEAT_1(FN, DL, X, ...) FN(X) +#define REPEAT_2(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_1(FN, DL, __VA_ARGS__) +#define REPEAT_3(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_2(FN, DL, __VA_ARGS__) +#define REPEAT_4(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_3(FN, DL, __VA_ARGS__) +#define REPEAT_5(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_4(FN, DL, __VA_ARGS__) +#define REPEAT_6(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_5(FN, DL, __VA_ARGS__) +#define REPEAT_7(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_6(FN, DL, __VA_ARGS__) +#define REPEAT_8(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_7(FN, DL, __VA_ARGS__) +#define REPEAT_9(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_8(FN, DL, __VA_ARGS__) +#define REPEAT_10(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_9(FN, DL, __VA_ARGS__) +#define REPEAT_11(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_10(FN, DL, __VA_ARGS__) +#define REPEAT_12(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_11(FN, DL, __VA_ARGS__) +#define REPEAT(X, FN, DL, ...) REPEAT_##X(FN, DL, __VA_ARGS__) + +#define SARG(X) u64 arg##X +#ifdef COPY +#undef COPY +#endif + +#define COPY(X) args[X] = arg##X +#define __DL_COM (,) +#define __DL_SEM (;) + +#define __SEQ_0_11 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 + +#endif +#endif /* _LINUX_BPF_EVENT_H */ + diff --git a/include/trace/bpf_probe.h b/include/trace/bpf_probe.h index b04c29270973..5165dbc66098 100644 --- a/include/trace/bpf_probe.h +++ b/include/trace/bpf_probe.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#include + #undef TRACE_SYSTEM_VAR #ifdef CONFIG_BPF_EVENTS @@ -27,34 +29,6 @@ #undef __perf_task #define __perf_task(t) (t) -/* cast any integer, pointer, or small struct to u64 */ -#define UINTTYPE(size) \ - __typeof__(__builtin_choose_expr(size == 1, (u8)1, \ - __builtin_choose_expr(size == 2, (u16)2, \ - __builtin_choose_expr(size == 4, (u32)3, \ - __builtin_choose_expr(size == 8, (u64)4, \ - (void)5))))) -#define __CAST_TO_U64(x) ({ \ - typeof(x) __src = (x); \ - UINTTYPE(sizeof(x)) __dst; \ - memcpy(&__dst, &__src, sizeof(__dst)); \ - (u64)__dst; }) - -#define __CAST1(a,...) __CAST_TO_U64(a) -#define __CAST2(a,...) __CAST_TO_U64(a), __CAST1(__VA_ARGS__) -#define __CAST3(a,...) __CAST_TO_U64(a), __CAST2(__VA_ARGS__) -#define __CAST4(a,...) __CAST_TO_U64(a), __CAST3(__VA_ARGS__) -#define __CAST5(a,...) __CAST_TO_U64(a), __CAST4(__VA_ARGS__) -#define __CAST6(a,...) __CAST_TO_U64(a), __CAST5(__VA_ARGS__) -#define __CAST7(a,...) __CAST_TO_U64(a), __CAST6(__VA_ARGS__) -#define __CAST8(a,...) __CAST_TO_U64(a), __CAST7(__VA_ARGS__) -#define __CAST9(a,...) __CAST_TO_U64(a), __CAST8(__VA_ARGS__) -#define __CAST10(a,...) __CAST_TO_U64(a), __CAST9(__VA_ARGS__) -#define __CAST11(a,...) __CAST_TO_U64(a), __CAST10(__VA_ARGS__) -#define __CAST12(a,...) __CAST_TO_U64(a), __CAST11(__VA_ARGS__) -/* tracepoints with more than 12 arguments will hit build error */ -#define CAST_TO_U64(...) CONCATENATE(__CAST, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__) - #undef DECLARE_EVENT_CLASS #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ static notrace void \ diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index ffc91d4935ac..3fb02fe799ab 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1461,29 +1462,6 @@ void __bpf_trace_run(struct bpf_prog *prog, u64 *args) rcu_read_unlock(); } -#define UNPACK(...) __VA_ARGS__ -#define REPEAT_1(FN, DL, X, ...) FN(X) -#define REPEAT_2(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_1(FN, DL, __VA_ARGS__) -#define REPEAT_3(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_2(FN, DL, __VA_ARGS__) -#define REPEAT_4(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_3(FN, DL, __VA_ARGS__) -#define REPEAT_5(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_4(FN, DL, __VA_ARGS__) -#define REPEAT_6(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_5(FN, DL, __VA_ARGS__) -#define REPEAT_7(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_6(FN, DL, __VA_ARGS__) -#define REPEAT_8(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_7(FN, DL, __VA_ARGS__) -#define REPEAT_9(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_8(FN, DL, __VA_ARGS__) -#define REPEAT_10(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_9(FN, DL, __VA_ARGS__) -#define REPEAT_11(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_10(FN, DL, __VA_ARGS__) -#define REPEAT_12(FN, DL, X, ...) FN(X) UNPACK DL REPEAT_11(FN, DL, __VA_ARGS__) -#define REPEAT(X, FN, DL, ...) REPEAT_##X(FN, DL, __VA_ARGS__) - -#define SARG(X) u64 arg##X -#define COPY(X) args[X] = arg##X - -#define __DL_COM (,) -#define __DL_SEM (;) - -#define __SEQ_0_11 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 - #define BPF_TRACE_DEFN_x(x) \ void bpf_trace_run##x(struct bpf_prog *prog, \ REPEAT(x, SARG, __DL_COM, __SEQ_0_11)) \ From patchwork Fri Dec 20 15:41:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305829 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1DC9D14E3 for ; Fri, 20 Dec 2019 15:43:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F0B1124683 for ; Fri, 20 Dec 2019 15:43:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Za0Ik+yT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727489AbfLTPnG (ORCPT ); Fri, 20 Dec 2019 10:43:06 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:39804 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727414AbfLTPmI (ORCPT ); Fri, 20 Dec 2019 10:42:08 -0500 Received: by mail-wr1-f66.google.com with SMTP id y11so9846684wrt.6 for ; Fri, 20 Dec 2019 07:42:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6t1SoqwVuPN5RZrWbZ/JmprOHgDz/qxqketSjNkDxYQ=; b=Za0Ik+yT8Naldmi7JYTHp0+WuOF/mI5o4+6wTWn6WVqreRl0BuH5kZGrkAT65FqOhL ik4xff8Y0GYoREJjknBeExBw0poezt9BfP29XsTroIiGfvbmr3lTTPQvSc4q7cV48WMa JD9UHz8JdBAmhXmajPinQmLxnyjUaYDP/S4UE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6t1SoqwVuPN5RZrWbZ/JmprOHgDz/qxqketSjNkDxYQ=; b=qyDDVhiInDYb5h2PTuK4oO35KNx2rARIHfYLoe1+ybOwTQ5AkOkYObNxnae/VqZVEn eHe2iznjfGq+Z3xX0GDxyqT/oYjzuO7mv7cVWrMYW1bq+ZKpMQ49XtxwIONeKcOyfKT0 9FGRJwD2EZFGSPtVH1S6UYdy55zHLVJZLlOmSykbkoofjQm/Eyflnf+/wSf2tdR3Th0k C9818xFQAeT8Y+hRa8XjX10sXhQXjgm2mHNjl9R7wfcycsYYDBb0VDH6FxqhmdcrU0fP hIcXcYSPVZ/WUc8ysmWX/9pXpP2nLdnRrcOUHuzpa2v1OD31oN6fLLINo0TPTPuyWL3r NA6g== X-Gm-Message-State: APjAAAWMZYr+M2ygpbyhhM2xqqL3JEyW3gFJnq8CDOc/lBO9dYu3O+gK sXDoqA/zVRY7pF1jI1iywdUjMw== X-Google-Smtp-Source: APXvYqzUw2zZWd01RnFUny0Ejrm3QP4gMWGxtDfpl5hA1PwIuv83c3ZBZMhLU1YB2ifHyAALBcDveA== X-Received: by 2002:a5d:6349:: with SMTP id b9mr16641794wrw.346.1576856525938; Fri, 20 Dec 2019 07:42:05 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:05 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 02/13] bpf: lsm: Add a skeleton and config options Date: Fri, 20 Dec 2019 16:41:57 +0100 Message-Id: <20191220154208.15895-3-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh The LSM can be enabled by CONFIG_SECURITY_BPF. Without CONFIG_SECURITY_BPF_ENFORCE, the LSM will run the attached eBPF programs but not enforce MAC policy based on the return value of the attached programs. Signed-off-by: KP Singh Reviewed-by: James Morris --- MAINTAINERS | 7 +++++++ security/Kconfig | 11 ++++++----- security/Makefile | 2 ++ security/bpf/Kconfig | 25 +++++++++++++++++++++++++ security/bpf/Makefile | 5 +++++ security/bpf/lsm.c | 28 ++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 security/bpf/Kconfig create mode 100644 security/bpf/Makefile create mode 100644 security/bpf/lsm.c diff --git a/MAINTAINERS b/MAINTAINERS index 8f075b866aaf..3b82d8ff21fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3175,6 +3175,13 @@ S: Supported F: arch/x86/net/ X: arch/x86/net/bpf_jit_comp32.c +BPF SECURITY MODULE +M: KP Singh +L: linux-security-module@vger.kernel.org +L: bpf@vger.kernel.org +S: Maintained +F: security/bpf/ + BROADCOM B44 10/100 ETHERNET DRIVER M: Michael Chan L: netdev@vger.kernel.org diff --git a/security/Kconfig b/security/Kconfig index 2a1a2d396228..6f1aab195e7d 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -236,6 +236,7 @@ source "security/tomoyo/Kconfig" source "security/apparmor/Kconfig" source "security/loadpin/Kconfig" source "security/yama/Kconfig" +source "security/bpf/Kconfig" source "security/safesetid/Kconfig" source "security/lockdown/Kconfig" @@ -277,11 +278,11 @@ endchoice config LSM string "Ordered list of enabled LSMs" - default "lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK - default "lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR - default "lockdown,yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO - default "lockdown,yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC - default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" + default "lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK + default "lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR + default "lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO + default "lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC + default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf" help A comma-separated list of LSMs, in initialization order. Any LSMs left off this list will be ignored. This can be diff --git a/security/Makefile b/security/Makefile index be1dd9d2cb2f..50e6821dd7b7 100644 --- a/security/Makefile +++ b/security/Makefile @@ -12,6 +12,7 @@ subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown +subdir-$(CONFIG_SECURITY_BPF) += bpf # always enable default capabilities obj-y += commoncap.o @@ -29,6 +30,7 @@ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/ +obj-$(CONFIG_SECURITY_BPF) += bpf/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/bpf/Kconfig b/security/bpf/Kconfig new file mode 100644 index 000000000000..1aaa1340e795 --- /dev/null +++ b/security/bpf/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2019 Google LLC. + +config SECURITY_BPF + bool "BPF-based MAC and audit policy" + depends on SECURITY + depends on SECURITYFS + depends on BPF + depends on BPF_SYSCALL + help + This enables instrumentation of the security hooks with + eBPF programs. The LSM creates per-hook files in securityfs to which + eBPF programs can be attached. + + If you are unsure how to answer this question, answer N. + +config SECURITY_BPF_ENFORCE + bool "Deny operations based on the evaluation of the attached programs" + depends on SECURITY_BPF + help + eBPF programs attached to hooks can be used for both auditing and + enforcement. Enabling enforcement implies that the evaluation result + from the attached eBPF programs will allow or deny the operation + guarded by the security hook. diff --git a/security/bpf/Makefile b/security/bpf/Makefile new file mode 100644 index 000000000000..26a0ab6f99b7 --- /dev/null +++ b/security/bpf/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2019 Google LLC. + +obj-$(CONFIG_SECURITY_BPF) := lsm.o diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c new file mode 100644 index 000000000000..fe5c65bbdd45 --- /dev/null +++ b/security/bpf/lsm.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include + +static int process_execution(struct linux_binprm *bprm) +{ + return 0; +} + +static struct security_hook_list lsm_hooks[] __lsm_ro_after_init = { + LSM_HOOK_INIT(bprm_check_security, process_execution), +}; + +static int __init lsm_init(void) +{ + security_add_hooks(lsm_hooks, ARRAY_SIZE(lsm_hooks), "bpf"); + pr_info("eBPF and LSM are friends now.\n"); + return 0; +} + +DEFINE_LSM(bpf) = { + .name = "bpf", + .init = lsm_init, +}; From patchwork Fri Dec 20 15:41:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305825 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CBE2D139A for ; Fri, 20 Dec 2019 15:43:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A01AB24682 for ; Fri, 20 Dec 2019 15:43:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="RJtIT+M7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727422AbfLTPmK (ORCPT ); Fri, 20 Dec 2019 10:42:10 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:36206 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727469AbfLTPmJ (ORCPT ); Fri, 20 Dec 2019 10:42:09 -0500 Received: by mail-wm1-f66.google.com with SMTP id p17so9701221wma.1 for ; Fri, 20 Dec 2019 07:42:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=W3ikVYW2VHd7LIQCP37/NV9odo+wJGrACNZfFA7D07g=; b=RJtIT+M71DBSAz6HBmcqeDGoEFJnpaRfB3D1OWgMxlX6No49nBa97p0CrZRCeg+YmI EBf6iqD1S5sCoqauyOqOluyS9TZrzGwUnIrQ04zuz6icOhtJri7WSJB1z7AhuOx57PPa PTyNtY0+Na/YSdwN0shWHSYSW9CivxHkLwj6A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=W3ikVYW2VHd7LIQCP37/NV9odo+wJGrACNZfFA7D07g=; b=LwQCNmxWiCqJctkrW1oXtSOk6Ysl7jM8Pp86kgcP9hKTW5Voz7cwY1n9eBBCd+I7Wu 3A8i3Jclfp/h7PQ7qbahrqC4127+7MFcVFN5nkGHRl5If159OrMBq1estsGJRh0LAEaL hfROQJhEKk3Cul0zt9JrKKYwkrHgI1ZNTg8hblw4rxBx7xw97ocs9G2v+VDZGa5eeOph aI9J4lqFZYhv0rJEajbnHR990Vp4VmyGBNqa3EhSAs2L5wuXVEhbbUHWZRyxim7vzCeW Zxk7g8HpNtWVam6TAtQksqBW3qyUI/3slU/RT8wrjFmgxwG8s6CtV9oZFk/4Nsdy4bHH 1q5g== X-Gm-Message-State: APjAAAWjJ4G1nZQgRpb4kA8GxkRkiH3lYbqP3TM7fhMkKq5lCkq3mo+B p4kWvT+QZLFXZS9gbrEEc10D4Q== X-Google-Smtp-Source: APXvYqyVKsjtf80AQbpdWBOAeWsiNIXNCUAtx2pp1vsLceMqRMKQcroWanJ2rJpf4oA/3/lvTJTTZg== X-Received: by 2002:a7b:c407:: with SMTP id k7mr17559393wmi.46.1576856527148; Fri, 20 Dec 2019 07:42:07 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:06 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 03/13] bpf: lsm: Introduce types for eBPF based LSM Date: Fri, 20 Dec 2019 16:41:58 +0100 Message-Id: <20191220154208.15895-4-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh A new eBPF program type BPF_PROG_TYPE_LSM with an expected attach type of BPF_LSM_MAC. An -EINVAL error is returned if an attachment is currently requested. Signed-off-by: KP Singh --- include/linux/bpf_types.h | 4 ++++ include/uapi/linux/bpf.h | 2 ++ kernel/bpf/syscall.c | 6 ++++++ security/bpf/Makefile | 2 +- security/bpf/ops.c | 14 ++++++++++++++ tools/include/uapi/linux/bpf.h | 2 ++ 6 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 security/bpf/ops.c diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h index 93740b3614d7..5f48161529b4 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -65,6 +65,10 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LIRC_MODE2, lirc_mode2, BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport, struct sk_reuseport_md, struct sk_reuseport_kern) #endif +#ifdef CONFIG_SECURITY_BPF +BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm, + void *, void *) +#endif BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index dbbcf0b02970..fc64ae865526 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -174,6 +174,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_PROG_TYPE_TRACING, + BPF_PROG_TYPE_LSM, }; enum bpf_attach_type { @@ -203,6 +204,7 @@ enum bpf_attach_type { BPF_TRACE_RAW_TP, BPF_TRACE_FENTRY, BPF_TRACE_FEXIT, + BPF_LSM_MAC, __MAX_BPF_ATTACH_TYPE }; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index e3461ec59570..5a773fc6f9f5 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2096,6 +2096,9 @@ static int bpf_prog_attach(const union bpf_attr *attr) case BPF_LIRC_MODE2: ptype = BPF_PROG_TYPE_LIRC_MODE2; break; + case BPF_LSM_MAC: + ptype = BPF_PROG_TYPE_LSM; + break; case BPF_FLOW_DISSECTOR: ptype = BPF_PROG_TYPE_FLOW_DISSECTOR; break; @@ -2127,6 +2130,9 @@ static int bpf_prog_attach(const union bpf_attr *attr) case BPF_PROG_TYPE_LIRC_MODE2: ret = lirc_prog_attach(attr, prog); break; + case BPF_PROG_TYPE_LSM: + ret = -EINVAL; + break; case BPF_PROG_TYPE_FLOW_DISSECTOR: ret = skb_flow_dissector_bpf_prog_attach(attr, prog); break; diff --git a/security/bpf/Makefile b/security/bpf/Makefile index 26a0ab6f99b7..c78a8a056e7e 100644 --- a/security/bpf/Makefile +++ b/security/bpf/Makefile @@ -2,4 +2,4 @@ # # Copyright 2019 Google LLC. -obj-$(CONFIG_SECURITY_BPF) := lsm.o +obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o diff --git a/security/bpf/ops.c b/security/bpf/ops.c new file mode 100644 index 000000000000..2fa3ebdf598d --- /dev/null +++ b/security/bpf/ops.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include + +const struct bpf_prog_ops lsm_prog_ops = { +}; + +const struct bpf_verifier_ops lsm_verifier_ops = { +}; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index dbbcf0b02970..fc64ae865526 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -174,6 +174,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_PROG_TYPE_TRACING, + BPF_PROG_TYPE_LSM, }; enum bpf_attach_type { @@ -203,6 +204,7 @@ enum bpf_attach_type { BPF_TRACE_RAW_TP, BPF_TRACE_FENTRY, BPF_TRACE_FEXIT, + BPF_LSM_MAC, __MAX_BPF_ATTACH_TYPE }; From patchwork Fri Dec 20 15:41:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305827 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C3A176C1 for ; Fri, 20 Dec 2019 15:43:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 98F6324686 for ; Fri, 20 Dec 2019 15:43:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="VETjIrwl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727499AbfLTPnG (ORCPT ); Fri, 20 Dec 2019 10:43:06 -0500 Received: from mail-wm1-f67.google.com ([209.85.128.67]:36211 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727489AbfLTPmK (ORCPT ); Fri, 20 Dec 2019 10:42:10 -0500 Received: by mail-wm1-f67.google.com with SMTP id p17so9701322wma.1 for ; Fri, 20 Dec 2019 07:42:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lGbC4jtkbenMhpDKup9C3+jqzXEqt+dJgjev6KEIOek=; b=VETjIrwlgBW+OUmHFNDHX0Zw88OSzly/p7nHYWblLY6Sa7Mb0z/OHhmgj8gGVu3ziR NZiUBuYscoE9SQixKMWe+y5BYzC+o9rLeenQZY0PJ7YFdIMGpxEcVg1r43b2O2w9+q0u 0sNNIQWuzU9puQcbjPYK83aY2M9InywGj1AgA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=lGbC4jtkbenMhpDKup9C3+jqzXEqt+dJgjev6KEIOek=; b=W8iGDkmwsWKr2oKAJ8bM5/+aIlUdELnmULcKwA5Ey5Q4HR8yPm7MjwkOWkcrFWXjv2 vrtJ8h7NvQpmNtlIioMDnBSeNgSQxZvF4XHqLvI99DAem7sJqa4Do5qLHjQVMCE+lBtL 0CUVFBgzyeqJK6mEmKemVgJerPY+kHVUAxKqWMxzmkSffjVqAnQdBGMQMQukJm8kRRq0 6VENlaJ6rBtdKAcLt80OHGCAJBE6DEytaMcp5sJT97SdsXQp7N5SCLNCX5I9brnbvuEI Cu1HQLYuzrsPSwbQyaasqPQnHX7Cgg6/+rNrNUOlFMzZ1+b0r9jRd53rCGHWkD8zM40c eOQA== X-Gm-Message-State: APjAAAUu3hNUtn55JFpRW4htUPbsRR0Vt5LRexA5dVYAKQaxhDJ4k6DT pHRIOM7+kR1Y1mMOumcK8oaocw== X-Google-Smtp-Source: APXvYqwtrwTRJzANfCKqBfDMYFXH9/CapY3ImHpG/kCN7tNJtEhkLmU9gs6jlTYpwZFGZgFqOD9DQA== X-Received: by 2002:a1c:6809:: with SMTP id d9mr17402626wmc.70.1576856528490; Fri, 20 Dec 2019 07:42:08 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:08 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 04/13] bpf: lsm: Allow btf_id based attachment for LSM hooks Date: Fri, 20 Dec 2019 16:41:59 +0100 Message-Id: <20191220154208.15895-5-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh Refactor and re-use most of the logic for BPF_PROG_TYPE_TRACING with a few changes. - The LSM hook BTF types are prefixed with "lsm_btf_" - These types do not need the first (void *) pointer argument. The verifier only looks for this argument if prod->aux->attach_btf_trace is set. Signed-off-by: KP Singh --- kernel/bpf/syscall.c | 1 + kernel/bpf/verifier.c | 83 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 5a773fc6f9f5..4fcaf6042c07 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1642,6 +1642,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type, { switch (prog_type) { case BPF_PROG_TYPE_TRACING: + case BPF_PROG_TYPE_LSM: if (btf_id > BTF_MAX_TYPE) return -EINVAL; break; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a0482e1c4a77..0d1231d9c1ef 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9504,7 +9504,71 @@ static void print_verification_stats(struct bpf_verifier_env *env) env->peak_states, env->longest_mark_read_walk); } -static int check_attach_btf_id(struct bpf_verifier_env *env) +/* + * LSM hooks have a typedef associated with them. The BTF information for this + * type is used by the verifier to validate memory accesses made by the + * attached information. + * + * For example the: + * + * int bprm_check_security(struct linux_binprm *brpm) + * + * has the following typedef: + * + * typedef int (*lsm_btf_bprm_check_security)(struct linux_binprm *bprm); + */ +#define BTF_LSM_PREFIX "lsm_btf_" + +static inline int check_attach_btf_id_lsm(struct bpf_verifier_env *env) +{ + struct bpf_prog *prog = env->prog; + u32 btf_id = prog->aux->attach_btf_id; + const struct btf_type *t; + const char *tname; + + if (!btf_id) { + verbose(env, "LSM programs must provide btf_id\n"); + return -EINVAL; + } + + t = btf_type_by_id(btf_vmlinux, btf_id); + if (!t) { + verbose(env, "attach_btf_id %u is invalid\n", btf_id); + return -EINVAL; + } + + tname = btf_name_by_offset(btf_vmlinux, t->name_off); + if (!tname) { + verbose(env, "attach_btf_id %u doesn't have a name\n", btf_id); + return -EINVAL; + } + + if (!btf_type_is_typedef(t)) { + verbose(env, "attach_btf_id %u is not a typedef\n", btf_id); + return -EINVAL; + } + if (strncmp(BTF_LSM_PREFIX, tname, sizeof(BTF_LSM_PREFIX) - 1)) { + verbose(env, "attach_btf_id %u points to wrong type name %s\n", + btf_id, tname); + return -EINVAL; + } + + t = btf_type_by_id(btf_vmlinux, t->type); + /* should never happen in valid vmlinux build */ + if (!btf_type_is_ptr(t)) + return -EINVAL; + t = btf_type_by_id(btf_vmlinux, t->type); + /* should never happen in valid vmlinux build */ + if (!btf_type_is_func_proto(t)) + return -EINVAL; + + tname += sizeof(BTF_LSM_PREFIX) - 1; + prog->aux->attach_func_name = tname; + prog->aux->attach_func_proto = t; + return 0; +} + +static int check_attach_btf_id_tracing(struct bpf_verifier_env *env) { struct bpf_prog *prog = env->prog; struct bpf_prog *tgt_prog = prog->aux->linked_prog; @@ -9519,9 +9583,6 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) long addr; u64 key; - if (prog->type != BPF_PROG_TYPE_TRACING) - return 0; - if (!btf_id) { verbose(env, "Tracing programs must provide btf_id\n"); return -EINVAL; @@ -9659,6 +9720,20 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) } } +static int check_attach_btf_id(struct bpf_verifier_env *env) +{ + struct bpf_prog *prog = env->prog; + + switch (prog->type) { + case BPF_PROG_TYPE_TRACING: + return check_attach_btf_id_tracing(env); + case BPF_PROG_TYPE_LSM: + return check_attach_btf_id_lsm(env); + default: + return 0; + } +} + int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, union bpf_attr __user *uattr) { From patchwork Fri Dec 20 15:42:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305823 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 15D0C139A for ; Fri, 20 Dec 2019 15:43:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D520424680 for ; Fri, 20 Dec 2019 15:43:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="LSixZOBH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727567AbfLTPmz (ORCPT ); Fri, 20 Dec 2019 10:42:55 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:40473 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727469AbfLTPmM (ORCPT ); Fri, 20 Dec 2019 10:42:12 -0500 Received: by mail-wr1-f66.google.com with SMTP id c14so9826136wrn.7 for ; Fri, 20 Dec 2019 07:42:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=paRFHTiw/4aHrEDwPYYt5DNAc5B07BiR533ZjOOgfNA=; b=LSixZOBHgCAqq5f5I3USgUDTDjz3ai4Mcl5c54BhPwpOnGd00SVi46jrFyJI4O+YTj OfT49wqSAXZHqc35BN1589wYs++ESJgrkdVSEbxoEEeh1Z3QJqoYWCyEVtQxKDrRzv1f h2gBiz2+2tBGjZz/gZdnZ/yzKNgphy5Bd2KR8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=paRFHTiw/4aHrEDwPYYt5DNAc5B07BiR533ZjOOgfNA=; b=nSg+zci6rUpoIdzNDbAjKxrP8YhcIT4pmKWCPoX0t1zIliwwTPosSHabITAy16YOUT MbTf7fIdBawzjPrOF1DbYmS1zEu1CWPNcuNtQZ00S1C2I5vPhaga0cUxElfUOdKAmROr tsEHRdzzipEimAoN83fONFxQOCBTI0QQVjP7NtNclFNEUaEeDyDBKtYTn8OviVUwJVUr AG1fR96j2kQDCmsinxKEZGAiqXvNK0tvx9tirA9pMTYh55WUO4mPaxBBB41zjmRFNkWh dtORDJMm3uyW6kHX0BQotr4gyMIuk7oZFfJVsmFUPPw2TP0Vs8rKkqilG1qu9AEq7JxR f/Aw== X-Gm-Message-State: APjAAAVyessktOfAT3nf93USvBb09eeTsECSAqG7sEFgEv+ApLwXrXkK gKxrozwh5/Oua0sHQXZpMrbxbw== X-Google-Smtp-Source: APXvYqxUhzkZqdzoLus5OLbBOFCDlsljW/eOFBtyxNAMOKpkpK3KXKXVADOUkwzlSnIiq/UcP9kD2A== X-Received: by 2002:a5d:6a8e:: with SMTP id s14mr16505533wru.150.1576856529739; Fri, 20 Dec 2019 07:42:09 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:09 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM Date: Fri, 20 Dec 2019 16:42:00 +0100 Message-Id: <20191220154208.15895-6-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh 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 --- 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; } From patchwork Fri Dec 20 15:42:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305817 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 665FA6C1 for ; Fri, 20 Dec 2019 15:42:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 272932467F for ; Fri, 20 Dec 2019 15:42:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="HAUV7SFT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727615AbfLTPmQ (ORCPT ); Fri, 20 Dec 2019 10:42:16 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:38776 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727556AbfLTPmQ (ORCPT ); Fri, 20 Dec 2019 10:42:16 -0500 Received: by mail-wr1-f68.google.com with SMTP id y17so9867866wrh.5 for ; Fri, 20 Dec 2019 07:42:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=FUDtwe+tHTdIyYF0y1BKJlXUkUXphA4Xluv5daGuYQ8=; b=HAUV7SFTG23CnfApTAreWQAGw7ScReF/JhZiD0u3UJQJmZ5ahVx3v9kxWNIN6NlAeP fT65LiBfj5m6ncaMyYHIiq7IJ0s2K7vQGX07wls4XSGTGxB/i3cos5OR7jkf4gAaC7e9 7YLI7XKX2hA96BvUS+0vEAtbRwdLcYLAuO290= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=FUDtwe+tHTdIyYF0y1BKJlXUkUXphA4Xluv5daGuYQ8=; b=GpWtSTT0xNeyV2kQBZUJNYohn5AF71TzLAk1evZJbXGHB5FpKM/3x2npM0bgyO7ugv /OMOal8KYrSVVgUBErtiP+xWK0mVzCUONJmU3cV7/9hMCbqVBCnfKoMmQHM9lqGFRRL4 vpzg4IREdyx948xG6Fcz1MdntmJrCxsCMy6tnXankLMtfbpje3YNR2wYnzOvXRojF0cK Kvdg9kgXcNNXhELxQ0tRqL0yP44Xl4UR2hTEDq9M5alaYbYh6aY15VpScuvP48zUx3nb kc854OV465gI8VcLDncsK+K2+m3pRzKgPfLqBWRrcLWCMeXfO0kDvrpP+5aPNnF08xQ0 c+uw== X-Gm-Message-State: APjAAAX18iR5qZtl0bj3vLpA+cd2o6+sjnvnPovoz/UAES8T8XPrwuyi YcIqKUDSrTo1zv55nSTjf3kSEQ== X-Google-Smtp-Source: APXvYqyOFDfCVjajx8LYp+W4yrW50EsoTdd4rxixqncktY/UISuqbWd4kn+bmYsDPqMKh/fYdjF/PQ== X-Received: by 2002:adf:b648:: with SMTP id i8mr16207783wre.91.1576856531012; Fri, 20 Dec 2019 07:42:11 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:10 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs Date: Fri, 20 Dec 2019 16:42:01 +0100 Message-Id: <20191220154208.15895-7-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh The LSM creates files in securityfs for each hook registered with the LSM. /sys/kernel/security/bpf/ 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 Reviewed-by: James Morris --- 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 + +#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 +#include +#include +#include "fs.h" + +/* + * This enum indexes one of the LSM hooks defined in hooks.h. + * Each value of the enum is defined as _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 +#include +#include + +bool is_bpf_lsm_hook_file(struct file *f); + +/* + * The name of the directory created in securityfs + * + * /sys/kernel/security/ + */ +#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 +#include -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_ 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_ 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 +#include +#include +#include +#include +#include +#include + +#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); From patchwork Fri Dec 20 15:42:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305821 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C0C8B139A for ; Fri, 20 Dec 2019 15:42:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8BC642468D for ; Fri, 20 Dec 2019 15:42:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ILIcn9J7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727727AbfLTPmq (ORCPT ); Fri, 20 Dec 2019 10:42:46 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:43222 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727579AbfLTPmP (ORCPT ); Fri, 20 Dec 2019 10:42:15 -0500 Received: by mail-wr1-f68.google.com with SMTP id d16so9812357wre.10 for ; Fri, 20 Dec 2019 07:42:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=26xnb3yuodzvJ1GOX80TL/NTUMzeN/hcWJWSUPgYjvU=; b=ILIcn9J79FlT8818+aNbXNhk50sYcbV+kGDqSyLUn+qVfFlVVl4PbEomsmB8G+mSOJ 7HVcdPU/TXhyZcHGoOX6W2RZ4hja6cYG9ROG263qp7cyp1k9AYr73jLeSyWEASdUXLPy iTZH4ChZT//wxRl1PTQHmS8vt7ZfFK3rRalgI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=26xnb3yuodzvJ1GOX80TL/NTUMzeN/hcWJWSUPgYjvU=; b=WYbVj0FpXruyPVxP44RtUNK67m5poZmIeA5ozZFuIO1B5NMIbiVZjaFEr40hn8p/S1 YmVbBdVDNCPntRM+Pl4Li6ROFMoOpdZAwKY+m+2kaSuiTPY2FoA2+CJELUgxbUWGgShz MDKOmhVORab7lV7QUWokxX9pGSwkqEwMMmcLKsG9/LTmO5AihKcqYuojRT77uu5A77aP qNUST4U5No8fLbGZxga+zEEGVo64lG+IBvVLjruQ4T0J4C9MaFzL+pK5tqGoDxvuAvNo iBTV9JNYP2X7p30+NtLmbReWMz75VskRAKlFF08VBRmVcIAVRC6GMwCkp8MEw3tB1lb6 Pv7Q== X-Gm-Message-State: APjAAAUDbyals40ceBMf8yMyE0jvV9l/9CYqT+e3VGHhHYD3kLxwoMQf q0+/eUhUDRGaoqlia40nW8cwxg== X-Google-Smtp-Source: APXvYqx0SCWAGTWBEvQnNAPV9/Z+sh+xziw7OolJOaozCJhZq+TwINckqp4msLHVrwe7MrC50G83Uw== X-Received: by 2002:adf:de84:: with SMTP id w4mr15240542wrl.97.1576856532603; Fri, 20 Dec 2019 07:42:12 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:11 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 07/13] bpf: lsm: Implement attach, detach and execution. Date: Fri, 20 Dec 2019 16:42:02 +0100 Message-Id: <20191220154208.15895-8-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh A user space program can attach an eBPF program by: hook_fd = open("/sys/kernel/security/bpf/bprm_check_security", O_RDWR|O_CLOEXEC) prog_fd = bpf(BPF_PROG_LOAD, ...) bpf(BPF_PROG_ATTACH, hook_fd, prog_fd) The following permissions are required to attach a program to a hook: - CAP_SYS_ADMIN to load eBPF programs - CAP_MAC_ADMIN (to update the policy of an LSM) - The securityfs file being a valid hook and writable (O_RDWR) When such an attach call is received, the attachment logic looks up the dentry and appends the program to the bpf_prog_array. The BPF programs are stored in a bpf_prog_array and writes to the array are guarded by a mutex. The eBPF programs are executed as a part of the LSM hook they are attached to. If any of the eBPF programs return an error (-ENOPERM) the action represented by the hook is denied. Signed-off-by: KP Singh Acked-by: Andrii Nakryiko Reviewed-by: James Morris --- MAINTAINERS | 1 + include/linux/bpf_lsm.h | 13 ++++ kernel/bpf/syscall.c | 5 +- security/bpf/lsm_fs.c | 19 +++++- security/bpf/ops.c | 134 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3b82d8ff21fb..681ae39bb2f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3181,6 +3181,7 @@ L: linux-security-module@vger.kernel.org L: bpf@vger.kernel.org S: Maintained F: security/bpf/ +F: include/linux/bpf_lsm.h BROADCOM B44 10/100 ETHERNET DRIVER M: Michael Chan diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h index 76f81e642dc2..c029f2b8d6fd 100644 --- a/include/linux/bpf_lsm.h +++ b/include/linux/bpf_lsm.h @@ -7,6 +7,19 @@ #ifdef CONFIG_SECURITY_BPF extern int bpf_lsm_fs_initialized; +int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog); +int bpf_lsm_detach(const union bpf_attr *attr); +#else +static inline int bpf_lsm_attach(const union bpf_attr *attr, + struct bpf_prog *prog) +{ + return -EINVAL; +} + +static inline int bpf_lsm_detach(const union bpf_attr *attr) +{ + return -EINVAL; +} #endif /* CONFIG_SECURITY_BPF */ #endif /* _LINUX_BPF_LSM_H */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 4fcaf6042c07..8897b774973f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -2132,7 +2133,7 @@ static int bpf_prog_attach(const union bpf_attr *attr) ret = lirc_prog_attach(attr, prog); break; case BPF_PROG_TYPE_LSM: - ret = -EINVAL; + ret = bpf_lsm_attach(attr, prog); break; case BPF_PROG_TYPE_FLOW_DISSECTOR: ret = skb_flow_dissector_bpf_prog_attach(attr, prog); @@ -2200,6 +2201,8 @@ static int bpf_prog_detach(const union bpf_attr *attr) case BPF_CGROUP_SETSOCKOPT: ptype = BPF_PROG_TYPE_CGROUP_SOCKOPT; break; + case BPF_LSM_MAC: + return bpf_lsm_detach(attr); default: return -EINVAL; } diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c index 49165394ef7d..b271e9582d0f 100644 --- a/security/bpf/lsm_fs.c +++ b/security/bpf/lsm_fs.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -28,6 +30,19 @@ bool is_bpf_lsm_hook_file(struct file *f) static void __init free_hook(struct bpf_lsm_hook *h) { + struct bpf_prog_array_item *item; + /* + * This function is __init so we are guaranteed that there will be + * no concurrent access. + */ + struct bpf_prog_array *progs = rcu_dereference_raw(h->progs); + + if (progs) { + for (item = progs->items; item->prog; item++) + bpf_prog_put(item->prog); + bpf_prog_array_free(progs); + } + securityfs_remove(h->h_dentry); h->h_dentry = NULL; } @@ -36,8 +51,8 @@ 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); + h_dentry = securityfs_create_file(h->name, 0600, + parent, NULL, &hook_ops); if (IS_ERR(h_dentry)) return PTR_ERR(h_dentry); diff --git a/security/bpf/ops.c b/security/bpf/ops.c index 2fa3ebdf598d..eb8a8db28109 100644 --- a/security/bpf/ops.c +++ b/security/bpf/ops.c @@ -4,11 +4,145 @@ * Copyright 2019 Google LLC. */ +#include +#include #include #include +#include +#include + +#include "bpf_lsm.h" +#include "fs.h" + +static struct bpf_lsm_hook *get_hook_from_fd(int fd) +{ + struct bpf_lsm_hook *h; + struct fd f; + int ret; + + /* + * Only CAP_MAC_ADMIN users are allowed to make changes to LSM hooks + */ + if (!capable(CAP_MAC_ADMIN)) + return ERR_PTR(-EPERM); + + + f = fdget(fd); + if (!f.file) + return ERR_PTR(-EBADF); + + + if (!is_bpf_lsm_hook_file(f.file)) { + ret = -EINVAL; + goto error; + } + + /* + * It's wrong to attach the program to the hook if the file is not + * opened for a writing. Note that, this is an EBADF and not an EPERM + * because the file has been opened with an incorrect mode. + */ + if (!(f.file->f_mode & FMODE_WRITE)) { + ret = -EBADF; + goto error; + } + + /* + * The securityfs dentry never disappears, so we don't need to take a + * reference to it. + */ + h = file_dentry(f.file)->d_fsdata; + if (WARN_ON(!h)) { + ret = -EINVAL; + goto error; + } + fdput(f); + return h; + +error: + fdput(f); + return ERR_PTR(ret); +} + +int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog) +{ + struct bpf_prog_array *old_array; + struct bpf_prog_array *new_array; + struct bpf_lsm_hook *h; + int ret = 0; + + h = get_hook_from_fd(attr->target_fd); + if (IS_ERR(h)) + return PTR_ERR(h); + + mutex_lock(&h->mutex); + old_array = rcu_dereference_protected(h->progs, + lockdep_is_held(&h->mutex)); + + ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array); + if (ret < 0) + goto unlock; + + rcu_assign_pointer(h->progs, new_array); + bpf_prog_array_free(old_array); + +unlock: + mutex_unlock(&h->mutex); + return ret; +} + +int bpf_lsm_detach(const union bpf_attr *attr) +{ + struct bpf_prog_array *old_array, *new_array; + struct bpf_prog *prog; + struct bpf_lsm_hook *h; + int ret = 0; + + if (attr->attach_flags) + return -EINVAL; + + h = get_hook_from_fd(attr->target_fd); + if (IS_ERR(h)) + return PTR_ERR(h); + + prog = bpf_prog_get_type(attr->attach_bpf_fd, + BPF_PROG_TYPE_LSM); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + mutex_lock(&h->mutex); + old_array = rcu_dereference_protected(h->progs, + lockdep_is_held(&h->mutex)); + + ret = bpf_prog_array_copy(old_array, prog, NULL, &new_array); + if (ret) + goto unlock; + + rcu_assign_pointer(h->progs, new_array); + bpf_prog_array_free(old_array); +unlock: + bpf_prog_put(prog); + mutex_unlock(&h->mutex); + return ret; +} const struct bpf_prog_ops lsm_prog_ops = { }; +static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id + func_id, const struct bpf_prog *prog) +{ + switch (func_id) { + case BPF_FUNC_map_lookup_elem: + return &bpf_map_lookup_elem_proto; + case BPF_FUNC_get_current_pid_tgid: + return &bpf_get_current_pid_tgid_proto; + default: + return NULL; + } +} + const struct bpf_verifier_ops lsm_verifier_ops = { + .get_func_proto = get_bpf_func_proto, + .is_valid_access = btf_ctx_access, }; From patchwork Fri Dec 20 15:42:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305819 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D448D14E3 for ; Fri, 20 Dec 2019 15:42:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B349C2467F for ; Fri, 20 Dec 2019 15:42:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="CG0ZvaL7" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727494AbfLTPmQ (ORCPT ); Fri, 20 Dec 2019 10:42:16 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:42577 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727590AbfLTPmQ (ORCPT ); Fri, 20 Dec 2019 10:42:16 -0500 Received: by mail-wr1-f65.google.com with SMTP id q6so9816667wro.9 for ; Fri, 20 Dec 2019 07:42:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=sAPx/qSpknm81mAjK6n50HYFMwR3Dc07XTjZ/N5q/14=; b=CG0ZvaL7Wd/DINrzFx+GeaXy7K63Erl9nn+5LqdgxsYGqiksVxbrDXCAu0fVki91kB GtQSHKuvsDqmk2cvFiy4Jmigdc02sK/KydIMyIe9ttsFEfpjkI3RPrpYL/hJjPuoA0N7 JYlOP0PBy1DmUbV0WL051NdvQkki4QAFHG480= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=sAPx/qSpknm81mAjK6n50HYFMwR3Dc07XTjZ/N5q/14=; b=ndsBewVRaCOc7LKAk0G6tuHQTR+9beiPZs5EeaFUbbSUYr3lYySme6MSfV1w/M+D5J VLaks25BouMPhfuWSAHkLRIOnD4QoLmeAT7RrZ22wYl2j7uksm9WScmGENgR/CmI8QFb uOoicLKGrer4HFvTeYVzjqmZkrVCGAh91VEQDg7gAfCz90SpNWR7hv5lyAfnHn/G90Z2 /TmYxGfJl8PItmn3Gr0s1sNHAgqD8xuaV0aI70TMzn6cBf1PrUjoe8CAJM8NCiHo18X9 pytcbS6nRjNaDqIRV8E/1L5pTnQhNOHtIkJK7TMwqAqCC1ZaK18KPGEG9Q9wGwvFF9nI bXEQ== X-Gm-Message-State: APjAAAU03SyCWDT64BV+kEBnCu95Vcp2/pFW7rnaMrkJi5R5aHXbNLRG nJb4PYoTVbaUPe7joJdc9B7RZg== X-Google-Smtp-Source: APXvYqxw9sxOQDAQeXYFvHsJkOAe+9rfbeVVbI7uTVCrv/2zfc5kXXzi/J5NgL/9VhQqjLKQZkd8pQ== X-Received: by 2002:a5d:4045:: with SMTP id w5mr14951352wrp.59.1576856533909; Fri, 20 Dec 2019 07:42:13 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:13 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 08/13] bpf: lsm: Show attached program names in hook read handler. Date: Fri, 20 Dec 2019 16:42:03 +0100 Message-Id: <20191220154208.15895-9-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh For inspectability the system administrator should be able to view the list of active KRSI programs: bash # cat /sys/kernel/security/bpf/bprm_check_security bpf_prog1 Signed-off-by: KP Singh Reviewed-by: James Morris --- security/bpf/lsm_fs.c | 81 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c index b271e9582d0f..01a89bce1347 100644 --- a/security/bpf/lsm_fs.c +++ b/security/bpf/lsm_fs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,85 @@ static struct dentry *bpf_lsm_dir; -static const struct file_operations hook_ops = {}; +static void *seq_start(struct seq_file *m, loff_t *pos) + __acquires(RCU) +{ + struct bpf_prog_array_item *item; + struct bpf_prog_array *progs; + struct bpf_lsm_hook *h; + struct dentry *dentry; + + /* + * rcu_read_lock() must be held before any return statement because the + * stop() will always be called and thus call rcu_read_unlock() + */ + rcu_read_lock(); + + dentry = file_dentry(m->file); + h = dentry->d_fsdata; + if (WARN_ON(!h)) + return ERR_PTR(-EFAULT); + + progs = rcu_dereference(h->progs); + if (!progs) + return NULL; + + /* Assumes that no &dummy_bpf_prog entries exist */ + if ((*pos) >= bpf_prog_array_length(progs)) + return NULL; + + item = progs->items + *pos; + if (!item->prog) + return NULL; + + return item; +} + +static void *seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct bpf_prog_array_item *item = v; + + item++; + ++*pos; + + if (!item->prog) + return NULL; + + return item; +} + +static void seq_stop(struct seq_file *m, void *v) + __releases(RCU) +{ + rcu_read_unlock(); +} + +static int show_prog(struct seq_file *m, void *v) +{ + struct bpf_prog_array_item *item = v; + + seq_printf(m, "%s\n", item->prog->aux->name); + return 0; +} + +static const struct seq_operations hook_seq_ops = { + .show = show_prog, + .start = seq_start, + .next = seq_next, + .stop = seq_stop, +}; + +static int hook_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &hook_seq_ops); +} + +static const struct file_operations hook_ops = { + .open = hook_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; int bpf_lsm_fs_initialized; From patchwork Fri Dec 20 15:42:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305815 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6F37014E3 for ; Fri, 20 Dec 2019 15:42:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4D5E324682 for ; Fri, 20 Dec 2019 15:42:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="gaLV8Raq" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727698AbfLTPmh (ORCPT ); Fri, 20 Dec 2019 10:42:37 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:34236 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727608AbfLTPmR (ORCPT ); Fri, 20 Dec 2019 10:42:17 -0500 Received: by mail-wm1-f65.google.com with SMTP id c127so2047713wme.1 for ; Fri, 20 Dec 2019 07:42:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CYWJ2URo8mjs0x8nMZWhI4jpk+MpL4wZVs4eBeXrsUE=; b=gaLV8RaqsIk6PcheutwFOcwCTJTOq+9pY0YnqLS9Xr93Q6kmHhWykg7wh6QBTREgG/ Q1ZxTakEI+XXkWBgO3FP19dUWHEKr00AV9goO9XBHAvtb52oMkP4GoZrjJwGS8BGgFji h9oePflZ4Ps1KAlC+m+cMvbA0ELtIGKOq+cys= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CYWJ2URo8mjs0x8nMZWhI4jpk+MpL4wZVs4eBeXrsUE=; b=huo5eaYcFMtKp0GXa5ZKqYHbp4thzjYntw2DFORedfDDLb4/m4wtuznCcd37nULyy5 VqywSFh90oVVmu8l2++iHyT0DOeauvgDAdPWh7LYUfxq3WQswjaqNq6gMjqE5lInAUif xeKkAYhd9TFMAT2yWFcrkJ773HhVJLt6nBqobBqKsnJ3JR58GjBwz4VmRaLcx6duCqTn txhvMSaNNnrGp2tXxoZ2RKFQ0pCU4zQ1JjbqXH+r29OOJvVLLVvow583ptLJOEowDSMu vTxDQhkXIzERQu46l33/9I8tE9Jd93R0+Wnx4a3xd58wMlvy13xuxdDwKCOSbjwEv0O9 SYmg== X-Gm-Message-State: APjAAAWh3LXvXPv6geXnqIH4sanhHzZBXnw9LbsOFwImshyGfMOx7H4c Nhk4+lbEkOtI1bpmnBK+nuWnCw== X-Google-Smtp-Source: APXvYqxza4vYJuCwfGbOtBIg2+UIbNuLIe8LlwTs049KCCz0BjChZd60j+gUte33pdPrBrNKcZPDLg== X-Received: by 2002:a7b:c775:: with SMTP id x21mr10365683wmk.59.1576856535130; Fri, 20 Dec 2019 07:42:15 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:14 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 09/13] bpf: lsm: Add a helper function bpf_lsm_event_output Date: Fri, 20 Dec 2019 16:42:04 +0100 Message-Id: <20191220154208.15895-10-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh This helper is similar to bpf_perf_event_output except that it does need a ctx argument which is more usable in the BTF based LSM programs where the context is converted to the signature of the attacthed BTF type. An example usage of this function would be: struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __uint(key_size, sizeof(int)); __uint(value_size, sizeof(u32)); } perf_map SEC(".maps"); BPF_TRACE_1(bpf_prog1, "lsm/bprm_check_security, struct linux_binprm *, bprm) { char buf[BUF_SIZE]; int len; u64 flags = BPF_F_CURRENT_CPU; /* some logic that fills up buf with len data */ len = fill_up_buf(buf); if (len < 0) return len; if (len > BU) return 0; bpf_lsm_event_output(&perf_map, flags, buf, len); return 0; } Signed-off-by: KP Singh --- include/uapi/linux/bpf.h | 10 +++++++++- kernel/bpf/verifier.c | 1 + security/bpf/ops.c | 21 +++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 10 +++++++++- 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index fc64ae865526..3511fa271c9b 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -2823,6 +2823,13 @@ union bpf_attr { * Return * On success, the strictly positive length of the string, including * the trailing NUL character. On error, a negative value. + * + * int bpf_lsm_event_output(struct bpf_map *map, u64 flags, void *data, u64 size) + * Description + * This helper is similar to bpf_perf_event_output except that it + * it does not need a context argument. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2940,7 +2947,8 @@ union bpf_attr { FN(probe_read_user), \ FN(probe_read_kernel), \ FN(probe_read_user_str), \ - FN(probe_read_kernel_str), + FN(probe_read_kernel_str), \ + FN(lsm_event_output), \ /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0d1231d9c1ef..ff050fd71e9f 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3641,6 +3641,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env, if (func_id != BPF_FUNC_perf_event_read && func_id != BPF_FUNC_perf_event_output && func_id != BPF_FUNC_skb_output && + func_id != BPF_FUNC_lsm_event_output && func_id != BPF_FUNC_perf_event_read_value) goto error; break; diff --git a/security/bpf/ops.c b/security/bpf/ops.c index eb8a8db28109..e9aae2ce718c 100644 --- a/security/bpf/ops.c +++ b/security/bpf/ops.c @@ -129,6 +129,25 @@ int bpf_lsm_detach(const union bpf_attr *attr) const struct bpf_prog_ops lsm_prog_ops = { }; +BPF_CALL_4(bpf_lsm_event_output, + struct bpf_map *, map, u64, flags, void *, data, u64, size) +{ + if (unlikely(flags & ~(BPF_F_INDEX_MASK))) + return -EINVAL; + + return bpf_event_output(map, flags, data, size, NULL, 0, NULL); +} + +static const struct bpf_func_proto bpf_lsm_event_output_proto = { + .func = bpf_lsm_event_output, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_CONST_MAP_PTR, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_PTR_TO_MEM, + .arg4_type = ARG_CONST_SIZE_OR_ZERO, +}; + static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -137,6 +156,8 @@ static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id return &bpf_map_lookup_elem_proto; case BPF_FUNC_get_current_pid_tgid: return &bpf_get_current_pid_tgid_proto; + case BPF_FUNC_lsm_event_output: + return &bpf_lsm_event_output_proto; default: return NULL; } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index fc64ae865526..3511fa271c9b 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2823,6 +2823,13 @@ union bpf_attr { * Return * On success, the strictly positive length of the string, including * the trailing NUL character. On error, a negative value. + * + * int bpf_lsm_event_output(struct bpf_map *map, u64 flags, void *data, u64 size) + * Description + * This helper is similar to bpf_perf_event_output except that it + * it does not need a context argument. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2940,7 +2947,8 @@ union bpf_attr { FN(probe_read_user), \ FN(probe_read_kernel), \ FN(probe_read_user_str), \ - FN(probe_read_kernel_str), + FN(probe_read_kernel_str), \ + FN(lsm_event_output), \ /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call From patchwork Fri Dec 20 15:42:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305813 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 41BE36C1 for ; Fri, 20 Dec 2019 15:42:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 20C402465E for ; Fri, 20 Dec 2019 15:42:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="mPg4tSkV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727639AbfLTPmT (ORCPT ); Fri, 20 Dec 2019 10:42:19 -0500 Received: from mail-wm1-f68.google.com ([209.85.128.68]:38290 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727618AbfLTPmS (ORCPT ); Fri, 20 Dec 2019 10:42:18 -0500 Received: by mail-wm1-f68.google.com with SMTP id u2so9682200wmc.3 for ; Fri, 20 Dec 2019 07:42:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0HkMzNoMVPiVpqpbSBCK+53bDNIFc61jgux3uZuo+QQ=; b=mPg4tSkVAdYB6gDrbbk4elkEX+LPkWpPTJcDyBhaI6hW5XdDtpHApUBN2ptv1uG6ki KqAuzf4gGEJnzn33e/H1WO0mEPWb7MbbF52y4qM6hv3VtNiDFd7ytjY5FJmEo5r32kLF 7CxMEu6iOrStK4WRHGxCEjTrBisvJB9YeIDv8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0HkMzNoMVPiVpqpbSBCK+53bDNIFc61jgux3uZuo+QQ=; b=AZf2FsCW43M1TbmG+TWB5ykPCgONUqs71Z63X3zUoU3ylh0cQx27jz7HKnPI1Lf9yv iC7CswbEU+Vg0ONJ8CEH8MHvGpBGpOErbffIA8rqjV/fdI1xJpYj1MHzk541mLHnY6EC acc+UgpnfxVLI1ptf4d1Jp2ZOCMMh8DlJ9tWuz2WUA321aEPkI7Jji62McaeBqYGcIG3 CCn9aOhXnFz9FjZqJlMTtTf27JsE1scTmPFi0upODdMvJyOBzAurbwrzYufkv1dhra+u XBOFy+miGzIufp13nK+RTQsGFIT5VYQwXstKPQXd+lz6reOsqfJ6kRoQ67peWyq4EzmQ S1/A== X-Gm-Message-State: APjAAAXRx6lp66SoyzI+m4e6gAB8+AvHyTT6eDme9X1xkXsH75d1g06g qi7aZIF7oC7frbYfi2CwP0yDAw== X-Google-Smtp-Source: APXvYqxk+DJG/ss1hnX5rJ1ggq2B9xRnZK9Mh5Bwa3L8cfr8gTj+2bW+JKB0ebSOUshdoP7oURpSHg== X-Received: by 2002:a1c:7d93:: with SMTP id y141mr17776295wmc.111.1576856536353; Fri, 20 Dec 2019 07:42:16 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:15 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 10/13] bpf: lsm: Handle attachment of the same program Date: Fri, 20 Dec 2019 16:42:05 +0100 Message-Id: <20191220154208.15895-11-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh Allow userspace to attach a newer version of a program without having duplicates of the same program. If BPF_F_ALLOW_OVERRIDE is passed, the attachment logic compares the name of the new program to the names of existing attached programs. The names are only compared till a "__" (or '\0', if there is no "__"). If a successful match is found, the existing program is replaced with the newer attachment. ./loader Attaches "env_dumper__v1" followed by "env_dumper__v2" to the bprm_check_security hook.. ./loader ./loader Before: cat /sys/kernel/security/bpf/process_execution env_dumper__v1 env_dumper__v2 After: cat /sys/kernel/security/bpf/process_execution env_dumper__v2 Signed-off-by: KP Singh Reviewed-by: James Morris --- security/bpf/ops.c | 57 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/security/bpf/ops.c b/security/bpf/ops.c index e9aae2ce718c..481e6ee75f27 100644 --- a/security/bpf/ops.c +++ b/security/bpf/ops.c @@ -64,11 +64,52 @@ static struct bpf_lsm_hook *get_hook_from_fd(int fd) return ERR_PTR(ret); } +/* + * match_prog_name matches the name of the program till "__" + * or the end of the string is encountered. This allows + * the matched program to be replaced by a newer version. + * + * For example: + * + * env_dumper__v1 is matched with env_dumper__v2 + * + */ +static bool match_prog_name(const char *a, const char *b) +{ + size_t m, n; + char *end; + + end = strstr(a, "__"); + n = end ? end - a : strlen(a); + + end = strstr(b, "__"); + m = end ? end - b : strlen(b); + + if (m != n) + return false; + + return strncmp(a, b, n) == 0; +} + +static struct bpf_prog *find_attached_prog(struct bpf_prog_array *array, + struct bpf_prog *prog) +{ + struct bpf_prog_array_item *item = array->items; + + for (; item->prog; item++) { + if (match_prog_name(item->prog->aux->name, prog->aux->name)) + return item->prog; + } + + return NULL; +} + int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog) { struct bpf_prog_array *old_array; struct bpf_prog_array *new_array; struct bpf_lsm_hook *h; + struct bpf_prog *old_prog = NULL; int ret = 0; h = get_hook_from_fd(attr->target_fd); @@ -78,13 +119,27 @@ int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog) mutex_lock(&h->mutex); old_array = rcu_dereference_protected(h->progs, lockdep_is_held(&h->mutex)); + /* + * Check if a matching program already exists and replace + * the existing program if BPF_F_ALLOW_OVERRIDE is specified in + * the attach flags. + */ + if (old_array) { + old_prog = find_attached_prog(old_array, prog); + if (old_prog && !(attr->attach_flags & BPF_F_ALLOW_OVERRIDE)) { + ret = -EEXIST; + goto unlock; + } + } - ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array); + ret = bpf_prog_array_copy(old_array, old_prog, prog, &new_array); if (ret < 0) goto unlock; rcu_assign_pointer(h->progs, new_array); bpf_prog_array_free(old_array); + if (old_prog) + bpf_prog_put(old_prog); unlock: mutex_unlock(&h->mutex); From patchwork Fri Dec 20 15:42:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305809 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E7E226C1 for ; Fri, 20 Dec 2019 15:42:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BC7E021655 for ; Fri, 20 Dec 2019 15:42:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ekYYzsl5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727659AbfLTPmX (ORCPT ); Fri, 20 Dec 2019 10:42:23 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:37464 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727629AbfLTPmU (ORCPT ); Fri, 20 Dec 2019 10:42:20 -0500 Received: by mail-wr1-f68.google.com with SMTP id w15so9875469wru.4 for ; Fri, 20 Dec 2019 07:42:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5zWF1EvSsIPmLOxhaJXNA5ILlHc0a+yRKkyOT6dTzZ0=; b=ekYYzsl5m79LwnzVS7qykSQ/bDpL/PQ3sz6ILbns2uGcBdHs9gFfdJCiZU35xAZvBt ALSFkkfruiwXpSdgmiS+xMCO3kqNS44kbO5+hwzdk3Xqh5cdHWQhqi2L6d2gr9RCm/fl O5KtaLptB41j8CC4qrlMKbhgZ90Xylo/7IOfg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5zWF1EvSsIPmLOxhaJXNA5ILlHc0a+yRKkyOT6dTzZ0=; b=ociMvBDkddMNFtLZ45v5HcNKGY8+AfzwkaA6aDVlEd3ggCEB4XeKeM/JuDkLxH9Wc6 mKdeS8ma2zVMJYVIjm/BD2tKQPBlD7/iDpwffcWRk39DvA0IIUzxVns4WY0kOPU9HDtU vs/6nucrDeqUzGg4MgWKR8Pu2JfPJW4VjO66ed7UUECH+pN3TUUo3st8jm2meU7kW9Sg fmG6pM96TPtx4pAf86z5dGjti24Za6XU5wWVp+DiL/VlmGA85dnuzahzBXNkyK8kw8+6 HqmZ2/rzpd3yOeJBR5u6ZLUveafX1eHUq16WPAPnlP5TNaUy4ihRLBcvTyzVWqauv3xK n/rg== X-Gm-Message-State: APjAAAUuxPNAXHDgy/kvR8BsJBcbP/fRlE6lFlpMcsv/lc2+PoA1MHr0 c55lUiiEs4YmZtRl4OpGZJN1Cg== X-Google-Smtp-Source: APXvYqwhzZbMjbi+ZJg+l9hDKucUyaSA8WMPRiw5JVHGlJMxsqgRYJf0NTeCQOf2APAkXBjQt/dlOA== X-Received: by 2002:a5d:5283:: with SMTP id c3mr16601729wrv.148.1576856537603; Fri, 20 Dec 2019 07:42:17 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:17 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 11/13] tools/libbpf: Add bpf_program__attach_lsm Date: Fri, 20 Dec 2019 16:42:06 +0100 Message-Id: <20191220154208.15895-12-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh Add functionality in libbpf to attach eBPF program to LSM hooks. Signed-off-by: KP Singh Reviewed-by: James Morris --- tools/lib/bpf/libbpf.c | 127 +++++++++++++++++++++++++++++++++++++-- tools/lib/bpf/libbpf.h | 2 + tools/lib/bpf/libbpf.map | 1 + 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index b0b27d8e5a37..ab2b23b4f21f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -5122,8 +5122,8 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, return -ESRCH; } -static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name, - const char *prefix) +static inline int __btf__type_with_prefix(struct btf *btf, const char *name, + const char *prefix) { size_t prefix_len = strlen(prefix); @@ -5149,9 +5149,9 @@ int libbpf_find_vmlinux_btf_id(const char *name, } if (attach_type == BPF_TRACE_RAW_TP) - err = __btf__typdef_with_prefix(btf, name, BTF_TRACE_PREFIX); + err = __btf__type_with_prefix(btf, name, BTF_TRACE_PREFIX); else if (attach_type == BPF_LSM_MAC) - err = __btf__typdef_with_prefix(btf, name, BTF_LSM_PREFIX); + err = __btf__type_with_prefix(btf, name, BTF_LSM_PREFIX); else err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC); @@ -5502,6 +5502,18 @@ struct bpf_link_fd { int fd; /* hook FD */ }; +/* + * The other attach types allow the link to be destroyed by using an ioctl or + * an operation on some file descriptor that describes the attachment. An LSM + * hook can have multiple programs attached to each hook, so the link needs to + * specify the program that must be detached when the link is destroyed. + */ +struct bpf_link_lsm { + struct bpf_link link; + int hook_fd; + int prog_fd; +}; + static int bpf_link__destroy_perf_event(struct bpf_link *link) { struct bpf_link_fd *l = (void *)link; @@ -5876,6 +5888,113 @@ struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog) return (struct bpf_link *)link; } + +static int bpf_link__destroy_lsm(struct bpf_link *link) +{ + struct bpf_link_lsm *ll = container_of(link, struct bpf_link_lsm, link); + char errmsg[STRERR_BUFSIZE]; + int ret; + + ret = bpf_prog_detach2(ll->prog_fd, ll->hook_fd, BPF_LSM_MAC); + if (ret < 0) { + ret = -errno; + pr_warn("failed to detach from hook: %s\n", + libbpf_strerror_r(ret, errmsg, sizeof(errmsg))); + return ret; + } + close(ll->hook_fd); + return 0; +} + +static const char *__lsm_hook_name(const char *title) +{ + + int i; + + if (!title) + return ERR_PTR(-EINVAL); + + for (i = 0; i < ARRAY_SIZE(section_names); i++) { + if (section_names[i].prog_type != BPF_PROG_TYPE_LSM) + continue; + + if (strncmp(title, section_names[i].sec, + section_names[i].len)) { + pr_warn("title for a LSM prog must begin with '%s'\n", + section_names[i].sec); + return ERR_PTR(-EINVAL); + } + + return title + section_names[i].len; + } + + pr_warn("could not find section information for BPF_PROG_TYPE_LSM\n"); + return ERR_PTR(-ESRCH); +} + +struct bpf_link *bpf_program__attach_lsm(struct bpf_program *prog) +{ + char hook_path[PATH_MAX] = "/sys/kernel/security/bpf/"; + const char *title, *hook_name; + char errmsg[STRERR_BUFSIZE]; + int prog_fd, target_fd, ret; + struct bpf_link_lsm *link; + + title = bpf_program__title(prog, false); + if (IS_ERR(title)) { + pr_warn("could not determine title of the program\n"); + return ERR_PTR(-EINVAL); + } + + hook_name = __lsm_hook_name(title); + if (IS_ERR(hook_name)) { + pr_warn("could not determine LSM hook name from title '%s'\n", + title); + return ERR_PTR(-EINVAL); + } + + prog_fd = bpf_program__fd(prog); + if (prog_fd < 0) { + pr_warn("program '%s': can't attach before loaded\n", title); + return ERR_PTR(-EINVAL); + } + + link = malloc(sizeof(*link)); + if (!link) + return ERR_PTR(-ENOMEM); + link->link.destroy = &bpf_link__destroy_lsm; + + /* Attach the BPF program to the given hook */ + strncat(hook_path, hook_name, + sizeof(hook_path) - (strlen(hook_path) + 1)); + target_fd = open(hook_path, O_RDWR); + if (target_fd < 0) { + ret = -errno; + pr_warn("program '%s': failed to open to hook '%s': %s\n", + title, hook_path, + libbpf_strerror_r(ret, errmsg, sizeof(errmsg))); + return ERR_PTR(ret); + } + + ret = bpf_prog_attach(prog_fd, target_fd, BPF_LSM_MAC, + BPF_F_ALLOW_OVERRIDE); + if (ret < 0) { + ret = -errno; + pr_warn("program '%s': failed to attach to hook '%s': %s\n", + title, hook_name, + libbpf_strerror_r(ret, errmsg, sizeof(errmsg))); + goto error; + } + + link->hook_fd = target_fd; + link->prog_fd = prog_fd; + return &link->link; + +error: + close(target_fd); + return ERR_PTR(ret); +} + enum bpf_perf_event_ret bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size, void **copy_mem, size_t *copy_size, diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 9cd69d602c82..655f27ad6ece 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -256,6 +256,8 @@ bpf_program__attach_raw_tracepoint(struct bpf_program *prog, LIBBPF_API struct bpf_link * bpf_program__attach_trace(struct bpf_program *prog); +LIBBPF_API struct bpf_link * +bpf_program__attach_lsm(struct bpf_program *prog); struct bpf_insn; /* diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 3d396149755d..5d64ba9b2a43 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -213,4 +213,5 @@ LIBBPF_0.0.7 { global: bpf_program__is_lsm; bpf_program__set_lsm; + bpf_program__attach_lsm; } LIBBPF_0.0.6; From patchwork Fri Dec 20 15:42:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305811 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5655E14E3 for ; Fri, 20 Dec 2019 15:42:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2B3C82465E for ; Fri, 20 Dec 2019 15:42:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="WKw3HQHg" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727497AbfLTPmX (ORCPT ); Fri, 20 Dec 2019 10:42:23 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:46254 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727650AbfLTPmW (ORCPT ); Fri, 20 Dec 2019 10:42:22 -0500 Received: by mail-wr1-f66.google.com with SMTP id z7so9800665wrl.13 for ; Fri, 20 Dec 2019 07:42:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yc9ODbRkpfKhA+Bxs3/DUYVIlQWXjVZp723Z2EeGdZc=; b=WKw3HQHg8X+hta1mRj20MRUciozMczPH5i128KkU11Y/6Nfc2CEQ+6Ypk95wkKHT7r trfBNwxwBNf8iNEWqfH6SHFqHARVSDKiAIyucpNqWzGpe/cejc3LEOlUuUqu66H6ummD 1X6RfGF7NJWW0klqQLrlq2ImKsEQBIB5k4ojE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yc9ODbRkpfKhA+Bxs3/DUYVIlQWXjVZp723Z2EeGdZc=; b=VsoW+x6MGUbt1jiACKJFFDl7Zan9G/Z6/zW0sSKA1AM2iP1WVXRo4L+UtaHYNkteol T644JvWmPOffoS+gxnk2LqWaXW1E4ZoVEyJIQVp9saSANNLdm7vq+C6a1fq+M3J3/f0r ls1xLtNJF6BnvL+Nqv8E39AIZvAYEcNFKmM+LHq5w1wLpK588Ve3PnLMUcy/qBNJ7j4g U+JCNH/PZQ6tkLZ6nzvDxQo4yHq6PyeN/Qgtu9WPYlXMexXFVQosAE2XPnoPOTDBk857 c0gLNLy+1j7rYXCgxlbSP+50OcekRtUUOClm8APwIaso5V0k7NRDc8ZxcJshTyxid2TM SEkQ== X-Gm-Message-State: APjAAAVBzW7UA/hYrmHrnzV3AEkSa2ch75rHCH9SBkiWessNqUu4auyd bvH1Ax9GQT1bNj6sbm1KCQ586g== X-Google-Smtp-Source: APXvYqzZ/HeRiZyZqrHoGSRsTXmhTrhLhDdpjhDTQVQ/O6PcFtqYk1+XLqNQTXzXh0J3Va+0rBVjAQ== X-Received: by 2002:a05:6000:11c3:: with SMTP id i3mr15758099wrx.244.1576856539446; Fri, 20 Dec 2019 07:42:19 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:18 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 12/13] bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM Date: Fri, 20 Dec 2019 16:42:07 +0100 Message-Id: <20191220154208.15895-13-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh * Load a BPF program that audits mprotect calls * Attach the program to the "file_mprotect" LSM hook * Verify if the program is actually loading by reading securityfs * Initialize the perf events buffer and poll for audit events * Do an mprotect on some memory allocated on the heap * Verify if the audit event was received Signed-off-by: KP Singh Reviewed-by: James Morris --- MAINTAINERS | 2 + .../bpf/prog_tests/lsm_mprotect_audit.c | 129 ++++++++++++++++++ .../selftests/bpf/progs/lsm_mprotect_audit.c | 58 ++++++++ 3 files changed, 189 insertions(+) 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 diff --git a/MAINTAINERS b/MAINTAINERS index 681ae39bb2f0..652c93292ae9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3182,6 +3182,8 @@ L: bpf@vger.kernel.org S: Maintained F: security/bpf/ F: include/linux/bpf_lsm.h +F: tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c +F: tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c BROADCOM B44 10/100 ETHERNET DRIVER M: Michael Chan diff --git a/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c b/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c new file mode 100644 index 000000000000..953531cec9fd --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include +#include +#include + +#define EXPECTED_PROG_NAME "mprotect_audit" +#define MPROTECT_AUDIT_MAGIC 0xDEAD + +struct mprotect_audit_log { + int is_heap, magic; +}; + +static void on_sample(void *ctx, int cpu, void *data, __u32 size) +{ + struct mprotect_audit_log *audit_log = data; + int duration = 0; + + if (audit_log->magic != MPROTECT_AUDIT_MAGIC) + return; + + if (CHECK(audit_log->is_heap != 1, "mprotect on heap", + "is_heap = %d\n", audit_log->is_heap)) + return; + + *(bool *)ctx = true; +} + +int heap_mprotect(void) +{ + void *buf; + long sz; + + sz = sysconf(_SC_PAGESIZE); + if (sz < 0) + return sz; + + buf = memalign(sz, 2 * sz); + if (buf == NULL) + return -ENOMEM; + + return mprotect(buf, sz, PROT_READ | PROT_EXEC); +} + +void test_lsm_mprotect_audit(void) +{ + struct bpf_prog_load_attr attr = { + .file = "./lsm_mprotect_audit.o", + }; + + struct perf_buffer_opts pb_opts = {}; + struct perf_buffer *pb = NULL; + struct bpf_link *link = NULL; + struct bpf_map *perf_buf_map; + struct bpf_object *prog_obj; + struct bpf_program *prog; + int err, prog_fd, sfs_fd; + char sfs_buf[1024]; + int duration = 0; + bool passed = false; + + err = bpf_prog_load_xattr(&attr, &prog_obj, &prog_fd); + if (CHECK(err, "prog_load lsm/file_mprotect", + "err %d errno %d\n", err, errno)) + goto close_prog; + + prog = bpf_object__find_program_by_title(prog_obj, "lsm/file_mprotect"); + if (CHECK(!prog, "find_prog", "lsm/file_mprotect not found\n")) + goto close_prog; + + link = bpf_program__attach_lsm(prog); + if (CHECK(IS_ERR(link), "attach_lsm file_mprotect", + "err %ld\n", PTR_ERR(link))) + goto close_prog; + + sfs_fd = open("/sys/kernel/security/bpf/file_mprotect", O_RDONLY); + if (CHECK(sfs_fd < 0, "sfs_open file_mprotect", + "err %d errno %d\n", sfs_fd, errno)) + goto close_prog; + + err = read(sfs_fd, sfs_buf, sizeof(sfs_buf)); + if (CHECK(err < 0, "sfs_read file_mprotect", + "err %d errno %d\n", sfs_fd, errno)) + goto close_prog; + + err = strncmp(sfs_buf, EXPECTED_PROG_NAME, strlen(EXPECTED_PROG_NAME)); + if (CHECK(err != 0, + "sfs_read value", "want = %s, got = %s\n", + EXPECTED_PROG_NAME, sfs_buf)) + goto close_prog; + + perf_buf_map = bpf_object__find_map_by_name(prog_obj, "perf_buf_map"); + if (CHECK(!perf_buf_map, "find_perf_buf_map", "not found\n")) + goto close_prog; + + /* set up perf buffer */ + pb_opts.sample_cb = on_sample; + pb_opts.ctx = &passed; + pb = perf_buffer__new(bpf_map__fd(perf_buf_map), 1, &pb_opts); + if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb))) + goto close_prog; + + err = heap_mprotect(); + if (CHECK(err < 0, "heap_mprotect", + "err %d errno %d\n", err, errno)) + goto close_prog; + + /* read perf buffer */ + err = perf_buffer__poll(pb, 100); + if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err)) + goto close_prog; + + /* + * make sure mprotect_audit program was triggered + * and detected an mprotect on the heap + */ + CHECK_FAIL(!passed); + +close_prog: + perf_buffer__free(pb); + if (!IS_ERR_OR_NULL(link)) + bpf_link__destroy(link); + bpf_object__close(prog_obj); +} diff --git a/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c b/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c new file mode 100644 index 000000000000..85048315baae --- /dev/null +++ b/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include +#include "bpf_helpers.h" +#include "bpf_trace_helpers.h" + +char _license[] SEC("license") = "GPL"; +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); +} perf_buf_map SEC(".maps"); + +#define MPROTECT_AUDIT_MAGIC 0xDEAD + +struct mprotect_audit_log { + int is_heap, magic; +}; + +/* + * Define some of the structs used in the BPF program. + * Only the field names and their sizes need to be the + * same as the kernel type, the order is irrelevant. + */ +struct mm_struct { + unsigned long start_brk, brk, start_stack; +}; + +struct vm_area_struct { + unsigned long start_brk, brk, start_stack; + unsigned long vm_start, vm_end; + struct mm_struct *vm_mm; + unsigned long vm_flags; +}; + +BPF_TRACE_3("lsm/file_mprotect", mprotect_audit, + struct vm_area_struct *, vma, + unsigned long, reqprot, unsigned long, prot) +{ + struct mprotect_audit_log audit_log = {}; + int is_heap = 0; + + __builtin_preserve_access_index(({ + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && + vma->vm_end <= vma->vm_mm->brk); + })); + + audit_log.magic = MPROTECT_AUDIT_MAGIC; + audit_log.is_heap = is_heap; + bpf_lsm_event_output(&perf_buf_map, BPF_F_CURRENT_CPU, &audit_log, + sizeof(audit_log)); + return 0; +} From patchwork Fri Dec 20 15:42:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11305807 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C881A6C1 for ; Fri, 20 Dec 2019 15:42:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9400524680 for ; Fri, 20 Dec 2019 15:42:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="UnFHOJ8+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727696AbfLTPmc (ORCPT ); Fri, 20 Dec 2019 10:42:32 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:43238 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727655AbfLTPmX (ORCPT ); Fri, 20 Dec 2019 10:42:23 -0500 Received: by mail-wr1-f65.google.com with SMTP id d16so9812841wre.10 for ; Fri, 20 Dec 2019 07:42:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=E3KRI0OMvvIk1Vp8KAUHmCXVK/1yf6rawh5IXDd9ces=; b=UnFHOJ8+GMLl+jOi6cH3hewYYZpM8CrAZz0SocrwHbHAJi5kJCGxdWoGBYNd56FKms 4iXoCWR0Y+JGIzj7lVun/7TKSmQCrI86eAVnrLNHcZl2fSFj/iOG2XC4x+bnuIvXMVkx pA9LhZZrfM+iekDJ2f8ZjDb6LS4rmGE8qv4Ns= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=E3KRI0OMvvIk1Vp8KAUHmCXVK/1yf6rawh5IXDd9ces=; b=V8EMqIRkBb6Qk6/SW+fQArqqF1it8OGxQUIAEa70H3YPApTl7fjI1eAI227u1ASK5a T3pm8OgNnvNeAOPnlNrP7IbZ4Iv2N5ODzypc/uGpo2N1P1zvkM18/S0f0JQPxAJjZvNF pn3IgKwZyTX/yuZzOE4raVs+ABDxyd4mgGKa5rAY1Dty+9eg7RgnLDU1v5OzaXMK1y4n BVAGHRwkiOUbcipwHj4Ge1lp5mMeFEWi33mYCFLLGu/8vJVFPxfuOJY7nxaOb4+PvdMK EVZSkQW/EMdW9GGS0bxJ9EySU0ceEK46gjrYBMxYIPAmhXh3xyLm4v4AOBRHiOY229RX lRHg== X-Gm-Message-State: APjAAAWOi8+MBAMJg1huzkUVb3903E1/bJQ5Vm3Ahk7tPa/4B+O7EPAy I6LrQP1/wXxHGmftzuDdZjRt7A== X-Google-Smtp-Source: APXvYqy+NoYaSlhnrfxz+YqWELrNDqgsG8cS58xKXuhUA6jx2tHjZj6TMGrFdnsggisjjCwLLCdlkQ== X-Received: by 2002:adf:d184:: with SMTP id v4mr15936626wrc.76.1576856540672; Fri, 20 Dec 2019 07:42:20 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2a00:79e1:abc:308:c46b:b838:66cf:6204]) by smtp.gmail.com with ESMTPSA id x11sm10118062wmg.46.2019.12.20.07.42.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Dec 2019 07:42:20 -0800 (PST) From: KP Singh To: linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-security-module@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , James Morris , Kees Cook , Thomas Garnier , Michael Halcrow , Paul Turner , Brendan Gregg , Jann Horn , Matthew Garrett , Christian Brauner , =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= , Florent Revest , Brendan Jackman , Martin KaFai Lau , Song Liu , Yonghong Song , "Serge E. Hallyn" , Mauro Carvalho Chehab , "David S. Miller" , Greg Kroah-Hartman , Nicolas Ferre , Stanislav Fomichev , Quentin Monnet , Andrey Ignatov , Joe Stringer Subject: [PATCH bpf-next v1 13/13] bpf: lsm: Add Documentation Date: Fri, 20 Dec 2019 16:42:08 +0100 Message-Id: <20191220154208.15895-14-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org> References: <20191220154208.15895-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh Document how eBPF programs (BPF_PROG_TYPE_LSM) can be loaded and attached (BPF_LSM_MAC) to the LSM hooks. Signed-off-by: KP Singh --- Documentation/security/bpf.rst | 164 +++++++++++++++++++++++++++++++ Documentation/security/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 166 insertions(+) create mode 100644 Documentation/security/bpf.rst diff --git a/Documentation/security/bpf.rst b/Documentation/security/bpf.rst new file mode 100644 index 000000000000..898b7de148a0 --- /dev/null +++ b/Documentation/security/bpf.rst @@ -0,0 +1,164 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright 2019 Google LLC. + +========================== +eBPF Linux Security Module +========================== + +This LSM allows runtime instrumentation of the LSM hooks by privileged users to +implement system-wide MAC (Mandatory Access Control) and Audit policies using +eBPF. The LSM is priveleged and stackable and requires both ``CAP_SYS_ADMIN`` +and ``CAP_MAC_ADMIN`` for the loading of BPF programs and modification of MAC +policies respectively. + +eBPF Programs +============== + +`eBPF (extended BPF) `_ is a +virtual machine-like construct in the Linux Kernel allowing the execution of +verifiable, just-in-time compiled byte code at various points in the Kernel. + +The eBPF LSM adds a new type, ``BPF_PROG_TYPE_LSM``, of eBPF programs which +have the following characteristics: + + * Multiple eBPF programs can be attached to the same LSM hook. + * LSM hooks can return an ``-EPERM`` to indicate the decision of the + MAC policy being enforced or simply be used for auditing. + * Allowing the eBPF programs to be attached to all the LSM hooks by + making :doc:`/bpf/btf` type information available for all LSM hooks + and allowing the BPF verifier to perform runtime relocations and + validation on the programs. + +Structure +--------- + +The example shows an eBPF program that can be attached to the ``file_mprotect`` +LSM hook: + +.. c:function:: int file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); + +eBPF programs that use :doc:`/bpf/btf` do not need to include kernel headers +for accessing information from the attached eBPF program's context. They can +simply declare the structures in the eBPF program and only specify the fields +that need to be accessed. + +.. code-block:: c + + struct mm_struct { + unsigned long start_brk, brk, start_stack; + }; + + struct vm_area_struct { + unsigned long start_brk, brk, start_stack; + unsigned long vm_start, vm_end; + struct mm_struct *vm_mm; + }; + + +.. note:: Only the size and the names of the fields must match the type in the + kernel and the order of the fields is irrelevant. + +The eBPF programs can be declared using macros similar to the ``BPF_TRACE_`` +macros defined in `tools/testing/selftests/bpf/bpf_trace_helpers.h`_. In this +example: + + * The LSM hook takes 3 args so we use ``BPF_TRACE_3``. + * ``"lsm/file_mprotect"`` indicates the LSM hook that the program must + be attached to. + * ``mprotect_audit`` is the name of the eBPF program. + +.. code-block:: c + + BPF_TRACE_3("lsm/file_mprotect", mprotect_audit, + struct vm_area_struct *, vma, + unsigned long, reqprot, unsigned long, prot) + { + int is_heap = 0; + + __builtin_preserve_access_index(({ + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && + vma->vm_end <= vma->vm_mm->brk); + })); + + /* + * Return an -EPERM or Write information to the perf events buffer + * for auditing + */ + } + +The ``__builtin_preserve_access_index`` is a clang primitive that allows the +BPF verifier to update the offsets for the access at runtime using the +:doc:`/bpf/btf` information. Since the BPF verifier is aware of the types, it +also validates all the accesses made to the various types in the eBPF program. + +Loading +------- + +eBPP programs can be loaded with the :manpage:`bpf(2)` syscall's +``BPF_PROG_LOAD`` operation or more simply by using the the libbpf helper +``bpf_prog_load_xattr``: + + +.. code-block:: c + + struct bpf_prog_load_attr attr = { + .file = "./prog.o", + }; + struct bpf_object *prog_obj; + struct bpf_program *prog; + int prog_fd; + + bpf_prog_load_xattr(&attr, &prog_obj, &prog_fd); + +Attachment to LSM Hooks +----------------------- + +The LSM creates a file in securityfs for each LSM hook to which eBPF programs +can be attached using :manpage:`bpf(2)` syscall's ``BPF_PROG_ATTACH`` operation +or more simply by using the libbpf helper ``bpf_program__attach_lsm``. In the +code shown below ``prog`` is the eBPF program loaded using ``BPF_PROG_LOAD``: + + +.. code-block:: c + + struct bpf_link *link; + + link = bpf_program__attach_lsm(prog); + +The attachment can be verified by: + +.. code-block:: console + + # cat /sys/kernel/security/bpf/file_mprotect + mprotect_audit + +If, when a program is attached, another program by the same name is already attached to the hook, that program is replaced. + + +.. note:: This requires that the ``BPF_F_ALLOW_OVERRIDE`` flag be passed to + the :manpage:`bpf(2)` syscall. If not, an ``-EEXIST`` error is returned instead. + +For conveniently versioning updating programs, program names are only compared up to the first ``"__"``. Thus if a program ``mprotect_audit__v1`` is attached and then ``mprotect_audit__v2`` is attached to the same hook, the latter will *replace* the former. + +The program can be detached from the LSM hook by *destroying* the ``link`` +link returned by ``bpf_program__attach_lsm``: + +.. code-block:: c + + link->destroy(); + +Examples +-------- + +An example eBPF program can be found in +`tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c`_ and the corresponding +userspace code in +`tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c`_ + +.. Links +.. _tools/testing/selftests/bpf/bpf_trace_helpers.h: + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/selftests/bpf/bpf_trace_helpers.h +.. _tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c: + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c +.. _tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c: + https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c diff --git a/Documentation/security/index.rst b/Documentation/security/index.rst index fc503dd689a7..844463df4547 100644 --- a/Documentation/security/index.rst +++ b/Documentation/security/index.rst @@ -5,6 +5,7 @@ Security Documentation .. toctree:: :maxdepth: 1 + bpf credentials IMA-templates keys/index diff --git a/MAINTAINERS b/MAINTAINERS index 652c93292ae9..6f34c24519ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3184,6 +3184,7 @@ F: security/bpf/ F: include/linux/bpf_lsm.h F: tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c F: tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c +F: Documentation/security/bpf.rst BROADCOM B44 10/100 ETHERNET DRIVER M: Michael Chan