diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2013-03-15 12:20:12 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2013-03-15 12:20:12 +0000 |
commit | 63dda3cf702a788990d4471393a388d565a581e0 (patch) | |
tree | a511adf1951fea29ed2370260cb10864d8452715 | |
parent | a009bd2e2529fa6523c2f5e355758653ce8d4c16 (diff) |
fix a huge bug in tftpd.
there was a double free if an option ack failed. if oack fails, the client
gets freed, then the oack caller tries to free the options which were just
freed.
found by Maxime Villard who provided a fix. unfortunately his fix still
had a double free but it was pretty close.
ok MALLOC_OPTIONS=S
-rw-r--r-- | usr.sbin/tftpd/tftpd.c | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/usr.sbin/tftpd/tftpd.c b/usr.sbin/tftpd/tftpd.c index f2a0582cd37..cf5238f406e 100644 --- a/usr.sbin/tftpd/tftpd.c +++ b/usr.sbin/tftpd/tftpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tftpd.c,v 1.8 2012/07/13 02:31:46 gsoares Exp $ */ +/* $OpenBSD: tftpd.c,v 1.9 2013/03/15 12:20:11 dlg Exp $ */ /* * Copyright (c) 2012 David Gwynne <dlg@uq.edu.au> @@ -168,7 +168,7 @@ void tftp_end(struct tftp_client *); void tftp(struct tftp_client *, struct tftphdr *, size_t); void tftp_open(struct tftp_client *, const char *); void nak(struct tftp_client *, int); -void oack(struct tftp_client *); +int oack(struct tftp_client *); void oack_done(int, short, void *); void sendfile(struct tftp_client *); @@ -872,11 +872,14 @@ tftp_open(struct tftp_client *client, const char *filename) int ecode; ecode = validate_access(client, filename); - if (ecode) - goto error; + if (ecode) { + nak(client, ecode); + return; + } if (client->options) { - oack(client); + if (oack(client) == -1) + return; free(client->options); client->options = NULL; @@ -886,9 +889,6 @@ tftp_open(struct tftp_client *client, const char *filename) sendfile(client); return; - -error: - nak(client, ecode); } /* @@ -1386,7 +1386,7 @@ nak(struct tftp_client *client, int error) /* * Send an oack packet (option acknowledgement). */ -void +int oack(struct tftp_client *client) { struct opt_client *options = client->options; @@ -1436,10 +1436,11 @@ oack(struct tftp_client *client) oack_done, client); event_add(&client->sev, &client->tv); - return; + return (0); error: client_free(client); + return (-1); } int |