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);