Bugzilla – Bug 1002
Interactive sudo removes newlines
Last modified: 2021-10-12 18:58:20 MDT
The following behavior, thought to be a bug in sudo, was noted on bug-bash mailing list, see thread https://lists.gnu.org/archive/html/bug-bash/2021-10/msg00012.html When passing parameters with embedded newlines to the normal sudo $ sudo echo 'foo bar' calls execve("/usr/bin/echo", ["echo", "foo\nbar"]…) and prints «foo bar» (as expected) However, when running with -i / --login the newline gets prepended with a backslash, which causes the newline to be removed by the shell $ sudo -i echo 'foo bar' calls execve("/bin/bash", ["-bash", "--login", "-c", "echo foo\\\nbar"],…) and thus prints «foobar» whereas the expected output was «foo bar» as in the earlier case. This was confirmed to still be the case with stock sudo-1.9.8p2 as provided by sudo.ws.
For "sudo -i", sudo escapes whitespace so it is preserved when the arguments are concatenated and run as shell -c "..." Another approach would be for sudo to run the command as follows: $ bash --login -c 'echo "$@"' echo 'foo > bar' foo bar That allows the arguments to be preserved as-is. Unfortuantely, that would break the existing support for interpreting shell variables in a "sudo -i" command (which was probably a mistake but is now hard to remove). It may be necessary to add a sudoers configuration option to control what characters are escaped in -i and -s mode.
Thanks, that explains why it is doing the backslashing. When faced with sudo -i echo "foo bar" since it is going to run bash --login -c "echo foo bar" that has to be bash --login -c "echo foo\ bar" so that both words are received in the first argument to echo. However, in the case of the newline it is removed when prepended with a backslash, even though it appears in IFS. Reviewing the standard for the exact specification, it says: « A backslash that is not quoted preserves the literal value of the following character, with the exception of a newline character. If a newline character follows the backslash, the shell will interpret this as line continuation. The backslash and newline characters will be removed before splitting the input into tokens. Since the escaped newline character is removed entirely from the input and is not replaced by any white space, it cannot serve as a token separator. » https://pubs.opengroup.org/onlinepubs/007908799/xcu/chap2.html#tag_001_002_001 So it's wrong to convert the "\n" into "\\\n" for preserving it. The issue is how to escape such newlines. It is also wrong not to escape it, as it would treat "bar" as a separate command. I would suggest replacing "\n" into "'\n'" (i.e. surround the newline with single quotes). That should preserve it, unless they are used for anything else in the command line it builds. I'm afraid I was unable to find the point where it performs the escaping to check this.