When recieving a ill-formed ERROR TFTP packet, with Opcode=05, any ErrorCode, but a zero-length ErrMsg and no zero terminator, which is illegal according to RFC-1350, see page 7, then atftpd (either launched as a standalone daemon or from inetd) crashes with a SIGSEGV in strncpy (as seen by gdb) in GLIBC. Example of invalid ethernet packet (as sent by the buggy OpenBSD pxeboot): 0000 00 48 54 3d cd 88 00 90 90 70 70 70 08 00 45 00 .HT=.... .ppp..E. 0010 00 20 00 00 00 00 3c 11 f9 d6 c0 a8 01 db c0 a8 . ....<. ........ 0020 01 cb 08 06 c9 68 00 0c a9 68 00 05 00 03 00 00 .....h.. .h...... 0030 00 00 00 00 00 00 00 00 00 00 00 00 ........ .... Note: The zeroes are a trailer not belonging to the IP packet. The actual IP data ends at 03. In short, the TFTP packet is: 00 05 00 03 Sample segfault: segfault at b7dfe000 ip b7e988a0 sp b7dfc900 error 7 in libc-2.5.s [b7e2e000+123000] Reproducible: Always Steps to Reproduce: 1. atftpd --daemon --no-fork 2. Launch OpenBSD 4.2 pxeboot. Actual Results: OpenBSD pxeboot (that's an OpenBSD bug) sends an ill-formed 00 05 00 03 error packet in reply to data packet #8, and atftpd crashes with a SIGSEGV. Expected Results: atftpd should ignore the ill-formed packet. The invalid packet is recieved and returned by tftp_get_packet to tftpd_send_file (in tftpd_file.c). Its size is 4, the opcode is 05 and tftpd_get_packet returns GET_ERROR. There's a switch case in tftpd_send_file, and it copies the RFC-1350 error message with Strncpy, at line 905. Strncpy(string, tftphdr->th_msg, (((data_size - 4) > MAXLEN) ? MAXLEN : (data_size - 4))); data_size is 4, and so, 0 is passed as size to Strncpy. Strncpy is defined in tftp_def.c. It assumes that size>=1 by to[size-1] = '\000'; return strncpy(to, from, size - 1); But, size-1 is converted to size_t 0xFFFFFFFF when passed to strncpy, which crashes with a SIGSEGV soon or later. Quick fix: Add: if (size <= 0) {*to=0;return to;} As the first line of Strncpy in tftp_def.c It assumes that the destination buffer is at least one byte sized, but I'm pretty sure the buffer is always MAXLEN sized, so, it should be ok. Scope: This bug isn't specific to Gentoo. It is found in Debian binaries and sources (AFAIK, Debian is the main maintainer of this package) atftp_0.7.dfsg.orig.tar.gz + atftp_0.7.dfsg-6.diff.gz. Patch: $ diff -c tftp_def.old.c tftp_def.c *** tftp_def.old.c 2009-02-28 17:56:12.000000000 +0100 --- tftp_def.c 2009-02-28 17:57:02.000000000 +0100 *************** *** 141,146 **** --- 141,147 ---- */ inline char *Strncpy(char *to, const char *from, size_t size) { + if (size <= 0) { *to = '\000'; return to; } to[size-1] = '\000'; return strncpy(to, from, size - 1); }
The fix has been integrated into net-ftp/atftp-0.7-r2