From patchwork Wed Jan 15 17:13:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335467 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 6B1FE14B4 for ; Wed, 15 Jan 2020 17:14:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4984724681 for ; Wed, 15 Jan 2020 17:14:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="CDuGgPNG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729134AbgAORNY (ORCPT ); Wed, 15 Jan 2020 12:13:24 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:40940 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729037AbgAORNY (ORCPT ); Wed, 15 Jan 2020 12:13:24 -0500 Received: by mail-wm1-f66.google.com with SMTP id t14so726917wmi.5 for ; Wed, 15 Jan 2020 09:13:22 -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=lMrzaXbHOJoXJR4BqSM8/Q4xofgHVyPxrukOYhnuR8w=; b=CDuGgPNGWYz4c7wtILqThkFOu+2SErXXx0agyzMiefku/qGD/up2rxB74jjJxZUpBd CGMun26K8cwuHV8+eF1JDPocckf2uAIRYQlk2HncWsO3bcdjtDSbfcIWLkcZ8KVUc2zI K5bVO4gJX9/CZv2WMSjT0r0RtWS0O7XLR3pkQ= 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=lMrzaXbHOJoXJR4BqSM8/Q4xofgHVyPxrukOYhnuR8w=; b=IOwfeYPnsRuadVNeckki8KfbJbL9tPytwantH8rMp4otrrIfyWs+GgUqmkW0im4gOZ EPGSFVTw6y5YKpSu+aCr6cjlw7d5HZ58l7Las0F4xdUB/1VqYU7AhBH7TQ3VngWfXMI/ oxFZadz9BWcmU/JG5pzK6RGAajT8jkgCMZh7u96pO1LKoQxSkBTn5iHQBWcfNGlr9FlC RaAMDd9Ozc7Z0Uiar827pbqbu3Hovar7HM8hZLXqi9fnmh6sVvPi7HQNUSKwO5FGHL0y GaTde7B5rYsA5jwr8juBbvWgYld70J9muHrbghMoJZRUiuSb3+PdICNplnjbYjfsoeU1 tnUg== X-Gm-Message-State: APjAAAVio/lS2+WSX/fzi2XbEYTYpuBh0s8iuVBvvQuLjtvsSDRa/FCM nYqrco3MAfOwJRbcsZN392H71w== X-Google-Smtp-Source: APXvYqw+83aJOogdP51uHjakQPrbRphvcxTyKNh4lFcbQf8mJWthRqQx/L4xsXdKWcUBUCE2YaLkWA== X-Received: by 2002:a1c:5f06:: with SMTP id t6mr978688wmb.32.1579108401751; Wed, 15 Jan 2020 09:13:21 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:21 -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 v2 01/10] bpf: btf: Make some of the API visible outside BTF Date: Wed, 15 Jan 2020 18:13:24 +0100 Message-Id: <20200115171333.28811-2-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh - Add an extern for btf_vmlinux in btf.h - Add btf_type_by_name_kind, the LSM code does the combination of btf_find_by_name_kind and btf_type_by_id quite often. Signed-off-by: KP Singh Reported-by: kbuild test robot --- include/linux/btf.h | 8 ++++++++ kernel/bpf/btf.c | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/linux/btf.h b/include/linux/btf.h index 881e9b76ef49..dc650d294bc4 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -15,6 +15,7 @@ struct btf_type; union bpf_attr; extern const struct file_operations btf_fops; +extern struct btf *btf_vmlinux; void btf_put(struct btf *btf); int btf_new_fd(const union bpf_attr *attr); @@ -66,6 +67,8 @@ const struct btf_type * btf_resolve_size(const struct btf *btf, const struct btf_type *type, u32 *type_size, const struct btf_type **elem_type, u32 *total_nelems); +const struct btf_type *btf_type_by_name_kind( + struct btf *btf, const char *name, u8 kind); #define for_each_member(i, struct_type, member) \ for (i = 0, member = btf_type_member(struct_type); \ @@ -142,6 +145,11 @@ static inline const struct btf_type *btf_type_by_id(const struct btf *btf, { return NULL; } +static inline const struct btf_type *btf_type_by_name_kind( + struct btf *btf, const char *name, u8 kind) +{ + return ERR_PTR(-EOPNOTSUPP); +} static inline const char *btf_name_by_offset(const struct btf *btf, u32 offset) { diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 832b5d7fd892..b8968cec8718 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -436,6 +436,23 @@ const struct btf_type *btf_type_resolve_func_ptr(const struct btf *btf, return NULL; } +const struct btf_type *btf_type_by_name_kind( + struct btf *btf, const char *name, u8 kind) +{ + const struct btf_type *t; + s32 type_id; + + type_id = btf_find_by_name_kind(btf, name, kind); + if (type_id < 0) + return ERR_PTR(-EINVAL); + + t = btf_type_by_id(btf, type_id); + if (!t) + return ERR_PTR(-EINVAL); + + return t; +} + /* Types that act only as a source, not sink or intermediate * type when resolving. */ From patchwork Wed Jan 15 17:13:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335469 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 28F971398 for ; Wed, 15 Jan 2020 17:14:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F1C6F24679 for ; Wed, 15 Jan 2020 17:14:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="NBBS9adp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728921AbgAOROL (ORCPT ); Wed, 15 Jan 2020 12:14:11 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:50541 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729067AbgAORNY (ORCPT ); Wed, 15 Jan 2020 12:13:24 -0500 Received: by mail-wm1-f66.google.com with SMTP id a5so775316wmb.0 for ; Wed, 15 Jan 2020 09:13:23 -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=zt23Gw134AtqUrID89ClnKzSfIIutA/T+EnUaIX5zWA=; b=NBBS9adpw1krpgiY6cgia1Zz9UP84IQn3ay0NYkaK4mkhuQ6ptlQvCtvk7gJTYaZzU G96QBd2Kwfz1YmLA3BNnm4ldIcvGOn1U1rRlyoWxDAJLQpGF14Vmox6s1mdS0/SY/RVi uUbb48ALx/0ajIj3PmDPnPk2Uh//4ogTSKK5I= 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=zt23Gw134AtqUrID89ClnKzSfIIutA/T+EnUaIX5zWA=; b=senObEUtPhwglX/S+v1wA6XewXraMdF0laGrtuX6f/kfpOblln5NBXtBQ7L7puW6AA vpDs6yHf+nXEWdUEr/TyHIWDr5Qd9CituBizzWOgPOyOkMzty8pULB4M0gcYIAZ+dprD FPlG5jvEtJ6jrAfJNfoYFcW0aFgnb1bwAQ+sdC19mcEE5OEXVEpgSNRTAC62jKzey6pn qyT8swUD0lDlEw6mPM7+Zz80bMW9luAvKx9AuePFGQflkWGbNblgoCiDpFwe7i2Oj63E ZJP5g1882gpsuyMvj4Mat/u6Vfk6KS7hvehRblvQUtX3baPL+ayJ+OXdzJW4Qm44Sgjo 4Vew== X-Gm-Message-State: APjAAAWMS/D1wkpVO1D6FcVvN6zgIpnGVWmsNdndvlo6WEbudF29YiEV mOK7gNcqCxJxZxvVPvN0N8Lj6t2MajtoOQ== X-Google-Smtp-Source: APXvYqyqM2ZGAqYm77/2GaQNvQod38TkiKqGyB7jaqiFFZibyCpAIIJKzdKdqzdMmN/plWRlHGgMJA== X-Received: by 2002:a05:600c:224d:: with SMTP id a13mr937586wmm.57.1579108402877; Wed, 15 Jan 2020 09:13:22 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:22 -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 v2 02/10] bpf: lsm: Add a skeleton and config options Date: Wed, 15 Jan 2020 18:13:25 +0100 Message-Id: <20200115171333.28811-3-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-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 --- MAINTAINERS | 7 +++++++ security/Kconfig | 11 ++++++----- security/Makefile | 2 ++ security/bpf/Kconfig | 22 ++++++++++++++++++++++ security/bpf/Makefile | 5 +++++ security/bpf/lsm.c | 25 +++++++++++++++++++++++++ 6 files changed, 67 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 66a2e5e07117..0941f478cfa5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3203,6 +3203,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..a5f6c67ae526 --- /dev/null +++ b/security/bpf/Kconfig @@ -0,0 +1,22 @@ +# 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 BPF_SYSCALL + help + This enables instrumentation of the security hooks with + eBPF programs. + + 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..5c5c14f990ce --- /dev/null +++ b/security/bpf/lsm.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include + +/* This is only for internal hooks, always statically shipped as part of the + * BPF LSM. Statically defined hooks are appeneded to the security_hook_heads + * which is common for LSMs and R/O after init. + */ +static struct security_hook_list lsm_hooks[] __lsm_ro_after_init = {}; + +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 Wed Jan 15 17:13:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335451 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 89D4B92A for ; Wed, 15 Jan 2020 17:13:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5E6B02467E for ; Wed, 15 Jan 2020 17:13:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="JkYY+k1n" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728911AbgAORN0 (ORCPT ); Wed, 15 Jan 2020 12:13:26 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:45805 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729138AbgAORNZ (ORCPT ); Wed, 15 Jan 2020 12:13:25 -0500 Received: by mail-wr1-f67.google.com with SMTP id j42so16487191wrj.12 for ; Wed, 15 Jan 2020 09:13:24 -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=1qpppvmxUsdoHOAo4Mt0fdfqe/zAKnsM8OMMV6DxgYo=; b=JkYY+k1nQptDXMc1K3ZJXsjo5EisX3f4Se8aov6LIW3URg1EZSqPii8H35t2Ba5kRp q3AbE+l2t7G2L+AHhLEma/CQnkJ4UcMWFTaMW8KbfeO+1yHA8NdorBrBU9Ye2uEtrOV/ VoaPDoyccqGCcJnIbKLR0oGRhJARcqBUxSlq0= 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=1qpppvmxUsdoHOAo4Mt0fdfqe/zAKnsM8OMMV6DxgYo=; b=ssIR/Mr8OZ6zMq6cCORkhxKNEiMmsL8xzu1dj9TserMaRHViAR/i33yHTx7XPhSFw5 OVW2QIDNbBDBVrYs2lTWtLYxS/lutfUkGlsW4hvY4B9OfmNraXLYAhQKWbCPhD0gmfrs 1ucwjedlv3y36utaa9v0ndpfgBv6+KYLQFIJS3GmiL6z6xryPN/SxNAyKM03fesPgihp F9gdT/YcoGU2BPTXIscMJkOr1is+CK2Cs5VhSzb3qIeARPb2logHh2/djWoMAg1vU81S z3FDvy9CJtIdwRfrP/uUgbMUkslEVG/wst9MzTBrOPV0wWxyKNjEbPtBrEz4pMKPX2qL kYRw== X-Gm-Message-State: APjAAAXfQH6nPsgRwjy04ZPrrIRyWcCcjH5FzDm3glEkCu1nM3wGUr0w VnRgowdVDLEbcA9tLvwI1PQBZA== X-Google-Smtp-Source: APXvYqz/VjlQXnNTb8DZIKjOpRbcHFB5LHITo4nFweinfMbDgY2p9mOZN9D7fnWO11/ygS2/nbpcYA== X-Received: by 2002:a5d:608e:: with SMTP id w14mr33246082wrt.256.1579108404001; Wed, 15 Jan 2020 09:13:24 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:23 -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 v2 03/10] bpf: lsm: Introduce types for eBPF based LSM Date: Wed, 15 Jan 2020 18:13:26 +0100 Message-Id: <20200115171333.28811-4-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-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. Attachment to LSM hooks is not implemented in this patch. On defining the types for the program, the macros expect that _prog_ops and _verifier_ops exist. This is implicitly required by the macro: BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm, ...) 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 | 28 ++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 2 ++ tools/lib/bpf/libbpf_probes.c | 1 + 7 files changed, 44 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 9f326e6ef885..2f5b054500d7 100644 --- a/include/linux/bpf_types.h +++ b/include/linux/bpf_types.h @@ -68,6 +68,10 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport, #if defined(CONFIG_BPF_JIT) BPF_PROG_TYPE(BPF_PROG_TYPE_STRUCT_OPS, bpf_struct_ops, void *, void *) +#ifdef CONFIG_SECURITY_BPF +BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm, + void *, void *) +#endif /* CONFIG_SECURITY_BPF */ #endif BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 52966e758fe5..b6a725a8a21d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -176,6 +176,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_PROG_TYPE_TRACING, BPF_PROG_TYPE_STRUCT_OPS, + BPF_PROG_TYPE_LSM, }; enum bpf_attach_type { @@ -205,6 +206,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 f9db72a96ec0..2945739618c9 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2151,6 +2151,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; @@ -2182,6 +2185,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..81c2bd9c0495 --- /dev/null +++ b/security/bpf/ops.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include + +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, +}; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 52966e758fe5..b6a725a8a21d 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -176,6 +176,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_PROG_TYPE_TRACING, BPF_PROG_TYPE_STRUCT_OPS, + BPF_PROG_TYPE_LSM, }; enum bpf_attach_type { @@ -205,6 +206,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/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index 8cc992bc532a..2314889369cc 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -107,6 +107,7 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, case BPF_PROG_TYPE_CGROUP_SOCKOPT: case BPF_PROG_TYPE_TRACING: case BPF_PROG_TYPE_STRUCT_OPS: + case BPF_PROG_TYPE_LSM: default: break; } From patchwork Wed Jan 15 17:13:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335465 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 63BDC1398 for ; Wed, 15 Jan 2020 17:14:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2F05024687 for ; Wed, 15 Jan 2020 17:14:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="Yga+W/iC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729030AbgAOROH (ORCPT ); Wed, 15 Jan 2020 12:14:07 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:33905 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729157AbgAORN0 (ORCPT ); Wed, 15 Jan 2020 12:13:26 -0500 Received: by mail-wr1-f67.google.com with SMTP id t2so16547067wrr.1 for ; Wed, 15 Jan 2020 09:13:26 -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=LQxyMYtQgG6tF+BejS82EQt5eHXmPPeHraWUkmIc0QY=; b=Yga+W/iCrwZEPrgbOH4uvmZSQ4eJbT4jPmG7QfaLvI8q/IhW+b3j6ruG6TShNLD0bP AKf8N8df7zWHLD4+mWV28aqub0K6suL8XejKMq5vK88tmApvSDircxWWy86eNl+C96uz ZrW0VwqLFo/ZEBPgHZGBi1vzL9BFTsATdWVCc= 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=LQxyMYtQgG6tF+BejS82EQt5eHXmPPeHraWUkmIc0QY=; b=mJ4Sig+FEK+MGvcBlJB2BseTDkGP6zw7aEYEjs2QI35cQC+8Azg5/DJh+jFH4kKcrb vknn8cec2XbRiw/cHI8DpJQJOaX1qt49qcNFA90rWQ8OqPnfBh5g46WMSnnoFHhkWzuv e0BLUcu9K4CWll96zCvC/Pmo0m64OHkfQsMtqm3D+i0TJwLXJW665fpia8+0TlTic86E 04djZB6lBOItUq8xqaPec31VSCR9EMbY2hhfexwNu6CBsL5pYzEg2jNsVUPH7s8DJxsI KUNrJqtbhFY8r04ry9UOhgnHSdoCPndQgeY2Lm4UX1k1AysWVUA+A0H41R5yRaVqbKvR ropg== X-Gm-Message-State: APjAAAXy0mLEIH2I5f30Rt4E+VOjSIx2rPqWQZanBqelRkqstffVuYWE FzVbt/jnOwyWhNcDtkgVesjVXg== X-Google-Smtp-Source: APXvYqyStWbKFkVOZQVLej5NW5P7eiu3AV1pQZ7BoLB818RceL/4QpAvR2W5UVweCfin0rbmzynJVw== X-Received: by 2002:adf:ebd0:: with SMTP id v16mr33132617wrn.146.1579108405163; Wed, 15 Jan 2020 09:13:25 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:24 -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 v2 04/10] bpf: lsm: Add mutable hooks list for the BPF LSM Date: Wed, 15 Jan 2020 18:13:27 +0100 Message-Id: <20200115171333.28811-5-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh - The list of hooks registered by an LSM is currently immutable as they are declared with __lsm_ro_after_init and they are attached to a security_hook_heads struct. - For the BPF LSM we need to de/register the hooks at runtime. Making the existing security_hook_heads mutable broadens an attack vector, so a separate security_hook_heads is added for only those that ~must~ be mutable. - These mutable hooks are run only after all the static hooks have successfully executed. This is based on the ideas discussed in: https://lore.kernel.org/lkml/20180408065916.GA2832@ircssh-2.c.rugged-nimbus-611.internal Signed-off-by: KP Singh --- MAINTAINERS | 1 + include/linux/bpf_lsm.h | 71 +++++++++++++++++++++++++++++++++++++++++ security/bpf/Kconfig | 1 + security/bpf/Makefile | 2 +- security/bpf/hooks.c | 20 ++++++++++++ security/bpf/lsm.c | 9 +++++- security/security.c | 24 +++++++------- 7 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 include/linux/bpf_lsm.h create mode 100644 security/bpf/hooks.c diff --git a/MAINTAINERS b/MAINTAINERS index 0941f478cfa5..02d7e05e9b75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3209,6 +3209,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 new file mode 100644 index 000000000000..9883cf25241c --- /dev/null +++ b/include/linux/bpf_lsm.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright 2019 Google LLC. + */ + +#ifndef _LINUX_BPF_LSM_H +#define _LINUX_BPF_LSM_H + +#include +#include + +#ifdef CONFIG_SECURITY_BPF + +/* Mutable hooks defined at runtime and executed after all the statically + * define LSM hooks. + */ +extern struct security_hook_heads bpf_lsm_hook_heads; + +int bpf_lsm_srcu_read_lock(void); +void bpf_lsm_srcu_read_unlock(int idx); + +#define CALL_BPF_LSM_VOID_HOOKS(FUNC, ...) \ + do { \ + struct security_hook_list *P; \ + int _idx; \ + \ + if (hlist_empty(&bpf_lsm_hook_heads.FUNC)) \ + break; \ + \ + _idx = bpf_lsm_srcu_read_lock(); \ + hlist_for_each_entry(P, &bpf_lsm_hook_heads.FUNC, list) \ + P->hook.FUNC(__VA_ARGS__); \ + bpf_lsm_srcu_read_unlock(_idx); \ + } while (0) + +#define CALL_BPF_LSM_INT_HOOKS(RC, FUNC, ...) ({ \ + do { \ + struct security_hook_list *P; \ + int _idx; \ + \ + if (hlist_empty(&bpf_lsm_hook_heads.FUNC)) \ + break; \ + \ + _idx = bpf_lsm_srcu_read_lock(); \ + \ + hlist_for_each_entry(P, \ + &bpf_lsm_hook_heads.FUNC, list) { \ + RC = P->hook.FUNC(__VA_ARGS__); \ + if (RC && IS_ENABLED(CONFIG_SECURITY_BPF_ENFORCE)) \ + break; \ + } \ + bpf_lsm_srcu_read_unlock(_idx); \ + } while (0); \ + IS_ENABLED(CONFIG_SECURITY_BPF_ENFORCE) ? RC : 0; \ +}) + +#else /* !CONFIG_SECURITY_BPF */ + +#define CALL_BPF_LSM_INT_HOOKS(RC, FUNC, ...) (RC) +#define CALL_BPF_LSM_VOID_HOOKS(...) + +static inline int bpf_lsm_srcu_read_lock(void) +{ + return 0; +} +static inline void bpf_lsm_srcu_read_unlock(int idx) {} + +#endif /* CONFIG_SECURITY_BPF */ + +#endif /* _LINUX_BPF_LSM_H */ diff --git a/security/bpf/Kconfig b/security/bpf/Kconfig index a5f6c67ae526..595e4ad597ae 100644 --- a/security/bpf/Kconfig +++ b/security/bpf/Kconfig @@ -6,6 +6,7 @@ config SECURITY_BPF bool "BPF-based MAC and audit policy" depends on SECURITY depends on BPF_SYSCALL + depends on SRCU help This enables instrumentation of the security hooks with eBPF programs. diff --git a/security/bpf/Makefile b/security/bpf/Makefile index c78a8a056e7e..c526927c337d 100644 --- a/security/bpf/Makefile +++ b/security/bpf/Makefile @@ -2,4 +2,4 @@ # # Copyright 2019 Google LLC. -obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o +obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o hooks.o diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c new file mode 100644 index 000000000000..b123d9cb4cd4 --- /dev/null +++ b/security/bpf/hooks.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include + +DEFINE_STATIC_SRCU(security_hook_srcu); + +int bpf_lsm_srcu_read_lock(void) +{ + return srcu_read_lock(&security_hook_srcu); +} + +void bpf_lsm_srcu_read_unlock(int idx) +{ + return srcu_read_unlock(&security_hook_srcu, idx); +} diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c index 5c5c14f990ce..d4ea6aa9ddb8 100644 --- a/security/bpf/lsm.c +++ b/security/bpf/lsm.c @@ -4,14 +4,21 @@ * Copyright 2019 Google LLC. */ +#include #include /* This is only for internal hooks, always statically shipped as part of the - * BPF LSM. Statically defined hooks are appeneded to the security_hook_heads + * BPF LSM. Statically defined hooks are appended to the security_hook_heads * which is common for LSMs and R/O after init. */ static struct security_hook_list lsm_hooks[] __lsm_ro_after_init = {}; +/* Security hooks registered dynamically by the BPF LSM and must be accessed + * by holding bpf_lsm_srcu_read_lock and bpf_lsm_srcu_read_unlock. The mutable + * hooks dynamically allocated by the BPF LSM are appeneded here. + */ +struct security_hook_heads bpf_lsm_hook_heads; + static int __init lsm_init(void) { security_add_hooks(lsm_hooks, ARRAY_SIZE(lsm_hooks), "bpf"); diff --git a/security/security.c b/security/security.c index cd2d18d2d279..4a2eb4c089b2 100644 --- a/security/security.c +++ b/security/security.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #define MAX_LSM_EVM_XATTR 2 @@ -652,20 +653,21 @@ static void __init lsm_early_task(struct task_struct *task) \ hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ P->hook.FUNC(__VA_ARGS__); \ + CALL_BPF_LSM_VOID_HOOKS(FUNC, __VA_ARGS__); \ } while (0) -#define call_int_hook(FUNC, IRC, ...) ({ \ - int RC = IRC; \ - do { \ - struct security_hook_list *P; \ - \ +#define call_int_hook(FUNC, IRC, ...) ({ \ + int RC = IRC; \ + do { \ + struct security_hook_list *P; \ hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \ - RC = P->hook.FUNC(__VA_ARGS__); \ - if (RC != 0) \ - break; \ - } \ - } while (0); \ - RC; \ + RC = P->hook.FUNC(__VA_ARGS__); \ + if (RC != 0) \ + break; \ + } \ + RC = CALL_BPF_LSM_INT_HOOKS(RC, FUNC, __VA_ARGS__); \ + } while (0); \ + RC; \ }) /* Security operations */ From patchwork Wed Jan 15 17:13:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335453 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 8978892A for ; Wed, 15 Jan 2020 17:13:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5D86A2467E for ; Wed, 15 Jan 2020 17:13:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="gZOvsoWn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729147AbgAORN2 (ORCPT ); Wed, 15 Jan 2020 12:13:28 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:41526 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729169AbgAORN2 (ORCPT ); Wed, 15 Jan 2020 12:13:28 -0500 Received: by mail-wr1-f68.google.com with SMTP id c9so16529056wrw.8 for ; Wed, 15 Jan 2020 09:13:27 -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=b3NJ2CZ8kBjGjnKwLifa2Rd0VYqXxRjZEy90LqHwLt4=; b=gZOvsoWniHlHh9h21Kxu4FD8G1kLvd5AkOP1w+Fz6LnT80ZgROGkilczKCyE38xgkJ XXhRGIWXyL3OagMSvBfHaI8clTj/ouKIxzFCMBJyQD+eJqVb0Scj6I6C4JK+jKL7fdaT tqyTFAfDLsPunlujzvO6ku+GDMtqs5nhOnocA= 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=b3NJ2CZ8kBjGjnKwLifa2Rd0VYqXxRjZEy90LqHwLt4=; b=TwKZHd7ZEYMQ8d1i/9NcRdmSoLkiaC83TYyapSupzSSjzwzBVf4i0suk4vzzuSvZpR ySUZcMxcoCh/CaT/5x4AVioX5JQWUg6k6N9lUJvVzQwOzDp83xWFqfAK3BZunSHjajrn n7UYHPBm0BTPhGcdKEaZ1+6pEKkRTkFM/+OOGOG9ii82qTko9OgEJRSs/hBjoqRH4Y/1 2Ek0XT7tBwlV5JZH9zTehqkBZ6YcgJHLR0gLHia0oq9/R2myj8aJAO3LR5UYusx1j0kj o0iG/0KKx+oA2q0P1nRu6lHhPwCn+EZGGKghQ8meshUrFRRK1Je1i/zfN6VATz8v7JoN KyWQ== X-Gm-Message-State: APjAAAWBpkcbih0TKHH2HYRQW7i+ynH2uztHdGUoA6dyarcGp8uae8WJ Q7i13y1p9Echw4NE48RrwkFPeA== X-Google-Smtp-Source: APXvYqyNMe56nhpaM0QPg8Iq77aVz1Uk0rCoiJFQBIjfH0WChRwfqVoiuHVttVDhg0HUIlsXbAlCZQ== X-Received: by 2002:a5d:6a8e:: with SMTP id s14mr33286303wru.150.1579108406382; Wed, 15 Jan 2020 09:13:26 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:25 -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 v2 05/10] bpf: lsm: BTF API for LSM hooks Date: Wed, 15 Jan 2020 18:13:28 +0100 Message-Id: <20200115171333.28811-6-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh The BTF API provides information required by the BPF verifier to attach eBPF programs to the LSM hooks by using the BTF information of two types: - struct security_hook_heads: This type provides the offset which a new dynamically allocated security hook must be attached to. - union security_list_options: This provides the information about the function prototype required by the hook. When the program is loaded: - The verifier receives the index of a member in struct security_hook_heads to which a program must be attached as prog->aux->lsm_hook_index. The index is one-based for better verification. - bpf_lsm_type_by_index is used to determine the func_proto of the LSM hook and updates prog->aux->attach_func_proto - bpf_lsm_head_by_index is used to determine the hlist_head to which the BPF program must be attached. Signed-off-by: KP Singh --- include/linux/bpf_lsm.h | 12 +++++ security/bpf/Kconfig | 1 + security/bpf/hooks.c | 104 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h index 9883cf25241c..a9b4f7b41c65 100644 --- a/include/linux/bpf_lsm.h +++ b/include/linux/bpf_lsm.h @@ -19,6 +19,8 @@ extern struct security_hook_heads bpf_lsm_hook_heads; int bpf_lsm_srcu_read_lock(void); void bpf_lsm_srcu_read_unlock(int idx); +const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 offset); +const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 id); #define CALL_BPF_LSM_VOID_HOOKS(FUNC, ...) \ do { \ @@ -65,6 +67,16 @@ static inline int bpf_lsm_srcu_read_lock(void) return 0; } static inline void bpf_lsm_srcu_read_unlock(int idx) {} +static inline const struct btf_type *bpf_lsm_type_by_index( + struct btf *btf, u32 index) +{ + return ERR_PTR(-EOPNOTSUPP); +} +static inline const struct btf_member *bpf_lsm_head_by_index( + struct btf *btf, u32 id) +{ + return ERR_PTR(-EOPNOTSUPP); +} #endif /* CONFIG_SECURITY_BPF */ diff --git a/security/bpf/Kconfig b/security/bpf/Kconfig index 595e4ad597ae..9438d899b618 100644 --- a/security/bpf/Kconfig +++ b/security/bpf/Kconfig @@ -7,6 +7,7 @@ config SECURITY_BPF depends on SECURITY depends on BPF_SYSCALL depends on SRCU + depends on DEBUG_INFO_BTF help This enables instrumentation of the security hooks with eBPF programs. diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index b123d9cb4cd4..82725611693d 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -5,6 +5,8 @@ */ #include +#include +#include #include DEFINE_STATIC_SRCU(security_hook_srcu); @@ -18,3 +20,105 @@ void bpf_lsm_srcu_read_unlock(int idx) { return srcu_read_unlock(&security_hook_srcu, idx); } + +static inline int validate_hlist_head(struct btf *btf, u32 type_id) +{ + s32 hlist_id; + + hlist_id = btf_find_by_name_kind(btf, "hlist_head", BTF_KIND_STRUCT); + if (hlist_id < 0 || hlist_id != type_id) + return -EINVAL; + + return 0; +} + +/* Find the BTF representation of the security_hook_heads member for a member + * with a given index in struct security_hook_heads. + */ +const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 index) +{ + const struct btf_member *member; + const struct btf_type *t; + u32 off, i; + int ret; + + t = btf_type_by_name_kind(btf, "security_hook_heads", BTF_KIND_STRUCT); + if (WARN_ON_ONCE(IS_ERR(t))) + return ERR_CAST(t); + + for_each_member(i, t, member) { + /* We've found the id requested and need to check the + * the following: + * + * - Is it at a valid alignment for struct hlist_head? + * + * - Is it a valid hlist_head struct? + */ + if (index == i) { + off = btf_member_bit_offset(t, member); + if (off % 8) + /* valid c code cannot generate such btf */ + return ERR_PTR(-EINVAL); + off /= 8; + + if (off % __alignof__(struct hlist_head)) + return ERR_PTR(-EINVAL); + + ret = validate_hlist_head(btf, member->type); + if (ret < 0) + return ERR_PTR(ret); + + return member; + } + } + + return ERR_PTR(-ENOENT); +} + +/* Given an index of a member in security_hook_heads return the + * corresponding type for the LSM hook. The members of the union + * security_list_options have the same name as the security_hook_heads which + * is ensured by the LSM_HOOK_INIT macro defined in include/linux/lsm_hooks.h + */ +const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 index) +{ + const struct btf_member *member, *hook_head = NULL; + const struct btf_type *t, *hook_type = NULL; + u32 i; + + hook_head = bpf_lsm_head_by_index(btf, index); + if (IS_ERR(hook_head)) + return ERR_PTR(PTR_ERR(hook_head)); + + t = btf_type_by_name_kind(btf, "security_list_options", BTF_KIND_UNION); + if (WARN_ON_ONCE(IS_ERR(t))) + return ERR_CAST(t); + + for_each_member(i, t, member) { + if (hook_head->name_off == member->name_off) { + /* There should be only one member with the same name + * as the LSM hook. This should never really happen + * and either indicates malformed BTF or someone trying + * trick the LSM. + */ + if (WARN_ON(hook_type)) + return ERR_PTR(-EINVAL); + + hook_type = btf_type_by_id(btf, member->type); + if (unlikely(!hook_type)) + return ERR_PTR(-EINVAL); + + if (!btf_type_is_ptr(hook_type)) + return ERR_PTR(-EINVAL); + } + } + + if (!hook_type) + return ERR_PTR(-ENOENT); + + t = btf_type_by_id(btf, hook_type->type); + if (unlikely(!t)) + return ERR_PTR(-EINVAL); + + return t; +} From patchwork Wed Jan 15 17:13:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335461 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 8AFE892A for ; Wed, 15 Jan 2020 17:13:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 428D02467D for ; Wed, 15 Jan 2020 17:13:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="UAqE1k/B" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728982AbgAORNu (ORCPT ); Wed, 15 Jan 2020 12:13:50 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:33341 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729187AbgAORNb (ORCPT ); Wed, 15 Jan 2020 12:13:31 -0500 Received: by mail-wr1-f66.google.com with SMTP id b6so16561450wrq.0 for ; Wed, 15 Jan 2020 09:13:28 -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=TKI5amT2na9Il6KONhJbeMpaYalV+M2OyoEG7nNgKVk=; b=UAqE1k/Bumb0lpHC6d/UGds9by6q1/Uq3m8yWT2DkVDlQTsJ1WCz8nfyLXOMYspxWY dDpKtm7YafGL/hwkj594NtcbnG0L4KwY1hWk6lsmmjaaUap2q/Ar75AAC7vMdohl3ysg 4ZVg/YccybcKfCSyajMG8GI4/g9IIfwZdi2Wo= 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=TKI5amT2na9Il6KONhJbeMpaYalV+M2OyoEG7nNgKVk=; b=hGldcD1CnVcbrsxWhBdMxG1H0TSeJOOIwpGnf55lA5qF7xJDcL4FluTkMrW9Xyl1Xx 2B3RA1aXNFrB0zAUA3oPDB6tWuz1lle7jT3JN5VdpelJMmZpk2ZUBQTLt3J6KTNIWDMa eB/Pv1Hk8/VyaYEWHzylAvia5AFNOY5E8VbwpKQgaJ+6zIZYkfUKk5AAX6SywEUYBDZu hS6roeKvee17wyCQMSruoiSp7UFEDvXim5E9RFVP1BQOUGkOHhBpIMWWZ7+ah63Su/xl je5t6BynCAGGwRAcyRvLoDOcJuZAz+WV6Xu/Y3AZ9KlCQeMBW6LPr/MlLh0zN8ACJZKw Y6lg== X-Gm-Message-State: APjAAAWYICMWxdTlFZmXYip5LXPFqHxw7vW0b+oeROUkAW8abL0V++pD qmPEaAdKucXZKkBKr2AbBzg0Tw== X-Google-Smtp-Source: APXvYqwhCLwnUOFpVlhM9nzQ0g74CrDkSrQ2pmzYatqz9AK9bnwO108JmkCxA1m2IVOaOlLngh1QXQ== X-Received: by 2002:a5d:6652:: with SMTP id f18mr15639432wrw.246.1579108407570; Wed, 15 Jan 2020 09:13:27 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:27 -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 v2 06/10] bpf: lsm: Implement attach, detach and execution Date: Wed, 15 Jan 2020 18:13:29 +0100 Message-Id: <20200115171333.28811-7-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh JITed BPF programs are used by the BPF LSM as dynamically allocated security hooks. arch_bpf_prepare_trampoline handles the arch_bpf_prepare_trampoline generates code to handle conversion of the signature of the hook to the BPF context and allows the BPF program to be called directly as a C function. The following permissions are required to attach a program to a hook: - CAP_SYS_ADMIN to load the program - CAP_MAC_ADMIN to attach it (i.e. to update the security policy) When the program is loaded (BPF_PROG_LOAD), the verifier receives the index (one-based) of the member in the security_hook_heads struct in the prog->aux->lsm_hook_index and uses the BTF API provided by the LSM to: - Populate the name of the hook in prog->aux->attach_func_name and the prototype in prog->aux->attach_func_proto. - Verify if the offset is valid for a type struct hlist_head. - The program is verified for accesses based on the attach_func_proto similar to raw_tp BPF programs. When an attachment (BPF_PROG_ATTACH) is requested: - The information required to set-up of a callback is populated in the struct bpf_lsm_list. - A new callback and a bpf_lsm_hook is allocated and the address of the hook is set to the be the address of the allocated callback. - The attachment returns an anonymous O_CLOEXEC fd which detaches the program on close. Signed-off-by: KP Singh Reviewed-by: Greg Kroah-Hartman --- include/linux/bpf.h | 4 + include/linux/bpf_lsm.h | 15 +++ include/uapi/linux/bpf.h | 4 + kernel/bpf/syscall.c | 47 ++++++- kernel/bpf/verifier.c | 74 +++++++++-- security/bpf/Kconfig | 1 + security/bpf/Makefile | 2 + security/bpf/hooks.c | 230 +++++++++++++++++++++++++++++++-- security/bpf/include/bpf_lsm.h | 75 +++++++++++ security/bpf/lsm.c | 60 +++++++++ security/bpf/ops.c | 2 + tools/include/uapi/linux/bpf.h | 4 + 12 files changed, 494 insertions(+), 24 deletions(-) create mode 100644 security/bpf/include/bpf_lsm.h diff --git a/include/linux/bpf.h b/include/linux/bpf.h index aed2bc39d72b..5ed4780c2091 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -599,6 +599,10 @@ struct bpf_prog_aux { u32 func_cnt; /* used by non-func prog as the number of func progs */ u32 func_idx; /* 0 for non-func prog, the index in func array for func prog */ u32 attach_btf_id; /* in-kernel BTF type id to attach to */ + /* Index (one-based) of the hlist_head in security_hook_heads to which + * the program must be attached. + */ + u32 lsm_hook_index; struct bpf_prog *linked_prog; bool verifier_zext; /* Zero extensions has been inserted by verifier. */ bool offload_requested; diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h index a9b4f7b41c65..8c86672437f0 100644 --- a/include/linux/bpf_lsm.h +++ b/include/linux/bpf_lsm.h @@ -19,8 +19,11 @@ extern struct security_hook_heads bpf_lsm_hook_heads; int bpf_lsm_srcu_read_lock(void); void bpf_lsm_srcu_read_unlock(int idx); +int bpf_lsm_verify_prog(const struct bpf_prog *prog); const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 offset); const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 id); +int bpf_lsm_attach(struct bpf_prog *prog); +int bpf_lsm_detach(struct bpf_prog *prog); #define CALL_BPF_LSM_VOID_HOOKS(FUNC, ...) \ do { \ @@ -67,6 +70,10 @@ static inline int bpf_lsm_srcu_read_lock(void) return 0; } static inline void bpf_lsm_srcu_read_unlock(int idx) {} +static inline int bpf_lsm_verify_prog(const struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} static inline const struct btf_type *bpf_lsm_type_by_index( struct btf *btf, u32 index) { @@ -77,6 +84,14 @@ static inline const struct btf_member *bpf_lsm_head_by_index( { return ERR_PTR(-EOPNOTSUPP); } +static inline int bpf_lsm_attach(struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} +static inline int bpf_lsm_detach(struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_SECURITY_BPF */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index b6a725a8a21d..fa5513cb3332 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -448,6 +448,10 @@ union bpf_attr { __u32 line_info_cnt; /* number of bpf_line_info records */ __u32 attach_btf_id; /* in-kernel BTF type id to attach to */ __u32 attach_prog_fd; /* 0 to attach to vmlinux */ + /* Index (one-based) of the hlist_head in security_hook_heads to + * which the program must be attached. + */ + __u32 lsm_hook_index; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 2945739618c9..a54eb1032fdd 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -1751,7 +1752,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type, } /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD attach_prog_fd +#define BPF_PROG_LOAD_LAST_FIELD lsm_hook_index static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) { @@ -1805,6 +1806,10 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) prog->expected_attach_type = attr->expected_attach_type; prog->aux->attach_btf_id = attr->attach_btf_id; + + if (type == BPF_PROG_TYPE_LSM) + prog->aux->lsm_hook_index = attr->lsm_hook_index; + if (attr->attach_prog_fd) { struct bpf_prog *tgt_prog; @@ -1970,6 +1975,44 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog) return err; } +static int bpf_lsm_prog_release(struct inode *inode, struct file *filp) +{ + struct bpf_prog *prog = filp->private_data; + + WARN_ON_ONCE(bpf_lsm_detach(prog)); + bpf_prog_put(prog); + return 0; +} + +static const struct file_operations bpf_lsm_prog_fops = { + .release = bpf_lsm_prog_release, + .read = bpf_dummy_read, + .write = bpf_dummy_write, +}; + +static int bpf_lsm_prog_attach(struct bpf_prog *prog) +{ + int ret; + + if (prog->expected_attach_type != BPF_LSM_MAC) + return -EINVAL; + + /* The attach increments the references to the program which is + * decremented on detach as a part of bpf_lsm_hook_free. + */ + ret = bpf_lsm_attach(prog); + if (ret) + return ret; + + ret = anon_inode_getfd("bpf-lsm-prog", &bpf_lsm_prog_fops, + prog, O_CLOEXEC); + if (ret < 0) { + bpf_lsm_detach(prog); + return ret; + } + return 0; +} + struct bpf_raw_tracepoint { struct bpf_raw_event_map *btp; struct bpf_prog *prog; @@ -2186,7 +2229,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_prog_attach(prog); break; case BPF_PROG_TYPE_FLOW_DISSECTOR: ret = skb_flow_dissector_bpf_prog_attach(attr, prog); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ca17dccc17ba..10f44c3b15ec 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "disasm.h" @@ -6393,8 +6394,9 @@ static int check_return_code(struct bpf_verifier_env *env) struct tnum range = tnum_range(0, 1); int err; - /* The struct_ops func-ptr's return type could be "void" */ - if (env->prog->type == BPF_PROG_TYPE_STRUCT_OPS && + /* LSM and struct_ops func-ptr's return type could be "void" */ + if ((env->prog->type == BPF_PROG_TYPE_STRUCT_OPS || + env->prog->type == BPF_PROG_TYPE_LSM) && !prog->aux->attach_func_proto->type) return 0; @@ -9734,7 +9736,51 @@ static int check_struct_ops_btf_id(struct bpf_verifier_env *env) return 0; } -static int check_attach_btf_id(struct bpf_verifier_env *env) +/* BPF_PROG_TYPE_LSM programs pass the member index of the LSM hook in the + * security_hook_heads as the lsm_hook_index. The verifier determines the + * name and the prototype for the LSM hook using the information in + * security_list_options, validates if the offset is a valid hlist_head, and + * updates the attach_btf_id to the byte offset in the security_hook_heads + * struct. + */ +static inline int check_attach_btf_id_lsm(struct bpf_verifier_env *env) +{ + struct bpf_prog *prog = env->prog; + u32 index = prog->aux->lsm_hook_index; + const struct btf_member *head; + const struct btf_type *t; + const char *tname; + int ret; + + ret = bpf_lsm_verify_prog(prog); + if (ret < 0) + return -EINVAL; + + t = bpf_lsm_type_by_index(btf_vmlinux, index); + if (!t) { + verbose(env, "unable to find security_list_option for index %u in security_hook_heads\n", index); + return -EINVAL; + } + + if (!btf_type_is_func_proto(t)) + return -EINVAL; + + head = bpf_lsm_head_by_index(btf_vmlinux, index); + if (IS_ERR(head)) { + verbose(env, "no security_hook_heads index = %u\n", index); + return PTR_ERR(head); + } + + tname = btf_name_by_offset(btf_vmlinux, head->name_off); + if (!tname || !tname[0]) + return -EINVAL; + + 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; @@ -9749,12 +9795,6 @@ static int check_attach_btf_id(struct bpf_verifier_env *env) long addr; u64 key; - if (prog->type == BPF_PROG_TYPE_STRUCT_OPS) - return check_struct_ops_btf_id(env); - - if (prog->type != BPF_PROG_TYPE_TRACING) - return 0; - if (!btf_id) { verbose(env, "Tracing programs must provide btf_id\n"); return -EINVAL; @@ -9895,6 +9935,22 @@ 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_STRUCT_OPS: + return check_struct_ops_btf_id(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) { diff --git a/security/bpf/Kconfig b/security/bpf/Kconfig index 9438d899b618..a915c549f4b8 100644 --- a/security/bpf/Kconfig +++ b/security/bpf/Kconfig @@ -8,6 +8,7 @@ config SECURITY_BPF depends on BPF_SYSCALL depends on SRCU depends on DEBUG_INFO_BTF + depends on BPF_JIT && HAVE_EBPF_JIT help This enables instrumentation of the security hooks with eBPF programs. diff --git a/security/bpf/Makefile b/security/bpf/Makefile index c526927c337d..748b9b7d4bc7 100644 --- a/security/bpf/Makefile +++ b/security/bpf/Makefile @@ -3,3 +3,5 @@ # Copyright 2019 Google LLC. obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o hooks.o + +ccflags-y := -I$(srctree)/security/bpf -I$(srctree)/security/bpf/include diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index 82725611693d..4e71da0e8e9e 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -6,9 +6,14 @@ #include #include +#include #include #include +#include "bpf_lsm.h" + +#define SECURITY_LIST_HEAD(off) ((void *)&bpf_lsm_hook_heads + off) + DEFINE_STATIC_SRCU(security_hook_srcu); int bpf_lsm_srcu_read_lock(void) @@ -32,21 +37,36 @@ static inline int validate_hlist_head(struct btf *btf, u32 type_id) return 0; } +int bpf_lsm_verify_prog(const struct bpf_prog *prog) +{ + u32 index = prog->aux->lsm_hook_index; + struct bpf_verifier_log log = {}; + + if (!prog->gpl_compatible) { + bpf_log(&log, + "LSM programs must have a GPL compatible license\n"); + return -EINVAL; + } + + if (index < 1 || index > bpf_lsm_info.num_hooks) { + bpf_log(&log, "lsm_hook_index should be between 1 and %lu\n", + bpf_lsm_info.num_hooks); + return -EINVAL; + } + + return 0; +} + /* Find the BTF representation of the security_hook_heads member for a member * with a given index in struct security_hook_heads. */ const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 index) { const struct btf_member *member; - const struct btf_type *t; u32 off, i; int ret; - t = btf_type_by_name_kind(btf, "security_hook_heads", BTF_KIND_STRUCT); - if (WARN_ON_ONCE(IS_ERR(t))) - return ERR_CAST(t); - - for_each_member(i, t, member) { + for_each_member(i, bpf_lsm_info.btf_hook_heads, member) { /* We've found the id requested and need to check the * the following: * @@ -54,8 +74,9 @@ const struct btf_member *bpf_lsm_head_by_index(struct btf *btf, u32 index) * * - Is it a valid hlist_head struct? */ - if (index == i) { - off = btf_member_bit_offset(t, member); + if (index == i + 1) { + off = btf_member_bit_offset( + bpf_lsm_info.btf_hook_heads, member); if (off % 8) /* valid c code cannot generate such btf */ return ERR_PTR(-EINVAL); @@ -90,11 +111,7 @@ const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 index) if (IS_ERR(hook_head)) return ERR_PTR(PTR_ERR(hook_head)); - t = btf_type_by_name_kind(btf, "security_list_options", BTF_KIND_UNION); - if (WARN_ON_ONCE(IS_ERR(t))) - return ERR_CAST(t); - - for_each_member(i, t, member) { + for_each_member(i, bpf_lsm_info.btf_hook_types, member) { if (hook_head->name_off == member->name_off) { /* There should be only one member with the same name * as the LSM hook. This should never really happen @@ -122,3 +139,190 @@ const struct btf_type *bpf_lsm_type_by_index(struct btf *btf, u32 index) return t; } + +static void *bpf_lsm_get_func_addr(struct security_hook_list *s, + const char *name) +{ + const struct btf_member *member; + void *addr = NULL; + s32 i; + + for_each_member(i, bpf_lsm_info.btf_hook_types, member) { + if (!strncmp(btf_name_by_offset(btf_vmlinux, member->name_off), + name, strlen(name) + 1)) { + /* There should be only one member with the same name + * as the LSM hook. + */ + if (WARN_ON(addr)) + return ERR_PTR(-EINVAL); + addr = (void *)&s->hook + member->offset / 8; + } + } + + if (!addr) + return ERR_PTR(-ENOENT); + return addr; +} + +static struct bpf_lsm_list *bpf_lsm_list_lookup(struct bpf_prog *prog) +{ + u32 index = prog->aux->lsm_hook_index; + struct bpf_verifier_log bpf_log = {}; + const struct btf_member *head; + struct bpf_lsm_list *list; + int ret = 0; + + list = &bpf_lsm_info.hook_lists[index - 1]; + + mutex_lock(&list->mutex); + + if (list->initialized) + goto unlock; + + list->attach_type = prog->aux->attach_func_proto; + + ret = btf_distill_func_proto(&bpf_log, btf_vmlinux, list->attach_type, + prog->aux->attach_func_name, + &list->func_model); + if (ret) + goto unlock; + + head = bpf_lsm_head_by_index(btf_vmlinux, index); + if (IS_ERR(head)) { + ret = PTR_ERR(head); + goto unlock; + } + + list->security_list_head = SECURITY_LIST_HEAD(head->offset / 8); + list->initialized = true; +unlock: + mutex_unlock(&list->mutex); + if (ret) + return ERR_PTR(ret); + return list; +} + +static struct bpf_lsm_hook *bpf_lsm_hook_alloc( + struct bpf_lsm_list *list, struct bpf_prog *prog) +{ + struct bpf_lsm_hook *hook; + void *image; + int ret = 0; + + image = bpf_jit_alloc_exec(PAGE_SIZE); + if (!image) + return ERR_PTR(-ENOMEM); + + set_vm_flush_reset_perms(image); + + ret = arch_prepare_bpf_trampoline(image, image + PAGE_SIZE, + &list->func_model, 0, &prog, 1, NULL, 0, NULL); + if (ret < 0) { + ret = -EINVAL; + goto error; + } + + hook = kzalloc(sizeof(struct bpf_lsm_hook), GFP_KERNEL); + if (!hook) { + ret = -ENOMEM; + goto error; + } + + hook->image = image; + hook->prog = prog; + bpf_prog_inc(prog); + return hook; +error: + bpf_jit_free_exec(image); + return ERR_PTR(ret); +} + +static void bpf_lsm_hook_free(struct bpf_lsm_hook *tr) +{ + if (!tr) + return; + + if (tr->prog) + bpf_prog_put(tr->prog); + + bpf_jit_free_exec(tr->image); + kfree(tr); +} + +int bpf_lsm_attach(struct bpf_prog *prog) +{ + struct bpf_lsm_hook *hook; + struct bpf_lsm_list *list; + void **addr; + int ret = 0; + + /* Only CAP_MAC_ADMIN users are allowed to make changes to LSM hooks + */ + if (!capable(CAP_MAC_ADMIN)) + return -EPERM; + + if (!bpf_lsm_info.initialized) + return -EBUSY; + + list = bpf_lsm_list_lookup(prog); + if (IS_ERR(list)) + return PTR_ERR(list); + + hook = bpf_lsm_hook_alloc(list, prog); + if (IS_ERR(hook)) + return PTR_ERR(hook); + + hook->sec_hook.head = list->security_list_head; + addr = bpf_lsm_get_func_addr(&hook->sec_hook, + prog->aux->attach_func_name); + if (IS_ERR(addr)) { + ret = PTR_ERR(addr); + goto error; + } + + *addr = hook->image; + + mutex_lock(&list->mutex); + hlist_add_tail_rcu(&hook->sec_hook.list, hook->sec_hook.head); + mutex_unlock(&list->mutex); + return 0; + +error: + bpf_lsm_hook_free(hook); + return ret; +} + +int bpf_lsm_detach(struct bpf_prog *prog) +{ + struct security_hook_list *sec_hook; + struct bpf_lsm_hook *hook = NULL; + struct bpf_lsm_list *list; + struct hlist_node *n; + + /* Only CAP_MAC_ADMIN users are allowed to make changes to LSM hooks + */ + if (!capable(CAP_MAC_ADMIN)) + return -EPERM; + + if (!bpf_lsm_info.initialized) + return -EBUSY; + + list = &bpf_lsm_info.hook_lists[prog->aux->lsm_hook_index - 1]; + + mutex_lock(&list->mutex); + hlist_for_each_entry_safe(sec_hook, n, list->security_list_head, list) { + hook = container_of(sec_hook, struct bpf_lsm_hook, sec_hook); + if (hook->prog == prog) { + hlist_del_rcu(&hook->sec_hook.list); + break; + } + } + mutex_unlock(&list->mutex); + /* call_rcu is not used directly as module_memfree cannot run from an + * softirq context. The best way would be to schedule this on a work + * queue. + */ + synchronize_srcu(&security_hook_srcu); + bpf_lsm_hook_free(hook); + return 0; +} diff --git a/security/bpf/include/bpf_lsm.h b/security/bpf/include/bpf_lsm.h new file mode 100644 index 000000000000..849f7f64d7f2 --- /dev/null +++ b/security/bpf/include/bpf_lsm.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _BPF_LSM_H +#define _BPF_LSM_H + +#include +#include +#include +#include + + +struct bpf_lsm_hook { + /* The security_hook_list is initialized dynamically. These are + * initialized in static LSMs by LSM_HOOK_INIT. + */ + struct security_hook_list sec_hook; + /* The BPF program for which this hook was allocated, this is used upon + * detachment to find the hook corresponding to a program. + */ + struct bpf_prog *prog; + /* The address of the allocated function */ + void *image; +}; + +/* The list represents the list of hooks attached to a particular + * security_list_head and contains information required for attaching and + * detaching BPF Programs. + */ +struct bpf_lsm_list { + /* Used on the first attached BPF program to populate the remaining + * information + */ + bool initialized; + /* This mutex is used to serialize accesses to all the fields in + * this structure. + */ + struct mutex mutex; + /* The BTF type for this hook. + */ + const struct btf_type *attach_type; + /* func_model for the setup of the callback. + */ + struct btf_func_model func_model; + /* The list of functions currently associated with the LSM hook. + */ + struct list_head callback_list; + /* The head to which the allocated hooks must be attached to. + */ + struct hlist_head *security_list_head; +}; + +struct bpf_lsm_info { + /* Dynamic Hooks can only be attached after the LSM is initialized. + */ + bool initialized; + /* The number of hooks is calculated at runtime using the BTF + * information of the struct security_hook_heads. + */ + size_t num_hooks; + /* The hook_lists is allocated during __init and mutexes for each + * allocated on __init, the remaining initialization happens when a + * BPF program is attached to the list. + */ + struct bpf_lsm_list *hook_lists; + /* BTF type for security_hook_heads populated at init. + */ + const struct btf_type *btf_hook_heads; + /* BTF type for security_list_options populated at init. + */ + const struct btf_type *btf_hook_types; +}; + +extern struct bpf_lsm_info bpf_lsm_info; + +#endif /* _BPF_LSM_H */ diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c index d4ea6aa9ddb8..3bab187e7574 100644 --- a/security/bpf/lsm.c +++ b/security/bpf/lsm.c @@ -7,6 +7,8 @@ #include #include +#include "bpf_lsm.h" + /* This is only for internal hooks, always statically shipped as part of the * BPF LSM. Statically defined hooks are appended to the security_hook_heads * which is common for LSMs and R/O after init. @@ -19,6 +21,64 @@ static struct security_hook_list lsm_hooks[] __lsm_ro_after_init = {}; */ struct security_hook_heads bpf_lsm_hook_heads; +/* Security hooks registered dynamically by the BPF LSM and must be accessed + * by holding bpf_lsm_srcu_read_lock and bpf_lsm_srcu_read_unlock. + */ +struct bpf_lsm_info bpf_lsm_info; + +static __init int init_lsm_info(void) +{ + const struct btf_type *t; + size_t num_hooks; + int i; + + if (!btf_vmlinux) + /* No need to grab any locks because we are still in init */ + btf_vmlinux = btf_parse_vmlinux(); + + if (IS_ERR(btf_vmlinux)) { + pr_err("btf_vmlinux is malformed\n"); + return PTR_ERR(btf_vmlinux); + } + + t = btf_type_by_name_kind(btf_vmlinux, "security_hook_heads", + BTF_KIND_STRUCT); + if (WARN_ON(IS_ERR(t))) + return PTR_ERR(t); + + num_hooks = btf_type_vlen(t); + if (num_hooks <= 0) + return -EINVAL; + + bpf_lsm_info.num_hooks = num_hooks; + bpf_lsm_info.btf_hook_heads = t; + + t = btf_type_by_name_kind(btf_vmlinux, "security_list_options", + BTF_KIND_UNION); + if (WARN_ON(IS_ERR(t))) + return PTR_ERR(t); + + bpf_lsm_info.btf_hook_types = t; + + bpf_lsm_info.hook_lists = kcalloc(num_hooks, + sizeof(struct bpf_lsm_list), GFP_KERNEL); + if (!bpf_lsm_info.hook_lists) + return -ENOMEM; + + /* The mutex needs to be initialized at init as it must be held + * when mutating the list. The rest of the information in the list + * is populated lazily when the first LSM hook callback is appeneded + * to the list. + */ + for (i = 0; i < num_hooks; i++) + mutex_init(&bpf_lsm_info.hook_lists[i].mutex); + + bpf_lsm_info.initialized = true; + return 0; +} + +late_initcall(init_lsm_info); + static int __init lsm_init(void) { security_add_hooks(lsm_hooks, ARRAY_SIZE(lsm_hooks), "bpf"); diff --git a/security/bpf/ops.c b/security/bpf/ops.c index 81c2bd9c0495..9a26633ac6f3 100644 --- a/security/bpf/ops.c +++ b/security/bpf/ops.c @@ -6,6 +6,7 @@ #include #include +#include const struct bpf_prog_ops lsm_prog_ops = { }; @@ -25,4 +26,5 @@ static const struct bpf_func_proto *get_bpf_func_proto( const struct bpf_verifier_ops lsm_verifier_ops = { .get_func_proto = get_bpf_func_proto, + .is_valid_access = btf_ctx_access, }; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index b6a725a8a21d..fa5513cb3332 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -448,6 +448,10 @@ union bpf_attr { __u32 line_info_cnt; /* number of bpf_line_info records */ __u32 attach_btf_id; /* in-kernel BTF type id to attach to */ __u32 attach_prog_fd; /* 0 to attach to vmlinux */ + /* Index (one-based) of the hlist_head in security_hook_heads to + * which the program must be attached. + */ + __u32 lsm_hook_index; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ From patchwork Wed Jan 15 17:13:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335463 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 3AD151398 for ; Wed, 15 Jan 2020 17:13:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 19231214AF for ; Wed, 15 Jan 2020 17:13:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="LBAXJRfH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729187AbgAORNv (ORCPT ); Wed, 15 Jan 2020 12:13:51 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:37313 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729205AbgAORNb (ORCPT ); Wed, 15 Jan 2020 12:13:31 -0500 Received: by mail-wr1-f66.google.com with SMTP id w15so16555285wru.4 for ; Wed, 15 Jan 2020 09:13:29 -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=BaXbvr8+/AA5pEwEC4kv+1bgxSxLzCBOcAqmhtuHoC8=; b=LBAXJRfH3GQwmfbGHhOP1Qs+7KpRm8fZjQ41I8LdOrmCDEDC2viG0gJQUFHB/CVPGk oj75ReZAzSfNOXgWbBKxLiPwi8i+/+EawU5XrPOsLq3jjkkBS1xYPzP1d0YrdhdZTiAm 6y9G1Av8SYD6NNmlGhd8DNjum6poEDVsfuZVo= 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=BaXbvr8+/AA5pEwEC4kv+1bgxSxLzCBOcAqmhtuHoC8=; b=W9VPiBpeDnHUbTBGAWDrRms1AfujgEnHG0aez25ZR6qTe5DrHiSH9DQ+UcanDy9n9M iOOEHgFeGj3ZXChzMgfCPXKM3cH5qyCLUc3vfysYJNiAHZ06qBujOpbA+uhK416swQWT nn3+DBl3K/7LoXOZ82iSDYm1JgfitKd4wK30qGUVsVdV64MwOPVvtADA6Y7vxRG/GFa0 EfCa8X1BPYptPNIctPNC7EbKk+4PMxbikABVGVYw/YyqcYjzOyJzXrDwrKg+Ry5Yl5lw AwsgV6TDTyuTDTT82Pi3fxxK9e19voKhM5+5nL0bsoXbSjzjGsr+t5SDIk6yRfKF0ssx 7zgw== X-Gm-Message-State: APjAAAUpfpmkxanrvvO/5ZLw/nEFOYFzLNDuLSpbNfPZznvDhRjot+si JijsYRrCLJfTHtXh22XpZJTAQQ== X-Google-Smtp-Source: APXvYqz+g9S4xsM16ZfhVtVBf5Pz0OA7zWuCU8BbSiBF/2A6sRIyLfsT4wowSgFNOpCHDbrvJcI30g== X-Received: by 2002:adf:df83:: with SMTP id z3mr33208227wrl.389.1579108408840; Wed, 15 Jan 2020 09:13:28 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:28 -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 v2 07/10] bpf: lsm: Make the allocated callback RO+X Date: Wed, 15 Jan 2020 18:13:30 +0100 Message-Id: <20200115171333.28811-8-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-1-kpsingh@chromium.org> MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: From: KP Singh This patch is not needed after arch_bpf_prepare_trampoline moves to using text_poke. The two IPI TLB flushes can be further optimized if a new API to handle W^X in the kernel emerges as an outcome of: https://lore.kernel.org/bpf/20200103234725.22846-1-kpsingh@chromium.org/ Signed-off-by: KP Singh --- security/bpf/hooks.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index 4e71da0e8e9e..30f68341f5ef 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -222,6 +222,15 @@ static struct bpf_lsm_hook *bpf_lsm_hook_alloc( goto error; } + /* First make the page read-only, and only then make it executable to + * prevent it from being W+X in between. + */ + set_memory_ro((unsigned long)image, 1); + /* More checks can be done here to ensure that nothing was changed + * between arch_prepare_bpf_trampoline and set_memory_ro. + */ + set_memory_x((unsigned long)image, 1); + hook = kzalloc(sizeof(struct bpf_lsm_hook), GFP_KERNEL); if (!hook) { ret = -ENOMEM; From patchwork Wed Jan 15 17:13:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335459 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 BE6751398 for ; Wed, 15 Jan 2020 17:13:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 89FC22465A for ; Wed, 15 Jan 2020 17:13:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="B4TDSS4j" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729238AbgAORNe (ORCPT ); Wed, 15 Jan 2020 12:13:34 -0500 Received: from mail-wm1-f68.google.com ([209.85.128.68]:33166 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729214AbgAORNd (ORCPT ); Wed, 15 Jan 2020 12:13:33 -0500 Received: by mail-wm1-f68.google.com with SMTP id d139so5232182wmd.0 for ; Wed, 15 Jan 2020 09:13:30 -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=mktwKZSETcjiyrbo7D7SVrrGAN7eQ+QLRwyOiaxwtjk=; b=B4TDSS4jpyYEUcz/GoC5f99iaMqwHeBgWIsQaVZvGplJkQZ7NsKTJEgrarESMQmabU u2yfVEXrxmblphZ9r0cIamh0raC9hc9gfXzU2aWne6YoEH5I1WDZ2l+3ceakArmSep88 KFehzMly1smDp1ctozNrUO7iijhZ4HKOuY7Dk= 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=mktwKZSETcjiyrbo7D7SVrrGAN7eQ+QLRwyOiaxwtjk=; b=Zot6xrLhghYq/OQFkQBcVsjvyydXeLsCDfqrkV2H3sjC0QLj9mwPTkkjxhb3gmc4ed 8+GTQkTvBMJUNRHm9K50mPlYLTdgOugLMoywMtc/lsqk7u22C+ukKO944Uzoeqao5SmY bWbCejbkpBZDotYW3BaNPwTcBNlkOKHjy7HOokv835OEUbAQVebbcw6l8xJRJzMDdy92 ip+d07W9Xh82Tv6iLtV2cqo6TEyEpvMJbXlXMusmONFhp65OBXpnXxEZd/4z/9aIvlz3 1GvJDIwtH/r+t8A/wNI5bsSu9qGLEbpu74e2FhiZDppnhY/9c6AP50F124Na0yFB9/9l JkOQ== X-Gm-Message-State: APjAAAV6i3xXZBq2lg4BAXtWYYxyXQ2Xt8UGPHmD+wkHG5H8bYWHCMlO sr6egvQ6MZkZ8tEHco7LqRGRNg== X-Google-Smtp-Source: APXvYqwpDqKQNfPTUoZyZm6olZzqzzgR4tL2MYWWuI+CK8yw2ObHvBugmOqztNTIztWF4DbH/ZwZXQ== X-Received: by 2002:a1c:5444:: with SMTP id p4mr910785wmi.33.1579108410123; Wed, 15 Jan 2020 09:13:30 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:29 -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 v2 08/10] tools/libbpf: Add support for BPF_PROG_TYPE_LSM Date: Wed, 15 Jan 2020 18:13:31 +0100 Message-Id: <20200115171333.28811-9-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-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 * Lookup the index of the LSM hook in security_hook_heads and pass it in attr->lsm_hook_index Signed-off-by: KP Singh --- tools/lib/bpf/bpf.c | 6 +- tools/lib/bpf/bpf.h | 1 + tools/lib/bpf/libbpf.c | 143 ++++++++++++++++++++++++++++++++++----- tools/lib/bpf/libbpf.h | 4 ++ tools/lib/bpf/libbpf.map | 3 + 5 files changed, 138 insertions(+), 19 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 500afe478e94..b138d98ff862 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -235,7 +235,10 @@ 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_STRUCT_OPS) { + + if (attr.prog_type == BPF_PROG_TYPE_LSM) { + attr.lsm_hook_index = load_attr->lsm_hook_index; + } else if (attr.prog_type == BPF_PROG_TYPE_STRUCT_OPS) { attr.attach_btf_id = load_attr->attach_btf_id; } else if (attr.prog_type == BPF_PROG_TYPE_TRACING) { attr.attach_btf_id = load_attr->attach_btf_id; @@ -244,6 +247,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, attr.prog_ifindex = load_attr->prog_ifindex; attr.kern_version = load_attr->kern_version; } + attr.insn_cnt = (__u32)load_attr->insns_cnt; attr.insns = ptr_to_u64(load_attr->insns); attr.license = ptr_to_u64(load_attr->license); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 56341d117e5b..54458a102939 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -86,6 +86,7 @@ struct bpf_load_program_attr { __u32 prog_ifindex; __u32 attach_btf_id; }; + __u32 lsm_hook_index; __u32 prog_btf_fd; __u32 func_info_rec_size; const void *func_info; diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 0c229f00a67e..60737559a9a6 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -229,6 +229,7 @@ struct bpf_program { enum bpf_attach_type expected_attach_type; __u32 attach_btf_id; __u32 attach_prog_fd; + __u32 lsm_hook_index; void *func_info; __u32 func_info_rec_size; __u32 func_info_cnt; @@ -4886,7 +4887,10 @@ 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_STRUCT_OPS) { + + if (prog->type == BPF_PROG_TYPE_LSM) { + load_attr.lsm_hook_index = prog->lsm_hook_index; + } else if (prog->type == BPF_PROG_TYPE_STRUCT_OPS) { load_attr.attach_btf_id = prog->attach_btf_id; } else if (prog->type == BPF_PROG_TYPE_TRACING) { load_attr.attach_prog_fd = prog->attach_prog_fd; @@ -4895,6 +4899,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, load_attr.kern_version = kern_version; load_attr.prog_ifindex = prog->prog_ifindex; } + /* if .BTF.ext was loaded, kernel supports associated BTF for prog */ if (prog->obj->btf_ext) btf_fd = bpf_object__btf_fd(prog->obj); @@ -4967,9 +4972,11 @@ static int libbpf_find_attach_btf_id(const char *name, enum bpf_attach_type attach_type, __u32 attach_prog_fd); +static __s32 btf__find_lsm_hook_index(const char *name); + int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver) { - int err = 0, fd, i, btf_id; + int err = 0, fd, i, btf_id, index; if (prog->type == BPF_PROG_TYPE_TRACING) { btf_id = libbpf_find_attach_btf_id(prog->section_name, @@ -4980,6 +4987,13 @@ int bpf_program__load(struct bpf_program *prog, char *license, __u32 kern_ver) prog->attach_btf_id = btf_id; } + if (prog->type == BPF_PROG_TYPE_LSM) { + index = btf__find_lsm_hook_index(prog->section_name); + if (index < 0) + return index; + prog->lsm_hook_index = index; + } + if (prog->instances.nr < 0 || !prog->instances.fds) { if (prog->preprocessor) { pr_warn("Internal error: can't load program '%s'\n", @@ -6207,6 +6221,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); @@ -6272,6 +6287,8 @@ static struct bpf_link *attach_raw_tp(const struct bpf_sec_def *sec, struct bpf_program *prog); static struct bpf_link *attach_trace(const struct bpf_sec_def *sec, struct bpf_program *prog); +static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec, + struct bpf_program *prog); struct bpf_sec_def { const char *sec; @@ -6315,12 +6332,17 @@ static const struct bpf_sec_def section_defs[] = { .expected_attach_type = BPF_TRACE_FEXIT, .is_attach_btf = true, .attach_fn = attach_trace), + SEC_DEF("lsm/", LSM, + .expected_attach_type = BPF_LSM_MAC, + .attach_fn = attach_lsm), BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP), BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT), BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), 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, @@ -6576,32 +6598,80 @@ static int bpf_object__collect_struct_ops_map_reloc(struct bpf_object *obj, return -EINVAL; } -#define BTF_PREFIX "btf_trace_" +#define BTF_TRACE_PREFIX "btf_trace_" + +static inline int btf__find_by_prefix_kind(struct btf *btf, const char *name, + const char *prefix, __u32 kind) +{ + char btf_type_name[128]; + + snprintf(btf_type_name, sizeof(btf_type_name), "%s%s", prefix, name); + return btf__find_by_name_kind(btf, btf_type_name, kind); +} + +static __s32 btf__find_lsm_hook_index(const char *name) +{ + struct btf *btf = bpf_find_kernel_btf(); + const struct bpf_sec_def *sec_def; + const struct btf_type *hl_type; + struct btf_member *m; + __u16 vlen; + __s32 hl_id; + int j; + + sec_def = find_sec_def(name); + if (!sec_def) + return -ESRCH; + + name += sec_def->len; + + hl_id = btf__find_by_name_kind(btf, "security_hook_heads", + BTF_KIND_STRUCT); + if (hl_id < 0) { + pr_debug("security_hook_heads cannot be found in BTF\n"); + return hl_id; + } + + hl_type = btf__type_by_id(btf, hl_id); + if (!hl_type) { + pr_warn("Can't find type for security_hook_heads: %u\n", hl_id); + return -EINVAL; + } + + m = btf_members(hl_type); + vlen = btf_vlen(hl_type); + + for (j = 0; j < vlen; j++) { + if (!strcmp(btf__name_by_offset(btf, m->name_off), name)) + return j + 1; + m++; + } + + pr_warn("Cannot find offset for %s in security_hook_heads\n", name); + return -ENOENT; +} + int libbpf_find_vmlinux_btf_id(const char *name, enum bpf_attach_type attach_type) { struct btf *btf = bpf_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__find_by_prefix_kind(btf, name, BTF_TRACE_PREFIX, + BTF_KIND_TYPEDEF); + else + err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC); + + /* err = 0 means void / UNKNOWN which is treated as an error */ + if (err == 0) + err = -EINVAL; + btf__free(btf); return err; } @@ -6630,7 +6700,7 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd) } err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC); btf__free(btf); - if (err <= 0) { + if (err < 0) { pr_warn("%s is not found in prog's BTF\n", name); goto out; } @@ -7395,6 +7465,43 @@ static struct bpf_link *attach_trace(const struct bpf_sec_def *sec, return bpf_program__attach_trace(prog); } +struct bpf_link *bpf_program__attach_lsm(struct bpf_program *prog) +{ + char errmsg[STRERR_BUFSIZE]; + struct bpf_link_fd *link; + int prog_fd, pfd; + + prog_fd = bpf_program__fd(prog); + if (prog_fd < 0) { + pr_warn("program '%s': can't attach before loaded\n", + bpf_program__title(prog, false)); + return ERR_PTR(-EINVAL); + } + + link = calloc(1, sizeof(*link)); + if (!link) + return ERR_PTR(-ENOMEM); + link->link.detach = &bpf_link__detach_fd; + + pfd = bpf_prog_attach(prog_fd, 0, BPF_LSM_MAC, + BPF_F_ALLOW_OVERRIDE); + if (pfd < 0) { + pfd = -errno; + pr_warn("program '%s': failed to attach: %s\n", + bpf_program__title(prog, false), + libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); + return ERR_PTR(pfd); + } + link->fd = pfd; + return (struct bpf_link *)link; +} + +static struct bpf_link *attach_lsm(const struct bpf_sec_def *sec, + struct bpf_program *prog) +{ + return bpf_program__attach_lsm(prog); +} + struct bpf_link *bpf_program__attach(struct bpf_program *prog) { const struct bpf_sec_def *sec_def; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 01639f9a1062..a97e709a29e6 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -241,6 +241,8 @@ LIBBPF_API struct bpf_link * bpf_program__attach_trace(struct bpf_program *prog); struct bpf_map; LIBBPF_API struct bpf_link *bpf_map__attach_struct_ops(struct bpf_map *map); +LIBBPF_API struct bpf_link * +bpf_program__attach_lsm(struct bpf_program *prog); struct bpf_insn; /* @@ -318,6 +320,7 @@ 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_struct_ops(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, @@ -339,6 +342,7 @@ 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_struct_ops(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 a19f04e6e3d9..3da0452ce679 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -227,4 +227,7 @@ LIBBPF_0.0.7 { bpf_program__is_struct_ops; bpf_program__set_struct_ops; btf__align_of; + bpf_program__is_lsm; + bpf_program__set_lsm; + bpf_program__attach_lsm; } LIBBPF_0.0.6; From patchwork Wed Jan 15 17:13:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335455 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 A416792A for ; Wed, 15 Jan 2020 17:13:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 788B524685 for ; Wed, 15 Jan 2020 17:13:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="VoK/cfOe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728993AbgAORNd (ORCPT ); Wed, 15 Jan 2020 12:13:33 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:36841 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729238AbgAORNd (ORCPT ); Wed, 15 Jan 2020 12:13:33 -0500 Received: by mail-wm1-f66.google.com with SMTP id p17so769177wma.1 for ; Wed, 15 Jan 2020 09:13:31 -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=Lk48qetZKyKWukIhgwRh7oanEwAxdHUHawT8EKhLs24=; b=VoK/cfOe18OMZeAhDw6GvIcgIn+YfEmL6obJDGmidtIeyWIry3wPOk4NCkSghYOqgt FeSzZ7cht3VGP5OcZA27IdhxA1nLZrCn47WOd4vn8st/5s/ELgE31T77Hh95XdCiVWTq +WTpsm9K1VCH6FCQ9+xRFEFX/AGr4ShHKjHKk= 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=Lk48qetZKyKWukIhgwRh7oanEwAxdHUHawT8EKhLs24=; b=XhpmzPRZ+aU3+DIvXQYCBsX3Z9MiRaYqetnR6BCFEwm13Iqv0XcYUsYyYdm37Awaka y+2ujpfafDyCdGGtTPUhSPCD2hx4rQMYG+5yL9fU/k652zELos15Gk7Os6NtTIwQtK0I JVRtSQZy3tiH6W8O5Ut+MJGdO3ulUCrVQeSmc4a2NOAIGuxKZ2SveWS/Ad29hbFe3mUN 6ZewNUAX4rPDgNHP2HK7AdjiNUp9VhcYxIIbc9OgIs37/Y0nR7KvtTL2GtS7EclARdzC sXlhAuT1dtmHzKMAsMWG1JYZOnFdgLYGDCWYwP5WkZgWqTKgb/OHJ26h9DTy49h1rzWb Vxvw== X-Gm-Message-State: APjAAAXVvEW/RjpcyJ5orpCJn5f2hKV2Tn9Wiq3spLZm0FwmzC3u5gdP HJcp9OH+dwGfMlphQRwNidCI6Q== X-Google-Smtp-Source: APXvYqxZnUBXj2TFr0fRlMTriJRJqkxc4KcmmCaQtMroHNbH2lkUynRPDo66FDJDeFTfsoDchvsRXw== X-Received: by 2002:a05:600c:2c2:: with SMTP id 2mr879104wmn.155.1579108411281; Wed, 15 Jan 2020 09:13:31 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:30 -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 v2 09/10] bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM Date: Wed, 15 Jan 2020 18:13:32 +0100 Message-Id: <20200115171333.28811-10-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-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 * 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 --- MAINTAINERS | 2 + tools/testing/selftests/bpf/lsm_helpers.h | 19 ++++++ .../bpf/prog_tests/lsm_mprotect_audit.c | 58 +++++++++++++++++++ .../selftests/bpf/progs/lsm_mprotect_audit.c | 48 +++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 tools/testing/selftests/bpf/lsm_helpers.h 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 02d7e05e9b75..5d553c2e7452 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3210,6 +3210,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/lsm_helpers.h b/tools/testing/selftests/bpf/lsm_helpers.h new file mode 100644 index 000000000000..8bad08f77654 --- /dev/null +++ b/tools/testing/selftests/bpf/lsm_helpers.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright 2019 Google LLC. + */ +#ifndef _LSM_HELPERS_H +#define _LSM_HELPERS_H + +struct lsm_mprotect_audit_result { + /* This ensures that the LSM Hook only monitors the PID requested + * by the loader + */ + __u32 monitored_pid; + /* The number of mprotect calls for the monitored PID. + */ + __u32 mprotect_count; +}; + +#endif /* _LSM_HELPERS_H */ 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..ff90b874eafc --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include +#include +#include +#include "lsm_helpers.h" +#include "lsm_mprotect_audit.skel.h" + +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 lsm_mprotect_audit_result *result; + struct lsm_mprotect_audit *skel = NULL; + int err, duration = 0; + + skel = lsm_mprotect_audit__open_and_load(); + if (CHECK(!skel, "skel_load", "lsm_mprotect_audit skeleton failed\n")) + goto close_prog; + + err = lsm_mprotect_audit__attach(skel); + if (CHECK(err, "attach", "lsm_mprotect_audit attach failed: %d\n", err)) + goto close_prog; + + result = &skel->bss->result; + result->monitored_pid = getpid(); + + err = heap_mprotect(); + if (CHECK(err < 0, "heap_mprotect", "err %d errno %d\n", err, errno)) + goto close_prog; + + /* Make sure mprotect_audit program was triggered + * and detected an mprotect on the heap. + */ + CHECK_FAIL(result->mprotect_count != 1); + +close_prog: + lsm_mprotect_audit__destroy(skel); +} 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..f4569b418616 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2019 Google LLC. + */ + +#include +#include +#include "bpf_helpers.h" +#include "bpf_trace_helpers.h" +#include "lsm_helpers.h" + +char _license[] SEC("license") = "GPL"; + +struct lsm_mprotect_audit_result result = { + .mprotect_count = 0, + .monitored_pid = 0, +}; + +/* + * 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; +} __attribute__((preserve_access_index)); + +struct vm_area_struct { + unsigned long vm_start, vm_end; + struct mm_struct *vm_mm; +} __attribute__((preserve_access_index)); + +SEC("lsm/file_mprotect") +int BPF_PROG(mprotect_audit, struct vm_area_struct *vma, + unsigned long reqprot, unsigned long prot) +{ + __u32 pid = bpf_get_current_pid_tgid(); + int is_heap = 0; + + is_heap = (vma->vm_start >= vma->vm_mm->start_brk && + vma->vm_end <= vma->vm_mm->brk); + + if (is_heap && result.monitored_pid == pid) + result.mprotect_count++; + + return 0; +} From patchwork Wed Jan 15 17:13:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: KP Singh X-Patchwork-Id: 11335457 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 BFF0892A for ; Wed, 15 Jan 2020 17:13:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8B4052465A for ; Wed, 15 Jan 2020 17:13:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="a//MelKG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729222AbgAORNf (ORCPT ); Wed, 15 Jan 2020 12:13:35 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:56215 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729256AbgAORNe (ORCPT ); Wed, 15 Jan 2020 12:13:34 -0500 Received: by mail-wm1-f66.google.com with SMTP id q9so742251wmj.5 for ; Wed, 15 Jan 2020 09:13:33 -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=irVenSBk+qsWtPOnLfffjUTanFCczadJPyzi1GpXUI4=; b=a//MelKGTTeEPFAZ8QADS5Z8uj/uFdQChD92Dj6apjnnBYpt9gKl/YmEguk6YRTFPv SFUzm3VB9+TvPOnNrtNxJeNRxKSVNjTKfGxIotIxfbJNp4b/gR3ib679Xl3FWX2JWOal acK9dmUlomW7rFWZ/X8zGHyyO8WSv8g5xez3k= 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=irVenSBk+qsWtPOnLfffjUTanFCczadJPyzi1GpXUI4=; b=Lp+oF6f3D7tu2+3tbpxlE+AohvcauwhNQb8IuMvusvKsINHihAHhmKohbzAjdTaaxD gFM2VA+oQlKgMs9m0kFMRLLsE8bY9dkQjp/WqicSus/PSEy5TNTMrt5j+VsBGUCZ58J4 iu1ocA1Av+bOpNR9QhTZBxX75LboYtpaTYQmuUhzgDEtEjd/q8xbvKUK33l0YCjNA3ur haZipA+pwWCZijyCBrL36C832MDTHEurdB9vzcUgOTbBBUCTPRzFMgwxqDJv5UGTBODd ux0NI1TZM5/s+6RFdmaBIaR5KGijKd0/5wgY/cCenUnNQqoWG8vrumlGkztXFacguzcP i6VA== X-Gm-Message-State: APjAAAXoEO7WivLWh02CBTOSW++jdTwyX79doi1Ar4VMKmQp+RrZyeXI Butd79i9tVfVf+kDDvXPbn7vdw== X-Google-Smtp-Source: APXvYqyq8Y0listaQwfuHlfsGtWorsrBUDEQxn03dRh8XEsYAWMqFyOm7c4bfHb/zSQJFrYZ0loj6w== X-Received: by 2002:a1c:48c1:: with SMTP id v184mr942072wma.5.1579108412501; Wed, 15 Jan 2020 09:13:32 -0800 (PST) Received: from kpsingh-kernel.localdomain ([2620:0:105f:fd00:84f3:4331:4ae9:c5f1]) by smtp.gmail.com with ESMTPSA id d16sm26943227wrg.27.2020.01.15.09.13.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jan 2020 09:13:32 -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 v2 10/10] bpf: lsm: Add Documentation Date: Wed, 15 Jan 2020 18:13:33 +0100 Message-Id: <20200115171333.28811-11-kpsingh@chromium.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200115171333.28811-1-kpsingh@chromium.org> References: <20200115171333.28811-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 | 150 +++++++++++++++++++++++++++++++ Documentation/security/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 152 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..4d115c07c370 --- /dev/null +++ b/Documentation/security/bpf.rst @@ -0,0 +1,150 @@ +.. 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 privileged 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 + * The programs are always run after the static hooks (i.e. the ones + registered by SELinux, AppArmor, Smack etc.) + * LSM hooks can return an ``-EPERM`` to indicate the decision of the + MAC policy being enforced or simply be used for auditing + * If ``CONFIG_SECURITY_BPF_ENFORCE`` is enabled and a non-zero error + code is returned from the BPF program, no further BPF programs for the hook are executed + * 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; + } __attribute__((preserve_access_index)); + + struct vm_area_struct { + unsigned long start_brk, brk, start_stack; + unsigned long vm_start, vm_end; + struct mm_struct *vm_mm; + } __attribute__((preserve_access_index)); + + +.. 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 + + SEC("lsm/file_mprotect") + int BPF_PROG(mprotect_audit, struct vm_area_struct *vma, + unsigned long reqprot, unsigned long prot) + { + int is_heap; + + 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 ``__attribute__((preserve_access_index))`` is a clang feature 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 allows attachment of eBPF programs as LSM hooks 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 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 5d553c2e7452..dd4c4ee151b0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3212,6 +3212,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