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; }
/* * Security blob allocation for xfrm_policy and xfrm_state * CTX does not have a meaningful value on input */ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *uctx, u32 sid) { int rc = 0; const struct task_security_struct *tsec = current_security(); struct xfrm_sec_ctx *ctx = NULL; char *ctx_str = NULL; u32 str_len; BUG_ON(uctx && sid); if (!uctx) goto not_from_user; if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX) return -EINVAL; str_len = uctx->ctx_len; if (str_len >= PAGE_SIZE) return -ENOMEM; *ctxp = ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL); if (!ctx) return -ENOMEM; ctx->ctx_doi = uctx->ctx_doi; ctx->ctx_len = str_len; ctx->ctx_alg = uctx->ctx_alg; memcpy(ctx->ctx_str, uctx+1, str_len); ctx->ctx_str[str_len] = 0; rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid); if (rc) goto out; /* * Does the subject have permission to set security context? */ rc = avc_has_perm(tsec->sid, ctx->ctx_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); if (rc) goto out; return rc; not_from_user: rc = security_sid_to_context(sid, &ctx_str, &str_len); if (rc) goto out; *ctxp = ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); if (!ctx) { rc = -ENOMEM; goto out; } ctx->ctx_doi = XFRM_SC_DOI_LSM; ctx->ctx_alg = XFRM_SC_ALG_SELINUX; ctx->ctx_sid = sid; ctx->ctx_len = str_len; memcpy(ctx->ctx_str, ctx_str, str_len); goto out2; out: *ctxp = NULL; kfree(ctx); out2: kfree(ctx_str); return rc; }
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_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_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; }