Module Name:    src
Committed By:   christos
Date:           Fri Jun 28 17:20:16 UTC 2013

Modified Files:
        src/libexec/tftpd: tftpd.c

Log Message:
Prevent buffer overflows; reported by Maxime Villard


To generate a diff of this commit:
cvs rdiff -u -r1.39 -r1.40 src/libexec/tftpd/tftpd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/tftpd/tftpd.c
diff -u src/libexec/tftpd/tftpd.c:1.39 src/libexec/tftpd/tftpd.c:1.40
--- src/libexec/tftpd/tftpd.c:1.39	Mon Aug 29 16:41:07 2011
+++ src/libexec/tftpd/tftpd.c	Fri Jun 28 13:20:15 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: tftpd.c,v 1.39 2011/08/29 20:41:07 joerg Exp $	*/
+/*	$NetBSD: tftpd.c,v 1.40 2013/06/28 17:20:15 christos Exp $	*/
 
 /*
  * Copyright (c) 1983, 1993
@@ -36,7 +36,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 19
 #if 0
 static char sccsid[] = "@(#)tftpd.c	8.1 (Berkeley) 6/4/93";
 #else
-__RCSID("$NetBSD: tftpd.c,v 1.39 2011/08/29 20:41:07 joerg Exp $");
+__RCSID("$NetBSD: tftpd.c,v 1.40 2013/06/28 17:20:15 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -419,8 +419,8 @@ main(int argc, char *argv[])
 }
 
 static int
-blk_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
-	    int *ackl, int *ec)
+blk_handler(struct tftphdr *tp, const char *val, char *ack, size_t asize,
+    size_t *ackl, int *ec)
 {
 	unsigned long bsize;
 	char *endp;
@@ -450,17 +450,18 @@ blk_handler(struct tftphdr *tp, char *op
 	}
 
 	tftp_blksize = bsize;
-	strcpy(ack + *ackl, "blksize");
-	*ackl += 8;
-	l = sprintf(ack + *ackl, "%lu", bsize);
-	*ackl += l + 1;
+	if (asize > *ackl && (l = snprintf(ack + *ackl, asize - *ackl,
+	    "blksize%c%lu%c", 0, bsize, 0)) > 0)
+		*ackl += l;
+	else
+		return -1;
 
 	return 0;
 }
 
 static int
-timeout_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
-		int *ackl, int *ec)
+timeout_handler(struct tftphdr *tp, const char *val, char *ack, size_t asize,
+		size_t *ackl, int *ec)
 {
 	unsigned long tout;
 	char *endp;
@@ -486,11 +487,11 @@ timeout_handler(struct tftphdr *tp, char
 	}
 
 	rexmtval = tout;
-	strcpy(ack + *ackl, "timeout");
-	*ackl += 8;
-	l = sprintf(ack + *ackl, "%lu", tout);
-	*ackl += l + 1;
-
+	if (asize > *ackl && (l = snprintf(ack + *ackl, asize - *ackl,
+	    "timeout%c%lu%c", 0, tout, 0)))
+		*ackl += l;
+	else
+		return -1;
 	/*
 	 * Arbitrarily pick a maximum timeout on a request to 3
 	 * retransmissions if the interval timeout is more than
@@ -507,8 +508,8 @@ timeout_handler(struct tftphdr *tp, char
 }
 
 static int
-tsize_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
-	      int *ackl, int *ec)
+tsize_handler(struct tftphdr *tp, const char *val, char *ack, size_t asize,
+    size_t *ackl, int *ec)
 {
 	unsigned long fsize;
 	char *endp;
@@ -550,8 +551,8 @@ tsize_handler(struct tftphdr *tp, char *
 
 static const struct tftp_options {
 	const char *o_name;
-	int (*o_handler)(struct tftphdr *, char *, char *, char *,
-			 int *, int *);
+	int (*o_handler)(struct tftphdr *, const char *, char *, size_t,
+			 size_t *, int *);
 } options[] = {
 	{ "blksize", blk_handler },
 	{ "timeout", timeout_handler },
@@ -564,8 +565,8 @@ static const struct tftp_options {
  * recognize in oackbuf.
  */
 static int
-get_options(struct tftphdr *tp, char *cp, int size, char *ackb,
-    int *alen, int *err)
+get_options(struct tftphdr *tp, char *cp, int size, char *ackb, size_t asize,
+    size_t *alen, int *err)
 {
 	const struct tftp_options *op;
 	char *option, *value, *endp;
@@ -597,7 +598,7 @@ get_options(struct tftphdr *tp, char *cp
 				break;
 		}
 		if (op->o_name) {
-			r = op->o_handler(tp, option, value, ackb, alen, &ec);
+			r = op->o_handler(tp, value, ackb, asize, alen, &ec);
 			if (r < 0) {
 				rv = -1;
 				break;
@@ -621,7 +622,8 @@ tftp(struct tftphdr *tp, int size)
 	struct formats *pf;
 	char	*cp;
 	char	*filename, *mode;
-	int	 first, ecode, alen, etftp = 0, r;
+	int	 first, ecode, etftp = 0, r;
+	size_t alen;
 
 	ecode = 0;	/* XXX gcc */
 	first = 1;
@@ -666,7 +668,8 @@ again:
 	size -= (++cp - (char *) tp);
 	if (size > 0 && *cp) {
 		alen = 2; /* Skip over opcode */
-		r = get_options(tp, cp, size, oackbuf, &alen, &ecode);
+		r = get_options(tp, cp, size, oackbuf, sizeof(oackbuf),
+		    &alen, &ecode);
 		if (r > 0) {
 			etftp = 1;
 		} else if (r < 0) {
@@ -708,10 +711,11 @@ again:
 		if (tftp_opt_tsize) {
 			int l;
 
-			strcpy(oackbuf + alen, "tsize");
-			alen += 6;
-			l = sprintf(oackbuf + alen, "%u", tftp_tsize);
-			alen += l + 1;
+			if (sizeof(oackbuf) > alen &&
+			    (l = snprintf(oackbuf + alen,
+			    sizeof(oackbuf) - alen, "tsize%c%u%c", 0,
+			    tftp_tsize, 0)))
+				alen += l;
 		}
 		oack_h = (struct tftphdr *) oackbuf;
 		oack_h->th_opcode = htons(OACK);

Reply via email to