Bug 2112372

Summary: sudoing as sysadm_r still requires specifying "-r sysadm_r" parameter
Product: Red Hat Enterprise Linux 8 Reporter: Patrik Koncity <pkoncity>
Component: selinux-policyAssignee: Zdenek Pytela <zpytela>
Status: CLOSED NOTABUG QA Contact: BaseOS QE Security Team <qe-baseos-security>
Severity: medium Docs Contact:
Priority: low    
Version: 8.3CC: lvrabec, mmalik, ssekidde
Target Milestone: rcKeywords: Triaged
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: No Doc Update
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2023-02-02 16:44:28 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Patrik Koncity 2022-07-29 14:12:23 UTC
This bug was initially created as a copy of Bug #1910077

I am copying this bug because: 

The final decision is to not alter sudo code at all.
All known transitions which are missing will be backported to the selinux-policy.

Description of problem:

A sysadm user mapped to "sysadm_u" SELinux user and with "sysadm_r" role shouldn't have to specify "-r sysadm_r" to run an administrative command, as shown in the example below:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
$ id -Z
sysadm_u:sysadm_r:sysadm_t:s0-s0:c0.c1023

$ sudo dnf check-update
error: cannot open Packages database in /var/lib/rpm
Error: Error: rpmdb open failed

--> FAIL

$ sudo -r sysadm_r dnf check-update

--> SUCCESS
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------


Version-Release number of selected component (if applicable):

sudo-1.8.29-6.el8.x86_64


How reproducible:

ALWAYS

Steps to Reproduce:
1. Create a sysadm user

  # useradd -Z sysadm_u -G wheel sysadm_user
  # echo "sysadm_pass" | passwd sysadm_user --stdin
  # semanage boolean -m ssh_sysadm_login --on

2. Login as the sysadm user

  # ssh sysadm_user@localhost
  $ id -Z
  sysadm_u:sysadm_r:sysadm_t:s0-s0:c0.c1023

3. Execute admin command

  $ sudo dnf check-update

Actual results:

  error: cannot open Packages database in /var/lib/rpm
  Error: Error: rpmdb open failed

Expected results:

  Success

Additional info:

Digging into the code, I can see that selinux_execve() is called only when "-r <role>" argument is passed to the command.

-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
134 #define CD_RBAC_ENABLED         0x000800

206 /*
207  * Setup the execution environment and execute the command.
208  * If SELinux is enabled, run the command via sesh, otherwise
209  * execute it directly.
210  * If the exec fails, cstat is filled in with the value of errno.
211  */
212 void
213 exec_cmnd(struct command_details *details, int errfd)
214 {
 :
236 #ifdef HAVE_SELINUX
237         if (ISSET(details->flags, CD_RBAC_ENABLED)) {
238             selinux_execve(details->execfd, details->command, details->argv,
239                 details->envp, ISSET(details->flags, CD_NOEXEC));
240         } else
241 #endif
242         {
243             sudo_execve(details->execfd, details->command, details->argv,
244                 details->envp, ISSET(details->flags, CD_NOEXEC));
245         }
246     }
 :
250 }
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

WITHOUT "-r sysadm_r" (line 243, "sudo_execve"):
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
(gdb) bt
#0  sudo_execve (fd=-1, path=0x55c1573d0a08 "/bin/dnf", argv=0x55c1574031b8, envp=0x55c1574b2c20, noexec=false)
    at ./exec_common.c:191
#1  0x000055c155842a35 in exec_cmnd (details=details@entry=0x55c155a621e0 <command_details>, errfd=7) at ./exec.c:243
#2  0x000055c1558468e7 in exec_nopty (details=details@entry=0x55c155a621e0 <command_details>, 
    cstat=cstat@entry=0x7ffd1d2c4e80) at ./exec_nopty.c:401
#3  0x000055c155842f5c in sudo_execute (details=0x55c155a621e0 <command_details>, cstat=0x7ffd1d2c4e80)
    at ./exec.c:393
#4  0x000055c155851a3f in run_command (details=0x55c155a621e0 <command_details>) at ./sudo.c:957
#5  0x000055c155841772 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at ./sudo.c:301

(gdb) up
#1  0x000055c155842a35 in exec_cmnd (details=details@entry=0x55c155a621e0 <command_details>, errfd=7) at ./exec.c:243
243		    sudo_execve(details->execfd, details->command, details->argv,

(gdb) p/x details->flags
$2 = 0x22085

--> no CD_RBAC_ENABLED flag, hence normal sudo_execve()
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------


WITH "-r sysadm_r" (line 237, "selinux_execve"):
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
(gdb) bt
#0  selinux_execve (fd=-1, path=0x5566a977ca08 "/bin/dnf", argv=0x5566a97a8738, envp=0x5566a97b2610, noexec=false)
    at ./selinux.c:418
#1  0x00005566a79a08e3 in exec_cmnd (details=details@entry=0x5566a7bc01e0 <command_details>, errfd=7) at ./exec.c:238
#2  0x00005566a79a48e7 in exec_nopty (details=details@entry=0x5566a7bc01e0 <command_details>, 
    cstat=cstat@entry=0x7ffcca03b370) at ./exec_nopty.c:401
#3  0x00005566a79a0f5c in sudo_execute (details=0x5566a7bc01e0 <command_details>, cstat=0x7ffcca03b370)
    at ./exec.c:393
#4  0x00005566a79afa3f in run_command (details=0x5566a7bc01e0 <command_details>) at ./sudo.c:957
#5  0x00005566a799f772 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at ./sudo.c:301
(gdb) up
#1  0x00005566a79a08e3 in exec_cmnd (details=details@entry=0x5566a7bc01e0 <command_details>, errfd=7) at ./exec.c:238
238		    selinux_execve(details->execfd, details->command, details->argv,
(gdb) p/x details->flags
$1 = 0x22885

--> CD_RBAC_ENABLED flag, hence selinux_execve()
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------


Who sets CD_RBAC_ENABLED?
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
 633 /*
 634  * Convert a command_info array into a command_details structure.
 635  */
 636 static void
 637 command_info_to_details(char * const info[], struct command_details *details)
 638 {
 :
 849 #ifdef HAVE_SELINUX
 850     if (details->selinux_role != NULL && is_selinux_enabled() > 0)
 851         SET(details->flags, CD_RBAC_ENABLED);
 852 #endif
 853     debug_return;
 854 }
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------

The test on line 850 should likely be amended to retrieve the current role using the SELinux API.
The result would be to always execute selinux_execve() when SELinux is enabled.

If you believe the issue is within the SELinux policy instead (since role is already "sysadm_r"), then please redirect the BZ to selinux maintainers.

Comment 1 Zdenek Pytela 2023-01-04 14:19:16 UTC
After evaluating available resources, I am going to close also this bz unless some additional argument appears.

The recommended confined administrators setup is described in the "Confining an administrator using sudo and the sysadm_r role" chapter in the product documentation, Using SELinux:

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/using_selinux/managing-confined-and-unconfined-users_using-selinux#confining-an-administrator-using-sudo-and-the-sysadm_r-role_managing-confined-and-unconfined-users

or for particular domains administrators (e. g. webadm_r):
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/using_selinux/index#selinux-user-capabilities_managing-confined-and-unconfined-users

The policy only contains a limited subset of commands where there is an automated transition when sysadm_r role is used for a non-root user that subsequently uses sudo to get the root privileges.

See the attached kbase for workarounds.

Comment 2 Zdenek Pytela 2023-02-02 16:44:28 UTC
Closing the bz, see #c1 for the reasoning.