static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) { char *scon = NULL, *tcon = NULL; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon = NULL; u32 len; length = task_has_security(current, SECURITY__COMPUTE_RELABEL); if (length) goto out; length = -ENOMEM; scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) goto out; length = -ENOMEM; tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out; length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length) goto out; length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length) goto out; length = security_change_sid(ssid, tsid, tclass, &newsid); if (length) goto out; length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; length = -ERANGE; if (len > SIMPLE_TRANSACTION_LIMIT) goto out; memcpy(buf, newcon, len); length = len; out: kfree(newcon); kfree(tcon); kfree(scon); return length; }
static ssize_t sel_write_bool(struct file *filep, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; struct inode *inode = filep->f_path.dentry->d_inode; unsigned index = inode->i_ino & SEL_INO_MASK; const char *name = filep->f_path.dentry->d_name.name; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; length = -EINVAL; if (index >= bool_num || strcmp(name, bool_pending_names[index])) goto out; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; length = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) goto out; length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; if (new_value) new_value = 1; bool_pending_values[index] = new_value; length = count; out: mutex_unlock(&sel_mutex); free_page((unsigned long) page); return length; }
static ssize_t sel_write_enforce(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; length = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) goto out; length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; new_value = 0; if (new_value != selinux_enforcing) { length = task_has_security(current, SECURITY__SETENFORCE); if (length) goto out; audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u", new_value, selinux_enforcing, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); selinux_enforcing = new_value; if (selinux_enforcing) avc_ss_reset(0); selnl_notify_setenforce(selinux_enforcing); selinux_status_update_setenforce(selinux_enforcing); } length = count; out: free_page((unsigned long) page); return length; }
static ssize_t sel_write_bool(struct file *filep, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; const char *name = filep->f_path.dentry->d_name.name; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; length = -EINVAL; if (index >= bool_num || strcmp(name, bool_pending_names[index])) goto out; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; page = memdup_user_nul(buf, count); if (IS_ERR(page)) { length = PTR_ERR(page); page = NULL; goto out; } length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; if (new_value) new_value = 1; bool_pending_values[index] = new_value; length = count; out: mutex_unlock(&sel_mutex); kfree(page); return length; }
static ssize_t sel_commit_bools_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; length = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) goto out; length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; length = 0; if (new_value && bool_pending_values) length = security_set_bools(bool_num, bool_pending_values); if (!length) length = count; out: mutex_unlock(&sel_mutex); free_page((unsigned long) page); return length; }
static ssize_t sel_write_access(struct file *file, char *buf, size_t size) { char *scon, *tcon; u32 ssid, tsid; u16 tclass; u32 req; struct av_decision avd; ssize_t length; length = task_has_security(current, SECURITY__COMPUTE_AV); if (length) return length; length = -ENOMEM; scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) goto out2; length = security_context_to_sid(scon, strlen(scon)+1, &ssid); if (length < 0) goto out2; length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); if (length < 0) goto out2; length = security_compute_av_user(ssid, tsid, tclass, req, &avd); if (length < 0) goto out2; length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%x %x %x %x %u %x", avd.allowed, 0xffffffff, avd.auditallow, avd.auditdeny, avd.seqno, avd.flags); out2: kfree(tcon); out: kfree(scon); return length; }
static ssize_t sel_write_access(struct file *file, char *buf, size_t size) { char *scon = NULL, *tcon = NULL; u32 ssid, tsid; u16 tclass; struct av_decision avd; ssize_t length; char format[32]; length = task_has_security(current, SECURITY__COMPUTE_AV); if (length) goto out; length = -ENOMEM; scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) goto out; length = -ENOMEM; tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; snprintf(format, sizeof(format), "%%%ds %%%ds %%hu", size, size); if (sscanf(buf, format, scon, tcon, &tclass) != 3) goto out; length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length) goto out; length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length) goto out; security_compute_av_user(ssid, tsid, tclass, &avd); length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%x %x %x %x %u %x", avd.allowed, 0xffffffff, avd.auditallow, avd.auditdeny, avd.seqno, avd.flags); out: kfree(tcon); kfree(scon); return length; }
static ssize_t sel_write_avc_cache_threshold(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page; ssize_t ret; int new_value; if (count >= PAGE_SIZE) { ret = -ENOMEM; goto out; } if (*ppos != 0) { /* No partial writes. */ ret = -EINVAL; goto out; } page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) { ret = -ENOMEM; goto out; } if (copy_from_user(page, buf, count)) { ret = -EFAULT; goto out_free; } if (sscanf(page, "%u", &new_value) != 1) { ret = -EINVAL; goto out; } if (new_value != avc_cache_threshold) { ret = task_has_security(current, SECURITY__SETSECPARAM); if (ret) goto out_free; avc_cache_threshold = new_value; } ret = count; out_free: free_page((unsigned long)page); out: return ret; }
static int sel_open_policy(struct inode *inode, struct file *filp) { struct policy_load_memory *plm = NULL; int rc; BUG_ON(filp->private_data); mutex_lock(&sel_mutex); rc = task_has_security(current, SECURITY__READ_POLICY); if (rc) goto err; rc = -EBUSY; if (policy_opened) goto err; rc = -ENOMEM; plm = kzalloc(sizeof(*plm), GFP_KERNEL); if (!plm) goto err; if (i_size_read(inode) != security_policydb_len()) { mutex_lock(&inode->i_mutex); i_size_write(inode, security_policydb_len()); mutex_unlock(&inode->i_mutex); } rc = security_read_policy(&plm->data, &plm->len); if (rc) goto err; policy_opened = 1; filp->private_data = plm; mutex_unlock(&sel_mutex); return 0; err: mutex_unlock(&sel_mutex); if (plm) vfree(plm->data); kfree(plm); return rc; }
static ssize_t sel_read_policy(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct policy_load_memory *plm = filp->private_data; int ret; mutex_lock(&sel_mutex); ret = task_has_security(current, SECURITY__READ_POLICY); if (ret) goto out; ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); out: mutex_unlock(&sel_mutex); return ret; }
static ssize_t sel_commit_bools_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; page = memdup_user_nul(buf, count); if (IS_ERR(page)) { length = PTR_ERR(page); page = NULL; goto out; } length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; length = 0; if (new_value && bool_pending_values) length = security_set_bools(bool_num, bool_pending_values); if (!length) length = count; out: mutex_unlock(&sel_mutex); kfree(page); return length; }
static ssize_t sel_write_enforce(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; if (count >= PAGE_SIZE) return -ENOMEM; /* No partial writes. */ if (*ppos != 0) return -EINVAL; page = memdup_user_nul(buf, count); if (IS_ERR(page)) return PTR_ERR(page); length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; new_value = !!new_value; if (new_value != selinux_enforcing) { length = task_has_security(current, SECURITY__SETENFORCE); if (length) goto out; audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u", new_value, selinux_enforcing, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); selinux_enforcing = new_value; if (selinux_enforcing) avc_ss_reset(0); selnl_notify_setenforce(selinux_enforcing); selinux_status_update_setenforce(selinux_enforcing); } length = count; out: kfree(page); return length; }
static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; unsigned int new_value; length = task_has_security(current, SECURITY__SETCHECKREQPROT); if (length) goto out; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = -EINVAL; if (*ppos != 0) goto out; length = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) goto out; length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%u", &new_value) != 1) goto out; selinux_checkreqprot = new_value ? 1 : 0; length = count; out: free_page((unsigned long) page); return length; }
static ssize_t sel_write_create(struct file *file, char *buf, size_t size) { char *scon = NULL, *tcon = NULL; char *namebuf = NULL, *objname = NULL; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon = NULL; u32 len; int nargs; char format[32]; length = task_has_security(current, SECURITY__COMPUTE_CREATE); if (length) goto out; length = -ENOMEM; scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) goto out; length = -ENOMEM; tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; length = -ENOMEM; namebuf = kzalloc(size + 1, GFP_KERNEL); if (!namebuf) goto out; length = -EINVAL; snprintf(format, sizeof(format), "%%%ds %%%ds %%hu %%%ds", size, size, size); nargs = sscanf(buf, format, scon, tcon, &tclass, namebuf); if (nargs < 3 || nargs > 4) goto out; if (nargs == 4) { char *r, *w; int c1, c2; r = w = namebuf; do { c1 = *r++; if (c1 == '+') c1 = ' '; else if (c1 == '%') { c1 = hex_to_bin(*r++); if (c1 < 0) goto out; c2 = hex_to_bin(*r++); if (c2 < 0) goto out; c1 = (c1 << 4) | c2; } *w++ = c1; } while (c1 != '\0'); objname = namebuf; } length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length) goto out; length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length) goto out; length = security_transition_sid_user(ssid, tsid, tclass, objname, &newsid); if (length) goto out; length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; length = -ERANGE; if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " "payload max\n", __func__, len); goto out; } memcpy(buf, newcon, len); length = len; out: kfree(newcon); kfree(namebuf); kfree(tcon); kfree(scon); return length; }
static ssize_t sel_write_validatetrans(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *oldcon = NULL, *newcon = NULL, *taskcon = NULL; char *req = NULL; u32 osid, nsid, tsid; u16 tclass; int rc; rc = task_has_security(current, SECURITY__VALIDATE_TRANS); if (rc) goto out; rc = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ rc = -EINVAL; if (*ppos != 0) goto out; rc = -ENOMEM; req = kzalloc(count + 1, GFP_KERNEL); if (!req) goto out; rc = -EFAULT; if (copy_from_user(req, buf, count)) goto out; rc = -ENOMEM; oldcon = kzalloc(count + 1, GFP_KERNEL); if (!oldcon) goto out; newcon = kzalloc(count + 1, GFP_KERNEL); if (!newcon) goto out; taskcon = kzalloc(count + 1, GFP_KERNEL); if (!taskcon) goto out; rc = -EINVAL; if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4) goto out; rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL); if (rc) goto out; rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL); if (rc) goto out; rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL); if (rc) goto out; rc = security_validate_transition_user(osid, nsid, tsid, tclass); if (!rc) rc = count; out: kfree(req); kfree(oldcon); kfree(newcon); kfree(taskcon); return rc; }
static ssize_t sel_write_load(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int ret; ssize_t length; void *data = NULL; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__LOAD_POLICY); if (length) goto out; if (*ppos != 0) { /* No partial writes. */ length = -EINVAL; goto out; } if ((count > 64 * 1024 * 1024) || (data = vmalloc(count)) == NULL) { length = -ENOMEM; goto out; } length = -EFAULT; if (copy_from_user(data, buf, count) != 0) goto out; length = security_load_policy(data, count); if (length) goto out; ret = sel_make_bools(); if (ret) { length = ret; goto out1; } ret = sel_make_classes(); if (ret) { length = ret; goto out1; } ret = sel_make_policycap(); if (ret) length = ret; else length = count; out1: audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, "policy loaded auid=%u ses=%u", audit_get_loginuid(current), audit_get_sessionid(current)); out: mutex_unlock(&sel_mutex); vfree(data); return length; }
static ssize_t sel_write_user(struct file *file, char *buf, size_t size) { char *con = NULL, *user = NULL, *ptr; u32 sid, *sids = NULL; ssize_t length; char *newcon; int i, rc; u32 len, nsids; char format[32]; length = task_has_security(current, SECURITY__COMPUTE_USER); if (length) goto out; length = -ENOMEM; con = kzalloc(size + 1, GFP_KERNEL); if (!con) goto out; length = -ENOMEM; user = kzalloc(size + 1, GFP_KERNEL); if (!user) goto out; length = -EINVAL; snprintf(format, sizeof(format), "%%%ds %%%ds", size, size); if (sscanf(buf, format, con, user) != 2) goto out; length = security_context_to_sid(con, strlen(con) + 1, &sid); if (length) goto out; length = security_get_user_sids(sid, user, &sids, &nsids); if (length) goto out; length = snprintf(buf, PAGE_SIZE, "%u", nsids) + 1; ptr = buf + length; for (i = 0; i < nsids; i++) { rc = security_sid_to_context(sids[i], &newcon, &len); if (rc) { length = rc; goto out; } if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) { kfree(newcon); length = -ERANGE; goto out; } memcpy(ptr, newcon, len); kfree(newcon); ptr += len; length += len; } out: kfree(sids); kfree(user); kfree(con); return length; }
static ssize_t sel_write_enforce(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t length; int new_value; length = -ENOMEM; if (count >= PAGE_SIZE) goto out; /* No partial writes. */ length = EINVAL; if (*ppos != 0) goto out; length = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) goto out; length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; #ifdef CONFIG_ALWAYS_ENFORCE // If build is user build and enforce option is set, selinux is always enforcing new_value = 1; length = task_has_security(current, SECURITY__SETENFORCE); audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "config_always_enforce - true; enforcing=%d old_enforcing=%d auid=%u ses=%u", new_value, selinux_enforcing, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); selinux_enforcing = new_value; avc_ss_reset(0); selnl_notify_setenforce(new_value); selinux_status_update_setenforce(new_value); #else new_value = 0; /* Bye NSA! Nobody invited you here, so go back into reclusion and be permissive */ if (new_value != selinux_enforcing) { length = task_has_security(current, SECURITY__SETENFORCE); if (length) goto out; audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, "enforcing=%d old_enforcing=%d auid=%u ses=%u", new_value, selinux_enforcing, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); selinux_enforcing = new_value; if (selinux_enforcing) avc_ss_reset(0); selnl_notify_setenforce(selinux_enforcing); selinux_status_update_setenforce(selinux_enforcing); } #endif length = count; out: free_page((unsigned long) page); return length; }
static ssize_t sel_write_create(struct file *file, char *buf, size_t size) { char *scon = NULL, *tcon = NULL; char *namebuf = NULL, *objname = NULL; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon = NULL; u32 len; int nargs; length = task_has_security(current, SECURITY__COMPUTE_CREATE); if (length) goto out; length = -ENOMEM; scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) goto out; length = -ENOMEM; tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; length = -ENOMEM; namebuf = kzalloc(size + 1, GFP_KERNEL); if (!namebuf) goto out; length = -EINVAL; nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf); if (nargs < 3 || nargs > 4) goto out; if (nargs == 4) { /* * If and when the name of new object to be queried contains * either whitespace or multibyte characters, they shall be * encoded based on the percentage-encoding rule. * If not encoded, the sscanf logic picks up only left-half * of the supplied name; splitted by a whitespace unexpectedly. */ char *r, *w; int c1, c2; r = w = namebuf; do { c1 = *r++; if (c1 == '+') c1 = ' '; else if (c1 == '%') { c1 = hex_to_bin(*r++); if (c1 < 0) goto out; c2 = hex_to_bin(*r++); if (c2 < 0) goto out; c1 = (c1 << 4) | c2; } *w++ = c1; } while (c1 != '\0'); objname = namebuf; } length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length) goto out; length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length) goto out; length = security_transition_sid_user(ssid, tsid, tclass, objname, &newsid); if (length) goto out; length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; length = -ERANGE; if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " "payload max\n", __func__, len); goto out; } memcpy(buf, newcon, len); length = len; out: kfree(newcon); kfree(namebuf); kfree(tcon); kfree(scon); return length; }
static ssize_t sel_write_create(struct file *file, char *buf, size_t size) { char *scon = NULL, *tcon = NULL; char *namebuf = NULL, *objname = NULL; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon = NULL; u32 len; int nargs; length = task_has_security(current, SECURITY__COMPUTE_CREATE); if (length) goto out; length = -ENOMEM; scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) goto out; length = -ENOMEM; tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; length = -ENOMEM; namebuf = kzalloc(size + 1, GFP_KERNEL); if (!namebuf) goto out; length = -EINVAL; nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf); if (nargs < 3 || nargs > 4) goto out; if (nargs == 4) objname = namebuf; length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length) goto out; length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length) goto out; length = security_transition_sid_user(ssid, tsid, tclass, objname, &newsid); if (length) goto out; length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; length = -ERANGE; if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " "payload max\n", __func__, len); goto out; } memcpy(buf, newcon, len); length = len; out: kfree(newcon); kfree(namebuf); kfree(tcon); kfree(scon); return length; }