Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filesystem: Add labeling for pidfs. #762

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

pebenito
Copy link
Member

@pebenito pebenito commented Feb 23, 2024

Add task SID labeling for pidfs, which is the new backing pseudo filesystem for pidfds.

The existing rules will allow domains to open pidfds and use them internally, but other domains will require additional access (fd and file) when passing around the pidfd.

@pebenito
Copy link
Member Author

Need to decide if we should use task sid or a single common genfs label, like anon_inode.

@stephensmalley @jwcart2 @pcmoore if you have thoughts

@brauner
Copy link

brauner commented Feb 23, 2024

This will also allow you to do fine-grained labeling finally because it now goes through the regular security_file_open().

@cgzones
Copy link
Contributor

cgzones commented Feb 23, 2024

@pcmoore
Copy link
Member

pcmoore commented Feb 23, 2024

As a pidfd is a reference to a task, I believe it should use the task's SID/label.

@pebenito pebenito marked this pull request as ready for review February 23, 2024 18:19
brauner added a commit to brauner/linux that referenced this pull request Feb 24, 2024
Moving pidfds from the anonymous inode infrastructure to a separate tiny
in-kernel filesystem similar to sockfs, pipefs, and anon_inodefs causes
Selinux denials and thus various userspace components that make heavy
use of pidfds to fail if we would be using dentry_open() directly.
pidfds used anon_inode_getfile() which never was subject to any LSM
hooks. But dentry_open() is and that would cause regressions:

Feb 23 12:09:58 fed1 audit[353]: AVC avc:  denied  { read write open } for  pid=353 comm="systemd-userdbd" path="pidfd:[709]" dev="pidfs" ino=709 scontext=system_u:system_r:systemd_userdbd_t:>

The failures that are seen are selinux denials. But the core failure is
dbus-broker. That cascades into other services failing that depend on
dbus-broker. For example, when dbus-broker fails to start polkit and all
the others won't be able to work because they depend on dbus-broker.

The reason for dbus-broker failing is because it doesn't handle failures
for SO_PEERPIDFD correctly. Last kernel release (either v6.7 or v6.6,
I'm not completely sure right now) we introduced SO_PEERPIDFD (and
SCM_PIDFD). SO_PEERPIDFD allows dbus-broker and polkit and others to
receive a pidfd for the peer of an AF_UNIX socket. This is the first
time in the history of Linux that we can safely authenticate clients in
a race-free manner.

dbus-broker immediately made use of this but messed up the error
checking. It only allowed EINVAL as a valid failure for SO_PEERPIDFD.
That's obviously problematic not just because of LSM denials but because
of seccomp denials that would prevent SO_PEERPIDFD from working; or any
other new error code from there.

So this is catching a flawed implementation in dbus-broker as well. It
has to fallback to the old pid-based authentication when SO_PEERPIDFD
doesn't work no matter the reasons otherwise it'll always risk such
failures. So overall that LSM denial should not have caused dbus-broker
to fail. It can never assume that a feature released one kernel ago like
SO_PEERPIDFD can be assumed to be available.

So, the next fix separate from the selinux policy update is to fix
dbus-broker at [3]. That should make it into Fedora as well. In addition
the selinux reference policy should also be updated. See [4] for that.
If Selinux is in enforcing mode in userspace and it encounters anything
that it doesn't know about it will deny it by default. And the policy is
entirely in userspace including declaring new types for stuff like nsfs
or pidfs to allow it. There's just nothing to do in the kernel so we
can't use dentry_open(). So instead we use alloc_file(). Once selinux is
ready we can switch to dentry_open() or we introduce separate LSM hook
for pidfds.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2265630 [1]
Link: fedora-selinux/selinux-policy#2050 [2]
Link: bus1/dbus-broker#343 [3]
Link: SELinuxProject/refpolicy#762 [4]
Reported-by: Nathan Chancellor <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Link: https://lore.kernel.org/r/20240218-neufahrzeuge-brauhaus-fb0eb6459771@brauner
Signed-off-by: Christian Brauner <[email protected]>
brauner added a commit to brauner/linux that referenced this pull request Feb 25, 2024
Moving pidfds from the anonymous inode infrastructure to a separate tiny
in-kernel filesystem similar to sockfs, pipefs, and anon_inodefs causes
Selinux denials and thus various userspace components that make heavy
use of pidfds to fail if we would be using dentry_open() directly.
pidfds used anon_inode_getfile() which never was subject to any LSM
hooks. But dentry_open() is and that would cause regressions:

Feb 23 12:09:58 fed1 audit[353]: AVC avc:  denied  { read write open } for  pid=353 comm="systemd-userdbd" path="pidfd:[709]" dev="pidfs" ino=709 scontext=system_u:system_r:systemd_userdbd_t:>

The failures that are seen are selinux denials. But the core failure is
dbus-broker. That cascades into other services failing that depend on
dbus-broker. For example, when dbus-broker fails to start polkit and all
the others won't be able to work because they depend on dbus-broker.

The reason for dbus-broker failing is because it doesn't handle failures
for SO_PEERPIDFD correctly. Last kernel release (either v6.7 or v6.6,
I'm not completely sure right now) we introduced SO_PEERPIDFD (and
SCM_PIDFD). SO_PEERPIDFD allows dbus-broker and polkit and others to
receive a pidfd for the peer of an AF_UNIX socket. This is the first
time in the history of Linux that we can safely authenticate clients in
a race-free manner.

dbus-broker immediately made use of this but messed up the error
checking. It only allowed EINVAL as a valid failure for SO_PEERPIDFD.
That's obviously problematic not just because of LSM denials but because
of seccomp denials that would prevent SO_PEERPIDFD from working; or any
other new error code from there.

So this is catching a flawed implementation in dbus-broker as well. It
has to fallback to the old pid-based authentication when SO_PEERPIDFD
doesn't work no matter the reasons otherwise it'll always risk such
failures. So overall that LSM denial should not have caused dbus-broker
to fail. It can never assume that a feature released one kernel ago like
SO_PEERPIDFD can be assumed to be available.

So, the next fix separate from the selinux policy update is to fix
dbus-broker at [3]. That should make it into Fedora as well. In addition
the selinux reference policy should also be updated. See [4] for that.
If Selinux is in enforcing mode in userspace and it encounters anything
that it doesn't know about it will deny it by default. And the policy is
entirely in userspace including declaring new types for stuff like nsfs
or pidfs to allow it. There's just nothing to do in the kernel so we
can't use dentry_open(). So instead we use alloc_file(). Once selinux is
ready we can switch to dentry_open() or we introduce separate LSM hook
for pidfds.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2265630 [1]
Link: fedora-selinux/selinux-policy#2050 [2]
Link: bus1/dbus-broker#343 [3]
Link: SELinuxProject/refpolicy#762 [4]
Reported-by: Nathan Chancellor <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Link: https://lore.kernel.org/r/20240218-neufahrzeuge-brauhaus-fb0eb6459771@brauner
Signed-off-by: Christian Brauner <[email protected]>
Signed-off-by: Chris PeBenito <[email protected]>
brauner added a commit to brauner/linux that referenced this pull request Feb 27, 2024
Moving pidfds from the anonymous inode infrastructure to a separate tiny
in-kernel filesystem similar to sockfs, pipefs, and anon_inodefs causes
Selinux denials and thus various userspace components that make heavy
use of pidfds to fail if we would be using dentry_open() directly.
pidfds used anon_inode_getfile() which never was subject to any LSM
hooks. But dentry_open() is and that would cause regressions:

Feb 23 12:09:58 fed1 audit[353]: AVC avc:  denied  { read write open } for  pid=353 comm="systemd-userdbd" path="pidfd:[709]" dev="pidfs" ino=709 scontext=system_u:system_r:systemd_userdbd_t:>

The failures that are seen are selinux denials. But the core failure is
dbus-broker. That cascades into other services failing that depend on
dbus-broker. For example, when dbus-broker fails to start polkit and all
the others won't be able to work because they depend on dbus-broker.

The reason for dbus-broker failing is because it doesn't handle failures
for SO_PEERPIDFD correctly. Last kernel release (either v6.7 or v6.6,
I'm not completely sure right now) we introduced SO_PEERPIDFD (and
SCM_PIDFD). SO_PEERPIDFD allows dbus-broker and polkit and others to
receive a pidfd for the peer of an AF_UNIX socket. This is the first
time in the history of Linux that we can safely authenticate clients in
a race-free manner.

dbus-broker immediately made use of this but messed up the error
checking. It only allowed EINVAL as a valid failure for SO_PEERPIDFD.
That's obviously problematic not just because of LSM denials but because
of seccomp denials that would prevent SO_PEERPIDFD from working; or any
other new error code from there.

So this is catching a flawed implementation in dbus-broker as well. It
has to fallback to the old pid-based authentication when SO_PEERPIDFD
doesn't work no matter the reasons otherwise it'll always risk such
failures. So overall that LSM denial should not have caused dbus-broker
to fail. It can never assume that a feature released one kernel ago like
SO_PEERPIDFD can be assumed to be available.

So, the next fix separate from the selinux policy update is to fix
dbus-broker at [3]. That should make it into Fedora as well. In addition
the selinux reference policy should also be updated. See [4] for that.
If Selinux is in enforcing mode in userspace and it encounters anything
that it doesn't know about it will deny it by default. And the policy is
entirely in userspace including declaring new types for stuff like nsfs
or pidfs to allow it. So for now we continue to raise S_PRIVATE on the
inode if it's a pidfs inode.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2265630 [1]
Link: fedora-selinux/selinux-policy#2050 [2]
Link: bus1/dbus-broker#343 [3]
Link: SELinuxProject/refpolicy#762 [4]
Reported-by: Nathan Chancellor <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Link: https://lore.kernel.org/r/20240218-neufahrzeuge-brauhaus-fb0eb6459771@brauner
Signed-off-by: Christian Brauner <[email protected]>
@pebenito
Copy link
Member Author

pebenito commented Feb 27, 2024

There is an issue where if process A does pidfd_open() on process B, the pidfs entries will have process A's context instead of process B's, which is undesirable. Not sure if @brauner 's change above addresses it but want to note it here.

cc @pcmoore

@pcmoore
Copy link
Member

pcmoore commented Feb 27, 2024

There is an issue where if process A does pidfd_open() on process B, the pidfs entries will have process A's context instead of process B's, which is undesirable ...

"undesirable" is certainly a mild way to put it ;) It's definitely wrong and something we need to resolve. I'll take a look it as I suspect this is going to require kernel code to handle properly.

@brauner
Copy link

brauner commented Feb 28, 2024

he pidfs entries will have process A's context instead of process B's

I don't understand what that is supposed to mean? The pidfd entries are anonymous inodes. They don't have any process credentials attached to them?

I was talking about file->f_cred, e.g., if you do pidfd_open(1234, ...) then it's the same as open("/proc/1234", ...). In both cases the opened file file->f_cred will be set to the opener's credentials. That's literally how file->f_cred is defined; to be able to go back to the opener's credentials.

@brauner
Copy link

brauner commented Feb 28, 2024

Open File Credentials
=====================

When a new file is opened, a reference is obtained on the opening task's
credentials and this is attached to the file struct as ``f_cred`` in place of
``f_uid`` and ``f_gid``.  Code that used to access ``file->f_uid`` and
``file->f_gid`` should now access ``file->f_cred->fsuid`` and
``file->f_cred->fsgid``.

Documentation/filesystems/credentials.rst

@pebenito
Copy link
Member Author

I don't understand what that is supposed to mean? The pidfd entries are anonymous inodes. They don't have any process credentials attached to them?

It might be my lack of knowledge injecting confusion into this. I'll leave it to Paul and the other kernel devs to clarify.

@pcmoore
Copy link
Member

pcmoore commented Feb 28, 2024

I haven't had a chance to look at any code yet, I'm basing my comments purely on what has been written here and the pidfs patchset cover letter, but you've explicitly mentioned moving away from the anonymous inode infrastructure @brauner:

This moves pidfds from the anonymous inode infrastructure to a tiny pseudo filesystem.

... if this isn't the case, that would be good to know.

@brauner
Copy link

brauner commented Feb 28, 2024

I haven't had a chance to look at any code yet, I'm basing my comments purely on what has been written here and the pidfs patchset cover letter, but you've explicitly mentioned moving away from the anonymous inode infrastructure @brauner:

This moves pidfds from the anonymous inode infrastructure to a tiny pseudo filesystem.

... if this isn't the case, that would be good to know.

Anonymous inodes are just inodes marked with S_PRIVATE, so no we're not moving away from that.

@brauner
Copy link

brauner commented Feb 28, 2024

We're just using our own superblock just like dma, drm, cxl, or oxcl, aio, iomem, or secretmem.

@pcmoore
Copy link
Member

pcmoore commented Feb 28, 2024

I haven't had a chance to look at any code yet, I'm basing my comments purely on what has been written here and the pidfs patchset cover letter, but you've explicitly mentioned moving away from the anonymous inode infrastructure @brauner:

This moves pidfds from the anonymous inode infrastructure to a tiny pseudo filesystem.

... if this isn't the case, that would be good to know.

Anonymous inodes are just inodes marked with S_PRIVATE, so no we're not moving away from that.

Sure, but you did mention that you were moving away from the anonymous inode infrastructure which could be relevant from a LSM perspective. I still need to check the code.

@pcmoore
Copy link
Member

pcmoore commented Feb 28, 2024

There is also still the original issue that we likely want to label pidfds based on their associated task, similar to what we do with process entries in procfs. While the concept is independent of the pidfd/pidfs implementation, how we satisfy this requirement is obviously very implementation specific.

@brauner
Copy link

brauner commented Feb 28, 2024

brauner added a commit to brauner/linux that referenced this pull request Feb 28, 2024
Moving pidfds from the anonymous inode infrastructure to a separate tiny
in-kernel filesystem similar to sockfs, pipefs, and anon_inodefs causes
selinux denials and thus various userspace components that make heavy
use of pidfds to fail as pidfds used anon_inode_getfile() which aren't
subject to any LSM hooks. But dentry_open() is and that would cause
regressions.

The failures that are seen are selinux denials. But the core failure is
dbus-broker. That cascades into other services failing that depend on
dbus-broker. For example, when dbus-broker fails to start polkit and all
the others won't be able to work because they depend on dbus-broker.

The reason for dbus-broker failing is because it doesn't handle failures
for SO_PEERPIDFD correctly. Last kernel release we introduced
SO_PEERPIDFD (and SCM_PIDFD). SO_PEERPIDFD allows dbus-broker and polkit
and others to receive a pidfd for the peer of an AF_UNIX socket. This is
the first time in the history of Linux that we can safely authenticate
clients in a race-free manner.

dbus-broker immediately made use of this but messed up the error
checking. It only allowed EINVAL as a valid failure for SO_PEERPIDFD.
That's obviously problematic not just because of LSM denials but because
of seccomp denials that would prevent SO_PEERPIDFD from working; or any
other new error code from there.

So this is catching a flawed implementation in dbus-broker as well. It
has to fallback to the old pid-based authentication when SO_PEERPIDFD
doesn't work no matter the reasons otherwise it'll always risk such
failures. So overall that LSM denial should not have caused dbus-broker
to fail. It can never assume that a feature released one kernel ago like
SO_PEERPIDFD can be assumed to be available.

So, the next fix separate from the selinux policy update is to try and
fix dbus-broker at [3]. That should make it into Fedora as well. In
addition the selinux reference policy should also be updated. See [4]
for that. If Selinux is in enforcing mode in userspace and it encounters
anything that it doesn't know about it will deny it by default. And the
policy is entirely in userspace including declaring new types for stuff
like nsfs or pidfs to allow it.

For now we continue to raise S_PRIVATE on the inode if it's a pidfs
inode which means things behave exactly like before.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2265630
Link: fedora-selinux/selinux-policy#2050
Link: bus1/dbus-broker#343 [3]
Link: SELinuxProject/refpolicy#762 [4]
Reported-by: Nathan Chancellor <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Link: https://lore.kernel.org/r/20240218-neufahrzeuge-brauhaus-fb0eb6459771@brauner
Signed-off-by: Christian Brauner <[email protected]>
brauner added a commit to brauner/linux that referenced this pull request Mar 1, 2024
Moving pidfds from the anonymous inode infrastructure to a separate tiny
in-kernel filesystem similar to sockfs, pipefs, and anon_inodefs causes
selinux denials and thus various userspace components that make heavy
use of pidfds to fail as pidfds used anon_inode_getfile() which aren't
subject to any LSM hooks. But dentry_open() is and that would cause
regressions.

The failures that are seen are selinux denials. But the core failure is
dbus-broker. That cascades into other services failing that depend on
dbus-broker. For example, when dbus-broker fails to start polkit and all
the others won't be able to work because they depend on dbus-broker.

The reason for dbus-broker failing is because it doesn't handle failures
for SO_PEERPIDFD correctly. Last kernel release we introduced
SO_PEERPIDFD (and SCM_PIDFD). SO_PEERPIDFD allows dbus-broker and polkit
and others to receive a pidfd for the peer of an AF_UNIX socket. This is
the first time in the history of Linux that we can safely authenticate
clients in a race-free manner.

dbus-broker immediately made use of this but messed up the error
checking. It only allowed EINVAL as a valid failure for SO_PEERPIDFD.
That's obviously problematic not just because of LSM denials but because
of seccomp denials that would prevent SO_PEERPIDFD from working; or any
other new error code from there.

So this is catching a flawed implementation in dbus-broker as well. It
has to fallback to the old pid-based authentication when SO_PEERPIDFD
doesn't work no matter the reasons otherwise it'll always risk such
failures. So overall that LSM denial should not have caused dbus-broker
to fail. It can never assume that a feature released one kernel ago like
SO_PEERPIDFD can be assumed to be available.

So, the next fix separate from the selinux policy update is to try and
fix dbus-broker at [3]. That should make it into Fedora as well. In
addition the selinux reference policy should also be updated. See [4]
for that. If Selinux is in enforcing mode in userspace and it encounters
anything that it doesn't know about it will deny it by default. And the
policy is entirely in userspace including declaring new types for stuff
like nsfs or pidfs to allow it.

For now we continue to raise S_PRIVATE on the inode if it's a pidfs
inode which means things behave exactly like before.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=2265630
Link: fedora-selinux/selinux-policy#2050
Link: bus1/dbus-broker#343 [3]
Link: SELinuxProject/refpolicy#762 [4]
Reported-by: Nathan Chancellor <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Link: https://lore.kernel.org/r/20240218-neufahrzeuge-brauhaus-fb0eb6459771@brauner
Signed-off-by: Christian Brauner <[email protected]>
@pebenito pebenito marked this pull request as draft April 2, 2024 12:59
Copy link

github-actions bot commented Jun 2, 2024

This PR has not had any recent activity. It will be closed in 7 days if it makes no further progress.

@github-actions github-actions bot added the stale Issue/PR has not had any recent activity. label Jun 2, 2024
@pebenito pebenito removed the stale Issue/PR has not had any recent activity. label Jun 4, 2024
Copy link

github-actions bot commented Aug 4, 2024

This PR has not had any recent activity. It will be closed in 7 days if it makes no further progress.

@github-actions github-actions bot added the stale Issue/PR has not had any recent activity. label Aug 4, 2024
Copy link

Closing stale PR.

@github-actions github-actions bot closed this Aug 11, 2024
@pebenito pebenito reopened this Dec 9, 2024
@pebenito pebenito removed the stale Issue/PR has not had any recent activity. label Dec 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants