| Summary: | [kernel] [patch] allow processes know about their file descriptors, reliably & efficiently | ||
|---|---|---|---|
| Product: | Base System | Reporter: | Valentin Nechayev <netch> |
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | ||
| Priority: | Normal | ||
| Version: | Unspecified | ||
| Hardware: | Any | ||
| OS: | Any | ||
State Changed From-To: open->suspended Mark as 'suspended' since this does not seem as though it is being actively worked on. 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- State Changed From-To: suspended->closed This functionality has been implemented as a new closefrom(2) system call. |
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: ;)