Author: kevans
Date: Wed Aug  8 21:21:28 2018
New Revision: 337504
URL: https://svnweb.freebsd.org/changeset/base/337504

Log:
  apply(1): Fix magic number substitution with magic character ' '
  
  Using a space as the magic character would result in problems if the command
  started with a number:
  
  - For a 'valid' number n, n < size of argv, it would erroneously get
    replaced with that argument; e.g. `apply -a ' ' -d 1rm x => `execxrm x`
  
  - For an 'invalid' number n, n >= size of argv, it would segfault.
    e.g. `apply -a ' ' 2to3 test.py` would try to access argv[2]
  
  This problem occurred because apply(1) would prepend "exec " to the command
  string before doing the actual magic number replacements, so it would come
  across "exec 2to3 1" and assume that the " 2" is also a magic number to be
  replaced.
  
  Re-work this to instead just append "exec " to the command sbuf and
  workaround the ugliness. This also simplifies stuff in the process.
  
  PR:           226948
  Submitted by: Tobias Stoeckmann <tob...@stoeckmann.org>
  MFC after:    1 week

Modified:
  head/usr.bin/apply/apply.c

Modified: head/usr.bin/apply/apply.c
==============================================================================
--- head/usr.bin/apply/apply.c  Wed Aug  8 21:19:07 2018        (r337503)
+++ head/usr.bin/apply/apply.c  Wed Aug  8 21:21:28 2018        (r337504)
@@ -55,7 +55,8 @@ __FBSDID("$FreeBSD$");
 #include <string.h>
 #include <unistd.h>
 
-#define EXEC   "exec "
+#define ISMAGICNO(p) \
+           (p)[0] == magic && isdigit((unsigned char)(p)[1]) && (p)[1] != '0'
 
 static int     exec_shell(const char *, const char *, const char *);
 static void    usage(void);
@@ -65,8 +66,9 @@ main(int argc, char *argv[])
 {
        struct sbuf *cmdbuf;
        long arg_max;
-       int ch, debug, i, magic, n, nargs, offset, rval;
+       int ch, debug, i, magic, n, nargs, rval;
        size_t cmdsize;
+       char buf[4];
        char *cmd, *name, *p, *shell, *slashp, *tmpshell;
 
        debug = 0;
@@ -75,7 +77,7 @@ main(int argc, char *argv[])
        while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
                switch (ch) {
                case 'a':
-                       if (optarg[1] != '\0')
+                       if (optarg[0] == '\0' || optarg[1] != '\0')
                                errx(1,
                                    "illegal magic character specification");
                        magic = optarg[0];
@@ -105,7 +107,7 @@ main(int argc, char *argv[])
         * largest one.
         */
        for (n = 0, p = argv[0]; *p != '\0'; ++p)
-               if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
+               if (ISMAGICNO(p)) {
                        ++p;
                        if (p[0] - '0' > n)
                                n = p[0] - '0';
@@ -134,28 +136,19 @@ main(int argc, char *argv[])
         * Allocate enough space to hold the maximum command.  Save the
         * size to pass to snprintf().
         */
-       cmdsize = sizeof(EXEC) - 1 + strlen(argv[0])
-           + 9 * (sizeof(" %1") - 1) + 1;
-       if ((cmd = malloc(cmdsize)) == NULL)
-               err(1, NULL);
-
        if (n == 0) {
+               cmdsize = strlen(argv[0]) + 9 * (sizeof(" %1") - 1) + 1;
+               if ((cmd = malloc(cmdsize)) == NULL)
+                       err(1, NULL);
+               strlcpy(cmd, argv[0], cmdsize);
+
                /* If nargs not set, default to a single argument. */
                if (nargs == -1)
                        nargs = 1;
 
-               p = cmd;
-               offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
-               if ((size_t)offset >= cmdsize)
-                       errx(1, "snprintf() failed");
-               p += offset;
-               cmdsize -= offset;
                for (i = 1; i <= nargs; i++) {
-                       offset = snprintf(p, cmdsize, " %c%d", magic, i);
-                       if ((size_t)offset >= cmdsize)
-                               errx(1, "snprintf() failed");
-                       p += offset;
-                       cmdsize -= offset;
+                       snprintf(buf, sizeof(buf), " %c%d", magic, i);
+                       strlcat(cmd, buf, cmdsize);
                }
 
                /*
@@ -165,9 +158,8 @@ main(int argc, char *argv[])
                if (nargs == 0)
                        nargs = 1;
        } else {
-               offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
-               if ((size_t)offset >= cmdsize)
-                       errx(1, "snprintf() failed");
+               if ((cmd = strdup(argv[0])) == NULL)
+                       err(1, NULL);
                nargs = n;
        }
 
@@ -184,9 +176,10 @@ main(int argc, char *argv[])
         */
        for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
                sbuf_clear(cmdbuf);
+               sbuf_cat(cmdbuf, "exec ");
                /* Expand command argv references. */
                for (p = cmd; *p != '\0'; ++p) {
-                       if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
+                       if (ISMAGICNO(p)) {
                                if (sbuf_cat(cmdbuf, argv[(++p)[0] - '0'])
                                    == -1)
                                        errc(1, ENOMEM, "sbuf");
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to