Bug 19363

Summary: [kernel] [patch] allow processes know about their file descriptors, reliably & efficiently
Product: Base System Reporter: Valentin Nechayev <netch>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Valentin Nechayev 2000-06-18 12:40:01 UTC
The goal is described in synopsis field. I suppose it is really useful now.
Reasons (mostly in field of security):

1) On exec(), caller can pass any descriptor to called program. This can
be used for DoS attacks: i.e., sendmail slowly sends a letter and locks
some file system from unmounting. (The situation is semi phantastic,
but only "semi".)

2)

==={
root@nn:~##sysctl -a | grep chroot
kern.chroot_allow_open_directories: 1
root@nn:~##
===}

This is, of course, good idea ;|, but it is correct to provide more
flexibility for programs, isn't it? :)

3) Some programs (sendmail, uucico) try to close all extra files, but
they do it ugly and non-reliably (getdtablesize() does not report possible
descriptors which are more that soft rlimit). This ugly method should be
changed to something similar to
==={
	while ((o = getfd(GETFD_NEXT, 2)) != -1)
		close(o);
===}
and at least added to most setuid/setgid programs, for safety sake.

Fix: Add syscall with following implementation.

=== cut here ===


Selected syscall number, of course, does not matter.;) Iteration in both
upper and lower should be sufficient for first time. Possible progress
for next extension may be adding filter on f_type field value of struct file.

PS. Possibly, MPSAFE can be added to getfd() syscall description.

--
NVA--WvNBV9TxTAg0BD8NXM9DVZr6YqyW6V6tSvgGVSn7b5lzFs9U
Content-Type: text/plain; name="file.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="file.diff"

--- src/include/unistd.h.orig	Sat Jun 17 22:56:11 2000
+++ src/include/unistd.h	Sat Jun 17 22:57:39 2000
@@ -134,6 +134,7 @@
 #endif
 int	 getdomainname __P((char *, int));
 int	 getdtablesize __P((void));
+int	 getfd __P((int, int));
 int	 getgrouplist __P((const char *, int, int *, int *));
 long	 gethostid __P((void));
 int	 gethostname __P((char *, int));
--- kern_descrip.c.orig	Fri Jun 16 00:05:49 2000
+++ kern_descrip.c	Sat Jun 17 23:18:40 2000
@@ -124,6 +124,49 @@
 }
 
 /*
+ * Query used descriptors
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct getfd_args {
+	int query;
+	int param;
+};
+#endif
+int
+getfd(p, uap)
+	struct proc *p;
+	struct getfd_args *uap;
+{
+	register struct filedesc *fdp = p->p_fd;
+	register int i;
+	if (uap->query == GETFD_NEXT) {
+		i = uap->param + 1;
+		if (i < 0)
+			i = 0;
+		for (; i < fdp->fd_nfiles; i++) {
+			if (fdp->fd_ofiles[i] != NULL) {
+				p->p_retval[0] = i;
+				return (0);
+			}
+		}
+		return (EBADF);
+	}
+	if (uap->query == GETFD_PREV) {
+		i = uap->param - 1;
+		if (i < 0 || i >= fdp->fd_nfiles)
+			i = fdp->fd_nfiles - 1;
+		for (; i >= 0; i--) {
+			if (fdp->fd_ofiles[i] != NULL) {
+				p->p_retval[0] = i;
+				return (0);
+			}
+		}
+		return (EBADF);
+	}
+	return (EINVAL);
+}
+
+/*
  * Duplicate a file descriptor to a particular value.
  */
 #ifndef _SYS_SYSPROTO_H_
--- src/sys/kern/syscalls.master.orig	Sun Jun 18 14:16:27 2000
+++ src/sys/kern/syscalls.master	Sun Jun 18 14:17:07 2000
@@ -520,3 +520,4 @@
 			    int nchanges, struct kevent **changelist, \
 			    int nevents, struct kevent *eventlist, \
 			    struct timespec *timeout); }
+364	STD	BSD	{ int getfd( int query, int param); }
--- src/sys/sys/unistd.h.orig	Wed May 10 08:16:11 2000
+++ src/sys/sys/unistd.h	Sat Jun 17 23:00:49 2000
@@ -219,6 +219,12 @@
 #define RFLINUXTHPN     (1<<16) /* do linux clone exit parent notification */
 #define RFPPWAIT	(1<<31) /* parent sleeps until child exits (vfork) */
 
+/*
+ * getfd() queries
+ */
+#define GETFD_NEXT	0
+#define GETFD_PREV	1
+
 #endif /* !_POSIX_SOURCE */
 
 #endif /* !_SYS_UNISTD_H_ */
=== end cut ===
How-To-Repeat: 
;)
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2005-10-24 03:14:21 UTC
State Changed
From-To: open->suspended

Mark as 'suspended' since this does not seem as though it is being 
actively worked on.
Comment 2 Valentin Nechayev 2006-07-05 15:18:55 UTC
1. Another bad behaved program is erlang:( Closing all descriptors up to 
rlimit (7264 now at my system)
2. Now I think this shall be not separate syscall, but fcntl() 
subcommand; changes are trivial


-netch-
Comment 3 John Baldwin freebsd_committer freebsd_triage 2009-06-16 14:29:01 UTC
State Changed
From-To: suspended->closed

This functionality has been implemented as a new closefrom(2) system call.