Setuid not working in Linux as script fails to write to file.

Hi,

I have the following 3 test files to test setuid bit which if it works I would like to implement in our application. However setuid doesnot seem to be having any impact on my test below.Following are the 3 files of interest in /tmp/ folder.

[usl20010097 tmp]$ ls -ltr *env*
-rw------- 1 g332008 users 6 Jun 25 17:31 mainoutputfile.txt
-rwxr-x--x 1 cddsuat cddsuat 38 Jun 25 17:51 subscript.ksh
-rwsr-xr-x 1 g332008 users 51 Jun 25 17:53 mainscript.ksh

As you can see /tmp/subscript.ksh
is owned by user cddsuat. It invokes /tmp/mainscript.ksh
and has the following contents:

-bash-3.2$ cat subscript.ksh
#!/usr/bin/ksh
/tmp/mainscript.ksh

/tmp/mainscript.ksh has the following contents:
[usl20010097 tmp]$ cat mainscript.ksh
#!/usr/bin/ksh
echo "hello" >> /tmp/mainoutputfile.txt

Based on the above, setuid bit has been set for owner on /tmp/mainscript.ksh. This means that when /tmp/subscript.ksh invokes /tmp/mainscript.ksh, /tmp/mainscript.ksh runs as the owner of /tmp/mainscript.ksh which is g332008 rather than user cddsuat. So /tmp/mainscript.ksh should be able to write "hello" to the file /tmp/mainoutputfile.txt which is owned by g332008. However when I run /tmp/subscript.ksh I get the following error with respect to write permission on /tmp/mainoutputfile.txt.

-

bash-3.2$ ./subscript.ksh
/tmp/mainscript.ksh[2]: /tmp/mainoutputfile.txt: cannot create [Permission denied]

Please advise why do I get the above permission error even though /tmp/mainscript.ksh has setuid bit set so that any other user invoking this script would be able to run this script as the owner of /tmp/mainscript.ksh. Your advise is much appreciated.

thanks

  1. most ksh insist in safe mode
#!/usr/bin/ksh -p
  1. Linux does not support suid scripts. You need to write and compile a binary helper, or use an existing helper like sudo .

I didnot know that setuid is not supported by Linux.
But I noticed that the /usr/bin/passwd binary has setuid set on Linux. Similarly ping program also has setuid bit set on Linux.
How is that possible if Linux doesnot support setuid. ALso how will the passwd command write to /etc/shadow if setuid is not supported on Linux. Also how come I saw the rwsr-xr-x permission on the /usr/bin/passwd executable ?
Please throw some light.

thanks

---------- Post updated at 12:48 AM ---------- Previous update was at 12:36 AM ----------

My objective is for an environment file which has database passwords in it NOT to be readable by the anybody logging as the application user but at the same time the script which uses these passwords must be able to execute some script and read these passwords and use the passwords for running its internal database sqls'. I was thinking of making the environment file owner as root with no read permission to the application userid so that nobody can view the passwords and then use setuid bit on the support script which when called by the main script is able to fetch these passwords as it runs as root user. But since setuid is not supported by Linux I will not be able to make the password file non-readable owned by root and be able to execute some setuid script that can fetch the passwords from this root owned password file.
Any suggestions on an alternative way to achieve this would be highly welcome ?

thanks

your example setuid files are binaries and not scripts btw ...

as for your issue ... (not advisable but an option nonetheless) ...

  1. create generic database admin user like "sqadmin"
  2. set sqadmin $HOME permissions to 700
  3. write sqluser password into sqadmin's $HOME/.sqlpass
  4. chmod 500 $HOME/.sqlpass
  5. run crypt on $HOME/.sqlpass
  6. in sqadmin's script, uncrypt $HOME/.sqlpass to read password and then recrypt
  7. continue processing of sqadmin script

It'd be better to use sudo for this... Allow users to run said script and only said script as another user. (Does NOT need to be root. More secure if it is not, in case someone exploits a bug in your script.)

Yes it does, but you have to consider the filesystem it is in though. Many installations only allow SUID scripts in OS filesystems (/, /bin, /sbin, /usr/bin depending how you have them mounted) and as such you may find that /home (or wherever) is mounted with that disabled.

Change to the directory where the script is and do the following:-

df -k .
grep "filesystem name" /etc/fstab

Remember to escape the forward slash in the grep command, e.g.

grep "\/my\/filesystem" /etc/fstab

What do you have in the fourth column? Actually, post the whole line.

Robin
Liverpool/Blackburn
UK

Your analysis of the situation is incorrect, rbatte.

While you are correct that mount options can forbid suid binary executables (and even non-suid executables), linux does not support suid interpreted script executables, regardless of mount options.

Regards,
Alister

---------- Post updated at 02:06 PM ---------- Previous update was at 12:04 PM ----------

In case anyone is interested, a more detailed explanation.

Relevant functions from the 3.9.7 stable kernel:
fs/exec.c :: do_execve_common()
fs/exec.c :: prepare_binprm()
fs/exec.c :: search_binary_handler()
fs/binfmt_script.c :: load_script()

Linux can support many executable formats. Each format has a dedicated handler registered with the kernel. When loading an executable, the execve syscall must first identify the format of the executable. This is accomplished in search_binary_handler by walking the list of registered handlers until one of them succeeds. If none succeed, the system call fails.

This procedure can occur more than once. A typical, successful shell script execve requires two passes. The first pass ends with the success of load_script, the handler that recognizes the #! shebang header. This handler parses the interpreter's pathname from the shebang line and uses it to begin the second pass. Usually, the interpreter is a native binary (e.g. sh, awk, perl, etc), in which case this second handler search concludes with load_elf_binary.

The kernel calls prepare_binprm before each pass.

prepare_binprm resets the effective uid and gid to match that of the current process (execve's caller), before checking the inode of the executable it intends to load. If the inode's mode has a SUID/SGID bit set, then the euid/egid for the to-be-loaded executable is set to match the inode uid/gid (incidentally, rbatte, this is also where the NOSUID mount option check is located).

The first prepare_binprm call is in do_execve_common and involves the SUID shell script executable. The second call is in load_script and involves the interpreter pathname.

Between the two calls to prepare_binprm, the relevant data structure actually has the shell script owner's credentials, as if the kernel intends to allow the change in ownership. However, the second prepare_binprm invocation (just as the first) resets the euid/egid values to those of the current process. The shell script's inode's SUID/SGID change is clobbered and this time prepare_binprm consults the interpreter's inode, not the shell script's.

Regards,
Alister

1 Like

This is a frequent argument on this forum.

It does not. Period.

I used to think all UNIX shared this behavior, but it's not quite that stark. Some do and some don't.

1 Like

Thanks for the clarification folks

Thanks for the info, but to try and explore it myself I wrote three scripts that pass control along. I set the middle one as SUID and then a funny thing happened when I edited the file. The server crashed! :eek:

Undeterred, I tried again, same result (good thing it's not production :rolleyes:)

I own the files thus:-

$ cd ~/unix229213
$ ls -l
total 12
-rwxrwxrwx 1 RBATTE1 techsupp 65 Jun 27 10:13 scr_a.ksh
-rwsrwxrwx 1 RBATTE1 techsupp 66 Jun 27 10:14 scr_b.ksh
-rwxrwxrwx 1 RBATTE1 techsupp 52 Jun 27 10:15 scr_c.ksh

It seems that whenever I write the file, the server crashes. The very simple code runs find, but if I try to sudo chown root scr_b.ksh the server crashes. I can issue the sudo chown if it's not SUID at the time. The filesystem allows SUID, by the way.

What on earth can an un-privileged user be doing wrong :confused:

Naturally, I'm very concerned that a mis-key by someone else may cause them to get an error on the habitual chmod 777 and run chmod 7777 and then editing the file will cause a server crash. The crash happens when actually writing the file. I haven't tried it with a simple redirect yet - I don't want to crash the server yet again!

Output from uname gives me a RHEL version of 2.6.32-279.14.1.el6.x86_64

Robin

That bug is new to me, must be related to ext4!
I only know about the "everyone can become root" bug around kernel.perf_event.

In what way did it crash? Anything in the logs?

Server went unresponsive. The console was not connected, so nothing there. Looking in /var/log/messages, I have these from this morning:-

Jun 27 03:23:34 dlvmrhdliv01 rhsmd: This system is registered to RHN Classic
Jun 27 09:15:19 dlvmrhdliv01 sshd[31219]: Accepted password for RBATTE1 from 129.221.180.234 port 1940 ssh2
Jun 27 09:15:19 dlvmrhdliv01 sshd[31219]: pam_unix(sshd:session): session opened for user RBATTE1 by (uid=0)
Jun 27 09:32:38 dlvmrhdliv01 kernel: imklog 5.8.10, log source = /proc/kmsg started.
Jun 27 09:32:38 dlvmrhdliv01 rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="1961" x-info="http://www.rsyslog.com"] start
Jun 27 09:32:38 dlvmrhdliv01 kernel: Initializing cgroup subsys cpuset
Jun 27 09:32:38 dlvmrhdliv01 kernel: Initializing cgroup subsys cpu
Jun 27 09:32:38 dlvmrhdliv01 kernel: Linux version 2.6.32-279.14.1.el6.x86_64 (mockbuild@x86-002.build.bos.redhat.com) (gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) ) #1 SMP Mon Oct 15 13:44:51 EDT 2012
Jun 27 09:32:38 dlvmrhdliv01 kernel: Command line: ro root=/dev/mapper/vg_rhel63x64-lv_root rd_NO_LUKS  KEYBOARDTYPE=pc KEYTABLE=uk LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_rhel63x64/lv_swap rd_LVM_LV=vg_rhel63x64/lv_root rd_NO_DM rhgb quiet
Jun 27 09:32:38 dlvmrhdliv01 kernel: KERNEL supported cpus:
Jun 27 09:32:38 dlvmrhdliv01 kernel:  Intel GenuineIntel
Jun 27 09:32:38 dlvmrhdliv01 kernel:  AMD AuthenticAMD
Jun 27 09:32:38 dlvmrhdliv01 kernel:  Centaur CentaurHauls
Jun 27 09:32:38 dlvmrhdliv01 kernel: Disabled fast string operations

..... and then off further into the boot.

I have another test server that should be at the same versions, and it doesn't exhibit this behaviour. Suspicion lies with the replication software that is under test on the one that crashed. Don't panic anyone else, unless you are running (I think it's called) RHA from CA. I will pass this on to the person running that project. Maybe I will just take your word for it and keep quiet.

Robin



Further testing has shown that this is linked to the replication software under evaluation.  I think that this, along with other hangs/crashes will end that evaluation process.


Robin

it was good the issue was mentioned ... keeping quiet about it does not help anybody ...

if the replication job is the actual culprit and this replication job is deemed fit to be released for production installs into every critical server, not letting anybody else know about the potential for a server crash when doing a simple find from a setuid script could be catastrophic to the environment and goes against what i believe are the duties and responsibilities of a system administrator ... any risks to the supported computing environment should be mitigated as soon as known and not hidden ...

at the least, the company should know about the bug and ensure there are safeguards against it ... it would also help the vendors of the replication software to know this so they can actually fix the issue ...

now the general computing community also benefits ...

Just Ice,

Inline with your suggestion d I came up with a way to encrypt the file using gpg (GNU Privacy guard) and then decrypting it.
'
(1) First encrypt it using the below command which generates a binary encrypted file.

echo "some passphrase" |gpg --passphrase-fd 0 --output <full path of output encrypted file> --symmetric <full path of input file>

(2) Then delete the readable flat file

(3) Within my scripts, decrypt the encrypted environment file using
echo "above passphrase" |gpg --passphrase-fd 0 --output <full path of output decrypted file> --decrypt <full path of input encrypted file>

(4) Source the resulting decrypted flat file and read all variables defined in it and immediately delete it within the script.

With this approach nobody would be able to view the flat file as at any point there will only be an encrypted binary file in the file system.
However the caveat with this approach to hiding DB passwords in the env file from developers is that is that developers need to remember the passphrase to use with GPG.If they have access to passphrase anybody can decrypt the encrypted file.

Can you please suggest a mechanism to read the passphrase from somewhere so that nobody can actually see the passphrase but should be able to use it to encrypt and decrypt the envronment file without any problems ?

thanks

if you have to have the passphrase, put it in a file in a protected directory (i.e., /home/sqadmin/.sqlpp) that is source in the beginning of the script as far away as the line sourcing the password and hidden within comments if you could do it ...

#! /bin/ksh
# jhkjhkhfkljhfkljhlkjh
. /home/sqadmin/.sqlpp #hgjhgjhghkhkjhkjhk
# kljhkjhkljhkljfhsklljljlj;lkj;lkj;lkj;l
# kjlkjdflkj;lkj;lkj;lkjk;k;'k;'lk;'k;l
# llkjlj;lkjlkj;lkjlkj;lkj;lj;lkj;lkjl;kjlk
# lkj;lkj;lkj;lkjlkjlkj;lj;lkjl;kjlkjlkjl
# lkj;lkjl;kjlkjjlkj;ljlkj;lkjljljlkjlkjljj

script=$0
admin=admin@some.com
log=/dir/log
password=$get_sql_pass
date=$(date +%Y%m%d)

.......
.......
......

exit 0

. . . . . Deleted . . . . .

No, we cannot. If the script can decrypt it, so can anyone examining the script, since by necessity it contains complete instructions for doing so.

You could PPK encrypt it using someone's public key, so only their private key can decode it. The private key is usually in a user-only-readable file 0400. Of course, root can peek!

This nicely protects the public key, but I don't see how this prevents any access to the encrypted file. Same problem as before again. If the script can access the private key, so can they, if the script can decrypt the file from it so can they.