2

In the course of working on a way to (safely) load assignments from configuration files, I am trying to come up with a shell function that would:

  • With arbitrary string received as first argument, apply safe expansions (i.e. variable expansions, ${} expansions...) but block any unsafe expansion (including if nested in other constructs).
  • Assign the result to the variable name received as second argument (the variable name can be assumed safe for the purpose of this question)
  • Preferably be pure shell (Bash-specific is OK for me), but a proposal using an external command would be ok if it provides better results, does not degrade performance too much and depends on utilities normally present on the basic install of UNIX-like operating systems.
  • Perform the expansion while getting rid of "first level" quotes, like the shell would do.

Here is an example (assuming function safeval meeting the above, and already loaded in current context) :

export A=1
safeval '$A$(ls /)' B
echo "$B"      # Echoes 1$(ls /)
safeval '"a""b"' C
echo "$C"      # Echoes ab
Fred
  • 6,590
  • 9
  • 20
  • With the exception of accepting a 2nd argument - which is easily added - [this](http://stackoverflow.com/a/29268513/45375) answer of mine we've [previously discussed](http://stackoverflow.com/a/42328711/45375) satisfies your requirements (except that you wanted to look into replacing `tr` calls with shell parameter expansions). – mklement0 Feb 20 '17 at 12:18
  • 1
    @123 I do not think sourcing would meet my safety requirement. – Fred Feb 20 '17 at 12:19
  • @mklement0 I will provide an answer inspired from your answer above, but that does not do the exact same thing. Please bear with me. – Fred Feb 20 '17 at 12:20
  • Sounds good, but please add any additional requirements to your question. – mklement0 Feb 20 '17 at 12:22
  • @mklement By the way, trying to avoid `tr` in your previous answer is one thing I am trying to avoid if possible. – Fred Feb 20 '17 at 12:27

1 Answers1

0

Following a previous question I asked ( Reading assignments from configuration files) and an answer with comments by mklement0 which led me to mklemen0's answer on this question : Bash Templating: How to build configuration files from templates with Bash?, I came up with a potential solution on which I am looking for feedback, especially as to its safety and potential failure modes I might have missed.

#
# Argument 1 : string to safely expand
# Argument 2 : name of the variable to which expanded value will be assigned
#
safeval()
{
local _v=$1
_v=${_v//\$\(/\$$'\1'}
_v=${_v//\$\[/\$$'\2'}
_v=${_v//'`'/$'\3'}
_v=${_v//\\ /$'\4'}
_v=${_v// /$'\5'}
eval printf -v _v %b "$_v" || return 1
_v=${_v//$'\1'/\(}
_v=${_v//$'\2'/\[}
_v=${_v//$'\3'/'`'}
_v=${_v//$'\4'/\\ }
_v=${_v//$'\5'/ }
printf -v "$2" %s "$_v"
}

Please note that this (should, I think) handle discontinuous quoting in the string supplied (e.g. '"a"b"c" on input would be assigned as abc).

This code aims to do the following :

  • Remplace all occurrences of $(, '$[' and ` with (hopefully) safe strings.
  • Then perform eval
  • Then revert back
  • Do it only with shell features

There are a few avoidable assignments which I kept in the answer for readability purposes and I would remove in the final code. I would also probably redirect stderr of the first printf to /dev/null.

I used %b as a string format for printf to allow things like newlines in the configuration files. Comment as to whether this is a good or bad idea are welcome.

Community
  • 1
  • 1
Fred
  • 6,590
  • 9
  • 20
  • Even if the answer solves the problem, IMHO, the code is much suitable in codereview SE and not here. – Inian Feb 20 '17 at 12:39
  • @Inian I have added a question on codereview : http://codereview.stackexchange.com/questions/155842/safe-and-restricted-version-of-eval?noredirect=1#comment295051_155842. Thanks for the tip. – Fred Feb 20 '17 at 18:50