From nobody  Thu Nov 28 22:54:22 1996
Received: (from nobody@localhost)
          by freefall.freebsd.org (8.7.5/8.7.3) id WAA01756;
          Thu, 28 Nov 1996 22:54:22 -0800 (PST)
Message-Id: <199611290654.WAA01756@freefall.freebsd.org>
Date: Thu, 28 Nov 1996 22:54:22 -0800 (PST)
From: vax@linkdead.paranoia.com
To: freebsd-gnats-submit@freebsd.org
Subject: mount lies to child about argv0, which causes crunch to lose
X-Send-Pr-Version: www-1.0

>Number:         2119
>Category:       bin
>Synopsis:       [PATCH] mount lies to child about argv0, which causes crunch to lose
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Nov 28 23:00:01 PST 1996
>Closed-Date:    Wed Jun 28 02:30:20 PDT 2000
>Last-Modified:  Wed Jun 28 02:31:41 PDT 2000
>Originator:     VaX#n8
>Release:        HEAD revisions
>Organization:
League of Non-aligned Wizards
>Environment:
I'm using your CVS/WWW interface and notice you have the same problem
as NetBSD.
>Description:
The program /sbin/mount lies to child about argv[0], saying that it is "ffs"
instead of "mount_ffs".  This is wrong, doesn't really save much work
(if any), and confuses crunched executables, which branch in main() based
on argv[0].  While it might be possible to put in "ffs" as an alias for
"mount_ffs", this pollutes the namespace and conflicts with an identical
problem in NetBSD's fsck which I will submit seperately.

The code calls exit() rather than _exit() in the child if it fails
to execve().  This is wrong.  Quoth vfork(2):
     Be careful, also, to call _exit
     rather than exit if you can't execve,  since exit will flush and close
     standard I/O channels, and thereby mess up the parent processes standard
     I/O data structures.  (Even with fork it is wrong to call exit since
     buffered data would then be flushed twice.)

One of the tests for the debug flag which enabled some output was
supposed to be a test for the verbose flag --- the debug flag
is supposed to prevent execing the sub-program.

Our fsck had a special GNUC thing to protect optbuf from vfork clobbering.
I assume that is since optbuf is a dynamically allocated object.
Since I do not understand it completely, it is possible that it is
not necessary in this chunk of code.

>How-To-Repeat:
bash# mount /usr
ffs: /dev/sd1e on /usr: Device busy

That second line is generated by mount_ffs, and the label is the value
of argv[0].

bash# mount -v /mnt
/dev/fd0a on /mnt type ffs (local)
bash# mount -dv /mnt
exec: mount_ffs -o noauto /dev/fd0a /mnt

Whoops! Option "-v" doesn't really give us information on the exec call.
I was considering moving the printf loop into the child but didn't
know what the implications of writing to stdout in the child would be.

bash# cc -O  -Werror -Wall   -c /usr/src/sbin/mount/mount.c

I evaluated the FreeBSD error handling in the edirs/execve loop and
decided I didn't like it -- it never reports the error if the first
exec generates one (e.g. ENOEXEC).

>Fix:
Patch for NetBSD but should give an idea

--- sbin/mount/mount.c~ Thu Oct 24 06:13:48 1996
+++ sbin/mount/mount.c  Thu Nov 28 23:35:55 1996
@@ -243,7 +243,7 @@
         */
        if (rval == 0 && getuid() == 0 &&
            (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
-               if (fscanf(mountdfp, "%ld", &pid) == 1 &&
+               if (fscanf(mountdfp, "%ld", (long *) &pid) == 1 &&
                     pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
                        err(1, "signal mountd");
                (void)fclose(mountdfp);
@@ -288,12 +288,19 @@
                _PATH_USRSBIN,
                NULL
        };
-       const char *argv[100], **edir;
+       char execbase[MAXPATHLEN] = "mount_";
+       const char *argv[100] = { (const char *)execbase }, **edir;
        struct statfs sf;
        pid_t pid;
-       int argc, i, status;
+       int argc = 1, i, status;
        char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
 
+#ifdef __GNUC__
+        /* Avoid vfork clobbering */
+        (void) &optbuf;
+        (void) &name;
+#endif
+
        if (realpath(name, mntpath) == NULL) {
                warn("realpath %s", name);
                return (1);
@@ -344,16 +351,23 @@
        if (flags & MNT_UPDATE)
                optbuf = catopt(optbuf, "update");
 
-       argc = 0;
-       argv[argc++] = vfstype;
+       /* construct basename of executable and argv[0] simultaneously */
+       (void)strncat(execbase,
+                     (const char *)vfstype,
+                     sizeof(execbase) - 6);  /* strlen("mount_") + \0 */
        mangle(optbuf, &argc, argv);
        argv[argc++] = spec;
        argv[argc++] = name;
        argv[argc] = NULL;
 
-       if (debug) {
-               (void)printf("exec: mount_%s", vfstype);
-               for (i = 1; i < argc; i++)
+       /*
+        * XXX
+        * perhaps this belongs just before each exec call in the child
+        * if you move it there, move the debug-related _exit(0) too
+        */
+       if (verbose) {
+               (void)printf("exec:");
+               for (i = 0; i < argc; i++)
                        (void)printf(" %s", argv[i]);
                (void)printf("\n");
                return (0);
@@ -365,11 +379,14 @@
                free(optbuf);
                return (1);
        case 0:                                 /* Child. */
+                if (debug)
+                        _exit(0);
+
                /* Go find an executable. */
                edir = edirs;
                do {
                        (void)snprintf(execname,
-                           sizeof(execname), "%s/mount_%s", *edir, vfstype);
+                           sizeof(execname), "%s/%s", *edir, execbase);
                        execv(execname, (char * const *)argv);
                        if (errno != ENOENT)
                                warn("exec %s for %s", execname, name);
@@ -377,7 +394,7 @@
 
                if (errno == ENOENT)
                        warn("exec %s for %s", execname, name);
-               exit(1);
+               _exit(1);
                /* NOTREACHED */
        default:                                /* Parent. */
                free(optbuf);
@@ -487,14 +504,14 @@
                which = IN_LIST;
 
        /* Count the number of types. */
-       for (i = 1, nextcp = fslist; nextcp = strchr(nextcp, ','); i++)
+       for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
                ++nextcp;
 
        /* Build an array of that many types. */
        if ((av = typelist = malloc((i + 1) * sizeof(char *))) == NULL)
-               err(1, NULL);
+               err(1, "mallocing typelist");
        av[0] = fslist;
-       for (i = 1, nextcp = fslist; nextcp = strchr(nextcp, ','); i++) {
+       for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
                *nextcp = '\0';
                av[i] = ++nextcp;
        }
@@ -513,7 +530,7 @@
        if (s0 && *s0) {
                i = strlen(s0) + strlen(s1) + 1 + 1;
                if ((cp = malloc(i)) == NULL)
-                       err(1, NULL);
+                       err(1, "mallocing options");
                (void)snprintf(cp, i, "%s,%s", s0, s1);
        } else
                cp = strdup(s1);

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->suspended 
State-Changed-By: phk 
State-Changed-When: Mon May 25 01:01:59 PDT 1998 
State-Changed-Why:  
Awaiting committer 
State-Changed-From-To: suspended->feedback 
State-Changed-By: sheldonh 
State-Changed-When: Fri Dec 24 01:46:23 PST 1999 
State-Changed-Why:  
A huge number of fixes went into mount recently.  Your How-To-Repeat 
produces the text: 

mount: Device busy 

Perhaps you'd like to look at the current state of this beast and 
offer your comments? 
State-Changed-From-To: feedback->closed 
State-Changed-By: nbm 
State-Changed-When: Wed Jun 28 02:30:20 PDT 2000 
State-Changed-Why:  
Feedback timed out, and testing indicates that the How-To-Repeat no 
longer misfunctions, and that mount is usable from crunchgen. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=2119 
>Unformatted:
