SECURITY HOLE IN tftpd (fix for a fix, sigh..)

lee at unmvax.UUCP lee at unmvax.UUCP
Fri Sep 28 08:41:57 AEST 1984


 The last "fix" I posted neglected to account for symlinks. I still
live in a 4.1 world, I guess.... This one gets the symlinks too.

RCS file: RCS/tftpd.c,v
retrieving revision 1.1
diff -c -r1.1 tftpd.c
*** /tmp/,RCSt1013277	Thu Sep 27 16:40:55 1984
--- tftpd.c	Thu Sep 27 16:34:50 1984
***************
*** 188,193
  	int mode;
  {
  	struct stat stbuf;
  
  	if (*file != '/')
  		return (EACCESS);

--- 188,200 -----
  	int mode;
  {
  	struct stat stbuf;
+ 	char	*ptr,
+ 		*lsptr,
+ 		*eptr,
+ 		buf[BUFSIZ],
+ 		tbuf[BUFSIZ];
+ 	int	sret,
+ 		cc;
  
  	(void )chdir("/");
  	if (*file != '/')
***************
*** 189,194
  {
  	struct stat stbuf;
  
  	if (*file != '/')
  		return (EACCESS);
  	if (stat(file, &stbuf) < 0)

--- 196,202 -----
  	int	sret,
  		cc;
  
+ 	(void )chdir("/");
  	if (*file != '/')
  		return (EACCESS);
  	/* Check path first */
***************
*** 191,196
  
  	if (*file != '/')
  		return (EACCESS);
  	if (stat(file, &stbuf) < 0)
  		return (errno == ENOENT ? ENOTFOUND : EACCESS);
  	if (mode == RRQ) {

--- 199,245 -----
  	(void )chdir("/");
  	if (*file != '/')
  		return (EACCESS);
+ 	/* Check path first */
+ 	eptr = file + strlen(file);
+ 	lsptr = ptr = file;
+ 	ptr++;
+ 	while (ptr < eptr) {
+ 		if (*ptr++ != '/' && *ptr)
+ 			continue;
+ 		if (*ptr) {
+ 			ptr--;
+ 			*ptr = NULL;
+ 		}
+ 		sret = lstat(file, &stbuf);
+ 		if (ptr != eptr)
+ 			*ptr++ = '/';
+ 		else
+ 			ptr++;
+ 		if (sret < 0)
+ 			return (errno == ENOENT ? ENOTFOUND : EACCESS);
+ 		if ((stbuf.st_mode&S_IFMT) == S_IFDIR) {
+ 			if((stbuf.st_mode&(S_IEXEC >> 6)) == 0)
+ 				return (EACCESS);
+ 		} else if ((stbuf.st_mode&S_IFMT) == S_IFLNK) {
+ 			*--ptr = NULL;
+ 			cc = readlink(file, tbuf, sizeof(tbuf));
+ 			if (cc < 0)
+ 				return(errno);
+ 			tbuf[cc] = NULL;
+ 			strncat(tbuf, ptr, sizeof(tbuf) - 1 - cc);
+ 			if (tbuf[0] != '/') {
+ 				*lsptr = NULL;
+ 				(void )chdir(file);
+ 				ptr = buf;
+ 			} else
+ 				ptr = &buf[1];
+ 			strcpy(buf, tbuf);
+ 			file = buf;
+ 			eptr = file + strlen(file);
+ 		} else
+ 			break;
+ 		lsptr = ptr - 1;
+ 	}
  	if (stat(file, &stbuf) < 0)
  		return (errno == ENOENT ? ENOTFOUND : EACCESS);
  	if (mode == RRQ) {
-- 
			--Lee (Ward)
			{ucbvax,convex,gatech,pur-ee}!unmvax!lee



More information about the Comp.bugs.4bsd.ucb-fixes mailing list