0

The setuid bit means if anyone executes the file, it runs as the owner of that file.

But let's say I, the owner, enable the setuid bit but disable execute rights for myself:

theowner@hostname:~$ echo "echo \"Running as user $(whoami)\"" > script.sh
theowner@hostname:~$ sudo chmod u=rs,go+x script.sh

The permissions for this file are now -r-Srwxr-x, see the upper case S for myself but x for group and others.

If I try to run the script, then I get as expected:

bash: ./script.sh: Permission denied

Because I do not have execute rights. If I did my permission bit would be s and not S with setuid set. But now let's say I su into another user account, someperson, and try running it now.

Running as user theowner

Why does it still let other users execute the script as theowner, when theowner is barred from executing the script?

  • Setuid is ignored on scripts in Linux. – muru Oct 4 '17 at 22:44
  • 1
    @muru Indeed, the same behavior is seen without setting the setuid bit. What the OP has observed happens on Ubuntu and other systems that use the Linux kernel (this not honoring setuid on text executables), with exactly the commands shown... because command substitution takes place inside double-quoted strings. The quoting mistake in the command used to created the script causes the name of the user who creates it to be hardcoded into the script. – Eliah Kagan Oct 4 '17 at 22:46
  • @EliahKagan figures. OP gets a known-good test for what they want to demonstrate and then mangles it. – muru Oct 4 '17 at 22:48
  • @muru Is your example using a binary? I am not familiar with cp $(which whoami) foo – AJJ Oct 4 '17 at 23:25
  • 2
    Oh I think I got it now, it's executing "which whoami" to get the path to the whoami binary, and copying that binary file to local foo so we have a local, independent copy of a binary to work with. – AJJ Oct 4 '17 at 23:46
4

The setuid bit has no effect whatsoever on scripts in Linux-based systems like Ubuntu. What you are observing is the result of a quoting mistake that you made while creating the script. Your script doesn't actually check who is running it. It has theowner hard-coded into it and always reports Running as user theowner regardless of which user it runs as. To confirm this, just check the contents of the script.

My username is ek. When I make your script and check its contents, I see:

$ echo "echo \"Running as user $(whoami)\"" > script.sh
$ cat script.sh
echo "Running as user ek"

That third line shows the contents of the script. The script is not determining ek programmatically by running. I haven't run it yet at all! The text ek appears in the script itself, just as the text theowner appears in yours.

I haven't changed permissions on the script. Here's what happens when I make it executable, then run it as myself (ek), then run it as a separate user (ek2). Note that this happens even when I don't set the setuid bit (and the output of ls -l reveals that it is not set).

$ chmod +x script.sh
$ ls -l script.sh
-rwxrwxr-x 1 ek ek 26 Oct  4 18:29 script.sh
$ ./script.sh
Running as user ek
$ su ek2 -c './script.sh'
Password:
Running as user ek

Why was $(whoami) evaluated rather than being preserved and written literally into your script? This is because command substitution, like parameter expansion and other expansions that triggered by $, is performed by your shell even inside double-quoted strings.

You can use single quotes instead to prevent this. Then you get:

$ echo 'echo "Running as user $(whoami)"' > script2.sh
$ cat script2.sh
echo "Running as user $(whoami)"
$ chmod +x script2.sh
$ ls -l script2.sh
-rwxrwxr-x 1 ek ek 33 Oct  4 18:39 script2.sh
$ ./script2.sh
Running as user ek
$ su ek2 -c './script2.sh'
Password:
Running as user ek2
$ chmod u=rs,go+x script2.sh
$ ls -l script2.sh
-r-Srwxr-x 1 ek ek 33 Oct  4 18:39 script2.sh
$ ./script2.sh
-bash: ./script2.sh: Permission denied
$ su ek2 --c './script2.sh'
Password:
Running as user ek2

Notice that the script still runs as ek2 because the operating system ignored the setuid bit, as it does on all scripts. The setuid and setgid bits are only honored on binary executables (and on directories, for which they do something altogether different).

  • The intended behavior still occurs on a binary, which still brings me to the same question – AJJ Oct 4 '17 at 23:35
  • @ArukaJ Yes, the other user would be able to run it, and it would run as the owner who cannot run it. Is that what you meant to ask in this question? If I understand that earlier question of yours correctly, it seems like I should post an answer about this behavior with binaries there, if I can explain it in a way that's not the same as the other answers that already exist (which I think I can). Or am I misunderstanding the purpose of that original question? – Eliah Kagan Oct 4 '17 at 23:39
  • "Is that what you meant to ask in this question" Yes. I don't understand why we can run as the owner who himself cannot run it. – AJJ Oct 4 '17 at 23:41
  • Your answer technically answers the current question (I messed up my script, and that's the cause of the output), but an answer on the other question would be welcome since that is what I was trying to understand. – AJJ Oct 4 '17 at 23:44
  • 1
    @ArukaJ I have to leave my keyboard very soon but I'll try to post an answer there when I get back. As far as this question goes, part of it is about " " quoting in the shell, but part of it is about the status of setuid/setgid scripts in Linux, which is an important topic too. So I think it's quite useful that this question exists, including to future readers, and even aside from maybe helping those who search about quoting problems. Of course I could be biased--I enjoyed writing this answer, after all, and one usually likes to imagine that one's posts are useful to a broad audience. :) – Eliah Kagan Oct 5 '17 at 0:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.