Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Sep 2014 16:28:23 -0400
From:      Patrick Kelsey <pkelsey@freebsd.org>
To:        current@freebsd.org
Cc:        George Neville-Neil <gnn@freebsd.org>
Subject:   _ftello() modification requires additional capsicum rights, breaking tcpdump and dhclient
Message-ID:  <CAD44qMWgWn_OZ1i0Jy2WTLY=YAai%2B6-_Bq24QN-AjD9iYJ2JOA@mail.gmail.com>

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

[-- Attachment #1 --]
In r268997, _ftello() was modified to use _fcntl(F_GETFL) in the
non-append, write-only path.  Consequently, programs that use _ftello()
(via ftell, fgetpos, fsetpos, fseek, rewind...) on non-append, write-only
files and that use capsicum to restrict capabilities on the associated fds
to [CAP_SEEK, CAP_WRITE] broke as all ftell() (and friends) calls on those
files fail with ENOTCAPABLE due to lack of CAP_FCNTL rights.  There appear
to be only two affected programs in the tree - tcpdump and dhclient.  This
affects both CURRENT and 10-STABLE (including 10.1-PRERELEASE)

tcpdump, when configured to write to capture files rotated by size, fails
to rotate and captures indefinitely to the first file in the series.  This
can be reproduced by a command such as: tcpdump -i <ifname> -C 1 -W 2 -w
packets -v

By inspection, dhclient will fail to trim old data from its client leases
file when rewriting that file with a lesser amount of data than it
currently contains.  See the ftruncate() call in
dhclient.c:rewrite_client_leases().

The attached patch adds CAP_FCNTL to the limited rights established for
non-append, write-only files used by tcpdump and dhclient.  It also
restricts the fcntl rights to CAP_FCNTL_GETFL.

The current need to have CAP_FCNTL rights in order to get or set the file
position on non-append, write-only files is subtle.  Perhaps part of the
answer is to define a CAP_FSEEK right in sys/capability.h that resolves to
CAP_SEEK|CAP_FCNTL, or to modify the CAP_SEEK description in rights(4) to
note the need for CAP_FCNTL when using ftell() and friends.

-Patrick

[-- Attachment #2 --]
Index: contrib/tcpdump/tcpdump.c
===================================================================
--- contrib/tcpdump/tcpdump.c	(revision 271281)
+++ contrib/tcpdump/tcpdump.c	(working copy)
@@ -1566,11 +1566,15 @@
 		if (p == NULL)
 			error("%s", pcap_geterr(pd));
 #ifdef __FreeBSD__
-		cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+		cap_rights_init(&rights, CAP_SEEK, CAP_FCNTL, CAP_WRITE);
 		if (cap_rights_limit(fileno(pcap_dump_file(p)), &rights) < 0 &&
 		    errno != ENOSYS) {
 			error("unable to limit dump descriptor");
 		}
+		if (cap_fcntls_limit(fileno(pcap_dump_file(p)), CAP_FCNTL_GETFL) < 0 &&
+		    errno != ENOSYS) {
+			error("unable to limit dump descriptor fcntls");
+		}
 #endif
 		if (Cflag != 0 || Gflag != 0) {
 #ifdef __FreeBSD__
@@ -1994,11 +1998,15 @@
 			if (dump_info->p == NULL)
 				error("%s", pcap_geterr(pd));
 #ifdef __FreeBSD__
-			cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+			cap_rights_init(&rights, CAP_SEEK, CAP_FCNTL, CAP_WRITE);
 			if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
 			    &rights) < 0 && errno != ENOSYS) {
 				error("unable to limit dump descriptor");
 			}
+			if (cap_fcntls_limit(fileno(pcap_dump_file(dump_info->p)),
+			    CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) {
+				error("unable to limit dump descriptor fcntls");
+			}
 #endif
 		}
 	}
@@ -2055,11 +2063,15 @@
 		if (dump_info->p == NULL)
 			error("%s", pcap_geterr(pd));
 #ifdef __FreeBSD__
-		cap_rights_init(&rights, CAP_SEEK, CAP_WRITE);
+		cap_rights_init(&rights, CAP_SEEK, CAP_FCNTL, CAP_WRITE);
 		if (cap_rights_limit(fileno(pcap_dump_file(dump_info->p)),
 		    &rights) < 0 && errno != ENOSYS) {
 			error("unable to limit dump descriptor");
 		}
+		if (cap_fcntls_limit(fileno(pcap_dump_file(dump_info->p)),
+		    CAP_FCNTL_GETFL) < 0 && errno != ENOSYS) {
+			error("unable to limit dump descriptor fcntls");
+		}
 #endif
 	}
 
Index: sbin/dhclient/dhclient.c
===================================================================
--- sbin/dhclient/dhclient.c	(revision 271281)
+++ sbin/dhclient/dhclient.c	(working copy)
@@ -1846,11 +1846,15 @@
 		if (!leaseFile)
 			error("can't create %s: %m", path_dhclient_db);
 		cap_rights_init(&rights, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE,
-		    CAP_SEEK, CAP_WRITE);
+		    CAP_SEEK, CAP_FCNTL, CAP_WRITE);
 		if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
 		    errno != ENOSYS) {
 			error("can't limit lease descriptor: %m");
 		}
+		if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 &&
+		    errno != ENOSYS) {
+			error("can't limit lease descriptor fcntls: %m");
+		}
 	} else {
 		fflush(leaseFile);
 		rewind(leaseFile);

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAD44qMWgWn_OZ1i0Jy2WTLY=YAai%2B6-_Bq24QN-AjD9iYJ2JOA>