Minor Rant: Linux, Scripts, and SetUID
You know the feeling when a system that you’ve used for years, and trusted, suddenly throws a curveball at you with a fun “Yeah you know this simple and concrete rule that’s never broken? Well in this one exception, it is, and nobody ever points it out. Have fun!”
So let’s set the stage.
You’re writing a blog.
This blog is kept in a Git repository.
“Great!” You think, knowing that you can make changes from any of your computers, and just git pull
on the server to bring everything down.
Because how NGINX works, you don’t need to reload anything, the new content is available immediately.
There’s just one problem: this means you need to SSH into the server to pull everything, which requires SSH into a border server first, tunneling your connection through another one.
While yes, a few tweaks to ~/.ssh
will make that work just fine, it’s still a bit of a pain.
Suddenly, an idea strikes you: cron
!
Set up a cron.hourly
task to cd
into the directory, run a git pull
, and then finally ask hugo
to rebuild the site.
To test this, you write a little shell script, give it +x
, and run.
Because you were planning to modify cron
files, you’re root
.
You try, and….
Error: add site dependencies: create deps: failed to create file caches from configuration: mkdir /tmp/hugo_cache/root: permission denied
That’s…. strange. Run from your user? Perfectly fine. Root? Error.
Then it hits you: Linux permission flags have two special bits: setuid
and setgid
.
setuid
will cause you to automatically assume the user that owns the file, and setgid
will do the same but for groups and group ownership.
So in theory, if your fictional user was named blog-update
, then chown blog-update update; chmod u+s update
would set setuid
on the update script, and designate blog-update
as the user that owns it… in theory, anyone who runs ./update
would assume the rights and permissions of blog-update
, right?
No. Try again, same error.
Debug time: add a whoami
to your script. What does it report? Why, root
of course.
If you weren’t already doing your best JonTron impression, you are now.
So… what gives?
Why setuid
and setgid
Aren’t as Useful as They Should Be
setuid
and setgid
do change your user and group ID, but with one major, and, in my research, unmentioned exception (until someone at StackOverflow had the answer… obviously): They do not work on scripts!
Yes, both bits work for compiled binary programs, such as fusermount
, umount
, su
, ping
(yes, ping
needs to be run as root), and so on.
Start your file with a #!/bin/sh
, make it a shell script, and as a security feature, the setuid
and setgid
bits are flat-out ignored. Lovely!
Now yes, in fairness, it does make sense. But either I’ve not been looking in the right places, or that information is so rare, that it really took a bit of head-scratching for me to even realize what was going on… after I googled the answer as to why.
But… The Solution?
I just made a cron
script as my user instead, problem solved.
Not super extravagant, but it works.