[PATCH 4/6] eval: Avoid crash when redirecting to file descriptor in expredir
From: Bernhard Übelacker When trying to redirect output to a filedescriptor contained in an environment variable, but if that variable is empty, dash crashes with a segmentation fault. To reproduce, run the following: echo test >&$EMPTY_VARIABLE Signed-off-by: Andrej Shadura Bug-Debian: https://bugs.debian.org/861354 --- src/eval.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/eval.c b/src/eval.c index 6185db4..ee43fa9 100644 --- a/src/eval.c +++ b/src/eval.c @@ -516,6 +516,7 @@ expredir(union node *n) for (redir = n ; redir ; redir = redir->nfile.next) { struct arglist fn; + fn.list = NULL; fn.lastp = switch (redir->type) { case NFROMTO: @@ -530,6 +531,8 @@ expredir(union node *n) case NTOFD: if (redir->ndup.vname) { expandarg(redir->ndup.vname, , EXP_FULL | EXP_TILDE); + if (!fn.list) + sh_error("ambiguous redirect"); fixredir(redir, fn.list->text, 1); } break; -- 2.17.1
[PATCH 3/6] mkbuiltins: Default to mktemp, not tempfile
Don't use tempfile, as it currently runs tempnam(), which is insecure and fails under pseudo(1). Signed-off-by: Andrej Shadura --- src/mkbuiltins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mkbuiltins b/src/mkbuiltins index b4d6f4e..f1f2593 100644 --- a/src/mkbuiltins +++ b/src/mkbuiltins @@ -35,7 +35,7 @@ # # @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 -tempfile=tempfile +tempfile=mktemp if ! type tempfile > /dev/null 2>&1 && ! type mktemp > /dev/null 2>&1; then _my_tempfile() { -- 2.17.1
[PATCH 1/6] exec: Don't execute binary files if execve() returned ENOEXEC.
From: Adam Borowski Both "dash -c foo" and "./foo" are supposed to be able to run hashbang-less scripts, but attempts to execute common binary files tend to be nasty: especially both ELF and PE tend to make dash create a bunch of files with unprintable names, that in turn confuse some tools up to causing data loss. Thus, let's read the first line and see if it looks like text. This is a variant of the approach used by bash and zsh; mksh instead checks for signatures of a bunch of common file types. POSIX says: "If the executable file is not a text file, the shell may bypass this command execution." Signed-off-by: Adam Borowski Signed-off-by: Andrej Shadura --- src/exec.c | 32 1 file changed, 32 insertions(+) diff --git a/src/exec.c b/src/exec.c index 9d0215a..631 100644 --- a/src/exec.c +++ b/src/exec.c @@ -148,6 +148,36 @@ shellexec(char **argv, const char *path, int idx) } +/* + * Check if an executable that just failed with ENOEXEC shouldn't be + * considered a script (wrong-arch ELF/PE, junk accidentally set +x, etc). + * We check only the first line to allow binaries encapsulated in a shell + * script without proper quoting. The first line, if not a hashbang, is + * likely to contain comments; even ancient encodings, at least popular + * ones, don't use 0x7f nor values below 0x1f other than whitespace (\t, + * \n, \v, \f, \r), ISO/IEC 2022 can have SI, SO and \e. + */ +STATIC int file_is_binary(const char *cmd) +{ + char buf[128]; + int fd = open(cmd, O_RDONLY|O_NOCTTY); + if (fd == -1) + return 1; + int len = read(fd, buf, sizeof(buf)); + close(fd); + for (int i = 0; i < len; ++i) { + char c = buf[i]; + if (c >= 0 && c <= 8 || + c >= 16 && c <= 31 && c != 27 || + c == 0x7f) + return 1; + if (c == '\n') + return 0; + } + return 0; +} + + STATIC void tryexec(char *cmd, char **argv, char **envp) { @@ -162,6 +192,8 @@ repeat: execve(cmd, argv, envp); #endif if (cmd != path_bshell && errno == ENOEXEC) { + if (file_is_binary(cmd)) + return; *argv-- = cmd; *argv = cmd = path_bshell; goto repeat; -- 2.17.1
Debian patches for dash
Hi, I’m submitting the patches we’ve had applied to dash in Debian for some time. I have rewritten the patch descriptions to include more information from the bug reports to make sure commit messages make more sense and help understand the purpose of the changes. I hope you find those patches useful and apply them upstream. Thanks! -- Cheers, Andrej
[PATCH 5/6] eval: Report I/O error on stdout
From: Gerrit Pape ENOSPC as a result of an echo builting failing gives no diagnostic. Just as other shells, dash sets $? to 1, but aside from terminating the script, this does not inform the user what the problem is: zsh: % echo foo > /dev/full echo: write error: no space left on device bash: $ echo foo > /dev/full bash: echo: write error: No space left on device dash: $ echo foo > /dev/full [nothing] Print an error to stderr like the other shells. Suggested by Roger Leigh. Signed-off-by: Gerrit Pape [reworded the patch description with information from the bug] Signed-off-by: Andrej Shadura Bug-Debian: http://bugs.debian.org/690473 --- src/eval.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/eval.c b/src/eval.c index ee43fa9..231d3e0 100644 --- a/src/eval.c +++ b/src/eval.c @@ -955,6 +955,8 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags) else status = (*cmd->builtin)(argc, argv); flushall(); + if (outerr(out1)) + warnx("%s: I/O error", commandname); status |= outerr(out1); exitstatus = status; cmddone: -- 2.17.1
[PATCH 2/6] printf: Support \e in "echo" and "printf" builtins.
From: Adam Borowski dash's builtin version of printf doesn't support '\e' (escape), and literaly outputs the 2 characters as-is. As is well known, this sequence is useful, for example, when outputting ANSI escape sequences. While it seems that POSIX does not require that printf support '\e', it is still worth implementing '\e' support, as a way to make the environment more consistent and avoid this small issue when porting scripts from certain other systems or when migrating from bash to dash. Signed-off-by: Adam Borowski [reworded the patch description] Signed-off-by: Andrej Shadura Bug-Debian: http://bugs.debian.org/816295 --- src/bltin/printf.c | 1 + src/dash.1 | 4 2 files changed, 5 insertions(+) diff --git a/src/bltin/printf.c b/src/bltin/printf.c index 7785735..9b878da 100644 --- a/src/bltin/printf.c +++ b/src/bltin/printf.c @@ -340,6 +340,7 @@ conv_escape(char *str, int *conv_ch) case '\\': value = '\\'; break; /* backslash */ case 'a': value = '\a'; break; /* alert */ case 'b': value = '\b'; break; /* backspace */ + case 'e': value = '\e'; break; /* escape */ case 'f': value = '\f'; break; /* form-feed */ case 'n': value = '\n'; break; /* newline */ case 'r': value = '\r'; break; /* carriage-return */ diff --git a/src/dash.1 b/src/dash.1 index 32f6ac0..b286f79 100644 --- a/src/dash.1 +++ b/src/dash.1 @@ -1201,6 +1201,8 @@ Subsequent output is suppressed. This is normally used at the end of the last argument to suppress the trailing newline that .Ic echo would otherwise output. +.It Li \ee +Outputs an escape character (ESC). .It Li \ef Output a form feed. .It Li \en @@ -1570,6 +1572,8 @@ The characters and their meanings are as follows: Write a \*[Lt]bell\*[Gt] character. .It Cm \eb Write a \*[Lt]backspace\*[Gt] character. +.It Cm \ee +Write an \*[Lt]escape\*[Gt] (ESC) character. .It Cm \ef Write a \*[Lt]form-feed\*[Gt] character. .It Cm \en -- 2.17.1