static int mmopen(dev_t dev, int flags, int fmt, struct thread *td) { int error; switch (minor(dev)) { case 0: case 1: if (flags & FWRITE) { error = securelevel_gt(td->td_ucred, 0); if (error != 0) return (error); } break; case 14: error = suser(td); if (error != 0) return (error); error = securelevel_gt(td->td_ucred, 0); if (error != 0) return (error); td->td_frame->tf_rflags |= PSL_IOPL; break; } return (0); }
/* * Lookup and potentially load the specified firmware image. * If the firmware is not found in the registry, try to load a kernel * module named as the image name. * If the firmware is located, a reference is returned. The caller must * release this reference for the image to be eligible for removal/unload. */ const struct firmware * firmware_get(const char *imagename) { struct task fwload_task; struct thread *td; struct priv_fw *fp; mtx_lock(&firmware_mtx); fp = lookup(imagename, NULL); if (fp != NULL) goto found; /* * Image not present, try to load the module holding it. */ td = curthread; if (priv_check(td, PRIV_FIRMWARE_LOAD) != 0 || securelevel_gt(td->td_ucred, 0) != 0) { mtx_unlock(&firmware_mtx); printf("%s: insufficient privileges to " "load firmware image %s\n", __func__, imagename); return NULL; } /* * Defer load to a thread with known context. linker_reference_module * may do filesystem i/o which requires root & current dirs, etc. * Also we must not hold any mtx's over this call which is problematic. */ if (!cold) { TASK_INIT(&fwload_task, 0, loadimage, __DECONST(void *, imagename)); taskqueue_enqueue(firmware_tq, &fwload_task); msleep(__DECONST(void *, imagename), &firmware_mtx, 0, "fwload", 0); }
/* ARGSUSED */ static int random_close(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) { if (flags & FWRITE) { if (!(suser(td) || securelevel_gt(td->td_ucred, 0))) random_reseed(); } return 0; }
static int pci_open(struct dev_open_args *ap) { #if 0 int error; if (oflags & FWRITE) { error = securelevel_gt(td->td_ucred, 0); if (error) return (error); } #endif return (0); }
static int pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { int error; if (oflags & FWRITE) { error = securelevel_gt(td->td_ucred, 0); if (error) return (error); } return (0); }
/* ARGSUSED */ static int random_open(dev_t dev __unused, int flags, int fmt __unused, struct thread *td) { int error; if (flags & FWRITE) { error = suser(td); if (error) return (error); error = securelevel_gt(td->td_ucred, 0); if (error) return (error); } return 0; }
int linux_iopl(struct thread *td, struct linux_iopl_args *args) { int error; LINUX_CTR(iopl); if (args->level > 3) return (EINVAL); if ((error = priv_check(td, PRIV_IO)) != 0) return (error); if ((error = securelevel_gt(td->td_ucred, 0)) != 0) return (error); td->td_frame->tf_rflags = (td->td_frame->tf_rflags & ~PSL_IOPL) | (args->level * (PSL_IOPL / 3)); return (0); }
/* * Set attribute vnode op. called from several syscalls */ static int ext2_setattr(struct vop_setattr_args *ap) { struct vattr *vap = ap->a_vap; struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); struct ucred *cred = ap->a_cred; struct thread *td = curthread; int error; /* * Check for unsettable attributes. */ if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { return (EINVAL); } if (vap->va_flags != VNOVAL) { /* Disallow flags not supported by ext2fs. */ if(vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP)) return (EOPNOTSUPP); if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); /* * Callers may only modify the file flags on objects they * have VADMIN rights for. */ if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) return (error); /* * Unprivileged processes and privileged processes in * jail() are not permitted to unset system flags, or * modify flags if any system flags are set. * Privileged non-jail processes may not modify system flags * if securelevel > 0 and any existing system flags are set. */ if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) { if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) { error = securelevel_gt(cred, 0); if (error) return (error); } } else { if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) || ((vap->va_flags ^ ip->i_flags) & SF_SETTABLE)) return (EPERM); } ip->i_flags = vap->va_flags; ip->i_flag |= IN_CHANGE; if (ip->i_flags & (IMMUTABLE | APPEND)) return (0); } if (ip->i_flags & (IMMUTABLE | APPEND)) return (EPERM); /* * Go through the fields and update iff not VNOVAL. */ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred, td)) != 0) return (error); } if (vap->va_size != VNOVAL) { /* * Disallow write attempts on read-only file systems; * unless the file is a socket, fifo, or a block or * character device resident on the file system. */ switch (vp->v_type) { case VDIR: return (EISDIR); case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); break; default: break; } if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0) return (error); } if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); /* * From utimes(2): * If times is NULL, ... The caller must be the owner of * the file, have permission to write the file, or be the * super-user. * If times is non-NULL, ... The caller must be the owner of * the file or be the super-user. */ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) && ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || (error = VOP_ACCESS(vp, VWRITE, cred, td)))) return (error); if (vap->va_atime.tv_sec != VNOVAL) ip->i_flag |= IN_ACCESS; if (vap->va_mtime.tv_sec != VNOVAL) ip->i_flag |= IN_CHANGE | IN_UPDATE; ext2_itimes(vp); if (vap->va_atime.tv_sec != VNOVAL) { ip->i_atime = vap->va_atime.tv_sec; ip->i_atimensec = vap->va_atime.tv_nsec; } if (vap->va_mtime.tv_sec != VNOVAL) { ip->i_mtime = vap->va_mtime.tv_sec; ip->i_mtimensec = vap->va_mtime.tv_nsec; } ip->i_birthtime = vap->va_birthtime.tv_sec; ip->i_birthnsec = vap->va_birthtime.tv_nsec; error = ext2_update(vp, 0); if (error) return (error); } error = 0; if (vap->va_mode != (mode_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); error = ext2_chmod(vp, (int)vap->va_mode, cred, td); } return (error); }
static int sysctl_control(SYSCTL_HANDLER_ARGS) { secadm_command_t cmd; secadm_reply_t reply; int err; if (!(req->newptr) || (req->newlen != sizeof(secadm_command_t))) return (EINVAL); if (!(req->oldptr) || (req->oldlen) != sizeof(secadm_reply_t)) return (EINVAL); err = SYSCTL_IN(req, &cmd, sizeof(secadm_command_t)); if (err) return (err); /* Access control comes first */ switch (cmd.sc_type) { case secadm_flush_rules: case secadm_set_rules: /* XXX Should we cache the ucred for local use in the * sysctl lifecycle? */ // XXXOP LOCKING if (req->td->td_ucred->cr_uid != 0) { printf("[SECADM] Disallowed command: 0x%x by uid: %d\n", cmd.sc_type, req->td->td_ucred->cr_uid); return (EPERM); } // XXXOP LOCKING if (securelevel_gt(req->td->td_ucred, 0)) { printf("[SECADM] Disallowed command: 0x%x by uid: %d\n", cmd.sc_type, req->td->td_ucred->cr_uid); return (EPERM); } break; default: break; } /* XXX We should relax this check once we get stable releases. */ if (cmd.sc_version < SECADM_VERSION) return (EINVAL); memset(&reply, 0x00, sizeof(reply)); if ((err = copyin(req->oldptr, &reply, sizeof(reply)))) return (err); reply.sr_version = SECADM_VERSION; reply.sr_id = cmd.sc_id; switch (cmd.sc_type) { case secadm_get_version: if (cmd.sc_bufsize < sizeof(unsigned long)) return (EINVAL); handle_version_command(&cmd, &reply); break; case secadm_set_rules: if (cmd.sc_size != sizeof(secadm_rule_t)) return (EINVAL); handle_add_rule(req->td, &cmd, &reply); break; case secadm_flush_rules: flush_rules(req->td); break; case secadm_get_rule_size: handle_get_rule_size(req->td, &cmd, &reply); break; case secadm_get_num_rules: get_num_rules(req->td, &cmd, &reply); break; case secadm_get_rule: handle_get_rule(req->td, &cmd, &reply); break; case secadm_get_rules: case secadm_get_admins: case secadm_set_admins: case secadm_get_views: case secadm_set_views: return (ENOTSUP); default: // XXXOP LOCKING printf("[SECADM] Unknown command: 0x%x by uid: %d\n", cmd.sc_type, req->td->td_ucred->cr_uid); return (EINVAL); } err = SYSCTL_OUT(req, &reply, sizeof(secadm_reply_t)); return (err); }