3

With sudo, it is possible to execute a command as an other user and really safely pass arguments to that command.

Example nasty argument:

nastyArg='"double quoted" `whoami` $(whoami) '"'simple quoted "'$(whoami)'"'" 

Expected output, run via a termninal as congelli501:

 % echo "$nastyArg" "double quoted" `whoami` $(whoami) 'simple quoted $(whoami)' 

Execute as congelli501, via sudo:

 # sudo -u congelli501 -- echo "$nastyArg" "double quoted" `whoami` $(whoami) 'simple quoted $(whoami)' 

Execute as congelli501, via su (usual escape method):

 # su congelli501 -c "echo '$nastyArg'" "double quoted" `whoami` $(whoami) simple quoted congelli501 

As you can see, the argument is not safely passed as it is re-interpreted by a shell.

Is there a way to launch a command via su and pass its arguments directly, as you can do with sudo ?

2 Answers 2

7

Passing the command as the shell script argument in su seems to work:

 # su congelli501 -s "$(which echo)" -- "$nastyArg" "'another arg'" "double quoted" `whoami` $(whoami) 'simple quoted $(whoami)' 'another arg' 

Example usage:

# Safely execute a command as an other user, via su # # $1 -> username # $2 -> program to run # $3 .. n -> arguments function execAs() { user="$1"; shift cmd="$1"; shift su "$user" -s "$(which -- "$cmd")" -- "$@" } execAs congelli501 echo "$nastyArg" "'another arg'" 
Sign up to request clarification or add additional context in comments.

Comments

1

The fundamental problem here is that you are trying to nest quotes. You would hope su -c "stuff "with" double "quotes" to be parsed as |su|, |-c|, |stuff "with" double "quotes"| but it actually gets parsed as |su|, |-c|, |stuff |, |with|, | double|, |quotes| where however the last four tokens are pasted together as one string after evaluation (notice the spaces where the "inner" quotes terminated the ostensible "outer" quotes instead of wrapping inside them).

Within double quotes, `whoami` gets expanded by the shell before anything gets passed to su.

What you can do instead is either (a) add yet more quoting around the values in $nastyArg (pretty much doomed) or (b) define it in the context of the shell executed by su. A distinct third option is to (c) pass in the value in a way which disarms it, such as on standard input.

printf '%s\n' "$nastyArg" | su -c 'cat' congelli501 

This may seem overtly simplistic, but is really the way to go when you do not have complete trust over what will possibly be evaluated by root somehow.

This is one of the reasons sudo is preferred over su.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.