A user reports:

   I know this code is wrong but it shouldn't cause the shell to exit:
   echo text >&9999
   This instead cause the creation of a file:
   echo text >&9999999999

   I think it would be better if they report Bad file descriptor

The first case happens because save_fd_on_redirect() causes an exit
when dup_CLOEXEC() returns any error other than EBADF.  Despite its
name dup_CLOEXEC() actually uses fcntl(2) which returns EINVAL when
the file descriptor is greater than the maximum allowed.

The second case is due to any numeric string longer than nine digits
being treated as a file name rather than a number.  Bash doesn't
do this.

Treat a numeric string of any length as a number and limit the
range of valid file descriptors to the maximum determined by
calling getrlimit(2).

function                                             old     new   delta
fixredir                                               -     174    +174
readtoken1                                          3059    3069     +10
.rodata                                            99930   99916     -14
isdigit_str9                                          45       -     -45
expredir                                             225     177     -48
parsefname                                           206     157     -49
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 1/3 up/down: 184/-156)           Total: 28 bytes

Signed-off-by: Ron Yorston <r...@pobox.com>
---
 shell/ash.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index ef4a47afe..31ad03e47 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -535,10 +535,9 @@ static void trace_vprintf(const char *fmt, va_list va);
 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
 
 static int
-isdigit_str9(const char *str)
+isdigit_str(const char *str)
 {
-       int maxlen = 9 + 1; /* max 9 digits: 999999999 */
-       while (--maxlen && isdigit(*str))
+       while (isdigit(*str))
                str++;
        return (*str == '\0');
 }
@@ -9635,7 +9634,7 @@ expredir(union node *n)
                                if (fn.list == NULL)
                                        ash_msg_and_raise_error("redir error");
 #if BASH_REDIR_OUTPUT
-                               if (!isdigit_str9(fn.list->text)) {
+                               if (!isdigit_str(fn.list->text)) {
                                        /* >&file, not >&fd */
                                        if (redir->nfile.fd != 1) /* 123>&file 
- BAD */
                                                ash_msg_and_raise_error("redir 
error");
@@ -11945,19 +11944,21 @@ static void
 fixredir(union node *n, const char *text, int err)
 {
        int fd;
+       struct rlimit limit;
 
        TRACE(("Fix redir %s %d\n", text, err));
        if (!err)
                n->ndup.vname = NULL;
 
+       getrlimit(RLIMIT_NOFILE, &limit);
        fd = bb_strtou(text, NULL, 10);
-       if (!errno && fd >= 0)
+       if (!errno && fd >= 0 && fd < limit.rlim_cur - 1)
                n->ndup.dupfd = fd;
        else if (LONE_DASH(text))
                n->ndup.dupfd = -1;
        else {
                if (err)
-                       raise_error_syntax("bad fd number");
+                       raise_error_syntax(strerror(EBADF));
                n->ndup.vname = makename();
        }
 }
@@ -12640,7 +12641,7 @@ readtoken1(int c, int syntax, char *eofmark, int 
striptabs)
                if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + 
'>'))
                 && quotef == 0
                ) {
-                       if (isdigit_str9(out)) {
+                       if (isdigit_str(out)) {
                                PARSEREDIR(); /* passed as params: out, c */
                                lasttoken = TREDIR;
                                return lasttoken;
-- 
2.35.1
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to