Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Jul 2006 12:44:23 +0200 (CEST)
From:      Auster <lrou@presto.telepluscom.net>
To:        FreeBSD-gnats-submit@FreeBSD.org
Cc:        lrou@x.ua
Subject:   bin/100914: libexec/tftpd: write access control
Message-ID:  <200607271044.k6RAiNTX008800@presto.telepluscom.net>
Resent-Message-ID: <200607271050.k6RAoC7J019695@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         100914
>Category:       bin
>Synopsis:       libexec/tftpd: write access control
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jul 27 10:50:11 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Auster
>Release:        FreeBSD 6.1-RELEASE-p2 i386
>Organization:
>Environment:
System: FreeBSD presto.telepluscom.net 6.1-RELEASE-p2 FreeBSD 6.1-RELEASE-p2 #0: Thu Jun 15 20:30:57 CEST 2006 yx@presto.telepluscom.net:/usr/obj/usr/src/sys/presto i386

>Description:
Traditional tftp file access control:
 read access:
  tftpd(8) - tftpd will allow only publicly readable files to be accessed.
 write access:
  tftpd(8) - files may be written only if they already exist and are publicly writable.

Test condition: files may be written only if they are publicly writable (i.e. mode ??2).

Summary, libexec/tftpd write access:
 absolute filenames:
  all modes (??0 ??2 ??4) - correct.
 relative filenames:
  mode ??0 - incorrect 6.1 (RELEASE-p2 tested)
  mode ??2 - incorrect 4.11 (RELEASE-p9 tested)
  mode ??4 - incorrect both - 4.11 and 6.1


>How-To-Repeat:

for example:

~# grep '^tftp' /etc/inetd.conf
tftp	dgram	udp	wait	root	/usr/libexec/tftpd	tftpd -l -s /spool/tftp

~# touch a
~# touch /spool/tftp/a
~# chown nobody:nogroup /spool/tftp/a


1) mode ??0
~# chmod 640 /spool/tftp/a
~# tftp localhost

1a) 6.1-RELEASE-p2
tftp| put a /a
Error code 2: Access violation
  ! error - correct
tftp| put a a
  ! no error - incorrect

1b) 4.11-RELEASE-p9
tftp| put a /a
Error code 2: Access violation
  ! error - correct
tftp| put a a
Error code 2: Access violation
  ! error - correct



2) mode ??2
~# chmod 642 /spool/tftp/a
~# tftp localhost

2a) 6.1-RELEASE-p2
tftp| put a /a
  ! no error - correct
tftp| put a a
  ! no error - correct

2b) 4.11-RELEASE-p9
tftp| put a /a
  ! no error - correct
tftp| put a a
Error code 2: Access violation
  ! error - incorrect



3) mode ??4
~# chmod 644 /spool/tftp/a
~# tftp localhost

3a) 6.1-RELEASE-p2
tftp| put a /a
Error code 2: Access violation
  ! error - correct
tftp| put a a
  ! no error - incorrect

3b) 4.11-RELEASE-p9
tftp| put a /a
Error code 2: Access violation
  ! error - correct
tftp| put a a
  ! no error - incorrect



>Fix:

1) 6.1-RELEASE-p2: diff -up libexec/tftpd/tftpd.c.orig libexec/tftpd/tftpd.c
--- libexec/tftpd/tftpd.c.orig	Thu Jul 27 12:02:59 2006
+++ libexec/tftpd/tftpd.c	Thu Jul 27 12:07:57 2006
@@ -588,16 +588,28 @@ validate_access(char **filep, int mode)
 				dirp->name, filename);
 			if (stat(pathname, &stbuf) == 0 &&
 			    (stbuf.st_mode & S_IFMT) == S_IFREG) {
-				if ((stbuf.st_mode & S_IROTH) != 0) {
-					break;
+				if (mode == RRQ) {
+					if ((stbuf.st_mode & S_IROTH) != 0) {
+						break;
+					}
+				} else {
+					if ((stbuf.st_mode & S_IWOTH) != 0) {
+						break;
+					}
 				}
 				err = EACCESS;
 			}
 		}
 		if (dirp->name != NULL)
 			*filep = filename = pathname;
-		else if (mode == RRQ)
-			return (err);
+		else {
+			if (mode == RRQ) {
+				return (err);
+			} else {
+				if (!create_new)
+					return (err);
+			}
+		}
 	}
 	if (options[OPT_TSIZE].o_request) {
 		if (mode == RRQ) 



2) 4.11-RELEASE-p9: diff -up libexec/tftpd/tftpd.c.orig libexec/tftpd/tftpd.c
--- libexec/tftpd/tftpd.c.orig	Thu Jul 27 13:14:46 2006
+++ libexec/tftpd/tftpd.c	Thu Jul 27 13:17:28 2006
@@ -538,8 +538,14 @@ validate_access(char **filep, int mode)
 				dirp->name, filename);
 			if (stat(pathname, &stbuf) == 0 &&
 			    (stbuf.st_mode & S_IFMT) == S_IFREG) {
-				if ((stbuf.st_mode & S_IROTH) != 0) {
-					break;
+				if (mode == RRQ) {
+					if ((stbuf.st_mode & S_IROTH) != 0) {
+						break;
+					}
+				} else {
+					if ((stbuf.st_mode & S_IWOTH) != 0) {
+						break;
+					}
 				}
 				err = EACCESS;
 			}
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607271044.k6RAiNTX008800>