Message ID | 1444826525-9758-11-git-send-email-l.pawelczyk@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 10/14/2015 5:42 AM, Lukasz Pawelczyk wrote: > This commit uses all the changes introduced in "namespace groundwork" > and previous preparation patches and makes smack aware of its namespace > and mapped labels. > > It modifies the following functions to be namespace aware: > - smk_access > - smk_find_label_name > - smk_get_label > > And all functions that use them (e.g. smk_tskacc). > > It also adds another function that is used throughout Smack LSM hooks: > - smk_labels_valid - it checks whether both, subject and object labels > are properly mapped in a namespace where they are to be used. This > function is used mostly together with a capability check when there is > no proper access check that usually checks for that. > > All the Smack LSM hooks have been adapted to be namespace aware. > > The capabilities (CAP_MAC_ADMIN, CAP_MAC_OVERRIDE) has been allowed in > the namespace for few cases. Check the documentation for the details. > > Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@samsung.com> > Reviewed-by: Casey Schaufler <casey@schaufler-ca.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> > --- > security/smack/smack.h | 29 +++- > security/smack/smack_access.c | 109 ++++++++++-- > security/smack/smack_lsm.c | 390 ++++++++++++++++++++++++++++++------------ > security/smack/smack_ns.c | 39 +++++ > security/smack/smackfs.c | 63 ++++--- > 5 files changed, 483 insertions(+), 147 deletions(-) > > diff --git a/security/smack/smack.h b/security/smack/smack.h > index 4b7489f..3d432f4 100644 > --- a/security/smack/smack.h > +++ b/security/smack/smack.h > @@ -119,6 +119,7 @@ struct superblock_smack { > struct smack_known *smk_floor; > struct smack_known *smk_hat; > struct smack_known *smk_default; > + struct user_namespace *smk_ns; > int smk_initialized; > }; > > @@ -126,6 +127,7 @@ struct socket_smack { > struct smack_known *smk_out; /* outbound label */ > struct smack_known *smk_in; /* inbound label */ > struct smack_known *smk_packet; /* TCP peer label */ > + struct user_namespace *smk_ns; /* user namespace */ > }; > > /* > @@ -146,6 +148,14 @@ struct task_smack { > struct mutex smk_rules_lock; /* lock for the rules */ > }; > > +/* > + * Used for IPC objects (sem, shm, etc) > + */ > +struct ipc_smack { > + struct smack_known *smk_known; /* label for access control */ > + struct user_namespace *smk_ns; /* user namespace */ > +}; > + > #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ > #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ > #define SMK_INODE_CHANGED 0x04 /* smack was transmuted */ > @@ -319,10 +329,11 @@ struct smk_audit_info { > */ > int smk_access_entry(char *, char *, struct list_head *); > int smk_access(struct smack_known *, struct smack_known *, > - int, struct smk_audit_info *); > + struct user_namespace *, int, struct smk_audit_info *); > int smk_tskacc(struct task_struct *, struct smack_known *, > + struct user_namespace *, u32, struct smk_audit_info *); > +int smk_curacc(struct smack_known *, struct user_namespace *, > u32, struct smk_audit_info *); > -int smk_curacc(struct smack_known *, u32, struct smk_audit_info *); > struct smack_known *smack_from_secid(const u32); > char *smk_parse_smack(const char *string, int len, bool *allocated); > int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); > @@ -335,8 +346,9 @@ int smack_has_ns_privilege(struct task_struct *task, > int smack_has_privilege(struct task_struct *task, int cap); > int smack_ns_privileged(struct user_namespace *user_ns, int cap); > int smack_privileged(int cap); > -char *smk_find_label_name(struct smack_known *skp); > -struct smack_known *smk_get_label(const char *string, int len, bool import); > +char *smk_find_label_name(struct smack_known *skp, struct user_namespace *ns); > +struct smack_known *smk_get_label(const char *string, int len, bool import, > + struct user_namespace *ns); > > /* > * These functions are in smack_ns.c > @@ -350,6 +362,15 @@ struct smack_known *smk_find_unmapped(const char *string, int len, > extern const struct seq_operations proc_label_map_seq_operations; > ssize_t proc_label_map_write(struct task_struct *p, const struct cred *f_cred, > void *value, size_t size); > +bool smk_labels_valid(struct smack_known *sbj, struct smack_known *obj, > + struct user_namespace *ns); > +#else > +static inline bool smk_labels_valid(struct smack_known *sbj, > + struct smack_known *obj, > + struct user_namespace *ns) > +{ > + return true; > +} > #endif /* CONFIG_SECURITY_SMACK_NS */ > > /* > diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c > index 17b7e2c..e230948 100644 > --- a/security/smack/smack_access.c > +++ b/security/smack/smack_access.c > @@ -14,6 +14,7 @@ > #include <linux/slab.h> > #include <linux/fs.h> > #include <linux/sched.h> > +#include <linux/user_namespace.h> > #include "smack.h" > > struct smack_known smack_known_huh = { > @@ -113,6 +114,7 @@ int smk_access_entry(char *subject_label, char *object_label, > * smk_access - determine if a subject has a specific access to an object > * @subject: a pointer to the subject's Smack label entry > * @object: a pointer to the object's Smack label entry > + * @ns: user namespace to check against (usually subject's) > * @request: the access requested, in "MAY" format > * @a : a pointer to the audit data > * > @@ -123,10 +125,34 @@ int smk_access_entry(char *subject_label, char *object_label, > * Smack labels are shared on smack_list > */ > int smk_access(struct smack_known *subject, struct smack_known *object, > - int request, struct smk_audit_info *a) > + struct user_namespace *ns, int request, struct smk_audit_info *a) > { > int may = MAY_NOT; > int rc = 0; > + char *subject_label = subject->smk_known; > + char *object_label = object->smk_known; > +#ifdef CONFIG_SECURITY_SMACK_NS > + struct smack_known_ns *sknp; > + struct smack_known_ns *oknp; > + > + /* > + * For the namespaced case we need to check whether the labels > + * are mapped. If not, refuse. If yes check the builtin rules > + * on the mapped label strings so the builtin labels can > + * work properly inside the namespace. > + */ > + if (smk_find_mapped_ns(ns)) { > + sknp = smk_find_mapped(subject, ns); > + oknp = smk_find_mapped(object, ns); > + if (!sknp || !oknp) { > + rc = -EACCES; > + goto out_audit; > + } > + > + subject_label = sknp->smk_mapped; > + object_label = oknp->smk_mapped; > + } > +#endif > > /* > * Hardcoded comparisons. > @@ -134,7 +160,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object, > /* > * A star subject can't access any object. > */ > - if (subject == &smack_known_star) { > + if (subject_label == smack_known_star.smk_known) { > rc = -EACCES; > goto out_audit; > } > @@ -143,18 +169,19 @@ int smk_access(struct smack_known *subject, struct smack_known *object, > * Tasks cannot be assigned the internet label. > * An internet subject can access any object. > */ > - if (object == &smack_known_web || subject == &smack_known_web) > + if (object_label == smack_known_web.smk_known || > + subject_label == smack_known_web.smk_known) > goto out_audit; > /* > * A star object can be accessed by any subject. > */ > - if (object == &smack_known_star) > + if (object_label == smack_known_star.smk_known) > goto out_audit; > /* > * An object can be accessed in any way by a subject > * with the same label. > */ > - if (subject->smk_known == object->smk_known) > + if (subject_label == object_label) > goto out_audit; > /* > * A hat subject can read or lock any object. > @@ -162,9 +189,9 @@ int smk_access(struct smack_known *subject, struct smack_known *object, > */ > if ((request & MAY_ANYREAD) == request || > (request & MAY_LOCK) == request) { > - if (object == &smack_known_floor) > + if (object_label == smack_known_floor.smk_known) > goto out_audit; > - if (subject == &smack_known_hat) > + if (subject_label == smack_known_hat.smk_known) > goto out_audit; > } > > @@ -174,6 +201,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object, > * access (e.g. read is included in readwrite) it's > * good. A negative response from smk_access_entry() > * indicates there is no entry for this pair. > + * For this check we need real, not mapped labels. > */ > rcu_read_lock(); > may = smk_access_entry(subject->smk_known, object->smk_known, > @@ -219,6 +247,7 @@ out_audit: > * smk_tskacc - determine if a task has a specific access to an object > * @tsp: a pointer to the subject's task > * @obj_known: a pointer to the object's label entry > + * @obj_ns: an object's namespace to check the caps against > * @mode: the access requested, in "MAY" format > * @a : common audit data > * > @@ -228,16 +257,18 @@ out_audit: > * to override the rules. > */ > int smk_tskacc(struct task_struct *task, struct smack_known *obj_known, > - u32 mode, struct smk_audit_info *a) > + struct user_namespace *obj_ns, u32 mode, > + struct smk_audit_info *a) > { > struct smack_known *sbj_known = smk_of_task_struct(task); > + struct user_namespace *sbj_ns = ns_of_task_struct(task); > int may; > int rc; > > /* > * Check the global rule list > */ > - rc = smk_access(sbj_known, obj_known, mode, NULL); > + rc = smk_access(sbj_known, obj_known, sbj_ns, mode, NULL); > if (rc >= 0) { > struct task_smack *tsp; > > @@ -261,8 +292,10 @@ int smk_tskacc(struct task_struct *task, struct smack_known *obj_known, > > /* > * Allow for priviliged to override policy. > + * Either in init_ns or when both labels are mapped. > */ > - if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE)) > + if (rc != 0 && smk_labels_valid(sbj_known, obj_known, sbj_ns) > + && smack_has_ns_privilege(task, obj_ns, CAP_MAC_OVERRIDE)) > rc = 0; > > out_audit: > @@ -277,6 +310,7 @@ out_audit: > /** > * smk_curacc - determine if current has a specific access to an object > * @obj_known: a pointer to the object's Smack label entry > + * @obj_ns: an object's namespace to check the caps against > * @mode: the access requested, in "MAY" format > * @a : common audit data > * > @@ -285,10 +319,10 @@ out_audit: > * non zero otherwise. It allows that current may have the capability > * to override the rules. > */ > -int smk_curacc(struct smack_known *obj_known, > +int smk_curacc(struct smack_known *obj_known, struct user_namespace *obj_ns, > u32 mode, struct smk_audit_info *a) > { > - return smk_tskacc(current, obj_known, mode, a); > + return smk_tskacc(current, obj_known, obj_ns, mode, a); > } > > #ifdef CONFIG_AUDIT > @@ -671,12 +705,13 @@ DEFINE_MUTEX(smack_onlycap_lock); > * > * For a capability in smack related checks to be effective it needs to: > * - be allowed to be privileged by the onlycap rule. > - * - be in the initial user ns > + * - be in the initial user ns or have a filled map in the child ns > */ > static int smack_capability_allowed(struct smack_known *skp, > struct user_namespace *user_ns) > { > struct smack_onlycap *sop; > + struct smack_ns *sns; > > /* > * All kernel tasks are privileged > @@ -684,8 +719,15 @@ static int smack_capability_allowed(struct smack_known *skp, > if (unlikely(current->flags & PF_KTHREAD)) > return 1; > > +#ifdef CONFIG_SECURITY_SMACK_NS > + sns = user_ns->security; > + > + if (user_ns != &init_user_ns && list_empty(&sns->smk_mapped)) > + return 0; > +#else > if (user_ns != &init_user_ns) > return 0; > +#endif /* CONFIG_SECURITY_SMACK_NS */ > > rcu_read_lock(); > if (list_empty(&smack_onlycap_list)) { > @@ -755,14 +797,32 @@ int smack_privileged(int cap) > } > > /** > - * smk_find_label_name - A helper to get a string value of a label > + * smk_find_label_name - A helper to get a string value of either a label or a > + * mapped label when inside a namespace > * @skp: a label we want a string value from > + * @ns: namespace against which we want to get the value > * > * Returns a pointer to a label name or NULL if label name not found. > */ > -char *smk_find_label_name(struct smack_known *skp) > +char *smk_find_label_name(struct smack_known *skp, struct user_namespace *ns) > { > - return skp->smk_known; > + char *name = NULL; > + > +#ifdef CONFIG_SECURITY_SMACK_NS > + struct smack_known_ns *sknp; > + > + if (smk_find_mapped_ns(ns)) { > + sknp = smk_find_mapped(skp, ns); > + if (sknp != NULL) > + name = sknp->smk_mapped; > + } else { > + name = skp->smk_known; > + } > +#else > + name = skp->smk_known; > +#endif > + > + return name; > } > > /** > @@ -771,17 +831,32 @@ char *smk_find_label_name(struct smack_known *skp) > * @string: a name of a label we look for or want to import > * @len: the string size, or zero if it is NULL terminated > * @import: whether we should import the label if not found > + * @ns: a namespace the looked for label should be in > * > * Returns a smack_known label that is either imported or found. > * NULL if label not found (only when import == false). > * Error code otherwise. > */ > -struct smack_known *smk_get_label(const char *string, int len, bool import) > +struct smack_known *smk_get_label(const char *string, int len, bool import, > + struct user_namespace *ns) > { > struct smack_known *skp; > bool allocated; > char *cp; > > +#ifdef CONFIG_SECURITY_SMACK_NS > + if (smk_find_mapped_ns(ns)) { > + skp = smk_find_unmapped(string, len, ns); > + > + /* Label not found but we can't import in namespaces */ > + if (skp == NULL && import) > + skp = ERR_PTR(-EBADR); > + > + /* will also return error codes from smk_find_unmapped() */ > + return skp; > + } > +#endif > + > if (import) { > skp = smk_import_entry(string, len); > } else { > diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c > index 206e0ce..8e0da67 100644 > --- a/security/smack/smack_lsm.c > +++ b/security/smack/smack_lsm.c > @@ -383,6 +383,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) > * smk_ptrace_rule_check - helper for ptrace access > * @tracer: tracer process > * @tracee_known: label entry of the process that's about to be traced > + * @tracee_ns: a tracee's namespace to check the caps against > * @mode: ptrace attachment mode (PTRACE_MODE_*) > * @func: name of the function that called us, used for audit > * > @@ -390,6 +391,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) > */ > static int smk_ptrace_rule_check(struct task_struct *tracer, > struct smack_known *tracee_known, > + struct user_namespace *tracee_ns, > unsigned int mode, const char *func) > { > int rc; > @@ -401,21 +403,28 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, > saip = &ad; > } > > - > if ((mode & PTRACE_MODE_ATTACH) && > (smack_ptrace_rule == SMACK_PTRACE_EXACT || > smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) { > struct smack_known *tracer_known = smk_of_task_struct(tracer); > + struct user_namespace *tracer_ns = ns_of_task_struct(tracer); > + > + if (!smk_labels_valid(tracer_known, tracee_known, tracer_ns)) { > + rc = -EACCES; > + goto out; > + } > > if (tracer_known->smk_known == tracee_known->smk_known) > rc = 0; > else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) > rc = -EACCES; > - else if (smack_has_privilege(tracer, CAP_SYS_PTRACE)) > + else if (smack_has_ns_privilege(tracer, tracee_ns, > + CAP_SYS_PTRACE)) > rc = 0; > else > rc = -EPERM; > > +out: > if (saip) > smack_log(tracer_known->smk_known, > tracee_known->smk_known, > @@ -425,7 +434,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, > } > > /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ > - return smk_tskacc(tracer, tracee_known, smk_ptrace_mode(mode), saip); > + return smk_tskacc(tracer, tracee_known, tracee_ns, > + smk_ptrace_mode(mode), saip); > } > > /* > @@ -445,8 +455,9 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, > static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) > { > struct smack_known *skp = smk_of_task_struct(ctp); > + struct user_namespace *ns = ns_of_task_struct(ctp); > > - return smk_ptrace_rule_check(current, skp, mode, __func__); > + return smk_ptrace_rule_check(current, skp, ns, mode, __func__); > } > > /** > @@ -460,8 +471,10 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) > static int smack_ptrace_traceme(struct task_struct *ptp) > { > struct smack_known *skp = smk_of_current(); > + struct user_namespace *ns = ns_of_current(); > > - return smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); > + return smk_ptrace_rule_check(ptp, skp, ns, PTRACE_MODE_ATTACH, > + __func__); > } > > /** > @@ -508,6 +521,7 @@ static int smack_sb_alloc_security(struct super_block *sb) > sbsp->smk_default = &smack_known_floor; > sbsp->smk_floor = &smack_known_floor; > sbsp->smk_hat = &smack_known_hat; > + sbsp->smk_ns = get_user_ns(&init_user_ns); > /* > * smk_initialized will be zero from kzalloc. > */ > @@ -523,6 +537,9 @@ static int smack_sb_alloc_security(struct super_block *sb) > */ > static void smack_sb_free_security(struct super_block *sb) > { > + struct superblock_smack *sbsp = sb->s_security; > + > + put_user_ns(sbsp->smk_ns); > kfree(sb->s_security); > sb->s_security = NULL; > } > @@ -724,6 +741,7 @@ static int smack_set_mnt_opts(struct super_block *sb, > struct smack_known *skp; > int i; > int num_opts = opts->num_mnt_opts; > + struct user_namespace *ns = ns_of_current(); > int transmute = 0; > > if (sp->smk_initialized) > @@ -734,31 +752,31 @@ static int smack_set_mnt_opts(struct super_block *sb, > for (i = 0; i < num_opts; i++) { > switch (opts->mnt_opts_flags[i]) { > case FSDEFAULT_MNT: > - skp = smk_get_label(opts->mnt_opts[i], 0, true); > + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > sp->smk_default = skp; > break; > case FSFLOOR_MNT: > - skp = smk_get_label(opts->mnt_opts[i], 0, true); > + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > sp->smk_floor = skp; > break; > case FSHAT_MNT: > - skp = smk_get_label(opts->mnt_opts[i], 0, true); > + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > sp->smk_hat = skp; > break; > case FSROOT_MNT: > - skp = smk_get_label(opts->mnt_opts[i], 0, true); > + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > sp->smk_root = skp; > break; > case FSTRANS_MNT: > - skp = smk_get_label(opts->mnt_opts[i], 0, true); > + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > sp->smk_root = skp; > @@ -769,7 +787,12 @@ static int smack_set_mnt_opts(struct super_block *sb, > } > } > > - if (!smack_privileged(CAP_MAC_ADMIN)) { > + /* > + * Check for non-privileged case. If current is inside the namespace > + * and the it has privileges the validity of labels has already been > + * checked during smk_get_label() > + */ > + if (!smack_ns_privileged(ns, CAP_MAC_ADMIN)) { > /* > * Unprivileged mounts don't get to specify Smack values. > */ > @@ -798,6 +821,12 @@ static int smack_set_mnt_opts(struct super_block *sb, > if (transmute) > isp->smk_flags |= SMK_INODE_TRANSMUTE; > > + /* > + * Set the superblock namespace from a mounting process > + */ > + put_user_ns(sp->smk_ns); > + sp->smk_ns = get_user_ns(ns); > + > return 0; > } > > @@ -848,7 +877,7 @@ static int smack_sb_statfs(struct dentry *dentry) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); > smk_ad_setfield_u_fs_path_dentry(&ad, dentry); > > - rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); > + rc = smk_curacc(sbp->smk_floor, sbp->smk_ns, MAY_READ, &ad); > rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc); > return rc; > } > @@ -868,6 +897,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) > struct inode *inode = file_inode(bprm->file); > struct task_smack *bsp = bprm->cred->security; > struct inode_smack *isp; > + struct user_namespace *ns = ns_of_current(); > int rc; > > if (bprm->cred_prepared) > @@ -877,6 +907,13 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) > if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) > return 0; > > +#ifdef CONFIG_SECURITY_SMACK_NS > + /* one label version of smk_labels_valid() */ > + if (smk_find_mapped_ns(ns) && > + smk_find_mapped(isp->smk_task, ns) == NULL) > + return -EACCES; > +#endif > + > if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { > struct task_struct *tracer; > rc = 0; > @@ -884,9 +921,8 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) > rcu_read_lock(); > tracer = ptrace_parent(current); > if (likely(tracer != NULL)) > - rc = smk_ptrace_rule_check(tracer, > - isp->smk_task, > - PTRACE_MODE_ATTACH, > + rc = smk_ptrace_rule_check(tracer, isp->smk_task, > + ns, PTRACE_MODE_ATTACH, > __func__); > rcu_read_unlock(); > > @@ -1027,6 +1063,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, > struct dentry *new_dentry) > { > struct smack_known *isp; > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int rc; > > @@ -1034,13 +1071,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, > smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); > > isp = smk_of_inode(d_backing_inode(old_dentry)); > - rc = smk_curacc(isp, MAY_WRITE, &ad); > + rc = smk_curacc(isp, ns, MAY_WRITE, &ad); > rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_WRITE, rc); > > if (rc == 0 && d_is_positive(new_dentry)) { > isp = smk_of_inode(d_backing_inode(new_dentry)); > smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); > - rc = smk_curacc(isp, MAY_WRITE, &ad); > + rc = smk_curacc(isp, ns, MAY_WRITE, &ad); > rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_WRITE, rc); > } > > @@ -1058,6 +1095,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, > static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) > { > struct inode *ip = d_backing_inode(dentry); > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int rc; > > @@ -1067,7 +1105,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) > /* > * You need write access to the thing you're unlinking > */ > - rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(ip), ns, MAY_WRITE, &ad); > rc = smk_bu_inode(ip, MAY_WRITE, rc); > if (rc == 0) { > /* > @@ -1075,7 +1113,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) > */ > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); > smk_ad_setfield_u_fs_inode(&ad, dir); > - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(dir), ns, MAY_WRITE, &ad); > rc = smk_bu_inode(dir, MAY_WRITE, rc); > } > return rc; > @@ -1091,6 +1129,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) > */ > static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) > { > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int rc; > > @@ -1100,7 +1139,8 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) > /* > * You need write access to the thing you're removing > */ > - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns, > + MAY_WRITE, &ad); > rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); > if (rc == 0) { > /* > @@ -1108,7 +1148,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) > */ > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); > smk_ad_setfield_u_fs_inode(&ad, dir); > - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(dir), ns, MAY_WRITE, &ad); > rc = smk_bu_inode(dir, MAY_WRITE, rc); > } > > @@ -1132,21 +1172,22 @@ static int smack_inode_rename(struct inode *old_inode, > struct inode *new_inode, > struct dentry *new_dentry) > { > - int rc; > struct smack_known *isp; > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > + int rc; > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); > smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); > > isp = smk_of_inode(d_backing_inode(old_dentry)); > - rc = smk_curacc(isp, MAY_READWRITE, &ad); > + rc = smk_curacc(isp, ns, MAY_READWRITE, &ad); > rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_READWRITE, rc); > > if (rc == 0 && d_is_positive(new_dentry)) { > isp = smk_of_inode(d_backing_inode(new_dentry)); > smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); > - rc = smk_curacc(isp, MAY_READWRITE, &ad); > + rc = smk_curacc(isp, ns, MAY_READWRITE, &ad); > rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_READWRITE, rc); > } > return rc; > @@ -1163,6 +1204,7 @@ static int smack_inode_rename(struct inode *old_inode, > */ > static int smack_inode_permission(struct inode *inode, int mask) > { > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int no_block = mask & MAY_NOT_BLOCK; > int rc; > @@ -1179,7 +1221,7 @@ static int smack_inode_permission(struct inode *inode, int mask) > return -ECHILD; > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); > smk_ad_setfield_u_fs_inode(&ad, inode); > - rc = smk_curacc(smk_of_inode(inode), mask, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, mask, &ad); > rc = smk_bu_inode(inode, mask, rc); > return rc; > } > @@ -1193,6 +1235,7 @@ static int smack_inode_permission(struct inode *inode, int mask) > */ > static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) > { > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int rc; > > @@ -1204,7 +1247,8 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); > smk_ad_setfield_u_fs_path_dentry(&ad, dentry); > > - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns, > + MAY_WRITE, &ad); > rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); > return rc; > } > @@ -1218,13 +1262,14 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) > */ > static int smack_inode_getattr(const struct path *path) > { > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > struct inode *inode = d_backing_inode(path->dentry); > int rc; > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); > smk_ad_setfield_u_fs_path(&ad, *path); > - rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, MAY_READ, &ad); > rc = smk_bu_inode(inode, MAY_READ, rc); > return rc; > } > @@ -1246,6 +1291,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, > { > struct smk_audit_info ad; > struct smack_known *skp; > + struct smack_known *sbj = smk_of_current(); > + struct smack_known *obj = smk_of_inode(d_backing_inode(dentry)); > + struct user_namespace *ns = ns_of_current(); > int check_priv = 0; > int check_import = 0; > int check_star = 0; > @@ -1272,11 +1320,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, > } else > rc = cap_inode_setxattr(dentry, name, value, size, flags); > > - if (check_priv && !smack_privileged(CAP_MAC_ADMIN)) > + if (check_priv && !(smk_labels_valid(sbj, obj, ns) && > + smack_ns_privileged(ns, CAP_MAC_ADMIN))) > rc = -EPERM; > > if (rc == 0 && check_import) { > - skp = size ? smk_get_label(value, size, true) : NULL; > + skp = size ? smk_get_label(value, size, true, ns) : NULL; > if (IS_ERR(skp)) > rc = PTR_ERR(skp); > else if (skp == NULL || (check_star && > @@ -1288,7 +1337,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, > smk_ad_setfield_u_fs_path_dentry(&ad, dentry); > > if (rc == 0) { > - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); > + rc = smk_curacc(obj, ns, MAY_WRITE, &ad); > rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); > } > > @@ -1296,6 +1345,40 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, > } > > /** > + * smack_inode_pre_setxattr - Unmap the namespaced label > + * @dentry: object > + * @name: attribute name > + * @value: attribute value > + * @size: attribute size > + * @flags: unused > + * @alloc: unused > + * > + * Guarantees that the real label value will be written to the filesystem. > + */ > +static int smack_inode_pre_setxattr(struct dentry *dentry, const char *name, > + const void **value, size_t *size, int flags, > + bool *alloc) > +{ > + struct smack_known *skp; > + struct user_namespace *ns = ns_of_current(); > + > + if (strcmp(name, XATTR_NAME_SMACK) != 0 && > + strcmp(name, XATTR_NAME_SMACKEXEC) != 0 && > + strcmp(name, XATTR_NAME_SMACKMMAP) != 0) > + return 0; > + > + /* Convert value to non namespaced label */ > + skp = smk_get_label(*value, *size, true, ns); > + if (IS_ERR(skp)) > + return PTR_ERR(skp); > + > + *value = skp->smk_known; > + *size = strlen(skp->smk_known); > + > + return 0; > +} > + > +/** > * smack_inode_post_setxattr - Apply the Smack update approved above > * @dentry: object > * @name: attribute name > @@ -1326,7 +1409,8 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, > skpp = &isp->smk_mmap; > > if (skpp) { > - skp = smk_get_label(value, size, true); > + /* value has been un-namespaced in inode_pre_setxattr() */ > + skp = smk_get_label(value, size, true, &init_user_ns); > > if (!IS_ERR(skp)) > *skpp = skp; > @@ -1344,13 +1428,15 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, > */ > static int smack_inode_getxattr(struct dentry *dentry, const char *name) > { > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int rc; > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); > smk_ad_setfield_u_fs_path_dentry(&ad, dentry); > > - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad); > + rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns, > + MAY_READ, &ad); > rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc); > return rc; > } > @@ -1367,6 +1453,9 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) > static int smack_inode_removexattr(struct dentry *dentry, const char *name) > { > struct inode_smack *isp; > + struct smack_known *sbj = smk_of_current(); > + struct smack_known *obj = smk_of_inode(d_backing_inode(dentry)); > + struct user_namespace *ns = ns_of_current(); > struct smk_audit_info ad; > int rc = 0; > > @@ -1376,7 +1465,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) > strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || > strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || > strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { > - if (!smack_privileged(CAP_MAC_ADMIN)) > + if (!smk_labels_valid(sbj, obj, ns) || > + !smack_ns_privileged(ns, CAP_MAC_ADMIN)) > rc = -EPERM; > } else > rc = cap_inode_removexattr(dentry, name); > @@ -1387,7 +1477,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); > smk_ad_setfield_u_fs_path_dentry(&ad, dentry); > > - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); > + rc = smk_curacc(obj, ns, MAY_WRITE, &ad); > rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); > if (rc != 0) > return rc; > @@ -1427,13 +1517,18 @@ static int smack_inode_getsecurity(const struct inode *inode, > struct super_block *sbp; > struct inode *ip = (struct inode *)inode; > struct smack_known *isp = NULL; > + struct user_namespace *ns = ns_of_current(); > int rc = 0; > > if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) > isp = smk_of_inode(inode); > + else if (strcmp(name, XATTR_SMACK_EXEC) == 0) > + isp = smk_of_exec(inode); > + else if (strcmp(name, XATTR_SMACK_MMAP) == 0) > + isp = smk_of_mmap(inode); > > if (isp) { > - *buffer = smk_find_label_name(isp); > + *buffer = smk_find_label_name(isp, ns); > if (*buffer == NULL) > *buffer = smack_known_huh.smk_known; > return strlen(*buffer); > @@ -1460,7 +1555,7 @@ static int smack_inode_getsecurity(const struct inode *inode, > return -EOPNOTSUPP; > > if (rc == 0) { > - *buffer = smk_find_label_name(isp); > + *buffer = smk_find_label_name(isp, ns); > if (*buffer == NULL) > *buffer = smack_known_huh.smk_known; > rc = strlen(*buffer); > @@ -1571,18 +1666,19 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, > { > int rc = 0; > struct smk_audit_info ad; > + struct user_namespace *ns = ns_of_current(); > struct inode *inode = file_inode(file); > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); > smk_ad_setfield_u_fs_path(&ad, file->f_path); > > if (_IOC_DIR(cmd) & _IOC_WRITE) { > - rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, MAY_WRITE, &ad); > rc = smk_bu_file(file, MAY_WRITE, rc); > } > > if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) { > - rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, MAY_READ, &ad); > rc = smk_bu_file(file, MAY_READ, rc); > } > > @@ -1600,11 +1696,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd) > { > struct smk_audit_info ad; > int rc; > + struct user_namespace *ns = ns_of_current(); > struct inode *inode = file_inode(file); > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); > smk_ad_setfield_u_fs_path(&ad, file->f_path); > - rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, MAY_LOCK, &ad); > rc = smk_bu_file(file, MAY_LOCK, rc); > return rc; > } > @@ -1626,6 +1723,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, > { > struct smk_audit_info ad; > int rc = 0; > + struct user_namespace *ns = ns_of_current(); > struct inode *inode = file_inode(file); > > switch (cmd) { > @@ -1635,14 +1733,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, > case F_SETLKW: > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); > smk_ad_setfield_u_fs_path(&ad, file->f_path); > - rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, MAY_LOCK, &ad); > rc = smk_bu_file(file, MAY_LOCK, rc); > break; > case F_SETOWN: > case F_SETSIG: > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); > smk_ad_setfield_u_fs_path(&ad, file->f_path); > - rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, MAY_WRITE, &ad); > rc = smk_bu_file(file, MAY_WRITE, rc); > break; > default: > @@ -1672,6 +1770,7 @@ static int smack_mmap_file(struct file *file, > struct task_smack *tsp; > struct smack_known *okp; > struct inode_smack *isp; > + struct user_namespace *sns; > int may; > int mmay; > int tmay; > @@ -1682,12 +1781,16 @@ static int smack_mmap_file(struct file *file, > > tsp = current_security(); > skp = smk_of_task(tsp); > + sns = ns_of_current(); > isp = file_inode(file)->i_security; > mkp = isp->smk_mmap; > > if (mkp == NULL) > return 0; > > + if (!smk_labels_valid(skp, mkp, sns)) > + return -EACCES; > + > rc = 0; > > rcu_read_lock(); > @@ -1703,6 +1806,7 @@ static int smack_mmap_file(struct file *file, > */ > if (mkp->smk_known == okp->smk_known) > continue; > + > /* > * If there is a matching local rule take > * that into account as well. > @@ -1782,8 +1886,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, > struct fown_struct *fown, int signum) > { > struct smack_known *skp; > - struct smack_known *tkp = smk_of_task(tsk->cred->security); > + struct smack_known *tkp; > struct file *file; > + struct user_namespace *sns; > + struct user_namespace *tns; > int rc; > struct smk_audit_info ad; > > @@ -1791,12 +1897,17 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, > * struct fown_struct is never outside the context of a struct file > */ > file = container_of(fown, struct file, f_owner); > + skp = file->f_security; > + sns = file->f_cred->user_ns; > + > + tkp = smk_of_task_struct(tsk); > + tns = ns_of_task_struct(tsk); > > /* we don't log here as rc can be overriden */ > - skp = file->f_security; > - rc = smk_access(skp, tkp, MAY_WRITE, NULL); > + rc = smk_access(skp, tkp, sns, MAY_WRITE, NULL); > rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc); > - if (rc != 0 && smack_has_privilege(tsk, CAP_MAC_OVERRIDE)) > + if (rc != 0 && smk_labels_valid(skp, tkp, sns) > + && smack_has_ns_privilege(tsk, tns, CAP_MAC_OVERRIDE)) > rc = 0; > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); > @@ -1816,6 +1927,7 @@ static int smack_file_receive(struct file *file) > int rc; > int may = 0; > struct smk_audit_info ad; > + struct user_namespace *ns = ns_of_current(); > struct inode *inode = file_inode(file); > > if (unlikely(IS_PRIVATE(inode))) > @@ -1831,7 +1943,7 @@ static int smack_file_receive(struct file *file) > if (file->f_mode & FMODE_WRITE) > may |= MAY_WRITE; > > - rc = smk_curacc(smk_of_inode(inode), may, &ad); > + rc = smk_curacc(smk_of_inode(inode), ns, may, &ad); > rc = smk_bu_file(file, may, rc); > return rc; > } > @@ -1851,16 +1963,19 @@ static int smack_file_receive(struct file *file) > static int smack_file_open(struct file *file, const struct cred *cred) > { > struct task_smack *tsp = cred->security; > + struct user_namespace *ns = cred->user_ns; > struct inode *inode = file_inode(file); > + struct inode_smack *isp = file_inode(file)->i_security; > struct smk_audit_info ad; > int rc; > > - if (smack_privileged(CAP_MAC_OVERRIDE)) > + if (smk_labels_valid(tsp->smk_task, isp->smk_inode, ns) && > + smack_ns_privileged(ns, CAP_MAC_OVERRIDE)) > return 0; > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); > smk_ad_setfield_u_fs_path(&ad, file->f_path); > - rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad); > + rc = smk_access(tsp->smk_task, smk_of_inode(inode), ns, MAY_READ, &ad); > rc = smk_bu_credfile(cred, file, MAY_READ, rc); > > return rc; > @@ -2015,12 +2130,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access, > const char *caller) > { > struct smk_audit_info ad; > - struct smack_known *skp = smk_of_task_struct(p); > + struct smack_known *tkp = smk_of_task_struct(p); > + struct user_namespace *tns = ns_of_task_struct(p); > int rc; > > smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); > smk_ad_setfield_u_tsk(&ad, p); > - rc = smk_curacc(skp, access, &ad); > + rc = smk_curacc(tkp, tns, access, &ad); > rc = smk_bu_task(p, access, rc); > return rc; > } > @@ -2161,6 +2277,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, > struct smk_audit_info ad; > struct smack_known *skp; > struct smack_known *tkp = smk_of_task_struct(p); > + struct user_namespace *tns = ns_of_task_struct(p); > int rc; > > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); > @@ -2170,7 +2287,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, > * can write the receiver. > */ > if (secid == 0) { > - rc = smk_curacc(tkp, MAY_WRITE, &ad); > + rc = smk_curacc(tkp, tns, MAY_WRITE, &ad); > rc = smk_bu_task(p, MAY_WRITE, rc); > return rc; > } > @@ -2180,8 +2297,9 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, > * we can't take privilege into account. > */ > skp = smack_from_secid(secid); > - rc = smk_access(skp, tkp, MAY_WRITE, &ad); > + rc = smk_access(skp, tkp, tns, MAY_WRITE, &ad); > rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc); > + > return rc; > } > > @@ -2236,6 +2354,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) > static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) > { > struct smack_known *skp = smk_of_current(); > + struct user_namespace *ns = ns_of_current(); > struct socket_smack *ssp; > > ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); > @@ -2245,6 +2364,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) > ssp->smk_in = skp; > ssp->smk_out = skp; > ssp->smk_packet = NULL; > + ssp->smk_ns = get_user_ns(ns); > > sk->sk_security = ssp; > > @@ -2259,7 +2379,11 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) > */ > static void smack_sk_free_security(struct sock *sk) > { > + struct socket_smack *ssp = sk->sk_security; > + > + put_user_ns(ssp->smk_ns); > kfree(sk->sk_security); > + sk->sk_security = NULL; > } > > /** > @@ -2420,6 +2544,7 @@ static int smack_netlabel(struct sock *sk, int labeled) > static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) > { > struct smack_known *skp; > + struct user_namespace *sns; > int rc; > int sk_lbl; > struct smack_known *hkp; > @@ -2439,7 +2564,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) > #endif > sk_lbl = SMACK_UNLABELED_SOCKET; > skp = ssp->smk_out; > - rc = smk_access(skp, hkp, MAY_WRITE, &ad); > + sns = ssp->smk_ns; > + rc = smk_access(skp, hkp, sns, MAY_WRITE, &ad); > rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc); > } else { > sk_lbl = SMACK_CIPSO_SOCKET; > @@ -2464,6 +2590,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) > */ > static int smk_ipv6_check(struct smack_known *subject, > struct smack_known *object, > + struct user_namespace *ns, > struct sockaddr_in6 *address, int act) > { > #ifdef CONFIG_AUDIT > @@ -2481,7 +2608,7 @@ static int smk_ipv6_check(struct smack_known *subject, > else > ad.a.u.net->v6info.daddr = address->sin6_addr; > #endif > - rc = smk_access(subject, object, MAY_WRITE, &ad); > + rc = smk_access(subject, object, ns, MAY_WRITE, &ad); > rc = smk_bu_note("IPv6 check", subject, object, MAY_WRITE, rc); > return rc; > } > @@ -2574,6 +2701,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, > struct smk_port_label *spp; > struct socket_smack *ssp = sk->sk_security; > struct smack_known *skp = NULL; > + struct user_namespace *sns = ssp->smk_ns; > unsigned short port; > struct smack_known *object; > > @@ -2617,7 +2745,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, > break; > } > > - return smk_ipv6_check(skp, object, address, act); > + return smk_ipv6_check(skp, object, sns, address, act); > } > #endif /* SMACK_IPV6_PORT_LABELING */ > > @@ -2640,12 +2768,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, > struct inode_smack *nsp = inode->i_security; > struct socket_smack *ssp; > struct socket *sock; > + struct user_namespace *ns = ns_of_current(); > int rc = 0; > > if (value == NULL || size > SMK_LONGLABEL || size == 0) > return -EINVAL; > > - skp = smk_get_label(value, size, true); > + skp = smk_get_label(value, size, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > > @@ -2765,6 +2894,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, > #ifdef SMACK_IPV6_SECMARK_LABELING > struct smack_known *rsp; > struct socket_smack *ssp = sock->sk->sk_security; > + struct user_namespace *sns = ssp->smk_ns; > #endif > > if (sock->sk == NULL) > @@ -2782,7 +2912,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, > #ifdef SMACK_IPV6_SECMARK_LABELING > rsp = smack_ipv6host_label(sip); > if (rsp != NULL) > - rc = smk_ipv6_check(ssp->smk_out, rsp, sip, > + rc = smk_ipv6_check(ssp->smk_out, rsp, sns, sip, > SMK_CONNECTING); > #endif > #ifdef SMACK_IPV6_PORT_LABELING > @@ -2839,14 +2969,14 @@ static void smack_msg_msg_free_security(struct msg_msg *msg) > } > > /** > - * smack_of_shm - the smack pointer for the shm > + * security_of_shm - the smack pointer for the shm > * @shp: the object > * > - * Returns a pointer to the smack value > + * Returns a pointer to the security_smack struct > */ > -static struct smack_known *smack_of_shm(struct shmid_kernel *shp) > +static struct ipc_smack *security_of_shm(struct shmid_kernel *shp) > { > - return (struct smack_known *)shp->shm_perm.security; > + return (struct ipc_smack *)shp->shm_perm.security; > } > > /** > @@ -2858,9 +2988,16 @@ static struct smack_known *smack_of_shm(struct shmid_kernel *shp) > static int smack_shm_alloc_security(struct shmid_kernel *shp) > { > struct kern_ipc_perm *isp = &shp->shm_perm; > - struct smack_known *skp = smk_of_current(); > + struct ipc_smack *ssp; > + > + ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL); > + if (ssp == NULL) > + return -ENOMEM; > + > + ssp->smk_known = smk_of_current(); > + ssp->smk_ns = get_user_ns(ns_of_current()); > > - isp->security = skp; > + isp->security = ssp; > return 0; > } > > @@ -2873,7 +3010,10 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp) > static void smack_shm_free_security(struct shmid_kernel *shp) > { > struct kern_ipc_perm *isp = &shp->shm_perm; > + struct ipc_smack *ssp = isp->security; > > + put_user_ns(ssp->smk_ns); > + kfree(isp->security); > isp->security = NULL; > } > > @@ -2886,7 +3026,7 @@ static void smack_shm_free_security(struct shmid_kernel *shp) > */ > static int smk_curacc_shm(struct shmid_kernel *shp, int access) > { > - struct smack_known *ssp = smack_of_shm(shp); > + struct ipc_smack *ssp = security_of_shm(shp); > struct smk_audit_info ad; > int rc; > > @@ -2894,8 +3034,8 @@ static int smk_curacc_shm(struct shmid_kernel *shp, int access) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); > ad.a.u.ipc_id = shp->shm_perm.id; > #endif > - rc = smk_curacc(ssp, access, &ad); > - rc = smk_bu_current("shm", ssp, access, rc); > + rc = smk_curacc(ssp->smk_known, ssp->smk_ns, access, &ad); > + rc = smk_bu_current("shm", ssp->smk_known, access, rc); > return rc; > } > > @@ -2966,14 +3106,14 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, > } > > /** > - * smack_of_sem - the smack pointer for the sem > + * security_of_sem - the smack pointer for the sem > * @sma: the object > * > - * Returns a pointer to the smack value > + * Returns a pointer to the ipc_smack struct > */ > -static struct smack_known *smack_of_sem(struct sem_array *sma) > +static struct ipc_smack *security_of_sem(struct sem_array *sma) > { > - return (struct smack_known *)sma->sem_perm.security; > + return (struct ipc_smack *)sma->sem_perm.security; > } > > /** > @@ -2985,9 +3125,16 @@ static struct smack_known *smack_of_sem(struct sem_array *sma) > static int smack_sem_alloc_security(struct sem_array *sma) > { > struct kern_ipc_perm *isp = &sma->sem_perm; > - struct smack_known *skp = smk_of_current(); > + struct ipc_smack *ssp; > + > + ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL); > + if (ssp == NULL) > + return -ENOMEM; > + > + ssp->smk_known = smk_of_current(); > + ssp->smk_ns = get_user_ns(ns_of_current()); > > - isp->security = skp; > + isp->security = ssp; > return 0; > } > > @@ -3000,7 +3147,10 @@ static int smack_sem_alloc_security(struct sem_array *sma) > static void smack_sem_free_security(struct sem_array *sma) > { > struct kern_ipc_perm *isp = &sma->sem_perm; > + struct ipc_smack *ssp = isp->security; > > + put_user_ns(ssp->smk_ns); > + kfree(isp->security); > isp->security = NULL; > } > > @@ -3013,7 +3163,7 @@ static void smack_sem_free_security(struct sem_array *sma) > */ > static int smk_curacc_sem(struct sem_array *sma, int access) > { > - struct smack_known *ssp = smack_of_sem(sma); > + struct ipc_smack *ssp = security_of_sem(sma); > struct smk_audit_info ad; > int rc; > > @@ -3021,8 +3171,8 @@ static int smk_curacc_sem(struct sem_array *sma, int access) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); > ad.a.u.ipc_id = sma->sem_perm.id; > #endif > - rc = smk_curacc(ssp, access, &ad); > - rc = smk_bu_current("sem", ssp, access, rc); > + rc = smk_curacc(ssp->smk_known, ssp->smk_ns, access, &ad); > + rc = smk_bu_current("sem", ssp->smk_known, access, rc); > return rc; > } > > @@ -3107,9 +3257,16 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, > static int smack_msg_queue_alloc_security(struct msg_queue *msq) > { > struct kern_ipc_perm *kisp = &msq->q_perm; > - struct smack_known *skp = smk_of_current(); > + struct ipc_smack *ssp; > + > + ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL); > + if (ssp == NULL) > + return -ENOMEM; > > - kisp->security = skp; > + ssp->smk_known = smk_of_current(); > + ssp->smk_ns = get_user_ns(ns_of_current()); > + > + kisp->security = ssp; > return 0; > } > > @@ -3122,19 +3279,22 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq) > static void smack_msg_queue_free_security(struct msg_queue *msq) > { > struct kern_ipc_perm *kisp = &msq->q_perm; > + struct ipc_smack *ssp = kisp->security; > > + put_user_ns(ssp->smk_ns); > + kfree(kisp->security); > kisp->security = NULL; > } > > /** > - * smack_of_msq - the smack pointer for the msq > + * security_of_msq - the smack pointer for the msq > * @msq: the object > * > - * Returns a pointer to the smack label entry > + * Returns a pointer to the ipc_smack struct > */ > -static struct smack_known *smack_of_msq(struct msg_queue *msq) > +static struct ipc_smack *security_of_msq(struct msg_queue *msq) > { > - return (struct smack_known *)msq->q_perm.security; > + return (struct ipc_smack *)msq->q_perm.security; > } > > /** > @@ -3146,7 +3306,7 @@ static struct smack_known *smack_of_msq(struct msg_queue *msq) > */ > static int smk_curacc_msq(struct msg_queue *msq, int access) > { > - struct smack_known *msp = smack_of_msq(msq); > + struct ipc_smack *msp = security_of_msq(msq); > struct smk_audit_info ad; > int rc; > > @@ -3154,8 +3314,8 @@ static int smk_curacc_msq(struct msg_queue *msq, int access) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); > ad.a.u.ipc_id = msq->q_perm.id; > #endif > - rc = smk_curacc(msp, access, &ad); > - rc = smk_bu_current("msq", msp, access, rc); > + rc = smk_curacc(msp->smk_known, msp->smk_ns, access, &ad); > + rc = smk_bu_current("msq", msp->smk_known, access, rc); > return rc; > } > > @@ -3249,7 +3409,7 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, > */ > static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) > { > - struct smack_known *iskp = ipp->security; > + struct ipc_smack *isp = ipp->security; > int may = smack_flags_to_may(flag); > struct smk_audit_info ad; > int rc; > @@ -3258,8 +3418,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) > smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); > ad.a.u.ipc_id = ipp->id; > #endif > - rc = smk_curacc(iskp, may, &ad); > - rc = smk_bu_current("svipc", iskp, may, rc); > + rc = smk_curacc(isp->smk_known, isp->smk_ns, may, &ad); > + rc = smk_bu_current("svipc", isp->smk_known, may, rc); > return rc; > } > > @@ -3270,9 +3430,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) > */ > static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) > { > - struct smack_known *iskp = ipp->security; > + struct ipc_smack *iskp = ipp->security; > > - *secid = iskp->smk_secid; > + *secid = iskp->smk_known->smk_secid; > } > > /** > @@ -3530,13 +3690,14 @@ int smack_getprocattr_seq(struct task_struct *p, const char *name, > static int smack_getprocattr(struct task_struct *p, char *name, char **value) > { > struct smack_known *skp = smk_of_task_struct(p); > + struct user_namespace *ns = ns_of_current(); > char *cp; > int slen; > > if (strcmp(name, "current") != 0) > return -EINVAL; > > - cp = smk_find_label_name(skp); > + cp = smk_find_label_name(skp, ns); > if (cp == NULL) > cp = smack_known_huh.smk_known; > cp = kstrdup(cp, GFP_KERNEL); > @@ -3564,6 +3725,7 @@ static int proc_current_write(struct task_struct *p, void *value, size_t size) > struct task_smack *tsp; > struct cred *new; > struct smack_known *skp; > + struct user_namespace *ns; > > /* > * Changing another process' Smack value is too dangerous > @@ -3572,13 +3734,15 @@ static int proc_current_write(struct task_struct *p, void *value, size_t size) > if (p != current) > return -EPERM; > > - if (!smack_privileged(CAP_MAC_ADMIN)) > + ns = ns_of_current(); > + > + if (!smack_ns_privileged(ns, CAP_MAC_ADMIN)) > return -EPERM; > > if (value == NULL || size == 0 || size >= SMK_LONGLABEL) > return -EINVAL; > > - skp = smk_get_label(value, size, true); > + skp = smk_get_label(value, size, true, ns); > if (IS_ERR(skp)) > return PTR_ERR(skp); > > @@ -3645,23 +3809,27 @@ static int smack_unix_stream_connect(struct sock *sock, > struct smack_known *okp_out = osp->smk_out; > struct smack_known *skp_in = ssp->smk_in; > struct smack_known *okp_in = osp->smk_in; > + struct user_namespace *sns = ssp->smk_ns; > + struct user_namespace *ons = osp->smk_ns; > struct smk_audit_info ad; > int rc = 0; > #ifdef CONFIG_AUDIT > struct lsm_network_audit net; > #endif > > - if (!smack_privileged(CAP_MAC_OVERRIDE)) { > + if (!smack_ns_privileged(ons, CAP_MAC_OVERRIDE) || > + !smk_labels_valid(skp_out, okp_in, sns) || > + !smk_labels_valid(okp_out, skp_in, ons)) { > #ifdef CONFIG_AUDIT > smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); > smk_ad_setfield_u_net_sk(&ad, other); > #endif > - rc = smk_access(skp_out, okp_in, MAY_WRITE, &ad); > + rc = smk_access(skp_out, okp_in, sns, MAY_WRITE, &ad); > rc = smk_bu_note("UDS connect", skp_out, okp_in, MAY_WRITE, rc); > if (rc == 0) { > - rc = smk_access(okp_out, skp_in, MAY_WRITE, &ad); > + rc = smk_access(okp_out, skp_in, ons, MAY_WRITE, &ad); > rc = smk_bu_note("UDS connect", okp_out, skp_in, > - MAY_WRITE, rc); > + MAY_WRITE, rc); > } > } > > @@ -3688,6 +3856,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) > { > struct socket_smack *ssp = sock->sk->sk_security; > struct socket_smack *osp = other->sk->sk_security; > + struct user_namespace *sns = ssp->smk_ns; > + struct user_namespace *ons = osp->smk_ns; > struct smk_audit_info ad; > int rc; > > @@ -3698,10 +3868,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) > smk_ad_setfield_u_net_sk(&ad, other->sk); > #endif > > - if (smack_privileged(CAP_MAC_OVERRIDE)) > + if (smk_labels_valid(ssp->smk_out, osp->smk_in, sns) && > + smack_ns_privileged(ons, CAP_MAC_OVERRIDE)) > return 0; > > - rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); > + rc = smk_access(ssp->smk_out, osp->smk_in, sns, MAY_WRITE, &ad); > rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc); > return rc; > } > @@ -3724,8 +3895,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, > struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; > #endif > #ifdef SMACK_IPV6_SECMARK_LABELING > - struct socket_smack *ssp = sock->sk->sk_security; > struct smack_known *rsp; > + struct socket_smack *ssp = sock->sk->sk_security; > + struct user_namespace *sns = ssp->smk_ns; > #endif > int rc = 0; > > @@ -3743,7 +3915,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, > #ifdef SMACK_IPV6_SECMARK_LABELING > rsp = smack_ipv6host_label(sap); > if (rsp != NULL) > - rc = smk_ipv6_check(ssp->smk_out, rsp, sap, > + rc = smk_ipv6_check(ssp->smk_out, rsp, sns, sap, > SMK_CONNECTING); > #endif > #ifdef SMACK_IPV6_PORT_LABELING > @@ -3951,7 +4123,7 @@ access_check: > * This is the simplist possible security model > * for networking. > */ > - rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); > + rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad); > rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in, > MAY_WRITE, rc); > if (rc != 0) > @@ -3975,7 +4147,7 @@ access_check: > ad.a.u.net->netif = skb->skb_iif; > ipv6_skb_to_auditdata(skb, &ad.a, NULL); > #endif /* CONFIG_AUDIT */ > - rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); > + rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad); > rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, > MAY_WRITE, rc); > #endif /* SMACK_IPV6_SECMARK_LABELING */ > @@ -4187,7 +4359,7 @@ access_check: > * Receiving a packet requires that the other end be able to write > * here. Read access is not required. > */ > - rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); > + rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad); > rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc); > if (rc != 0) > return rc; > @@ -4291,6 +4463,7 @@ static int smack_key_permission(key_ref_t key_ref, > struct key *keyp; > struct smk_audit_info ad; > struct smack_known *tkp = smk_of_task(cred->security); > + struct user_namespace *tns = cred->user_ns; > int request = 0; > int rc; > > @@ -4317,7 +4490,7 @@ static int smack_key_permission(key_ref_t key_ref, > request = MAY_READ; > if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) > request = MAY_WRITE; > - rc = smk_access(tkp, keyp->security, request, &ad); > + rc = smk_access(tkp, keyp->security, tns, request, &ad); > rc = smk_bu_note("key access", tkp, keyp->security, request, rc); > return rc; > } > @@ -4334,6 +4507,7 @@ static int smack_key_permission(key_ref_t key_ref, > static int smack_key_getsecurity(struct key *key, char **_buffer) > { > struct smack_known *skp = key->security; > + struct user_namespace *ns = ns_of_current(); > size_t length; > char *copy; > > @@ -4342,7 +4516,7 @@ static int smack_key_getsecurity(struct key *key, char **_buffer) > return 0; > } > > - copy = smk_find_label_name(skp); > + copy = smk_find_label_name(skp, ns); > if (copy == NULL) > copy = smack_known_huh.smk_known; > copy = kstrdup(copy, GFP_KERNEL); > @@ -4520,6 +4694,11 @@ static inline void smack_userns_free(struct user_namespace *ns) > static inline int smack_userns_setns(struct nsproxy *nsproxy, > struct user_namespace *ns) > { > + struct smack_known *skp = smk_of_current(); > + > + if (smk_find_mapped(skp, ns) == NULL) > + return -EACCES; > + > return 0; > } > > @@ -4632,6 +4811,7 @@ static struct security_hook_list smack_hooks[] = { > LSM_HOOK_INIT(inode_setattr, smack_inode_setattr), > LSM_HOOK_INIT(inode_getattr, smack_inode_getattr), > LSM_HOOK_INIT(inode_setxattr, smack_inode_setxattr), > + LSM_HOOK_INIT(inode_pre_setxattr, smack_inode_pre_setxattr), > LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr), > LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr), > LSM_HOOK_INIT(inode_removexattr, smack_inode_removexattr), > diff --git a/security/smack/smack_ns.c b/security/smack/smack_ns.c > index 49223c4..dc2a666 100644 > --- a/security/smack/smack_ns.c > +++ b/security/smack/smack_ns.c > @@ -206,6 +206,45 @@ unlockout: > return sknp; > } > > +/** > + * smk_labels_valid - A helper to check whether labels are valid/mapped > + * in the namespace and can be used there > + * @sbj: a subject label to be checked > + * @obj: an object label to be checked > + * @ns: user namespace to check against (usually subject's) > + * > + * Returns true if both valid/mapped, false otherwise. > + * This helper is mostly used while checking capabilities. > + * The access functions check the validity of labels by themselves. > + */ > +bool smk_labels_valid(struct smack_known *sbj, struct smack_known *obj, > + struct user_namespace *ns) > +{ > + struct user_namespace *user_ns; > + > + /* > + * labels are always valid if there is no map > + * (init_user_ns or unmapped descendants) > + */ > + user_ns = smk_find_mapped_ns(ns); > + if (user_ns == NULL) > + return true; > + > + /* > + * If we have a map though, both labels need to be mapped. > + */ > + if (__smk_find_mapped(sbj, user_ns) == NULL) > + return false; > + if (__smk_find_mapped(obj, user_ns) == NULL) > + return false; > + > + return true; > +} > + > +/* > + * proc mapping operations > + */ > + > static void *proc_label_map_seq_start(struct seq_file *seq, loff_t *pos) > { > struct smack_known *skp; > diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c > index 3149ec0..fe4ad24 100644 > --- a/security/smack/smackfs.c > +++ b/security/smack/smackfs.c > @@ -340,13 +340,15 @@ static int smk_fill_rule(const char *subject, const char *object, > struct smack_parsed_rule *rule, int import, > int len) > { > - rule->smk_subject = smk_get_label(subject, len, import); > + struct user_namespace *ns = ns_of_current(); > + > + rule->smk_subject = smk_get_label(subject, len, import, ns); > if (IS_ERR(rule->smk_subject)) > return PTR_ERR(rule->smk_subject); > if (rule->smk_subject == NULL) > return -ENOENT; > > - rule->smk_object = smk_get_label(object, len, import); > + rule->smk_object = smk_get_label(object, len, import, ns); > if (IS_ERR(rule->smk_object)) > return PTR_ERR(rule->smk_object); > if (rule->smk_object == NULL) > @@ -573,6 +575,7 @@ static void smk_seq_stop(struct seq_file *s, void *v) > > static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) > { > + struct user_namespace *ns = ns_of_current(); > char *sbj; > char *obj; > > @@ -581,6 +584,7 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) > * interface file (/smack/load or /smack/load2) > * because you should expect to be able to write > * anything you read back. > + * Show only fully mapped rules in a namespace (both labels mapped). > */ > if (strlen(srp->smk_subject->smk_known) >= max || > strlen(srp->smk_object->smk_known) >= max) > @@ -589,8 +593,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) > if (srp->smk_access == 0) > return; > > - sbj = smk_find_label_name(srp->smk_subject); > - obj = smk_find_label_name(srp->smk_object); > + sbj = smk_find_label_name(srp->smk_subject, ns); > + obj = smk_find_label_name(srp->smk_object, ns); > > if (sbj == NULL || obj == NULL) > return; > @@ -785,6 +789,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) > struct smack_known *skp = > list_entry_rcu(list, struct smack_known, list); > struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; > + struct user_namespace *ns = ns_of_current(); > char sep = '/'; > char *cp; > int i; > @@ -800,7 +805,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) > if (strlen(skp->smk_known) >= SMK_LABELLEN) > return 0; > > - cp = smk_find_label_name(skp); > + cp = smk_find_label_name(skp, ns); > if (cp == NULL) > return 0; > > @@ -853,6 +858,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, > { > struct smack_known *skp; > struct netlbl_lsm_secattr ncats; > + struct user_namespace *ns = ns_of_current(); > char mapcatset[SMK_CIPSOLEN]; > int maplevel; > unsigned int cat; > @@ -893,7 +899,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, > */ > mutex_lock(&smack_cipso_lock); > > - skp = smk_get_label(rule, 0, true); > + skp = smk_get_label(rule, 0, true, ns); > if (IS_ERR(skp)) { > rc = PTR_ERR(skp); > goto out; > @@ -981,11 +987,12 @@ static int cipso2_seq_show(struct seq_file *s, void *v) > struct smack_known *skp = > list_entry_rcu(list, struct smack_known, list); > struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; > + struct user_namespace *ns = ns_of_current(); > char sep = '/'; > char *cp; > int i; > > - cp = smk_find_label_name(skp); > + cp = smk_find_label_name(skp, ns); > if (cp == NULL) > return 0; > > @@ -1066,12 +1073,13 @@ static void *net4addr_seq_next(struct seq_file *s, void *v, loff_t *pos) > static int net4addr_seq_show(struct seq_file *s, void *v) > { > struct list_head *list = v; > + struct user_namespace *ns = ns_of_current(); > struct smk_net4addr *skp = > list_entry_rcu(list, struct smk_net4addr, list); > char *kp = SMACK_CIPSO_OPTION; > > if (skp->smk_label != NULL) { > - kp = smk_find_label_name(skp->smk_label); > + kp = smk_find_label_name(skp->smk_label, ns); > if (kp == NULL) > kp = smack_known_huh.smk_known; > } > @@ -1167,6 +1175,7 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, > int rc; > struct netlbl_audit audit_info; > struct in_addr mask; > + struct user_namespace *ns = ns_of_current(); > unsigned int m; > unsigned int masks; > int found; > @@ -1226,7 +1235,7 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, > * If smack begins with '-', it is an option, don't import it > */ > if (smack[0] != '-') { > - skp = smk_get_label(smack, 0, true); > + skp = smk_get_label(smack, 0, true, ns); > if (IS_ERR(skp)) { > rc = PTR_ERR(skp); > goto free_out; > @@ -1345,10 +1354,11 @@ static int net6addr_seq_show(struct seq_file *s, void *v) > struct list_head *list = v; > struct smk_net6addr *skp = > list_entry(list, struct smk_net6addr, list); > + struct user_namespace *ns = ns_of_current(); > char *kp; > > if (skp->smk_label != NULL) { > - kp = smk_find_label_name(skp->smk_label); > + kp = smk_find_label_name(skp->smk_label, ns); > if (kp == NULL) > kp = smack_known_huh.smk_known; > > @@ -1438,6 +1448,7 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, > struct in6_addr newname; > struct in6_addr fullmask; > struct smack_known *skp = NULL; > + struct user_namespace *ns = ns_of_current(); > char *smack; > char *data; > int rc = 0; > @@ -1508,7 +1519,7 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, > * If smack begins with '-', it is an option, don't import it > */ > if (smack[0] != '-') { > - skp = smk_get_label(smack, 0, true); > + skp = smk_get_label(smack, 0, true, ns); > if (IS_ERR(skp)) { > rc = PTR_ERR(skp); > goto free_out; > @@ -1827,6 +1838,7 @@ static const struct file_operations smk_mapped_ops = { > static ssize_t smk_read_ambient(struct file *filp, char __user *buf, > size_t cn, loff_t *ppos) > { > + struct user_namespace *ns = ns_of_current(); > ssize_t rc = -EINVAL; > char *cp; > int asize; > @@ -1839,7 +1851,7 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, > */ > mutex_lock(&smack_ambient_lock); > > - cp = smk_find_label_name(smack_net_ambient); > + cp = smk_find_label_name(smack_net_ambient, ns); > if (cp == NULL) > cp = smack_known_huh.smk_known; > > @@ -1866,6 +1878,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, > size_t count, loff_t *ppos) > { > struct smack_known *skp; > + struct user_namespace *ns = ns_of_current(); > char *oldambient; > char *data; > int rc = count; > @@ -1882,7 +1895,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, > goto out; > } > > - skp = smk_get_label(data, count, true); > + skp = smk_get_label(data, count, true, ns); > if (IS_ERR(skp)) { > rc = PTR_ERR(skp); > goto out; > @@ -1923,11 +1936,12 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos) > static int onlycap_seq_show(struct seq_file *s, void *v) > { > char *smack; > + struct user_namespace *ns = ns_of_current(); > struct list_head *list = v; > struct smack_onlycap *sop = > list_entry_rcu(list, struct smack_onlycap, list); > > - smack = smk_find_label_name(sop->smk_label); > + smack = smk_find_label_name(sop->smk_label, ns); > if (smack == NULL) > smack = smack_known_huh.smk_known; > > @@ -2006,6 +2020,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, > struct smack_onlycap *sop; > struct smack_onlycap *sop2; > LIST_HEAD(list_tmp); > + struct user_namespace *ns = ns_of_current(); > int rc = count; > > if (!smack_privileged(CAP_MAC_ADMIN)) > @@ -2025,7 +2040,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, > if (!*tok) > continue; > > - skp = smk_get_label(tok, 0, true); > + skp = smk_get_label(tok, 0, true, ns); > if (IS_ERR(skp)) { > rc = PTR_ERR(skp); > break; > @@ -2091,12 +2106,13 @@ static ssize_t smk_read_unconfined(struct file *filp, char __user *buf, > char *smack = ""; > ssize_t rc = -EINVAL; > int asize; > + struct user_namespace *ns = ns_of_current(); > > if (*ppos != 0) > return 0; > > if (smack_unconfined != NULL) { > - smack = smk_find_label_name(smack_unconfined); > + smack = smk_find_label_name(smack_unconfined, ns); > if (smack == NULL) > smack = smack_known_huh.smk_known; > } > @@ -2123,6 +2139,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf, > { > char *data; > struct smack_known *skp; > + struct user_namespace *ns = ns_of_current(); > int rc = count; > > if (!smack_privileged(CAP_MAC_ADMIN)) > @@ -2146,7 +2163,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf, > * > * But do so only on invalid label, not on system errors. > */ > - skp = smk_get_label(data, count, true); > + skp = smk_get_label(data, count, true, ns); > if (PTR_ERR(skp) == -EINVAL) > skp = NULL; > else if (IS_ERR(skp)) { > @@ -2318,6 +2335,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, > size_t count, loff_t *ppos, int format) > { > struct smack_parsed_rule rule; > + struct user_namespace *ns = ns_of_current(); > char *data; > int res; > > @@ -2337,7 +2355,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, > } > > if (res >= 0) > - res = smk_access(rule.smk_subject, rule.smk_object, > + res = smk_access(rule.smk_subject, rule.smk_object, ns, > rule.smk_access1, NULL); > else if (res != -ENOENT) > return res; > @@ -2547,6 +2565,7 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, > struct smack_rule *sp; > struct list_head *rule_list; > struct mutex *rule_lock; > + struct user_namespace *ns = ns_of_current(); > int rc = count; > > if (*ppos != 0) > @@ -2567,7 +2586,7 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, > goto out_data; > } > > - skp = smk_get_label(data, count, false); > + skp = smk_get_label(data, count, false, ns); > if (IS_ERR(skp)) { > rc = PTR_ERR(skp); > goto out_data; > @@ -2649,12 +2668,13 @@ static ssize_t smk_read_syslog(struct file *filp, char __user *buf, > char *smack = ""; > ssize_t rc = -EINVAL; > int asize; > + struct user_namespace *ns = ns_of_current(); > > if (*ppos != 0) > return 0; > > if (smack_syslog_label != NULL) { > - smack = smk_find_label_name(smack_syslog_label); > + smack = smk_find_label_name(smack_syslog_label, ns); > if (smack == NULL) > smack = smack_known_huh.smk_known; > } > @@ -2681,6 +2701,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf, > { > char *data; > struct smack_known *skp; > + struct user_namespace *ns = ns_of_current(); > int rc = count; > > if (!smack_privileged(CAP_MAC_ADMIN)) > @@ -2704,7 +2725,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf, > * > * But do so only on invalid label, not on system errors. > */ > - skp = smk_get_label(data, count, true); > + skp = smk_get_label(data, count, true, ns); > if (PTR_ERR(skp) == -EINVAL) > skp = NULL; > else if (IS_ERR(skp)) { -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/security/smack/smack.h b/security/smack/smack.h index 4b7489f..3d432f4 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -119,6 +119,7 @@ struct superblock_smack { struct smack_known *smk_floor; struct smack_known *smk_hat; struct smack_known *smk_default; + struct user_namespace *smk_ns; int smk_initialized; }; @@ -126,6 +127,7 @@ struct socket_smack { struct smack_known *smk_out; /* outbound label */ struct smack_known *smk_in; /* inbound label */ struct smack_known *smk_packet; /* TCP peer label */ + struct user_namespace *smk_ns; /* user namespace */ }; /* @@ -146,6 +148,14 @@ struct task_smack { struct mutex smk_rules_lock; /* lock for the rules */ }; +/* + * Used for IPC objects (sem, shm, etc) + */ +struct ipc_smack { + struct smack_known *smk_known; /* label for access control */ + struct user_namespace *smk_ns; /* user namespace */ +}; + #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ #define SMK_INODE_CHANGED 0x04 /* smack was transmuted */ @@ -319,10 +329,11 @@ struct smk_audit_info { */ int smk_access_entry(char *, char *, struct list_head *); int smk_access(struct smack_known *, struct smack_known *, - int, struct smk_audit_info *); + struct user_namespace *, int, struct smk_audit_info *); int smk_tskacc(struct task_struct *, struct smack_known *, + struct user_namespace *, u32, struct smk_audit_info *); +int smk_curacc(struct smack_known *, struct user_namespace *, u32, struct smk_audit_info *); -int smk_curacc(struct smack_known *, u32, struct smk_audit_info *); struct smack_known *smack_from_secid(const u32); char *smk_parse_smack(const char *string, int len, bool *allocated); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); @@ -335,8 +346,9 @@ int smack_has_ns_privilege(struct task_struct *task, int smack_has_privilege(struct task_struct *task, int cap); int smack_ns_privileged(struct user_namespace *user_ns, int cap); int smack_privileged(int cap); -char *smk_find_label_name(struct smack_known *skp); -struct smack_known *smk_get_label(const char *string, int len, bool import); +char *smk_find_label_name(struct smack_known *skp, struct user_namespace *ns); +struct smack_known *smk_get_label(const char *string, int len, bool import, + struct user_namespace *ns); /* * These functions are in smack_ns.c @@ -350,6 +362,15 @@ struct smack_known *smk_find_unmapped(const char *string, int len, extern const struct seq_operations proc_label_map_seq_operations; ssize_t proc_label_map_write(struct task_struct *p, const struct cred *f_cred, void *value, size_t size); +bool smk_labels_valid(struct smack_known *sbj, struct smack_known *obj, + struct user_namespace *ns); +#else +static inline bool smk_labels_valid(struct smack_known *sbj, + struct smack_known *obj, + struct user_namespace *ns) +{ + return true; +} #endif /* CONFIG_SECURITY_SMACK_NS */ /* diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 17b7e2c..e230948 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/fs.h> #include <linux/sched.h> +#include <linux/user_namespace.h> #include "smack.h" struct smack_known smack_known_huh = { @@ -113,6 +114,7 @@ int smk_access_entry(char *subject_label, char *object_label, * smk_access - determine if a subject has a specific access to an object * @subject: a pointer to the subject's Smack label entry * @object: a pointer to the object's Smack label entry + * @ns: user namespace to check against (usually subject's) * @request: the access requested, in "MAY" format * @a : a pointer to the audit data * @@ -123,10 +125,34 @@ int smk_access_entry(char *subject_label, char *object_label, * Smack labels are shared on smack_list */ int smk_access(struct smack_known *subject, struct smack_known *object, - int request, struct smk_audit_info *a) + struct user_namespace *ns, int request, struct smk_audit_info *a) { int may = MAY_NOT; int rc = 0; + char *subject_label = subject->smk_known; + char *object_label = object->smk_known; +#ifdef CONFIG_SECURITY_SMACK_NS + struct smack_known_ns *sknp; + struct smack_known_ns *oknp; + + /* + * For the namespaced case we need to check whether the labels + * are mapped. If not, refuse. If yes check the builtin rules + * on the mapped label strings so the builtin labels can + * work properly inside the namespace. + */ + if (smk_find_mapped_ns(ns)) { + sknp = smk_find_mapped(subject, ns); + oknp = smk_find_mapped(object, ns); + if (!sknp || !oknp) { + rc = -EACCES; + goto out_audit; + } + + subject_label = sknp->smk_mapped; + object_label = oknp->smk_mapped; + } +#endif /* * Hardcoded comparisons. @@ -134,7 +160,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object, /* * A star subject can't access any object. */ - if (subject == &smack_known_star) { + if (subject_label == smack_known_star.smk_known) { rc = -EACCES; goto out_audit; } @@ -143,18 +169,19 @@ int smk_access(struct smack_known *subject, struct smack_known *object, * Tasks cannot be assigned the internet label. * An internet subject can access any object. */ - if (object == &smack_known_web || subject == &smack_known_web) + if (object_label == smack_known_web.smk_known || + subject_label == smack_known_web.smk_known) goto out_audit; /* * A star object can be accessed by any subject. */ - if (object == &smack_known_star) + if (object_label == smack_known_star.smk_known) goto out_audit; /* * An object can be accessed in any way by a subject * with the same label. */ - if (subject->smk_known == object->smk_known) + if (subject_label == object_label) goto out_audit; /* * A hat subject can read or lock any object. @@ -162,9 +189,9 @@ int smk_access(struct smack_known *subject, struct smack_known *object, */ if ((request & MAY_ANYREAD) == request || (request & MAY_LOCK) == request) { - if (object == &smack_known_floor) + if (object_label == smack_known_floor.smk_known) goto out_audit; - if (subject == &smack_known_hat) + if (subject_label == smack_known_hat.smk_known) goto out_audit; } @@ -174,6 +201,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object, * access (e.g. read is included in readwrite) it's * good. A negative response from smk_access_entry() * indicates there is no entry for this pair. + * For this check we need real, not mapped labels. */ rcu_read_lock(); may = smk_access_entry(subject->smk_known, object->smk_known, @@ -219,6 +247,7 @@ out_audit: * smk_tskacc - determine if a task has a specific access to an object * @tsp: a pointer to the subject's task * @obj_known: a pointer to the object's label entry + * @obj_ns: an object's namespace to check the caps against * @mode: the access requested, in "MAY" format * @a : common audit data * @@ -228,16 +257,18 @@ out_audit: * to override the rules. */ int smk_tskacc(struct task_struct *task, struct smack_known *obj_known, - u32 mode, struct smk_audit_info *a) + struct user_namespace *obj_ns, u32 mode, + struct smk_audit_info *a) { struct smack_known *sbj_known = smk_of_task_struct(task); + struct user_namespace *sbj_ns = ns_of_task_struct(task); int may; int rc; /* * Check the global rule list */ - rc = smk_access(sbj_known, obj_known, mode, NULL); + rc = smk_access(sbj_known, obj_known, sbj_ns, mode, NULL); if (rc >= 0) { struct task_smack *tsp; @@ -261,8 +292,10 @@ int smk_tskacc(struct task_struct *task, struct smack_known *obj_known, /* * Allow for priviliged to override policy. + * Either in init_ns or when both labels are mapped. */ - if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE)) + if (rc != 0 && smk_labels_valid(sbj_known, obj_known, sbj_ns) + && smack_has_ns_privilege(task, obj_ns, CAP_MAC_OVERRIDE)) rc = 0; out_audit: @@ -277,6 +310,7 @@ out_audit: /** * smk_curacc - determine if current has a specific access to an object * @obj_known: a pointer to the object's Smack label entry + * @obj_ns: an object's namespace to check the caps against * @mode: the access requested, in "MAY" format * @a : common audit data * @@ -285,10 +319,10 @@ out_audit: * non zero otherwise. It allows that current may have the capability * to override the rules. */ -int smk_curacc(struct smack_known *obj_known, +int smk_curacc(struct smack_known *obj_known, struct user_namespace *obj_ns, u32 mode, struct smk_audit_info *a) { - return smk_tskacc(current, obj_known, mode, a); + return smk_tskacc(current, obj_known, obj_ns, mode, a); } #ifdef CONFIG_AUDIT @@ -671,12 +705,13 @@ DEFINE_MUTEX(smack_onlycap_lock); * * For a capability in smack related checks to be effective it needs to: * - be allowed to be privileged by the onlycap rule. - * - be in the initial user ns + * - be in the initial user ns or have a filled map in the child ns */ static int smack_capability_allowed(struct smack_known *skp, struct user_namespace *user_ns) { struct smack_onlycap *sop; + struct smack_ns *sns; /* * All kernel tasks are privileged @@ -684,8 +719,15 @@ static int smack_capability_allowed(struct smack_known *skp, if (unlikely(current->flags & PF_KTHREAD)) return 1; +#ifdef CONFIG_SECURITY_SMACK_NS + sns = user_ns->security; + + if (user_ns != &init_user_ns && list_empty(&sns->smk_mapped)) + return 0; +#else if (user_ns != &init_user_ns) return 0; +#endif /* CONFIG_SECURITY_SMACK_NS */ rcu_read_lock(); if (list_empty(&smack_onlycap_list)) { @@ -755,14 +797,32 @@ int smack_privileged(int cap) } /** - * smk_find_label_name - A helper to get a string value of a label + * smk_find_label_name - A helper to get a string value of either a label or a + * mapped label when inside a namespace * @skp: a label we want a string value from + * @ns: namespace against which we want to get the value * * Returns a pointer to a label name or NULL if label name not found. */ -char *smk_find_label_name(struct smack_known *skp) +char *smk_find_label_name(struct smack_known *skp, struct user_namespace *ns) { - return skp->smk_known; + char *name = NULL; + +#ifdef CONFIG_SECURITY_SMACK_NS + struct smack_known_ns *sknp; + + if (smk_find_mapped_ns(ns)) { + sknp = smk_find_mapped(skp, ns); + if (sknp != NULL) + name = sknp->smk_mapped; + } else { + name = skp->smk_known; + } +#else + name = skp->smk_known; +#endif + + return name; } /** @@ -771,17 +831,32 @@ char *smk_find_label_name(struct smack_known *skp) * @string: a name of a label we look for or want to import * @len: the string size, or zero if it is NULL terminated * @import: whether we should import the label if not found + * @ns: a namespace the looked for label should be in * * Returns a smack_known label that is either imported or found. * NULL if label not found (only when import == false). * Error code otherwise. */ -struct smack_known *smk_get_label(const char *string, int len, bool import) +struct smack_known *smk_get_label(const char *string, int len, bool import, + struct user_namespace *ns) { struct smack_known *skp; bool allocated; char *cp; +#ifdef CONFIG_SECURITY_SMACK_NS + if (smk_find_mapped_ns(ns)) { + skp = smk_find_unmapped(string, len, ns); + + /* Label not found but we can't import in namespaces */ + if (skp == NULL && import) + skp = ERR_PTR(-EBADR); + + /* will also return error codes from smk_find_unmapped() */ + return skp; + } +#endif + if (import) { skp = smk_import_entry(string, len); } else { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 206e0ce..8e0da67 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -383,6 +383,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) * smk_ptrace_rule_check - helper for ptrace access * @tracer: tracer process * @tracee_known: label entry of the process that's about to be traced + * @tracee_ns: a tracee's namespace to check the caps against * @mode: ptrace attachment mode (PTRACE_MODE_*) * @func: name of the function that called us, used for audit * @@ -390,6 +391,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode) */ static int smk_ptrace_rule_check(struct task_struct *tracer, struct smack_known *tracee_known, + struct user_namespace *tracee_ns, unsigned int mode, const char *func) { int rc; @@ -401,21 +403,28 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, saip = &ad; } - if ((mode & PTRACE_MODE_ATTACH) && (smack_ptrace_rule == SMACK_PTRACE_EXACT || smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) { struct smack_known *tracer_known = smk_of_task_struct(tracer); + struct user_namespace *tracer_ns = ns_of_task_struct(tracer); + + if (!smk_labels_valid(tracer_known, tracee_known, tracer_ns)) { + rc = -EACCES; + goto out; + } if (tracer_known->smk_known == tracee_known->smk_known) rc = 0; else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) rc = -EACCES; - else if (smack_has_privilege(tracer, CAP_SYS_PTRACE)) + else if (smack_has_ns_privilege(tracer, tracee_ns, + CAP_SYS_PTRACE)) rc = 0; else rc = -EPERM; +out: if (saip) smack_log(tracer_known->smk_known, tracee_known->smk_known, @@ -425,7 +434,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, } /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ - return smk_tskacc(tracer, tracee_known, smk_ptrace_mode(mode), saip); + return smk_tskacc(tracer, tracee_known, tracee_ns, + smk_ptrace_mode(mode), saip); } /* @@ -445,8 +455,9 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) { struct smack_known *skp = smk_of_task_struct(ctp); + struct user_namespace *ns = ns_of_task_struct(ctp); - return smk_ptrace_rule_check(current, skp, mode, __func__); + return smk_ptrace_rule_check(current, skp, ns, mode, __func__); } /** @@ -460,8 +471,10 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) static int smack_ptrace_traceme(struct task_struct *ptp) { struct smack_known *skp = smk_of_current(); + struct user_namespace *ns = ns_of_current(); - return smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); + return smk_ptrace_rule_check(ptp, skp, ns, PTRACE_MODE_ATTACH, + __func__); } /** @@ -508,6 +521,7 @@ static int smack_sb_alloc_security(struct super_block *sb) sbsp->smk_default = &smack_known_floor; sbsp->smk_floor = &smack_known_floor; sbsp->smk_hat = &smack_known_hat; + sbsp->smk_ns = get_user_ns(&init_user_ns); /* * smk_initialized will be zero from kzalloc. */ @@ -523,6 +537,9 @@ static int smack_sb_alloc_security(struct super_block *sb) */ static void smack_sb_free_security(struct super_block *sb) { + struct superblock_smack *sbsp = sb->s_security; + + put_user_ns(sbsp->smk_ns); kfree(sb->s_security); sb->s_security = NULL; } @@ -724,6 +741,7 @@ static int smack_set_mnt_opts(struct super_block *sb, struct smack_known *skp; int i; int num_opts = opts->num_mnt_opts; + struct user_namespace *ns = ns_of_current(); int transmute = 0; if (sp->smk_initialized) @@ -734,31 +752,31 @@ static int smack_set_mnt_opts(struct super_block *sb, for (i = 0; i < num_opts; i++) { switch (opts->mnt_opts_flags[i]) { case FSDEFAULT_MNT: - skp = smk_get_label(opts->mnt_opts[i], 0, true); + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_default = skp; break; case FSFLOOR_MNT: - skp = smk_get_label(opts->mnt_opts[i], 0, true); + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_floor = skp; break; case FSHAT_MNT: - skp = smk_get_label(opts->mnt_opts[i], 0, true); + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_hat = skp; break; case FSROOT_MNT: - skp = smk_get_label(opts->mnt_opts[i], 0, true); + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_root = skp; break; case FSTRANS_MNT: - skp = smk_get_label(opts->mnt_opts[i], 0, true); + skp = smk_get_label(opts->mnt_opts[i], 0, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_root = skp; @@ -769,7 +787,12 @@ static int smack_set_mnt_opts(struct super_block *sb, } } - if (!smack_privileged(CAP_MAC_ADMIN)) { + /* + * Check for non-privileged case. If current is inside the namespace + * and the it has privileges the validity of labels has already been + * checked during smk_get_label() + */ + if (!smack_ns_privileged(ns, CAP_MAC_ADMIN)) { /* * Unprivileged mounts don't get to specify Smack values. */ @@ -798,6 +821,12 @@ static int smack_set_mnt_opts(struct super_block *sb, if (transmute) isp->smk_flags |= SMK_INODE_TRANSMUTE; + /* + * Set the superblock namespace from a mounting process + */ + put_user_ns(sp->smk_ns); + sp->smk_ns = get_user_ns(ns); + return 0; } @@ -848,7 +877,7 @@ static int smack_sb_statfs(struct dentry *dentry) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); + rc = smk_curacc(sbp->smk_floor, sbp->smk_ns, MAY_READ, &ad); rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc); return rc; } @@ -868,6 +897,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) struct inode *inode = file_inode(bprm->file); struct task_smack *bsp = bprm->cred->security; struct inode_smack *isp; + struct user_namespace *ns = ns_of_current(); int rc; if (bprm->cred_prepared) @@ -877,6 +907,13 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) return 0; +#ifdef CONFIG_SECURITY_SMACK_NS + /* one label version of smk_labels_valid() */ + if (smk_find_mapped_ns(ns) && + smk_find_mapped(isp->smk_task, ns) == NULL) + return -EACCES; +#endif + if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { struct task_struct *tracer; rc = 0; @@ -884,9 +921,8 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) rcu_read_lock(); tracer = ptrace_parent(current); if (likely(tracer != NULL)) - rc = smk_ptrace_rule_check(tracer, - isp->smk_task, - PTRACE_MODE_ATTACH, + rc = smk_ptrace_rule_check(tracer, isp->smk_task, + ns, PTRACE_MODE_ATTACH, __func__); rcu_read_unlock(); @@ -1027,6 +1063,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct smack_known *isp; + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int rc; @@ -1034,13 +1071,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(d_backing_inode(old_dentry)); - rc = smk_curacc(isp, MAY_WRITE, &ad); + rc = smk_curacc(isp, ns, MAY_WRITE, &ad); rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_WRITE, rc); if (rc == 0 && d_is_positive(new_dentry)) { isp = smk_of_inode(d_backing_inode(new_dentry)); smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); - rc = smk_curacc(isp, MAY_WRITE, &ad); + rc = smk_curacc(isp, ns, MAY_WRITE, &ad); rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_WRITE, rc); } @@ -1058,6 +1095,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) { struct inode *ip = d_backing_inode(dentry); + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int rc; @@ -1067,7 +1105,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) /* * You need write access to the thing you're unlinking */ - rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(ip), ns, MAY_WRITE, &ad); rc = smk_bu_inode(ip, MAY_WRITE, rc); if (rc == 0) { /* @@ -1075,7 +1113,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) */ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, dir); - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(dir), ns, MAY_WRITE, &ad); rc = smk_bu_inode(dir, MAY_WRITE, rc); } return rc; @@ -1091,6 +1129,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) */ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) { + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int rc; @@ -1100,7 +1139,8 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) /* * You need write access to the thing you're removing */ - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns, + MAY_WRITE, &ad); rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); if (rc == 0) { /* @@ -1108,7 +1148,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) */ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, dir); - rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(dir), ns, MAY_WRITE, &ad); rc = smk_bu_inode(dir, MAY_WRITE, rc); } @@ -1132,21 +1172,22 @@ static int smack_inode_rename(struct inode *old_inode, struct inode *new_inode, struct dentry *new_dentry) { - int rc; struct smack_known *isp; + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; + int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); isp = smk_of_inode(d_backing_inode(old_dentry)); - rc = smk_curacc(isp, MAY_READWRITE, &ad); + rc = smk_curacc(isp, ns, MAY_READWRITE, &ad); rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_READWRITE, rc); if (rc == 0 && d_is_positive(new_dentry)) { isp = smk_of_inode(d_backing_inode(new_dentry)); smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); - rc = smk_curacc(isp, MAY_READWRITE, &ad); + rc = smk_curacc(isp, ns, MAY_READWRITE, &ad); rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_READWRITE, rc); } return rc; @@ -1163,6 +1204,7 @@ static int smack_inode_rename(struct inode *old_inode, */ static int smack_inode_permission(struct inode *inode, int mask) { + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int no_block = mask & MAY_NOT_BLOCK; int rc; @@ -1179,7 +1221,7 @@ static int smack_inode_permission(struct inode *inode, int mask) return -ECHILD; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); - rc = smk_curacc(smk_of_inode(inode), mask, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, mask, &ad); rc = smk_bu_inode(inode, mask, rc); return rc; } @@ -1193,6 +1235,7 @@ static int smack_inode_permission(struct inode *inode, int mask) */ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) { + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int rc; @@ -1204,7 +1247,8 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns, + MAY_WRITE, &ad); rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); return rc; } @@ -1218,13 +1262,14 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) */ static int smack_inode_getattr(const struct path *path) { + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; struct inode *inode = d_backing_inode(path->dentry); int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, *path); - rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, MAY_READ, &ad); rc = smk_bu_inode(inode, MAY_READ, rc); return rc; } @@ -1246,6 +1291,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, { struct smk_audit_info ad; struct smack_known *skp; + struct smack_known *sbj = smk_of_current(); + struct smack_known *obj = smk_of_inode(d_backing_inode(dentry)); + struct user_namespace *ns = ns_of_current(); int check_priv = 0; int check_import = 0; int check_star = 0; @@ -1272,11 +1320,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, } else rc = cap_inode_setxattr(dentry, name, value, size, flags); - if (check_priv && !smack_privileged(CAP_MAC_ADMIN)) + if (check_priv && !(smk_labels_valid(sbj, obj, ns) && + smack_ns_privileged(ns, CAP_MAC_ADMIN))) rc = -EPERM; if (rc == 0 && check_import) { - skp = size ? smk_get_label(value, size, true) : NULL; + skp = size ? smk_get_label(value, size, true, ns) : NULL; if (IS_ERR(skp)) rc = PTR_ERR(skp); else if (skp == NULL || (check_star && @@ -1288,7 +1337,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, smk_ad_setfield_u_fs_path_dentry(&ad, dentry); if (rc == 0) { - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); + rc = smk_curacc(obj, ns, MAY_WRITE, &ad); rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); } @@ -1296,6 +1345,40 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, } /** + * smack_inode_pre_setxattr - Unmap the namespaced label + * @dentry: object + * @name: attribute name + * @value: attribute value + * @size: attribute size + * @flags: unused + * @alloc: unused + * + * Guarantees that the real label value will be written to the filesystem. + */ +static int smack_inode_pre_setxattr(struct dentry *dentry, const char *name, + const void **value, size_t *size, int flags, + bool *alloc) +{ + struct smack_known *skp; + struct user_namespace *ns = ns_of_current(); + + if (strcmp(name, XATTR_NAME_SMACK) != 0 && + strcmp(name, XATTR_NAME_SMACKEXEC) != 0 && + strcmp(name, XATTR_NAME_SMACKMMAP) != 0) + return 0; + + /* Convert value to non namespaced label */ + skp = smk_get_label(*value, *size, true, ns); + if (IS_ERR(skp)) + return PTR_ERR(skp); + + *value = skp->smk_known; + *size = strlen(skp->smk_known); + + return 0; +} + +/** * smack_inode_post_setxattr - Apply the Smack update approved above * @dentry: object * @name: attribute name @@ -1326,7 +1409,8 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, skpp = &isp->smk_mmap; if (skpp) { - skp = smk_get_label(value, size, true); + /* value has been un-namespaced in inode_pre_setxattr() */ + skp = smk_get_label(value, size, true, &init_user_ns); if (!IS_ERR(skp)) *skpp = skp; @@ -1344,13 +1428,15 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, */ static int smack_inode_getxattr(struct dentry *dentry, const char *name) { + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns, + MAY_READ, &ad); rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc); return rc; } @@ -1367,6 +1453,9 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) static int smack_inode_removexattr(struct dentry *dentry, const char *name) { struct inode_smack *isp; + struct smack_known *sbj = smk_of_current(); + struct smack_known *obj = smk_of_inode(d_backing_inode(dentry)); + struct user_namespace *ns = ns_of_current(); struct smk_audit_info ad; int rc = 0; @@ -1376,7 +1465,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!smk_labels_valid(sbj, obj, ns) || + !smack_ns_privileged(ns, CAP_MAC_ADMIN)) rc = -EPERM; } else rc = cap_inode_removexattr(dentry, name); @@ -1387,7 +1477,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); smk_ad_setfield_u_fs_path_dentry(&ad, dentry); - rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); + rc = smk_curacc(obj, ns, MAY_WRITE, &ad); rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); if (rc != 0) return rc; @@ -1427,13 +1517,18 @@ static int smack_inode_getsecurity(const struct inode *inode, struct super_block *sbp; struct inode *ip = (struct inode *)inode; struct smack_known *isp = NULL; + struct user_namespace *ns = ns_of_current(); int rc = 0; if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) isp = smk_of_inode(inode); + else if (strcmp(name, XATTR_SMACK_EXEC) == 0) + isp = smk_of_exec(inode); + else if (strcmp(name, XATTR_SMACK_MMAP) == 0) + isp = smk_of_mmap(inode); if (isp) { - *buffer = smk_find_label_name(isp); + *buffer = smk_find_label_name(isp, ns); if (*buffer == NULL) *buffer = smack_known_huh.smk_known; return strlen(*buffer); @@ -1460,7 +1555,7 @@ static int smack_inode_getsecurity(const struct inode *inode, return -EOPNOTSUPP; if (rc == 0) { - *buffer = smk_find_label_name(isp); + *buffer = smk_find_label_name(isp, ns); if (*buffer == NULL) *buffer = smack_known_huh.smk_known; rc = strlen(*buffer); @@ -1571,18 +1666,19 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, { int rc = 0; struct smk_audit_info ad; + struct user_namespace *ns = ns_of_current(); struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); if (_IOC_DIR(cmd) & _IOC_WRITE) { - rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, MAY_WRITE, &ad); rc = smk_bu_file(file, MAY_WRITE, rc); } if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) { - rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, MAY_READ, &ad); rc = smk_bu_file(file, MAY_READ, rc); } @@ -1600,11 +1696,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd) { struct smk_audit_info ad; int rc; + struct user_namespace *ns = ns_of_current(); struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, MAY_LOCK, &ad); rc = smk_bu_file(file, MAY_LOCK, rc); return rc; } @@ -1626,6 +1723,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, { struct smk_audit_info ad; int rc = 0; + struct user_namespace *ns = ns_of_current(); struct inode *inode = file_inode(file); switch (cmd) { @@ -1635,14 +1733,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, case F_SETLKW: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, MAY_LOCK, &ad); rc = smk_bu_file(file, MAY_LOCK, rc); break; case F_SETOWN: case F_SETSIG: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, MAY_WRITE, &ad); rc = smk_bu_file(file, MAY_WRITE, rc); break; default: @@ -1672,6 +1770,7 @@ static int smack_mmap_file(struct file *file, struct task_smack *tsp; struct smack_known *okp; struct inode_smack *isp; + struct user_namespace *sns; int may; int mmay; int tmay; @@ -1682,12 +1781,16 @@ static int smack_mmap_file(struct file *file, tsp = current_security(); skp = smk_of_task(tsp); + sns = ns_of_current(); isp = file_inode(file)->i_security; mkp = isp->smk_mmap; if (mkp == NULL) return 0; + if (!smk_labels_valid(skp, mkp, sns)) + return -EACCES; + rc = 0; rcu_read_lock(); @@ -1703,6 +1806,7 @@ static int smack_mmap_file(struct file *file, */ if (mkp->smk_known == okp->smk_known) continue; + /* * If there is a matching local rule take * that into account as well. @@ -1782,8 +1886,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { struct smack_known *skp; - struct smack_known *tkp = smk_of_task(tsk->cred->security); + struct smack_known *tkp; struct file *file; + struct user_namespace *sns; + struct user_namespace *tns; int rc; struct smk_audit_info ad; @@ -1791,12 +1897,17 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, * struct fown_struct is never outside the context of a struct file */ file = container_of(fown, struct file, f_owner); + skp = file->f_security; + sns = file->f_cred->user_ns; + + tkp = smk_of_task_struct(tsk); + tns = ns_of_task_struct(tsk); /* we don't log here as rc can be overriden */ - skp = file->f_security; - rc = smk_access(skp, tkp, MAY_WRITE, NULL); + rc = smk_access(skp, tkp, sns, MAY_WRITE, NULL); rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc); - if (rc != 0 && smack_has_privilege(tsk, CAP_MAC_OVERRIDE)) + if (rc != 0 && smk_labels_valid(skp, tkp, sns) + && smack_has_ns_privilege(tsk, tns, CAP_MAC_OVERRIDE)) rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); @@ -1816,6 +1927,7 @@ static int smack_file_receive(struct file *file) int rc; int may = 0; struct smk_audit_info ad; + struct user_namespace *ns = ns_of_current(); struct inode *inode = file_inode(file); if (unlikely(IS_PRIVATE(inode))) @@ -1831,7 +1943,7 @@ static int smack_file_receive(struct file *file) if (file->f_mode & FMODE_WRITE) may |= MAY_WRITE; - rc = smk_curacc(smk_of_inode(inode), may, &ad); + rc = smk_curacc(smk_of_inode(inode), ns, may, &ad); rc = smk_bu_file(file, may, rc); return rc; } @@ -1851,16 +1963,19 @@ static int smack_file_receive(struct file *file) static int smack_file_open(struct file *file, const struct cred *cred) { struct task_smack *tsp = cred->security; + struct user_namespace *ns = cred->user_ns; struct inode *inode = file_inode(file); + struct inode_smack *isp = file_inode(file)->i_security; struct smk_audit_info ad; int rc; - if (smack_privileged(CAP_MAC_OVERRIDE)) + if (smk_labels_valid(tsp->smk_task, isp->smk_inode, ns) && + smack_ns_privileged(ns, CAP_MAC_OVERRIDE)) return 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad); + rc = smk_access(tsp->smk_task, smk_of_inode(inode), ns, MAY_READ, &ad); rc = smk_bu_credfile(cred, file, MAY_READ, rc); return rc; @@ -2015,12 +2130,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access, const char *caller) { struct smk_audit_info ad; - struct smack_known *skp = smk_of_task_struct(p); + struct smack_known *tkp = smk_of_task_struct(p); + struct user_namespace *tns = ns_of_task_struct(p); int rc; smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - rc = smk_curacc(skp, access, &ad); + rc = smk_curacc(tkp, tns, access, &ad); rc = smk_bu_task(p, access, rc); return rc; } @@ -2161,6 +2277,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, struct smk_audit_info ad; struct smack_known *skp; struct smack_known *tkp = smk_of_task_struct(p); + struct user_namespace *tns = ns_of_task_struct(p); int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); @@ -2170,7 +2287,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * can write the receiver. */ if (secid == 0) { - rc = smk_curacc(tkp, MAY_WRITE, &ad); + rc = smk_curacc(tkp, tns, MAY_WRITE, &ad); rc = smk_bu_task(p, MAY_WRITE, rc); return rc; } @@ -2180,8 +2297,9 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * we can't take privilege into account. */ skp = smack_from_secid(secid); - rc = smk_access(skp, tkp, MAY_WRITE, &ad); + rc = smk_access(skp, tkp, tns, MAY_WRITE, &ad); rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc); + return rc; } @@ -2236,6 +2354,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) { struct smack_known *skp = smk_of_current(); + struct user_namespace *ns = ns_of_current(); struct socket_smack *ssp; ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); @@ -2245,6 +2364,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) ssp->smk_in = skp; ssp->smk_out = skp; ssp->smk_packet = NULL; + ssp->smk_ns = get_user_ns(ns); sk->sk_security = ssp; @@ -2259,7 +2379,11 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) */ static void smack_sk_free_security(struct sock *sk) { + struct socket_smack *ssp = sk->sk_security; + + put_user_ns(ssp->smk_ns); kfree(sk->sk_security); + sk->sk_security = NULL; } /** @@ -2420,6 +2544,7 @@ static int smack_netlabel(struct sock *sk, int labeled) static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) { struct smack_known *skp; + struct user_namespace *sns; int rc; int sk_lbl; struct smack_known *hkp; @@ -2439,7 +2564,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) #endif sk_lbl = SMACK_UNLABELED_SOCKET; skp = ssp->smk_out; - rc = smk_access(skp, hkp, MAY_WRITE, &ad); + sns = ssp->smk_ns; + rc = smk_access(skp, hkp, sns, MAY_WRITE, &ad); rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc); } else { sk_lbl = SMACK_CIPSO_SOCKET; @@ -2464,6 +2590,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) */ static int smk_ipv6_check(struct smack_known *subject, struct smack_known *object, + struct user_namespace *ns, struct sockaddr_in6 *address, int act) { #ifdef CONFIG_AUDIT @@ -2481,7 +2608,7 @@ static int smk_ipv6_check(struct smack_known *subject, else ad.a.u.net->v6info.daddr = address->sin6_addr; #endif - rc = smk_access(subject, object, MAY_WRITE, &ad); + rc = smk_access(subject, object, ns, MAY_WRITE, &ad); rc = smk_bu_note("IPv6 check", subject, object, MAY_WRITE, rc); return rc; } @@ -2574,6 +2701,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, struct smk_port_label *spp; struct socket_smack *ssp = sk->sk_security; struct smack_known *skp = NULL; + struct user_namespace *sns = ssp->smk_ns; unsigned short port; struct smack_known *object; @@ -2617,7 +2745,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, break; } - return smk_ipv6_check(skp, object, address, act); + return smk_ipv6_check(skp, object, sns, address, act); } #endif /* SMACK_IPV6_PORT_LABELING */ @@ -2640,12 +2768,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, struct inode_smack *nsp = inode->i_security; struct socket_smack *ssp; struct socket *sock; + struct user_namespace *ns = ns_of_current(); int rc = 0; if (value == NULL || size > SMK_LONGLABEL || size == 0) return -EINVAL; - skp = smk_get_label(value, size, true); + skp = smk_get_label(value, size, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); @@ -2765,6 +2894,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, #ifdef SMACK_IPV6_SECMARK_LABELING struct smack_known *rsp; struct socket_smack *ssp = sock->sk->sk_security; + struct user_namespace *sns = ssp->smk_ns; #endif if (sock->sk == NULL) @@ -2782,7 +2912,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, #ifdef SMACK_IPV6_SECMARK_LABELING rsp = smack_ipv6host_label(sip); if (rsp != NULL) - rc = smk_ipv6_check(ssp->smk_out, rsp, sip, + rc = smk_ipv6_check(ssp->smk_out, rsp, sns, sip, SMK_CONNECTING); #endif #ifdef SMACK_IPV6_PORT_LABELING @@ -2839,14 +2969,14 @@ static void smack_msg_msg_free_security(struct msg_msg *msg) } /** - * smack_of_shm - the smack pointer for the shm + * security_of_shm - the smack pointer for the shm * @shp: the object * - * Returns a pointer to the smack value + * Returns a pointer to the security_smack struct */ -static struct smack_known *smack_of_shm(struct shmid_kernel *shp) +static struct ipc_smack *security_of_shm(struct shmid_kernel *shp) { - return (struct smack_known *)shp->shm_perm.security; + return (struct ipc_smack *)shp->shm_perm.security; } /** @@ -2858,9 +2988,16 @@ static struct smack_known *smack_of_shm(struct shmid_kernel *shp) static int smack_shm_alloc_security(struct shmid_kernel *shp) { struct kern_ipc_perm *isp = &shp->shm_perm; - struct smack_known *skp = smk_of_current(); + struct ipc_smack *ssp; + + ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL); + if (ssp == NULL) + return -ENOMEM; + + ssp->smk_known = smk_of_current(); + ssp->smk_ns = get_user_ns(ns_of_current()); - isp->security = skp; + isp->security = ssp; return 0; } @@ -2873,7 +3010,10 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp) static void smack_shm_free_security(struct shmid_kernel *shp) { struct kern_ipc_perm *isp = &shp->shm_perm; + struct ipc_smack *ssp = isp->security; + put_user_ns(ssp->smk_ns); + kfree(isp->security); isp->security = NULL; } @@ -2886,7 +3026,7 @@ static void smack_shm_free_security(struct shmid_kernel *shp) */ static int smk_curacc_shm(struct shmid_kernel *shp, int access) { - struct smack_known *ssp = smack_of_shm(shp); + struct ipc_smack *ssp = security_of_shm(shp); struct smk_audit_info ad; int rc; @@ -2894,8 +3034,8 @@ static int smk_curacc_shm(struct shmid_kernel *shp, int access) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = shp->shm_perm.id; #endif - rc = smk_curacc(ssp, access, &ad); - rc = smk_bu_current("shm", ssp, access, rc); + rc = smk_curacc(ssp->smk_known, ssp->smk_ns, access, &ad); + rc = smk_bu_current("shm", ssp->smk_known, access, rc); return rc; } @@ -2966,14 +3106,14 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, } /** - * smack_of_sem - the smack pointer for the sem + * security_of_sem - the smack pointer for the sem * @sma: the object * - * Returns a pointer to the smack value + * Returns a pointer to the ipc_smack struct */ -static struct smack_known *smack_of_sem(struct sem_array *sma) +static struct ipc_smack *security_of_sem(struct sem_array *sma) { - return (struct smack_known *)sma->sem_perm.security; + return (struct ipc_smack *)sma->sem_perm.security; } /** @@ -2985,9 +3125,16 @@ static struct smack_known *smack_of_sem(struct sem_array *sma) static int smack_sem_alloc_security(struct sem_array *sma) { struct kern_ipc_perm *isp = &sma->sem_perm; - struct smack_known *skp = smk_of_current(); + struct ipc_smack *ssp; + + ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL); + if (ssp == NULL) + return -ENOMEM; + + ssp->smk_known = smk_of_current(); + ssp->smk_ns = get_user_ns(ns_of_current()); - isp->security = skp; + isp->security = ssp; return 0; } @@ -3000,7 +3147,10 @@ static int smack_sem_alloc_security(struct sem_array *sma) static void smack_sem_free_security(struct sem_array *sma) { struct kern_ipc_perm *isp = &sma->sem_perm; + struct ipc_smack *ssp = isp->security; + put_user_ns(ssp->smk_ns); + kfree(isp->security); isp->security = NULL; } @@ -3013,7 +3163,7 @@ static void smack_sem_free_security(struct sem_array *sma) */ static int smk_curacc_sem(struct sem_array *sma, int access) { - struct smack_known *ssp = smack_of_sem(sma); + struct ipc_smack *ssp = security_of_sem(sma); struct smk_audit_info ad; int rc; @@ -3021,8 +3171,8 @@ static int smk_curacc_sem(struct sem_array *sma, int access) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = sma->sem_perm.id; #endif - rc = smk_curacc(ssp, access, &ad); - rc = smk_bu_current("sem", ssp, access, rc); + rc = smk_curacc(ssp->smk_known, ssp->smk_ns, access, &ad); + rc = smk_bu_current("sem", ssp->smk_known, access, rc); return rc; } @@ -3107,9 +3257,16 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops, static int smack_msg_queue_alloc_security(struct msg_queue *msq) { struct kern_ipc_perm *kisp = &msq->q_perm; - struct smack_known *skp = smk_of_current(); + struct ipc_smack *ssp; + + ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL); + if (ssp == NULL) + return -ENOMEM; - kisp->security = skp; + ssp->smk_known = smk_of_current(); + ssp->smk_ns = get_user_ns(ns_of_current()); + + kisp->security = ssp; return 0; } @@ -3122,19 +3279,22 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq) static void smack_msg_queue_free_security(struct msg_queue *msq) { struct kern_ipc_perm *kisp = &msq->q_perm; + struct ipc_smack *ssp = kisp->security; + put_user_ns(ssp->smk_ns); + kfree(kisp->security); kisp->security = NULL; } /** - * smack_of_msq - the smack pointer for the msq + * security_of_msq - the smack pointer for the msq * @msq: the object * - * Returns a pointer to the smack label entry + * Returns a pointer to the ipc_smack struct */ -static struct smack_known *smack_of_msq(struct msg_queue *msq) +static struct ipc_smack *security_of_msq(struct msg_queue *msq) { - return (struct smack_known *)msq->q_perm.security; + return (struct ipc_smack *)msq->q_perm.security; } /** @@ -3146,7 +3306,7 @@ static struct smack_known *smack_of_msq(struct msg_queue *msq) */ static int smk_curacc_msq(struct msg_queue *msq, int access) { - struct smack_known *msp = smack_of_msq(msq); + struct ipc_smack *msp = security_of_msq(msq); struct smk_audit_info ad; int rc; @@ -3154,8 +3314,8 @@ static int smk_curacc_msq(struct msg_queue *msq, int access) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = msq->q_perm.id; #endif - rc = smk_curacc(msp, access, &ad); - rc = smk_bu_current("msq", msp, access, rc); + rc = smk_curacc(msp->smk_known, msp->smk_ns, access, &ad); + rc = smk_bu_current("msq", msp->smk_known, access, rc); return rc; } @@ -3249,7 +3409,7 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, */ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) { - struct smack_known *iskp = ipp->security; + struct ipc_smack *isp = ipp->security; int may = smack_flags_to_may(flag); struct smk_audit_info ad; int rc; @@ -3258,8 +3418,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); ad.a.u.ipc_id = ipp->id; #endif - rc = smk_curacc(iskp, may, &ad); - rc = smk_bu_current("svipc", iskp, may, rc); + rc = smk_curacc(isp->smk_known, isp->smk_ns, may, &ad); + rc = smk_bu_current("svipc", isp->smk_known, may, rc); return rc; } @@ -3270,9 +3430,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) */ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) { - struct smack_known *iskp = ipp->security; + struct ipc_smack *iskp = ipp->security; - *secid = iskp->smk_secid; + *secid = iskp->smk_known->smk_secid; } /** @@ -3530,13 +3690,14 @@ int smack_getprocattr_seq(struct task_struct *p, const char *name, static int smack_getprocattr(struct task_struct *p, char *name, char **value) { struct smack_known *skp = smk_of_task_struct(p); + struct user_namespace *ns = ns_of_current(); char *cp; int slen; if (strcmp(name, "current") != 0) return -EINVAL; - cp = smk_find_label_name(skp); + cp = smk_find_label_name(skp, ns); if (cp == NULL) cp = smack_known_huh.smk_known; cp = kstrdup(cp, GFP_KERNEL); @@ -3564,6 +3725,7 @@ static int proc_current_write(struct task_struct *p, void *value, size_t size) struct task_smack *tsp; struct cred *new; struct smack_known *skp; + struct user_namespace *ns; /* * Changing another process' Smack value is too dangerous @@ -3572,13 +3734,15 @@ static int proc_current_write(struct task_struct *p, void *value, size_t size) if (p != current) return -EPERM; - if (!smack_privileged(CAP_MAC_ADMIN)) + ns = ns_of_current(); + + if (!smack_ns_privileged(ns, CAP_MAC_ADMIN)) return -EPERM; if (value == NULL || size == 0 || size >= SMK_LONGLABEL) return -EINVAL; - skp = smk_get_label(value, size, true); + skp = smk_get_label(value, size, true, ns); if (IS_ERR(skp)) return PTR_ERR(skp); @@ -3645,23 +3809,27 @@ static int smack_unix_stream_connect(struct sock *sock, struct smack_known *okp_out = osp->smk_out; struct smack_known *skp_in = ssp->smk_in; struct smack_known *okp_in = osp->smk_in; + struct user_namespace *sns = ssp->smk_ns; + struct user_namespace *ons = osp->smk_ns; struct smk_audit_info ad; int rc = 0; #ifdef CONFIG_AUDIT struct lsm_network_audit net; #endif - if (!smack_privileged(CAP_MAC_OVERRIDE)) { + if (!smack_ns_privileged(ons, CAP_MAC_OVERRIDE) || + !smk_labels_valid(skp_out, okp_in, sns) || + !smk_labels_valid(okp_out, skp_in, ons)) { #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); smk_ad_setfield_u_net_sk(&ad, other); #endif - rc = smk_access(skp_out, okp_in, MAY_WRITE, &ad); + rc = smk_access(skp_out, okp_in, sns, MAY_WRITE, &ad); rc = smk_bu_note("UDS connect", skp_out, okp_in, MAY_WRITE, rc); if (rc == 0) { - rc = smk_access(okp_out, skp_in, MAY_WRITE, &ad); + rc = smk_access(okp_out, skp_in, ons, MAY_WRITE, &ad); rc = smk_bu_note("UDS connect", okp_out, skp_in, - MAY_WRITE, rc); + MAY_WRITE, rc); } } @@ -3688,6 +3856,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) { struct socket_smack *ssp = sock->sk->sk_security; struct socket_smack *osp = other->sk->sk_security; + struct user_namespace *sns = ssp->smk_ns; + struct user_namespace *ons = osp->smk_ns; struct smk_audit_info ad; int rc; @@ -3698,10 +3868,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) smk_ad_setfield_u_net_sk(&ad, other->sk); #endif - if (smack_privileged(CAP_MAC_OVERRIDE)) + if (smk_labels_valid(ssp->smk_out, osp->smk_in, sns) && + smack_ns_privileged(ons, CAP_MAC_OVERRIDE)) return 0; - rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + rc = smk_access(ssp->smk_out, osp->smk_in, sns, MAY_WRITE, &ad); rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc); return rc; } @@ -3724,8 +3895,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; #endif #ifdef SMACK_IPV6_SECMARK_LABELING - struct socket_smack *ssp = sock->sk->sk_security; struct smack_known *rsp; + struct socket_smack *ssp = sock->sk->sk_security; + struct user_namespace *sns = ssp->smk_ns; #endif int rc = 0; @@ -3743,7 +3915,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, #ifdef SMACK_IPV6_SECMARK_LABELING rsp = smack_ipv6host_label(sap); if (rsp != NULL) - rc = smk_ipv6_check(ssp->smk_out, rsp, sap, + rc = smk_ipv6_check(ssp->smk_out, rsp, sns, sap, SMK_CONNECTING); #endif #ifdef SMACK_IPV6_PORT_LABELING @@ -3951,7 +4123,7 @@ access_check: * This is the simplist possible security model * for networking. */ - rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad); rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in, MAY_WRITE, rc); if (rc != 0) @@ -3975,7 +4147,7 @@ access_check: ad.a.u.net->netif = skb->skb_iif; ipv6_skb_to_auditdata(skb, &ad.a, NULL); #endif /* CONFIG_AUDIT */ - rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad); rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, MAY_WRITE, rc); #endif /* SMACK_IPV6_SECMARK_LABELING */ @@ -4187,7 +4359,7 @@ access_check: * Receiving a packet requires that the other end be able to write * here. Read access is not required. */ - rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad); rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc); if (rc != 0) return rc; @@ -4291,6 +4463,7 @@ static int smack_key_permission(key_ref_t key_ref, struct key *keyp; struct smk_audit_info ad; struct smack_known *tkp = smk_of_task(cred->security); + struct user_namespace *tns = cred->user_ns; int request = 0; int rc; @@ -4317,7 +4490,7 @@ static int smack_key_permission(key_ref_t key_ref, request = MAY_READ; if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) request = MAY_WRITE; - rc = smk_access(tkp, keyp->security, request, &ad); + rc = smk_access(tkp, keyp->security, tns, request, &ad); rc = smk_bu_note("key access", tkp, keyp->security, request, rc); return rc; } @@ -4334,6 +4507,7 @@ static int smack_key_permission(key_ref_t key_ref, static int smack_key_getsecurity(struct key *key, char **_buffer) { struct smack_known *skp = key->security; + struct user_namespace *ns = ns_of_current(); size_t length; char *copy; @@ -4342,7 +4516,7 @@ static int smack_key_getsecurity(struct key *key, char **_buffer) return 0; } - copy = smk_find_label_name(skp); + copy = smk_find_label_name(skp, ns); if (copy == NULL) copy = smack_known_huh.smk_known; copy = kstrdup(copy, GFP_KERNEL); @@ -4520,6 +4694,11 @@ static inline void smack_userns_free(struct user_namespace *ns) static inline int smack_userns_setns(struct nsproxy *nsproxy, struct user_namespace *ns) { + struct smack_known *skp = smk_of_current(); + + if (smk_find_mapped(skp, ns) == NULL) + return -EACCES; + return 0; } @@ -4632,6 +4811,7 @@ static struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(inode_setattr, smack_inode_setattr), LSM_HOOK_INIT(inode_getattr, smack_inode_getattr), LSM_HOOK_INIT(inode_setxattr, smack_inode_setxattr), + LSM_HOOK_INIT(inode_pre_setxattr, smack_inode_pre_setxattr), LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr), LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr), LSM_HOOK_INIT(inode_removexattr, smack_inode_removexattr), diff --git a/security/smack/smack_ns.c b/security/smack/smack_ns.c index 49223c4..dc2a666 100644 --- a/security/smack/smack_ns.c +++ b/security/smack/smack_ns.c @@ -206,6 +206,45 @@ unlockout: return sknp; } +/** + * smk_labels_valid - A helper to check whether labels are valid/mapped + * in the namespace and can be used there + * @sbj: a subject label to be checked + * @obj: an object label to be checked + * @ns: user namespace to check against (usually subject's) + * + * Returns true if both valid/mapped, false otherwise. + * This helper is mostly used while checking capabilities. + * The access functions check the validity of labels by themselves. + */ +bool smk_labels_valid(struct smack_known *sbj, struct smack_known *obj, + struct user_namespace *ns) +{ + struct user_namespace *user_ns; + + /* + * labels are always valid if there is no map + * (init_user_ns or unmapped descendants) + */ + user_ns = smk_find_mapped_ns(ns); + if (user_ns == NULL) + return true; + + /* + * If we have a map though, both labels need to be mapped. + */ + if (__smk_find_mapped(sbj, user_ns) == NULL) + return false; + if (__smk_find_mapped(obj, user_ns) == NULL) + return false; + + return true; +} + +/* + * proc mapping operations + */ + static void *proc_label_map_seq_start(struct seq_file *seq, loff_t *pos) { struct smack_known *skp; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 3149ec0..fe4ad24 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -340,13 +340,15 @@ static int smk_fill_rule(const char *subject, const char *object, struct smack_parsed_rule *rule, int import, int len) { - rule->smk_subject = smk_get_label(subject, len, import); + struct user_namespace *ns = ns_of_current(); + + rule->smk_subject = smk_get_label(subject, len, import, ns); if (IS_ERR(rule->smk_subject)) return PTR_ERR(rule->smk_subject); if (rule->smk_subject == NULL) return -ENOENT; - rule->smk_object = smk_get_label(object, len, import); + rule->smk_object = smk_get_label(object, len, import, ns); if (IS_ERR(rule->smk_object)) return PTR_ERR(rule->smk_object); if (rule->smk_object == NULL) @@ -573,6 +575,7 @@ static void smk_seq_stop(struct seq_file *s, void *v) static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) { + struct user_namespace *ns = ns_of_current(); char *sbj; char *obj; @@ -581,6 +584,7 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) * interface file (/smack/load or /smack/load2) * because you should expect to be able to write * anything you read back. + * Show only fully mapped rules in a namespace (both labels mapped). */ if (strlen(srp->smk_subject->smk_known) >= max || strlen(srp->smk_object->smk_known) >= max) @@ -589,8 +593,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) if (srp->smk_access == 0) return; - sbj = smk_find_label_name(srp->smk_subject); - obj = smk_find_label_name(srp->smk_object); + sbj = smk_find_label_name(srp->smk_subject, ns); + obj = smk_find_label_name(srp->smk_object, ns); if (sbj == NULL || obj == NULL) return; @@ -785,6 +789,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) struct smack_known *skp = list_entry_rcu(list, struct smack_known, list); struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; + struct user_namespace *ns = ns_of_current(); char sep = '/'; char *cp; int i; @@ -800,7 +805,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) if (strlen(skp->smk_known) >= SMK_LABELLEN) return 0; - cp = smk_find_label_name(skp); + cp = smk_find_label_name(skp, ns); if (cp == NULL) return 0; @@ -853,6 +858,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, { struct smack_known *skp; struct netlbl_lsm_secattr ncats; + struct user_namespace *ns = ns_of_current(); char mapcatset[SMK_CIPSOLEN]; int maplevel; unsigned int cat; @@ -893,7 +899,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, */ mutex_lock(&smack_cipso_lock); - skp = smk_get_label(rule, 0, true); + skp = smk_get_label(rule, 0, true, ns); if (IS_ERR(skp)) { rc = PTR_ERR(skp); goto out; @@ -981,11 +987,12 @@ static int cipso2_seq_show(struct seq_file *s, void *v) struct smack_known *skp = list_entry_rcu(list, struct smack_known, list); struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; + struct user_namespace *ns = ns_of_current(); char sep = '/'; char *cp; int i; - cp = smk_find_label_name(skp); + cp = smk_find_label_name(skp, ns); if (cp == NULL) return 0; @@ -1066,12 +1073,13 @@ static void *net4addr_seq_next(struct seq_file *s, void *v, loff_t *pos) static int net4addr_seq_show(struct seq_file *s, void *v) { struct list_head *list = v; + struct user_namespace *ns = ns_of_current(); struct smk_net4addr *skp = list_entry_rcu(list, struct smk_net4addr, list); char *kp = SMACK_CIPSO_OPTION; if (skp->smk_label != NULL) { - kp = smk_find_label_name(skp->smk_label); + kp = smk_find_label_name(skp->smk_label, ns); if (kp == NULL) kp = smack_known_huh.smk_known; } @@ -1167,6 +1175,7 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, int rc; struct netlbl_audit audit_info; struct in_addr mask; + struct user_namespace *ns = ns_of_current(); unsigned int m; unsigned int masks; int found; @@ -1226,7 +1235,7 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, * If smack begins with '-', it is an option, don't import it */ if (smack[0] != '-') { - skp = smk_get_label(smack, 0, true); + skp = smk_get_label(smack, 0, true, ns); if (IS_ERR(skp)) { rc = PTR_ERR(skp); goto free_out; @@ -1345,10 +1354,11 @@ static int net6addr_seq_show(struct seq_file *s, void *v) struct list_head *list = v; struct smk_net6addr *skp = list_entry(list, struct smk_net6addr, list); + struct user_namespace *ns = ns_of_current(); char *kp; if (skp->smk_label != NULL) { - kp = smk_find_label_name(skp->smk_label); + kp = smk_find_label_name(skp->smk_label, ns); if (kp == NULL) kp = smack_known_huh.smk_known; @@ -1438,6 +1448,7 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, struct in6_addr newname; struct in6_addr fullmask; struct smack_known *skp = NULL; + struct user_namespace *ns = ns_of_current(); char *smack; char *data; int rc = 0; @@ -1508,7 +1519,7 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, * If smack begins with '-', it is an option, don't import it */ if (smack[0] != '-') { - skp = smk_get_label(smack, 0, true); + skp = smk_get_label(smack, 0, true, ns); if (IS_ERR(skp)) { rc = PTR_ERR(skp); goto free_out; @@ -1827,6 +1838,7 @@ static const struct file_operations smk_mapped_ops = { static ssize_t smk_read_ambient(struct file *filp, char __user *buf, size_t cn, loff_t *ppos) { + struct user_namespace *ns = ns_of_current(); ssize_t rc = -EINVAL; char *cp; int asize; @@ -1839,7 +1851,7 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, */ mutex_lock(&smack_ambient_lock); - cp = smk_find_label_name(smack_net_ambient); + cp = smk_find_label_name(smack_net_ambient, ns); if (cp == NULL) cp = smack_known_huh.smk_known; @@ -1866,6 +1878,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct smack_known *skp; + struct user_namespace *ns = ns_of_current(); char *oldambient; char *data; int rc = count; @@ -1882,7 +1895,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, goto out; } - skp = smk_get_label(data, count, true); + skp = smk_get_label(data, count, true, ns); if (IS_ERR(skp)) { rc = PTR_ERR(skp); goto out; @@ -1923,11 +1936,12 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos) static int onlycap_seq_show(struct seq_file *s, void *v) { char *smack; + struct user_namespace *ns = ns_of_current(); struct list_head *list = v; struct smack_onlycap *sop = list_entry_rcu(list, struct smack_onlycap, list); - smack = smk_find_label_name(sop->smk_label); + smack = smk_find_label_name(sop->smk_label, ns); if (smack == NULL) smack = smack_known_huh.smk_known; @@ -2006,6 +2020,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, struct smack_onlycap *sop; struct smack_onlycap *sop2; LIST_HEAD(list_tmp); + struct user_namespace *ns = ns_of_current(); int rc = count; if (!smack_privileged(CAP_MAC_ADMIN)) @@ -2025,7 +2040,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, if (!*tok) continue; - skp = smk_get_label(tok, 0, true); + skp = smk_get_label(tok, 0, true, ns); if (IS_ERR(skp)) { rc = PTR_ERR(skp); break; @@ -2091,12 +2106,13 @@ static ssize_t smk_read_unconfined(struct file *filp, char __user *buf, char *smack = ""; ssize_t rc = -EINVAL; int asize; + struct user_namespace *ns = ns_of_current(); if (*ppos != 0) return 0; if (smack_unconfined != NULL) { - smack = smk_find_label_name(smack_unconfined); + smack = smk_find_label_name(smack_unconfined, ns); if (smack == NULL) smack = smack_known_huh.smk_known; } @@ -2123,6 +2139,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf, { char *data; struct smack_known *skp; + struct user_namespace *ns = ns_of_current(); int rc = count; if (!smack_privileged(CAP_MAC_ADMIN)) @@ -2146,7 +2163,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf, * * But do so only on invalid label, not on system errors. */ - skp = smk_get_label(data, count, true); + skp = smk_get_label(data, count, true, ns); if (PTR_ERR(skp) == -EINVAL) skp = NULL; else if (IS_ERR(skp)) { @@ -2318,6 +2335,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, size_t count, loff_t *ppos, int format) { struct smack_parsed_rule rule; + struct user_namespace *ns = ns_of_current(); char *data; int res; @@ -2337,7 +2355,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf, } if (res >= 0) - res = smk_access(rule.smk_subject, rule.smk_object, + res = smk_access(rule.smk_subject, rule.smk_object, ns, rule.smk_access1, NULL); else if (res != -ENOENT) return res; @@ -2547,6 +2565,7 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, struct smack_rule *sp; struct list_head *rule_list; struct mutex *rule_lock; + struct user_namespace *ns = ns_of_current(); int rc = count; if (*ppos != 0) @@ -2567,7 +2586,7 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, goto out_data; } - skp = smk_get_label(data, count, false); + skp = smk_get_label(data, count, false, ns); if (IS_ERR(skp)) { rc = PTR_ERR(skp); goto out_data; @@ -2649,12 +2668,13 @@ static ssize_t smk_read_syslog(struct file *filp, char __user *buf, char *smack = ""; ssize_t rc = -EINVAL; int asize; + struct user_namespace *ns = ns_of_current(); if (*ppos != 0) return 0; if (smack_syslog_label != NULL) { - smack = smk_find_label_name(smack_syslog_label); + smack = smk_find_label_name(smack_syslog_label, ns); if (smack == NULL) smack = smack_known_huh.smk_known; } @@ -2681,6 +2701,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf, { char *data; struct smack_known *skp; + struct user_namespace *ns = ns_of_current(); int rc = count; if (!smack_privileged(CAP_MAC_ADMIN)) @@ -2704,7 +2725,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf, * * But do so only on invalid label, not on system errors. */ - skp = smk_get_label(data, count, true); + skp = smk_get_label(data, count, true, ns); if (PTR_ERR(skp) == -EINVAL) skp = NULL; else if (IS_ERR(skp)) {