int secadm_vnode_check_open(struct ucred *ucred, struct vnode *vp, struct label *label, accmode_t accmode) { struct rm_priotracker tracker; struct secadm_prison_entry *entry; secadm_rule_t *rule; struct vattr vap; int err, res; if (!(accmode & (VWRITE | VAPPEND))) return (0); res = 0; entry = get_prison_list_entry(ucred->cr_prison->pr_name, 0); if (entry == NULL) return (0); err = VOP_GETATTR(vp, &vap, ucred); if (err) return (err); SPL_RLOCK(entry, tracker); for (rule = entry->spl_rules; rule != NULL; rule = rule->sr_next) { if (vap.va_fileid != rule->sr_inode) continue; if (strcmp(vp->v_mount->mnt_stat.f_mntonname, rule->sr_mount)) continue; if (lookup_integriforce_feature(rule) != NULL) { KASSERT(rule != NULL && rule->sr_path != NULL, ("%s: failed ...", __func__)); printf("[SECADM] Warning: A process tried to modify " "file %s, which is protected by a secadm rule. " "Returning EPERM.\n", rule->sr_path); res=EPERM; } break; } SPL_RUNLOCK(entry, tracker); return (res); }
int secadm_vnode_check_unlink(struct ucred *ucred, struct vnode *dvp, struct label *dvplabel, struct vnode *vp, struct label *vplabel, struct componentname *cnp) { struct rm_priotracker tracker; struct secadm_prison_entry *entry; secadm_rule_t *rule; struct vattr vap; int err, res=0; entry = get_prison_list_entry(ucred->cr_prison->pr_name, 0); if (entry == NULL) return (0); err = VOP_GETATTR(vp, &vap, ucred); if (err) return (err); SPL_RLOCK(entry, tracker); for (rule = entry->spl_rules; rule != NULL; rule = rule->sr_next) { if (vap.va_fileid != rule->sr_inode) continue; if (strcmp(vp->v_mount->mnt_stat.f_mntonname, rule->sr_mount)) continue; KASSERT(rule != NULL && rule->sr_path != NULL, ("%s: failed ...", __func__)); printf("[SECADM] Prevented to unlink %s: protected by a secadm rule.\n", rule->sr_path); res=EPERM; break; } SPL_RUNLOCK(entry, tracker); return (res); }
static int sysctl_integriforce_so(SYSCTL_HANDLER_ARGS) { integriforce_so_check_t *integriforce_so; secadm_prison_entry_t *entry; secadm_rule_t r, *rule; struct nameidata nd; struct vattr vap; secadm_key_t key; int err; if (!(req->newptr) || req->newlen != sizeof(integriforce_so_check_t)) return (EINVAL); if (!(req->oldptr) || req->oldlen != sizeof(integriforce_so_check_t)) return (EINVAL); integriforce_so = malloc(sizeof(integriforce_so_check_t), M_SECADM, M_WAITOK); err = SYSCTL_IN(req, integriforce_so, sizeof(integriforce_so_check_t)); if (err) { free(integriforce_so, M_SECADM); return (err); } NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, integriforce_so->isc_path, req->td); err = namei(&nd); if (err) { free(integriforce_so, M_SECADM); NDFREE(&nd, 0); return (err); } if ((err = vn_lock(nd.ni_vp, LK_SHARED | LK_RETRY)) != 0) { free(integriforce_so, M_SECADM); NDFREE(&nd, 0); return (err); } err = VOP_GETATTR(nd.ni_vp, &vap, req->td->td_ucred); if (err) { free(integriforce_so, M_SECADM); NDFREE(&nd, 0); return (err); } VOP_UNLOCK(nd.ni_vp, 0); key.sk_jid = req->td->td_ucred->cr_prison->pr_id; key.sk_type = secadm_integriforce_rule; key.sk_fileid = vap.va_fileid; strncpy(key.sk_mntonname, nd.ni_vp->v_mount->mnt_stat.f_mntonname, MNAMELEN); r.sr_key = fnv_32_buf(&key, sizeof(secadm_key_t), FNV1_32_INIT); entry = get_prison_list_entry( req->td->td_ucred->cr_prison->pr_id); PE_RLOCK(entry); rule = RB_FIND(secadm_rules_tree, &(entry->sp_rules), &r); if (rule) { integriforce_so->isc_result = do_integriforce_check(rule, &vap, nd.ni_vp, req->td->td_ucred); } PE_RUNLOCK(entry); SYSCTL_OUT(req, integriforce_so, sizeof(integriforce_so_check_t)); free(integriforce_so, M_SECADM); NDFREE(&nd, 0); return (0); }
int secadm_vnode_check_exec(struct ucred *ucred, struct vnode *vp, struct label *vplabel, struct image_params *imgp, struct label *execlabel) { struct rm_priotracker tracker; struct secadm_prison_entry *entry; secadm_rule_t *rule; struct vattr vap; size_t i; int err=0, flags=0; entry = get_prison_list_entry(ucred->cr_prison->pr_name, 0); if (entry == NULL) return (0); err = VOP_GETATTR(imgp->vp, &vap, ucred); if (err) return (err); SPL_RLOCK(entry, tracker); for (rule = entry->spl_rules; rule != NULL; rule = rule->sr_next) { if (vap.va_fileid != rule->sr_inode) continue; if (strcmp(imgp->vp->v_mount->mnt_stat.f_mntonname, rule->sr_mount)) continue; for (i=0; i < rule->sr_nfeatures; i++) { switch(rule->sr_features[i].sf_type) { case pageexec_enabled: flags |= PAX_NOTE_PAGEEXEC; break; case pageexec_disabled: flags |= PAX_NOTE_NOPAGEEXEC; break; case mprotect_enabled: flags |= PAX_NOTE_MPROTECT; break; case mprotect_disabled: flags |= PAX_NOTE_NOMPROTECT; break; case segvguard_enabled: flags |= PAX_NOTE_SEGVGUARD; break; case segvguard_disabled: flags |= PAX_NOTE_NOSEGVGUARD; break; case aslr_enabled: flags |= PAX_NOTE_ASLR; break; case aslr_disabled: flags |= PAX_NOTE_NOASLR; break; case integriforce: err = do_integriforce_check(rule, &vap, imgp->vp, ucred); break; #if __HardenedBSD_version > 21 case shlibrandom_enabled: flags |= PAX_NOTE_SHLIBRANDOM; break; case shlibrandom_disabled: flags |= PAX_NOTE_NOSHLIBRANDOM; break; #endif default: break; } } break; } SPL_RUNLOCK(entry, tracker); if (err == 0 && flags) err = pax_elf(imgp, flags); return (err); }
static secadm_error_t handle_add_rule(struct thread *td, secadm_command_t *cmd, secadm_reply_t *reply) { secadm_rule_t *rule, *next, *tail; struct secadm_prison_entry *entry; size_t maxid=0; secadm_error_t res=secadm_success; int err; entry = get_prison_list_entry(td->td_ucred->cr_prison->pr_name, 1); rule = malloc(sizeof(secadm_rule_t), M_SECADM, M_WAITOK); if ((err = copyin(cmd->sc_metadata, rule, sizeof(secadm_rule_t))) != 0) { free(rule, M_SECADM); reply->sr_code = secadm_fail; reply->sr_errno = err; return (secadm_fail); } if (read_rule_from_userland(td, rule)) { reply->sr_errno = EINVAL; rule->sr_next = NULL; goto error; } rule->sr_id = maxid++; tail = rule; while (tail->sr_next != NULL) { next = malloc(sizeof(secadm_rule_t), M_SECADM, M_WAITOK); if ((err = copyin(tail->sr_next, next, sizeof(secadm_rule_t))) != 0) { reply->sr_errno = err; free(next, M_SECADM); tail->sr_next = NULL; goto error; } if (read_rule_from_userland(td, next)) { res=secadm_fail; reply->sr_errno = EINVAL; free_rule(next, 1); tail->sr_next = NULL; goto error; } next->sr_id = maxid++; tail->sr_next = next; tail = next; } if (validate_ruleset(td, rule)) { res = secadm_fail; reply->sr_errno = EINVAL; goto error; } flush_rules(td); SPL_WLOCK(entry); entry->spl_rules = rule; entry->spl_max_id = maxid; SPL_WUNLOCK(entry); reply->sr_code = secadm_success; reply->sr_errno = 0; return (0); error: while (rule != NULL) { next = rule->sr_next; free_rule(rule, 1); rule = next; } reply->sr_code = secadm_fail; return (res); }