Remove the setjmp/longjmp stuff completely. Use signal
handlers to set flags only (with exception for sigquit(), which still seems to call some non-reentrant functions on its way to _exit(2).) That must eliminate the possibility of catching SIGSEGV from following non-reentrant paths from signal handlers. PR: bin/32740 bin/33846 Submitted by: Maxim Konovalov <maxim@macomnet.ru> Obtained from: OpenBSD
This commit is contained in:
parent
5cc5c73a03
commit
4b82fc955f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=89935
@ -60,7 +60,6 @@ static const char rcsid[] =
|
||||
#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 @@ off_t restart_point;
|
||||
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 @@ cmd
|
||||
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 @@ check_login_ro
|
||||
|
||||
%%
|
||||
|
||||
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 @@ toolong(signo)
|
||||
static int
|
||||
yylex()
|
||||
{
|
||||
static int cpos, state;
|
||||
static int cpos;
|
||||
char *cp, *cp2;
|
||||
struct tab *p;
|
||||
int n;
|
||||
@ -1290,8 +1290,7 @@ yylex()
|
||||
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 @@ yylex()
|
||||
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 @@ yylex()
|
||||
default:
|
||||
fatalerror("Unknown state in scanner.");
|
||||
}
|
||||
yyerror((char *) 0);
|
||||
state = CMD;
|
||||
longjmp(errcatch,0);
|
||||
return (LEXERR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,6 @@ static const char rcsid[] =
|
||||
#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 @@ union sockunion pasv_addr;
|
||||
|
||||
int daemon_mode;
|
||||
int data;
|
||||
jmp_buf errcatch, urgcatch;
|
||||
int logged_in;
|
||||
struct passwd *pw;
|
||||
int ftpdebug;
|
||||
@ -150,6 +148,7 @@ int noepsv=0; /* EPSV command is disabled. */
|
||||
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 inithosts __P((void));
|
||||
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 void end_login __P((void));
|
||||
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 *));
|
||||
@ -286,8 +287,11 @@ main(argc, argv, envp)
|
||||
char *bindname = NULL;
|
||||
int family = AF_UNSPEC;
|
||||
int enable_v4 = 0;
|
||||
struct sigaction sa;
|
||||
|
||||
tzset(); /* in case no timezone database in ~ftp */
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
#ifdef OLD_SETPROCTITLE
|
||||
/*
|
||||
@ -419,7 +423,8 @@ main(argc, argv, envp)
|
||||
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,10 +527,23 @@ main(argc, argv, envp)
|
||||
}
|
||||
}
|
||||
|
||||
(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) {
|
||||
@ -610,7 +628,6 @@ main(argc, argv, envp)
|
||||
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 @@ lostconn(signo)
|
||||
dologout(1);
|
||||
}
|
||||
|
||||
static void
|
||||
sigquit(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
syslog(LOG_ERR, "got signal %d", signo);
|
||||
dologout(1);
|
||||
}
|
||||
|
||||
#ifdef VIRTUAL_HOSTING
|
||||
/*
|
||||
* read in virtual host tables (if they exist)
|
||||
@ -1770,7 +1796,7 @@ dataconn(name, size, mode)
|
||||
*
|
||||
* NB: Form isn't handled.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
send_data(instr, outstr, blksize, filesize, isreg)
|
||||
FILE *instr, *outstr;
|
||||
off_t blksize;
|
||||
@ -1783,14 +1809,12 @@ send_data(instr, outstr, blksize, filesize, isreg)
|
||||
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))
|
||||
@ -1799,6 +1823,8 @@ send_data(instr, outstr, blksize, filesize, isreg)
|
||||
}
|
||||
(void) putc(c, outstr);
|
||||
}
|
||||
if (recvurg)
|
||||
goto got_oob;
|
||||
fflush(outstr);
|
||||
transflag = 0;
|
||||
if (ferror(instr))
|
||||
@ -1806,7 +1832,7 @@ send_data(instr, outstr, blksize, filesize, isreg)
|
||||
if (ferror(outstr))
|
||||
goto data_err;
|
||||
reply(226, "Transfer complete.");
|
||||
return;
|
||||
return (0);
|
||||
|
||||
case TYPE_I:
|
||||
case TYPE_L:
|
||||
@ -1828,6 +1854,8 @@ send_data(instr, outstr, blksize, filesize, isreg)
|
||||
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;
|
||||
@ -1841,14 +1869,14 @@ send_data(instr, outstr, blksize, filesize, isreg)
|
||||
}
|
||||
|
||||
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 &&
|
||||
@ -1862,21 +1890,28 @@ send_data(instr, outstr, blksize, filesize, isreg)
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1894,11 +1929,6 @@ receive_data(instr, outstr)
|
||||
char buf[BUFSIZ];
|
||||
|
||||
transflag++;
|
||||
if (setjmp(urgcatch)) {
|
||||
transflag = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bare_lfs = 0;
|
||||
|
||||
switch (type) {
|
||||
@ -1906,10 +1936,14 @@ receive_data(instr, outstr)
|
||||
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;
|
||||
}
|
||||
if (recvurg)
|
||||
goto got_oob;
|
||||
if (cnt < 0)
|
||||
goto data_err;
|
||||
transflag = 0;
|
||||
@ -1922,6 +1956,8 @@ receive_data(instr, outstr)
|
||||
|
||||
case TYPE_A:
|
||||
while ((c = getc(instr)) != EOF) {
|
||||
if (recvurg)
|
||||
goto got_oob;
|
||||
byte_count++;
|
||||
if (c == '\n')
|
||||
bare_lfs++;
|
||||
@ -1937,6 +1973,8 @@ receive_data(instr, outstr)
|
||||
(void) putc(c, outstr);
|
||||
contin2: ;
|
||||
}
|
||||
if (recvurg)
|
||||
goto got_oob;
|
||||
fflush(outstr);
|
||||
if (ferror(instr))
|
||||
goto data_err;
|
||||
@ -1965,6 +2003,12 @@ receive_data(instr, outstr)
|
||||
transflag = 0;
|
||||
perror_reply(452, "Error writing file");
|
||||
return (-1);
|
||||
|
||||
got_oob:
|
||||
myoob();
|
||||
recvurg = 0;
|
||||
transflag = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2384,8 +2428,15 @@ dologout(status)
|
||||
}
|
||||
|
||||
static void
|
||||
myoob(signo)
|
||||
sigurg(signo)
|
||||
int signo;
|
||||
{
|
||||
|
||||
recvurg = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
myoob()
|
||||
{
|
||||
char *cp;
|
||||
|
||||
@ -2402,7 +2453,6 @@ myoob(signo)
|
||||
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';
|
||||
@ -2718,10 +2768,6 @@ send_file_list(whichf)
|
||||
simple = 1;
|
||||
}
|
||||
|
||||
if (setjmp(urgcatch)) {
|
||||
transflag = 0;
|
||||
goto out;
|
||||
}
|
||||
while ((dirname = *dirlist++)) {
|
||||
if (stat(dirname, &st) < 0) {
|
||||
/*
|
||||
@ -2763,6 +2809,13 @@ send_file_list(whichf)
|
||||
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;
|
||||
if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
|
||||
|
Loading…
Reference in New Issue
Block a user