Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Jan 2002 01:50:02 -0800 (PST)
From:      Maxim Konovalov <maxim@macomnet.ru>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/33846: 4.5RC1: ftpd dies with SIGSEGV after ABOR
Message-ID:  <200201160950.g0G9o2m37835@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/33846; it has been noted by GNATS.

From: Maxim Konovalov <maxim@macomnet.ru>
To: Eugene Grosbein <eugen@grosbein.pp.ru>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG, <yar@FreeBSD.ORG>,
	"Alexandr P. Kovalenko" <never@nevermind.kiev.ua>
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 <glob.h>
  #include <netdb.h>
  #include <pwd.h>
 -#include <setjmp.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
 @@ -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 <pwd.h>
  #include <grp.h>
  #include <opie.h>
 -#include <setjmp.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
 @@ -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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200201160950.g0G9o2m37835>