diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/domain.c | 8 | ||||
-rw-r--r-- | security/apparmor/file.c | 4 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 25 | ||||
-rw-r--r-- | security/commoncap.c | 51 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 34 |
5 files changed, 68 insertions, 54 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 91689d34d281..7bafb4c4767c 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -859,10 +859,10 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) const char *info = NULL; int error = 0; bool unsafe = false; - kuid_t i_uid = i_uid_into_mnt(file_mnt_user_ns(bprm->file), - file_inode(bprm->file)); + vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(bprm->file), + file_inode(bprm->file)); struct path_cond cond = { - i_uid, + vfsuid_into_kuid(vfsuid), file_inode(bprm->file)->i_mode }; @@ -970,7 +970,7 @@ audit: error = fn_for_each(label, profile, aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC, bprm->filename, NULL, new, - i_uid, info, error)); + vfsuid_into_kuid(vfsuid), info, error)); aa_put_label(new); goto done; } diff --git a/security/apparmor/file.c b/security/apparmor/file.c index e1b7e93602e4..d43679894d23 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -510,8 +510,10 @@ static int __file_path_perm(const char *op, struct aa_label *label, { struct aa_profile *profile; struct aa_perms perms = {}; + vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(file), + file_inode(file)); struct path_cond cond = { - .uid = i_uid_into_mnt(file_mnt_user_ns(file), file_inode(file)), + .uid = vfsuid_into_kuid(vfsuid), .mode = file_inode(file)->i_mode }; char *buffer; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f56070270c69..f34675f7c3df 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -225,8 +225,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask, static int common_perm_cond(const char *op, const struct path *path, u32 mask) { struct user_namespace *mnt_userns = mnt_user_ns(path->mnt); + vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, + d_backing_inode(path->dentry)); struct path_cond cond = { - i_uid_into_mnt(mnt_userns, d_backing_inode(path->dentry)), + vfsuid_into_kuid(vfsuid), d_backing_inode(path->dentry)->i_mode }; @@ -270,11 +272,13 @@ static int common_perm_rm(const char *op, const struct path *dir, struct inode *inode = d_backing_inode(dentry); struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt); struct path_cond cond = { }; + vfsuid_t vfsuid; if (!inode || !path_mediated_fs(dentry)) return 0; - cond.uid = i_uid_into_mnt(mnt_userns, inode); + vfsuid = i_uid_into_vfsuid(mnt_userns, inode); + cond.uid = vfsuid_into_kuid(vfsuid); cond.mode = inode->i_mode; return common_perm_dir_dentry(op, dir, dentry, mask, &cond); @@ -368,20 +372,23 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d label = begin_current_label_crit_section(); if (!unconfined(label)) { struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt); + vfsuid_t vfsuid; struct path old_path = { .mnt = old_dir->mnt, .dentry = old_dentry }; struct path new_path = { .mnt = new_dir->mnt, .dentry = new_dentry }; struct path_cond cond = { - i_uid_into_mnt(mnt_userns, d_backing_inode(old_dentry)), - d_backing_inode(old_dentry)->i_mode + .mode = d_backing_inode(old_dentry)->i_mode }; + vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry)); + cond.uid = vfsuid_into_kuid(vfsuid); if (flags & RENAME_EXCHANGE) { struct path_cond cond_exchange = { - i_uid_into_mnt(mnt_userns, d_backing_inode(new_dentry)), - d_backing_inode(new_dentry)->i_mode + .mode = d_backing_inode(new_dentry)->i_mode, }; + vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry)); + cond_exchange.uid = vfsuid_into_kuid(vfsuid); error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0, MAY_READ | AA_MAY_GETATTR | MAY_WRITE | @@ -447,10 +454,12 @@ static int apparmor_file_open(struct file *file) if (!unconfined(label)) { struct user_namespace *mnt_userns = file_mnt_user_ns(file); struct inode *inode = file_inode(file); + vfsuid_t vfsuid; struct path_cond cond = { - i_uid_into_mnt(mnt_userns, inode), - inode->i_mode + .mode = inode->i_mode, }; + vfsuid = i_uid_into_vfsuid(mnt_userns, inode); + cond.uid = vfsuid_into_kuid(vfsuid); error = aa_path_perm(OP_OPEN, label, &file->f_path, 0, aa_map_file_to_perms(file), &cond); diff --git a/security/commoncap.c b/security/commoncap.c index bc751fa5adad..5d9570f54a1c 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -328,14 +328,16 @@ int cap_inode_killpriv(struct user_namespace *mnt_userns, struct dentry *dentry) return error; } -static bool rootid_owns_currentns(kuid_t kroot) +static bool rootid_owns_currentns(vfsuid_t rootvfsuid) { struct user_namespace *ns; + kuid_t kroot; - if (!uid_valid(kroot)) + if (!vfsuid_valid(rootvfsuid)) return false; - for (ns = current_user_ns(); ; ns = ns->parent) { + kroot = vfsuid_into_kuid(rootvfsuid); + for (ns = current_user_ns();; ns = ns->parent) { if (from_kuid(ns, kroot) == 0) return true; if (ns == &init_user_ns) @@ -381,6 +383,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns, { int size, ret; kuid_t kroot; + vfsuid_t vfsroot; u32 nsmagic, magic; uid_t root, mappedroot; char *tmpbuf = NULL; @@ -421,11 +424,11 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns, kroot = make_kuid(fs_ns, root); /* If this is an idmapped mount shift the kuid. */ - kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot); + vfsroot = make_vfsuid(mnt_userns, fs_ns, kroot); /* If the root kuid maps to a valid uid in current ns, then return * this as a nscap. */ - mappedroot = from_kuid(current_user_ns(), kroot); + mappedroot = from_kuid(current_user_ns(), vfsuid_into_kuid(vfsroot)); if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) { size = sizeof(struct vfs_ns_cap_data); if (alloc) { @@ -452,7 +455,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns, goto out_free; } - if (!rootid_owns_currentns(kroot)) { + if (!rootid_owns_currentns(vfsroot)) { size = -EOVERFLOW; goto out_free; } @@ -490,29 +493,17 @@ out_free: * @value: vfs caps value which may be modified by this function * @size: size of @ivalue * @task_ns: user namespace of the caller - * @mnt_userns: user namespace of the mount the inode was found from - * @fs_userns: user namespace of the filesystem - * - * If the inode has been found through an idmapped mount the user namespace of - * the vfsmount must be passed through @mnt_userns. This function will then - * take care to map the inode according to @mnt_userns before checking - * permissions. On non-idmapped mounts or if permission checking is to be - * performed on the raw inode simply passs init_user_ns. */ -static kuid_t rootid_from_xattr(const void *value, size_t size, - struct user_namespace *task_ns, - struct user_namespace *mnt_userns, - struct user_namespace *fs_userns) +static vfsuid_t rootid_from_xattr(const void *value, size_t size, + struct user_namespace *task_ns) { const struct vfs_ns_cap_data *nscap = value; - kuid_t rootkid; uid_t rootid = 0; if (size == XATTR_CAPS_SZ_3) rootid = le32_to_cpu(nscap->rootid); - rootkid = make_kuid(task_ns, rootid); - return mapped_kuid_user(mnt_userns, fs_userns, rootkid); + return VFSUIDT_INIT(make_kuid(task_ns, rootid)); } static bool validheader(size_t size, const struct vfs_cap_data *cap) @@ -550,6 +541,7 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry, struct user_namespace *task_ns = current_user_ns(), *fs_ns = inode->i_sb->s_user_ns; kuid_t rootid; + vfsuid_t vfsrootid; size_t newsize; if (!*ivalue) @@ -563,7 +555,11 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry, /* user is privileged, just write the v2 */ return size; - rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns); + vfsrootid = rootid_from_xattr(*ivalue, size, task_ns); + if (!vfsuid_valid(vfsrootid)) + return -EINVAL; + + rootid = from_vfsuid(mnt_userns, fs_ns, vfsrootid); if (!uid_valid(rootid)) return -EINVAL; @@ -657,6 +653,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, struct vfs_ns_cap_data data, *nscaps = &data; struct vfs_cap_data *caps = (struct vfs_cap_data *) &data; kuid_t rootkuid; + vfsuid_t rootvfsuid; struct user_namespace *fs_ns; memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); @@ -701,11 +698,15 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, default: return -EINVAL; } + + rootvfsuid = make_vfsuid(mnt_userns, fs_ns, rootkuid); + if (!vfsuid_valid(rootvfsuid)) + return -ENODATA; + /* Limit the caps to the mounter of the filesystem * or the more limited uid specified in the xattr. */ - rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid); - if (!rootid_owns_currentns(rootkuid)) + if (!rootid_owns_currentns(rootvfsuid)) return -ENODATA; CAP_FOR_EACH_U32(i) { @@ -718,7 +719,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns, 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; + cpu_caps->rootid = vfsuid_into_kuid(rootvfsuid); return 0; } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index a8802b8da946..54c475f98ce1 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -85,8 +85,8 @@ struct ima_rule_entry { kgid_t fgroup; bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */ bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid); - bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */ - bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */ + bool (*fowner_op)(vfsuid_t vfsuid, kuid_t rule_uid); /* vfsuid_eq_kuid(), vfsuid_gt_kuid(), vfsuid_lt_kuid() */ + bool (*fgroup_op)(vfsgid_t vfsgid, kgid_t rule_gid); /* vfsgid_eq_kgid(), vfsgid_gt_kgid(), vfsgid_lt_kgid() */ int pcr; unsigned int allowed_algos; /* bitfield of allowed hash algorithms */ struct { @@ -186,11 +186,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, #endif #ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT - {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid, .flags = IMA_FOWNER}, #else /* force signature */ - {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq, + {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid, .flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED}, #endif }; @@ -601,10 +601,12 @@ static bool ima_match_rules(struct ima_rule_entry *rule, return false; } if ((rule->flags & IMA_FOWNER) && - !rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner)) + !rule->fowner_op(i_uid_into_vfsuid(mnt_userns, inode), + rule->fowner)) return false; if ((rule->flags & IMA_FGROUP) && - !rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup)) + !rule->fgroup_op(i_gid_into_vfsgid(mnt_userns, inode), + rule->fgroup)) return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; @@ -1371,8 +1373,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->fgroup = INVALID_GID; entry->uid_op = &uid_eq; entry->gid_op = &gid_eq; - entry->fowner_op = &uid_eq; - entry->fgroup_op = &gid_eq; + entry->fowner_op = &vfsuid_eq_kuid; + entry->fgroup_op = &vfsgid_eq_kgid; entry->action = UNKNOWN; while ((p = strsep(&rule, " \t")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -1650,11 +1652,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) } break; case Opt_fowner_gt: - entry->fowner_op = &uid_gt; + entry->fowner_op = &vfsuid_gt_kuid; fallthrough; case Opt_fowner_lt: if (token == Opt_fowner_lt) - entry->fowner_op = &uid_lt; + entry->fowner_op = &vfsuid_lt_kuid; fallthrough; case Opt_fowner_eq: ima_log_string_op(ab, "fowner", args[0].from, token); @@ -1676,11 +1678,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) } break; case Opt_fgroup_gt: - entry->fgroup_op = &gid_gt; + entry->fgroup_op = &vfsgid_gt_kgid; fallthrough; case Opt_fgroup_lt: if (token == Opt_fgroup_lt) - entry->fgroup_op = &gid_lt; + entry->fgroup_op = &vfsgid_lt_kgid; fallthrough; case Opt_fgroup_eq: ima_log_string_op(ab, "fgroup", args[0].from, token); @@ -2151,9 +2153,9 @@ int ima_policy_show(struct seq_file *m, void *v) if (entry->flags & IMA_FOWNER) { snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner)); - if (entry->fowner_op == &uid_gt) + if (entry->fowner_op == &vfsuid_gt_kuid) seq_printf(m, pt(Opt_fowner_gt), tbuf); - else if (entry->fowner_op == &uid_lt) + else if (entry->fowner_op == &vfsuid_lt_kuid) seq_printf(m, pt(Opt_fowner_lt), tbuf); else seq_printf(m, pt(Opt_fowner_eq), tbuf); @@ -2162,9 +2164,9 @@ int ima_policy_show(struct seq_file *m, void *v) if (entry->flags & IMA_FGROUP) { snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup)); - if (entry->fgroup_op == &gid_gt) + if (entry->fgroup_op == &vfsgid_gt_kgid) seq_printf(m, pt(Opt_fgroup_gt), tbuf); - else if (entry->fgroup_op == &gid_lt) + else if (entry->fgroup_op == &vfsgid_lt_kgid) seq_printf(m, pt(Opt_fgroup_lt), tbuf); else seq_printf(m, pt(Opt_fgroup_eq), tbuf); |