[v17,20/23] Audit: Add a new record for multiple subject LSM attributes
diff mbox series

Message ID 20200514221142.11857-21-casey@schaufler-ca.com
State Superseded
Headers show
Series
  • LSM: Module stacking for AppArmor
Related show

Commit Message

Casey Schaufler May 14, 2020, 10:11 p.m. UTC
Create a new audit record type to contain the subject information
when there are multiple security modules that require such data.
This record is emitted before the other records for the event, but
is linked with the same timestamp and serial number.

Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Cc: linux-audit@redhat.com
---
 drivers/android/binder.c                |  2 +-
 include/linux/security.h                |  9 +++-
 include/net/scm.h                       |  3 +-
 include/uapi/linux/audit.h              |  1 +
 kernel/audit.c                          | 56 +++++++++++++++++++------
 kernel/auditsc.c                        |  7 ++--
 net/ipv4/ip_sockglue.c                  |  2 +-
 net/netfilter/nf_conntrack_netlink.c    |  4 +-
 net/netfilter/nf_conntrack_standalone.c |  2 +-
 net/netfilter/nfnetlink_queue.c         |  2 +-
 net/netlabel/netlabel_unlabeled.c       | 11 +++--
 net/netlabel/netlabel_user.c            |  2 +-
 security/security.c                     | 51 ++++++++++++++++++++--
 13 files changed, 118 insertions(+), 34 deletions(-)

Comments

Stephen Smalley May 18, 2020, 6:02 p.m. UTC | #1
On Thu, May 14, 2020 at 7:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>
> Create a new audit record type to contain the subject information
> when there are multiple security modules that require such data.
> This record is emitted before the other records for the event, but
> is linked with the same timestamp and serial number.
>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> Cc: linux-audit@redhat.com
> ---

With this patch, I see userspace audit records like this one:

type=SYSTEM_BOOT msg=audit(1589816792.181:103): pid=789 uid=0
auid=4294967295 ses=4294967295 subj=? subj=system_u:system_r:init_t:s0
msg=' comm="systemd-update-utmp"
exe="/usr/lib/systemd/systemd-update-utmp" hostname=? addr=?
terminal=? res=success'

I'm guessing that userspace is appending the second subj= field when
it sees subj=? or otherwise is missing subj= information?

Then we have kernel audit records like this:

type=PROCTITLE msg=audit(1589816791.959:101): proctitle=2F7362696E2F617564697463
746C002D52002F6574632F61756469742F61756469742E72756C6573
type=SYSCALL msg=audit(1589816791.959:101): arch=c000003e syscall=44
success=yes exit=1056 a0=3 a1=7fff9ccc98a0 a2=420 a3=0 items=0
ppid=773 pid=783 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl"
exe="/usr/sbin/auditctl" subj=? key=(null)
type=UNKNOWN[1420] msg=audit(1589816791.959:101):
subj_selinux=system_u:system_r:unconfined_service_t:s0
subj_apparmor==unconfined
type=CONFIG_CHANGE msg=audit(1589816791.959:101): auid=4294967295
ses=4294967295 subj=? op=add_rule key=(null) list=1 res=1
type=UNKNOWN[1420] msg=audit(1589816791.959:101):
subj_selinux=system_u:system_r:unconfined_service_t:s0
subj_apparmor==unconfined

where we are getting multiple copies of the new record type, one for
each record type that had subj=?.

Not sure what it is the audit folks want here.

This is with multiple LSMs enabled; need to confirm that no change
occurs if only one is enabled.
Casey Schaufler May 18, 2020, 8:42 p.m. UTC | #2
On 5/18/2020 11:02 AM, Stephen Smalley wrote:
> On Thu, May 14, 2020 at 7:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>> Create a new audit record type to contain the subject information
>> when there are multiple security modules that require such data.
>> This record is emitted before the other records for the event, but
>> is linked with the same timestamp and serial number.
>>
>> Reviewed-by: Kees Cook <keescook@chromium.org>
>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>> Cc: linux-audit@redhat.com
>> ---
> With this patch, I see userspace audit records like this one:
>
> type=SYSTEM_BOOT msg=audit(1589816792.181:103): pid=789 uid=0
> auid=4294967295 ses=4294967295 subj=? subj=system_u:system_r:init_t:s0
> msg=' comm="systemd-update-utmp"
> exe="/usr/lib/systemd/systemd-update-utmp" hostname=? addr=?
> terminal=? res=success'
>
> I'm guessing that userspace is appending the second subj= field when
> it sees subj=? or otherwise is missing subj= information?

I haven't looked at the userspace code, but I expect you're right.
It looks like there will need to be some change in the userspace
for the multiple LSM case. The "completion" shown here isn't correct,
because it only fills in one of the subject attributes, not both.

> Then we have kernel audit records like this:
>
> type=PROCTITLE msg=audit(1589816791.959:101): proctitle=2F7362696E2F617564697463
> 746C002D52002F6574632F61756469742F61756469742E72756C6573
> type=SYSCALL msg=audit(1589816791.959:101): arch=c000003e syscall=44
> success=yes exit=1056 a0=3 a1=7fff9ccc98a0 a2=420 a3=0 items=0
> ppid=773 pid=783 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
> egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl"
> exe="/usr/sbin/auditctl" subj=? key=(null)
> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
> subj_selinux=system_u:system_r:unconfined_service_t:s0
> subj_apparmor==unconfined
> type=CONFIG_CHANGE msg=audit(1589816791.959:101): auid=4294967295
> ses=4294967295 subj=? op=add_rule key=(null) list=1 res=1
> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
> subj_selinux=system_u:system_r:unconfined_service_t:s0
> subj_apparmor==unconfined
>
> where we are getting multiple copies of the new record type, one for
> each record type that had subj=?.

While obviously wasteful, the type=1420 behavior is consistent with
the subj=? behavior, which is to duplicate the subj= value. I know
we've got enough hobgoblins in the audit system that we don't need
to add any more in the name of a foolish consistency.

> Not sure what it is the audit folks want here.

I doubt that redundant type=1420 records are a good idea, but having
seen some of the other active threads about useless fields I am not
going to assume what is most appropriate.

> This is with multiple LSMs enabled; need to confirm that no change
> occurs if only one is enabled.
Paul Moore May 18, 2020, 10:21 p.m. UTC | #3
On Mon, May 18, 2020 at 4:43 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 5/18/2020 11:02 AM, Stephen Smalley wrote:
> > On Thu, May 14, 2020 at 7:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> Create a new audit record type to contain the subject information
> >> when there are multiple security modules that require such data.
> >> This record is emitted before the other records for the event, but
> >> is linked with the same timestamp and serial number.
> >>
> >> Reviewed-by: Kees Cook <keescook@chromium.org>
> >> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> >> Cc: linux-audit@redhat.com
> >> ---
> > With this patch, I see userspace audit records like this one:
> >
> > type=SYSTEM_BOOT msg=audit(1589816792.181:103): pid=789 uid=0
> > auid=4294967295 ses=4294967295 subj=? subj=system_u:system_r:init_t:s0
> > msg=' comm="systemd-update-utmp"
> > exe="/usr/lib/systemd/systemd-update-utmp" hostname=? addr=?
> > terminal=? res=success'
> >
> > I'm guessing that userspace is appending the second subj= field when
> > it sees subj=? or otherwise is missing subj= information?
>
> I haven't looked at the userspace code, but I expect you're right.
> It looks like there will need to be some change in the userspace
> for the multiple LSM case. The "completion" shown here isn't correct,
> because it only fills in one of the subject attributes, not both.

Wait, didn't we agree on a a "subj=? subj_selinux=XXX
subj_apparmor=YYY subj_smack=ZZZ" format?  It looks like there are two
'subj' fields in the record above which is bad, don't do that please.

> > Then we have kernel audit records like this:
> >
> > type=PROCTITLE msg=audit(1589816791.959:101): proctitle=2F7362696E2F617564697463
> > 746C002D52002F6574632F61756469742F61756469742E72756C6573
> > type=SYSCALL msg=audit(1589816791.959:101): arch=c000003e syscall=44
> > success=yes exit=1056 a0=3 a1=7fff9ccc98a0 a2=420 a3=0 items=0
> > ppid=773 pid=783 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
> > egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl"
> > exe="/usr/sbin/auditctl" subj=? key=(null)
> > type=UNKNOWN[1420] msg=audit(1589816791.959:101):
> > subj_selinux=system_u:system_r:unconfined_service_t:s0
> > subj_apparmor==unconfined
> > type=CONFIG_CHANGE msg=audit(1589816791.959:101): auid=4294967295
> > ses=4294967295 subj=? op=add_rule key=(null) list=1 res=1
> > type=UNKNOWN[1420] msg=audit(1589816791.959:101):
> > subj_selinux=system_u:system_r:unconfined_service_t:s0
> > subj_apparmor==unconfined
> >
> > where we are getting multiple copies of the new record type, one for
> > each record type that had subj=?.
>
> While obviously wasteful, the type=1420 behavior is consistent with
> the subj=? behavior, which is to duplicate the subj= value. I know
> we've got enough hobgoblins in the audit system that we don't need
> to add any more in the name of a foolish consistency.

You need to provide a bit more reason why we need byte-for-byte
duplicate records in a single event.  As it currently stands this
looks like something we definitely don't want.

--
paul moore
www.paul-moore.com
Casey Schaufler May 19, 2020, 12:16 a.m. UTC | #4
On 5/18/2020 3:21 PM, Paul Moore wrote:
> On Mon, May 18, 2020 at 4:43 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 5/18/2020 11:02 AM, Stephen Smalley wrote:
>>> On Thu, May 14, 2020 at 7:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>> Create a new audit record type to contain the subject information
>>>> when there are multiple security modules that require such data.
>>>> This record is emitted before the other records for the event, but
>>>> is linked with the same timestamp and serial number.
>>>>
>>>> Reviewed-by: Kees Cook <keescook@chromium.org>
>>>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>>>> Cc: linux-audit@redhat.com
>>>> ---
>>> With this patch, I see userspace audit records like this one:
>>>
>>> type=SYSTEM_BOOT msg=audit(1589816792.181:103): pid=789 uid=0
>>> auid=4294967295 ses=4294967295 subj=? subj=system_u:system_r:init_t:s0
>>> msg=' comm="systemd-update-utmp"
>>> exe="/usr/lib/systemd/systemd-update-utmp" hostname=? addr=?
>>> terminal=? res=success'
>>>
>>> I'm guessing that userspace is appending the second subj= field when
>>> it sees subj=? or otherwise is missing subj= information?
>> I haven't looked at the userspace code, but I expect you're right.
>> It looks like there will need to be some change in the userspace
>> for the multiple LSM case. The "completion" shown here isn't correct,
>> because it only fills in one of the subject attributes, not both.
> Wait, didn't we agree on a a "subj=? subj_selinux=XXX
> subj_apparmor=YYY subj_smack=ZZZ" format?  It looks like there are two
> 'subj' fields in the record above which is bad, don't do that please.

That's not something that's coming from the kernel.
I'll check again, but I think that everyplace in the kernel that
produces a subj= has been trained to create a type=1420 record
instead.

>
>>> Then we have kernel audit records like this:
>>>
>>> type=PROCTITLE msg=audit(1589816791.959:101): proctitle=2F7362696E2F617564697463
>>> 746C002D52002F6574632F61756469742F61756469742E72756C6573
>>> type=SYSCALL msg=audit(1589816791.959:101): arch=c000003e syscall=44
>>> success=yes exit=1056 a0=3 a1=7fff9ccc98a0 a2=420 a3=0 items=0
>>> ppid=773 pid=783 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
>>> egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl"
>>> exe="/usr/sbin/auditctl" subj=? key=(null)
>>> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
>>> subj_selinux=system_u:system_r:unconfined_service_t:s0
>>> subj_apparmor==unconfined
>>> type=CONFIG_CHANGE msg=audit(1589816791.959:101): auid=4294967295
>>> ses=4294967295 subj=? op=add_rule key=(null) list=1 res=1
>>> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
>>> subj_selinux=system_u:system_r:unconfined_service_t:s0
>>> subj_apparmor==unconfined
>>>
>>> where we are getting multiple copies of the new record type, one for
>>> each record type that had subj=?.
>> While obviously wasteful, the type=1420 behavior is consistent with
>> the subj=? behavior, which is to duplicate the subj= value. I know
>> we've got enough hobgoblins in the audit system that we don't need
>> to add any more in the name of a foolish consistency.
> You need to provide a bit more reason why we need byte-for-byte
> duplicate records in a single event.  As it currently stands this
> looks like something we definitely don't want.

The CONFIG_CHANGE record already duplicates the subj= information
in the SYSCALL record. I just maintained the duplication. You're
right, it's silly to have two identical type=1420 records for the event.
I will have to come up with a mechanism to prevent the duplication.
with luck, there's already a similar case for some other record.

>
> --
> paul moore
> www.paul-moore.com
Casey Schaufler May 19, 2020, 12:58 a.m. UTC | #5
On 5/18/2020 5:16 PM, Casey Schaufler wrote:
> On 5/18/2020 3:21 PM, Paul Moore wrote:
>> On Mon, May 18, 2020 at 4:43 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>> On 5/18/2020 11:02 AM, Stephen Smalley wrote:
>>>> On Thu, May 14, 2020 at 7:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
>>>>> Create a new audit record type to contain the subject information
>>>>> when there are multiple security modules that require such data.
>>>>> This record is emitted before the other records for the event, but
>>>>> is linked with the same timestamp and serial number.
>>>>>
>>>>> Reviewed-by: Kees Cook <keescook@chromium.org>
>>>>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
>>>>> Cc: linux-audit@redhat.com
>>>>> ---
>>>> With this patch, I see userspace audit records like this one:
>>>>
>>>> type=SYSTEM_BOOT msg=audit(1589816792.181:103): pid=789 uid=0
>>>> auid=4294967295 ses=4294967295 subj=? subj=system_u:system_r:init_t:s0
>>>> msg=' comm="systemd-update-utmp"
>>>> exe="/usr/lib/systemd/systemd-update-utmp" hostname=? addr=?
>>>> terminal=? res=success'
>>>>
>>>> I'm guessing that userspace is appending the second subj= field when
>>>> it sees subj=? or otherwise is missing subj= information?
>>> I haven't looked at the userspace code, but I expect you're right.
>>> It looks like there will need to be some change in the userspace
>>> for the multiple LSM case. The "completion" shown here isn't correct,
>>> because it only fills in one of the subject attributes, not both.
>> Wait, didn't we agree on a a "subj=? subj_selinux=XXX
>> subj_apparmor=YYY subj_smack=ZZZ" format?  It looks like there are two
>> 'subj' fields in the record above which is bad, don't do that please.
> That's not something that's coming from the kernel.

OK, I see that I missed one in netlbl_audit_start_common(),
although I don't think that's where this event came from.

> I'll check again, but I think that everyplace in the kernel that
> produces a subj= has been trained to create a type=1420 record
> instead.
>
>>>> Then we have kernel audit records like this:
>>>>
>>>> type=PROCTITLE msg=audit(1589816791.959:101): proctitle=2F7362696E2F617564697463
>>>> 746C002D52002F6574632F61756469742F61756469742E72756C6573
>>>> type=SYSCALL msg=audit(1589816791.959:101): arch=c000003e syscall=44
>>>> success=yes exit=1056 a0=3 a1=7fff9ccc98a0 a2=420 a3=0 items=0
>>>> ppid=773 pid=783 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
>>>> egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl"
>>>> exe="/usr/sbin/auditctl" subj=? key=(null)
>>>> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
>>>> subj_selinux=system_u:system_r:unconfined_service_t:s0
>>>> subj_apparmor==unconfined
>>>> type=CONFIG_CHANGE msg=audit(1589816791.959:101): auid=4294967295
>>>> ses=4294967295 subj=? op=add_rule key=(null) list=1 res=1
>>>> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
>>>> subj_selinux=system_u:system_r:unconfined_service_t:s0
>>>> subj_apparmor==unconfined
>>>>
>>>> where we are getting multiple copies of the new record type, one for
>>>> each record type that had subj=?.
>>> While obviously wasteful, the type=1420 behavior is consistent with
>>> the subj=? behavior, which is to duplicate the subj= value. I know
>>> we've got enough hobgoblins in the audit system that we don't need
>>> to add any more in the name of a foolish consistency.
>> You need to provide a bit more reason why we need byte-for-byte
>> duplicate records in a single event.  As it currently stands this
>> looks like something we definitely don't want.
> The CONFIG_CHANGE record already duplicates the subj= information
> in the SYSCALL record. I just maintained the duplication. You're
> right, it's silly to have two identical type=1420 records for the event.
> I will have to come up with a mechanism to prevent the duplication.
> with luck, there's already a similar case for some other record.
>
>> --
>> paul moore
>> www.paul-moore.com
Paul Moore May 19, 2020, 3:48 p.m. UTC | #6
On Mon, May 18, 2020 at 8:16 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 5/18/2020 3:21 PM, Paul Moore wrote:
> > On Mon, May 18, 2020 at 4:43 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >> On 5/18/2020 11:02 AM, Stephen Smalley wrote:
> >>> On Thu, May 14, 2020 at 7:30 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> >>>> Create a new audit record type to contain the subject information
> >>>> when there are multiple security modules that require such data.
> >>>> This record is emitted before the other records for the event, but
> >>>> is linked with the same timestamp and serial number.
> >>>>
> >>>> Reviewed-by: Kees Cook <keescook@chromium.org>
> >>>> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
> >>>> Cc: linux-audit@redhat.com
> >>>> ---
> >>> With this patch, I see userspace audit records like this one:
> >>>
> >>> type=SYSTEM_BOOT msg=audit(1589816792.181:103): pid=789 uid=0
> >>> auid=4294967295 ses=4294967295 subj=? subj=system_u:system_r:init_t:s0
> >>> msg=' comm="systemd-update-utmp"
> >>> exe="/usr/lib/systemd/systemd-update-utmp" hostname=? addr=?
> >>> terminal=? res=success'
> >>>
> >>> I'm guessing that userspace is appending the second subj= field when
> >>> it sees subj=? or otherwise is missing subj= information?
> >> I haven't looked at the userspace code, but I expect you're right.
> >> It looks like there will need to be some change in the userspace
> >> for the multiple LSM case. The "completion" shown here isn't correct,
> >> because it only fills in one of the subject attributes, not both.
> > Wait, didn't we agree on a a "subj=? subj_selinux=XXX
> > subj_apparmor=YYY subj_smack=ZZZ" format?  It looks like there are two
> > 'subj' fields in the record above which is bad, don't do that please.
>
> That's not something that's coming from the kernel.

Yes it is.  Well, sorta.  With audit *everything* must come from the
kernel in order to meet the security goals that audit tries to
achieve.  I know you already know most of this, but I'm mentioning it
for others who are following along.

The record above is an audit user message which is a message that is
generated in userspace by a trusted process and written to the kernel,
the kernel then generates an audit record based on this message and
inserts it into the audit stream.  The text string that originates
from the userspace process is placed in the "msg" field; the
UID/AUID/subj/etc. information is supplied by the kernel (we don't
want to trust the process any more than absolutely necessary).

On my system, running a random but fairly modern kernel (a 5.7.0-rc5
variant) I see the following for the SYSTEM_BOOT record on my most
recent boot:

  type=SYSTEM_BOOT msg=audit(05/13/2020 14:19:23.983:89) : pid=633
    uid=root auid=unset ses=unset subj=system_u:system_r:init_t:s0
    msg=' comm=systemd-update-utmp
      exe=/usr/lib/systemd/systemd-update-utmp hostname=? addr=?
      terminal=? res=success'

... pay special attention to the single "subj" field ;)

> I'll check again, but I think that everyplace in the kernel that
> produces a subj= has been trained to create a type=1420 record
> instead.
>
> >>> Then we have kernel audit records like this:
> >>>
> >>> type=PROCTITLE msg=audit(1589816791.959:101): proctitle=2F7362696E2F617564697463
> >>> 746C002D52002F6574632F61756469742F61756469742E72756C6573
> >>> type=SYSCALL msg=audit(1589816791.959:101): arch=c000003e syscall=44
> >>> success=yes exit=1056 a0=3 a1=7fff9ccc98a0 a2=420 a3=0 items=0
> >>> ppid=773 pid=783 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0
> >>> egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="auditctl"
> >>> exe="/usr/sbin/auditctl" subj=? key=(null)
> >>> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
> >>> subj_selinux=system_u:system_r:unconfined_service_t:s0
> >>> subj_apparmor==unconfined
> >>> type=CONFIG_CHANGE msg=audit(1589816791.959:101): auid=4294967295
> >>> ses=4294967295 subj=? op=add_rule key=(null) list=1 res=1
> >>> type=UNKNOWN[1420] msg=audit(1589816791.959:101):
> >>> subj_selinux=system_u:system_r:unconfined_service_t:s0
> >>> subj_apparmor==unconfined
> >>>
> >>> where we are getting multiple copies of the new record type, one for
> >>> each record type that had subj=?.
> >> While obviously wasteful, the type=1420 behavior is consistent with
> >> the subj=? behavior, which is to duplicate the subj= value. I know
> >> we've got enough hobgoblins in the audit system that we don't need
> >> to add any more in the name of a foolish consistency.
> > You need to provide a bit more reason why we need byte-for-byte
> > duplicate records in a single event.  As it currently stands this
> > looks like something we definitely don't want.
>
> The CONFIG_CHANGE record already duplicates the subj= information
> in the SYSCALL record.

Yeah, let's not get started on that discussion ;)  Thankfully that
isn't what I was talking about in my earlier comment in this thread.

In the audit event above we see a number of records all part of a
single event (they all share the same timestamp:
"audit(1589816791.959:101)"), and in this single event we see two
identical records of type 1420 (the new record you are proposing).
That is my concern, I would expect just a single type 1420 record to
be added to this event.

For those who may not be familiar with audit, this is what a typical
audit event with a CONFIG_CHANGE record that adds an audit filter rule
looks like with an unpatched kernel:

  type=PROCTITLE msg=audit(05/13/2020 13:55:25.598:10349) :
    proctitle=auditctl -a always,exit -F arch b64 -S bpf
      -k testsuite-1589392525-yPWwmHYp
  type=SYSCALL msg=audit(05/13/2020 13:55:25.598:10349) : arch=x86_64
    syscall=send to success=yes exit=1088 a0=0x4 a1=0x7ffc93b8c910
    a2=0x440 a3=0x0 items=0 ppid=2650 pid=2659 auid=root uid=root
    gid=root euid=root suid=root fsuid=root egid=root sgid=root
    fsgid=root tty=pts0 ses=1 comm=auditctl exe=/usr/sbin/auditctl
    subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
  type=CONFIG_CHANGE msg=audit(05/13/2020 13:55:25.598:10349) : auid=root
    ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
    op=add_rule key=testsuite-1589392525-yPWwmHYp list=exit res=yes

> I just maintained the duplication. You're
> right, it's silly to have two identical type=1420 records for the event.
> I will have to come up with a mechanism to prevent the duplication.
> with luck, there's already a similar case for some other record.

Patch
diff mbox series

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index c76fc2abd091..e79c4948ab12 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3109,7 +3109,7 @@  static void binder_transaction(struct binder_proc *proc,
 		size_t added_size;
 
 		security_task_getsecid(proc->tsk, &blob);
-		ret = security_secid_to_secctx(&blob, &lsmctx);
+		ret = security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_DISPLAY);
 		if (ret) {
 			return_error = BR_FAILED_REPLY;
 			return_error_param = ret;
diff --git a/include/linux/security.h b/include/linux/security.h
index 3f53098ee89f..292fb89fa4f6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -177,6 +177,8 @@  struct lsmblob {
 #define LSMBLOB_INVALID		-1	/* Not a valid LSM slot number */
 #define LSMBLOB_NEEDED		-2	/* Slot requested on initialization */
 #define LSMBLOB_NOT_NEEDED	-3	/* Slot not requested */
+#define LSMBLOB_DISPLAY		-4	/* Use the "display" slot */
+#define LSMBLOB_FIRST		-5	/* Use the default "display" slot */
 
 /**
  * lsmblob_init - initialize an lsmblob structure.
@@ -239,6 +241,8 @@  static inline u32 lsmblob_value(const struct lsmblob *blob)
 	return 0;
 }
 
+const char *security_lsm_slot_name(int slot);
+
 /* These functions are in security/commoncap.c */
 extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
 		       int cap, unsigned int opts);
@@ -548,7 +552,8 @@  int security_setprocattr(const char *lsm, const char *name, void *value,
 			 size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
-int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp);
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
+			     int display);
 int security_secctx_to_secid(const char *secdata, u32 seclen,
 			     struct lsmblob *blob);
 void security_release_secctx(struct lsmcontext *cp);
@@ -1353,7 +1358,7 @@  static inline int security_ismaclabel(const char *name)
 }
 
 static inline int security_secid_to_secctx(struct lsmblob *blob,
-					   struct lsmcontext *cp)
+					   struct lsmcontext *cp, int display)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/include/net/scm.h b/include/net/scm.h
index 4a6ad8caf423..8b5a4737e1b8 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -96,7 +96,8 @@  static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
 	int err;
 
 	if (test_bit(SOCK_PASSSEC, &sock->flags)) {
-		err = security_secid_to_secctx(&scm->lsmblob, &context);
+		err = security_secid_to_secctx(&scm->lsmblob, &context,
+					       LSMBLOB_DISPLAY);
 
 		if (!err) {
 			put_cmsg(msg, SOL_SOCKET, SCM_SECURITY,
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index a534d71e689a..2e6dbf907ee3 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -138,6 +138,7 @@ 
 #define AUDIT_MAC_UNLBL_STCDEL	1417	/* NetLabel: del a static label */
 #define AUDIT_MAC_CALIPSO_ADD	1418	/* NetLabel: add CALIPSO DOI entry */
 #define AUDIT_MAC_CALIPSO_DEL	1419	/* NetLabel: del CALIPSO DOI entry */
+#define AUDIT_MAC_TASK_CONTEXTS	1420	/* Multiple LSM contexts */
 
 #define AUDIT_FIRST_KERN_ANOM_MSG   1700
 #define AUDIT_LAST_KERN_ANOM_MSG    1799
diff --git a/kernel/audit.c b/kernel/audit.c
index 7cd055b09cbe..5e8c3559dbef 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1422,7 +1422,7 @@  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	case AUDIT_SIGNAL_INFO:
 		if (lsmblob_is_set(&audit_sig_lsm)) {
 			err = security_secid_to_secctx(&audit_sig_lsm,
-						       &context);
+						       &context, LSMBLOB_FIRST);
 			if (err)
 				return err;
 		}
@@ -2062,28 +2062,58 @@  void audit_log_key(struct audit_buffer *ab, char *key)
 
 int audit_log_task_context(struct audit_buffer *ab)
 {
+	int i;
 	int error;
+	bool sep = false;
 	struct lsmblob blob;
-	struct lsmcontext context;
+	struct lsmcontext lsmdata;
+	struct audit_buffer *lsmab = NULL;
+	struct audit_context *context = NULL;
 
 	security_task_getsecid(current, &blob);
 	if (!lsmblob_is_set(&blob))
 		return 0;
 
-	error = security_secid_to_secctx(&blob, &context);
-	if (error) {
-		if (error != -EINVAL)
-			goto error_path;
-		return 0;
+	/*
+	 * If there is more than one security module that has a
+	 * subject "context" it's necessary to put the subject data
+	 * into a separate record to maintain compatibility.
+	 */
+	if (security_lsm_slot_name(1) != NULL) {
+		audit_log_format(ab, " subj=?");
+		context = ab->ctx;
+		if (context)
+			lsmab = audit_log_start(context, GFP_KERNEL,
+						AUDIT_MAC_TASK_CONTEXTS);
 	}
 
-	audit_log_format(ab, " subj=%s", context.context);
-	security_release_secctx(&context);
-	return 0;
+	for (i = 0; i < LSMBLOB_ENTRIES; i++) {
+		if (blob.secid[i] == 0)
+			continue;
+		error = security_secid_to_secctx(&blob, &lsmdata, i);
+		if (error && error != -EINVAL) {
+			audit_panic("error in audit_log_task_context");
+			return error;
+		}
+
+		if (context) {
+			audit_log_format(lsmab, "%ssubj_%s=%s",
+					 sep ? " " : "",
+					 security_lsm_slot_name(i),
+					 lsmdata.context);
+			sep = true;
+		} else
+			audit_log_format(ab, " subj=%s", lsmdata.context);
+
+		security_release_secctx(&lsmdata);
+		if (!context)
+			break;
+	}
+
+	if (context)
+		audit_log_end(lsmab);
 
-error_path:
-	audit_panic("error in audit_log_task_context");
-	return error;
+	return 0;
 }
 EXPORT_SYMBOL(audit_log_task_context);
 
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index d858bb4757b8..661527d14166 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -980,7 +980,7 @@  static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 			 from_kuid(&init_user_ns, auid),
 			 from_kuid(&init_user_ns, uid), sessionid);
 	if (lsmblob_is_set(blob)) {
-		if (security_secid_to_secctx(blob, &lsmctx)) {
+		if (security_secid_to_secctx(blob, &lsmctx, LSMBLOB_FIRST)) {
 			audit_log_format(ab, " obj=(none)");
 			rc = 1;
 		} else {
@@ -1225,7 +1225,8 @@  static void show_special(struct audit_context *context, int *call_panic)
 			struct lsmblob blob;
 
 			lsmblob_init(&blob, osid);
-			if (security_secid_to_secctx(&blob, &lsmcxt)) {
+			if (security_secid_to_secctx(&blob, &lsmcxt,
+						     LSMBLOB_FIRST)) {
 				audit_log_format(ab, " osid=%u", osid);
 				*call_panic = 1;
 			} else {
@@ -1377,7 +1378,7 @@  static void audit_log_name(struct audit_context *context, struct audit_names *n,
 		struct lsmcontext lsmctx;
 
 		lsmblob_init(&blob, n->osid);
-		if (security_secid_to_secctx(&blob, &lsmctx)) {
+		if (security_secid_to_secctx(&blob, &lsmctx, LSMBLOB_FIRST)) {
 			audit_log_format(ab, " osid=%u", n->osid);
 			if (call_panic)
 				*call_panic = 2;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 27af7a6b8780..10b418029cdd 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -138,7 +138,7 @@  static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
 	if (err)
 		return;
 
-	err = security_secid_to_secctx(&lb, &context);
+	err = security_secid_to_secctx(&lb, &context, LSMBLOB_DISPLAY);
 	if (err)
 		return;
 
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 5aaeeba01541..e3b2849b1c8b 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -337,7 +337,7 @@  static int ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
 	 * security_secid_to_secctx() will know which security module
 	 * to use to create the secctx.  */
 	lsmblob_init(&blob, ct->secmark);
-	ret = security_secid_to_secctx(&blob, &context);
+	ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
 	if (ret)
 		return 0;
 
@@ -651,7 +651,7 @@  static inline int ctnetlink_secctx_size(const struct nf_conn *ct)
 	struct lsmblob blob;
 	struct lsmcontext context;
 
-	ret = security_secid_to_secctx(&blob, &context);
+	ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
 	if (ret)
 		return 0;
 
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index b58d340d30f4..f109652d1322 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -177,7 +177,7 @@  static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
 	struct lsmcontext context;
 
 	lsmblob_init(&blob, ct->secmark);
-	ret = security_secid_to_secctx(&blob, &context);
+	ret = security_secid_to_secctx(&blob, &context, LSMBLOB_DISPLAY);
 	if (ret)
 		return;
 
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a4d4602ab9b7..15cabd7be92a 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -316,7 +316,7 @@  static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, struct lsmcontext *context)
 		 * blob. security_secid_to_secctx() will know which security
 		 * module to use to create the secctx.  */
 		lsmblob_init(&blob, skb->secmark);
-		security_secid_to_secctx(&blob, context);
+		security_secid_to_secctx(&blob, context, LSMBLOB_DISPLAY);
 	}
 
 	read_unlock_bh(&skb->sk->sk_callback_lock);
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index c14a485ff045..d816909866cc 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -437,7 +437,8 @@  int netlbl_unlhsh_add(struct net *net,
 unlhsh_add_return:
 	rcu_read_unlock();
 	if (audit_buf != NULL) {
-		if (security_secid_to_secctx(lsmblob, &context) == 0) {
+		if (security_secid_to_secctx(lsmblob, &context,
+					     LSMBLOB_FIRST) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s",
 					 context.context);
 			security_release_secctx(&context);
@@ -492,7 +493,8 @@  static int netlbl_unlhsh_remove_addr4(struct net *net,
 		if (dev != NULL)
 			dev_put(dev);
 		if (entry != NULL &&
-		    security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
+		    security_secid_to_secctx(&entry->lsmblob, &context,
+					     LSMBLOB_FIRST) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s",
 					 context.context);
 			security_release_secctx(&context);
@@ -552,7 +554,8 @@  static int netlbl_unlhsh_remove_addr6(struct net *net,
 		if (dev != NULL)
 			dev_put(dev);
 		if (entry != NULL &&
-		    security_secid_to_secctx(&entry->lsmblob, &context) == 0) {
+		    security_secid_to_secctx(&entry->lsmblob, &context,
+					     LSMBLOB_FIRST) == 0) {
 			audit_log_format(audit_buf, " sec_obj=%s",
 					 context.context);
 			security_release_secctx(&context);
@@ -1122,7 +1125,7 @@  static int netlbl_unlabel_staticlist_gen(u32 cmd,
 		lsmb = (struct lsmblob *)&addr6->lsmblob;
 	}
 
-	ret_val = security_secid_to_secctx(lsmb, &context);
+	ret_val = security_secid_to_secctx(lsmb, &context, LSMBLOB_FIRST);
 	if (ret_val != 0)
 		goto list_cb_failure;
 	ret_val = nla_put(cb_arg->skb,
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 951ba0639d20..1941877fd16f 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -100,7 +100,7 @@  struct audit_buffer *netlbl_audit_start_common(int type,
 
 	lsmblob_init(&blob, audit_info->secid);
 	if (audit_info->secid != 0 &&
-	    security_secid_to_secctx(&blob, &context) == 0) {
+	    security_secid_to_secctx(&blob, &context, LSMBLOB_FIRST) == 0) {
 		audit_log_format(audit_buf, " subj=%s", context.context);
 		security_release_secctx(&context);
 	}
diff --git a/security/security.c b/security/security.c
index 677a9f409dc2..ed20d4c6ed93 100644
--- a/security/security.c
+++ b/security/security.c
@@ -480,7 +480,31 @@  static int lsm_append(const char *new, char **result)
  * Pointers to the LSM id structures for local use.
  */
 static int lsm_slot __lsm_ro_after_init;
-static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES];
+static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES] __lsm_ro_after_init;
+
+/**
+ * security_lsm_slot_name - Get the name of the security module in a slot
+ * @slot: index into the "display" slot list.
+ *
+ * Provide the name of the security module associated with
+ * a display slot.
+ *
+ * If @slot is LSMBLOB_INVALID return the value
+ * for slot 0 if it has been set, otherwise NULL.
+ *
+ * Returns a pointer to the name string or NULL.
+ */
+const char *security_lsm_slot_name(int slot)
+{
+	if (slot == LSMBLOB_INVALID)
+		slot = 0;
+	else if (slot >= LSMBLOB_ENTRIES || slot < 0)
+		return NULL;
+
+	if (lsm_slotlist[slot] == NULL)
+		return NULL;
+	return lsm_slotlist[slot]->lsm;
+}
 
 /**
  * security_add_hooks - Add a modules hooks to the hook lists.
@@ -2188,13 +2212,32 @@  int security_ismaclabel(const char *name)
 }
 EXPORT_SYMBOL(security_ismaclabel);
 
-int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp,
+			     int display)
 {
 	struct security_hook_list *hp;
-	int display = lsm_task_display(current);
 
 	memset(cp, 0, sizeof(*cp));
 
+	/*
+	 * display either is the slot number use for formatting
+	 * or an instruction on which relative slot to use.
+	 */
+	if (display == LSMBLOB_DISPLAY)
+		display = lsm_task_display(current);
+	else if (display == LSMBLOB_FIRST)
+		display = LSMBLOB_INVALID;
+	else if (display < 0) {
+		WARN_ONCE(true,
+			"LSM: %s unknown display\n", __func__);
+		display = LSMBLOB_INVALID;
+	} else if (display >= lsm_slot) {
+		WARN_ONCE(true,
+			"LSM: %s invalid display\n", __func__);
+		display = LSMBLOB_INVALID;
+	}
+
+
 	hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
 		if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
 			continue;
@@ -2205,7 +2248,7 @@  int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
 					&cp->context, &cp->len);
 		}
 	}
-	return 0;
+	return -EOPNOTSUPP;
 }
 EXPORT_SYMBOL(security_secid_to_secctx);