COMMAND lpd SYSTEMS AFFECTED FreeBSD 2.1.5, 2.1.6, 2.1.7, 2.2 Gamma, FreeBSD -current is vulnerable for dates prior to February 25, 1997 PROBLEM The following information is Secure Networks Inc. (SNI) copyright and it is a part of their security advisory (March 5, 1997). There is a serious security vulnerability in all FreeBSD lpd implementations This vulnerability allows remote users to gain unauthorized root access to any system allowing connections to the line printer daemon (lpd). A user is not required to be in lpd's access list (/etc/hosts.lpd) to exploit this vulnerability, as the problem occurs while lpd is attempting to determine whether the host is permitted to connect. The vulnerability is present in the source file lib/libc/net/rcmd.c, which contains the function __ivaliduser(). This function is used by the line printer daemon (lpd) to determine whether the user connecting to the daemon is in it's access list (contained in /etc/hosts.lpd). When performing a domain name lookup on the connecting IP address, the resulting response is copied into a fixed size buffer of size MAXHOSTNAMELEN (256 bytes). Since DNS responses containing a hostname and domain name are currently allowed to exceed 256 bytes, overflow can occur. The faulty code follows: if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), AF_INET)) == NULL) return (-1); strcpy(hname, hp->h_name); The string copy is done without any bounds checking. Corrected code looks as follows: if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), AF_INET)) == NULL) return (-1); strncpy(hname, hp->h_name, sizeof(hname)); hname[sizeof(hname)-1] = '\0'; SOLUTION FreeBSD 2.2 is not vulnerable and it was corrected in -current, and -stable as of February 25, 1997. If the system in question does not require the use of printing services, lpd should be removed or commented out from the system startup file /etc/rc. If you require the use of printing services, this vulnerability can be fixed by applying the following patch to lib/libc/net/rcmd.c. This patch has been known to apply to all FreeBSD 2.x systems. --- CUT HERE --- *** libc/lib/net/rcmd.c.old Tue Feb 25 15:33:42 1997 --- libc/lib/net/rcmd.c Tue Feb 25 15:33:56 1997 *************** *** 377,383 **** if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), AF_INET)) == NULL) return (-1); ! strcpy(hname, hp->h_name); while (fgets(buf, sizeof(buf), hostf)) { p = buf; --- 377,384 ---- if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), AF_INET)) == NULL) return (-1); ! strncpy(hname, hp->h_name, sizeof(hname)); ! hname[sizeof(hname)-1] = '\0'; while (fgets(buf, sizeof(buf), hostf)) { p = buf; --- CUT HERE --- At this point, libc will have to be recompiled. lpd is shipped dynamically linked under FreeBSD, therefore the fix will take effect without recompiling lpd itself.