Bug 2229146 - Login not possible with Python bridge with user_u restricted user accounts and user_exec_content==off
Summary: Login not possible with Python bridge with user_u restricted user accounts an...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Fedora
Classification: Fedora
Component: cockpit
Version: 38
Hardware: x86_64
OS: Linux
unspecified
medium
Target Milestone: ---
Assignee: Martin Pitt
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2023-08-04 12:25 UTC by Christopher Klooz
Modified: 2023-11-23 11:29 UTC (History)
5 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-11-23 11:28:20 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)

Description Christopher Klooz 2023-08-04 12:25:56 UTC
Any update in the recent two weeks (I assume the recent update to  cockpit-297-1.fc38) has made cockpit unusable on Fedora installations where SELinux is enforcing within user accounts ("confined user") and not only around them. This means that many use cases no longer work with cockpit (in short, cockpit is in the new version no longer compatible with and compliant to SELinux), which likely also affects other systems: I assume on RHEL it would be the same [1].

The issue relates to the confinement of the user accounts in which cockpit is logging into, not to the user accounts the user is using to open the cockpit web interface. For example, if I open Firefox and go to the web interface of cockpit in order to login, and if I then log in with the user "virtual-user" whereas "virtual-user" is confined (e.g., user_u), cockpit does no longer work.

The issue looks at first glance like wrong credentials, since the web interface always outputs that the username or the password is wrong. However, I have tested many times and also in testing environments with copy-paste-passwords: the credentials seem wrong when the user account in which I want to log into with cockpit is confined, but it works if it is unconfined. 

The root log documents the problem: first, the new cockpit version seems to provoke an avc denial, which is followed by an error in cockpit (the error type indicates a bug, even if the avc denial is provoking it). A little later, cockpit starts to provoke another series of SELinux denials. It seems that SELinux becomes active because cockpit does not handle issues with regards to /tmp/ properly. This can be a misconfiguration of policy files but also a bug. Given the overall behavior and logs (especially the Python error type), I tend to assume that this is a bug. This issue could also have security implications depending on how and where cockpit is used.

This is the full output of "journalctl -r": https://gitlab.com/py0xc31/tmp71/-/raw/main/cockpit-error-log

The major part is imho:

```
<see full output for more>
...
...
Aug 04 13:35:11 fedora setroubleshoot[8232]: SELinux is preventing cockpit-bridge from execute access on the file /tmp/#135 (deleted).

                                             *****  Plugin catchall_boolean (89.3 confidence) suggests   ******************

                                             If you want to allow user to exec content
                                             Then you must tell SELinux about this by enabling the 'user_exec_content' boolean.

                                             Do
                                             setsebool -P user_exec_content 1

                                             *****  Plugin catchall (11.6 confidence) suggests   **************************

                                             If you believe that cockpit-bridge should be allowed execute access on the #135 (deleted) file by default.
                                             Then you should report this as a bug.
                                             You can generate a local policy module to allow this access.
                                             Do
                                             allow this access for now by executing:
                                             # ausearch -c 'cockpit-bridge' --raw | audit2allow -M my-cockpitbridge
                                             # semodule -X 300 -i my-cockpitbridge.pp

Aug 04 13:35:11 fedora setroubleshoot[8232]: SELinux is preventing cockpit-bridge from execute access on the file /tmp/#135 (deleted). For complete SELinux messages run: sealert -l 23e5953f-7c79-4b04-8367-470ec578df3b
Aug 04 13:35:11 fedora setroubleshoot[8232]: SELinux is preventing cockpit-bridge from execute access on the file /memfd:libffi (deleted).

                                             *****  Plugin catchall_boolean (89.3 confidence) suggests   ******************

                                             If you want to allow user to exec content
                                             Then you must tell SELinux about this by enabling the 'user_exec_content' boolean.

                                             Do
                                             setsebool -P user_exec_content 1

                                             *****  Plugin catchall (11.6 confidence) suggests   **************************

                                             If you believe that cockpit-bridge should be allowed execute access on the memfd:libffi (deleted) file by default.
                                             Then you should report this as a bug.
                                             You can generate a local policy module to allow this access.
                                             Do
                                             allow this access for now by executing:
                                             # ausearch -c 'cockpit-bridge' --raw | audit2allow -M my-cockpitbridge
                                             # semodule -X 300 -i my-cockpitbridge.pp

Aug 04 13:35:11 fedora setroubleshoot[8232]: SELinux is preventing cockpit-bridge from execute access on the file /memfd:libffi (deleted). For complete SELinux messages run: sealert -l 23e5953f-7c79-4b04-8367-470ec578df3b
...
...
<see full output for more>
...
...
Aug 04 13:35:08 fedora abrt-notification[7924]: Process 4629 (cockpit-bridge) of user 1002 encountered an uncaught MemoryError exception
Aug 04 13:35:08 fedora abrt-server[7880]: Deleting problem directory Python3-2023-08-04-13:35:08-7846 (dup of Python3-2023-08-03-23:05:29-4629)
Aug 04 13:35:08 fedora systemd-logind[1732]: Removed session 12.
Aug 04 13:35:08 fedora systemd-logind[1732]: Session 12 logged out. Waiting for processes to exit.
Aug 04 13:35:08 fedora systemd[1]: session-12.scope: Deactivated successfully.
Aug 04 13:35:08 fedora audit[7785]: USER_END pid=7785 uid=0 auid=1002 ses=12 subj=system_u:system_r:cockpit_session_t:s0 msg='op=PAM:session_close grantors=pam_selinux,pam_loginuid,pam_selinux,pam_keyinit,pam_ssh_add,pam_keyinit,pam_limits,pam_systemd,pam_unix,pam_umask,pam_lastlog acct="virtual" exe="/usr/libexec/cockpit-session" hostname=fe80::278f:3155:4884:44e3%enp1s0f0 addr=fe80::278f:3155:4884:44e3 terminal=? res=success'
Aug 04 13:35:08 fedora cockpit-session[7785]: pam_unix(cockpit:session): session closed for user virtual
Aug 04 13:35:08 fedora audit[7785]: CRED_DISP pid=7785 uid=0 auid=1002 ses=12 subj=system_u:system_r:cockpit_session_t:s0 msg='op=PAM:setcred grantors=pam_localuser,pam_unix,pam_listfile acct="virtual" exe="/usr/libexec/cockpit-session" hostname=fe80::278f:3155:4884:44e3%enp1s0f0 addr=fe80::278f:3155:4884:44e3 terminal=? res=success'
Aug 04 13:35:08 fedora cockpit-ws[7846]: MemoryError
Aug 04 13:35:08 fedora cockpit-ws[7846]:                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     self.callback = sd.bus_message_handler_t(handler)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/_vendor/systemd_ctypes/bus.py", line 226, in __init__
Aug 04 13:35:08 fedora cockpit-ws[7846]:            ^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     slot = Slot(obj.message_received)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/_vendor/systemd_ctypes/bus.py", line 345, in add_object
Aug 04 13:35:08 fedora cockpit-ws[7846]:                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     self.exportees = [self.server.add_object(path, cls()) for path, cls in exports]
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/bridge.py", line 54, in <listcomp>
Aug 04 13:35:08 fedora cockpit-ws[7846]:                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     self.exportees = [self.server.add_object(path, cls()) for path, cls in exports]
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/bridge.py", line 54, in __init__
Aug 04 13:35:08 fedora cockpit-ws[7846]:                         ^^^^^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     self.internal_bus = InternalBus(EXPORTS)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/bridge.py", line 67, in __init__
Aug 04 13:35:08 fedora cockpit-ws[7846]:              ^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     router = Bridge(args)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/bridge.py", line 168, in run
Aug 04 13:35:08 fedora cockpit-ws[7846]:            ^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     return future.result()
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib64/python3.11/asyncio/base_events.py", line 653, in run_until_complete
Aug 04 13:35:08 fedora cockpit-ws[7846]:            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     return self._loop.run_until_complete(task)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib64/python3.11/asyncio/runners.py", line 118, in run
Aug 04 13:35:08 fedora cockpit-ws[7846]:            ^^^^^^^^^^^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     return runner.run(main)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib64/python3.11/asyncio/runners.py", line 190, in run
Aug 04 13:35:08 fedora cockpit-ws[7846]:     asyncio.run(main, debug=debug)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/_vendor/systemd_ctypes/event.py", line 109, in run_async
Aug 04 13:35:08 fedora cockpit-ws[7846]:     run_async(run(args), debug=args.debug)
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/lib/python3.11/site-packages/cockpit/bridge.py", line 283, in main
Aug 04 13:35:08 fedora cockpit-ws[7846]:              ^^^^^^
Aug 04 13:35:08 fedora cockpit-ws[7846]:     sys.exit(main())
Aug 04 13:35:08 fedora cockpit-ws[7846]:   File "/usr/bin/cockpit-bridge", line 8, in <module>
Aug 04 13:35:08 fedora cockpit-ws[7846]: Traceback (most recent call last):
Aug 04 13:35:08 fedora python3[7846]: detected unhandled Python exception in '/usr/bin/cockpit-bridge'
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F72756E2F757365722F313030322F233437202864656C6574656429 dev="tmpfs" ino=47 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F746D702F23313337202864656C6574656429 dev="tmpfs" ino=137 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F6465762F73686D2F2334202864656C6574656429 dev="tmpfs" ino=4 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F72756E2F757365722F313030322F233436202864656C6574656429 dev="tmpfs" ino=46 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F746D702F23313336202864656C6574656429 dev="tmpfs" ino=136 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F6465762F73686D2F2333202864656C6574656429 dev="tmpfs" ino=3 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { map } for  pid=7846 comm="cockpit-bridge" path=2F686F6D652F7669727475616C2F233230373338363736202864656C6574656429 dev="dm-0" ino=20738676 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_home_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F6465762F73686D2F2332202864656C6574656429 dev="tmpfs" ino=2 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F7661722F746D702F2331343739363939202864656C6574656429 dev="dm-0" ino=1479699 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F746D702F23313335202864656C6574656429 dev="tmpfs" ino=135 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:08 fedora audit[7846]: AVC avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F6D656D66643A6C6962666669202864656C6574656429 dev="tmpfs" ino=9259 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass=file permissive=0
Aug 04 13:35:07 fedora audit[7785]: CRED_REFR pid=7785 uid=0 auid=1002 ses=12 subj=system_u:system_r:cockpit_session_t:s0 msg='op=PAM:setcred grantors=pam_localuser,pam_unix,pam_listfile acct="virtual" exe="/usr/libexec/cockpit-session" hostname=fe80::278f:3155:4884:44e3%enp1s0f0 addr=fe80::278f:3155:4884:44e3 terminal=? res=success'
Aug 04 13:35:07 fedora audit[7785]: USER_START pid=7785 uid=0 auid=1002 ses=12 subj=system_u:system_r:cockpit_session_t:s0 msg='op=PAM:session_open grantors=pam_selinux,pam_loginuid,pam_selinux,pam_keyinit,pam_ssh_add,pam_keyinit,pam_limits,pam_systemd,pam_unix,pam_umask,pam_lastlog acct="virtual" exe="/usr/libexec/cockpit-session" hostname=fe80::278f:3155:4884:44e3%enp1s0f0 addr=fe80::278f:3155:4884:44e3 terminal=? res=success'
Aug 04 13:35:07 fedora cockpit-session[7785]: pam_unix(cockpit:session): session opened for user virtual(uid=1002) by (uid=0)
Aug 04 13:35:07 fedora systemd[1]: Started session-12.scope - Session 12 of User virtual.
...
...
<see full output for more>
```

If you need more information, let me know.
[1] https://access.redhat.com/documentation/de-de/red_hat_enterprise_linux/8/html/using_selinux/managing-confined-and-unconfined-users_using-selinux

Reproducible: Always

Steps to Reproduce:
1. create a user account with password and then confine the user account (I did this by making __default__ to "user_u", which makes any login "user_u" except those that are determined explicitly in a different way) -> e.g., "semanage login -a -s user_u __default__"
2. Go to cockpit web interface (I used Firefox) and try to login into cockpit with the confined user
3. The web interface will tell that credentials are wrong
4. Check the journalctl of root
5. Remove the confinement, log out and then log in again, or simply reboot (changed confinements needs a re-login to become active).
6. Test again without confinement: it will work.
Actual Results:  
The new version of cockpit cannot be used when SELinux is active within and among user accounts that are used by cockpit, which limits use cases and environments/infrastructures that can use cockpit.

Expected Results:  
The new version of cockpit should work with confined user accounts just like previous versions.

F38 KDE Spin. All up to date as of today. Only stable branches on the test system. cat /proc/sys/kernel/tainted = 0. No third party repositories.

Comment 2 Martin Pitt 2023-08-04 13:00:11 UTC
Thanks for your report! We already cover a restricted `user_u` login in our tests: https://github.com/cockpit-project/cockpit/blob/fabdc84b/test/verify/check-static-login#L457

However, that uses "semanage login -a -s user_u username", not the __default__ appraoch. perhaps this is slightly different. This also creates a brand new user, whereas possibly your user has existed for a while? Can you reproduce this with a newly created user as well?

Comment 3 Christopher Klooz 2023-08-04 13:49:31 UTC
I have just retested with __default__ being unconfined_u and the user I want to log into with cockpit being user_u. First, I tested with changing the existing user.

Then, I kept __default__ at unconfined_u and created a completely new user (virtual2) and did "semanage login -a -s user_u virtual2". The problem remains the same in all cases.

When setting __default__ to unconfined_u, I have always restarted both cockpit.service and cockpit.socket with systemctl to ensure that the accounts cockpit-ws* get the new confinement condition (is there maybe a consideration I have missed?).

> not the __default__ approach

This should not make a difference: if I log into an account with cockpit, only the confinement of this account should be relevant. SELinux behavior is equal if the "abc" account is user_u through mapping from __default__ or through mapping from "abc". If cockpit is itself working with an account, this should be likewise confined. If cockpit would need an account for itself that has to be unconfined (while being used by non-confined accounts), this would partly break the security concept. However, having tested successfully with __default__ being user_u when only the log-in-account was unconfined_u, this seems to be not the origin. So it seems that cockpit does not need any unconfined_u account for its processes.

It would be interesting to know if your tests behave different if you change in the tests "semanage login -a -s user_u username" to "semanage login -a -s user_u __default__"? My expectation is that "semanage login -a -s user_u username" and "semanage login -a -s user_u __default__" should behave the same because we know circumstances where __default__=user_u works (so, if the user account that is used to log in with cockpit is explicitly determined unconfined_u to be not mapped to __default__).

The account I am using to work (and from which I opened Firefox) is sysadm_u. But this works properly if the account in cockpit is unconfined_u, so I assume this is not related.

Can maybe the python error give us some hint?

Concerning the configuration of cockpit, the only modification in its configs that I have made is to add some accounts on the disallow list in /etc/cockpit (I just rechecked: none of the tested accounts are contained on the disallow list).

I will also play a bit and see if I can get more. If you need me to provide more information or test something, let me know.

Comment 4 Christopher Klooz 2023-08-04 14:13:22 UTC
I forgot: I have made my original tests also with an earlier kernel where I know for sure that I have used it already successfully with cockpit: 6.3.6 (now I am on 6.3.7). So the kernel is not the issue.

The last time I know for sure that cockpit worked properly was on 28st July according to my logs (I was using virtual machines in cockpit). Theoretically, any update in between could be the origin. It seems that the new cockpit was updated the same day, and the dnf updates started two minutes before the last log entry of my cockpit machines. So I guess the new cockpit has not been active back then since I did definitely no systemctl restart or so.

It might be noted that there are two other updates that are not cockpit-specific but that could be related: 
 selinux-policy              noarch     38.22-1.fc38          updates      50 k
 selinux-policy-targeted     noarch     38.22-1.fc38          updates     6.7 M

All updates that have been applied after I used cockpit the last time successfully can be seen below (I don't think that I did any other change to my system since then):
 cockpit                    x86_64     297-1.fc38             updates      41 k
 cockpit-bridge             x86_64     297-1.fc38             updates     545 k
 cockpit-networkmanager     noarch     297-1.fc38             updates     949 k
 cockpit-packagekit         noarch     297-1.fc38             updates     1.0 M
 cockpit-selinux            noarch     297-1.fc38             updates     482 k
 cockpit-storaged           noarch     297-1.fc38             updates     954 k
 cockpit-system             noarch     297-1.fc38             updates     3.7 M
 cockpit-ws                 x86_64     297-1.fc38             updates     927 k
 swtpm                      x86_64     0.8.0-5.fc38           updates      29 k
 swtpm-libs                 x86_64     0.8.0-5.fc38           updates      50 k
 swtpm-tools                x86_64     0.8.0-5.fc38           updates     115 k
 vim-data                   noarch     2:9.0.1677-2.fc38      updates      23 k
 vim-minimal                x86_64     2:9.0.1677-2.fc38      updates     796 k
Installing dependencies:
 swtpm-selinux              noarch     0.8.0-5.fc38           updates      20 k
-------------------
 kernel-*                   x86_64     6.4.7-200.fc38         updates-testing
 <kernel packages>
-------------------
 cmake-filesystem                        x86_64 3.27.1-1.fc38     updates  18 k
 dnf                                     noarch 4.16.2-1.fc38     updates 475 k
 dnf-automatic                           noarch 4.16.2-1.fc38     updates  44 k
 dnf-data                                noarch 4.16.2-1.fc38     updates  38 k
 dnf-plugins-core                        noarch 4.4.2-1.fc38      updates  38 k
 libdnf                                  x86_64 0.70.2-1.fc38     updates 670 k
 libgexiv2                               x86_64 0.14.2-1.fc38     updates  98 k
 libqalculate                            x86_64 4.7.0-1.fc38      updates 2.2 M
 m17n-db                                 noarch 1.8.3-1.fc38      updates 688 k
 m17n-lib                                x86_64 1.8.3-1.fc38      updates 197 k
 mariadb                                 x86_64 3:10.5.21-1.fc38  updates 1.6 M
 mariadb-backup                          x86_64 3:10.5.21-1.fc38  updates 6.5 M
 mariadb-common                          x86_64 3:10.5.21-1.fc38  updates  33 k
 mariadb-cracklib-password-check         x86_64 3:10.5.21-1.fc38  updates  13 k
 mariadb-embedded                        x86_64 3:10.5.21-1.fc38  updates 5.4 M
 mariadb-errmsg                          x86_64 3:10.5.21-1.fc38  updates 217 k
 mariadb-gssapi-server                   x86_64 3:10.5.21-1.fc38  updates  16 k
 mariadb-server                          x86_64 3:10.5.21-1.fc38  updates  11 M
 mariadb-server-utils                    x86_64 3:10.5.21-1.fc38  updates 216 k
 openssh                                 x86_64 9.0p1-17.fc38     updates 435 k
 openssh-clients                         x86_64 9.0p1-17.fc38     updates 698 k
 openssh-server                          x86_64 9.0p1-17.fc38     updates 450 k
 openssl                                 x86_64 1:3.0.9-2.fc38    updates 1.0 M
 openssl-libs                            x86_64 1:3.0.9-2.fc38    updates 2.1 M
 pipewire                                x86_64 0.3.76-1.fc38     updates 108 k
 pipewire-alsa                           x86_64 0.3.76-1.fc38     updates  63 k
 pipewire-gstreamer                      x86_64 0.3.76-1.fc38     updates  64 k
 pipewire-jack-audio-connection-kit      x86_64 0.3.76-1.fc38     updates  16 k
 pipewire-jack-audio-connection-kit-libs x86_64 0.3.76-1.fc38     updates 139 k
 pipewire-libs                           x86_64 0.3.76-1.fc38     updates 1.8 M
 pipewire-pulseaudio                     x86_64 0.3.76-1.fc38     updates 171 k
 pipewire-utils                          x86_64 0.3.76-1.fc38     updates 344 k
 python3-dnf                             noarch 4.16.2-1.fc38     updates 604 k
 python3-dnf-plugins-core                noarch 4.4.2-1.fc38      updates 299 k
 python3-hawkey                          x86_64 0.70.2-1.fc38     updates 106 k
 python3-libdnf                          x86_64 0.70.2-1.fc38     updates 826 k
 qpdf-libs                               x86_64 11.5.0-1.fc38     updates 928 k
 smartmontools                           x86_64 1:7.3-9.fc38      updates 600 k
 smartmontools-selinux                   noarch 1:7.3-9.fc38      updates  31 k
 xapian-core-libs                        x86_64 1.4.23-1.fc38     updates 771 k
 yum                                     noarch 4.16.2-1.fc38     updates  36 k
-------------------
cpp           x86_64      13.2.1-1.fc38        updates       11 M
libatomic     x86_64      13.2.1-1.fc38        updates       34 k
libgcc        x86_64      13.2.1-1.fc38        updates      109 k
libgomp       x86_64      13.2.1-1.fc38        updates      319 k
libobjc       x86_64      13.2.1-1.fc38        updates       59 k
libstdc++     x86_64      13.2.1-1.fc38        updates      863 k
-------------------
 podman                      x86_64     5:4.6.0-1.fc38        updates      14 M
 podman-gvproxy              x86_64     5:4.6.0-1.fc38        updates     5.0 M
 selinux-policy              noarch     38.22-1.fc38          updates      50 k
 selinux-policy-targeted     noarch     38.22-1.fc38          updates     6.7 M
-------------------
 firefox                 x86_64       116.0-2.fc38          updates        61 M
 firefox-langpacks       x86_64       116.0-2.fc38          updates        42 M
 firefox-wayland         x86_64       116.0-2.fc38          updates        23 k
 mkpasswd                x86_64       5.5.18-1.fc38         updates        26 k
 whois                   x86_64       5.5.18-1.fc38         updates        76 k
 whois-nls               noarch       5.5.18-1.fc38         updates        38 k
-------------------
 clevis-pin-tpm2        x86_64        0.5.3-1.fc38         updates        885 k
 gupnp                  x86_64        1.6.5-1.fc38         updates        105 k
-------------------
 autocorr-de                     noarch    1:7.5.5.2-1.fc38    updates     77 k
 autocorr-en                     noarch    1:7.5.5.2-1.fc38    updates    110 k
 cockpit-machines                noarch    295-1.fc38          updates    1.2 M
 ibus-typing-booster             noarch    2.23.2-1.fc38       updates    1.2 M
 libreoffice-calc                x86_64    1:7.5.5.2-1.fc38    updates    8.4 M
 libreoffice-core                x86_64    1:7.5.5.2-1.fc38    updates    121 M
 libreoffice-data                x86_64    1:7.5.5.2-1.fc38    updates    559 k
 libreoffice-draw                x86_64    1:7.5.5.2-1.fc38    updates     22 k
 libreoffice-graphicfilter       x86_64    1:7.5.5.2-1.fc38    updates    271 k
 libreoffice-gtk3                x86_64    1:7.5.5.2-1.fc38    updates    571 k
 libreoffice-gtk4                x86_64    1:7.5.5.2-1.fc38    updates    503 k
 libreoffice-help-de             x86_64    1:7.5.5.2-1.fc38    updates    3.7 M
 libreoffice-help-en             x86_64    1:7.5.5.2-1.fc38    updates    3.0 M
 libreoffice-impress             x86_64    1:7.5.5.2-1.fc38    updates    479 k
 libreoffice-kf5                 x86_64    1:7.5.5.2-1.fc38    updates    283 k
 libreoffice-langpack-de         x86_64    1:7.5.5.2-1.fc38    updates    915 k
 libreoffice-langpack-en         x86_64    1:7.5.5.2-1.fc38    updates     99 k
 libreoffice-ogltrans            x86_64    1:7.5.5.2-1.fc38    updates    169 k
 libreoffice-opensymbol-fonts    noarch    1:7.5.5.2-1.fc38    updates    150 k
 libreoffice-pdfimport           x86_64    1:7.5.5.2-1.fc38    updates    243 k
 libreoffice-pyuno               x86_64    1:7.5.5.2-1.fc38    updates    457 k
 libreoffice-ure                 x86_64    1:7.5.5.2-1.fc38    updates    2.3 M
 libreoffice-ure-common          x86_64    1:7.5.5.2-1.fc38    updates    1.6 M
 libreoffice-writer              x86_64    1:7.5.5.2-1.fc38    updates    3.8 M
 libreoffice-x11                 x86_64    1:7.5.5.2-1.fc38    updates    240 k
 librepo                         x86_64    1.15.2-1.fc38       updates     95 k
 nspr                            x86_64    4.35.0-9.fc38       updates    136 k
 nss                             x86_64    3.92.0-1.fc38       updates    695 k
 nss-softokn                     x86_64    3.92.0-1.fc38       updates    1.0 M
 nss-softokn-freebl              x86_64    3.92.0-1.fc38       updates    326 k
 nss-sysinit                     x86_64    3.92.0-1.fc38       updates     18 k
 nss-tools                       x86_64    3.92.0-1.fc38       updates    537 k
 nss-util                        x86_64    3.92.0-1.fc38       updates     86 k
 python-pip-wheel                noarch    22.3.1-3.fc38       updates    1.4 M
 python3-productmd               noarch    1.36-1.fc38         updates    101 k
 python3-regex                   x86_64    2023.6.3-1.fc38     updates    414 k
 xdg-desktop-portal-gnome        x86_64    44.2-1.fc38         updates    197 k
-------------------

Comment 5 Martin Pitt 2023-08-07 04:55:48 UTC
I'm testing this with a pristine Fedora 38 cloud image, with cockpit-{bridge,system,ws}-297-1.fc38.x86_64 -- i.e. not a build in our CI, but *the* Fedora packages.

Testing changing the default restriction mapping as you said:

# semanage login -a -s user_u __default__
ValueError: Login mapping for __default__ is already defined

# semanage login -m -s user_u __default__
libsemanage.validate_handler: MLS range s0-s0:c0.c1023 for Unix user __default__ exceeds allowed range s0 for SELinux user user_u (No such file or directory).
libsemanage.validate_handler: seuser mapping [__default__ -> (user_u, s0-s0:c0.c1023)] is invalid (No such file or directory).
libsemanage.dbase_llist_iterate: could not iterate over records (No such file or directory).
FileNotFoundError: No such file or directory

# semanage login -d -s user_u __default__
ValueError: Login mapping for __default__ is defined in policy, cannot be deleted

Meh, I'm too stupid to drive SELinux... How *exactly* did you change the default?

So in the meantime, going back to creating a new user with user_u. You already confirmed that the issue happens for you with that as well:

# useradd unpriv; echo 'unpriv:foobar' | chpasswd; semanage login -a -s user_u unpriv
# semanage login --list
__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
unpriv               user_u               s0                   *


This causes a lot of noise in the journal, as a lot of operations are restricted. For example:

  (tmpfiles)[1244]: systemd-tmpfiles-setup.service: Failed to locate executable systemd-tmpfiles: No such file or directory
  (tmpfiles)[1244]: systemd-tmpfiles-setup.service: Failed at step EXEC spawning systemd-tmpfiles: No such file or directory
  systemd[1231]: systemd-tmpfiles-setup.service: Main process exited, code=exited, status=203/EXEC

and also various SELinux denials:

systemd[1231]: selinux: avc:  denied  { status } for auid=1003 uid=1003 gid=1003 cmdline="/usr/bin/dbus-broker-launch --scope user" function="method_subscribe" scontext=user_u:user_r:user_dbusd_t:s0 tcontext=user_u:user_r:user_t:s0 tclass=system permissive=0
audit[1246]: AVC avc:  denied  { watch } for  pid=1246 comm="cockpit-bridge" path="/run/systemd" dev="tmpfs" ino=2 scontext=user_u:user_r:user_t:s0 tcontext=system_u:object_r:init_var_run_t:s0 tclass=dir permissive=0
audit[1246]: AVC avc:  denied  { watch } for  pid=1246 comm="cockpit-bridge" path="/var" dev="vda5" ino=269 scontext=user_u:user_r:user_t:s0 tcontext=system_u:object_r:var_t:s0 tclass=dir permissive=0
audit[1246]: AVC avc:  denied  { watch } for  pid=1246 comm="cockpit-bridge" path="/var" dev="vda5" ino=269 scontext=user_u:user_r:user_t:s0 tcontext=system_u:object_r:var_t:s0 tclass=dir permissive=0

but that's fine -- I still get a working cockpit session and no bridge crash. The current kernel is 6.4.6, quite a bit newer than your 6.3.7, but it's not very probable that this is the cause. `id -Z` in cockpit's terminal confirms "user_u:user_r:user_t:s0".

The denials that I *don't* get, but appear in your log, are things like these:

avc:  denied  { execute } for  pid=7846 comm="cockpit-bridge" path=2F72756E2F757365722F313030322F233437202864656C6574656429 dev="tmpfs" ino=47 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:user_tmp_t:s0 tclass

that's something that may have changed with the Python bridge. That "path=" looks like hex ASCII code for "/run/user/1002/#47 (deleted)". My "unpriv" user's runtime directory is mounted like this:

   tmpfs on /run/user/1003 type tmpfs (rw,nosuid,nodev,relatime,seclabel,size=109752k,nr_inodes=27438,mode=700,uid=1003,gid=1003,inode64)

perhaps you can compare? Is that mounted "noexec" for you by any chance? But perhaps it is an SELinux policy instead of a mount option -- the "user_exec_content boolean option" in your log hints to this. The default policy is "on":

# semanage boolean --list | grep user_exec_content
container_user_exec_content    (on   ,   on)  Allow container to user exec content
user_exec_content              (on   ,   on)  Allow user to exec content

And indeed I get your error after "semanage boolean --modify --off user_exec_content". An unrestricted user account still works, just the user_u one fails.

So I'm fairly sure that the relevant change on your system is just that.

I'll now check how to properly handle that MemoryError exception in the bridge.

Thanks!

Comment 6 Martin Pitt 2023-08-07 05:17:44 UTC
I started with the patch below, but this isn't an isolated thing -- *every* D-Bus operation fails with user_exec_content being off. It also doesn't help that SELinux responds with ENOMEM to all such denied calls, which is very misleading (what about good old EPERM?).

It feels to me that this is either due to how sd_bus itself works, or how Python's ctypes wraps C calls -- one of these seems to require user_exec_content in the user's $XDG_RUNTIME_DIR.

diff --git src/cockpit/bridge.py src/cockpit/bridge.py
index 806bf64eb..9cec94823 100644
--- src/cockpit/bridge.py
+++ src/cockpit/bridge.py
@@ -51,10 +51,17 @@ class InternalBus:
         client_socket, server_socket = socket.socketpair()
         self.client = bus.Bus.new(fd=client_socket.detach())
         self.server = bus.Bus.new(fd=server_socket.detach(), server=True)
-        self.exportees = [self.server.add_object(path, cls()) for path, cls in exports]
+        self.exportees = []
+        for path, cls in exports:
+            self.export(path, cls())
 
     def export(self, path: str, obj: bus.BaseObject) -> None:
-        self.exportees.append(self.server.add_object(path, obj))
+        try:
+            slot = self.server.add_object(path, obj)
+        except (OSError, MemoryError) as e:
+            logger.warning("Failed to export internal bus path %s: %s", path, str(e))
+            return
+        self.exportees.append(slot)
 
 
 class Bridge(Router, PackagesListener):
diff --git src/cockpit/internal_endpoints.py src/cockpit/internal_endpoints.py
index 6bc27d503..c92eb2647 100644
--- src/cockpit/internal_endpoints.py
+++ src/cockpit/internal_endpoints.py
@@ -128,7 +128,10 @@ class cockpit_Machines(bus.Object):
 
         # ignore the first callback
         self.pending_notify = ...
-        self.watch = pathwatch.PathWatch(str(self.path), self)
+        try:
+            self.watch = pathwatch.PathWatch(str(self.path), self)
+        except (OSError, MemoryError) as e:
+            logger.warning("Failed to set up watch for %s: %s", self.path, e)
         self.pending_notify = None

Comment 7 Christopher Klooz 2023-08-07 11:02:17 UTC
I'm currently much on the way and cannot test much. 

But concerning your question:

> How *exactly* did you change the default?

Check "semanage login -l" to see what accounts / mappings are regulated (which includes user accounts like "username", "virtual" and such, but also including the mapping "__default__" to which user accounts that are not explicitly regulated are mapped to). 

If you change the setting of an account that is already listed (=regulated), you use "-m", and if it is not yet listed/regulated, you use "-a".
E.g., if it is already listed with "-l": semanage login -m -s user_u username
E.g., if it is not yet listed with "-l": semanage login -a -s user_u username

However, you cannot delete __default__ because this is the condition for any account that is not explicitly regulated (otherwise, SELinux would not know what to do if an account logs in that is not explicitly regulated in the "-l" list). The default condition of __default__ is unconfined_u, which means there is no confinement at all. This means, if you want to disable confinement by default (which is also the default for Fedora), you do not delete __default__ but you change it to unconfined_u. 

So if I understand what you want to achieve, you have to REPLACE "semanage login -d -s user_u __default__" with "semanage login -m -s unconfined_u username" -> if you delete all explicitly regulated accounts while you set __default__ to unconfined_u, you have disabled confined user accounts at all. I think Fedora keeps by default root separated from __default__ (this means, by default you have both __default__ and root listed with "semanage login -l") so that root does not get accidentally confined (this can create a situation where people lock themselves out of the system).

Let me know if I misunderstood your goal or if something is unclear. Also let me know I shall test something on my side (I can dedicate some time to test by the end of the week).

Comment 8 Christopher Klooz 2023-08-07 11:10:54 UTC
> perhaps you can compare? Is that mounted "noexec" for you by any chance? But perhaps it is an SELinux policy instead of a mount option -- the "user_exec_content boolean option" in your log hints to this. The default policy is "on":

```
[username@fedora ~]$ cat /etc/mtab | grep tmpfs
...
...
...
tmpfs /tmp tmpfs rw,seclabel,nosuid,nodev,nr_inodes=1048576,inode64 0 0
tmpfs /run/user/1000 tmpfs rw,seclabel,nosuid,nodev,relatime,size=3157620k,nr_inodes=789405,mode=700,uid=1000,gid=1000,inode64 0 0
tmpfs /run/user/1001 tmpfs rw,seclabel,nosuid,nodev,relatime,size=3157620k,nr_inodes=789405,mode=700,uid=1001,gid=1001,inode64 0 0
```

I have not changed the defaults here (so, default of F38 KDE Spin). So there's no noexec in the tmpfs.

I can currently not check the condition of user_exec_content on the system, but I will check later and then let you know how this is set currently on my system. It is possible that I have changed the default of user_exec_content since I have modified some of the booleans there. I will check later also what F38 Workstation and F38 KDE have by default to check if I changed that.

Comment 9 Martin Pitt 2023-08-07 11:37:53 UTC
(In reply to Christopher Klooz from comment #7)

> > How *exactly* did you change the default?
> 
> Check "semanage login -l" to see what accounts [...]

For the record: This and the "noexec mount option" bits are not relevant any more, this was mostly me thinking aloud.

> I can currently not check the condition of user_exec_content on the system

This must be the cause. If it's not, then I'll throw away my hat and open a bar or something, because then what am I even doing here :-)

Comment 10 Christopher Klooz 2023-08-07 13:13:27 UTC
> For the record: This and the "noexec mount option" bits are not relevant any more, this was mostly me thinking aloud.
I am currently working much out of my email account, and I didn't see the mail of your second post when writing the first answer ;)

> This must be the cause. If it's not, then I'll throw away my hat and open a bar or something, because then what am I even doing here :-)

I am happy to tell you that you do not need to open a bar (although I would appreciate a good drink ;) -> user_exec_content seems to be indeed the origin.

The condition I have set on my system is:

```
[username@fedora ~]$ semanage boolean --list  | grep user_exec_content
...
user_exec_content              (off  ,  off)  Allow user to exec content
```

I have just had a minute at home to test: I changed user_exec_content from "off" to "on" and after that, I was able to log into cockpit and also to use my virtual machines. It seems that I have changed this value myself since the live images of KDE and Workstation have the value set to "on" by default.

So we found the SELinux boolean that causes the trouble...

However, the question is: Why did this work in the previous cockpit versions? And can we adjust the current version to work again with user_exec_content=="off" ?

This is not a serious security issue or so, but it reduces the use cases for the current version of cockpit because user_exec_content can be a powerful means to increase security or to satisfy corporate IT/security policies in several environments (and some environments with untrusted users might even depend on it).

------

If you choose to not consider user_exec_content=="off" in future versions, you might check if the documentation of RHEL needs to be adjusted (I don't know what the default value is in RHEL, and thus if it can cause trouble if RHEL 8 users update without adjusting the boolean if it is "off" by default).

In any case, thank you for taking care of this!

Comment 11 Martin Pitt 2023-08-07 14:16:35 UTC
> Why did this work in the previous cockpit versions? And can we adjust the current version to work again with user_exec_content=="off" ?

The bridge implementation changed from gdbus to sdbus, wrapped in Python's ctypes. Either of these seems to require exec permissions on the user's runtime directory. Indeed we should check if this can be salvaged -- but that will take a few weeks (holiday season and all). That's why I keep this bugzilla open, but it's not a "stop the line" urgency.

Comment 12 Christopher Klooz 2023-08-07 14:29:57 UTC
It would be cool if user_exec_content=="off" would work again future. But this is indeed not urgent.
 
Let me know if I can help with testing or so.

Have a nice holiday ;)

Comment 13 Christopher Klooz 2023-11-23 11:28:20 UTC
The issue seems to be solved: The cockpit login does now work again when I use credentials from a user account that is set to user_u while __default__ is also user_u. I have just worked again with virtual machines (cockpit-machines) in this condition: looks good. Only the account I am working in is still sysadm_u (as it was in the tests above). 

Solved.

My system is at the moment F39 KDE, up to date as of today with stable updates. Unfortunately, I have not tested this for some time, so I cannot say which stable update solved the issue.

Thanks for taking care :)

Comment 14 Christopher Klooz 2023-11-23 11:29:35 UTC
... of course the new test was with user_exec_content=="off"


Note You need to log in before you can comment on or make changes to this bug.