capsicum: perform copyout without the fildesc lock held in sys_cap_ioctls_get

Reviewed by:	pjd
This commit is contained in:
Mariusz Zaborski 2016-10-21 16:12:23 +00:00
parent a7a560be79
commit 4b83a77606
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=307734

View File

@ -89,6 +89,8 @@ SYSCTL_INT(_kern, OID_AUTO, trap_enotcap, CTLFLAG_RW, &trap_enotcap, 0,
#ifdef CAPABILITY_MODE
#define IOCTLS_MAX_COUNT 256 /* XXX: Is 256 sane? */
FEATURE(security_capability_mode, "Capsicum Capability Mode");
/*
@ -398,6 +400,11 @@ kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds)
AUDIT_ARG_FD(fd);
if (ncmds > IOCTLS_MAX_COUNT) {
error = EINVAL;
goto out_free;
}
fdp = td->td_proc->p_fd;
FILEDESC_XLOCK(fdp);
@ -418,6 +425,7 @@ kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds)
error = 0;
out:
FILEDESC_XUNLOCK(fdp);
out_free:
free(cmds, M_FILECAPS);
return (error);
}
@ -431,7 +439,7 @@ sys_cap_ioctls_limit(struct thread *td, struct cap_ioctls_limit_args *uap)
ncmds = uap->ncmds;
if (ncmds > 256) /* XXX: Is 256 sane? */
if (ncmds > IOCTLS_MAX_COUNT)
return (EINVAL);
if (ncmds == 0) {
@ -453,45 +461,59 @@ sys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap)
{
struct filedesc *fdp;
struct filedescent *fdep;
u_long *cmds;
size_t maxcmds;
u_long *cmdsp, *dstcmds;
size_t maxcmds, ncmds;
int16_t count;
int error, fd;
fd = uap->fd;
cmds = uap->cmds;
dstcmds = uap->cmds;
maxcmds = uap->maxcmds;
AUDIT_ARG_FD(fd);
fdp = td->td_proc->p_fd;
FILEDESC_SLOCK(fdp);
if (fget_locked(fdp, fd) == NULL) {
cmdsp = NULL;
if (dstcmds != NULL) {
cmdsp = malloc(sizeof(cmdsp[0]) * IOCTLS_MAX_COUNT, M_FILECAPS,
M_WAITOK | M_ZERO);
}
FILEDESC_SLOCK(fdp);
fdep = fdeget_locked(fdp, fd);
if (fdep == NULL) {
error = EBADF;
FILEDESC_SUNLOCK(fdp);
goto out;
}
count = fdep->fde_nioctls;
if (count != -1 && cmdsp != NULL) {
ncmds = MIN(count, maxcmds);
memcpy(cmdsp, fdep->fde_ioctls, sizeof(cmdsp[0]) * ncmds);
}
FILEDESC_SUNLOCK(fdp);
/*
* If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL)
* the only sane thing we can do is to not populate the given array and
* return CAP_IOCTLS_ALL.
*/
fdep = &fdp->fd_ofiles[fd];
if (cmds != NULL && fdep->fde_ioctls != NULL) {
error = copyout(fdep->fde_ioctls, cmds,
sizeof(cmds[0]) * MIN(fdep->fde_nioctls, maxcmds));
if (error != 0)
goto out;
}
if (fdep->fde_nioctls == -1)
if (count != -1) {
if (cmdsp != NULL) {
error = copyout(cmdsp, dstcmds,
sizeof(cmdsp[0]) * ncmds);
if (error != 0)
goto out;
}
td->td_retval[0] = count;
} else {
td->td_retval[0] = CAP_IOCTLS_ALL;
else
td->td_retval[0] = fdep->fde_nioctls;
}
error = 0;
out:
FILEDESC_SUNLOCK(fdp);
free(cmdsp, M_FILECAPS);
return (error);
}