From owner-freebsd-bugs Wed Jan 16 1:50:20 2002 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id 749B337B416 for ; Wed, 16 Jan 2002 01:50:02 -0800 (PST) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g0G9o2m37835; Wed, 16 Jan 2002 01:50:02 -0800 (PST) (envelope-from gnats) Date: Wed, 16 Jan 2002 01:50:02 -0800 (PST) Message-Id: <200201160950.g0G9o2m37835@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Maxim Konovalov Subject: Re: bin/33846: 4.5RC1: ftpd dies with SIGSEGV after ABOR Reply-To: Maxim Konovalov Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org The following reply was made to PR bin/33846; it has been noted by GNATS. From: Maxim Konovalov To: Eugene Grosbein Cc: FreeBSD-gnats-submit@FreeBSD.ORG, , "Alexandr P. Kovalenko" Subject: Re: bin/33846: 4.5RC1: ftpd dies with SIGSEGV after ABOR Date: Wed, 16 Jan 2002 12:49:10 +0300 (MSK) [ CC'd Yar who is working on bin/32740 and Alexandr, is a bin/32740 originator ] Hello, This PR duplicates bin/32740: http://www.FreeBSD.org/cgi/query-pr.cgi?pr=bin/32740 Here is a patch which is stolen from OpenBSD: http://www.freebsd.org/cgi/cvsweb.cgi/src/libexec/ftpd/ftpd.c?rev=1.109&content-type=text/x-cvsweb-markup&cvsroot=openbsd It works like a charm on our very busy ftp server. Btw, your How-To-Repeat section was very helpful, thanks. Index: ftpcmd.y =================================================================== RCS file: /home/ncvs/src/libexec/ftpd/ftpcmd.y,v retrieving revision 1.29 diff -u -r1.29 ftpcmd.y --- ftpcmd.y 2002/01/05 20:13:01 1.29 +++ ftpcmd.y 2002/01/15 13:39:10 @@ -60,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -101,6 +100,7 @@ static int cmd_type; static int cmd_form; static int cmd_bytesz; +static int state; char cbuf[512]; char *fromname = (char *) 0; @@ -750,9 +750,11 @@ reply(221, "Goodbye."); dologout(0); } - | error CRLF + | error { - yyerrok; + yyclearin; /* discard lookahead data */ + yyerrok; /* clear error condition */ + state = 0; /* reset lexer state */ } ; rcmd @@ -1047,8 +1049,6 @@ %% -extern jmp_buf errcatch; - #define CMD 0 /* beginning of command */ #define ARGS 1 /* expect miscellaneous arguments */ #define STR1 2 /* expect SP followed by STRING */ @@ -1253,7 +1253,7 @@ static int yylex() { - static int cpos, state; + static int cpos; char *cp, *cp2; struct tab *p; int n; @@ -1290,8 +1290,7 @@ if (p != 0) { if (p->implemented == 0) { nack(p->name); - longjmp(errcatch,0); - /* NOTREACHED */ + return (LEXERR); } state = p->state; yylval.s = p->name; @@ -1316,8 +1315,7 @@ if (p->implemented == 0) { state = CMD; nack(p->name); - longjmp(errcatch,0); - /* NOTREACHED */ + return (LEXERR); } state = p->state; yylval.s = p->name; @@ -1467,9 +1465,8 @@ default: fatalerror("Unknown state in scanner."); } - yyerror((char *) 0); state = CMD; - longjmp(errcatch,0); + return (LEXERR); } } Index: ftpd.c =================================================================== RCS file: /home/ncvs/src/libexec/ftpd/ftpd.c,v retrieving revision 1.88 diff -u -r1.88 ftpd.c --- ftpd.c 2002/01/01 13:14:25 1.88 +++ ftpd.c 2002/01/15 13:39:11 @@ -79,7 +79,6 @@ #include #include #include -#include #include #include #include @@ -125,7 +124,6 @@ int daemon_mode; int data; -jmp_buf errcatch, urgcatch; int logged_in; struct passwd *pw; int ftpdebug; @@ -150,6 +148,7 @@ int noretr=0; /* RETR command is disabled. */ int noguestretr=0; /* RETR command is disabled for anon users. */ +static volatile sig_atomic_t recvurg; sig_atomic_t transflag; off_t file_size; off_t byte_count; @@ -243,7 +242,8 @@ static void selecthost __P((union sockunion *)); #endif static void ack __P((char *)); -static void myoob __P((int)); +static void sigurg __P((int)); +static void myoob __P((void)); static int checkuser __P((char *, char *, int)); static FILE *dataconn __P((char *, off_t, char *)); static void dolog __P((struct sockaddr *)); @@ -252,8 +252,9 @@ static FILE *getdatasock __P((char *)); static char *gunique __P((char *)); static void lostconn __P((int)); +static void sigquit __P((int)); static int receive_data __P((FILE *, FILE *)); -static void send_data __P((FILE *, FILE *, off_t, off_t, int)); +static int send_data __P((FILE *, FILE *, off_t, off_t, int)); static struct passwd * sgetpwnam __P((char *)); static char *sgetsave __P((char *)); @@ -279,6 +280,7 @@ char *argv[]; char **envp; { + struct sigaction sa; int addrlen, ch, on = 1, tos; char *cp, line[LINE_MAX]; FILE *fd; @@ -288,6 +290,8 @@ int enable_v4 = 0; tzset(); /* in case no timezone database in ~ftp */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; #ifdef OLD_SETPROCTITLE /* @@ -419,7 +423,8 @@ syslog(LOG_ERR, "failed to become a daemon"); exit(1); } - (void) signal(SIGCHLD, reapchild); + sa.sa_handler = reapchild; + (void)sigaction(SIGCHLD, &sa, NULL); /* init bind_sa */ memset(&hints, 0, sizeof(hints)); @@ -522,11 +527,24 @@ } } - (void) signal(SIGCHLD, SIG_IGN); - (void) signal(SIGPIPE, lostconn); - if (signal(SIGURG, myoob) == SIG_ERR) - syslog(LOG_ERR, "signal: %m"); + sa.sa_handler = SIG_DFL; + (void)sigaction(SIGCHLD, &sa, NULL); + sa.sa_handler = sigurg; + sa.sa_flags = 0; /* don't restart syscalls for SIGURG */ + (void)sigaction(SIGURG, &sa, NULL); + + sigfillset(&sa.sa_mask); /* block all signals in handler */ + sa.sa_flags = SA_RESTART; + sa.sa_handler = sigquit; + (void)sigaction(SIGHUP, &sa, NULL); + (void)sigaction(SIGINT, &sa, NULL); + (void)sigaction(SIGQUIT, &sa, NULL); + (void)sigaction(SIGTERM, &sa, NULL); + + sa.sa_handler = lostconn; + (void)sigaction(SIGPIPE, &sa, NULL); + addrlen = sizeof(ctrl_addr); if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); @@ -610,7 +628,6 @@ hostname[MAXHOSTNAMELEN - 1] = '\0'; #endif reply(220, "%s FTP server (%s) ready.", hostname, version); - (void) setjmp(errcatch); for (;;) (void) yyparse(); /* NOTREACHED */ @@ -626,6 +643,15 @@ dologout(1); } +static void +sigquit(signo) + int signo; +{ + + syslog(LOG_ERR, "got signal SIGQUIT"); + dologout(1); +} + #ifdef VIRTUAL_HOSTING /* * read in virtual host tables (if they exist) @@ -1771,7 +1797,7 @@ * * NB: Form isn't handled. */ -static void +static int send_data(instr, outstr, blksize, filesize, isreg) FILE *instr, *outstr; off_t blksize; @@ -1784,14 +1810,12 @@ off_t cnt; transflag++; - if (setjmp(urgcatch)) { - transflag = 0; - return; - } switch (type) { case TYPE_A: while ((c = getc(instr)) != EOF) { + if (recvurg) + goto got_oob; byte_count++; if (c == '\n') { if (ferror(outstr)) @@ -1807,7 +1831,7 @@ if (ferror(outstr)) goto data_err; reply(226, "Transfer complete."); - return; + return(0); case TYPE_I: case TYPE_L: @@ -1829,6 +1853,8 @@ while (err != -1 && cnt < filesize) { err = sendfile(filefd, netfd, offset, len, (struct sf_hdtr *) NULL, &cnt, 0); + if (recvurg) + goto got_oob; byte_count += cnt; offset += cnt; len -= cnt; @@ -1842,14 +1868,14 @@ } reply(226, "Transfer complete."); - return; + return(0); } oldway: if ((buf = malloc((u_int)blksize)) == NULL) { transflag = 0; perror_reply(451, "Local resource failure: malloc"); - return; + return(-1); } while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && @@ -1863,21 +1889,28 @@ goto data_err; } reply(226, "Transfer complete."); - return; + return(0); default: transflag = 0; reply(550, "Unimplemented TYPE %d in send_data", type); - return; + return(-1); } data_err: transflag = 0; perror_reply(426, "Data connection"); - return; + return(-1); file_err: transflag = 0; perror_reply(551, "Error on input file"); + return(-1); + +got_oob: + myoob(); + recvurg = 0; + transflag = 0; + return(-1); } /* @@ -1895,11 +1928,6 @@ char buf[BUFSIZ]; transflag++; - if (setjmp(urgcatch)) { - transflag = 0; - return (-1); - } - bare_lfs = 0; switch (type) { @@ -1907,6 +1935,8 @@ case TYPE_I: case TYPE_L: while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { + if (recvurg) + goto got_oob; if (write(fileno(outstr), buf, cnt) != cnt) goto file_err; byte_count += cnt; @@ -1923,6 +1953,8 @@ case TYPE_A: while ((c = getc(instr)) != EOF) { + if (recvurg) + goto got_oob; byte_count++; if (c == '\n') bare_lfs++; @@ -1966,6 +1998,12 @@ transflag = 0; perror_reply(452, "Error writing file"); return (-1); + +got_oob: + myoob(); + recvurg = 0; + transflag = 0; + return (-1); } void @@ -2385,9 +2423,16 @@ } static void -myoob(signo) +sigurg(signo) int signo; { + + recvurg = 1; +} + +static void +myoob() +{ char *cp; /* only process if transfer occurring */ @@ -2403,7 +2448,6 @@ tmpline[0] = '\0'; reply(426, "Transfer aborted. Data connection closed."); reply(226, "Abort successful"); - longjmp(urgcatch, 1); } if (strcmp(cp, "STAT\r\n") == 0) { tmpline[0] = '\0'; @@ -2719,10 +2763,6 @@ simple = 1; } - if (setjmp(urgcatch)) { - transflag = 0; - goto out; - } while ((dirname = *dirlist++)) { if (stat(dirname, &st) < 0) { /* @@ -2763,6 +2803,13 @@ while ((dir = readdir(dirp)) != NULL) { char nbuf[MAXPATHLEN]; + + if (recvurg) { + myoob(); + recvurg = 0; + transflag = 0; + goto out; + } if (dir->d_name[0] == '.' && dir->d_namlen == 1) continue; -- Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message