Bug 1672447 - sudo is resetting the real user id in the process tables
Summary: sudo is resetting the real user id in the process tables
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: sudo
Version: rawhide
Hardware: All
OS: Unspecified
unspecified
low
Target Milestone: ---
Assignee: Marek Tamaskovic
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2019-02-05 00:06 UTC by Thomas Walker Lynch
Modified: 2019-04-01 09:08 UTC (History)
6 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2019-04-01 09:08:35 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Thomas Walker Lynch 2019-02-05 00:06:55 UTC
Description of problem:  Note the man page for the pam login module, https://linux.die.net/man/8/pam_loginuid  It says "You should not use it for applications like sudo or su as that defeats the purpose by changing the loginuid to the account they just switched to." And there is good reason for this, as otherwise there is no reliable method for finding the real user id.  Currently people appear to be using environment variables, but those can be changed by programs or scripts after sudo is called (but not before, as sudo resets them).


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


How reproducible:
completely


Steps to Reproduce:
1. enter this program:
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>

int main(){
  int uid = getuid();
  int euid = geteuid();
  printf("real_id: %u effective_id: %u\n",uid,euid);
  return 0;
}

2. compile it:
gcc -o real_id real_id.cc

3. run it from a shell:

> ./real_id
real_id: 49972 effective_id: 49972

4. now run it with sudo:
> sudo ./real_id
real_id: 0 effective_id: 0

Actual results:

real_id: 0 effective_id: 0

The real_id is reset, and there is no way to reliably get the information back because it is gone from the OS process table.


Expected results:
real_id: 49972 effective_id: 0
here the processes real id remains the processes real id

Additional info:
When a program runs as root, there is no way to reliably distinguish if it is natively run, or if it has been invoked by a user land shell through sudo.  Say for example, program1 calls program2.   Userland calls program 1 via sudo:
sudo program1.   Then program1 calls program2.  Program1 might be poorly written where it does not pass its environment to program2, or it might be subtly malicious and change environment variables.  program2 might then mistakenly believe it is root native run root program, instead of a userland invoked program.  Furthermore, it can be the case, that a user land person sets the variables, for example SUDO_USER=whoever  and then calls program2 but not through sudo.  If program2 relies on the environment variables it might assume that it is running under sudo when it is not.  Perhaps then it makes a mess and crashes when it gets to the part where it really needs to be root.

Comment 1 Thomas Walker Lynch 2019-02-05 11:11:58 UTC
This affects applications that desire to provide a service to a specified user, particularly those that are called by programs that have been called by sudo. The question within such a program will be 'which user?'. As noted above this question can be perhaps be reliably answered by examining the SUDO_USER variable in the target program called by sudo, I'm not really sure as the environment variable passing system was not designed to be bullet proof (?), but demonstrably not in secondary programs that sudo target program calls.  

Note, however, setuid root programs do preserve the real id.  

-r-sr-x---. 1 root     morpheus 18440 Feb  5 11:47 real_id_suid_root

Where this is the same program as given in the bug report above, runs as:
> ./real_id_suid_root
real_id: 49972 effective_id: 0

Which is the expected behavior.

People have suggested instead using getlogin(3) or programs that call it,  but that is based on utmp, as the manpage notes,  https://linux.die.net/man/3/getlogin, "
Unfortunately, it is often rather easy to fool getlogin()."  Others have suggested reading other log files that have similar problems.  All of this because the real id is missing.  In addition because setuid root programs function as expected, even if such a solution was found, another sudo target program that calls such a program would not know to use this workaround.  (Once the real id is lost, it remains lost to all children processes.)

Perhaps one solution is to say that a program run by sudo should never call a service that needs to know who the user who it is providing the service for really is.  That would be really tough rule for programmers to verify. In addition, today, because the real id has been reset to user, any such program will assume that it is providing the service for root.  That is a bad thing.  It has surely already happened that root data has been affected by this.

Comment 2 Thomas Walker Lynch 2019-02-13 15:42:23 UTC
This looks to be a manifestation of this bug.  Here is the output of a setuid script that outputs sss_cache errors because the program thinks it is not root.  I.e. it is examining the realid that sudo has reset, instead of examining the effective id which determines if it has root privilege. Testers using sudo will not see the problem.

sss_cache must be run as root
useradd: sss_cache exited with status 1
useradd: Failed to flush the sssd cache.
sss_cache must be run as root
useradd: sss_cache exited with status 1
useradd: Failed to flush the sssd cache.

The source code for the setuid root program that calls useradd with fork/exec/wait may be found here:
https://github.com/Reasoning-Technology/subu/tree/master/try/useradd_probs

Comment 3 Thomas Walker Lynch 2019-02-13 16:22:36 UTC
this calls sss_cache directly instead of invoking it through useradd:
https://github.com/Reasoning-Technology/subu/tree/master/try/sss_cache_probs

> make clean
> make
> sudo ./setuid_root.sh
> ./sss_cache
Checking we are running from a user and are setuid root.
uid 49972, gid 49972, euid 0 egid 49972
yes, uid is not zero, and euid is zero, so we are setuid to the root user.
dispatching sss_cache -U to clear users
dispatching:
arg: 0x7ffdbebdf6f0 /usr/sbin/sss_cache
arg: 0x7ffdbebdf6f8 -U

/usr/sbin/sss_cache must be run as root  <----- error issued by sss_cache
sss_cache failed

Comment 4 Marek Tamaskovic 2019-03-21 09:50:34 UTC
I see your point but if you add stay_setuid in sudoers it is behaving like you intended.

here is man sudoers:

 stay_setuid
Normally, when sudo executes a command the real and effective UIDs are set to the target user (root by default).  This option changes that behavior such that the real UID is left as invoking user's UID.  In other words, this makes sudo act as a setuid wrapper.  This can be useful on systems that disable some potentially dangerous functionality when a program run setuid.  This option is only effective on systems that support either the setreuid(2) or setresuid(2) system call.  This flag is off by default.

Comment 5 Thomas Walker Lynch 2019-03-21 15:37:17 UTC
There are some serious disadvantages to resetting the real UID, some are described in posts above, and it is also noted in the first post that the author of the pam login module man page warns administrators not to do it.  So this begs the question:  what is it that sudo is buying here by resetting the real UID and losing that information, that is of such value that it overwhelms the disadvantages?
It can't be part of giving processes run under it different permissions because the effective UID does that. 

That there is an option that I can set on my system to change this behavior is a local convenience, but that doesn't help with sharing code that requires real UID information. That covers a large class of programs that need reliable information on who they are providing services for.  Unfortunately the alternative mechanism is not secure, that of using environment variables.  Many people are using that method. So that is a second problem.

Comment 7 Thomas Walker Lynch 2019-03-22 08:38:46 UTC
It was a lot of work documenting this. Do we just wave our hands and ignore the warnings in the pam docs. Can you not provide a single reason for this behavior before closing this?


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