summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2013-03-15 12:20:12 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2013-03-15 12:20:12 +0000
commit63dda3cf702a788990d4471393a388d565a581e0 (patch)
treea511adf1951fea29ed2370260cb10864d8452715
parenta009bd2e2529fa6523c2f5e355758653ce8d4c16 (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.c21
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