ash: dont allow e.g. exec <&10 to attach to stript's fd!
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 25 Jul 2008 13:34:05 +0000 (13:34 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 25 Jul 2008 13:34:05 +0000 (13:34 -0000)
function                                             old     new   delta
is_hidden_fd                                           -      61     +61
redirect                                            1135    1164     +29
popstring                                            134     140      +6
printf_main                                          635     637      +2
evalvar                                             1374    1376      +2
echo_main                                            294     296      +2
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 5/0 up/down: 102/0)             Total: 102 bytes

coreutils/echo.c
coreutils/printf.c
shell/ash.c

index 36cb6b3afc415631d16e269aa2d4d63b8254ba38..decca095f25fc1dfa4f92a299e8a183cb731ba20 100644 (file)
@@ -46,8 +46,11 @@ int echo_main(int argc UNUSED_PARAM, char **argv)
         * even if libc receives EBADF on write attempts, it feels determined
         * to output data no matter what. So it will try later,
         * and possibly will clobber future output. Not good. */
-       if (dup2(1, 1) != 1)
-               return -1;
+// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
+       if (fcntl(1, F_GETFL) == -1)
+               return 1; /* match coreutils 6.10 (sans error msg to stderr) */
+       //if (dup2(1, 1) != 1) - old way
+       //      return 1;
 
        arg = *++argv;
        if (!arg)
@@ -58,8 +61,8 @@ int echo_main(int argc UNUSED_PARAM, char **argv)
        char eflag = 0;
 
        /* We must check that stdout is not closed. */
-       if (dup2(1, 1) != 1)
-               return -1;
+       if (fcntl(1, F_GETFL) == -1)
+               return 1;
 
        while (1) {
                arg = *++argv;
index 72acbc7510d4f73dd956e03575e293e0f1b87930..76524f70648e6d1d66ffa47c81d5f97facb8e4a9 100644 (file)
@@ -348,8 +348,11 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
         * even if libc receives EBADF on write attempts, it feels determined
         * to output data no matter what. So it will try later,
         * and possibly will clobber future output. Not good. */
-       if (dup2(1, 1) != 1)
-               return -1;
+// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
+       if (fcntl(1, F_GETFL) == -1)
+               return 1; /* match coreutils 6.10 (sans error msg to stderr) */
+       //if (dup2(1, 1) != 1) - old way
+       //      return 1;
 
        /* bash builtin errors out on "printf '-%s-\n' foo",
         * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo".
index bd2433c8809ffe88c0f04449ee1d2e0aa012ff4b..11174683e7766ec2b8b799bce24e7c1effad45d5 100644 (file)
@@ -4889,7 +4889,7 @@ static int need_to_remember(struct redirtab *rp, int fd)
 {
        int i;
 
-       if (!rp) /* remebering was not requested */
+       if (!rp) /* remembering was not requested */
                return 0;
 
        for (i = 0; i < rp->pair_count; i++) {
@@ -4901,6 +4901,28 @@ static int need_to_remember(struct redirtab *rp, int fd)
        return 1;
 }
 
+/* "hidden" fd is a fd used to read scripts, or a copy of such */
+static int is_hidden_fd(struct redirtab *rp, int fd)
+{
+       int i;
+       struct parsefile *pf = g_parsefile;
+       while (pf) {
+               if (fd == pf->fd) {
+                       return 1;
+               }
+               pf = pf->prev;
+       }
+       if (!rp)
+               return 0;
+       fd |= COPYFD_RESTORE;
+       for (i = 0; i < rp->pair_count; i++) {
+               if (rp->two_fd[i].copy == fd) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 /*
  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
  * old file descriptors are stashed away so that the redirection can be
@@ -4950,8 +4972,15 @@ redirect(union node *redir, int flags)
        do {
                fd = redir->nfile.fd;
                if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
-                       if (redir->ndup.dupfd == fd)
-                               continue; /* redirect from/to same file descriptor */
+                       int right_fd = redir->ndup.dupfd;
+                       /* redirect from/to same file descriptor? */
+                       if (right_fd == fd)
+                               continue;
+                       /* echo >&10 and 10 is a fd opened to the sh script? */
+                       if (is_hidden_fd(sv, right_fd)) {
+                               errno = EBADF; /* as if it is closed */
+                               ash_msg_and_raise_error("%d: %m", right_fd);
+                       }
                        newfd = -1;
                } else {
                        newfd = openredirect(redir); /* always >= 0 */
@@ -4988,14 +5017,8 @@ redirect(union node *redir, int flags)
                                /* "exec fd>&-" should not close fds
                                 * which point to script file(s).
                                 * Force them to be restored afterwards */
-                               struct parsefile *pf = g_parsefile;
-                               while (pf) {
-                                       if (fd == pf->fd) {
-                                               i |= COPYFD_RESTORE;
-                                               break;
-                                       }
-                                       pf = pf->prev;
-                               }
+                               if (is_hidden_fd(sv, fd))
+                                       i |= COPYFD_RESTORE;
                        }
                        if (fd == 2)
                                copied_fd2 = i;
@@ -9026,7 +9049,7 @@ static int
 preadfd(void)
 {
        int nr;
-       char *buf =  g_parsefile->buf;
+       char *buf = g_parsefile->buf;
        parsenextc = buf;
 
 #if ENABLE_FEATURE_EDITING