Small bug, but still...

naddy@ reported a double free when interrupting (^C) ftp(1) at the end
or url_get().  If that happens, the SIGINT handler longjmps and the
cleanup path is taken a second time.  To avoid this, restore the
previous SIGINT handler in each possible error path.  I chose to restore
it earlier in the successful path to avoid too much duplication.
file_get() gets the same treatment.

Note that naddy hit this because of another bug causing ftp_close()
to stall, and this depends on the server you're talking to.  You can
insert a sleep(10); call before "return (rval);" to help reproduce the
crash.

ok?


Index: fetch.c
===================================================================
RCS file: /d/cvs/src/usr.bin/ftp/fetch.c,v
retrieving revision 1.195
diff -u -p -p -u -r1.195 fetch.c
--- fetch.c     20 Jun 2020 09:59:48 -0000      1.195
+++ fetch.c     21 Jun 2020 00:12:10 -0000
@@ -261,6 +261,7 @@ file_get(const char *path, const char *o
                for (cp = buf; len > 0; len -= wlen, cp += wlen) {
                        if ((wlen = write(out, cp, len)) == -1) {
                                warn("Writing %s", savefile);
+                               signal(SIGINT, oldintr);
                                signal(SIGINFO, oldinti);
                                goto cleanup_copy;
                        }
@@ -274,6 +275,7 @@ file_get(const char *path, const char *o
                }
        }
        save_errno = errno;
+       signal(SIGINT, oldintr);
        signal(SIGINFO, oldinti);
        if (hash && !progress && bytes > 0) {
                if (bytes < mark)
@@ -288,7 +290,6 @@ file_get(const char *path, const char *o
        progressmeter(1, NULL);
        if (verbose)
                ptransfer(0);
-       (void)signal(SIGINT, oldintr);
 
        rval = 0;
 
@@ -1032,6 +1033,7 @@ noslash:
        oldinti = signal(SIGINFO, psummary);
        if (chunked) {
                error = save_chunked(fin, tls, out, buf, buflen);
+               signal(SIGINT, oldintr);
                signal(SIGINFO, oldinti);
                if (error == -1)
                        goto cleanup_url_get;
@@ -1041,6 +1043,7 @@ noslash:
                        for (cp = buf; len > 0; len -= wlen, cp += wlen) {
                                if ((wlen = write(out, cp, len)) == -1) {
                                        warn("Writing %s", savefile);
+                                       signal(SIGINT, oldintr);
                                        signal(SIGINFO, oldinti);
                                        goto cleanup_url_get;
                                }
@@ -1054,6 +1057,7 @@ noslash:
                        }
                }
                save_errno = errno;
+               signal(SIGINT, oldintr);
                signal(SIGINFO, oldinti);
                if (hash && !progress && bytes > 0) {
                        if (bytes < mark)
@@ -1080,7 +1084,6 @@ noslash:
 
        if (verbose)
                ptransfer(0);
-       (void)signal(SIGINT, oldintr);
 
        rval = 0;
        goto cleanup_url_get;


-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to