Changeset View
Standalone View
sys/kern/kern_descrip.c
Show First 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
static __read_mostly uma_zone_t file_zone; | static __read_mostly uma_zone_t file_zone; | ||||
static __read_mostly uma_zone_t filedesc0_zone; | static __read_mostly uma_zone_t filedesc0_zone; | ||||
__read_mostly uma_zone_t pwd_zone; | __read_mostly uma_zone_t pwd_zone; | ||||
VFS_SMR_DECLARE; | VFS_SMR_DECLARE; | ||||
static int closefp(struct filedesc *fdp, int fd, struct file *fp, | static int closefp(struct filedesc *fdp, int fd, struct file *fp, | ||||
struct thread *td, bool holdleaders, bool audit); | struct thread *td, bool holdleaders, bool audit); | ||||
static void export_file_to_kinfo(struct file *fp, int fd, | |||||
cap_rights_t *rightsp, struct kinfo_file *kif, | |||||
struct filedesc *fdp, int flags); | |||||
static int fd_first_free(struct filedesc *fdp, int low, int size); | static int fd_first_free(struct filedesc *fdp, int low, int size); | ||||
static void fdgrowtable(struct filedesc *fdp, int nfd); | static void fdgrowtable(struct filedesc *fdp, int nfd); | ||||
static void fdgrowtable_exp(struct filedesc *fdp, int nfd); | static void fdgrowtable_exp(struct filedesc *fdp, int nfd); | ||||
static void fdunused(struct filedesc *fdp, int fd); | static void fdunused(struct filedesc *fdp, int fd); | ||||
static void fdused(struct filedesc *fdp, int fd); | static void fdused(struct filedesc *fdp, int fd); | ||||
static int getmaxfd(struct thread *td); | static int getmaxfd(struct thread *td); | ||||
static u_long *filecaps_copy_prep(const struct filecaps *src); | static u_long *filecaps_copy_prep(const struct filecaps *src); | ||||
static void filecaps_copy_finish(const struct filecaps *src, | static void filecaps_copy_finish(const struct filecaps *src, | ||||
▲ Show 20 Lines • Show All 731 Lines • ▼ Show 20 Lines | case F_ISUNIONSTACK: | ||||
if (mp->mnt_kern_flag & MNTK_UNIONFS || | if (mp->mnt_kern_flag & MNTK_UNIONFS || | ||||
mp->mnt_flag & MNT_UNION) | mp->mnt_flag & MNT_UNION) | ||||
td->td_retval[0] = 1; | td->td_retval[0] = 1; | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
markj: I suspect it should be at least cap_fcntl_rights. Maybe this should not be permitted in… | |||||
Done Inline ActionsSo I added this, but an after-thought is that I do not see anything wrong with resolving full path even in capability mode. What additional privilege does this resolution grant? kib: So I added this, but an after-thought is that I do not see anything wrong with resolving full… | |||||
Not Done Inline ActionsIt doesn't grant any new privileges, but it leaks information about a namespace. KERN_PROC_FILEDESC is not permitted in capability mode, for example, and the fd may have been opened by a process with more privileges than the current (sandboxed) process. As another example, we have CAP_GETPEERNAME for a socket, but this operation returns a superset of the information provided by getpeername(2), so the right can be bypassed. Hmm, I forgot that we have cap_fcntls_limit(2) and fget_fcntl(). So with a bit more work it could be possible to strip the right to call F_KINFO for a particular fd. If that is implemented, then I think it is ok to remove the IN_CAPABILITY_MODE() check. The code should also check for CAP_GETPEERNAME for a socket, though. markj: It doesn't grant any new privileges, but it leaks information about a namespace. | |||||
} | } | ||||
Done Inline ActionsShould this be ECAPMODE or ENOTCAPABLE? kib: Should this be ECAPMODE or ENOTCAPABLE? | |||||
Done Inline ActionsECAPMODE means, "this operation is not permitted in capability mode," whereas ENOTCAPABLE means "this fd has insufficient rights to perform the operation," so ECAPMODE is correct. If we added a fine-grained right(4) for this operation, like CAP_FCNTL_KINFO, and it was missing, then the error would be ENOTCAPABLE. markj: ECAPMODE means, "this operation is not permitted in capability mode," whereas ENOTCAPABLE means… | |||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
Done Inline ActionsThis should be zeroed, the fo_fill_kinfo() implementations do not handle it and we'll copy out uninitialized pad bytes. markj: This should be zeroed, the fo_fill_kinfo() implementations do not handle it and we'll copy out… | |||||
getmaxfd(struct thread *td) | getmaxfd(struct thread *td) | ||||
{ | { | ||||
return (min((int)lim_cur(td, RLIMIT_NOFILE), maxfilesperproc)); | return (min((int)lim_cur(td, RLIMIT_NOFILE), maxfilesperproc)); | ||||
} | } | ||||
/* | /* | ||||
* Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD). | * Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD). | ||||
*/ | */ | ||||
int | int | ||||
Done Inline ActionsShould this be using export_file_to_kinfo() instead of calling the file method directly? It fills out some generic fields. markj: Should this be using export_file_to_kinfo() instead of calling the file method directly? It… | |||||
kern_dup(struct thread *td, u_int mode, int flags, int old, int new) | kern_dup(struct thread *td, u_int mode, int flags, int old, int new) | ||||
{ | { | ||||
struct filedesc *fdp; | struct filedesc *fdp; | ||||
struct filedescent *oldfde, *newfde; | struct filedescent *oldfde, *newfde; | ||||
struct proc *p; | struct proc *p; | ||||
struct file *delfp, *oldfp; | struct file *delfp, *oldfp; | ||||
u_long *oioctls, *nioctls; | u_long *oioctls, *nioctls; | ||||
int error, maxfd; | int error, maxfd; | ||||
▲ Show 20 Lines • Show All 4,204 Lines • Show Last 20 Lines |
I suspect it should be at least cap_fcntl_rights. Maybe this should not be permitted in capability mode at all, it seems dubious to allow a capmode process to look up the path corresponding to an fd.