Preferred subj= with multiple LSMs

Casey Schaufler casey at schaufler-ca.com
Fri Jul 19 16:29:17 UTC 2019


On 7/19/2019 5:15 AM, Simon McVittie wrote:
> On Thu, 18 Jul 2019 at 09:13:52 -0700, Casey Schaufler wrote:
>> We have discussed what's currently being
>> called the "hideous" format, selinux='a:b:c:d',apparmor='x' which
>> in the past, and concluded that the compatibility issues would be too
>> great.
> I agree this might be too big a compat break for existing interfaces that
> were designed with the assumption that there can only be one "big" LSM
> at a time, like /proc/54321/attr/current and SO_PEERSEC. It would certainly
> break the current libapparmor, and presumably libselinux as well.
>
> However, I think it would be great to have multiple-"big"-LSM-aware
> replacements for those interfaces, which present the various LSMs as
> multiple parallel credentials.

Defining what would go into liblsm* is a task that has fallen to
the chicken/egg paradox. We can't really define how the user-space
should work without knowing how the kernel will work, and we can't
solidify how the kernel will work until we know what user-space
can use.

---
* I absolutely refuse to allow this to be libsecurity!

> I think it would also be valuable to take this opportunity to pin down
> what can and can't be in a label, to an extent where people who want
> to represent them in a similar encoding know what they can and can't
> assume about their format. For example, when dbus-daemon reports an
> unusual event (like rejecting a message due to policy rules or LSMs,
> or hitting a resource limit that isn't normally meant to be reached),
> the log entry contains miscellaneous information about the process for
> debugging purposes, and it would be good if we could include all the LSM
> labels in that string without ambiguity. This is essentially the same
> problem that the audit subsystem has, but with fewer constraints, since
> the audit subsystem has to meet externally-imposed security requirements
> but our equivalent is just a nice-to-have for debugging.

Sounds like the Hideous format, or a variant thereof, would be
fine for you, especially if you never parse it.

>> Have you been following the discussions on setting a "display" value
>> to specify which LSM data is presented by /proc/self/attr/current and
>> SO_PEERSEC? Briefly, a process can write the name of the LSM it wants
>> to see data from to /proc/self/attr/display, and the aforementioned
>> interfaces will use that LSM. If no value has been set the first LSM
>> registered that uses any of these interfaces gets the nod.
> I'm vaguely aware of the discussion, but LSMs aren't a big part of my
> D-Bus maintainer role, so I'm afraid I can't keep up with all of it.
>
> Do you mean that if process 11111 writes (for example) "apparmor" into
> /proc/11111/attr/display, and then reads /proc/22222/attr/current
> or queries the SO_PEERSEC of a socket opened by process 22222,
> it will specifically see 22222's AppArmor label and not 22222's SELinux
> label? Or is the contents of /proc/22222/attr/current controlled
> by /proc/22222/attr/display?

Process 11111 would see the AppArmor label when reading
/proc/22222/attr/current. The display value is controlled
by process 11111 so that it can control what data it wants
to see.

> How is this meant to work for generic LSM-aware user-space processes? If
> (for example) ps -Z 22222 wants to get both the AppArmor label and the
> SELinux label for process 22222, is it meant to write "apparmor" into
> attr/display, then read /proc/22222/attr/current, then write "selinux"
> to attr/display, then read /proc/22222/attr/current again? That sounds
> risky if another thread might be manipulating attr/display concurrently.

The display is set at the task level, so should be thread safe.

> The D-Bus message bus/broker (reference implementation: dbus-daemon)
> is somewhat tricky because it is returning data on behalf of processes
> other than itself, so it would be difficult for it to choose a good
> value for "display": there's no reason why it wouldn't be responding
> to requests from NetworkManager that expect to see SELinux labels, and
> also requests from lxd that expect to see AppArmor labels. Obviously
> it can't put both in LinuxSecurityLabel without the same compatibility
> issues you're discussing.

Just so.

> Also note that dbus-daemon is trusted but mostly unprivileged - it
> starts as root, then drops privileges to a system user normally called
> messagebus, dbus or _dbus for its normal operation (although it does
> retain CAP_AUDIT_WRITE) - so it can't carry out privileged operations
> on other processes' /proc entries, if that's what the API requires.

Writing to display does not require privilege, as it affects only
the current process. The display is inherited on fork and reset on
a privileged exec.

> I would strongly prefer it if we could get this information from
> the kernel in a way that is Linux-specific but LSM-agnostic, without
> having to link to libapparmor, libselinux, libsmack and everyone else's
> favourite LSM library. At the moment we only need to link to libraries
> for the LSMs where dbus-daemon can carry out mediation (asking the LSM
> whether to accept or reject messages), and we don't need the libraries
> if we are just passing through identity information.

I can see that making dbus-daemon have to decide which label of many
to pass on to its clients would be bad.

> I would also prefer it if we can get this information from SO_PEERSEC
> (or some newer SO_PEERSEC replacement) without having to manipulate
> ambient/implicit state like attr/display; but dbus-daemon is
> single-threaded, so if we must do that, it wouldn't be *so* horrible.

An option that hasn't been discussed is a display option to provide
the Hideous format for applications that know that's what they want.
Write "hideous" into /proc/self/attr/display, and from then on you
get selinux='a:b:c:d',apparmor='z'. This could be used widely in liblsm
interfaces.

> Ideally I would like to be able to get all the LSM labels in O(1)
> syscalls. Perhaps something with the same (buffer,length) kernel <->
> user-space API as SO_PEERSEC and SO_PEERGROUPS, but instead of returning
> a single \0-terminated string, it could return either the "hideous" format,
> or a byte-blob that looks something like this?
>
>     char buffer[ENOUGH_LENGTH] = { 0 };
>     socklen_t len = sizeof (buffer);
>     char[] expected =
>     "apparmor=unconfined\0"
>     "selinux=system_u:system_r:init_t:s0\0"
>     "\0"
>     ;
>
>     getsockopt (fd, SOL_SOCKET, SO_PEERSECLABELS, &buffer, &length);
>     /* should return 0 */
>     /* now buffer should have the same bytes as expected, ending with
>      * "\0\0" */
>
> (Obviously in real life you'd have a retry loop to get the length right,
> like the SO_PEERSEC code in dbus does.)

I would see creating a friendly interface like this as part of
my mythical liblsm, but I see your point.

> Because GetConnectionCredentials() is extensible, if there is some way
> to enumerate all the security labels and get their values individually,
> we could have (pseudocode)
>
> GetConnectionCredentials(":1.1") -> {
>   "UnixUserID": 0,
>   "ProcessID": 1,
>   "LinuxSecurityLabel.apparmor": "unconfined",
>   "LinuxSecurityLabel.selinux": "system_u:system_r:init_t:s0",
>   "LinuxSecurityLabel": "unconfined",    /* deprecated */
> }
>
> or (using D-Bus' structured type system)
>
> GetConnectionCredentials(":1.1") -> {
>   "UnixUserID": 0,
>   "ProcessID": 1,
>   "LinuxSecurityLabels": {
>     "apparmor": "unconfined",
>     "selinux": "system_u:system_r:init_t:s0",
>   },
>   "LinuxSecurityLabel": "unconfined",    /* deprecated */
> }
>
> with LinuxSecurityLabel showing the first LSM registered for backwards
> compatibility? Or we could make LinuxSecurityLabel always be in the
> "hideous" format if you chose to go that way in the kernel interfaces:
> it's defined in terms of SO_PEERSEC, so whatever you do at the kernel
> level, D-Bus should mimic that.

If providing the Hideous format makes library code easier or more
efficient I'm happy to make that happen. It can't be the default due to
backward compatibility, but it can be easy as
"echo hideous > /proc/self/attr/display".

>
>     smcv




More information about the Linux-security-module-archive mailing list