setuid on an executable doesn't seem to work
Asked Answered
F

3

8

I wrote a small C utility called killSPR to kill the following processes on my RHEL box. The idea is for anyone who logs into this linux box to be able to use this utility to kill the below mentioned processes (which doesn't work - explained below).

cadmn@rhel /tmp > ps -eaf | grep -v grep | grep " SPR "  
cadmn    5822  5821 99 17:19 ?        00:33:13 SPR 4 cadmn  
cadmn   10466 10465 99 17:25 ?        00:26:34 SPR 4 cadmn  
cadmn   13431 13430 99 17:32 ?        00:19:55 SPR 4 cadmn  
cadmn   17320 17319 99 17:39 ?        00:13:04 SPR 4 cadmn  
cadmn   20589 20588 99 16:50 ?        01:01:30 SPR 4 cadmn  
cadmn   22084 22083 99 17:45 ?        00:06:34 SPR 4 cadmn  
cadmn@rhel /tmp >  

This utility is owned by the user cadmn (under which these processes run) and has the setuid flag set on it (shown below).

cadmn@rhel /tmp > ls -l killSPR  
-rwsr-xr-x 1 cadmn cusers 9925 Dec 17 17:51 killSPR  
cadmn@rhel /tmp > 

The C code is given below:

/*  
 * Program Name: killSPR.c  
 * Description: A simple program that kills all SPR processes that  
 * run as user cadmn  
 */  
#include <stdio.h>  
int main()  
{  
    char *input;  
    printf("Before you proceed, find out under which ID I'm running. Hit enter when you are done...");  
    fgets(input, 2, stdin);  

    const char *killCmd = "kill -9 $(ps -eaf | grep -v grep | grep \" SPR \" | awk '{print $2}')";  
    system(killCmd);  
    return 0;  
} 

A user (pmn) different from cadmn tries to kill the above-mentioned processes with this utility and fails (shown below):

pmn@rhel /tmp > ./killSPR  
Before you proceed, find out under which ID I'm running. Hit enter when you are done...  
sh: line 0: kill: (5822) - Operation not permitted  
sh: line 0: kill: (10466) - Operation not permitted  
sh: line 0: kill: (13431) - Operation not permitted  
sh: line 0: kill: (17320) - Operation not permitted  
sh: line 0: kill: (20589) - Operation not permitted  
sh: line 0: kill: (22084) - Operation not permitted  
pmn@rhel /tmp >  

While the user waits to hit enter above, the process killSPR is inspected and is seen to be running as the user cadmn (shown below) despite which killSPR is unable to terminate the processes.

cadmn@rhel /tmp > ps -eaf | grep -v grep | grep killSPR  
cadmn   24851 22918  0 17:51 pts/36   00:00:00 ./killSPR  
cadmn@rhel /tmp >

BTW, none of the main partitions have any nosuid on them

pmn@rhel /tmp > mount | grep nosuid
pmn@rhel /tmp >

The setuid flag on the executable doesn't seem to have the desired effect. What am I missing here? Have I misunderstood how setuid works?

Formfitting answered 17/12, 2013 at 7:31 Comment(5)
is there a reason this couldn't just be a shell script with 777 permissions instead of a compiled binary?Stowaway
@Stowaway - A shell script with perms 777 won't work. Here's why - If the user pmn invoked this script, the ensuing process would run as user pmn who doesn't have privileges to kill the processes that are run as user cadmn (unless you are the root, you cannot kill processes that are run by others). BTW, setting setuid flag on scripts won't work either: setuid on scripts that are written in one of the shell languages are ignored by the system as a safety feature. Hence the need for this to be a compiled program. Hope this answers your question.Formfitting
I understand user rights and restrictions of Linux/Unix systems, I'm asking why you're trying to do this through a C program (which has the same limitations if run as a separate user in a separate login) given the code you've posted .. you're simply calling a system command from a C program, which has the same effect as calling the same command (kill in your program) through a shell script. Instead what it sounds like you're doing is wanting to give 'service like control' to a particular program to non-root users...if that's correct please rephrase your questionStowaway
Yes, I wanted to give normal users the privileges to kill any "SPR" process running as user cadmn. Anyway, @Grzegorz suggested using exec instead of system which apparently drops the setuid effect. I'll try this out and reply back.Formfitting
How is the SPR program started, by another user manually, automagically, through a startup script? .. User rights on Linux apply to ALL applications being run (it does not matter if they are in a shell script or C/C++/Java program), if a user does not have rights to do a certain action, there is no way (aside from a privilege escalation bug/attack) for that user to do that action. A 'service' or daemon gives a user the ability to 'control' it (to an extent) even though it doesn't have user rights to do so (again, to an extent...)Stowaway
R
7

First and foremost, setuid bit simply allows a script to set the uid. The script still needs to call setuid() or setreuid() to run in the the real uid or effective uid respectively. Without calling setuid() or setreuid(), the script will still run as the user who invoked the script.

Avoid system and exec as they drop privileges for security reason. You can use kill() to kill the processes.

Check These out.

http://linux.die.net/man/2/setuid

http://man7.org/linux/man-pages/man2/setreuid.2.html

http://man7.org/linux/man-pages/man2/kill.2.html

Rhinoceros answered 19/12, 2013 at 17:27 Comment(2)
Thank you. setreuid did the trick (though, setuid did not work). Nonetheless, the behavior is not consistent and here's why: The exact scenario, that had failed to work on the RHEL box, worked without setuid or setreuid on Mint XFCE 15 that runs as a VM on my home PC!Formfitting
The difference between setuid() and setreuid() is the ownership of the file. For files using setuid(), it has to be owned by root and setid bit. In the code setuid() can then switch to any uid including root. In your case you want to setuid() to cadmn. Should you want the file to be owned by cadmn, setuid() will not work but setreuid() will. This is probably what you did. The man page for setuid() and setreuid() discussed this difference.Rhinoceros
R
4

You should replace your system call with exec call. Manual for system say's it drops privileges when run from suid program.

The reason is explained in man system:

Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might be used to subvert system integrity. Use the exec(3) family of func‐ tions instead, but not execlp(3) or execvp(3). system() will not, in fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2 drops privileges on startup. (Debian uses a modified bash which does not do this when invoked as sh.)

If you replace system with exec you will need to be able to use shell syntax unless you call /bin/sh -c <shell command>, this is what is system actually doing.

Ravo answered 17/12, 2013 at 8:21 Comment(4)
Oh, I see. Let me try this and get back to you.Formfitting
exec has the same user restrictions as system .. in other words, if userX does not have permissions to read/write/execute anything in folder /blahsy/blah then a C call to system/exec('ls -l /blahsy/blah') would give an operation not permitted error because userX does not have permission to that folder .. if you did this instead though system('sudo ls -l /blahsy/blah'), it might be a different storyStowaway
Hmm, then it looks like I've misunderstood the powers of setuid. Can you give me a scenario where I can use setuid?Formfitting
@Formfitting No, you didn't misunderstood the powers of setuid, it's just the shell that drops privileges for security reasons.Fickle
S
2

Check out this link on making a shell script a daemon:

Best way to make a shell script daemon?

You might also want to google some 'linux script to service', I found a couple of links on this subject.

The idea is that you wrap a shell script that has some basic stuff in it that allows a user to control a program run as another user by calling a 'service' type script instead. For example, you could wrap up /usr/var/myservice/SPRkiller as a 'service' script that could then just be called as such from any user: service SPRkiller start, then SPRkiller would run, kill the appropriate services (assuming the SPR 'program' is run as a non-root user).

This is what it sounds like you are trying to achieve. Running a program (shell script/C program/whatever) carries the same user restrictions on it no matter what (except for escalation bugs/hacks).

On a side note, you seem to have a slight misunderstanding of user rights on Linux/Unix as well as what certain commands and functions do. If a user does not have permissions to do a certain action (like kill the process of another user), then calling setuid on the program you want to kill (or on kill itself) will have no effect because the user does not have permission to another users 'space' without super user rights. So even if you're in a shell script or a C program and called the same system command, you will get the same effect.

http://www.linux.com/learn/ is a great resource, and here's a link for file permissions

hope that helps

Stowaway answered 17/12, 2013 at 9:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.