int sys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap) { struct filedesc *fdp; struct filedescent *fdep; u_long *cmdsp, *dstcmds; size_t maxcmds, ncmds; int16_t count; int error, fd; fd = uap->fd; dstcmds = uap->cmds; maxcmds = uap->maxcmds; AUDIT_ARG_FD(fd); fdp = td->td_proc->p_fd; 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. */ 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; } error = 0; out: free(cmdsp, M_FILECAPS); return (error); }
/* * Test whether a capability grants the given ioctl command. * If descriptor doesn't have CAP_IOCTL, then ioctls list is empty and * ENOTCAPABLE will be returned. */ int cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd) { struct filedescent *fdep; u_long *cmds; ssize_t ncmds; long i; KASSERT(fd >= 0 && fd < fdp->fd_nfiles, ("%s: invalid fd=%d", __func__, fd)); fdep = fdeget_locked(fdp, fd); KASSERT(fdep != NULL, ("%s: invalid fd=%d", __func__, fd)); ncmds = fdep->fde_nioctls; if (ncmds == -1) return (0); cmds = fdep->fde_ioctls; for (i = 0; i < ncmds; i++) { if (cmds[i] == cmd) return (0); } return (ENOTCAPABLE); }
int kern_cap_rights_limit(struct thread *td, int fd, cap_rights_t *rights) { struct filedesc *fdp; struct filedescent *fdep; int error; fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); fdep = fdeget_locked(fdp, fd); if (fdep == NULL) { FILEDESC_XUNLOCK(fdp); return (EBADF); } error = _cap_check(cap_rights(fdp, fd), rights, CAPFAIL_INCREASE); if (error == 0) { fdep->fde_rights = *rights; if (!cap_rights_is_set(rights, CAP_IOCTL)) { free(fdep->fde_ioctls, M_FILECAPS); fdep->fde_ioctls = NULL; fdep->fde_nioctls = 0; } if (!cap_rights_is_set(rights, CAP_FCNTL)) fdep->fde_fcntls = 0; } FILEDESC_XUNLOCK(fdp); return (error); }
int kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds) { struct filedesc *fdp; struct filedescent *fdep; u_long *ocmds; int error; AUDIT_ARG_FD(fd); if (ncmds > IOCTLS_MAX_COUNT) { error = EINVAL; goto out_free; } fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); fdep = fdeget_locked(fdp, fd); if (fdep == NULL) { error = EBADF; goto out; } error = cap_ioctl_limit_check(fdep, cmds, ncmds); if (error != 0) goto out; ocmds = fdep->fde_ioctls; fdep->fde_ioctls = cmds; fdep->fde_nioctls = ncmds; cmds = ocmds; error = 0; out: FILEDESC_XUNLOCK(fdp); out_free: free(cmds, M_FILECAPS); return (error); }
int sys_cap_fcntls_get(struct thread *td, struct cap_fcntls_get_args *uap) { struct filedesc *fdp; struct filedescent *fdep; uint32_t rights; int fd; fd = uap->fd; AUDIT_ARG_FD(fd); fdp = td->td_proc->p_fd; FILEDESC_SLOCK(fdp); fdep = fdeget_locked(fdp, fd); if (fdep == NULL) { FILEDESC_SUNLOCK(fdp); return (EBADF); } rights = fdep->fde_fcntls; FILEDESC_SUNLOCK(fdp); return (copyout(&rights, uap->fcntlrightsp, sizeof(rights))); }
int sys_cap_fcntls_limit(struct thread *td, struct cap_fcntls_limit_args *uap) { struct filedesc *fdp; struct filedescent *fdep; uint32_t fcntlrights; int fd; fd = uap->fd; fcntlrights = uap->fcntlrights; AUDIT_ARG_FD(fd); AUDIT_ARG_FCNTL_RIGHTS(fcntlrights); if ((fcntlrights & ~CAP_FCNTL_ALL) != 0) return (EINVAL); fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); fdep = fdeget_locked(fdp, fd); if (fdep == NULL) { FILEDESC_XUNLOCK(fdp); return (EBADF); } if ((fcntlrights & ~fdep->fde_fcntls) != 0) { FILEDESC_XUNLOCK(fdp); return (ENOTCAPABLE); } fdep->fde_fcntls = fcntlrights; FILEDESC_XUNLOCK(fdp); return (0); }