* Re: Looks like issue in handling active_nodes count in 4.19 kernel .
From: Paul Moore @ 2019-12-19 18:11 UTC (permalink / raw)
To: Ravi Kumar Siddojigari; +Cc: Stephen Smalley, selinux, linux-security-module
In-Reply-To: <002701d5b651$8434b2b0$8c9e1810$@codeaurora.org>
On Thu, Dec 19, 2019 at 4:48 AM Ravi Kumar Siddojigari
<rsiddoji@codeaurora.org> wrote:
>
> Sorry , Re-adding the patch below as requested.
>
> Stephen ,
> Issue is fixed with this 2 changes , Issue as even reproduced on v4.14 and similar changes work there also .
>
> --
> From 77c618006397c7a65ead257f3cb4e4fe3da2d4b8 Mon Sep 17 00:00:00 2001
> From: Jaihind Yadav <jaihindyadav@codeaurora.org>
> Date: Tue, 17 Dec 2019 17:25:47 +0530
> Subject: [PATCH] selinux: ensure we cleanup the internal AVC counters on error
> in avc_update()
>
> In AVC update we don't call avc_node_kill() when avc_xperms_populate()
> fails, resulting in the avc->avc_cache.active_nodes counter having a
> false value. In last patch this changes was missed , so correcting it.
>
> Change-Id: Ic0298162cc766c0f21be7ab232e259766654dad3
> Signed-off-by: Ravi Kumar Siddojigari <rsiddoji@codeaurora.org>
> ---
> security/selinux/avc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Two things:
* As Stephen already pointed out, please don't include "Change-Id"
metadata in your commit, that means nothing to the upstream kernel.
* If the patch is really from Jaihind Yadav then they should include
their sign-off, and preferably you would include your sign-off as well
since you are the one posting the patch. Please look at the
"Developer's Certificate of Origin" section in
Documentation/process/submitting-patches.rst.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Re: [PATCH v12 23/25] NET: Add SO_PEERCONTEXT for multiple LSMs
From: John Johansen @ 2019-12-19 19:21 UTC (permalink / raw)
To: Simon McVittie, Stephen Smalley
Cc: Casey Schaufler, casey.schaufler, jmorris, linux-security-module,
selinux, keescook, penguin-kernel, paul
In-Reply-To: <20191219164831.GA1308552@horizon>
On 12/19/19 8:48 AM, Simon McVittie wrote:
> On Thu, 19 Dec 2019 at 10:00:31 -0500, Stephen Smalley wrote:
>> Looks like userspace is generally forgiving of whether the terminating NUL
>> byte is included or omitted by the kernel (with different behaviors for
>> SELinux - always included, Smack - omitted by /proc/pid/attr/current but
>> included in SO_PEERSEC, and AppArmor - omitted for /proc/pid/attr/current
>> but includes a terminating \n, omitted for SO_PEERSEC but no terminating
>> \n), and procps-ng explicitly tests for printable characters (but truncates
>> on the first unprintable character).
>
> Because LSM people have told me in the past that the '\0' is not
> conceptually part of the label, the D-Bus specification and reference
> implementation already assume that its presence or absence is irrelevant,
> and normalize to a canonical form (which happens to be that it appends a
> '\0' if missing, to be nice to C-like languages, but I could equally
> have chosen to strip the '\0' and rely on an out-of-band length count).
>
> By design, SO_PEERCONTEXT and /proc/pid/attr/context don't (can't!)
> preserve whether the label originally ended with '\0' or not (because
> they are designed to use '\0' as a terminator for each label), so these
> new kernel interfaces are already a bit closer than the old kernel
> interfaces to how D-Bus represents this information.
>
> The problematic case is AppArmor's terminating '\n' on
> /proc/pid/attr/current, because when I asked in the past, I was told
> that it would be (unwise but) valid to have a LSM where "foo" and "foo\n"
> are distinct labels.
>
that is true if any value except \0 is allowed, which is/was the case. I am
not opposed to the LSM defining it otherwise.
I would also love to ditch the trailing \n from /proc/pid/attr/current,
we tried that before and ran into problems with something in userspace.
I can look into it again.
> If that hypothetical LSM would make procps-ng lose information (because
> procps-ng truncates at the first unprintable character), does that change
> the situation any? Would that make it acceptable for other LSM-agnostic
> user-space components, like the reference implementation of D-Bus, to
> assume that stripping a trailing newline from /proc/pid/attr/context
> or from one of the component strings of /proc/pid/attr/current is a
> non-lossy operation?
>
>>>> If this new API is an opportunity to declare that LSMs are expected
>>>> to put the same canonical form of a label in
>>>> /proc/$pid/attr/context and
>>>> SO_PEERCONTEXT, possibly with a non-canonical version (adding '\n' or
>>>> '\0' or similar) exposed in the older /proc/$pid/attr/current and
>>>> SO_PEERSEC interfaces for backwards compatibility, then that
>>>> would make
>>>> life a lot easier for user-space developers like me.
>>>
>>> I'm all for this but the current implementation reuses the same
>>> underlying hooks as SO_PEERSEC, so it gets the same result for the
>>> per-lsm values. We'd need a separate hook if we cannot alter the
>>> current AppArmor SO_PEERSEC format.
>
> If AppArmor was going to change the format of one of its interfaces
> (or deviate from it when implementing new interfaces), I'd actually
> prefer it to be /proc/pid/attr/current that changed or was superseded,
> because /proc/pid/attr/current is the one that contains a newline that
> consumers are meant to ignore.
>
Right, I am not opposed to a new interface. Ditching the trailing \n
would be even better if we can get rid of it
> For what it's worth, libapparmor explicitly removes the newline, so this
> only matters to LSM-agnostic readers like D-Bus implementations, and to
> lower-level AppArmor-aware readers that use the kernel interfaces directly
> in preference to using libapparmor.
>
yeah
> smcv
>
^ permalink raw reply
* [RFC PATCH] selinux: deprecate disabling SELinux and runtime
From: Paul Moore @ 2019-12-19 19:22 UTC (permalink / raw)
To: selinux; +Cc: linux-security-module
Deprecate the CONFIG_SECURITY_SELINUX_DISABLE functionality. The
code was originally developed to make it easier for Linux
distributions to support architectures where adding parameters to the
kernel command line was difficult. Unfortunately, supporting runtime
disable meant we had to make some security trade-offs when it came to
the LSM hooks, as documented in the Kconfig help text:
NOTE: selecting this option will disable the '__ro_after_init'
kernel hardening feature for security hooks. Please consider
using the selinux=0 boot parameter instead of enabling this
option.
Fortunately it looks as if that the original motivation for the
runtime disable functionality is gone, and Fedora/RHEL appears to be
the only major distribution enabling this capability at build time
so we are now taking steps to remove it entirely from the kernel.
The first step is to mark the functionality as deprecated and print
an error when it is used (what this patch is doing). As Fedora/RHEL
makes progress in transitioning the distribution away from runtime
disable, we will introduce follow-up patches over several kernel
releases which will block for increasing periods of time when the
runtime disable is used. Finally we will remove the option entirely
once we believe all users have moved to the kernel cmdline approach.
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/selinux/Kconfig | 3 +++
security/selinux/selinuxfs.c | 6 ++++++
2 files changed, 9 insertions(+)
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 996d35d950f7..580ac24c7aa1 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -42,6 +42,9 @@ config SECURITY_SELINUX_DISABLE
using the selinux=0 boot parameter instead of enabling this
option.
+ WARNING: this option is deprecated and will be removed in a future
+ kernel release.
+
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DEVELOP
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 278417e67b4c..adbe2dd35202 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -281,6 +281,12 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
int new_value;
int enforcing;
+ /* NOTE: we are now officially considering runtime disable as
+ * deprecated, and using it will become increasingly painful
+ * (e.g. sleeping/blocking) as we progress through future
+ * kernel releases until eventually it is removed */
+ pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n");
+
if (count >= PAGE_SIZE)
return -ENOMEM;
^ permalink raw reply related
* Re: [PATCH v12 23/25] NET: Add SO_PEERCONTEXT for multiple LSMs
From: John Johansen @ 2019-12-19 19:27 UTC (permalink / raw)
To: Stephen Smalley, Simon McVittie
Cc: Casey Schaufler, casey.schaufler, jmorris, linux-security-module,
selinux, keescook, penguin-kernel, paul
In-Reply-To: <16af7932-a57b-1454-18ca-c2ff6e6b302d@tycho.nsa.gov>
On 12/19/19 9:02 AM, Stephen Smalley wrote:
> On 12/19/19 11:48 AM, Simon McVittie wrote:
>> On Thu, 19 Dec 2019 at 10:00:31 -0500, Stephen Smalley wrote:
>>> Looks like userspace is generally forgiving of whether the terminating NUL
>>> byte is included or omitted by the kernel (with different behaviors for
>>> SELinux - always included, Smack - omitted by /proc/pid/attr/current but
>>> included in SO_PEERSEC, and AppArmor - omitted for /proc/pid/attr/current
>>> but includes a terminating \n, omitted for SO_PEERSEC but no terminating
>>> \n), and procps-ng explicitly tests for printable characters (but truncates
>>> on the first unprintable character).
>>
>> Because LSM people have told me in the past that the '\0' is not
>> conceptually part of the label, the D-Bus specification and reference
>> implementation already assume that its presence or absence is irrelevant,
>> and normalize to a canonical form (which happens to be that it appends a
>> '\0' if missing, to be nice to C-like languages, but I could equally
>> have chosen to strip the '\0' and rely on an out-of-band length count).
>>
>> By design, SO_PEERCONTEXT and /proc/pid/attr/context don't (can't!)
>> preserve whether the label originally ended with '\0' or not (because
>> they are designed to use '\0' as a terminator for each label), so these
>> new kernel interfaces are already a bit closer than the old kernel
>> interfaces to how D-Bus represents this information.
>>
>> The problematic case is AppArmor's terminating '\n' on
>> /proc/pid/attr/current, because when I asked in the past, I was told
>> that it would be (unwise but) valid to have a LSM where "foo" and "foo\n"
>> are distinct labels.
>
> I don't agree with that stance, but obviously others may differ.
>
Its not so much a stance as a reality. The LSM allowed anything except
\0 values as part of the interface and there was no documentation
to set expectations beyond what the code allowed.
This could be tightened.
>> If that hypothetical LSM would make procps-ng lose information (because
>> procps-ng truncates at the first unprintable character), does that change
>> the situation any? Would that make it acceptable for other LSM-agnostic
>> user-space components, like the reference implementation of D-Bus, to
>> assume that stripping a trailing newline from /proc/pid/attr/context
>> or from one of the component strings of /proc/pid/attr/current is a
>> non-lossy operation?
>
> IMHO, yes. In fact, looking further, I see that systemd's src/libsystemd/sd-bus/bus-creds.c:bus_creds_add_more() reads /proc/pid/attr/current with its read_one_line_file() helper which ultimately uses read_line_full() and treats EOF, \n, \r, or \0 as terminators and truncates on first such occurrence.
>
fun
>>
>>>>> If this new API is an opportunity to declare that LSMs are expected
>>>>> to put the same canonical form of a label in
>>>>> /proc/$pid/attr/context and
>>>>> SO_PEERCONTEXT, possibly with a non-canonical version (adding '\n' or
>>>>> '\0' or similar) exposed in the older /proc/$pid/attr/current and
>>>>> SO_PEERSEC interfaces for backwards compatibility, then that
>>>>> would make
>>>>> life a lot easier for user-space developers like me.
>>>>
>>>> I'm all for this but the current implementation reuses the same
>>>> underlying hooks as SO_PEERSEC, so it gets the same result for the
>>>> per-lsm values. We'd need a separate hook if we cannot alter the
>>>> current AppArmor SO_PEERSEC format.
>>
>> If AppArmor was going to change the format of one of its interfaces
>> (or deviate from it when implementing new interfaces), I'd actually
>> prefer it to be /proc/pid/attr/current that changed or was superseded,
>> because /proc/pid/attr/current is the one that contains a newline that
>> consumers are meant to ignore.
>>
>> For what it's worth, libapparmor explicitly removes the newline, so this
>> only matters to LSM-agnostic readers like D-Bus implementations, and to
>> lower-level AppArmor-aware readers that use the kernel interfaces directly
>> in preference to using libapparmor.
>
> Deferring to the AA maintainer(s) to speak to this.
I will look into what I can do. If we can ditch the trailing \n, that would
be best. I tried to do that once before and we ran into some problems and
I had to revert the change. But that was a long time ago and we can probably
get away with doing it now.
^ permalink raw reply
* Re: [PATCH v12 23/25] NET: Add SO_PEERCONTEXT for multiple LSMs
From: Casey Schaufler @ 2019-12-19 20:51 UTC (permalink / raw)
To: John Johansen, Stephen Smalley, Simon McVittie
Cc: casey.schaufler, jmorris, linux-security-module, selinux,
keescook, penguin-kernel, paul, Casey Schaufler
In-Reply-To: <a828a629-cdb8-57c3-8c6e-9b080842ec05@canonical.com>
On 12/19/2019 11:27 AM, John Johansen wrote:
> On 12/19/19 9:02 AM, Stephen Smalley wrote:
>> On 12/19/19 11:48 AM, Simon McVittie wrote:
>>> On Thu, 19 Dec 2019 at 10:00:31 -0500, Stephen Smalley wrote:
>>>> Looks like userspace is generally forgiving of whether the terminating NUL
>>>> byte is included or omitted by the kernel (with different behaviors for
>>>> SELinux - always included, Smack - omitted by /proc/pid/attr/current but
>>>> included in SO_PEERSEC, and AppArmor - omitted for /proc/pid/attr/current
>>>> but includes a terminating \n, omitted for SO_PEERSEC but no terminating
>>>> \n), and procps-ng explicitly tests for printable characters (but truncates
>>>> on the first unprintable character).
>>> Because LSM people have told me in the past that the '\0' is not
>>> conceptually part of the label, the D-Bus specification and reference
>>> implementation already assume that its presence or absence is irrelevant,
>>> and normalize to a canonical form (which happens to be that it appends a
>>> '\0' if missing, to be nice to C-like languages, but I could equally
>>> have chosen to strip the '\0' and rely on an out-of-band length count).
>>>
>>> By design, SO_PEERCONTEXT and /proc/pid/attr/context don't (can't!)
>>> preserve whether the label originally ended with '\0' or not (because
>>> they are designed to use '\0' as a terminator for each label), so these
>>> new kernel interfaces are already a bit closer than the old kernel
>>> interfaces to how D-Bus represents this information.
>>>
>>> The problematic case is AppArmor's terminating '\n' on
>>> /proc/pid/attr/current, because when I asked in the past, I was told
>>> that it would be (unwise but) valid to have a LSM where "foo" and "foo\n"
>>> are distinct labels.
>> I don't agree with that stance, but obviously others may differ.
>>
> Its not so much a stance as a reality. The LSM allowed anything except
> \0 values as part of the interface and there was no documentation
> to set expectations beyond what the code allowed.
>
> This could be tightened.
>
>>> If that hypothetical LSM would make procps-ng lose information (because
>>> procps-ng truncates at the first unprintable character), does that change
>>> the situation any? Would that make it acceptable for other LSM-agnostic
>>> user-space components, like the reference implementation of D-Bus, to
>>> assume that stripping a trailing newline from /proc/pid/attr/context
>>> or from one of the component strings of /proc/pid/attr/current is a
>>> non-lossy operation?
>> IMHO, yes. In fact, looking further, I see that systemd's src/libsystemd/sd-bus/bus-creds.c:bus_creds_add_more() reads /proc/pid/attr/current with its read_one_line_file() helper which ultimately uses read_line_full() and treats EOF, \n, \r, or \0 as terminators and truncates on first such occurrence.
>>
> fun
>
>>>>>> If this new API is an opportunity to declare that LSMs are expected
>>>>>> to put the same canonical form of a label in
>>>>>> /proc/$pid/attr/context and
>>>>>> SO_PEERCONTEXT, possibly with a non-canonical version (adding '\n' or
>>>>>> '\0' or similar) exposed in the older /proc/$pid/attr/current and
>>>>>> SO_PEERSEC interfaces for backwards compatibility, then that
>>>>>> would make
>>>>>> life a lot easier for user-space developers like me.
>>>>> I'm all for this but the current implementation reuses the same
>>>>> underlying hooks as SO_PEERSEC, so it gets the same result for the
>>>>> per-lsm values. We'd need a separate hook if we cannot alter the
>>>>> current AppArmor SO_PEERSEC format.
>>> If AppArmor was going to change the format of one of its interfaces
>>> (or deviate from it when implementing new interfaces), I'd actually
>>> prefer it to be /proc/pid/attr/current that changed or was superseded,
>>> because /proc/pid/attr/current is the one that contains a newline that
>>> consumers are meant to ignore.
>>>
>>> For what it's worth, libapparmor explicitly removes the newline, so this
>>> only matters to LSM-agnostic readers like D-Bus implementations, and to
>>> lower-level AppArmor-aware readers that use the kernel interfaces directly
>>> in preference to using libapparmor.
>> Deferring to the AA maintainer(s) to speak to this.
> I will look into what I can do. If we can ditch the trailing \n, that would
> be best. I tried to do that once before and we ran into some problems and
> I had to revert the change. But that was a long time ago and we can probably
> get away with doing it now.
I would be happy to define and document that the compound context does
not include trailing \n. There are no existing security modules or
user space that would be impacted. No one uses /proc/self/attr/context
or SO_PEERCONTEXT yet. If AppArmor is happy with stripping the \n I
think we're good to go.
^ permalink raw reply
* Re: [PATCH v12 02/25] LSM: Create and manage the lsmblob data structure.
From: Mimi Zohar @ 2019-12-19 21:11 UTC (permalink / raw)
To: Casey Schaufler, casey.schaufler, jmorris, linux-security-module,
selinux
Cc: keescook, john.johansen, penguin-kernel, paul, sds
In-Reply-To: <20191216223621.5127-3-casey@schaufler-ca.com>
On Mon, 2019-12-16 at 14:35 -0800, Casey Schaufler wrote:
> When more than one security module is exporting data to
> audit and networking sub-systems a single 32 bit integer
> is no longer sufficient to represent the data. Add a
> structure to be used instead.
>
> The lsmblob structure is currently an array of
> u32 "secids". There is an entry for each of the
> security modules built into the system that would
> use secids if active. The system assigns the module
> a "slot" when it registers hooks. If modules are
> compiled in but not registered there will be unused
> slots.
>
> A new lsm_id structure, which contains the name
> of the LSM and its slot number, is created. There
> is an instance for each LSM, which assigns the name
> and passes it to the infrastructure to set the slot.
>
> Reviewed-by: John Johansen <john.johansen@canonical.com>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> include/linux/lsm_hooks.h | 12 ++++++--
> include/linux/security.h | 58 ++++++++++++++++++++++++++++++++++++++
> security/apparmor/lsm.c | 7 ++++-
> security/commoncap.c | 7 ++++-
> security/loadpin/loadpin.c | 8 +++++-
> security/safesetid/lsm.c | 8 +++++-
> security/security.c | 28 ++++++++++++++----
> security/selinux/hooks.c | 8 +++++-
> security/smack/smack_lsm.c | 7 ++++-
> security/tomoyo/tomoyo.c | 8 +++++-
> security/yama/yama_lsm.c | 7 ++++-
> 11 files changed, 142 insertions(+), 16 deletions(-)
security/lockdown/lockdown.c is missing. I'm getting a compiler
error.
Mimi
^ permalink raw reply
* Re: [PATCH v12 23/25] NET: Add SO_PEERCONTEXT for multiple LSMs
From: John Johansen @ 2019-12-19 21:41 UTC (permalink / raw)
To: Casey Schaufler, Stephen Smalley, Simon McVittie
Cc: casey.schaufler, jmorris, linux-security-module, selinux,
keescook, penguin-kernel, paul
In-Reply-To: <abea0322-cf44-c37f-35c3-955adb8a455d@schaufler-ca.com>
On 12/19/19 12:51 PM, Casey Schaufler wrote:
> On 12/19/2019 11:27 AM, John Johansen wrote:
>> On 12/19/19 9:02 AM, Stephen Smalley wrote:
>>> On 12/19/19 11:48 AM, Simon McVittie wrote:
>>>> On Thu, 19 Dec 2019 at 10:00:31 -0500, Stephen Smalley wrote:
>>>>> Looks like userspace is generally forgiving of whether the terminating NUL
>>>>> byte is included or omitted by the kernel (with different behaviors for
>>>>> SELinux - always included, Smack - omitted by /proc/pid/attr/current but
>>>>> included in SO_PEERSEC, and AppArmor - omitted for /proc/pid/attr/current
>>>>> but includes a terminating \n, omitted for SO_PEERSEC but no terminating
>>>>> \n), and procps-ng explicitly tests for printable characters (but truncates
>>>>> on the first unprintable character).
>>>> Because LSM people have told me in the past that the '\0' is not
>>>> conceptually part of the label, the D-Bus specification and reference
>>>> implementation already assume that its presence or absence is irrelevant,
>>>> and normalize to a canonical form (which happens to be that it appends a
>>>> '\0' if missing, to be nice to C-like languages, but I could equally
>>>> have chosen to strip the '\0' and rely on an out-of-band length count).
>>>>
>>>> By design, SO_PEERCONTEXT and /proc/pid/attr/context don't (can't!)
>>>> preserve whether the label originally ended with '\0' or not (because
>>>> they are designed to use '\0' as a terminator for each label), so these
>>>> new kernel interfaces are already a bit closer than the old kernel
>>>> interfaces to how D-Bus represents this information.
>>>>
>>>> The problematic case is AppArmor's terminating '\n' on
>>>> /proc/pid/attr/current, because when I asked in the past, I was told
>>>> that it would be (unwise but) valid to have a LSM where "foo" and "foo\n"
>>>> are distinct labels.
>>> I don't agree with that stance, but obviously others may differ.
>>>
>> Its not so much a stance as a reality. The LSM allowed anything except
>> \0 values as part of the interface and there was no documentation
>> to set expectations beyond what the code allowed.
>>
>> This could be tightened.
>>
>>>> If that hypothetical LSM would make procps-ng lose information (because
>>>> procps-ng truncates at the first unprintable character), does that change
>>>> the situation any? Would that make it acceptable for other LSM-agnostic
>>>> user-space components, like the reference implementation of D-Bus, to
>>>> assume that stripping a trailing newline from /proc/pid/attr/context
>>>> or from one of the component strings of /proc/pid/attr/current is a
>>>> non-lossy operation?
>>> IMHO, yes. In fact, looking further, I see that systemd's src/libsystemd/sd-bus/bus-creds.c:bus_creds_add_more() reads /proc/pid/attr/current with its read_one_line_file() helper which ultimately uses read_line_full() and treats EOF, \n, \r, or \0 as terminators and truncates on first such occurrence.
>>>
>> fun
>>
>>>>>>> If this new API is an opportunity to declare that LSMs are expected
>>>>>>> to put the same canonical form of a label in
>>>>>>> /proc/$pid/attr/context and
>>>>>>> SO_PEERCONTEXT, possibly with a non-canonical version (adding '\n' or
>>>>>>> '\0' or similar) exposed in the older /proc/$pid/attr/current and
>>>>>>> SO_PEERSEC interfaces for backwards compatibility, then that
>>>>>>> would make
>>>>>>> life a lot easier for user-space developers like me.
>>>>>> I'm all for this but the current implementation reuses the same
>>>>>> underlying hooks as SO_PEERSEC, so it gets the same result for the
>>>>>> per-lsm values. We'd need a separate hook if we cannot alter the
>>>>>> current AppArmor SO_PEERSEC format.
>>>> If AppArmor was going to change the format of one of its interfaces
>>>> (or deviate from it when implementing new interfaces), I'd actually
>>>> prefer it to be /proc/pid/attr/current that changed or was superseded,
>>>> because /proc/pid/attr/current is the one that contains a newline that
>>>> consumers are meant to ignore.
>>>>
>>>> For what it's worth, libapparmor explicitly removes the newline, so this
>>>> only matters to LSM-agnostic readers like D-Bus implementations, and to
>>>> lower-level AppArmor-aware readers that use the kernel interfaces directly
>>>> in preference to using libapparmor.
>>> Deferring to the AA maintainer(s) to speak to this.
>> I will look into what I can do. If we can ditch the trailing \n, that would
>> be best. I tried to do that once before and we ran into some problems and
>> I had to revert the change. But that was a long time ago and we can probably
>> get away with doing it now.
>
> I would be happy to define and document that the compound context does
> not include trailing \n. There are no existing security modules or
> user space that would be impacted. No one uses /proc/self/attr/context
> or SO_PEERCONTEXT yet. If AppArmor is happy with stripping the \n I
> think we're good to go.
>
yes, we can certainly remove it from peer context, and I expect we can
remove it from current as well
^ permalink raw reply
* Re: [PATCH v12 02/25] LSM: Create and manage the lsmblob data structure.
From: Casey Schaufler @ 2019-12-19 21:44 UTC (permalink / raw)
To: Mimi Zohar, casey.schaufler, jmorris, linux-security-module,
selinux
Cc: keescook, john.johansen, penguin-kernel, paul, sds,
Casey Schaufler
In-Reply-To: <1576789891.5660.3.camel@linux.ibm.com>
On 12/19/2019 1:11 PM, Mimi Zohar wrote:
> On Mon, 2019-12-16 at 14:35 -0800, Casey Schaufler wrote:
>> When more than one security module is exporting data to
>> audit and networking sub-systems a single 32 bit integer
>> is no longer sufficient to represent the data. Add a
>> structure to be used instead.
>>
>> The lsmblob structure is currently an array of
>> u32 "secids". There is an entry for each of the
>> security modules built into the system that would
>> use secids if active. The system assigns the module
>> a "slot" when it registers hooks. If modules are
>> compiled in but not registered there will be unused
>> slots.
>>
>> A new lsm_id structure, which contains the name
>> of the LSM and its slot number, is created. There
>> is an instance for each LSM, which assigns the name
>> and passes it to the infrastructure to set the slot.
>>
>> Reviewed-by: John Johansen <john.johansen@canonical.com>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> ---
>> include/linux/lsm_hooks.h | 12 ++++++--
>> include/linux/security.h | 58 ++++++++++++++++++++++++++++++++++++++
>> security/apparmor/lsm.c | 7 ++++-
>> security/commoncap.c | 7 ++++-
>> security/loadpin/loadpin.c | 8 +++++-
>> security/safesetid/lsm.c | 8 +++++-
>> security/security.c | 28 ++++++++++++++----
>> security/selinux/hooks.c | 8 +++++-
>> security/smack/smack_lsm.c | 7 ++++-
>> security/tomoyo/tomoyo.c | 8 +++++-
>> security/yama/yama_lsm.c | 7 ++++-
>> 11 files changed, 142 insertions(+), 16 deletions(-)
> security/lockdown/lockdown.c is missing. I'm getting a compiler
> error.
Whoops. I'll add the new kid to the list.
>
> Mimi
>
^ permalink raw reply
* Re: [RFC PATCH] selinux: deprecate disabling SELinux and runtime
From: Casey Schaufler @ 2019-12-19 23:40 UTC (permalink / raw)
To: Paul Moore, selinux; +Cc: linux-security-module, Casey Schaufler
In-Reply-To: <157678334821.158235.2125894638773393579.stgit@chester>
On 12/19/2019 11:22 AM, Paul Moore wrote:
> Deprecate the CONFIG_SECURITY_SELINUX_DISABLE functionality. The
> code was originally developed to make it easier for Linux
> distributions to support architectures where adding parameters to the
> kernel command line was difficult. Unfortunately, supporting runtime
> disable meant we had to make some security trade-offs when it came to
> the LSM hooks, as documented in the Kconfig help text:
>
> NOTE: selecting this option will disable the '__ro_after_init'
> kernel hardening feature for security hooks. Please consider
> using the selinux=0 boot parameter instead of enabling this
> option.
>
> Fortunately it looks as if that the original motivation for the
> runtime disable functionality is gone, and Fedora/RHEL appears to be
> the only major distribution enabling this capability at build time
> so we are now taking steps to remove it entirely from the kernel.
> The first step is to mark the functionality as deprecated and print
> an error when it is used (what this patch is doing). As Fedora/RHEL
> makes progress in transitioning the distribution away from runtime
> disable, we will introduce follow-up patches over several kernel
> releases which will block for increasing periods of time when the
> runtime disable is used. Finally we will remove the option entirely
> once we believe all users have moved to the kernel cmdline approach.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
> ---
> security/selinux/Kconfig | 3 +++
> security/selinux/selinuxfs.c | 6 ++++++
> 2 files changed, 9 insertions(+)
>
> diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
> index 996d35d950f7..580ac24c7aa1 100644
> --- a/security/selinux/Kconfig
> +++ b/security/selinux/Kconfig
> @@ -42,6 +42,9 @@ config SECURITY_SELINUX_DISABLE
> using the selinux=0 boot parameter instead of enabling this
> option.
>
> + WARNING: this option is deprecated and will be removed in a future
> + kernel release.
> +
> If you are unsure how to answer this question, answer N.
>
> config SECURITY_SELINUX_DEVELOP
> diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
> index 278417e67b4c..adbe2dd35202 100644
> --- a/security/selinux/selinuxfs.c
> +++ b/security/selinux/selinuxfs.c
> @@ -281,6 +281,12 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
> int new_value;
> int enforcing;
>
> + /* NOTE: we are now officially considering runtime disable as
> + * deprecated, and using it will become increasingly painful
> + * (e.g. sleeping/blocking) as we progress through future
> + * kernel releases until eventually it is removed */
> + pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n");
> +
> if (count >= PAGE_SIZE)
> return -ENOMEM;
>
>
>
^ permalink raw reply
* Re: Looks like issue in handling active_nodes count in 4.19 kernel
From: Ravi Kumar Siddojigari @ 2019-12-20 12:03 UTC (permalink / raw)
To: selinux, linux-security-module, sds; +Cc: rsiddoji, Jaihind Yadav
In-Reply-To: <CAHC9VhSv9BsjqNtwdpAv1yj630L-k8UBcWA5bwC9ySevrPw34w@mail.gmail.com>
Thanks for correcting , Adding the signoff of orginal author in the
following commit .
From 6308b405e2097ab9d82c5a3894815daf7331e0b6 Mon Sep 17 00:00:00 2001
From: Jaihind Yadav <jaihindyadav@codeaurora.org>
Date: Tue, 17 Dec 2019 17:25:47 +0530
Subject: [PATCH] selinux: ensure we cleanup the internal AVC counters on error
in avc_update()
To: rsiddoji@codeaurora.org
In AVC update we don't call avc_node_kill() when avc_xperms_populate()
fails, resulting in the avc->avc_cache.active_nodes counter having a
false value.In last patch this changes was missed , so correcting it.
Signed-off-by: Jaihind Yadav <jaihindyadav@codeaurora.org>
Signed-off-by: Ravi Kumar Siddojigari <rsiddoji@codeaurora.org>
---
security/selinux/avc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index ecd3829996aa..9c69e83834b0 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -907,7 +907,7 @@ static int avc_update_node(struct selinux_avc *avc,
if (orig->ae.xp_node) {
rc = avc_xperms_populate(node, orig->ae.xp_node);
if (rc) {
- kmem_cache_free(avc_node_cachep, node);
+ avc_node_kill(avc, node);
goto out_unlock;
}
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* Re: [PATCH v1 - RFC] ima: export the measurement list when needed
From: Mimi Zohar @ 2019-12-20 14:04 UTC (permalink / raw)
To: Janne Karhunen, linux-integrity, linux-security-module
Cc: kgold, david.safford, monty.wiseman
In-Reply-To: <20191220074929.8191-1-janne.karhunen@gmail.com>
[Cc'ing LSM mailing list for a wider audience]
On Fri, 2019-12-20 at 09:49 +0200, Janne Karhunen wrote:
> Some systems can end up carrying lots of entries in the ima
> measurement list. Since every entry is using a bit of kernel
> memory, add a new Kconfig variable to allow the sysadmin to
> define the maximum measurement list size and the location
> of the exported list.
>
> The list is written out in append mode, so the system will
> keep writing new entries as long as it stays running or runs
> out of space. File is also automatically truncated on startup.
>
> Signed-off-by: Janne Karhunen <janne.karhunen@gmail.com>
Continually adding new measurements, without limiting or removing the
measurement list seems to becoming more of an issue.
From Dave Safford's TLV patch description[1]:
A second goal of the [TLV] patch set is to test the more radical
idea of being able to copy the measurement list data out of the
kernel. The data is verifiable with the TPM PCR value, and need not
be kept in kernel memory. In some cases, this "memory leak" can
grow large enough to cause issues, and this is a test of a
potential way to solve that problem.
The TLV version automatically removed the measurement list the first
time the measurement list was read, which sounded very odd to me. In
an offline discussion, Dave further clarified that reading the
measurement list should be similar to how a trusted userspace
application reads kernel messages. The difference being kernel
messages are stored in a circular buffer and may be dropped. In the
IMA measurement list case, the measurement list would grow until the
trusted userspace application gets around to reading the measurement
list.
Should the kernel be involved in writing the IMA measurement list to a
file or, as Dave suggested, this should be delegated to a userspace
application?
Mimi
[1] https://lore.kernel.org/linux-integrity/BCA04D5D9A3B764C9B7405BBA4
D4A3C002569222@ALPMBAPA12.e2k.ad.ge.com/
^ permalink raw reply
* [PATCH AUTOSEL 4.19 11/34] afs: Fix SELinux setting security label on /afs
From: Sasha Levin @ 2019-12-20 14:34 UTC (permalink / raw)
To: linux-kernel, stable
Cc: David Howells, Marc Dionne, selinux, linux-security-module,
Sasha Levin, linux-afs
In-Reply-To: <20191220143433.9922-1-sashal@kernel.org>
From: David Howells <dhowells@redhat.com>
[ Upstream commit bcbccaf2edcf1b76f73f890e968babef446151a4 ]
Make the AFS dynamic root superblock R/W so that SELinux can set the
security label on it. Without this, upgrades to, say, the Fedora
filesystem-afs RPM fail if afs is mounted on it because the SELinux label
can't be (re-)applied.
It might be better to make it possible to bypass the R/O check for LSM
label application through setxattr.
Fixes: 4d673da14533 ("afs: Support the AFS dynamic root")
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Marc Dionne <marc.dionne@auristor.com>
cc: selinux@vger.kernel.org
cc: linux-security-module@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/afs/super.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 4d3e274207fb7..bd26082974732 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -404,7 +404,6 @@ static int afs_fill_super(struct super_block *sb,
/* allocate the root inode and dentry */
if (as->dyn_root) {
inode = afs_iget_pseudo_dir(sb, true);
- sb->s_flags |= SB_RDONLY;
} else {
sprintf(sb->s_id, "%u", as->volume->vid);
afs_activate_volume(as->volume);
--
2.20.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.4 20/52] afs: Fix SELinux setting security label on /afs
From: Sasha Levin @ 2019-12-20 14:29 UTC (permalink / raw)
To: linux-kernel, stable
Cc: David Howells, Marc Dionne, selinux, linux-security-module,
Sasha Levin, linux-afs
In-Reply-To: <20191220142954.9500-1-sashal@kernel.org>
From: David Howells <dhowells@redhat.com>
[ Upstream commit bcbccaf2edcf1b76f73f890e968babef446151a4 ]
Make the AFS dynamic root superblock R/W so that SELinux can set the
security label on it. Without this, upgrades to, say, the Fedora
filesystem-afs RPM fail if afs is mounted on it because the SELinux label
can't be (re-)applied.
It might be better to make it possible to bypass the R/O check for LSM
label application through setxattr.
Fixes: 4d673da14533 ("afs: Support the AFS dynamic root")
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Marc Dionne <marc.dionne@auristor.com>
cc: selinux@vger.kernel.org
cc: linux-security-module@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/afs/super.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 488641b1a418d..d9a6036b70b9f 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -448,7 +448,6 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
/* allocate the root inode and dentry */
if (as->dyn_root) {
inode = afs_iget_pseudo_dir(sb, true);
- sb->s_flags |= SB_RDONLY;
} else {
sprintf(sb->s_id, "%llu", as->volume->vid);
afs_activate_volume(as->volume);
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 00/13] MAC and Audit policy using eBPF (KRSI)
From: KP Singh @ 2019-12-20 15:41 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
From: KP Singh <kpsingh@google.com>
This patch series is a continuation of the KRSI RFC
(https://lore.kernel.org/bpf/20190910115527.5235-1-kpsingh@chromium.org/)
# Motivation
Google does rich analysis of runtime security data collected from
internal Linux deployments (corporate devices and servers) to detect and
thwart threats in real-time. Currently, this is done in custom kernel
modules but we would like to replace this with something that's upstream
and useful to others.
The current kernel infrastructure for providing telemetry (Audit, Perf
etc.) is disjoint from access enforcement (i.e. LSMs). Augmenting the
information provided by audit requires kernel changes to audit, its
policy language and user-space components. Furthermore, building a MAC
policy based on the newly added telemetry data requires changes to
various LSMs and their respective policy languages.
This patchset proposes a new stackable and privileged LSM which allows
the LSM hooks to be implemented using eBPF. This facilitates a unified
and dynamic (not requiring re-compilation of the kernel) audit and MAC
policy.
# Why an LSM?
Linux Security Modules target security behaviours rather than the
kernel's API. For example, it's easy to miss out a newly added system
call for executing processes (eg. execve, execveat etc.) but the LSM
framework ensures that all process executions trigger the relevant hooks
irrespective of how the process was executed.
Allowing users to implement LSM hooks at runtime also benefits the LSM
eco-system by enabling a quick feedback loop from the security community
about the kind of behaviours that the LSM Framework should be targeting.
# How does it work?
The LSM introduces a new eBPF (https://docs.cilium.io/en/v1.6/bpf/)
program type, BPF_PROG_TYPE_LSM, which can only be attached to a LSM
hook. All LSM hooks are exposed as files in securityfs. Attachment
requires CAP_SYS_ADMIN for loading eBPF programs and CAP_MAC_ADMIN for
modifying MAC policies.
The eBPF programs are passed the same arguments as the LSM hooks and
executed in the body of the hook. If any of the eBPF programs returns an
error (like ENOPERM), the behaviour represented by the hook is denied.
Audit logs can be written using a format chosen by the eBPF program to
the perf events buffer and can be further processed in user-space.
# Limitations of RFC v1
In the previous design
(https://lore.kernel.org/bpf/20190910115527.5235-1-kpsingh@chromium.org/),
the BPF programs received a context which could be queried to retrieve
specific pieces of information using specific helpers.
For example, a program that attaches to the file_mprotect LSM hook and
queries the VMA region could have had the following context:
// Special context for the hook.
struct bpf_mprotect_ctx {
struct vm_area_struct *vma;
};
and accessed the fields using a hypothetical helper
"bpf_mprotect_vma_get_start:
SEC("lsm/file_mprotect")
int mprotect_audit(bpf_mprotect_ctx *ctx)
{
unsigned long vm_start = bpf_mprotect_vma_get_start(ctx);
return 0;
}
or directly read them from the context by updating the verifier to allow
accessing the fields:
int mprotect_audit(bpf_mprotect_ctx *ctx)
{
unsigned long vm_start = ctx->vma->vm_start;
return 0;
}
As we prototyped policies based on this design, we realized that this
approach is not general enough. Adding helpers or verifier code for all
usages would imply a high maintenance cost while severely restricting
the instrumentation capabilities which is the key value add of our
eBPF-based LSM.
Feedback from the BPF maintainers at Linux Plumbers also pushed us
towards the following, more general, approach.
# BTF Based Design
The current design uses BTF
(https://facebookmicrosites.github.io/bpf/blog/2018/11/14/btf-enhancement.html,
https://lwn.net/Articles/803258/) which allows verifiable read-only
structure accesses by field names rather than fixed offsets. This allows
accessing the hook parameters using a dynamically created context which
provides a certain degree of ABI stability:
/* Clang builtin to handle field accesses. */
#define _(P) (__builtin_preserve_access_index(P))
// Only declare the structure and fields intended to be used
// in the program
struct vm_area_struct {
unsigned long vm_start;
};
// Declare the eBPF program mprotect_audit which attaches to
// to the file_mprotect LSM hook and accepts three arguments.
BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
struct vm_area_struct *, vma,
unsigned long, reqprot, unsigned long, prot
{
unsigned long vm_start = _(vma->vm_start);
return 0;
}
By relocating field offsets, BTF makes a large portion of kernel data
structures readily accessible across kernel versions without requiring a
large corpus of BPF helper functions and requiring recompilation with
every kernel version. The limitations of BTF compatibility are described
in BPF Co-Re (http://vger.kernel.org/bpfconf2019_talks/bpf-core.pdf,
i.e. field renames, #defines and changes to the signature of LSM hooks).
This design imposes that the MAC policy (eBPF programs) be updated when
the inspected kernel structures change outside of BTF compatibility
guarantees. In practice, this is only required when a structure field
used by a current policy is removed (or renamed) or when the used LSM
hooks change. We expect the maintenance cost of these changes to be
acceptable as compared to the previous design
(https://lore.kernel.org/bpf/20190910115527.5235-1-kpsingh@chromium.org/).
# Distinction from Landlock
We believe there exist two distinct use-cases with distinct set of users:
* Unprivileged processes voluntarily relinquishing privileges with the
primary users being software developers.
* Flexible privileged (CAP_MAC_ADMIN, CAP_SYS_ADMIN) MAC and Audit with
the primary users being system policy admins.
These use-cases imply different APIs and trade-offs:
* The unprivileged use case requires defining more stable and custom APIs
(through opaque contexts and precise helpers).
* Privileged Audit and MAC requires deeper introspection of the kernel
data structures to maximise the flexibility that can be achieved without
kernel modification.
Landlock has demonstrated filesystem sandboxes and now Ptrace access
control in its patches which are excellent use cases for an unprivileged
process voluntarily relinquishing privileges.
However, Landlock has expanded its original goal, "towards unprivileged
sandboxing", to being a "low-level framework to build
access-control/audit systems" (https://landlock.io). We feel that the
design and implementation are still driven by the constraints and
trade-offs of the former use-case, and do not provide a satisfactory
solution to the latter.
We also believe that our approach, direct access to common kernel data
structures as with BTF, is inappropriate for unprivileged processes and
probably not a good option for Landlock.
In conclusion, we feel that the design for a privileged LSM and
unprivileged LSM are mutually exclusive and that one cannot be built
"on-top-of" the other. Doing so would limit the capabilities of what can
be done for an LSM that provides flexible audit and MAC capabilities or
provide in-appropriate access to kernel internals to an unprivileged
process.
Furthermore, the Landlock design supports its historical use-case only
when unprivileged eBPF is allowed. This is something that warrants
discussion before an unprivileged LSM that uses eBPF is upstreamed.
# Why not tracepoints or kprobes?
In order to do MAC with tracepoints or kprobes, we would need to
override the return value of the security hook. This is not possible
with tracepoints or call-site kprobes.
Attaching to the return boundary (kretprobe) implies that BPF programs
would always get called after all the other LSM hooks are called and
clobber the pre-existing LSM semantics.
Enforcing MAC policy with an actual LSM helps leverage the verified
semantics of the framework.
# Usage Examples
A simple example and some documentation is included in the patchset.
In order to better illustrate the capabilities of the framework some
more advanced prototype code has also been published separately:
* Logging execution events (including environment variables and arguments):
https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
* Detecting deletion of running executables:
https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_detect_exec_unlink.c
* Detection of writes to /proc/<pid>/mem:
https://github.com/sinkap/linux-krsi/blob/patch/v1/examples/samples/bpf/lsm_audit_env.c
We have updated Google's internal telemetry infrastructure and have
started deploying this LSM on our Linux Workstations. This gives us more
confidence in the real-world applications of such a system.
KP Singh (13):
bpf: Refactor BPF_EVENT context macros to its own header.
bpf: lsm: Add a skeleton and config options
bpf: lsm: Introduce types for eBPF based LSM
bpf: lsm: Allow btf_id based attachment for LSM hooks
tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
bpf: lsm: Init Hooks and create files in securityfs
bpf: lsm: Implement attach, detach and execution.
bpf: lsm: Show attached program names in hook read handler.
bpf: lsm: Add a helper function bpf_lsm_event_output
bpf: lsm: Handle attachment of the same program
tools/libbpf: Add bpf_program__attach_lsm
bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
bpf: lsm: Add Documentation
Documentation/security/bpf.rst | 164 +++
Documentation/security/index.rst | 1 +
MAINTAINERS | 11 +
include/linux/bpf_event.h | 78 ++
include/linux/bpf_lsm.h | 25 +
include/linux/bpf_types.h | 4 +
include/trace/bpf_probe.h | 30 +-
include/uapi/linux/bpf.h | 12 +-
kernel/bpf/syscall.c | 10 +
kernel/bpf/verifier.c | 84 +-
kernel/trace/bpf_trace.c | 24 +-
security/Kconfig | 11 +-
security/Makefile | 2 +
security/bpf/Kconfig | 25 +
security/bpf/Makefile | 7 +
security/bpf/include/bpf_lsm.h | 63 +
security/bpf/include/fs.h | 23 +
security/bpf/include/hooks.h | 1015 +++++++++++++++++
security/bpf/lsm.c | 160 +++
security/bpf/lsm_fs.c | 176 +++
security/bpf/ops.c | 224 ++++
tools/include/uapi/linux/bpf.h | 12 +-
tools/lib/bpf/bpf.c | 2 +-
tools/lib/bpf/bpf.h | 6 +
tools/lib/bpf/libbpf.c | 163 ++-
tools/lib/bpf/libbpf.h | 4 +
tools/lib/bpf/libbpf.map | 7 +
tools/lib/bpf/libbpf_probes.c | 1 +
.../bpf/prog_tests/lsm_mprotect_audit.c | 129 +++
.../selftests/bpf/progs/lsm_mprotect_audit.c | 58 +
30 files changed, 2451 insertions(+), 80 deletions(-)
create mode 100644 Documentation/security/bpf.rst
create mode 100644 include/linux/bpf_event.h
create mode 100644 include/linux/bpf_lsm.h
create mode 100644 security/bpf/Kconfig
create mode 100644 security/bpf/Makefile
create mode 100644 security/bpf/include/bpf_lsm.h
create mode 100644 security/bpf/include/fs.h
create mode 100644 security/bpf/include/hooks.h
create mode 100644 security/bpf/lsm.c
create mode 100644 security/bpf/lsm_fs.c
create mode 100644 security/bpf/ops.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
create mode 100644 tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
--
2.20.1
^ permalink raw reply
* [PATCH bpf-next v1 13/13] bpf: lsm: Add Documentation
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
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 <kpsingh@google.com>
---
Documentation/security/bpf.rst | 164 +++++++++++++++++++++++++++++++
Documentation/security/index.rst | 1 +
MAINTAINERS | 1 +
3 files changed, 166 insertions(+)
create mode 100644 Documentation/security/bpf.rst
diff --git a/Documentation/security/bpf.rst b/Documentation/security/bpf.rst
new file mode 100644
index 000000000000..898b7de148a0
--- /dev/null
+++ b/Documentation/security/bpf.rst
@@ -0,0 +1,164 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright 2019 Google LLC.
+
+==========================
+eBPF Linux Security Module
+==========================
+
+This LSM allows runtime instrumentation of the LSM hooks by privileged users to
+implement system-wide MAC (Mandatory Access Control) and Audit policies using
+eBPF. The LSM is priveleged and stackable and requires both ``CAP_SYS_ADMIN``
+and ``CAP_MAC_ADMIN`` for the loading of BPF programs and modification of MAC
+policies respectively.
+
+eBPF Programs
+==============
+
+`eBPF (extended BPF) <https://cilium.readthedocs.io/en/latest/bpf>`_ is a
+virtual machine-like construct in the Linux Kernel allowing the execution of
+verifiable, just-in-time compiled byte code at various points in the Kernel.
+
+The eBPF LSM adds a new type, ``BPF_PROG_TYPE_LSM``, of eBPF programs which
+have the following characteristics:
+
+ * Multiple eBPF programs can be attached to the same LSM hook.
+ * LSM hooks can return an ``-EPERM`` to indicate the decision of the
+ MAC policy being enforced or simply be used for auditing.
+ * Allowing the eBPF programs to be attached to all the LSM hooks by
+ making :doc:`/bpf/btf` type information available for all LSM hooks
+ and allowing the BPF verifier to perform runtime relocations and
+ validation on the programs.
+
+Structure
+---------
+
+The example shows an eBPF program that can be attached to the ``file_mprotect``
+LSM hook:
+
+.. c:function:: int file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot);
+
+eBPF programs that use :doc:`/bpf/btf` do not need to include kernel headers
+for accessing information from the attached eBPF program's context. They can
+simply declare the structures in the eBPF program and only specify the fields
+that need to be accessed.
+
+.. code-block:: c
+
+ struct mm_struct {
+ unsigned long start_brk, brk, start_stack;
+ };
+
+ struct vm_area_struct {
+ unsigned long start_brk, brk, start_stack;
+ unsigned long vm_start, vm_end;
+ struct mm_struct *vm_mm;
+ };
+
+
+.. note:: Only the size and the names of the fields must match the type in the
+ kernel and the order of the fields is irrelevant.
+
+The eBPF programs can be declared using macros similar to the ``BPF_TRACE_<N>``
+macros defined in `tools/testing/selftests/bpf/bpf_trace_helpers.h`_. In this
+example:
+
+ * The LSM hook takes 3 args so we use ``BPF_TRACE_3``.
+ * ``"lsm/file_mprotect"`` indicates the LSM hook that the program must
+ be attached to.
+ * ``mprotect_audit`` is the name of the eBPF program.
+
+.. code-block:: c
+
+ BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
+ struct vm_area_struct *, vma,
+ unsigned long, reqprot, unsigned long, prot)
+ {
+ int is_heap = 0;
+
+ __builtin_preserve_access_index(({
+ is_heap = (vma->vm_start >= vma->vm_mm->start_brk &&
+ vma->vm_end <= vma->vm_mm->brk);
+ }));
+
+ /*
+ * Return an -EPERM or Write information to the perf events buffer
+ * for auditing
+ */
+ }
+
+The ``__builtin_preserve_access_index`` is a clang primitive that allows the
+BPF verifier to update the offsets for the access at runtime using the
+:doc:`/bpf/btf` information. Since the BPF verifier is aware of the types, it
+also validates all the accesses made to the various types in the eBPF program.
+
+Loading
+-------
+
+eBPP programs can be loaded with the :manpage:`bpf(2)` syscall's
+``BPF_PROG_LOAD`` operation or more simply by using the the libbpf helper
+``bpf_prog_load_xattr``:
+
+
+.. code-block:: c
+
+ struct bpf_prog_load_attr attr = {
+ .file = "./prog.o",
+ };
+ struct bpf_object *prog_obj;
+ struct bpf_program *prog;
+ int prog_fd;
+
+ bpf_prog_load_xattr(&attr, &prog_obj, &prog_fd);
+
+Attachment to LSM Hooks
+-----------------------
+
+The LSM creates a file in securityfs for each LSM hook to which eBPF programs
+can be attached using :manpage:`bpf(2)` syscall's ``BPF_PROG_ATTACH`` operation
+or more simply by using the libbpf helper ``bpf_program__attach_lsm``. In the
+code shown below ``prog`` is the eBPF program loaded using ``BPF_PROG_LOAD``:
+
+
+.. code-block:: c
+
+ struct bpf_link *link;
+
+ link = bpf_program__attach_lsm(prog);
+
+The attachment can be verified by:
+
+.. code-block:: console
+
+ # cat /sys/kernel/security/bpf/file_mprotect
+ mprotect_audit
+
+If, when a program is attached, another program by the same name is already attached to the hook, that program is replaced.
+
+
+.. note:: This requires that the ``BPF_F_ALLOW_OVERRIDE`` flag be passed to
+ the :manpage:`bpf(2)` syscall. If not, an ``-EEXIST`` error is returned instead.
+
+For conveniently versioning updating programs, program names are only compared up to the first ``"__"``. Thus if a program ``mprotect_audit__v1`` is attached and then ``mprotect_audit__v2`` is attached to the same hook, the latter will *replace* the former.
+
+The program can be detached from the LSM hook by *destroying* the ``link``
+link returned by ``bpf_program__attach_lsm``:
+
+.. code-block:: c
+
+ link->destroy();
+
+Examples
+--------
+
+An example eBPF program can be found in
+`tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c`_ and the corresponding
+userspace code in
+`tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c`_
+
+.. Links
+.. _tools/testing/selftests/bpf/bpf_trace_helpers.h:
+ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/selftests/bpf/bpf_trace_helpers.h
+.. _tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c:
+ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
+.. _tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c:
+ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
diff --git a/Documentation/security/index.rst b/Documentation/security/index.rst
index fc503dd689a7..844463df4547 100644
--- a/Documentation/security/index.rst
+++ b/Documentation/security/index.rst
@@ -5,6 +5,7 @@ Security Documentation
.. toctree::
:maxdepth: 1
+ bpf
credentials
IMA-templates
keys/index
diff --git a/MAINTAINERS b/MAINTAINERS
index 652c93292ae9..6f34c24519ca 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3184,6 +3184,7 @@ F: security/bpf/
F: include/linux/bpf_lsm.h
F: tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
F: tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
+F: Documentation/security/bpf.rst
BROADCOM B44 10/100 ETHERNET DRIVER
M: Michael Chan <michael.chan@broadcom.com>
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 11/13] tools/libbpf: Add bpf_program__attach_lsm
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
Add functionality in libbpf to attach eBPF program to LSM hooks.
Signed-off-by: KP Singh <kpsingh@google.com>
---
tools/lib/bpf/libbpf.c | 127 +++++++++++++++++++++++++++++++++++++--
tools/lib/bpf/libbpf.h | 2 +
tools/lib/bpf/libbpf.map | 1 +
3 files changed, 126 insertions(+), 4 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b0b27d8e5a37..ab2b23b4f21f 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -5122,8 +5122,8 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
return -ESRCH;
}
-static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name,
- const char *prefix)
+static inline int __btf__type_with_prefix(struct btf *btf, const char *name,
+ const char *prefix)
{
size_t prefix_len = strlen(prefix);
@@ -5149,9 +5149,9 @@ int libbpf_find_vmlinux_btf_id(const char *name,
}
if (attach_type == BPF_TRACE_RAW_TP)
- err = __btf__typdef_with_prefix(btf, name, BTF_TRACE_PREFIX);
+ err = __btf__type_with_prefix(btf, name, BTF_TRACE_PREFIX);
else if (attach_type == BPF_LSM_MAC)
- err = __btf__typdef_with_prefix(btf, name, BTF_LSM_PREFIX);
+ err = __btf__type_with_prefix(btf, name, BTF_LSM_PREFIX);
else
err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
@@ -5502,6 +5502,18 @@ struct bpf_link_fd {
int fd; /* hook FD */
};
+/*
+ * The other attach types allow the link to be destroyed by using an ioctl or
+ * an operation on some file descriptor that describes the attachment. An LSM
+ * hook can have multiple programs attached to each hook, so the link needs to
+ * specify the program that must be detached when the link is destroyed.
+ */
+struct bpf_link_lsm {
+ struct bpf_link link;
+ int hook_fd;
+ int prog_fd;
+};
+
static int bpf_link__destroy_perf_event(struct bpf_link *link)
{
struct bpf_link_fd *l = (void *)link;
@@ -5876,6 +5888,113 @@ struct bpf_link *bpf_program__attach_trace(struct bpf_program *prog)
return (struct bpf_link *)link;
}
+
+static int bpf_link__destroy_lsm(struct bpf_link *link)
+{
+ struct bpf_link_lsm *ll = container_of(link, struct bpf_link_lsm, link);
+ char errmsg[STRERR_BUFSIZE];
+ int ret;
+
+ ret = bpf_prog_detach2(ll->prog_fd, ll->hook_fd, BPF_LSM_MAC);
+ if (ret < 0) {
+ ret = -errno;
+ pr_warn("failed to detach from hook: %s\n",
+ libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
+ return ret;
+ }
+ close(ll->hook_fd);
+ return 0;
+}
+
+static const char *__lsm_hook_name(const char *title)
+{
+
+ int i;
+
+ if (!title)
+ return ERR_PTR(-EINVAL);
+
+ for (i = 0; i < ARRAY_SIZE(section_names); i++) {
+ if (section_names[i].prog_type != BPF_PROG_TYPE_LSM)
+ continue;
+
+ if (strncmp(title, section_names[i].sec,
+ section_names[i].len)) {
+ pr_warn("title for a LSM prog must begin with '%s'\n",
+ section_names[i].sec);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return title + section_names[i].len;
+ }
+
+ pr_warn("could not find section information for BPF_PROG_TYPE_LSM\n");
+ return ERR_PTR(-ESRCH);
+}
+
+struct bpf_link *bpf_program__attach_lsm(struct bpf_program *prog)
+{
+ char hook_path[PATH_MAX] = "/sys/kernel/security/bpf/";
+ const char *title, *hook_name;
+ char errmsg[STRERR_BUFSIZE];
+ int prog_fd, target_fd, ret;
+ struct bpf_link_lsm *link;
+
+ title = bpf_program__title(prog, false);
+ if (IS_ERR(title)) {
+ pr_warn("could not determine title of the program\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ hook_name = __lsm_hook_name(title);
+ if (IS_ERR(hook_name)) {
+ pr_warn("could not determine LSM hook name from title '%s'\n",
+ title);
+ return ERR_PTR(-EINVAL);
+ }
+
+ prog_fd = bpf_program__fd(prog);
+ if (prog_fd < 0) {
+ pr_warn("program '%s': can't attach before loaded\n", title);
+ return ERR_PTR(-EINVAL);
+ }
+
+ link = malloc(sizeof(*link));
+ if (!link)
+ return ERR_PTR(-ENOMEM);
+ link->link.destroy = &bpf_link__destroy_lsm;
+
+ /* Attach the BPF program to the given hook */
+ strncat(hook_path, hook_name,
+ sizeof(hook_path) - (strlen(hook_path) + 1));
+ target_fd = open(hook_path, O_RDWR);
+ if (target_fd < 0) {
+ ret = -errno;
+ pr_warn("program '%s': failed to open to hook '%s': %s\n",
+ title, hook_path,
+ libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
+ return ERR_PTR(ret);
+ }
+
+ ret = bpf_prog_attach(prog_fd, target_fd, BPF_LSM_MAC,
+ BPF_F_ALLOW_OVERRIDE);
+ if (ret < 0) {
+ ret = -errno;
+ pr_warn("program '%s': failed to attach to hook '%s': %s\n",
+ title, hook_name,
+ libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
+ goto error;
+ }
+
+ link->hook_fd = target_fd;
+ link->prog_fd = prog_fd;
+ return &link->link;
+
+error:
+ close(target_fd);
+ return ERR_PTR(ret);
+}
+
enum bpf_perf_event_ret
bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
void **copy_mem, size_t *copy_size,
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 9cd69d602c82..655f27ad6ece 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -256,6 +256,8 @@ bpf_program__attach_raw_tracepoint(struct bpf_program *prog,
LIBBPF_API struct bpf_link *
bpf_program__attach_trace(struct bpf_program *prog);
+LIBBPF_API struct bpf_link *
+bpf_program__attach_lsm(struct bpf_program *prog);
struct bpf_insn;
/*
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 3d396149755d..5d64ba9b2a43 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -213,4 +213,5 @@ LIBBPF_0.0.7 {
global:
bpf_program__is_lsm;
bpf_program__set_lsm;
+ bpf_program__attach_lsm;
} LIBBPF_0.0.6;
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 12/13] bpf: lsm: Add selftests for BPF_PROG_TYPE_LSM
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
* Load a BPF program that audits mprotect calls
* Attach the program to the "file_mprotect" LSM hook
* Verify if the program is actually loading by reading
securityfs
* Initialize the perf events buffer and poll for audit events
* Do an mprotect on some memory allocated on the heap
* Verify if the audit event was received
Signed-off-by: KP Singh <kpsingh@google.com>
---
MAINTAINERS | 2 +
.../bpf/prog_tests/lsm_mprotect_audit.c | 129 ++++++++++++++++++
.../selftests/bpf/progs/lsm_mprotect_audit.c | 58 ++++++++
3 files changed, 189 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
create mode 100644 tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 681ae39bb2f0..652c93292ae9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3182,6 +3182,8 @@ L: bpf@vger.kernel.org
S: Maintained
F: security/bpf/
F: include/linux/bpf_lsm.h
+F: tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
+F: tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
BROADCOM B44 10/100 ETHERNET DRIVER
M: Michael Chan <michael.chan@broadcom.com>
diff --git a/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c b/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
new file mode 100644
index 000000000000..953531cec9fd
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/lsm_mprotect_audit.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#include <test_progs.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <malloc.h>
+
+#define EXPECTED_PROG_NAME "mprotect_audit"
+#define MPROTECT_AUDIT_MAGIC 0xDEAD
+
+struct mprotect_audit_log {
+ int is_heap, magic;
+};
+
+static void on_sample(void *ctx, int cpu, void *data, __u32 size)
+{
+ struct mprotect_audit_log *audit_log = data;
+ int duration = 0;
+
+ if (audit_log->magic != MPROTECT_AUDIT_MAGIC)
+ return;
+
+ if (CHECK(audit_log->is_heap != 1, "mprotect on heap",
+ "is_heap = %d\n", audit_log->is_heap))
+ return;
+
+ *(bool *)ctx = true;
+}
+
+int heap_mprotect(void)
+{
+ void *buf;
+ long sz;
+
+ sz = sysconf(_SC_PAGESIZE);
+ if (sz < 0)
+ return sz;
+
+ buf = memalign(sz, 2 * sz);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ return mprotect(buf, sz, PROT_READ | PROT_EXEC);
+}
+
+void test_lsm_mprotect_audit(void)
+{
+ struct bpf_prog_load_attr attr = {
+ .file = "./lsm_mprotect_audit.o",
+ };
+
+ struct perf_buffer_opts pb_opts = {};
+ struct perf_buffer *pb = NULL;
+ struct bpf_link *link = NULL;
+ struct bpf_map *perf_buf_map;
+ struct bpf_object *prog_obj;
+ struct bpf_program *prog;
+ int err, prog_fd, sfs_fd;
+ char sfs_buf[1024];
+ int duration = 0;
+ bool passed = false;
+
+ err = bpf_prog_load_xattr(&attr, &prog_obj, &prog_fd);
+ if (CHECK(err, "prog_load lsm/file_mprotect",
+ "err %d errno %d\n", err, errno))
+ goto close_prog;
+
+ prog = bpf_object__find_program_by_title(prog_obj, "lsm/file_mprotect");
+ if (CHECK(!prog, "find_prog", "lsm/file_mprotect not found\n"))
+ goto close_prog;
+
+ link = bpf_program__attach_lsm(prog);
+ if (CHECK(IS_ERR(link), "attach_lsm file_mprotect",
+ "err %ld\n", PTR_ERR(link)))
+ goto close_prog;
+
+ sfs_fd = open("/sys/kernel/security/bpf/file_mprotect", O_RDONLY);
+ if (CHECK(sfs_fd < 0, "sfs_open file_mprotect",
+ "err %d errno %d\n", sfs_fd, errno))
+ goto close_prog;
+
+ err = read(sfs_fd, sfs_buf, sizeof(sfs_buf));
+ if (CHECK(err < 0, "sfs_read file_mprotect",
+ "err %d errno %d\n", sfs_fd, errno))
+ goto close_prog;
+
+ err = strncmp(sfs_buf, EXPECTED_PROG_NAME, strlen(EXPECTED_PROG_NAME));
+ if (CHECK(err != 0,
+ "sfs_read value", "want = %s, got = %s\n",
+ EXPECTED_PROG_NAME, sfs_buf))
+ goto close_prog;
+
+ perf_buf_map = bpf_object__find_map_by_name(prog_obj, "perf_buf_map");
+ if (CHECK(!perf_buf_map, "find_perf_buf_map", "not found\n"))
+ goto close_prog;
+
+ /* set up perf buffer */
+ pb_opts.sample_cb = on_sample;
+ pb_opts.ctx = &passed;
+ pb = perf_buffer__new(bpf_map__fd(perf_buf_map), 1, &pb_opts);
+ if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb)))
+ goto close_prog;
+
+ err = heap_mprotect();
+ if (CHECK(err < 0, "heap_mprotect",
+ "err %d errno %d\n", err, errno))
+ goto close_prog;
+
+ /* read perf buffer */
+ err = perf_buffer__poll(pb, 100);
+ if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err))
+ goto close_prog;
+
+ /*
+ * make sure mprotect_audit program was triggered
+ * and detected an mprotect on the heap
+ */
+ CHECK_FAIL(!passed);
+
+close_prog:
+ perf_buffer__free(pb);
+ if (!IS_ERR_OR_NULL(link))
+ bpf_link__destroy(link);
+ bpf_object__close(prog_obj);
+}
diff --git a/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c b/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
new file mode 100644
index 000000000000..85048315baae
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/lsm_mprotect_audit.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#include <linux/bpf.h>
+#include <stdbool.h>
+#include "bpf_helpers.h"
+#include "bpf_trace_helpers.h"
+
+char _license[] SEC("license") = "GPL";
+struct {
+ __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+ __uint(key_size, sizeof(int));
+ __uint(value_size, sizeof(int));
+} perf_buf_map SEC(".maps");
+
+#define MPROTECT_AUDIT_MAGIC 0xDEAD
+
+struct mprotect_audit_log {
+ int is_heap, magic;
+};
+
+/*
+ * Define some of the structs used in the BPF program.
+ * Only the field names and their sizes need to be the
+ * same as the kernel type, the order is irrelevant.
+ */
+struct mm_struct {
+ unsigned long start_brk, brk, start_stack;
+};
+
+struct vm_area_struct {
+ unsigned long start_brk, brk, start_stack;
+ unsigned long vm_start, vm_end;
+ struct mm_struct *vm_mm;
+ unsigned long vm_flags;
+};
+
+BPF_TRACE_3("lsm/file_mprotect", mprotect_audit,
+ struct vm_area_struct *, vma,
+ unsigned long, reqprot, unsigned long, prot)
+{
+ struct mprotect_audit_log audit_log = {};
+ int is_heap = 0;
+
+ __builtin_preserve_access_index(({
+ is_heap = (vma->vm_start >= vma->vm_mm->start_brk &&
+ vma->vm_end <= vma->vm_mm->brk);
+ }));
+
+ audit_log.magic = MPROTECT_AUDIT_MAGIC;
+ audit_log.is_heap = is_heap;
+ bpf_lsm_event_output(&perf_buf_map, BPF_F_CURRENT_CPU, &audit_log,
+ sizeof(audit_log));
+ return 0;
+}
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 10/13] bpf: lsm: Handle attachment of the same program
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
Allow userspace to attach a newer version of a program without having
duplicates of the same program.
If BPF_F_ALLOW_OVERRIDE is passed, the attachment logic compares the
name of the new program to the names of existing attached programs. The
names are only compared till a "__" (or '\0', if there is no "__"). If
a successful match is found, the existing program is replaced with the
newer attachment.
./loader Attaches "env_dumper__v1" followed by "env_dumper__v2"
to the bprm_check_security hook..
./loader
./loader
Before:
cat /sys/kernel/security/bpf/process_execution
env_dumper__v1
env_dumper__v2
After:
cat /sys/kernel/security/bpf/process_execution
env_dumper__v2
Signed-off-by: KP Singh <kpsingh@google.com>
---
security/bpf/ops.c | 57 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/security/bpf/ops.c b/security/bpf/ops.c
index e9aae2ce718c..481e6ee75f27 100644
--- a/security/bpf/ops.c
+++ b/security/bpf/ops.c
@@ -64,11 +64,52 @@ static struct bpf_lsm_hook *get_hook_from_fd(int fd)
return ERR_PTR(ret);
}
+/*
+ * match_prog_name matches the name of the program till "__"
+ * or the end of the string is encountered. This allows
+ * the matched program to be replaced by a newer version.
+ *
+ * For example:
+ *
+ * env_dumper__v1 is matched with env_dumper__v2
+ *
+ */
+static bool match_prog_name(const char *a, const char *b)
+{
+ size_t m, n;
+ char *end;
+
+ end = strstr(a, "__");
+ n = end ? end - a : strlen(a);
+
+ end = strstr(b, "__");
+ m = end ? end - b : strlen(b);
+
+ if (m != n)
+ return false;
+
+ return strncmp(a, b, n) == 0;
+}
+
+static struct bpf_prog *find_attached_prog(struct bpf_prog_array *array,
+ struct bpf_prog *prog)
+{
+ struct bpf_prog_array_item *item = array->items;
+
+ for (; item->prog; item++) {
+ if (match_prog_name(item->prog->aux->name, prog->aux->name))
+ return item->prog;
+ }
+
+ return NULL;
+}
+
int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog)
{
struct bpf_prog_array *old_array;
struct bpf_prog_array *new_array;
struct bpf_lsm_hook *h;
+ struct bpf_prog *old_prog = NULL;
int ret = 0;
h = get_hook_from_fd(attr->target_fd);
@@ -78,13 +119,27 @@ int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog)
mutex_lock(&h->mutex);
old_array = rcu_dereference_protected(h->progs,
lockdep_is_held(&h->mutex));
+ /*
+ * Check if a matching program already exists and replace
+ * the existing program if BPF_F_ALLOW_OVERRIDE is specified in
+ * the attach flags.
+ */
+ if (old_array) {
+ old_prog = find_attached_prog(old_array, prog);
+ if (old_prog && !(attr->attach_flags & BPF_F_ALLOW_OVERRIDE)) {
+ ret = -EEXIST;
+ goto unlock;
+ }
+ }
- ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array);
+ ret = bpf_prog_array_copy(old_array, old_prog, prog, &new_array);
if (ret < 0)
goto unlock;
rcu_assign_pointer(h->progs, new_array);
bpf_prog_array_free(old_array);
+ if (old_prog)
+ bpf_prog_put(old_prog);
unlock:
mutex_unlock(&h->mutex);
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 09/13] bpf: lsm: Add a helper function bpf_lsm_event_output
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
This helper is similar to bpf_perf_event_output except that
it does need a ctx argument which is more usable in the
BTF based LSM programs where the context is converted to
the signature of the attacthed BTF type.
An example usage of this function would be:
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(u32));
} perf_map SEC(".maps");
BPF_TRACE_1(bpf_prog1, "lsm/bprm_check_security,
struct linux_binprm *, bprm)
{
char buf[BUF_SIZE];
int len;
u64 flags = BPF_F_CURRENT_CPU;
/* some logic that fills up buf with len data */
len = fill_up_buf(buf);
if (len < 0)
return len;
if (len > BU)
return 0;
bpf_lsm_event_output(&perf_map, flags, buf, len);
return 0;
}
Signed-off-by: KP Singh <kpsingh@google.com>
---
include/uapi/linux/bpf.h | 10 +++++++++-
kernel/bpf/verifier.c | 1 +
security/bpf/ops.c | 21 +++++++++++++++++++++
tools/include/uapi/linux/bpf.h | 10 +++++++++-
4 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index fc64ae865526..3511fa271c9b 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -2823,6 +2823,13 @@ union bpf_attr {
* Return
* On success, the strictly positive length of the string, including
* the trailing NUL character. On error, a negative value.
+ *
+ * int bpf_lsm_event_output(struct bpf_map *map, u64 flags, void *data, u64 size)
+ * Description
+ * This helper is similar to bpf_perf_event_output except that it
+ * it does not need a context argument.
+ * Return
+ * 0 on success, or a negative error in case of failure.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -2940,7 +2947,8 @@ union bpf_attr {
FN(probe_read_user), \
FN(probe_read_kernel), \
FN(probe_read_user_str), \
- FN(probe_read_kernel_str),
+ FN(probe_read_kernel_str), \
+ FN(lsm_event_output), \
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 0d1231d9c1ef..ff050fd71e9f 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3641,6 +3641,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
if (func_id != BPF_FUNC_perf_event_read &&
func_id != BPF_FUNC_perf_event_output &&
func_id != BPF_FUNC_skb_output &&
+ func_id != BPF_FUNC_lsm_event_output &&
func_id != BPF_FUNC_perf_event_read_value)
goto error;
break;
diff --git a/security/bpf/ops.c b/security/bpf/ops.c
index eb8a8db28109..e9aae2ce718c 100644
--- a/security/bpf/ops.c
+++ b/security/bpf/ops.c
@@ -129,6 +129,25 @@ int bpf_lsm_detach(const union bpf_attr *attr)
const struct bpf_prog_ops lsm_prog_ops = {
};
+BPF_CALL_4(bpf_lsm_event_output,
+ struct bpf_map *, map, u64, flags, void *, data, u64, size)
+{
+ if (unlikely(flags & ~(BPF_F_INDEX_MASK)))
+ return -EINVAL;
+
+ return bpf_event_output(map, flags, data, size, NULL, 0, NULL);
+}
+
+static const struct bpf_func_proto bpf_lsm_event_output_proto = {
+ .func = bpf_lsm_event_output,
+ .gpl_only = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_CONST_MAP_PTR,
+ .arg2_type = ARG_ANYTHING,
+ .arg3_type = ARG_PTR_TO_MEM,
+ .arg4_type = ARG_CONST_SIZE_OR_ZERO,
+};
+
static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id
func_id, const struct bpf_prog *prog)
{
@@ -137,6 +156,8 @@ static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id
return &bpf_map_lookup_elem_proto;
case BPF_FUNC_get_current_pid_tgid:
return &bpf_get_current_pid_tgid_proto;
+ case BPF_FUNC_lsm_event_output:
+ return &bpf_lsm_event_output_proto;
default:
return NULL;
}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index fc64ae865526..3511fa271c9b 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -2823,6 +2823,13 @@ union bpf_attr {
* Return
* On success, the strictly positive length of the string, including
* the trailing NUL character. On error, a negative value.
+ *
+ * int bpf_lsm_event_output(struct bpf_map *map, u64 flags, void *data, u64 size)
+ * Description
+ * This helper is similar to bpf_perf_event_output except that it
+ * it does not need a context argument.
+ * Return
+ * 0 on success, or a negative error in case of failure.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -2940,7 +2947,8 @@ union bpf_attr {
FN(probe_read_user), \
FN(probe_read_kernel), \
FN(probe_read_user_str), \
- FN(probe_read_kernel_str),
+ FN(probe_read_kernel_str), \
+ FN(lsm_event_output), \
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 08/13] bpf: lsm: Show attached program names in hook read handler.
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
For inspectability the system administrator should be able to view the
list of active KRSI programs:
bash # cat /sys/kernel/security/bpf/bprm_check_security
bpf_prog1
Signed-off-by: KP Singh <kpsingh@google.com>
---
security/bpf/lsm_fs.c | 81 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 1 deletion(-)
diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c
index b271e9582d0f..01a89bce1347 100644
--- a/security/bpf/lsm_fs.c
+++ b/security/bpf/lsm_fs.c
@@ -10,6 +10,7 @@
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/filter.h>
+#include <linux/seq_file.h>
#include <linux/bpf.h>
#include <linux/security.h>
#include <linux/bpf_lsm.h>
@@ -19,7 +20,85 @@
static struct dentry *bpf_lsm_dir;
-static const struct file_operations hook_ops = {};
+static void *seq_start(struct seq_file *m, loff_t *pos)
+ __acquires(RCU)
+{
+ struct bpf_prog_array_item *item;
+ struct bpf_prog_array *progs;
+ struct bpf_lsm_hook *h;
+ struct dentry *dentry;
+
+ /*
+ * rcu_read_lock() must be held before any return statement because the
+ * stop() will always be called and thus call rcu_read_unlock()
+ */
+ rcu_read_lock();
+
+ dentry = file_dentry(m->file);
+ h = dentry->d_fsdata;
+ if (WARN_ON(!h))
+ return ERR_PTR(-EFAULT);
+
+ progs = rcu_dereference(h->progs);
+ if (!progs)
+ return NULL;
+
+ /* Assumes that no &dummy_bpf_prog entries exist */
+ if ((*pos) >= bpf_prog_array_length(progs))
+ return NULL;
+
+ item = progs->items + *pos;
+ if (!item->prog)
+ return NULL;
+
+ return item;
+}
+
+static void *seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct bpf_prog_array_item *item = v;
+
+ item++;
+ ++*pos;
+
+ if (!item->prog)
+ return NULL;
+
+ return item;
+}
+
+static void seq_stop(struct seq_file *m, void *v)
+ __releases(RCU)
+{
+ rcu_read_unlock();
+}
+
+static int show_prog(struct seq_file *m, void *v)
+{
+ struct bpf_prog_array_item *item = v;
+
+ seq_printf(m, "%s\n", item->prog->aux->name);
+ return 0;
+}
+
+static const struct seq_operations hook_seq_ops = {
+ .show = show_prog,
+ .start = seq_start,
+ .next = seq_next,
+ .stop = seq_stop,
+};
+
+static int hook_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &hook_seq_ops);
+}
+
+static const struct file_operations hook_ops = {
+ .open = hook_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
int bpf_lsm_fs_initialized;
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 06/13] bpf: lsm: Init Hooks and create files in securityfs
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
The LSM creates files in securityfs for each hook registered with the
LSM.
/sys/kernel/security/bpf/<h_name>
The list of LSM hooks are maintained in an internal header "hooks.h"
Eventually, this list should either be defined collectively in
include/linux/lsm_hooks.h or auto-generated from it.
* Creation of a file for the hook in the securityfs.
* Allocation of a bpf_lsm_hook data structure which stores
a pointer to the dentry of the newly created file in securityfs.
* Creation of a typedef for the hook so that BTF information
can be generated for the LSM hooks to:
- Make them "Compile Once, Run Everywhere".
- Pass the right arguments when the attached programs are run.
- Verify the accesses made by the program by using the BTF
information.
Signed-off-by: KP Singh <kpsingh@google.com>
---
include/linux/bpf_lsm.h | 12 +
security/bpf/Makefile | 4 +-
security/bpf/include/bpf_lsm.h | 63 ++
security/bpf/include/fs.h | 23 +
security/bpf/include/hooks.h | 1015 ++++++++++++++++++++++++++++++++
security/bpf/lsm.c | 138 ++++-
security/bpf/lsm_fs.c | 82 +++
7 files changed, 1333 insertions(+), 4 deletions(-)
create mode 100644 include/linux/bpf_lsm.h
create mode 100644 security/bpf/include/bpf_lsm.h
create mode 100644 security/bpf/include/fs.h
create mode 100644 security/bpf/include/hooks.h
create mode 100644 security/bpf/lsm_fs.c
diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
new file mode 100644
index 000000000000..76f81e642dc2
--- /dev/null
+++ b/include/linux/bpf_lsm.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_BPF_LSM_H
+#define _LINUX_BPF_LSM_H
+
+#include <linux/bpf.h>
+
+#ifdef CONFIG_SECURITY_BPF
+extern int bpf_lsm_fs_initialized;
+#endif /* CONFIG_SECURITY_BPF */
+
+#endif /* _LINUX_BPF_LSM_H */
diff --git a/security/bpf/Makefile b/security/bpf/Makefile
index c78a8a056e7e..8bb5bfc936ee 100644
--- a/security/bpf/Makefile
+++ b/security/bpf/Makefile
@@ -2,4 +2,6 @@
#
# Copyright 2019 Google LLC.
-obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o
+obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o lsm_fs.o
+
+ccflags-y := -I$(srctree)/security/bpf -I$(srctree)/security/bpf/include
diff --git a/security/bpf/include/bpf_lsm.h b/security/bpf/include/bpf_lsm.h
new file mode 100644
index 000000000000..f2409d75d932
--- /dev/null
+++ b/security/bpf/include/bpf_lsm.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _BPF_LSM_H
+#define _BPF_LSM_H
+
+#include <linux/bpf_event.h>
+#include <linux/filter.h>
+#include <linux/bpf.h>
+#include "fs.h"
+
+/*
+ * This enum indexes one of the LSM hooks defined in hooks.h.
+ * Each value of the enum is defined as <hook>_type.
+ */
+enum lsm_hook_type {
+ #define BPF_LSM_HOOK(hook, ...) hook##_type,
+ #include "hooks.h"
+ #undef BPF_LSM_HOOK
+ __MAX_LSM_HOOK_TYPE,
+};
+
+/*
+ * This data structure contains all the information required by the LSM for a
+ * a hook.
+ */
+struct bpf_lsm_hook {
+ /*
+ * The name of the security hook, a file with this name will be created
+ * in the securityfs.
+ */
+ const char *name;
+ /*
+ * The type of the LSM hook, the LSM uses this to index the list of the
+ * hooks to run the eBPF programs that may have been attached.
+ */
+ enum lsm_hook_type h_type;
+ /*
+ * The dentry of the file created in securityfs.
+ */
+ struct dentry *h_dentry;
+ /*
+ * The mutex must be held when updating the progs attached to the hook.
+ */
+ struct mutex mutex;
+ /*
+ * The eBPF programs that are attached to this hook.
+ */
+ struct bpf_prog_array __rcu *progs;
+ /*
+ * The actual implementation of the hook. This also ensures that
+ * BTF information is generated for the hook.
+ */
+ void *btf_hook_func;
+};
+
+extern struct bpf_lsm_hook bpf_lsm_hooks_list[];
+
+#define lsm_for_each_hook(hook) \
+ for ((hook) = &bpf_lsm_hooks_list[0]; \
+ (hook) < &bpf_lsm_hooks_list[__MAX_LSM_HOOK_TYPE]; \
+ (hook)++)
+
+#endif /* _BPF_LSM_H */
diff --git a/security/bpf/include/fs.h b/security/bpf/include/fs.h
new file mode 100644
index 000000000000..9d87a0b2bf41
--- /dev/null
+++ b/security/bpf/include/fs.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#ifndef _BPF_LSM_FS_H
+#define _BPF_LSM_FS_H
+
+#include <linux/bpf.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+
+bool is_bpf_lsm_hook_file(struct file *f);
+
+/*
+ * The name of the directory created in securityfs
+ *
+ * /sys/kernel/security/<dir_name>
+ */
+#define BPF_LSM_SFS_NAME "bpf"
+
+#endif /* _BPF_LSM_FS_H */
diff --git a/security/bpf/include/hooks.h b/security/bpf/include/hooks.h
new file mode 100644
index 000000000000..c91c6fae8058
--- /dev/null
+++ b/security/bpf/include/hooks.h
@@ -0,0 +1,1015 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright 2019 Google LLC.
+ *
+ * The hooks for the KRSI LSM are declared in this file.
+ *
+ * This header MUST NOT be included directly and is included inline
+ * for generating various data structurs for the hooks using the
+ * following pattern:
+ *
+ * #define BPF_LSM_HOOK RET NAME(PROTO);
+ * #include "hooks.h"
+ * #undef BPF_LSM_HOOK
+ *
+ * Format:
+ *
+ * BPF_LSM_HOOK(NAME, RET, PROTO, ARGS)
+ *
+ */
+#define BPF_LSM_ARGS(args...) args
+
+BPF_LSM_HOOK(binder_set_context_mgr,
+ int,
+ BPF_LSM_ARGS(struct task_struct *mgr),
+ BPF_LSM_ARGS(mgr))
+BPF_LSM_HOOK(binder_transaction,
+ int,
+ BPF_LSM_ARGS(struct task_struct *from, struct task_struct *to),
+ BPF_LSM_ARGS(from, to))
+BPF_LSM_HOOK(binder_transfer_binder,
+ int,
+ BPF_LSM_ARGS(struct task_struct *from, struct task_struct *to),
+ BPF_LSM_ARGS(from, to))
+BPF_LSM_HOOK(binder_transfer_file,
+ int,
+ BPF_LSM_ARGS(struct task_struct *from, struct task_struct *to,
+ struct file *file),
+ BPF_LSM_ARGS(from, to, file))
+BPF_LSM_HOOK(ptrace_access_check,
+ int,
+ BPF_LSM_ARGS(struct task_struct *child, unsigned int mode),
+ BPF_LSM_ARGS(child, mode))
+BPF_LSM_HOOK(ptrace_traceme,
+ int,
+ BPF_LSM_ARGS(struct task_struct *parent),
+ BPF_LSM_ARGS(parent))
+BPF_LSM_HOOK(capget,
+ int,
+ BPF_LSM_ARGS(struct task_struct *target, kernel_cap_t *effective,
+ kernel_cap_t *inheritable, kernel_cap_t *permitted),
+ BPF_LSM_ARGS(target, effective, inheritable, permitted))
+BPF_LSM_HOOK(capset,
+ int,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old,
+ const kernel_cap_t *effective,
+ const kernel_cap_t *inheritable,
+ const kernel_cap_t *permitted),
+ BPF_LSM_ARGS(new, old, effective, inheritable, permitted))
+BPF_LSM_HOOK(capable,
+ int,
+ BPF_LSM_ARGS(const struct cred *cred, struct user_namespace *ns,
+ int cap, unsigned int opts),
+ BPF_LSM_ARGS(cred, ns, cap, opts))
+BPF_LSM_HOOK(quotactl,
+ int,
+ BPF_LSM_ARGS(int cmds, int type, int id, struct super_block *sb),
+ BPF_LSM_ARGS(cmds, type, id, sb))
+BPF_LSM_HOOK(quota_on,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(syslog,
+ int,
+ BPF_LSM_ARGS(int type),
+ BPF_LSM_ARGS(type))
+BPF_LSM_HOOK(settime,
+ int,
+ BPF_LSM_ARGS(const struct timespec64 *ts,
+ const struct timezone *tz),
+ BPF_LSM_ARGS(ts, tz))
+BPF_LSM_HOOK(vm_enough_memory,
+ int,
+ BPF_LSM_ARGS(struct mm_struct *mm, long pages),
+ BPF_LSM_ARGS(mm, pages))
+BPF_LSM_HOOK(bprm_set_creds,
+ int,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(bprm_check_security,
+ int,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(bprm_committing_creds,
+ void,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(bprm_committed_creds,
+ void,
+ BPF_LSM_ARGS(struct linux_binprm *bprm),
+ BPF_LSM_ARGS(bprm))
+BPF_LSM_HOOK(fs_context_dup,
+ int,
+ BPF_LSM_ARGS(struct fs_context *fc, struct fs_context *src_sc),
+ BPF_LSM_ARGS(fc, src_sc))
+BPF_LSM_HOOK(fs_context_parse_param,
+ int,
+ BPF_LSM_ARGS(struct fs_context *fc, struct fs_parameter *param),
+ BPF_LSM_ARGS(fc, param))
+BPF_LSM_HOOK(sb_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb),
+ BPF_LSM_ARGS(sb))
+BPF_LSM_HOOK(sb_free_security,
+ void,
+ BPF_LSM_ARGS(struct super_block *sb),
+ BPF_LSM_ARGS(sb))
+BPF_LSM_HOOK(sb_free_mnt_opts,
+ void,
+ BPF_LSM_ARGS(void *mnt_opts),
+ BPF_LSM_ARGS(mnt_opts))
+BPF_LSM_HOOK(sb_eat_lsm_opts,
+ int,
+ BPF_LSM_ARGS(char *orig, void **mnt_opts),
+ BPF_LSM_ARGS(orig, mnt_opts))
+BPF_LSM_HOOK(sb_remount,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb, void *mnt_opts),
+ BPF_LSM_ARGS(sb, mnt_opts))
+BPF_LSM_HOOK(sb_kern_mount,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb),
+ BPF_LSM_ARGS(sb))
+BPF_LSM_HOOK(sb_show_options,
+ int,
+ BPF_LSM_ARGS(struct seq_file *m, struct super_block *sb),
+ BPF_LSM_ARGS(m, sb))
+BPF_LSM_HOOK(sb_statfs,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(sb_mount,
+ int,
+ BPF_LSM_ARGS(const char *dev_name, const struct path *path,
+ const char *type, unsigned long flags, void *data),
+ BPF_LSM_ARGS(dev_name, path, type, flags, data))
+BPF_LSM_HOOK(sb_umount,
+ int,
+ BPF_LSM_ARGS(struct vfsmount *mnt, int flags),
+ BPF_LSM_ARGS(mnt, flags))
+BPF_LSM_HOOK(sb_pivotroot,
+ int,
+ BPF_LSM_ARGS(const struct path *old_path,
+ const struct path *new_path),
+ BPF_LSM_ARGS(old_path, new_path))
+BPF_LSM_HOOK(sb_set_mnt_opts,
+ int,
+ BPF_LSM_ARGS(struct super_block *sb, void *mnt_opts,
+ unsigned long kern_flags, unsigned long *set_kern_flags),
+ BPF_LSM_ARGS(sb, mnt_opts, kern_flags, set_kern_flags))
+BPF_LSM_HOOK(sb_clone_mnt_opts,
+ int,
+ BPF_LSM_ARGS(const struct super_block *oldsb,
+ struct super_block *newsb, unsigned long kern_flags,
+ unsigned long *set_kern_flags),
+ BPF_LSM_ARGS(oldsb, newsb, kern_flags, set_kern_flags))
+BPF_LSM_HOOK(sb_add_mnt_opt,
+ int,
+ BPF_LSM_ARGS(const char *option, const char *val, int len,
+ void **mnt_opts),
+ BPF_LSM_ARGS(option, val, len, mnt_opts))
+BPF_LSM_HOOK(move_mount,
+ int,
+ BPF_LSM_ARGS(const struct path *from_path,
+ const struct path *to_path),
+ BPF_LSM_ARGS(from_path, to_path))
+BPF_LSM_HOOK(dentry_init_security,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, int mode,
+ const struct qstr *name,
+ void **ctx, u32 *ctxlen),
+ BPF_LSM_ARGS(dentry, mode, name, ctx, ctxlen))
+BPF_LSM_HOOK(dentry_create_files_as,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, int mode, struct qstr *name,
+ const struct cred *old, struct cred *new),
+ BPF_LSM_ARGS(dentry, mode, name, old, new))
+
+#ifdef CONFIG_SECURITY_PATH
+BPF_LSM_HOOK(path_unlink,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(path_mkdir,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry,
+ umode_t mode),
+ BPF_LSM_ARGS(dir, dentry, mode))
+BPF_LSM_HOOK(path_rmdir,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(path_mknod,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry,
+ umode_t mode,
+ unsigned int dev),
+ BPF_LSM_ARGS(dir, dentry, mode, dev))
+BPF_LSM_HOOK(path_truncate,
+ int,
+ BPF_LSM_ARGS(const struct path *path),
+ BPF_LSM_ARGS(path))
+BPF_LSM_HOOK(path_symlink,
+ int,
+ BPF_LSM_ARGS(const struct path *dir, struct dentry *dentry,
+ const char *old_name),
+ BPF_LSM_ARGS(dir, dentry, old_name))
+BPF_LSM_HOOK(path_link,
+ int,
+ BPF_LSM_ARGS(struct dentry *old_dentry, const struct path *new_dir,
+ struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dentry, new_dir, new_dentry))
+BPF_LSM_HOOK(path_rename,
+ int,
+ BPF_LSM_ARGS(const struct path *old_dir, struct dentry *old_dentry,
+ const struct path *new_dir, struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dir, old_dentry, new_dir, new_dentry))
+BPF_LSM_HOOK(path_chmod,
+ int,
+ BPF_LSM_ARGS(const struct path *path, umode_t mode),
+ BPF_LSM_ARGS(path, mode))
+BPF_LSM_HOOK(path_chown,
+ int,
+ BPF_LSM_ARGS(const struct path *path, kuid_t uid, kgid_t gid),
+ BPF_LSM_ARGS(path, uid, gid))
+BPF_LSM_HOOK(path_chroot,
+ int,
+ BPF_LSM_ARGS(const struct path *path),
+ BPF_LSM_ARGS(path))
+#endif /* CONFIG_SECURITY_PATH */
+
+BPF_LSM_HOOK(path_notify,
+ int,
+ BPF_LSM_ARGS(const struct path *path, u64 mask,
+ unsigned int obj_type),
+ BPF_LSM_ARGS(path, mask, obj_type))
+BPF_LSM_HOOK(inode_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct inode *inode),
+ BPF_LSM_ARGS(inode))
+BPF_LSM_HOOK(inode_free_security,
+ void,
+ BPF_LSM_ARGS(struct inode *inode),
+ BPF_LSM_ARGS(inode))
+BPF_LSM_HOOK(inode_init_security,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, struct inode *dir,
+ const struct qstr *qstr, const char **name, void **value,
+ size_t *len),
+ BPF_LSM_ARGS(inode, dir, qstr, name, value, len))
+BPF_LSM_HOOK(inode_create,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ umode_t mode),
+ BPF_LSM_ARGS(dir, dentry, mode))
+BPF_LSM_HOOK(inode_link,
+ int,
+ BPF_LSM_ARGS(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dentry, dir, new_dentry))
+BPF_LSM_HOOK(inode_unlink,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(inode_symlink,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ const char *old_name),
+ BPF_LSM_ARGS(dir, dentry, old_name))
+BPF_LSM_HOOK(inode_mkdir,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ umode_t mode),
+ BPF_LSM_ARGS(dir, dentry, mode))
+BPF_LSM_HOOK(inode_rmdir,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry),
+ BPF_LSM_ARGS(dir, dentry))
+BPF_LSM_HOOK(inode_mknod,
+ int,
+ BPF_LSM_ARGS(struct inode *dir, struct dentry *dentry,
+ umode_t mode,
+ dev_t dev),
+ BPF_LSM_ARGS(dir, dentry, mode, dev))
+BPF_LSM_HOOK(inode_rename,
+ int,
+ BPF_LSM_ARGS(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry),
+ BPF_LSM_ARGS(old_dir, old_dentry, new_dir, new_dentry))
+BPF_LSM_HOOK(inode_readlink,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_follow_link,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, struct inode *inode, bool rcu),
+ BPF_LSM_ARGS(dentry, inode, rcu))
+BPF_LSM_HOOK(inode_permission,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, int mask),
+ BPF_LSM_ARGS(inode, mask))
+BPF_LSM_HOOK(inode_setattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, struct iattr *attr),
+ BPF_LSM_ARGS(dentry, attr))
+BPF_LSM_HOOK(inode_getattr,
+ int,
+ BPF_LSM_ARGS(const struct path *path),
+ BPF_LSM_ARGS(path))
+BPF_LSM_HOOK(inode_setxattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name,
+ const void *value,
+ size_t size, int flags),
+ BPF_LSM_ARGS(dentry, name, value, size, flags))
+BPF_LSM_HOOK(inode_post_setxattr,
+ void,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name,
+ const void *value,
+ size_t size, int flags),
+ BPF_LSM_ARGS(dentry, name, value, size, flags))
+BPF_LSM_HOOK(inode_getxattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name),
+ BPF_LSM_ARGS(dentry, name))
+BPF_LSM_HOOK(inode_listxattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_removexattr,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, const char *name),
+ BPF_LSM_ARGS(dentry, name))
+BPF_LSM_HOOK(inode_need_killpriv,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_killpriv,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry),
+ BPF_LSM_ARGS(dentry))
+BPF_LSM_HOOK(inode_getsecurity,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, const char *name, void **buffer,
+ bool alloc),
+ BPF_LSM_ARGS(inode, name, buffer, alloc))
+BPF_LSM_HOOK(inode_setsecurity,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, const char *name,
+ const void *value,
+ size_t size, int flags),
+ BPF_LSM_ARGS(inode, name, value, size, flags))
+BPF_LSM_HOOK(inode_listsecurity,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, char *buffer,
+ size_t buffer_size),
+ BPF_LSM_ARGS(inode, buffer, buffer_size))
+BPF_LSM_HOOK(inode_getsecid,
+ void,
+ BPF_LSM_ARGS(struct inode *inode, u32 *secid),
+ BPF_LSM_ARGS(inode, secid))
+BPF_LSM_HOOK(inode_copy_up,
+ int,
+ BPF_LSM_ARGS(struct dentry *src, struct cred **new),
+ BPF_LSM_ARGS(src, new))
+BPF_LSM_HOOK(inode_copy_up_xattr,
+ int,
+ BPF_LSM_ARGS(const char *name),
+ BPF_LSM_ARGS(name))
+BPF_LSM_HOOK(kernfs_init_security,
+ int,
+ BPF_LSM_ARGS(struct kernfs_node *kn_dir, struct kernfs_node *kn),
+ BPF_LSM_ARGS(kn_dir, kn))
+BPF_LSM_HOOK(file_permission,
+ int,
+ BPF_LSM_ARGS(struct file *file, int mask),
+ BPF_LSM_ARGS(file, mask))
+BPF_LSM_HOOK(file_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_free_security,
+ void,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_ioctl,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned int cmd,
+ unsigned long arg),
+ BPF_LSM_ARGS(file, cmd, arg))
+BPF_LSM_HOOK(mmap_addr,
+ int,
+ BPF_LSM_ARGS(unsigned long addr),
+ BPF_LSM_ARGS(addr))
+BPF_LSM_HOOK(mmap_file,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags),
+ BPF_LSM_ARGS(file, reqprot, prot, flags))
+BPF_LSM_HOOK(file_mprotect,
+ int,
+ BPF_LSM_ARGS(struct vm_area_struct *vma, unsigned long reqprot,
+ unsigned long prot),
+ BPF_LSM_ARGS(vma, reqprot, prot))
+BPF_LSM_HOOK(file_lock,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned int cmd),
+ BPF_LSM_ARGS(file, cmd))
+BPF_LSM_HOOK(file_fcntl,
+ int,
+ BPF_LSM_ARGS(struct file *file, unsigned int cmd,
+ unsigned long arg),
+ BPF_LSM_ARGS(file, cmd, arg))
+BPF_LSM_HOOK(file_set_fowner,
+ void,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_send_sigiotask,
+ int,
+ BPF_LSM_ARGS(struct task_struct *tsk, struct fown_struct *fown,
+ int sig),
+ BPF_LSM_ARGS(tsk, fown, sig))
+BPF_LSM_HOOK(file_receive,
+ int,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(file_open,
+ int,
+ BPF_LSM_ARGS(struct file *file),
+ BPF_LSM_ARGS(file))
+BPF_LSM_HOOK(task_alloc,
+ int,
+ BPF_LSM_ARGS(struct task_struct *task, unsigned long clone_flags),
+ BPF_LSM_ARGS(task, clone_flags))
+BPF_LSM_HOOK(task_free,
+ void,
+ BPF_LSM_ARGS(struct task_struct *task),
+ BPF_LSM_ARGS(task))
+BPF_LSM_HOOK(cred_alloc_blank,
+ int,
+ BPF_LSM_ARGS(struct cred *cred, gfp_t gfp),
+ BPF_LSM_ARGS(cred, gfp))
+BPF_LSM_HOOK(cred_free,
+ void,
+ BPF_LSM_ARGS(struct cred *cred),
+ BPF_LSM_ARGS(cred))
+BPF_LSM_HOOK(cred_prepare,
+ int,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old, gfp_t gfp),
+ BPF_LSM_ARGS(new, old, gfp))
+BPF_LSM_HOOK(cred_transfer,
+ void,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old),
+ BPF_LSM_ARGS(new, old))
+BPF_LSM_HOOK(cred_getsecid,
+ void,
+ BPF_LSM_ARGS(const struct cred *c, u32 *secid),
+ BPF_LSM_ARGS(c, secid))
+BPF_LSM_HOOK(kernel_act_as,
+ int,
+ BPF_LSM_ARGS(struct cred *new, u32 secid),
+ BPF_LSM_ARGS(new, secid))
+BPF_LSM_HOOK(kernel_create_files_as,
+ int,
+ BPF_LSM_ARGS(struct cred *new, struct inode *inode),
+ BPF_LSM_ARGS(new, inode))
+BPF_LSM_HOOK(kernel_module_request,
+ int,
+ BPF_LSM_ARGS(char *kmod_name),
+ BPF_LSM_ARGS(kmod_name))
+BPF_LSM_HOOK(kernel_load_data,
+ int,
+ BPF_LSM_ARGS(enum kernel_load_data_id id),
+ BPF_LSM_ARGS(id))
+BPF_LSM_HOOK(kernel_read_file,
+ int,
+ BPF_LSM_ARGS(struct file *file, enum kernel_read_file_id id),
+ BPF_LSM_ARGS(file, id))
+BPF_LSM_HOOK(kernel_post_read_file,
+ int,
+ BPF_LSM_ARGS(struct file *file, char *buf, loff_t size,
+ enum kernel_read_file_id id),
+ BPF_LSM_ARGS(file, buf, size, id))
+BPF_LSM_HOOK(task_fix_setuid,
+ int,
+ BPF_LSM_ARGS(struct cred *new, const struct cred *old, int flags),
+ BPF_LSM_ARGS(new, old, flags))
+BPF_LSM_HOOK(task_setpgid,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, pid_t pgid),
+ BPF_LSM_ARGS(p, pgid))
+BPF_LSM_HOOK(task_getpgid,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_getsid,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_getsecid,
+ void,
+ BPF_LSM_ARGS(struct task_struct *p, u32 *secid),
+ BPF_LSM_ARGS(p, secid))
+BPF_LSM_HOOK(task_setnice,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, int nice),
+ BPF_LSM_ARGS(p, nice))
+BPF_LSM_HOOK(task_setioprio,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, int ioprio),
+ BPF_LSM_ARGS(p, ioprio))
+BPF_LSM_HOOK(task_getioprio,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_prlimit,
+ int,
+ BPF_LSM_ARGS(const struct cred *cred, const struct cred *tcred,
+ unsigned int flags),
+ BPF_LSM_ARGS(cred, tcred, flags))
+BPF_LSM_HOOK(task_setrlimit,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim),
+ BPF_LSM_ARGS(p, resource, new_rlim))
+BPF_LSM_HOOK(task_setscheduler,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_getscheduler,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_movememory,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p),
+ BPF_LSM_ARGS(p))
+BPF_LSM_HOOK(task_kill,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, struct kernel_siginfo *info,
+ int sig,
+ const struct cred *cred),
+ BPF_LSM_ARGS(p, info, sig, cred))
+BPF_LSM_HOOK(task_prctl,
+ int,
+ BPF_LSM_ARGS(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5),
+ BPF_LSM_ARGS(option, arg2, arg3, arg4, arg5))
+BPF_LSM_HOOK(task_to_inode,
+ void,
+ BPF_LSM_ARGS(struct task_struct *p, struct inode *inode),
+ BPF_LSM_ARGS(p, inode))
+BPF_LSM_HOOK(ipc_permission,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *ipcp, short flag),
+ BPF_LSM_ARGS(ipcp, flag))
+BPF_LSM_HOOK(ipc_getsecid,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *ipcp, u32 *secid),
+ BPF_LSM_ARGS(ipcp, secid))
+BPF_LSM_HOOK(msg_msg_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct msg_msg *msg),
+ BPF_LSM_ARGS(msg))
+BPF_LSM_HOOK(msg_msg_free_security,
+ void,
+ BPF_LSM_ARGS(struct msg_msg *msg),
+ BPF_LSM_ARGS(msg))
+BPF_LSM_HOOK(msg_queue_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(msg_queue_free_security,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(msg_queue_associate,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int msqflg),
+ BPF_LSM_ARGS(perm, msqflg))
+BPF_LSM_HOOK(msg_queue_msgctl,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int cmd),
+ BPF_LSM_ARGS(perm, cmd))
+BPF_LSM_HOOK(msg_queue_msgsnd,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, struct msg_msg *msg,
+ int msqflg),
+ BPF_LSM_ARGS(perm, msg, msqflg))
+BPF_LSM_HOOK(msg_queue_msgrcv,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, struct msg_msg *msg,
+ struct task_struct *target, long type, int mode),
+ BPF_LSM_ARGS(perm, msg, target, type, mode))
+BPF_LSM_HOOK(shm_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(shm_free_security,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(shm_associate,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int shmflg),
+ BPF_LSM_ARGS(perm, shmflg))
+BPF_LSM_HOOK(shm_shmctl,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int cmd),
+ BPF_LSM_ARGS(perm, cmd))
+BPF_LSM_HOOK(shm_shmat,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, char __user *shmaddr,
+ int shmflg),
+ BPF_LSM_ARGS(perm, shmaddr, shmflg))
+BPF_LSM_HOOK(sem_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(sem_free_security,
+ void,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm),
+ BPF_LSM_ARGS(perm))
+BPF_LSM_HOOK(sem_associate,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int semflg),
+ BPF_LSM_ARGS(perm, semflg))
+BPF_LSM_HOOK(sem_semctl,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, int cmd),
+ BPF_LSM_ARGS(perm, cmd))
+BPF_LSM_HOOK(sem_semop,
+ int,
+ BPF_LSM_ARGS(struct kern_ipc_perm *perm, struct sembuf *sops,
+ unsigned nsops, int alter),
+ BPF_LSM_ARGS(perm, sops, nsops, alter))
+BPF_LSM_HOOK(netlink_send,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb),
+ BPF_LSM_ARGS(sk, skb))
+BPF_LSM_HOOK(d_instantiate,
+ void,
+ BPF_LSM_ARGS(struct dentry *dentry, struct inode *inode),
+ BPF_LSM_ARGS(dentry, inode))
+BPF_LSM_HOOK(getprocattr,
+ int,
+ BPF_LSM_ARGS(struct task_struct *p, char *name, char **value),
+ BPF_LSM_ARGS(p, name, value))
+BPF_LSM_HOOK(setprocattr,
+ int,
+ BPF_LSM_ARGS(const char *name, void *value, size_t size),
+ BPF_LSM_ARGS(name, value, size))
+BPF_LSM_HOOK(ismaclabel,
+ int,
+ BPF_LSM_ARGS(const char *name),
+ BPF_LSM_ARGS(name))
+BPF_LSM_HOOK(secid_to_secctx,
+ int,
+ BPF_LSM_ARGS(u32 secid, char **secdata, u32 *seclen),
+ BPF_LSM_ARGS(secid, secdata, seclen))
+BPF_LSM_HOOK(secctx_to_secid,
+ int,
+ BPF_LSM_ARGS(const char *secdata, u32 seclen, u32 *secid),
+ BPF_LSM_ARGS(secdata, seclen, secid))
+BPF_LSM_HOOK(release_secctx,
+ void,
+ BPF_LSM_ARGS(char *secdata, u32 seclen),
+ BPF_LSM_ARGS(secdata, seclen))
+BPF_LSM_HOOK(inode_invalidate_secctx,
+ void,
+ BPF_LSM_ARGS(struct inode *inode),
+ BPF_LSM_ARGS(inode))
+BPF_LSM_HOOK(inode_notifysecctx,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, void *ctx, u32 ctxlen),
+ BPF_LSM_ARGS(inode, ctx, ctxlen))
+BPF_LSM_HOOK(inode_setsecctx,
+ int,
+ BPF_LSM_ARGS(struct dentry *dentry, void *ctx, u32 ctxlen),
+ BPF_LSM_ARGS(dentry, ctx, ctxlen))
+BPF_LSM_HOOK(inode_getsecctx,
+ int,
+ BPF_LSM_ARGS(struct inode *inode, void **ctx, u32 *ctxlen),
+ BPF_LSM_ARGS(inode, ctx, ctxlen))
+
+#ifdef CONFIG_SECURITY_NETWORK
+BPF_LSM_HOOK(unix_stream_connect,
+ int,
+ BPF_LSM_ARGS(struct sock *sock, struct sock *other,
+ struct sock *newsk),
+ BPF_LSM_ARGS(sock, other, newsk))
+BPF_LSM_HOOK(unix_may_send,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct socket *other),
+ BPF_LSM_ARGS(sock, other))
+BPF_LSM_HOOK(socket_create,
+ int,
+ BPF_LSM_ARGS(int family, int type, int protocol, int kern),
+ BPF_LSM_ARGS(family, type, protocol, kern))
+BPF_LSM_HOOK(socket_post_create,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int family, int type,
+ int protocol,
+ int kern),
+ BPF_LSM_ARGS(sock, family, type, protocol, kern))
+BPF_LSM_HOOK(socket_socketpair,
+ int,
+ BPF_LSM_ARGS(struct socket *socka, struct socket *sockb),
+ BPF_LSM_ARGS(socka, sockb))
+BPF_LSM_HOOK(socket_bind,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct sockaddr *address,
+ int addrlen),
+ BPF_LSM_ARGS(sock, address, addrlen))
+BPF_LSM_HOOK(socket_connect,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct sockaddr *address,
+ int addrlen),
+ BPF_LSM_ARGS(sock, address, addrlen))
+BPF_LSM_HOOK(socket_listen,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int backlog),
+ BPF_LSM_ARGS(sock, backlog))
+BPF_LSM_HOOK(socket_accept,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct socket *newsock),
+ BPF_LSM_ARGS(sock, newsock))
+BPF_LSM_HOOK(socket_sendmsg,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct msghdr *msg, int size),
+ BPF_LSM_ARGS(sock, msg, size))
+BPF_LSM_HOOK(socket_recvmsg,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct msghdr *msg, int size,
+ int flags),
+ BPF_LSM_ARGS(sock, msg, size, flags))
+BPF_LSM_HOOK(socket_getsockname,
+ int,
+ BPF_LSM_ARGS(struct socket *sock),
+ BPF_LSM_ARGS(sock))
+BPF_LSM_HOOK(socket_getpeername,
+ int,
+ BPF_LSM_ARGS(struct socket *sock),
+ BPF_LSM_ARGS(sock))
+BPF_LSM_HOOK(socket_getsockopt,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int level, int optname),
+ BPF_LSM_ARGS(sock, level, optname))
+BPF_LSM_HOOK(socket_setsockopt,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int level, int optname),
+ BPF_LSM_ARGS(sock, level, optname))
+BPF_LSM_HOOK(socket_shutdown,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, int how),
+ BPF_LSM_ARGS(sock, how))
+BPF_LSM_HOOK(socket_sock_rcv_skb,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb),
+ BPF_LSM_ARGS(sk, skb))
+BPF_LSM_HOOK(socket_getpeersec_stream,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, char __user *optval,
+ int __user *optlen, unsigned len),
+ BPF_LSM_ARGS(sock, optval, optlen, len))
+BPF_LSM_HOOK(socket_getpeersec_dgram,
+ int,
+ BPF_LSM_ARGS(struct socket *sock, struct sk_buff *skb, u32 *secid),
+ BPF_LSM_ARGS(sock, skb, secid))
+BPF_LSM_HOOK(sk_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, int family, gfp_t priority),
+ BPF_LSM_ARGS(sk, family, priority))
+BPF_LSM_HOOK(sk_free_security,
+ void,
+ BPF_LSM_ARGS(struct sock *sk),
+ BPF_LSM_ARGS(sk))
+BPF_LSM_HOOK(sk_clone_security,
+ void,
+ BPF_LSM_ARGS(const struct sock *sk, struct sock *newsk),
+ BPF_LSM_ARGS(sk, newsk))
+BPF_LSM_HOOK(sk_getsecid,
+ void,
+ BPF_LSM_ARGS(struct sock *sk, u32 *secid),
+ BPF_LSM_ARGS(sk, secid))
+BPF_LSM_HOOK(sock_graft,
+ void,
+ BPF_LSM_ARGS(struct sock *sk, struct socket *parent),
+ BPF_LSM_ARGS(sk, parent))
+BPF_LSM_HOOK(inet_conn_request,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req),
+ BPF_LSM_ARGS(sk, skb, req))
+BPF_LSM_HOOK(inet_csk_clone,
+ void,
+ BPF_LSM_ARGS(struct sock *newsk, const struct request_sock *req),
+ BPF_LSM_ARGS(newsk, req))
+BPF_LSM_HOOK(inet_conn_established,
+ void,
+ BPF_LSM_ARGS(struct sock *sk, struct sk_buff *skb),
+ BPF_LSM_ARGS(sk, skb))
+BPF_LSM_HOOK(secmark_relabel_packet,
+ int,
+ BPF_LSM_ARGS(u32 secid),
+ BPF_LSM_ARGS(secid))
+BPF_LSM_HOOK(secmark_refcount_inc,
+ void,
+ BPF_LSM_ARGS(void),
+ BPF_LSM_ARGS())
+BPF_LSM_HOOK(secmark_refcount_dec,
+ void,
+ BPF_LSM_ARGS(void),
+ BPF_LSM_ARGS())
+BPF_LSM_HOOK(req_classify_flow,
+ void,
+ BPF_LSM_ARGS(const struct request_sock *req, struct flowi *fl),
+ BPF_LSM_ARGS(req, fl))
+BPF_LSM_HOOK(tun_dev_alloc_security,
+ int,
+ BPF_LSM_ARGS(void **security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(tun_dev_free_security,
+ void,
+ BPF_LSM_ARGS(void *security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(tun_dev_create,
+ int,
+ BPF_LSM_ARGS(void),
+ BPF_LSM_ARGS())
+BPF_LSM_HOOK(tun_dev_attach_queue,
+ int,
+ BPF_LSM_ARGS(void *security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(tun_dev_attach,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, void *security),
+ BPF_LSM_ARGS(sk, security))
+BPF_LSM_HOOK(tun_dev_open,
+ int,
+ BPF_LSM_ARGS(void *security),
+ BPF_LSM_ARGS(security))
+BPF_LSM_HOOK(sctp_assoc_request,
+ int,
+ BPF_LSM_ARGS(struct sctp_endpoint *ep, struct sk_buff *skb),
+ BPF_LSM_ARGS(ep, skb))
+BPF_LSM_HOOK(sctp_bind_connect,
+ int,
+ BPF_LSM_ARGS(struct sock *sk, int optname,
+ struct sockaddr *address,
+ int addrlen),
+ BPF_LSM_ARGS(sk, optname, address, addrlen))
+BPF_LSM_HOOK(sctp_sk_clone,
+ void,
+ BPF_LSM_ARGS(struct sctp_endpoint *ep, struct sock *sk,
+ struct sock *newsk),
+ BPF_LSM_ARGS(ep, sk, newsk))
+#endif /* CONFIG_SECURITY_NETWORK */
+
+#ifdef CONFIG_SECURITY_INFINIBAND
+BPF_LSM_HOOK(ib_pkey_access,
+ int,
+ BPF_LSM_ARGS(void *sec, u64 subnet_prefix, u16 pkey),
+ BPF_LSM_ARGS(sec, subnet_prefix, pkey))
+BPF_LSM_HOOK(ib_endport_manage_subnet,
+ int,
+ BPF_LSM_ARGS(void *sec, const char *dev_name, u8 port_num),
+ BPF_LSM_ARGS(sec, dev_name, port_num))
+BPF_LSM_HOOK(ib_alloc_security,
+ int,
+ BPF_LSM_ARGS(void **sec),
+ BPF_LSM_ARGS(sec))
+BPF_LSM_HOOK(ib_free_security,
+ void,
+ BPF_LSM_ARGS(void *sec),
+ BPF_LSM_ARGS(sec))
+#endif /* CONFIG_SECURITY_INFINIBAND */
+
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+BPF_LSM_HOOK(xfrm_policy_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx **ctxp,
+ struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp),
+ BPF_LSM_ARGS(ctxp, sec_ctx, gfp))
+BPF_LSM_HOOK(xfrm_policy_clone_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *old_ctx,
+ struct xfrm_sec_ctx **new_ctx),
+ BPF_LSM_ARGS(old_ctx, new_ctx))
+BPF_LSM_HOOK(xfrm_policy_free_security,
+ void,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *ctx),
+ BPF_LSM_ARGS(ctx))
+BPF_LSM_HOOK(xfrm_policy_delete_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *ctx),
+ BPF_LSM_ARGS(ctx))
+BPF_LSM_HOOK(xfrm_state_alloc,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x,
+ struct xfrm_user_sec_ctx *sec_ctx),
+ BPF_LSM_ARGS(x, sec_ctx))
+BPF_LSM_HOOK(xfrm_state_alloc_acquire,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x, struct xfrm_sec_ctx *polsec,
+ u32 secid),
+ BPF_LSM_ARGS(x, polsec, secid))
+BPF_LSM_HOOK(xfrm_state_free_security,
+ void,
+ BPF_LSM_ARGS(struct xfrm_state *x),
+ BPF_LSM_ARGS(x))
+BPF_LSM_HOOK(xfrm_state_delete_security,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x),
+ BPF_LSM_ARGS(x))
+BPF_LSM_HOOK(xfrm_policy_lookup,
+ int,
+ BPF_LSM_ARGS(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir),
+ BPF_LSM_ARGS(ctx, fl_secid, dir))
+BPF_LSM_HOOK(xfrm_state_pol_flow_match,
+ int,
+ BPF_LSM_ARGS(struct xfrm_state *x, struct xfrm_policy *xp,
+ const struct flowi *fl),
+ BPF_LSM_ARGS(x, xp, fl))
+BPF_LSM_HOOK(xfrm_decode_session,
+ int,
+ BPF_LSM_ARGS(struct sk_buff *skb, u32 *secid, int ckall),
+ BPF_LSM_ARGS(skb, secid, ckall))
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+
+#ifdef CONFIG_KEYS
+BPF_LSM_HOOK(key_alloc,
+ int,
+ BPF_LSM_ARGS(struct key *key, const struct cred *cred,
+ unsigned long flags),
+ BPF_LSM_ARGS(key, cred, flags))
+BPF_LSM_HOOK(key_free,
+ void,
+ BPF_LSM_ARGS(struct key *key),
+ BPF_LSM_ARGS(key))
+BPF_LSM_HOOK(key_permission,
+ int,
+ BPF_LSM_ARGS(key_ref_t key_ref, const struct cred *cred,
+ unsigned perm),
+ BPF_LSM_ARGS(key_ref, cred, perm))
+BPF_LSM_HOOK(key_getsecurity,
+ int,
+ BPF_LSM_ARGS(struct key *key, char **_buffer),
+ BPF_LSM_ARGS(key, _buffer))
+#endif /* CONFIG_KEYS */
+
+#ifdef CONFIG_AUDIT
+BPF_LSM_HOOK(audit_rule_init,
+ int,
+ BPF_LSM_ARGS(u32 field, u32 op, char *rulestr, void **lsmrule),
+ BPF_LSM_ARGS(field, op, rulestr, lsmrule))
+BPF_LSM_HOOK(audit_rule_known,
+ int,
+ BPF_LSM_ARGS(struct audit_krule *krule),
+ BPF_LSM_ARGS(krule))
+BPF_LSM_HOOK(audit_rule_match,
+ int,
+ BPF_LSM_ARGS(u32 secid, u32 field, u32 op, void *lsmrule),
+ BPF_LSM_ARGS(secid, field, op, lsmrule))
+BPF_LSM_HOOK(audit_rule_free,
+ void,
+ BPF_LSM_ARGS(void *lsmrule),
+ BPF_LSM_ARGS(lsmrule))
+#endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_BPF_SYSCALL
+BPF_LSM_HOOK(bpf,
+ int,
+ BPF_LSM_ARGS(int cmd, union bpf_attr *attr, unsigned int size),
+ BPF_LSM_ARGS(cmd, attr, size))
+BPF_LSM_HOOK(bpf_map,
+ int,
+ BPF_LSM_ARGS(struct bpf_map *map, fmode_t fmode),
+ BPF_LSM_ARGS(map, fmode))
+BPF_LSM_HOOK(bpf_prog,
+ int,
+ BPF_LSM_ARGS(struct bpf_prog *prog),
+ BPF_LSM_ARGS(prog))
+BPF_LSM_HOOK(bpf_map_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct bpf_map *map),
+ BPF_LSM_ARGS(map))
+BPF_LSM_HOOK(bpf_map_free_security,
+ void,
+ BPF_LSM_ARGS(struct bpf_map *map),
+ BPF_LSM_ARGS(map))
+BPF_LSM_HOOK(bpf_prog_alloc_security,
+ int,
+ BPF_LSM_ARGS(struct bpf_prog_aux *aux),
+ BPF_LSM_ARGS(aux))
+BPF_LSM_HOOK(bpf_prog_free_security,
+ void,
+ BPF_LSM_ARGS(struct bpf_prog_aux *aux),
+ BPF_LSM_ARGS(aux))
+#endif /* CONFIG_BPF_SYSCALL */
+
+BPF_LSM_HOOK(locked_down,
+ int,
+ BPF_LSM_ARGS(enum lockdown_reason what),
+ BPF_LSM_ARGS(what))
diff --git a/security/bpf/lsm.c b/security/bpf/lsm.c
index fe5c65bbdd45..8586ddfe8cda 100644
--- a/security/bpf/lsm.c
+++ b/security/bpf/lsm.c
@@ -5,14 +5,146 @@
*/
#include <linux/lsm_hooks.h>
+#include <linux/bpf_lsm.h>
-static int process_execution(struct linux_binprm *bprm)
+#include "bpf_lsm.h"
+
+/*
+ * Run the eBPF programs of the hook indexed by the type t with the arguments
+ * packed into an array of u64 integers as the context.
+ */
+static inline int __run_progs(enum lsm_hook_type t, u64 *args)
{
- return 0;
+ struct bpf_lsm_hook *h = &bpf_lsm_hooks_list[t];
+ struct bpf_prog_array_item *item;
+ struct bpf_prog_array *array;
+ int ret, retval = 0;
+
+ /*
+ * Some hooks might get called before the securityFS is initialized,
+ * this will result in a NULL pointer exception.
+ */
+ if (!bpf_lsm_fs_initialized)
+ return 0;
+
+ preempt_disable();
+ rcu_read_lock();
+
+ array = rcu_dereference(h->progs);
+ if (!array)
+ goto out;
+
+ for (item = array->items; item->prog; item++) {
+ ret = BPF_PROG_RUN(item->prog, args);
+ if (ret < 0) {
+ retval = ret;
+ break;
+ }
+ }
+out:
+ rcu_read_unlock();
+ preempt_enable();
+ return IS_ENABLED(CONFIG_SECURITY_BPF_ENFORCE) ? retval : 0;
+}
+
+/*
+ * This macro creates a bpf_lsm_run_progs_<x> function which accepts a known
+ * number of arguments and packs them into an array of u64 integers. The array
+ * is used as a context to run the BPF programs attached to the hook.
+ */
+#define DEFINE_LSM_RUN_PROGS_x(x) \
+ static int bpf_lsm_run_progs##x(enum lsm_hook_type t, \
+ REPEAT(x, SARG, __DL_COM, __SEQ_0_11)) \
+ { \
+ u64 args[x]; \
+ REPEAT(x, COPY, __DL_SEM, __SEQ_0_11); \
+ return __run_progs(t, args); \
+ }
+
+/*
+ * There are some hooks that have no arguments, so there's nothing to pack and
+ * the attached BPF programs get a NULL context.
+ */
+int bpf_lsm_run_progs0(enum lsm_hook_type t, u64 args)
+{
+ return __run_progs(t, NULL);
+}
+
+/*
+ * The largest number of args accepted by an LSM hook is currently 6. Define
+ * bpf_lsm_run_progs_1 to bpf_lsm_run_progs_6.
+ */
+DEFINE_LSM_RUN_PROGS_x(1);
+DEFINE_LSM_RUN_PROGS_x(2);
+DEFINE_LSM_RUN_PROGS_x(3);
+DEFINE_LSM_RUN_PROGS_x(4);
+DEFINE_LSM_RUN_PROGS_x(5);
+DEFINE_LSM_RUN_PROGS_x(6);
+
+/*
+ * This macro calls one of the bpf_lsm_args_<x> functions based on the number of
+ * arguments of the variadic macro. Each argument is casted to a u64 bit integer
+ * as expected by BTF.
+ */
+#define LSM_RUN_PROGS(T, args...) \
+ CONCATENATE(bpf_lsm_run_progs, COUNT_ARGS(args))(T, CAST_TO_U64(args))
+
+/*
+ * The hooks can have an int or void return type, these macros allow having a
+ * single implementation of DEFINE_LSM_HOOK irrespective of the return type.
+ */
+#define LSM_HOOK_RET(ret, x) LSM_HOOK_RET_##ret(x)
+#define LSM_HOOK_RET_int(x) x
+#define LSM_HOOK_RET_void(x)
+
+/*
+ * This macro defines the body of a LSM hook which runs the eBPF programs that
+ * are attached to the hook and returns the error code from the eBPF programs if
+ * the return type of the hook is int.
+ */
+#define DEFINE_LSM_HOOK(hook, ret, proto, args) \
+typedef ret (*lsm_btf_##hook)(proto); \
+static ret bpf_lsm_##hook(proto) \
+{ \
+ return LSM_HOOK_RET(ret, LSM_RUN_PROGS(hook##_type, args)); \
}
+/*
+ * Define the body of each of the LSM hooks defined in hooks.h.
+ */
+#define BPF_LSM_HOOK(hook, ret, args, proto) \
+ DEFINE_LSM_HOOK(hook, ret, BPF_LSM_ARGS(args), BPF_LSM_ARGS(proto))
+#include "hooks.h"
+#undef BPF_LSM_HOOK
+#undef DEFINE_LSM_HOOK
+
+/*
+ * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
+ * The list contains information for each of the hook and can be indexed by the
+ * its type to initialize security FS, attach, detach and execute eBPF programs
+ * for the hook.
+ */
+struct bpf_lsm_hook bpf_lsm_hooks_list[] = {
+ #define BPF_LSM_HOOK(h, ...) \
+ [h##_type] = { \
+ .h_type = h##_type, \
+ .mutex = __MUTEX_INITIALIZER( \
+ bpf_lsm_hooks_list[h##_type].mutex), \
+ .name = #h, \
+ .btf_hook_func = \
+ (void *)(lsm_btf_##h)(bpf_lsm_##h), \
+ },
+ #include "hooks.h"
+ #undef BPF_LSM_HOOK
+};
+
+/*
+ * Initialize the bpf_lsm_hooks_list for each of the hooks defined in hooks.h.
+ */
static struct security_hook_list lsm_hooks[] __lsm_ro_after_init = {
- LSM_HOOK_INIT(bprm_check_security, process_execution),
+ #define BPF_LSM_HOOK(h, ...) LSM_HOOK_INIT(h, bpf_lsm_##h),
+ #include "hooks.h"
+ #undef BPF_LSM_HOOK
};
static int __init lsm_init(void)
diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c
new file mode 100644
index 000000000000..49165394ef7d
--- /dev/null
+++ b/security/bpf/lsm_fs.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/security.h>
+#include <linux/bpf_lsm.h>
+
+#include "fs.h"
+#include "bpf_lsm.h"
+
+static struct dentry *bpf_lsm_dir;
+
+static const struct file_operations hook_ops = {};
+
+int bpf_lsm_fs_initialized;
+
+bool is_bpf_lsm_hook_file(struct file *f)
+{
+ return f->f_op == &hook_ops;
+}
+
+static void __init free_hook(struct bpf_lsm_hook *h)
+{
+ securityfs_remove(h->h_dentry);
+ h->h_dentry = NULL;
+}
+
+static int __init init_hook(struct bpf_lsm_hook *h, struct dentry *parent)
+{
+ struct dentry *h_dentry;
+
+ h_dentry = securityfs_create_file(h->name, 0600, parent,
+ NULL, &hook_ops);
+ if (IS_ERR(h_dentry))
+ return PTR_ERR(h_dentry);
+
+ h_dentry->d_fsdata = h;
+ h->h_dentry = h_dentry;
+ return 0;
+}
+
+static int __init bpf_lsm_fs_init(void)
+{
+ struct bpf_lsm_hook *hook;
+ int ret;
+
+ bpf_lsm_dir = securityfs_create_dir(BPF_LSM_SFS_NAME, NULL);
+ if (IS_ERR(bpf_lsm_dir)) {
+ ret = PTR_ERR(bpf_lsm_dir);
+ pr_err("BPF LSM: Unable to create sysfs dir: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * If there is an error in initializing a hook, the initialization
+ * logic makes sure that it has been freed, but this means that
+ * cleanup should be called for all the other hooks. The cleanup
+ * logic handles uninitialized data.
+ */
+ lsm_for_each_hook(hook) {
+ ret = init_hook(hook, bpf_lsm_dir);
+ if (ret < 0)
+ goto error;
+ }
+
+ bpf_lsm_fs_initialized = 1;
+ return 0;
+error:
+ lsm_for_each_hook(hook)
+ free_hook(hook);
+ securityfs_remove(bpf_lsm_dir);
+ return ret;
+}
+
+late_initcall(bpf_lsm_fs_init);
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 07/13] bpf: lsm: Implement attach, detach and execution.
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
A user space program can attach an eBPF program by:
hook_fd = open("/sys/kernel/security/bpf/bprm_check_security",
O_RDWR|O_CLOEXEC)
prog_fd = bpf(BPF_PROG_LOAD, ...)
bpf(BPF_PROG_ATTACH, hook_fd, prog_fd)
The following permissions are required to attach a program to a hook:
- CAP_SYS_ADMIN to load eBPF programs
- CAP_MAC_ADMIN (to update the policy of an LSM)
- The securityfs file being a valid hook and writable (O_RDWR)
When such an attach call is received, the attachment logic looks up the
dentry and appends the program to the bpf_prog_array.
The BPF programs are stored in a bpf_prog_array and writes to the array
are guarded by a mutex. The eBPF programs are executed as a part of the
LSM hook they are attached to. If any of the eBPF programs return
an error (-ENOPERM) the action represented by the hook is denied.
Signed-off-by: KP Singh <kpsingh@google.com>
---
MAINTAINERS | 1 +
include/linux/bpf_lsm.h | 13 ++++
kernel/bpf/syscall.c | 5 +-
security/bpf/lsm_fs.c | 19 +++++-
security/bpf/ops.c | 134 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 169 insertions(+), 3 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3b82d8ff21fb..681ae39bb2f0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3181,6 +3181,7 @@ L: linux-security-module@vger.kernel.org
L: bpf@vger.kernel.org
S: Maintained
F: security/bpf/
+F: include/linux/bpf_lsm.h
BROADCOM B44 10/100 ETHERNET DRIVER
M: Michael Chan <michael.chan@broadcom.com>
diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 76f81e642dc2..c029f2b8d6fd 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -7,6 +7,19 @@
#ifdef CONFIG_SECURITY_BPF
extern int bpf_lsm_fs_initialized;
+int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog);
+int bpf_lsm_detach(const union bpf_attr *attr);
+#else
+static inline int bpf_lsm_attach(const union bpf_attr *attr,
+ struct bpf_prog *prog)
+{
+ return -EINVAL;
+}
+
+static inline int bpf_lsm_detach(const union bpf_attr *attr)
+{
+ return -EINVAL;
+}
#endif /* CONFIG_SECURITY_BPF */
#endif /* _LINUX_BPF_LSM_H */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 4fcaf6042c07..8897b774973f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -4,6 +4,7 @@
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/bpf_lirc.h>
+#include <linux/bpf_lsm.h>
#include <linux/btf.h>
#include <linux/syscalls.h>
#include <linux/slab.h>
@@ -2132,7 +2133,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
ret = lirc_prog_attach(attr, prog);
break;
case BPF_PROG_TYPE_LSM:
- ret = -EINVAL;
+ ret = bpf_lsm_attach(attr, prog);
break;
case BPF_PROG_TYPE_FLOW_DISSECTOR:
ret = skb_flow_dissector_bpf_prog_attach(attr, prog);
@@ -2200,6 +2201,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
case BPF_CGROUP_SETSOCKOPT:
ptype = BPF_PROG_TYPE_CGROUP_SOCKOPT;
break;
+ case BPF_LSM_MAC:
+ return bpf_lsm_detach(attr);
default:
return -EINVAL;
}
diff --git a/security/bpf/lsm_fs.c b/security/bpf/lsm_fs.c
index 49165394ef7d..b271e9582d0f 100644
--- a/security/bpf/lsm_fs.c
+++ b/security/bpf/lsm_fs.c
@@ -9,6 +9,8 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/types.h>
+#include <linux/filter.h>
+#include <linux/bpf.h>
#include <linux/security.h>
#include <linux/bpf_lsm.h>
@@ -28,6 +30,19 @@ bool is_bpf_lsm_hook_file(struct file *f)
static void __init free_hook(struct bpf_lsm_hook *h)
{
+ struct bpf_prog_array_item *item;
+ /*
+ * This function is __init so we are guaranteed that there will be
+ * no concurrent access.
+ */
+ struct bpf_prog_array *progs = rcu_dereference_raw(h->progs);
+
+ if (progs) {
+ for (item = progs->items; item->prog; item++)
+ bpf_prog_put(item->prog);
+ bpf_prog_array_free(progs);
+ }
+
securityfs_remove(h->h_dentry);
h->h_dentry = NULL;
}
@@ -36,8 +51,8 @@ static int __init init_hook(struct bpf_lsm_hook *h, struct dentry *parent)
{
struct dentry *h_dentry;
- h_dentry = securityfs_create_file(h->name, 0600, parent,
- NULL, &hook_ops);
+ h_dentry = securityfs_create_file(h->name, 0600,
+ parent, NULL, &hook_ops);
if (IS_ERR(h_dentry))
return PTR_ERR(h_dentry);
diff --git a/security/bpf/ops.c b/security/bpf/ops.c
index 2fa3ebdf598d..eb8a8db28109 100644
--- a/security/bpf/ops.c
+++ b/security/bpf/ops.c
@@ -4,11 +4,145 @@
* Copyright 2019 Google LLC.
*/
+#include <linux/err.h>
+#include <linux/types.h>
#include <linux/filter.h>
#include <linux/bpf.h>
+#include <linux/security.h>
+#include <linux/bpf_lsm.h>
+
+#include "bpf_lsm.h"
+#include "fs.h"
+
+static struct bpf_lsm_hook *get_hook_from_fd(int fd)
+{
+ struct bpf_lsm_hook *h;
+ struct fd f;
+ int ret;
+
+ /*
+ * Only CAP_MAC_ADMIN users are allowed to make changes to LSM hooks
+ */
+ if (!capable(CAP_MAC_ADMIN))
+ return ERR_PTR(-EPERM);
+
+
+ f = fdget(fd);
+ if (!f.file)
+ return ERR_PTR(-EBADF);
+
+
+ if (!is_bpf_lsm_hook_file(f.file)) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /*
+ * It's wrong to attach the program to the hook if the file is not
+ * opened for a writing. Note that, this is an EBADF and not an EPERM
+ * because the file has been opened with an incorrect mode.
+ */
+ if (!(f.file->f_mode & FMODE_WRITE)) {
+ ret = -EBADF;
+ goto error;
+ }
+
+ /*
+ * The securityfs dentry never disappears, so we don't need to take a
+ * reference to it.
+ */
+ h = file_dentry(f.file)->d_fsdata;
+ if (WARN_ON(!h)) {
+ ret = -EINVAL;
+ goto error;
+ }
+ fdput(f);
+ return h;
+
+error:
+ fdput(f);
+ return ERR_PTR(ret);
+}
+
+int bpf_lsm_attach(const union bpf_attr *attr, struct bpf_prog *prog)
+{
+ struct bpf_prog_array *old_array;
+ struct bpf_prog_array *new_array;
+ struct bpf_lsm_hook *h;
+ int ret = 0;
+
+ h = get_hook_from_fd(attr->target_fd);
+ if (IS_ERR(h))
+ return PTR_ERR(h);
+
+ mutex_lock(&h->mutex);
+ old_array = rcu_dereference_protected(h->progs,
+ lockdep_is_held(&h->mutex));
+
+ ret = bpf_prog_array_copy(old_array, NULL, prog, &new_array);
+ if (ret < 0)
+ goto unlock;
+
+ rcu_assign_pointer(h->progs, new_array);
+ bpf_prog_array_free(old_array);
+
+unlock:
+ mutex_unlock(&h->mutex);
+ return ret;
+}
+
+int bpf_lsm_detach(const union bpf_attr *attr)
+{
+ struct bpf_prog_array *old_array, *new_array;
+ struct bpf_prog *prog;
+ struct bpf_lsm_hook *h;
+ int ret = 0;
+
+ if (attr->attach_flags)
+ return -EINVAL;
+
+ h = get_hook_from_fd(attr->target_fd);
+ if (IS_ERR(h))
+ return PTR_ERR(h);
+
+ prog = bpf_prog_get_type(attr->attach_bpf_fd,
+ BPF_PROG_TYPE_LSM);
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+
+ mutex_lock(&h->mutex);
+ old_array = rcu_dereference_protected(h->progs,
+ lockdep_is_held(&h->mutex));
+
+ ret = bpf_prog_array_copy(old_array, prog, NULL, &new_array);
+ if (ret)
+ goto unlock;
+
+ rcu_assign_pointer(h->progs, new_array);
+ bpf_prog_array_free(old_array);
+unlock:
+ bpf_prog_put(prog);
+ mutex_unlock(&h->mutex);
+ return ret;
+}
const struct bpf_prog_ops lsm_prog_ops = {
};
+static const struct bpf_func_proto *get_bpf_func_proto(enum bpf_func_id
+ func_id, const struct bpf_prog *prog)
+{
+ switch (func_id) {
+ case BPF_FUNC_map_lookup_elem:
+ return &bpf_map_lookup_elem_proto;
+ case BPF_FUNC_get_current_pid_tgid:
+ return &bpf_get_current_pid_tgid_proto;
+ default:
+ return NULL;
+ }
+}
+
const struct bpf_verifier_ops lsm_verifier_ops = {
+ .get_func_proto = get_bpf_func_proto,
+ .is_valid_access = btf_ctx_access,
};
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 05/13] tools/libbpf: Add support in libbpf for BPF_PROG_TYPE_LSM
From: KP Singh @ 2019-12-20 15:42 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
Update the libbpf library with functionality to load and
attach a program type BPF_PROG_TYPE_LSM, currently with
only one expected attach type BPF_LSM_MAC.
Signed-off-by: KP Singh <kpsingh@google.com>
---
tools/lib/bpf/bpf.c | 2 +-
tools/lib/bpf/bpf.h | 6 +++++
tools/lib/bpf/libbpf.c | 44 +++++++++++++++++++++--------------
tools/lib/bpf/libbpf.h | 2 ++
tools/lib/bpf/libbpf.map | 6 +++++
tools/lib/bpf/libbpf_probes.c | 1 +
6 files changed, 43 insertions(+), 18 deletions(-)
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 98596e15390f..9c6fb083f7de 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -228,7 +228,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
memset(&attr, 0, sizeof(attr));
attr.prog_type = load_attr->prog_type;
attr.expected_attach_type = load_attr->expected_attach_type;
- if (attr.prog_type == BPF_PROG_TYPE_TRACING) {
+ if (needs_btf_attach(attr.prog_type)) {
attr.attach_btf_id = load_attr->attach_btf_id;
attr.attach_prog_fd = load_attr->attach_prog_fd;
} else {
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 3c791fa8e68e..df2a00ff349f 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -177,6 +177,12 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf,
__u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
__u64 *probe_offset, __u64 *probe_addr);
+static inline bool needs_btf_attach(enum bpf_prog_type prog_type)
+{
+ return (prog_type == BPF_PROG_TYPE_TRACING ||
+ prog_type == BPF_PROG_TYPE_LSM);
+}
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b20f82e58989..b0b27d8e5a37 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3738,7 +3738,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
load_attr.insns = insns;
load_attr.insns_cnt = insns_cnt;
load_attr.license = license;
- if (prog->type == BPF_PROG_TYPE_TRACING) {
+ if (needs_btf_attach(prog->type)) {
load_attr.attach_prog_fd = prog->attach_prog_fd;
load_attr.attach_btf_id = prog->attach_btf_id;
} else {
@@ -3983,7 +3983,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz,
bpf_program__set_type(prog, prog_type);
bpf_program__set_expected_attach_type(prog, attach_type);
- if (prog_type == BPF_PROG_TYPE_TRACING) {
+ if (needs_btf_attach(prog_type)) {
err = libbpf_find_attach_btf_id(prog->section_name,
attach_type,
attach_prog_fd);
@@ -4933,6 +4933,7 @@ bool bpf_program__is_##NAME(const struct bpf_program *prog) \
} \
BPF_PROG_TYPE_FNS(socket_filter, BPF_PROG_TYPE_SOCKET_FILTER);
+BPF_PROG_TYPE_FNS(lsm, BPF_PROG_TYPE_LSM);
BPF_PROG_TYPE_FNS(kprobe, BPF_PROG_TYPE_KPROBE);
BPF_PROG_TYPE_FNS(sched_cls, BPF_PROG_TYPE_SCHED_CLS);
BPF_PROG_TYPE_FNS(sched_act, BPF_PROG_TYPE_SCHED_ACT);
@@ -5009,6 +5010,8 @@ static const struct {
BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
+ BPF_PROG_BTF("lsm/", BPF_PROG_TYPE_LSM,
+ BPF_LSM_MAC),
BPF_APROG_SEC("cgroup_skb/ingress", BPF_PROG_TYPE_CGROUP_SKB,
BPF_CGROUP_INET_INGRESS),
BPF_APROG_SEC("cgroup_skb/egress", BPF_PROG_TYPE_CGROUP_SKB,
@@ -5119,32 +5122,39 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
return -ESRCH;
}
-#define BTF_PREFIX "btf_trace_"
+static inline int __btf__typdef_with_prefix(struct btf *btf, const char *name,
+ const char *prefix)
+{
+
+ size_t prefix_len = strlen(prefix);
+ char btf_type_name[128];
+
+ strcpy(btf_type_name, prefix);
+ strncat(btf_type_name, name, sizeof(btf_type_name) - (prefix_len + 1));
+ return btf__find_by_name_kind(btf, btf_type_name, BTF_KIND_TYPEDEF);
+}
+
+#define BTF_TRACE_PREFIX "btf_trace_"
+#define BTF_LSM_PREFIX "lsm_btf_"
+
int libbpf_find_vmlinux_btf_id(const char *name,
enum bpf_attach_type attach_type)
{
struct btf *btf = bpf_core_find_kernel_btf();
- char raw_tp_btf[128] = BTF_PREFIX;
- char *dst = raw_tp_btf + sizeof(BTF_PREFIX) - 1;
- const char *btf_name;
int err = -EINVAL;
- __u32 kind;
if (IS_ERR(btf)) {
pr_warn("vmlinux BTF is not found\n");
return -EINVAL;
}
- if (attach_type == BPF_TRACE_RAW_TP) {
- /* prepend "btf_trace_" prefix per kernel convention */
- strncat(dst, name, sizeof(raw_tp_btf) - sizeof(BTF_PREFIX));
- btf_name = raw_tp_btf;
- kind = BTF_KIND_TYPEDEF;
- } else {
- btf_name = name;
- kind = BTF_KIND_FUNC;
- }
- err = btf__find_by_name_kind(btf, btf_name, kind);
+ if (attach_type == BPF_TRACE_RAW_TP)
+ err = __btf__typdef_with_prefix(btf, name, BTF_TRACE_PREFIX);
+ else if (attach_type == BPF_LSM_MAC)
+ err = __btf__typdef_with_prefix(btf, name, BTF_LSM_PREFIX);
+ else
+ err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
+
btf__free(btf);
return err;
}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 0dbf4bfba0c4..9cd69d602c82 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -332,6 +332,7 @@ LIBBPF_API int bpf_program__set_sched_act(struct bpf_program *prog);
LIBBPF_API int bpf_program__set_xdp(struct bpf_program *prog);
LIBBPF_API int bpf_program__set_perf_event(struct bpf_program *prog);
LIBBPF_API int bpf_program__set_tracing(struct bpf_program *prog);
+LIBBPF_API int bpf_program__set_lsm(struct bpf_program *prog);
LIBBPF_API enum bpf_prog_type bpf_program__get_type(struct bpf_program *prog);
LIBBPF_API void bpf_program__set_type(struct bpf_program *prog,
@@ -352,6 +353,7 @@ LIBBPF_API bool bpf_program__is_sched_act(const struct bpf_program *prog);
LIBBPF_API bool bpf_program__is_xdp(const struct bpf_program *prog);
LIBBPF_API bool bpf_program__is_perf_event(const struct bpf_program *prog);
LIBBPF_API bool bpf_program__is_tracing(const struct bpf_program *prog);
+LIBBPF_API bool bpf_program__is_lsm(const struct bpf_program *prog);
/*
* No need for __attribute__((packed)), all members of 'bpf_map_def'
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 8ddc2c40e482..3d396149755d 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -208,3 +208,9 @@ LIBBPF_0.0.6 {
btf__find_by_name_kind;
libbpf_find_vmlinux_btf_id;
} LIBBPF_0.0.5;
+
+LIBBPF_0.0.7 {
+ global:
+ bpf_program__is_lsm;
+ bpf_program__set_lsm;
+} LIBBPF_0.0.6;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index a9eb8b322671..203b4ecf7a0b 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -103,6 +103,7 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
case BPF_PROG_TYPE_CGROUP_SYSCTL:
case BPF_PROG_TYPE_CGROUP_SOCKOPT:
case BPF_PROG_TYPE_TRACING:
+ case BPF_PROG_TYPE_LSM:
default:
break;
}
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 03/13] bpf: lsm: Introduce types for eBPF based LSM
From: KP Singh @ 2019-12-20 15:41 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
A new eBPF program type BPF_PROG_TYPE_LSM with an
expected attach type of BPF_LSM_MAC. An -EINVAL error is returned if an
attachment is currently requested.
Signed-off-by: KP Singh <kpsingh@google.com>
---
include/linux/bpf_types.h | 4 ++++
include/uapi/linux/bpf.h | 2 ++
kernel/bpf/syscall.c | 6 ++++++
security/bpf/Makefile | 2 +-
security/bpf/ops.c | 14 ++++++++++++++
tools/include/uapi/linux/bpf.h | 2 ++
6 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 security/bpf/ops.c
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index 93740b3614d7..5f48161529b4 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -65,6 +65,10 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LIRC_MODE2, lirc_mode2,
BPF_PROG_TYPE(BPF_PROG_TYPE_SK_REUSEPORT, sk_reuseport,
struct sk_reuseport_md, struct sk_reuseport_kern)
#endif
+#ifdef CONFIG_SECURITY_BPF
+BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm,
+ void *, void *)
+#endif
BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index dbbcf0b02970..fc64ae865526 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -174,6 +174,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
BPF_PROG_TYPE_CGROUP_SOCKOPT,
BPF_PROG_TYPE_TRACING,
+ BPF_PROG_TYPE_LSM,
};
enum bpf_attach_type {
@@ -203,6 +204,7 @@ enum bpf_attach_type {
BPF_TRACE_RAW_TP,
BPF_TRACE_FENTRY,
BPF_TRACE_FEXIT,
+ BPF_LSM_MAC,
__MAX_BPF_ATTACH_TYPE
};
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index e3461ec59570..5a773fc6f9f5 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2096,6 +2096,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
case BPF_LIRC_MODE2:
ptype = BPF_PROG_TYPE_LIRC_MODE2;
break;
+ case BPF_LSM_MAC:
+ ptype = BPF_PROG_TYPE_LSM;
+ break;
case BPF_FLOW_DISSECTOR:
ptype = BPF_PROG_TYPE_FLOW_DISSECTOR;
break;
@@ -2127,6 +2130,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
case BPF_PROG_TYPE_LIRC_MODE2:
ret = lirc_prog_attach(attr, prog);
break;
+ case BPF_PROG_TYPE_LSM:
+ ret = -EINVAL;
+ break;
case BPF_PROG_TYPE_FLOW_DISSECTOR:
ret = skb_flow_dissector_bpf_prog_attach(attr, prog);
break;
diff --git a/security/bpf/Makefile b/security/bpf/Makefile
index 26a0ab6f99b7..c78a8a056e7e 100644
--- a/security/bpf/Makefile
+++ b/security/bpf/Makefile
@@ -2,4 +2,4 @@
#
# Copyright 2019 Google LLC.
-obj-$(CONFIG_SECURITY_BPF) := lsm.o
+obj-$(CONFIG_SECURITY_BPF) := lsm.o ops.o
diff --git a/security/bpf/ops.c b/security/bpf/ops.c
new file mode 100644
index 000000000000..2fa3ebdf598d
--- /dev/null
+++ b/security/bpf/ops.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright 2019 Google LLC.
+ */
+
+#include <linux/filter.h>
+#include <linux/bpf.h>
+
+const struct bpf_prog_ops lsm_prog_ops = {
+};
+
+const struct bpf_verifier_ops lsm_verifier_ops = {
+};
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index dbbcf0b02970..fc64ae865526 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -174,6 +174,7 @@ enum bpf_prog_type {
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
BPF_PROG_TYPE_CGROUP_SOCKOPT,
BPF_PROG_TYPE_TRACING,
+ BPF_PROG_TYPE_LSM,
};
enum bpf_attach_type {
@@ -203,6 +204,7 @@ enum bpf_attach_type {
BPF_TRACE_RAW_TP,
BPF_TRACE_FENTRY,
BPF_TRACE_FEXIT,
+ BPF_LSM_MAC,
__MAX_BPF_ATTACH_TYPE
};
--
2.20.1
^ permalink raw reply related
* [PATCH bpf-next v1 04/13] bpf: lsm: Allow btf_id based attachment for LSM hooks
From: KP Singh @ 2019-12-20 15:41 UTC (permalink / raw)
To: linux-kernel, bpf, linux-security-module
Cc: Alexei Starovoitov, Daniel Borkmann, James Morris, Kees Cook,
Thomas Garnier, Michael Halcrow, Paul Turner, Brendan Gregg,
Jann Horn, Matthew Garrett, Christian Brauner,
Mickaël Salaün, 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
In-Reply-To: <20191220154208.15895-1-kpsingh@chromium.org>
From: KP Singh <kpsingh@google.com>
Refactor and re-use most of the logic for BPF_PROG_TYPE_TRACING with a few
changes.
- The LSM hook BTF types are prefixed with "lsm_btf_"
- These types do not need the first (void *) pointer argument. The verifier
only looks for this argument if prod->aux->attach_btf_trace is set.
Signed-off-by: KP Singh <kpsingh@google.com>
---
kernel/bpf/syscall.c | 1 +
kernel/bpf/verifier.c | 83 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 80 insertions(+), 4 deletions(-)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 5a773fc6f9f5..4fcaf6042c07 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1642,6 +1642,7 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
{
switch (prog_type) {
case BPF_PROG_TYPE_TRACING:
+ case BPF_PROG_TYPE_LSM:
if (btf_id > BTF_MAX_TYPE)
return -EINVAL;
break;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a0482e1c4a77..0d1231d9c1ef 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9504,7 +9504,71 @@ static void print_verification_stats(struct bpf_verifier_env *env)
env->peak_states, env->longest_mark_read_walk);
}
-static int check_attach_btf_id(struct bpf_verifier_env *env)
+/*
+ * LSM hooks have a typedef associated with them. The BTF information for this
+ * type is used by the verifier to validate memory accesses made by the
+ * attached information.
+ *
+ * For example the:
+ *
+ * int bprm_check_security(struct linux_binprm *brpm)
+ *
+ * has the following typedef:
+ *
+ * typedef int (*lsm_btf_bprm_check_security)(struct linux_binprm *bprm);
+ */
+#define BTF_LSM_PREFIX "lsm_btf_"
+
+static inline int check_attach_btf_id_lsm(struct bpf_verifier_env *env)
+{
+ struct bpf_prog *prog = env->prog;
+ u32 btf_id = prog->aux->attach_btf_id;
+ const struct btf_type *t;
+ const char *tname;
+
+ if (!btf_id) {
+ verbose(env, "LSM programs must provide btf_id\n");
+ return -EINVAL;
+ }
+
+ t = btf_type_by_id(btf_vmlinux, btf_id);
+ if (!t) {
+ verbose(env, "attach_btf_id %u is invalid\n", btf_id);
+ return -EINVAL;
+ }
+
+ tname = btf_name_by_offset(btf_vmlinux, t->name_off);
+ if (!tname) {
+ verbose(env, "attach_btf_id %u doesn't have a name\n", btf_id);
+ return -EINVAL;
+ }
+
+ if (!btf_type_is_typedef(t)) {
+ verbose(env, "attach_btf_id %u is not a typedef\n", btf_id);
+ return -EINVAL;
+ }
+ if (strncmp(BTF_LSM_PREFIX, tname, sizeof(BTF_LSM_PREFIX) - 1)) {
+ verbose(env, "attach_btf_id %u points to wrong type name %s\n",
+ btf_id, tname);
+ return -EINVAL;
+ }
+
+ t = btf_type_by_id(btf_vmlinux, t->type);
+ /* should never happen in valid vmlinux build */
+ if (!btf_type_is_ptr(t))
+ return -EINVAL;
+ t = btf_type_by_id(btf_vmlinux, t->type);
+ /* should never happen in valid vmlinux build */
+ if (!btf_type_is_func_proto(t))
+ return -EINVAL;
+
+ tname += sizeof(BTF_LSM_PREFIX) - 1;
+ prog->aux->attach_func_name = tname;
+ prog->aux->attach_func_proto = t;
+ return 0;
+}
+
+static int check_attach_btf_id_tracing(struct bpf_verifier_env *env)
{
struct bpf_prog *prog = env->prog;
struct bpf_prog *tgt_prog = prog->aux->linked_prog;
@@ -9519,9 +9583,6 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
long addr;
u64 key;
- if (prog->type != BPF_PROG_TYPE_TRACING)
- return 0;
-
if (!btf_id) {
verbose(env, "Tracing programs must provide btf_id\n");
return -EINVAL;
@@ -9659,6 +9720,20 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
}
}
+static int check_attach_btf_id(struct bpf_verifier_env *env)
+{
+ struct bpf_prog *prog = env->prog;
+
+ switch (prog->type) {
+ case BPF_PROG_TYPE_TRACING:
+ return check_attach_btf_id_tracing(env);
+ case BPF_PROG_TYPE_LSM:
+ return check_attach_btf_id_lsm(env);
+ default:
+ return 0;
+ }
+}
+
int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
union bpf_attr __user *uattr)
{
--
2.20.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox