13

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?

2 Answers 2

14

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"
1
  • Other things to consider that might have an impact on the behavior of that command: current working directory, and what stdin, stdout, stderr point to, signal handlers and ulimits. For instance, by allowing core dumps (upon <kbd>Ctrl-\</kbd>), you could allow the user to litter /run/lock which on my system is a tmpfs with very limited size and could allow a DoS. Jan 5, 2013 at 21:25
5

You should match the passed input against known a good pattern.

For example, it looks like an IP address might be valid input for you. So you could use something like this:

if [[ "$1" =~ ^[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9].[0-9]?[0-9]?[0-9]$ ]]
then
  udhcpc -b -i eth0 -h "$1"
else
  echo "Don't mess with me pork chop."
fi

Note, that regexp hasn't been tested, you're responsible for making sure your regexp doesn't allow anything dangerous.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .