How do I explicitly and safely force the use of a built-in command in bash
Olivier D is almost correct, but you must set POSIXLY_CORRECT=1
before running unset
. POSIX has a notion of Special Built-ins, and bash supports this. unset
is one such builtin. Search for SPECIAL_BUILTIN
in builtins/*.c
in the bash source for a list, it includes set
, unset
, export
, eval
and source
.
$ unset() { echo muahaha-unset; }
$ unset unset
muahaha-unset
$ POSIXLY_CORRECT=1
$ unset unset
The rogue unset
has now been removed from the environment, if you unset command
, type
, builtin
then you should be able to proceed, but unset POSIXLY_CORRECT
if you are relying on non-POSIX behaviour or advanced bash features.
This does not address aliases though, so you must use \unset
to be sure it works in interactive shell (or always, in case expand_aliases
is in effect).
For the paranoid, this should fix everything, I think:
POSIXLY_CORRECT=1
\unset -f help read unset
\unset POSIXLY_CORRECT
re='^([a-z:.\[]+):' # =~ is troublesome to escape
while \read cmd; do
[[ "$cmd" =~ $re ]] && \unset -f ${BASH_REMATCH[1]};
done < <( \help -s "*" )
(while
, do
, done
and [[
are reserved words and don't need precautions.)
Note we are using unset -f
to be sure to unset functions, although variables and functions share the same namespace it's possible for both to exist simultaneously (thanks to Etan Reisner) in which case unset-ing twice would also do the trick. You can mark a function readonly, bash does not prevent you unsetting a readonly function up to and including bash-4.2, bash-4.3 does prevent you but it still honours the special builtins when POSIXLY_CORRECT
is set.
A readonly POSIXLY_CORRECT
is not a real problem, this is not a boolean or flag its presence enables POSIX mode, so if it exists as a readonly you can rely on POSIX features, even if the value is empty or 0. You'll simply need to unset problematic functions a different way than above, perhaps with some cut-and-paste:
\help -s "*" | while IFS=": " read cmd junk; do echo \\unset -f $cmd; done
(and ignore any errors) or engage in some other scriptobatics.
Other notes:
function
is a reserved word, it can be aliased but not overridden with a function. (Aliasingfunction
is mildly troublesome because\function
is not acceptable as a way of bypassing it)[[
,]]
are reserved words, they can be aliased (which will be ignored) but not overridden with a function (though functions can be so named)((
is not a valid name for a function, nor an alias
I realize if someone controls your environment you're probably screwed anyway
Yes, that. If you run a script in an unknown environment, all manner of things can go wrong, starting with LD_PRELOAD
causing the shell process to execute arbitrary code before it even reads your script. Attempting to protect against a hostile environment from inside the script is futile.
Sudo has been sanitizing the environment by removing anything that looks like a bash function definition for over a decade. Since Shellshock, other environments that run shell script in a not-fully-trusted environment have followed suit.
You cannot safely run a script in an environment that has been set by an untrusted entity. So worrying about function definitions is not productive. Sanitize your environment, and in doing so variables that bash would interpret as function definitions.