Fixes gross stack consumers
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 18 Sep 2014 01:41:25 +0000 (18:41 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 18 Sep 2014 01:41:25 +0000 (18:41 -0700)
Whenever we call etherbind(), we run off the bottom of a 4KB stack.  Sometimes
the canary catches it, if a clobber happened to trigger it.  Other times, it
seems fine.  And yet others, the machine locks up.  The major stack consumers
were the dials/calls and their huge strings.

If this breaks your ifconfig, let me know.

You should be able to run without LARGE_KSTACKS now.

kern/src/net/dial.c
kern/src/net/ethermedium.c

index 6bd2b8d..eb0c722 100644 (file)
@@ -47,67 +47,80 @@ int kdial(char *dest, char *local, char *dir, int *cfdp)
 {
        DS ds;
        int rv;
-       char err[ERRMAX], alterr[ERRMAX];
+       char *err, *alterr;
+
+       err = kmalloc(ERRMAX, KMALLOC_WAIT);
+       alterr = kmalloc(ERRMAX, KMALLOC_WAIT);
 
        ds.local = local;
        ds.dir = dir;
        ds.cfdp = cfdp;
 
        _dial_string_parse(dest, &ds);
-       if (ds.netdir)
-               return csdial(&ds);
+       if (ds.netdir) {
+               rv = csdial(&ds);
+               goto out;
+       }
 
        ds.netdir = "/net";
        rv = csdial(&ds);
        if (rv >= 0)
-               return rv;
+               goto out;
 
        err[0] = 0;
-       strncpy(err, current_errstr(), sizeof err);
+       strncpy(err, current_errstr(), ERRMAX);
        if (strstr(err, "refused") != 0) {
-               return rv;
+               goto out;
        }
 
        ds.netdir = "/net.alt";
        rv = csdial(&ds);
        if (rv >= 0)
-               return rv;
+               goto out;
 
        alterr[0] = 0;
-       kerrstr(alterr, sizeof err);
+       kerrstr(alterr, ERRMAX);
 
        if (strstr(alterr, "translate") || strstr(alterr, "does not exist"))
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
        else
-               kerrstr(alterr, sizeof alterr);
+               kerrstr(alterr, ERRMAX);
+out:
+       kfree(err);
+       kfree(alterr);
        return rv;
 }
 
 static int csdial(DS * ds)
 {
-       int n, fd, rv;
-       char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
+       int n, fd, rv = -1;
+       char *p, *buf, *clone, *err, *besterr;
 
+       buf = kmalloc(Maxstring, KMALLOC_WAIT);
+       clone = kmalloc(Maxpath, KMALLOC_WAIT);
+       err = kmalloc(ERRMAX, KMALLOC_WAIT);
+       besterr = kmalloc(ERRMAX, KMALLOC_WAIT);
        /*
         *  open connection server
         */
-       snprintf(buf, sizeof(buf), "%s/cs", ds->netdir);
+       snprintf(buf, Maxstring, "%s/cs", ds->netdir);
        fd = sysopen(buf, ORDWR);
        if (fd < 0) {
                /* no connection server, don't translate */
-               snprintf(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
-               return call(clone, ds->rem, ds);
+               snprintf(clone, Maxpath, "%s/%s/clone", ds->netdir, ds->proto);
+               rv = call(clone, ds->rem, ds);
+               goto out;
        }
 
        /*
         *  ask connection server to translate
         */
-       snprintf(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
+       snprintf(buf, Maxstring, "%s!%s", ds->proto, ds->rem);
        if (syswrite(fd, buf, strlen(buf)) < 0) {
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
                sysclose(fd);
                set_errstr("%s (%s)", err, buf);
-               return -1;
+               goto out;
        }
 
        /*
@@ -115,10 +128,9 @@ static int csdial(DS * ds)
         *  we get one that works.
         */
        *besterr = 0;
-       strncpy(err, Egreg, sizeof(err));
-       rv = -1;
+       strncpy(err, Egreg, ERRMAX);
        sysseek(fd, 0, 0);
-       while ((n = sysread(fd, buf, sizeof(buf) - 1)) > 0) {
+       while ((n = sysread(fd, buf, Maxstring - 1)) > 0) {
                buf[n] = 0;
                p = strchr(buf, ' ');
                if (p == 0)
@@ -128,76 +140,94 @@ static int csdial(DS * ds)
                if (rv >= 0)
                        break;
                err[0] = 0;
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
                if (strstr(err, "does not exist") == 0)
-                       memmove(besterr, err, sizeof besterr);
+                       memmove(besterr, err, ERRMAX);
        }
        sysclose(fd);
 
        if (rv < 0 && *besterr)
-               kerrstr(besterr, sizeof besterr);
+               kerrstr(besterr, ERRMAX);
        else
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
+out:
+       kfree(buf);
+       kfree(clone);
+       kfree(err);
+       kfree(besterr);
        return rv;
 }
 
 static int call(char *clone, char *dest, DS * ds)
 {
-       int fd, cfd, n;
-       char name[Maxpath], data[Maxpath], err[ERRMAX], *p;
+       int fd, cfd, n, retval;
+       char *name, *data, *err, *p;
+
+       name = kmalloc(Maxpath, KMALLOC_WAIT);
+       data = kmalloc(Maxpath, KMALLOC_WAIT);
+       err = kmalloc(ERRMAX, KMALLOC_WAIT);
 
        cfd = sysopen(clone, ORDWR);
        if (cfd < 0) {
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
                set_errstr("%s (%s)", err, clone);
-               return -1;
+               retval = -1;
+               goto out;
        }
 
        /* get directory name */
-       n = sysread(cfd, name, sizeof(name) - 1);
+       n = sysread(cfd, name, Maxpath - 1);
        if (n < 0) {
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
                sysclose(cfd);
                set_errstr("read %s: %s", clone, err);
-               return -1;
+               retval = -1;
+               goto out;
        }
        name[n] = 0;
        for (p = name; *p == ' '; p++) ;
-       snprintf(name, sizeof(name), "%ld", strtoul(p, 0, 0));
+       snprintf(name, Maxpath, "%ld", strtoul(p, 0, 0));
        p = strrchr(clone, '/');
        *p = 0;
        if (ds->dir)
                snprintf(ds->dir, NETPATHLEN, "%s/%s", clone, name);
-       snprintf(data, sizeof(data), "%s/%s/data", clone, name);
+       snprintf(data, Maxpath, "%s/%s/data", clone, name);
 
        /* connect */
        if (ds->local)
-               snprintf(name, sizeof(name), "connect %s %s", dest, ds->local);
+               snprintf(name, Maxpath, "connect %s %s", dest, ds->local);
        else
-               snprintf(name, sizeof(name), "connect %s", dest);
+               snprintf(name, Maxpath, "connect %s", dest);
        if (syswrite(cfd, name, strlen(name)) < 0) {
                err[0] = 0;
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
                sysclose(cfd);
                set_errstr("%s (%s)", err, name);
-               return -1;
+               retval = -1;
+               goto out;
        }
 
        /* open data connection */
        fd = sysopen(data, ORDWR);
        if (fd < 0) {
                err[0] = 0;
-               kerrstr(err, sizeof err);
+               kerrstr(err, ERRMAX);
                set_errstr("%s (%s)", err, data);
                sysclose(cfd);
-               return -1;
+               retval = -1;
+               goto out;
        }
        if (ds->cfdp)
                *ds->cfdp = cfd;
        else
                sysclose(cfd);
+       retval = fd;
+out:
+       kfree(name);
+       kfree(data);
+       kfree(err);
 
-       return fd;
+       return retval;
 }
 
 /*
index f4f22c1..c7d0c80 100644 (file)
@@ -147,9 +147,7 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
 {
        ERRSTACK(1);
        struct chan *mchan4, *cchan4, *achan, *mchan6, *cchan6;
-       char addr[Maxpath];                     //char addr[2*KNAMELEN];
-       char dir[Maxpath];                      //char dir[2*KNAMELEN];
-       char *buf;
+       char *addr, *dir, *buf;
        int fd, cfd, n;
        char *ptr;
        Etherrock *er;
@@ -157,6 +155,8 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
        if (argc < 2)
                error(Ebadarg);
 
+       addr = kmalloc(Maxpath, KMALLOC_WAIT);  //char addr[2*KNAMELEN];
+       dir = kmalloc(Maxpath, KMALLOC_WAIT);   //char addr[2*KNAMELEN];
        mchan4 = cchan4 = achan = mchan6 = cchan6 = NULL;
        buf = NULL;
        if (waserror()) {
@@ -172,6 +172,8 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
                        cclose(cchan6);
                if (buf != NULL)
                        kfree(buf);
+               kfree(addr);
+               kfree(dir);
                nexterror();
        }
 
@@ -181,7 +183,7 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
         *  the dial will fail if the type is already open on
         *  this device.
         */
-       snprintf(addr, sizeof(addr), "%s!0x800", argv[2]);
+       snprintf(addr, Maxpath, "%s!0x800", argv[2]);
        fd = kdial(addr, NULL, dir, &cfd);
        if (fd < 0)
                error("dial 0x800 failed: %s", get_cur_errbuf());
@@ -198,7 +200,7 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
        /*
         *  get mac address and speed
         */
-       snprintf(addr, sizeof(addr), "%s/stats", dir);
+       snprintf(addr, Maxpath, "%s/stats", dir);
        fd = sysopen(addr, OREAD);
        if (fd < 0)
                error("can't open ether stats: %s", get_cur_errbuf());
@@ -234,7 +236,7 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
        /*
         *  open arp conversation
         */
-       snprintf(addr, sizeof(addr), "%s!0x806", argv[2]);
+       snprintf(addr, Maxpath, "%s!0x806", argv[2]);
        fd = kdial(addr, NULL, NULL, NULL);
        if (fd < 0)
                error("dial 0x806 failed: %s", get_cur_errbuf());
@@ -247,7 +249,7 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
         *  the dial will fail if the type is already open on
         *  this device.
         */
-       snprintf(addr, sizeof(addr), "%s!0x86DD", argv[2]);
+       snprintf(addr, Maxpath, "%s!0x86DD", argv[2]);
        fd = kdial(addr, NULL, dir, &cfd);
        if (fd < 0)
                error("dial 0x86DD failed: %s", get_cur_errbuf());
@@ -271,6 +273,8 @@ static void etherbind(struct Ipifc *ifc, int argc, char **argv)
        ifc->arg = er;
 
        kfree(buf);
+       kfree(addr);
+       kfree(dir);
        poperror();
 
        ktask("etherread4", etherread4, ifc);