diff options
Diffstat (limited to 'security')
30 files changed, 280 insertions, 243 deletions
diff --git a/security/Kconfig b/security/Kconfig index 9555f4914492..1d6463fb1450 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -40,8 +40,7 @@ config SECURITYFS bool "Enable the securityfs filesystem" help This will build the securityfs filesystem. It is currently used by - the TPM bios character driver and IMA, an integrity provider. It is - not used by SELinux or SMACK. + various security modules (AppArmor, IMA, SafeSetID, TOMOYO, TPM). If you are unsure how to answer this question, answer N. diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index eeaddfe0c0fb..5a8b9cded4f2 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -225,8 +225,7 @@ int aa_audit_rule_known(struct audit_krule *rule) return 0; } -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, - struct audit_context *actx) +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) { struct aa_audit_rule *rule = vrule; struct aa_label *label; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 726910bba84b..ca2dccf5b445 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -572,7 +572,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile, stack = NULL; break; } - /* fall through to X_NAME */ + /* fall through - to X_NAME */ case AA_X_NAME: if (xindex & AA_X_CHILD) /* released by caller */ @@ -1444,7 +1444,10 @@ check: new = aa_label_merge(label, target, GFP_KERNEL); if (IS_ERR_OR_NULL(new)) { info = "failed to build target label"; - error = PTR_ERR(new); + if (!new) + error = -ENOMEM; + else + error = PTR_ERR(new); new = NULL; perms.allow = 0; goto audit; diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index b8c8b1066b0a..ee559bc2acb8 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -192,7 +192,6 @@ static inline int complain_error(int error) void aa_audit_rule_free(void *vrule); int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule); int aa_audit_rule_known(struct audit_krule *rule); -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, - struct audit_context *actx); +int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule); #endif /* __AA_AUDIT_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index bb5a02d2439f..49d664ddff44 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1597,12 +1597,14 @@ static unsigned int apparmor_ipv4_postroute(void *priv, return apparmor_ip_postroute(priv, skb, state); } +#if IS_ENABLED(CONFIG_IPV6) static unsigned int apparmor_ipv6_postroute(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { return apparmor_ip_postroute(priv, skb, state); } +#endif static const struct nf_hook_ops apparmor_nf_ops[] = { { diff --git a/security/commoncap.c b/security/commoncap.c index 188eaf59f82f..c477fb673701 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -57,7 +57,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname) * @cred: The credentials to use * @ns: The user namespace in which we need the capability * @cap: The capability to check for - * @audit: Whether to write an audit message or not + * @opts: Bitmask of options defined in include/linux/security.h * * Determine whether the nominated task has the specified capability amongst * its effective set, returning 0 if it does, -ve if it does not. @@ -642,6 +642,8 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; + cpu_caps->rootid = rootkuid; + return 0; } diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 88f04b3380d4..423876fca8b4 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -200,7 +200,7 @@ int integrity_kernel_read(struct file *file, loff_t offset, return -EBADF; old_fs = get_fs(); - set_fs(get_ds()); + set_fs(KERNEL_DS); ret = __vfs_read(file, buf, count, &offset); set_fs(old_fs); diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index cc12f3449a72..026163f37ba1 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -307,8 +307,7 @@ static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr, } static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, - void *lsmrule, - struct audit_context *actx) + void *lsmrule) { return -EINVAL; } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index a2baa85ea2f5..5fb7127bbe68 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -114,6 +114,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, break; case CREDS_CHECK: iint->ima_creds_status = status; + break; case FILE_CHECK: case POST_SETATTR: iint->ima_file_status = status; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 8bc8a1c8cb3f..e0cc323f948f 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -340,8 +340,7 @@ retry: rc = security_filter_rule_match(osid, rule->lsm[i].type, Audit_equal, - rule->lsm[i].rule, - NULL); + rule->lsm[i].rule); break; case LSM_SUBJ_USER: case LSM_SUBJ_ROLE: @@ -349,8 +348,7 @@ retry: rc = security_filter_rule_match(secid, rule->lsm[i].type, Audit_equal, - rule->lsm[i].rule, - NULL); + rule->lsm[i].rule); default: break; } @@ -938,10 +936,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) case Opt_uid_gt: case Opt_euid_gt: entry->uid_op = &uid_gt; + /* fall through */ case Opt_uid_lt: case Opt_euid_lt: if ((token == Opt_uid_lt) || (token == Opt_euid_lt)) entry->uid_op = &uid_lt; + /* fall through */ case Opt_uid_eq: case Opt_euid_eq: uid_token = (token == Opt_uid_eq) || @@ -970,9 +970,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) break; case Opt_fowner_gt: entry->fowner_op = &uid_gt; + /* fall through */ case Opt_fowner_lt: if (token == Opt_fowner_lt) entry->fowner_op = &uid_lt; + /* fall through */ case Opt_fowner_eq: ima_log_string_op(ab, "fowner", args[0].from, entry->fowner_op); diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 43752002c222..513b457ae900 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -83,6 +83,7 @@ static void ima_show_template_data_ascii(struct seq_file *m, /* skip ':' and '\0' */ buf_ptr += 2; buflen -= buf_ptr - field_data->data; + /* fall through */ case DATA_FMT_DIGEST: case DATA_FMT_HEX: if (!buflen) diff --git a/security/keys/internal.h b/security/keys/internal.h index 479909b858c7..8f533c81aa8d 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -186,20 +186,9 @@ static inline int key_permission(const key_ref_t key_ref, unsigned perm) return key_task_permission(key_ref, current_cred(), perm); } -/* - * Authorisation record for request_key(). - */ -struct request_key_auth { - struct key *target_key; - struct key *dest_keyring; - const struct cred *cred; - void *callout_info; - size_t callout_len; - pid_t pid; -} __randomize_layout; - extern struct key_type key_type_request_key_auth; extern struct key *request_key_auth_new(struct key *target, + const char *op, const void *callout_info, size_t callout_len, struct key *dest_keyring); diff --git a/security/keys/key.c b/security/keys/key.c index 44a80d6741a1..696f1c092c50 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -265,8 +265,8 @@ struct key *key_alloc(struct key_type *type, const char *desc, spin_lock(&user->lock); if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { - if (user->qnkeys + 1 >= maxkeys || - user->qnbytes + quotalen >= maxbytes || + if (user->qnkeys + 1 > maxkeys || + user->qnbytes + quotalen > maxbytes || user->qnbytes + quotalen < user->qnbytes) goto no_quota; } @@ -297,6 +297,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->gid = gid; key->perm = perm; key->restrict_link = restrict_link; + key->last_used_at = ktime_get_real_seconds(); if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) key->flags |= 1 << KEY_FLAG_IN_QUOTA; diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index e8093d025966..3e4053a217c3 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -25,6 +25,7 @@ #include <linux/security.h> #include <linux/uio.h> #include <linux/uaccess.h> +#include <keys/request_key_auth-type.h> #include "internal.h" #define KEY_MAX_DESC_SIZE 4096 @@ -1751,7 +1752,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, return -EINVAL; return keyctl_pkey_query((key_serial_t)arg2, (const char __user *)arg4, - (struct keyctl_pkey_query *)arg5); + (struct keyctl_pkey_query __user *)arg5); case KEYCTL_PKEY_ENCRYPT: case KEYCTL_PKEY_DECRYPT: diff --git a/security/keys/keyring.c b/security/keys/keyring.c index b1ff07d9ce37..e14f09e3a4b0 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -662,9 +662,6 @@ static bool search_nested_keyrings(struct key *keyring, BUG_ON((ctx->flags & STATE_CHECKS) == 0 || (ctx->flags & STATE_CHECKS) == STATE_CHECKS); - if (ctx->index_key.description) - ctx->index_key.desc_len = strlen(ctx->index_key.description); - /* Check to see if this top-level keyring is what we are looking for * and whether it is valid or not. */ @@ -915,6 +912,7 @@ key_ref_t keyring_search(key_ref_t keyring, struct keyring_search_context ctx = { .index_key.type = type, .index_key.description = description, + .index_key.desc_len = strlen(description), .cred = current_cred(), .match_data.cmp = key_default_cmp, .match_data.raw_data = description, diff --git a/security/keys/proc.c b/security/keys/proc.c index d2b802072693..78ac305d715e 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -165,8 +165,7 @@ static int proc_keys_show(struct seq_file *m, void *v) int rc; struct keyring_search_context ctx = { - .index_key.type = key->type, - .index_key.description = key->description, + .index_key = key->index_key, .cred = m->file->f_cred, .match_data.cmp = lookup_user_key_possessed, .match_data.raw_data = key, diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 3308d738734c..9320424c4a46 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -19,6 +19,7 @@ #include <linux/security.h> #include <linux/user_namespace.h> #include <linux/uaccess.h> +#include <keys/request_key_auth-type.h> #include "internal.h" /* Session keyring create vs join semaphore */ diff --git a/security/keys/request_key.c b/security/keys/request_key.c index af8816ffb6ce..2f17d84d46f1 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -18,31 +18,30 @@ #include <linux/keyctl.h> #include <linux/slab.h> #include "internal.h" +#include <keys/request_key_auth-type.h> #define key_negative_timeout 60 /* default timeout on a negative key's existence */ /** * complete_request_key - Complete the construction of a key. - * @cons: The key construction record. + * @auth_key: The authorisation key. * @error: The success or failute of the construction. * * Complete the attempt to construct a key. The key will be negated * if an error is indicated. The authorisation key will be revoked * unconditionally. */ -void complete_request_key(struct key_construction *cons, int error) +void complete_request_key(struct key *authkey, int error) { - kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error); + struct request_key_auth *rka = get_request_key_auth(authkey); + struct key *key = rka->target_key; + + kenter("%d{%d},%d", authkey->serial, key->serial, error); if (error < 0) - key_negate_and_link(cons->key, key_negative_timeout, NULL, - cons->authkey); + key_negate_and_link(key, key_negative_timeout, NULL, authkey); else - key_revoke(cons->authkey); - - key_put(cons->key); - key_put(cons->authkey); - kfree(cons); + key_revoke(authkey); } EXPORT_SYMBOL(complete_request_key); @@ -91,21 +90,19 @@ static int call_usermodehelper_keys(const char *path, char **argv, char **envp, * Request userspace finish the construction of a key * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" */ -static int call_sbin_request_key(struct key_construction *cons, - const char *op, - void *aux) +static int call_sbin_request_key(struct key *authkey, void *aux) { static char const request_key[] = "/sbin/request-key"; + struct request_key_auth *rka = get_request_key_auth(authkey); const struct cred *cred = current_cred(); key_serial_t prkey, sskey; - struct key *key = cons->key, *authkey = cons->authkey, *keyring, - *session; + struct key *key = rka->target_key, *keyring, *session; char *argv[9], *envp[3], uid_str[12], gid_str[12]; char key_str[12], keyring_str[3][12]; char desc[20]; int ret, i; - kenter("{%d},{%d},%s", key->serial, authkey->serial, op); + kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op); ret = install_user_keyrings(); if (ret < 0) @@ -163,7 +160,7 @@ static int call_sbin_request_key(struct key_construction *cons, /* set up the argument list */ i = 0; argv[i++] = (char *)request_key; - argv[i++] = (char *) op; + argv[i++] = (char *)rka->op; argv[i++] = key_str; argv[i++] = uid_str; argv[i++] = gid_str; @@ -191,7 +188,7 @@ error_link: key_put(keyring); error_alloc: - complete_request_key(cons, ret); + complete_request_key(authkey, ret); kleave(" = %d", ret); return ret; } @@ -205,42 +202,31 @@ static int construct_key(struct key *key, const void *callout_info, size_t callout_len, void *aux, struct key *dest_keyring) { - struct key_construction *cons; request_key_actor_t actor; struct key *authkey; int ret; kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux); - cons = kmalloc(sizeof(*cons), GFP_KERNEL); - if (!cons) - return -ENOMEM; - /* allocate an authorisation key */ - authkey = request_key_auth_new(key, callout_info, callout_len, + authkey = request_key_auth_new(key, "create", callout_info, callout_len, dest_keyring); - if (IS_ERR(authkey)) { - kfree(cons); - ret = PTR_ERR(authkey); - authkey = NULL; - } else { - cons->authkey = key_get(authkey); - cons->key = key_get(key); + if (IS_ERR(authkey)) + return PTR_ERR(authkey); - /* make the call */ - actor = call_sbin_request_key; - if (key->type->request_key) - actor = key->type->request_key; + /* Make the call */ + actor = call_sbin_request_key; + if (key->type->request_key) + actor = key->type->request_key; - ret = actor(cons, "create", aux); + ret = actor(authkey, aux); - /* check that the actor called complete_request_key() prior to - * returning an error */ - WARN_ON(ret < 0 && - !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); - key_put(authkey); - } + /* check that the actor called complete_request_key() prior to + * returning an error */ + WARN_ON(ret < 0 && + !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); + key_put(authkey); kleave(" = %d", ret); return ret; } @@ -275,7 +261,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) if (cred->request_key_auth) { authkey = cred->request_key_auth; down_read(&authkey->sem); - rka = authkey->payload.data[0]; + rka = get_request_key_auth(authkey); if (!test_bit(KEY_FLAG_REVOKED, &authkey->flags)) dest_keyring = @@ -549,6 +535,7 @@ struct key *request_key_and_link(struct key_type *type, struct keyring_search_context ctx = { .index_key.type = type, .index_key.description = description, + .index_key.desc_len = strlen(description), .cred = current_cred(), .match_data.cmp = key_default_cmp, .match_data.raw_data = description, diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 87ea2f54dedc..bda6201c6c45 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -17,7 +17,7 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include "internal.h" -#include <keys/user-type.h> +#include <keys/request_key_auth-type.h> static int request_key_auth_preparse(struct key_preparsed_payload *); static void request_key_auth_free_preparse(struct key_preparsed_payload *); @@ -68,7 +68,7 @@ static int request_key_auth_instantiate(struct key *key, static void request_key_auth_describe(const struct key *key, struct seq_file *m) { - struct request_key_auth *rka = key->payload.data[0]; + struct request_key_auth *rka = get_request_key_auth(key); seq_puts(m, "key:"); seq_puts(m, key->description); @@ -83,7 +83,7 @@ static void request_key_auth_describe(const struct key *key, static long request_key_auth_read(const struct key *key, char __user *buffer, size_t buflen) { - struct request_key_auth *rka = key->payload.data[0]; + struct request_key_auth *rka = get_request_key_auth(key); size_t datalen; long ret; @@ -109,7 +109,7 @@ static long request_key_auth_read(const struct key *key, */ static void request_key_auth_revoke(struct key *key) { - struct request_key_auth *rka = key->payload.data[0]; + struct request_key_auth *rka = get_request_key_auth(key); kenter("{%d}", key->serial); @@ -136,7 +136,7 @@ static void free_request_key_auth(struct request_key_auth *rka) */ static void request_key_auth_destroy(struct key *key) { - struct request_key_auth *rka = key->payload.data[0]; + struct request_key_auth *rka = get_request_key_auth(key); kenter("{%d}", key->serial); @@ -147,8 +147,9 @@ static void request_key_auth_destroy(struct key *key) * Create an authorisation token for /sbin/request-key or whoever to gain * access to the caller's security data. */ -struct key *request_key_auth_new(struct key *target, const void *callout_info, - size_t callout_len, struct key *dest_keyring) +struct key *request_key_auth_new(struct key *target, const char *op, + const void *callout_info, size_t callout_len, + struct key *dest_keyring) { struct request_key_auth *rka, *irka; const struct cred *cred = current->cred; @@ -166,6 +167,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info, if (!rka->callout_info) goto error_free_rka; rka->callout_len = callout_len; + strlcpy(rka->op, op, sizeof(rka->op)); /* see if the calling process is already servicing the key request of * another process */ @@ -245,7 +247,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) struct key *authkey; key_ref_t authkey_ref; - sprintf(description, "%x", target_id); + ctx.index_key.desc_len = sprintf(description, "%x", target_id); authkey_ref = search_process_keyrings(&ctx); diff --git a/security/lsm_audit.c b/security/lsm_audit.c index f84001019356..33028c098ef3 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -321,6 +321,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, if (a->u.net->sk) { struct sock *sk = a->u.net->sk; struct unix_sock *u; + struct unix_address *addr; int len = 0; char *p = NULL; @@ -351,14 +352,15 @@ static void dump_common_audit_data(struct audit_buffer *ab, #endif case AF_UNIX: u = unix_sk(sk); + addr = smp_load_acquire(&u->addr); + if (!addr) + break; if (u->path.dentry) { audit_log_d_path(ab, " path=", &u->path); break; } - if (!u->addr) - break; - len = u->addr->len-sizeof(short); - p = &u->addr->name->sun_path[0]; + len = addr->len-sizeof(short); + p = &addr->name->sun_path[0]; audit_log_format(ab, " path="); if (*p) audit_log_untrustedstring(ab, p); diff --git a/security/security.c b/security/security.c index b6bff646d373..301b141b9a32 100644 --- a/security/security.c +++ b/security/security.c @@ -288,9 +288,13 @@ static void __init ordered_lsm_init(void) ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms), GFP_KERNEL); - if (chosen_lsm_order) + if (chosen_lsm_order) { + if (chosen_major_lsm) { + pr_info("security= is ignored because it is superseded by lsm=\n"); + chosen_major_lsm = NULL; + } ordered_lsm_parse(chosen_lsm_order, "cmdline"); - else + } else ordered_lsm_parse(builtin_lsm_order, "builtin"); for (lsm = ordered_lsms; *lsm; lsm++) @@ -2298,11 +2302,9 @@ void security_audit_rule_free(void *lsmrule) call_void_hook(audit_rule_free, lsmrule); } -int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, - struct audit_context *actx) +int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule) { - return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule, - actx); + return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule); } #endif /* CONFIG_AUDIT */ diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 635e5c1e3e48..8346a4f7c5d7 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -130,75 +130,6 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) } /** - * avc_dump_av - Display an access vector in human-readable form. - * @tclass: target security class - * @av: access vector - */ -static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) -{ - const char **perms; - int i, perm; - - if (av == 0) { - audit_log_format(ab, " null"); - return; - } - - BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); - perms = secclass_map[tclass-1].perms; - - audit_log_format(ab, " {"); - i = 0; - perm = 1; - while (i < (sizeof(av) * 8)) { - if ((perm & av) && perms[i]) { - audit_log_format(ab, " %s", perms[i]); - av &= ~perm; - } - i++; - perm <<= 1; - } - - if (av) - audit_log_format(ab, " 0x%x", av); - - audit_log_format(ab, " }"); -} - -/** - * avc_dump_query - Display a SID pair and a class in human-readable form. - * @ssid: source security identifier - * @tsid: target security identifier - * @tclass: target security class - */ -static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass) -{ - int rc; - char *scontext; - u32 scontext_len; - - rc = security_sid_to_context(state, ssid, &scontext, &scontext_len); - if (rc) - audit_log_format(ab, "ssid=%d", ssid); - else { - audit_log_format(ab, "scontext=%s", scontext); - kfree(scontext); - } - - rc = security_sid_to_context(state, tsid, &scontext, &scontext_len); - if (rc) - audit_log_format(ab, " tsid=%d", tsid); - else { - audit_log_format(ab, " tcontext=%s", scontext); - kfree(scontext); - } - - BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); - audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); -} - -/** * avc_init - Initialize the AVC. * * Initialize the access vector cache. @@ -735,11 +666,36 @@ out: static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) { struct common_audit_data *ad = a; - audit_log_format(ab, "avc: %s ", - ad->selinux_audit_data->denied ? "denied" : "granted"); - avc_dump_av(ab, ad->selinux_audit_data->tclass, - ad->selinux_audit_data->audited); - audit_log_format(ab, " for "); + struct selinux_audit_data *sad = ad->selinux_audit_data; + u32 av = sad->audited; + const char **perms; + int i, perm; + + audit_log_format(ab, "avc: %s ", sad->denied ? "denied" : "granted"); + + if (av == 0) { + audit_log_format(ab, " null"); + return; + } + + perms = secclass_map[sad->tclass-1].perms; + + audit_log_format(ab, " {"); + i = 0; + perm = 1; + while (i < (sizeof(av) * 8)) { + if ((perm & av) && perms[i]) { + audit_log_format(ab, " %s", perms[i]); + av &= ~perm; + } + i++; + perm <<= 1; + } + + if (av) + audit_log_format(ab, " 0x%x", av); + + audit_log_format(ab, " } for "); } /** @@ -751,14 +707,47 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) static void avc_audit_post_callback(struct audit_buffer *ab, void *a) { struct common_audit_data *ad = a; - audit_log_format(ab, " "); - avc_dump_query(ab, ad->selinux_audit_data->state, - ad->selinux_audit_data->ssid, - ad->selinux_audit_data->tsid, - ad->selinux_audit_data->tclass); - if (ad->selinux_audit_data->denied) { - audit_log_format(ab, " permissive=%u", - ad->selinux_audit_data->result ? 0 : 1); + struct selinux_audit_data *sad = ad->selinux_audit_data; + char *scontext; + u32 scontext_len; + int rc; + + rc = security_sid_to_context(sad->state, sad->ssid, &scontext, + &scontext_len); + if (rc) + audit_log_format(ab, " ssid=%d", sad->ssid); + else { + audit_log_format(ab, " scontext=%s", scontext); + kfree(scontext); + } + + rc = security_sid_to_context(sad->state, sad->tsid, &scontext, + &scontext_len); + if (rc) + audit_log_format(ab, " tsid=%d", sad->tsid); + else { + audit_log_format(ab, " tcontext=%s", scontext); + kfree(scontext); + } + + audit_log_format(ab, " tclass=%s", secclass_map[sad->tclass-1].name); + + if (sad->denied) + audit_log_format(ab, " permissive=%u", sad->result ? 0 : 1); + + /* in case of invalid context report also the actual context string */ + rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext, + &scontext_len); + if (!rc && scontext) { + audit_log_format(ab, " srawcon=%s", scontext); + kfree(scontext); + } + + rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext, + &scontext_len); + if (!rc && scontext) { + audit_log_format(ab, " trawcon=%s", scontext); + kfree(scontext); } } @@ -772,6 +761,9 @@ noinline int slow_avc_audit(struct selinux_state *state, struct common_audit_data stack_data; struct selinux_audit_data sad; + if (WARN_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map))) + return -EINVAL; + if (!a) { a = &stack_data; a->type = LSM_AUDIT_DATA_NONE; @@ -838,6 +830,7 @@ out: * @ssid,@tsid,@tclass : identifier of an AVC entry * @seqno : sequence number when decision was made * @xpd: extended_perms_decision to be added to the node + * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0. * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. @@ -856,6 +849,22 @@ static int avc_update_node(struct selinux_avc *avc, struct hlist_head *head; spinlock_t *lock; + /* + * If we are in a non-blocking code path, e.g. VFS RCU walk, + * then we must not add permissions to a cache entry + * because we cannot safely audit the denial. Otherwise, + * during the subsequent blocking retry (e.g. VFS ref walk), we + * will find the permissions already granted in the cache entry + * and won't audit anything at all, leading to silent denials in + * permissive mode that only appear when in enforcing mode. + * + * See the corresponding handling in slow_avc_audit(), and the + * logic in selinux_inode_permission for the MAY_NOT_BLOCK flag, + * which is transliterated into AVC_NONBLOCKING. + */ + if (flags & AVC_NONBLOCKING) + return 0; + node = avc_alloc_node(avc); if (!node) { rc = -ENOMEM; @@ -1050,7 +1059,8 @@ int avc_has_extended_perms(struct selinux_state *state, int rc = 0, rc2; xp_node = &local_xp_node; - BUG_ON(!requested); + if (WARN_ON(!requested)) + return -EACCES; rcu_read_lock(); @@ -1115,7 +1125,7 @@ decision: * @tsid: target security identifier * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass - * @flags: AVC_STRICT or 0 + * @flags: AVC_STRICT, AVC_NONBLOCKING, or 0 * @avd: access vector decisions * * Check the AVC to determine whether the @requested permissions are granted @@ -1140,7 +1150,8 @@ inline int avc_has_perm_noaudit(struct selinux_state *state, int rc = 0; u32 denied; - BUG_ON(!requested); + if (WARN_ON(!requested)) + return -EACCES; rcu_read_lock(); @@ -1191,24 +1202,6 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, return rc; } -int avc_has_perm_flags(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, u32 requested, - struct common_audit_data *auditdata, - int flags) -{ - struct av_decision avd; - int rc, rc2; - - rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, - &avd); - - rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, - auditdata, flags); - if (rc2) - return rc2; - return rc; -} - u32 avc_policy_seqno(struct selinux_state *state) { return state->avc->avc_cache.latest_notif; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5d92167dbe05..333606b3a8ef 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -490,16 +490,10 @@ static int may_context_mount_inode_relabel(u32 sid, return rc; } -static int selinux_is_sblabel_mnt(struct super_block *sb) +static int selinux_is_genfs_special_handling(struct super_block *sb) { - struct superblock_security_struct *sbsec = sb->s_security; - - return sbsec->behavior == SECURITY_FS_USE_XATTR || - sbsec->behavior == SECURITY_FS_USE_TRANS || - sbsec->behavior == SECURITY_FS_USE_TASK || - sbsec->behavior == SECURITY_FS_USE_NATIVE || - /* Special handling. Genfs but also in-core setxattr handler */ - !strcmp(sb->s_type->name, "sysfs") || + /* Special handling. Genfs but also in-core setxattr handler */ + return !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore") || !strcmp(sb->s_type->name, "debugfs") || !strcmp(sb->s_type->name, "tracefs") || @@ -509,6 +503,34 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) !strcmp(sb->s_type->name, "cgroup2"))); } +static int selinux_is_sblabel_mnt(struct super_block *sb) +{ + struct superblock_security_struct *sbsec = sb->s_security; + + /* + * IMPORTANT: Double-check logic in this function when adding a new + * SECURITY_FS_USE_* definition! + */ + BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7); + + switch (sbsec->behavior) { + case SECURITY_FS_USE_XATTR: + case SECURITY_FS_USE_TRANS: + case SECURITY_FS_USE_TASK: + case SECURITY_FS_USE_NATIVE: + return 1; + + case SECURITY_FS_USE_GENFS: + return selinux_is_genfs_special_handling(sb); + + /* Never allow relabeling on context mounts */ + case SECURITY_FS_USE_MNTPOINT: + case SECURITY_FS_USE_NONE: + default: + return 0; + } +} + static int sb_finish_set_opts(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; @@ -2881,9 +2903,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, if (IS_ERR(isec)) return PTR_ERR(isec); - return avc_has_perm_flags(&selinux_state, - sid, isec->sid, isec->sclass, FILE__READ, &ad, - rcu ? MAY_NOT_BLOCK : 0); + return avc_has_perm(&selinux_state, + sid, isec->sid, isec->sclass, FILE__READ, &ad); } static noinline int audit_inode_permission(struct inode *inode, @@ -2938,7 +2959,9 @@ static int selinux_inode_permission(struct inode *inode, int mask) return PTR_ERR(isec); rc = avc_has_perm_noaudit(&selinux_state, - sid, isec->sid, isec->sclass, perms, 0, &avd); + sid, isec->sid, isec->sclass, perms, + (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0, + &avd); audited = avc_audit_required(perms, &avd, rc, from_access ? FILE__AUDIT_ACCESS : 0, &denied); @@ -3197,12 +3220,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { struct inode_security_struct *isec = inode_security_novalidate(inode); + struct superblock_security_struct *sbsec = inode->i_sb->s_security; u32 newsid; int rc; if (strcmp(name, XATTR_SELINUX_SUFFIX)) return -EOPNOTSUPP; + if (!(sbsec->flags & SBLABEL_MNT)) + return -EOPNOTSUPP; + if (!value || !size) return -EACCES; @@ -4445,7 +4472,7 @@ err_af: } /* This supports connect(2) and SCTP connect services such as sctp_connectx(3) - * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst + * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst */ static int selinux_socket_connect_helper(struct socket *sock, struct sockaddr *address, int addrlen) @@ -6236,7 +6263,10 @@ static void selinux_inode_invalidate_secctx(struct inode *inode) */ static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { - return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0); + int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, + ctx, ctxlen, 0); + /* Do not return error when suppressing label (SBLABEL_MNT not set). */ + return rc == -EOPNOTSUPP ? 0 : rc; } /* diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 36e1d44c0209..682e2b5de2a4 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h @@ -43,13 +43,11 @@ void selinux_audit_rule_free(void *rule); * @field: the field this rule refers to * @op: the operater the rule uses * @rule: pointer to the audit rule to check against - * @actx: the audit context (can be NULL) associated with the check * * Returns 1 if the context id matches the rule, 0 if it does not, and * -errno on failure. */ -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule, - struct audit_context *actx); +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule); /** * selinux_audit_rule_known - check to see if rule contains selinux fields. diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index ef899bcfd2cb..7be0e1e90e8b 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -142,6 +142,7 @@ static inline int avc_audit(struct selinux_state *state, #define AVC_STRICT 1 /* Ignore permissive mode. */ #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ +#define AVC_NONBLOCKING 4 /* non blocking */ int avc_has_perm_noaudit(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, u32 requested, @@ -152,11 +153,6 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata); -int avc_has_perm_flags(struct selinux_state *state, - u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct common_audit_data *auditdata, - int flags); int avc_has_extended_perms(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, u32 requested, diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ba8eedf42b90..f68fb25b5702 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -255,6 +255,9 @@ int security_sid_to_context(struct selinux_state *state, u32 sid, int security_sid_to_context_force(struct selinux_state *state, u32 sid, char **scontext, u32 *scontext_len); +int security_sid_to_context_inval(struct selinux_state *state, + u32 sid, char **scontext, u32 *scontext_len); + int security_context_to_sid(struct selinux_state *state, const char *scontext, u32 scontext_len, u32 *out_sid, gfp_t gfp); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d6e7b4856d93..1269e2be3c2d 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1280,7 +1280,8 @@ const char *security_get_initial_sid_context(u32 sid) static int security_sid_to_context_core(struct selinux_state *state, u32 sid, char **scontext, - u32 *scontext_len, int force) + u32 *scontext_len, int force, + int only_invalid) { struct policydb *policydb; struct sidtab *sidtab; @@ -1325,8 +1326,14 @@ static int security_sid_to_context_core(struct selinux_state *state, rc = -EINVAL; goto out_unlock; } - rc = context_struct_to_string(policydb, context, scontext, - scontext_len); + if (only_invalid && !context->len) { + scontext = NULL; + scontext_len = 0; + rc = 0; + } else { + rc = context_struct_to_string(policydb, context, scontext, + scontext_len); + } out_unlock: read_unlock(&state->ss->policy_rwlock); out: @@ -1348,14 +1355,34 @@ int security_sid_to_context(struct selinux_state *state, u32 sid, char **scontext, u32 *scontext_len) { return security_sid_to_context_core(state, sid, scontext, - scontext_len, 0); + scontext_len, 0, 0); } int security_sid_to_context_force(struct selinux_state *state, u32 sid, char **scontext, u32 *scontext_len) { return security_sid_to_context_core(state, sid, scontext, - scontext_len, 1); + scontext_len, 1, 0); +} + +/** + * security_sid_to_context_inval - Obtain a context for a given SID if it + * is invalid. + * @sid: security identifier, SID + * @scontext: security context + * @scontext_len: length in bytes + * + * Write the string representation of the context associated with @sid + * into a dynamically allocated string of the correct size, but only if the + * context is invalid in the current policy. Set @scontext to point to + * this string (or NULL if the context is valid) and set @scontext_len to + * the length of the string (or 0 if the context is valid). + */ +int security_sid_to_context_inval(struct selinux_state *state, u32 sid, + char **scontext, u32 *scontext_len) +{ + return security_sid_to_context_core(state, sid, scontext, + scontext_len, 1, 1); } /* @@ -3375,8 +3402,7 @@ int selinux_audit_rule_known(struct audit_krule *rule) return 0; } -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, - struct audit_context *actx) +int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) { struct selinux_state *state = &selinux_state; struct context *ctxt; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 79d6d2a6a0bc..424bce4ef21d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3293,13 +3293,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ final = &smack_known_star; /* - * Fall through. - * * If a smack value has been set we want to use it, * but since tmpfs isn't giving us the opportunity * to set mount options simulate setting the * superblock default. */ + /* Fall through */ default: /* * This isn't an understood special case. @@ -4296,13 +4295,11 @@ static int smack_audit_rule_known(struct audit_krule *krule) * @field: audit rule flags given from user-space * @op: required testing operator * @vrule: smack internal rule presentation - * @actx: audit context associated with the check * * The core Audit hook. It's used to take the decision of * whether to audit or not to audit a given object. */ -static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, - struct audit_context *actx) +static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule) { struct smack_known *skp; char *rule = vrule; diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 148ad50a1f94..57988d95d33d 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -354,7 +354,7 @@ void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns) INIT_LIST_HEAD(&ns->group_list[idx]); for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++) INIT_LIST_HEAD(&ns->policy_list[idx]); - ns->profile_version = 20110903; + ns->profile_version = 20150505; tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list); list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list); } @@ -2300,7 +2300,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) static void tomoyo_read_version(struct tomoyo_io_buffer *head) { if (!head->r.eof) { - tomoyo_io_printf(head, "2.5.0"); + tomoyo_io_printf(head, "2.6.0"); head->r.eof = true; } } @@ -2777,12 +2777,17 @@ void tomoyo_check_profile(void) const int idx = tomoyo_read_lock(); tomoyo_policy_loaded = true; - pr_info("TOMOYO: 2.5.0\n"); + pr_info("TOMOYO: 2.6.0\n"); list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { const u8 profile = domain->profile; - const struct tomoyo_policy_namespace *ns = domain->ns; + struct tomoyo_policy_namespace *ns = domain->ns; - if (ns->profile_version != 20110903) + if (ns->profile_version == 20110903) { + pr_info_once("Converting profile version from %u to %u.\n", + 20110903, 20150505); + ns->profile_version = 20150505; + } + if (ns->profile_version != 20150505) pr_err("Profile version %u is not supported.\n", ns->profile_version); else if (!ns->profile_ptr[profile]) @@ -2790,8 +2795,8 @@ void tomoyo_check_profile(void) profile, domain->domainname->name); else continue; - pr_err("Userland tools for TOMOYO 2.5 must be installed and policy must be initialized.\n"); - pr_err("Please see http://tomoyo.sourceforge.jp/2.5/ for more information.\n"); + pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n"); + pr_err("Please see https://tomoyo.osdn.jp/2.6/ for more information.\n"); panic("STOP!"); } tomoyo_read_unlock(idx); diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 74dbd3bdc64e..050473df5809 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -910,7 +910,7 @@ struct tomoyo_policy_namespace { struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS]; /* List for connecting to tomoyo_namespace_list list. */ struct list_head namespace_list; - /* Profile version. Currently only 20110903 is defined. */ + /* Profile version. Currently only 20150505 is defined. */ unsigned int profile_version; /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */ const char *name; |