Changeset View
Standalone View
sys/kern/kern_descrip.c
Show First 20 Lines • Show All 1,250 Lines • ▼ Show 20 Lines | if ((fp = fget_locked(fdp, fd)) == NULL) { | ||||
return (EBADF); | return (EBADF); | ||||
} | } | ||||
fdfree(fdp, fd); | fdfree(fdp, fd); | ||||
/* closefp() drops the FILEDESC lock for us. */ | /* closefp() drops the FILEDESC lock for us. */ | ||||
return (closefp(fdp, fd, fp, td, 1)); | return (closefp(fdp, fd, fp, td, 1)); | ||||
} | } | ||||
int | |||||
kern_close_range(struct thread *td, u_int lowfd, u_int highfd) | |||||
{ | |||||
struct filedesc *fdp; | |||||
int fd, ret; | |||||
ret = 0; | |||||
fdp = td->td_proc->p_fd; | |||||
FILEDESC_SLOCK(fdp); | |||||
/* Clamped to [lowfd, fd_lastfile] */ | |||||
markj: Is it intended for userland to be able to pass KERN_CLOSE_RANGE_MAXFD? If not we should check… | |||||
Done Inline ActionsHmm... based on the current definition of our close_range, we would have to since Linux is expecting ~0U to close all fd, and I've represented both fd parameters as int. I guess I should likely change this to u_int to match -- I didn't pay enough detail to this initially, and we usually don't accept unsigned fd in syscalls so I didn't think much of it. kevans: Hmm... based on the current definition of our close_range, we would have to since Linux is… | |||||
Done Inline Actionslowfd and highfd are not really descriptors, but rather bounds for a range of descriptors. Having fds typed as int is useful for detecting a programming error that results in userland specifying an fd of -1, but here we give a special meaning to a value of -1 (or ~0U, whatever) for highfd. So from that perspective, using u_int makes sense to me. Since we are allowing ~0U from userspace, should that be documented in the man page? markj: lowfd and highfd are not really descriptors, but rather bounds for a range of descriptors. | |||||
Done Inline ActionsFair- I'll go ahead and change that to match. I think once the implementation takes unsigned values instead, documenting it specifically in the manpage doesn't mean too much. At that point, there is no specific check for ~0U and it's no longer a violation of what would normally return EINVAL, it just gets naturally clamped down to fdp->fd_lastfile and the manpage should make sure to indicate that lowfd, highfd will get clamped to the valid range. kevans: Fair- I'll go ahead and change that to match.
I think once the implementation takes unsigned… | |||||
highfd = MIN(highfd, fdp->fd_lastfile); | |||||
if (highfd < lowfd) { | |||||
markjUnsubmitted Not Done Inline ActionsShouldn't the check come before the clamp? Suppose a process has descriptors 0, 1 and 2 open and fd_lastfile is 2. closefrom(3) would return EINVAL. markj: Shouldn't the check come before the clamp? Suppose a process has descriptors 0, 1 and 2 open… | |||||
kevansAuthorUnsubmitted Done Inline ActionsHmm... I thought I had wanted different semantics for close_range (i.e. close_range(3, ~0U, 0) in that same scenario to return EINVAL), but I suppose that also makes little sense. kevans: Hmm... I thought I had wanted different semantics for close_range (i.e. `close_range(3, ~0U… | |||||
ret = EINVAL; | |||||
goto out; | |||||
} | |||||
for (fd = lowfd; fd <= highfd; fd++) { | |||||
if (fdp->fd_ofiles[fd].fde_file != NULL) { | |||||
FILEDESC_SUNLOCK(fdp); | |||||
(void)kern_close(td, fd); | |||||
FILEDESC_SLOCK(fdp); | |||||
} | |||||
} | |||||
out: | |||||
FILEDESC_SUNLOCK(fdp); | |||||
return (ret); | |||||
} | |||||
#ifndef _SYS_SYSPROTO_H_ | |||||
struct close_range_args { | |||||
u_int lowfd; | |||||
u_int highfd; | |||||
int flags; | |||||
}; | |||||
#endif | |||||
int | |||||
sys_close_range(struct thread *td, struct close_range_args *uap) | |||||
{ | |||||
/* No flags currently defined */ | |||||
if (uap->flags != 0) | |||||
return (EINVAL); | |||||
/* | /* | ||||
Done Inline Actionss/available/defined/ kib: s/available/defined/ | |||||
* We won't sanity check lowfd < highfd here because highfd may be | |||||
* clamped down to the highest fd opened, which could be lower than | |||||
* lowfd while highfd wouldn't be. Let the implementation validate | |||||
* the range of fd and return an error as necessary. | |||||
*/ | |||||
return (kern_close_range(td, uap->lowfd, uap->highfd)); | |||||
} | |||||
/* | |||||
* Close open file descriptors. | * Close open file descriptors. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct closefrom_args { | struct closefrom_args { | ||||
int lowfd; | int lowfd; | ||||
}; | }; | ||||
#endif | #endif | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
int | int | ||||
sys_closefrom(struct thread *td, struct closefrom_args *uap) | sys_closefrom(struct thread *td, struct closefrom_args *uap) | ||||
{ | { | ||||
struct filedesc *fdp; | u_int lowfd; | ||||
int fd; | |||||
fdp = td->td_proc->p_fd; | |||||
AUDIT_ARG_FD(uap->lowfd); | AUDIT_ARG_FD(uap->lowfd); | ||||
/* | /* | ||||
* Treat negative starting file descriptor values identical to | * Treat negative starting file descriptor values identical to | ||||
* closefrom(0) which closes all files. | * closefrom(0) which closes all files. | ||||
*/ | */ | ||||
if (uap->lowfd < 0) | lowfd = MAX(0, uap->lowfd); | ||||
uap->lowfd = 0; | return (kern_close_range(td, lowfd, ~0U)); | ||||
FILEDESC_SLOCK(fdp); | |||||
for (fd = uap->lowfd; fd <= fdp->fd_lastfile; fd++) { | |||||
if (fdp->fd_ofiles[fd].fde_file != NULL) { | |||||
FILEDESC_SUNLOCK(fdp); | |||||
(void)kern_close(td, fd); | |||||
FILEDESC_SLOCK(fdp); | |||||
} | |||||
} | |||||
FILEDESC_SUNLOCK(fdp); | |||||
return (0); | |||||
} | } | ||||
#if defined(COMPAT_43) | #if defined(COMPAT_43) | ||||
/* | /* | ||||
* Return status information about a file descriptor. | * Return status information about a file descriptor. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct ofstat_args { | struct ofstat_args { | ||||
▲ Show 20 Lines • Show All 2,960 Lines • Show Last 20 Lines |
Is it intended for userland to be able to pass KERN_CLOSE_RANGE_MAXFD? If not we should check for it in the sys_ wrapper and return EINVAL.