Bash – How to safely pass variables to root-enabled scripts

bashparameterSecurityshell-scriptsudo

This question is totally general and not only applicable to my situation, but… I have a small busybox appliance where I want a non-root user to be able to execute a particular script with root priviliges. For example, something like this small script to enable DHCP, where the only variable ($1) to send in on the cmdline (!!) is what host name to send out:

#!/bin/bash
udhcpc -b -i eth0 -h $1

running udhcpc like this requires root access, so to do this I plan on modifying /etc/sudoers to contain this line:

joe ALL = NOPASSWD: /path/to/enable_dhcp.sh

which should enable "joe" to easily run that script with root privileges by simply running:

sudo /path/to/enable_dhcp.sh

and not being asked for a password (which is what I want, since I want joe to be able to script this).

Now.. I know (or at least think I do) that using $1 in a script that can easily be run with root privileges is a HORRIBLE idea since you can inject whatever you want into that.

So… what is the best way to deal with this? How do I let joe do what I want with root privileges, allow him to pass in a variable (or effectively do so like with an environment variable), while not being wide open to injection attacks?

Best Answer

Running shell scripts under sudo is safe provided that sudo is configured to reset the environment. Conversely, if sudo doesn't reset the environment, then running a shell script is not safe, even if your script doesn't use its parameters (see Allow setuid on shell scripts). Make sure that you have Defaults env_reset in /etc/sudoers or that this option is the compile-time default (sudo sudo -V | grep env should include Reset the environment to a default set of variables).

There is no particular danger in using the script parameters. $1 is a string, all you need to make sure is that you're using it as a string. (For example, don't do eval "$1".) Obviously, it's especially important here not to make assumptions about the contents of the variable, and to put double quotes around all variable substitutions (i.e. write "$1", not $1). Note that putting double quotes around variable substitutions isn't specific to scripts running with privileges, it's something you must do all the time.

You may want to validate the parameter further, depending on what udhcpc does with something that doesn't look like a host name. For example, this will perform a first syntactic check:

#!/bin/sh
case "$1" in
  *[!:-.0-9A-Za-z]*|-*) echo 1>&2 "Badly formed host name!"; exit 3;;
esac
udhcpc -b -i eth0 -h "$1"
Related Question