There are three Smack updates that have been accepted into the 2.6.38 linus kernel which are required for MSSF in Meego 1.2. They are described below, along with their respective commit messages.
commit b4e0d5f0791bd6dd12a1c1edea0340969c7c1f90 commit 676dac4b1bee0469d6932f698aeb77e8489f5861 commit 5c6d1125f8dbd1bfef39e38fbc2837003be78a59 commit 5c6d1125f8dbd1bfef39e38fbc2837003be78a59 Author: Jarkko Sakkinen <[email protected]> Date: Tue Dec 7 13:34:01 2010 +0200 Smack: Transmute labels on specified directories In a situation where Smack access rules allow processes with multiple labels to write to a directory it is easy to get into a situation where the directory gets cluttered with files that the owner can't deal with because while they could be written to the directory a process at the label of the directory can't write them. This is generally the desired behavior, but when it isn't it is a real issue. This patch introduces a new attribute SMACK64TRANSMUTE that instructs Smack to create the file with the label of the directory under certain circumstances. A new access mode, "t" for transmute, is made available to Smack access rules, which are expanded from "rwxa" to "rwxat". If a file is created in a directory marked as transmutable and if access was granted to perform the operation by a rule that included the transmute mode, then the file gets the Smack label of the directory instead of the Smack label of the creating process. Note that this is equivalent to creating an empty file at the label of the directory and then having the other process write to it. The transmute scheme requires that both the access rule allows transmutation and that the directory be explicitly marked. Signed-off-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Casey Schaufler <[email protected]> --- include/linux/xattr.h | 2 + security/smack/smack.h | 17 +++++++++- security/smack/smack_access.c | 54 ++++++++++++++++++++++------- security/smack/smack_lsm.c | 74 +++++++++++++++++++++++++++------------- security/smack/smackfs.c | 37 +++++++++++++++++--- 5 files changed, 141 insertions(+), 43 deletions(-) diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 351c790..e6131ef 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -41,10 +41,12 @@ #define XATTR_SMACK_IPIN "SMACK64IPIN" #define XATTR_SMACK_IPOUT "SMACK64IPOUT" #define XATTR_SMACK_EXEC "SMACK64EXEC" +#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE" #define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX #define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT #define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC +#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE #define XATTR_CAPS_SUFFIX "capability" #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX diff --git a/security/smack/smack.h b/security/smack/smack.h index a2e2cdf..129c4eb 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -62,6 +62,7 @@ struct task_smack { }; #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ +#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ /* * A label access rule. @@ -167,6 +168,10 @@ struct smack_known { #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ /* + * Flag for transmute access + */ +#define MAY_TRANSMUTE 64 +/* * Just to make the common cases easier to deal with */ #define MAY_ANY (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) @@ -197,6 +202,7 @@ struct inode_smack *new_inode_smack(char *); /* * These functions are in smack_access.c */ +int smk_access_entry(char *, char *); int smk_access(char *, char *, int, struct smk_audit_info *); int smk_curacc(char *, u32, struct smk_audit_info *); int smack_to_cipso(const char *, struct smack_cipso *); @@ -240,6 +246,15 @@ static inline void smack_catset_bit(int cat, char *catsetp) } /* + * Is the directory transmuting? + */ +static inline int smk_inode_transmutable(const struct inode *isp) +{ + struct inode_smack *sip = isp->i_security; + return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0; +} + +/* * Present a pointer to the smack label in an inode blob. */ static inline char *smk_of_inode(const struct inode *isp) @@ -265,7 +280,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp) } /* - * Present a pointer to the smack label in the curren task blob. + * Present a pointer to the smack label in the current task blob. */ static inline char *smk_of_current(void) { diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 42becbc..7ba8478 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -67,6 +67,46 @@ static u32 smack_next_secid = 10; int log_policy = SMACK_AUDIT_DENIED; /** + * smk_access_entry - look up matching access rule + * @subject_label: a pointer to the subject's Smack label + * @object_label: a pointer to the object's Smack label + * + * This function looks up the subject/object pair in the + * access rule list and returns pointer to the matching rule if found, + * NULL otherwise. + * + * NOTE: + * Even though Smack labels are usually shared on smack_list + * labels that come in off the network can't be imported + * and added to the list for locking reasons. + * + * Therefore, it is necessary to check the contents of the labels, + * not just the pointer values. Of course, in most cases the labels + * will be on the list, so checking the pointers may be a worthwhile + * optimization. + */ +int smk_access_entry(char *subject_label, char *object_label) +{ + u32 may = MAY_NOT; + struct smack_rule *srp; + + rcu_read_lock(); + list_for_each_entry_rcu(srp, &smack_rule_list, list) { + if (srp->smk_subject == subject_label || + strcmp(srp->smk_subject, subject_label) == 0) { + if (srp->smk_object == object_label || + strcmp(srp->smk_object, object_label) == 0) { + may = srp->smk_access; + break; + } + } + } + rcu_read_unlock(); + + return may; +} + +/** * smk_access - determine if a subject has a specific access to an object * @subject_label: a pointer to the subject's Smack label * @object_label: a pointer to the object's Smack label @@ -90,7 +130,6 @@ int smk_access(char *subject_label, char *object_label, int request, struct smk_audit_info *a) { u32 may = MAY_NOT; - struct smack_rule *srp; int rc = 0; /* @@ -144,18 +183,7 @@ int smk_access(char *subject_label, char *object_label, int request, * access (e.g. read is included in readwrite) it's * good. */ - rcu_read_lock(); - list_for_each_entry_rcu(srp, &smack_rule_list, list) { - if (srp->smk_subject == subject_label || - strcmp(srp->smk_subject, subject_label) == 0) { - if (srp->smk_object == object_label || - strcmp(srp->smk_object, object_label) == 0) { - may = srp->smk_access; - break; - } - } - } - rcu_read_unlock(); + may = smk_access_entry(subject_label, object_label); /* * This is a bit map operation. */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 7e19afe..05dc4da 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3,12 +3,14 @@ * * This file contains the smack hook function implementations. * - * Author: + * Authors: * Casey Schaufler <[email protected]> + * Jarkko Sakkinen <[email protected]> * * Copyright (C) 2007 Casey Schaufler <[email protected]> * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. * Paul Moore <[email protected]> + * Copyright (C) 2010 Nokia Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, @@ -35,6 +37,9 @@ #define task_security(task) (task_cred_xxx((task), security)) +#define TRANS_TRUE "TRUE" +#define TRANS_TRUE_SIZE 4 + /** * smk_fetch - Fetch the smack label from a file. * @ip: a pointer to the inode @@ -468,6 +473,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, char **name, void **value, size_t *len) { char *isp = smk_of_inode(inode); + char *dsp = smk_of_inode(dir); + u32 may; if (name) { *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); @@ -476,6 +483,16 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, } if (value) { + may = smk_access_entry(smk_of_current(), dsp); + + /* + * If the access rule allows transmutation and + * the directory requests transmutation then + * by all means transmute. + */ + if (((may & MAY_TRANSMUTE) != 0) && smk_inode_transmutable(dir)) + isp = dsp; + *value = kstrdup(isp, GFP_KERNEL); if (*value == NULL) return -ENOMEM; @@ -709,6 +726,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, if (size == 0 || size >= SMK_LABELLEN || smk_import(value, size) == NULL) rc = -EINVAL; + } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { + if (!capable(CAP_MAC_ADMIN)) + rc = -EPERM; + if (size != TRANS_TRUE_SIZE || + strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) + rc = -EINVAL; } else rc = cap_inode_setxattr(dentry, name, value, size, flags); @@ -735,35 +758,23 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct inode_smack *isp; char *nsp; - - /* - * Not SMACK or SMACKEXEC - */ - if (strcmp(name, XATTR_NAME_SMACK) && - strcmp(name, XATTR_NAME_SMACKEXEC)) - return; - - isp = dentry->d_inode->i_security; - - /* - * No locking is done here. This is a pointer - * assignment. - */ - nsp = smk_import(value, size); + struct inode_smack *isp = dentry->d_inode->i_security; if (strcmp(name, XATTR_NAME_SMACK) == 0) { + nsp = smk_import(value, size); if (nsp != NULL) isp->smk_inode = nsp; else isp->smk_inode = smack_known_invalid.smk_known; - } else { + } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { + nsp = smk_import(value, size); if (nsp != NULL) isp->smk_task = nsp; else isp->smk_task = smack_known_invalid.smk_known; - } + } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) + isp->smk_flags |= SMK_INODE_TRANSMUTE; return; } @@ -803,7 +814,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) if (strcmp(name, XATTR_NAME_SMACK) == 0 || strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || - strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { + strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || + strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; } else @@ -2274,6 +2286,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) char *csp = smk_of_current(); char *fetched; char *final; + char trattr[TRANS_TRUE_SIZE]; + int transflag = 0; struct dentry *dp; if (inode == NULL) @@ -2392,10 +2406,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ dp = dget(opt_dentry); fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); - if (fetched != NULL) + if (fetched != NULL) { final = fetched; - isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, - dp); + if (S_ISDIR(inode->i_mode)) { + trattr[0] = '\0'; + inode->i_op->getxattr(dp, + XATTR_NAME_SMACKTRANSMUTE, + trattr, TRANS_TRUE_SIZE); + if (strncmp(trattr, TRANS_TRUE, + TRANS_TRUE_SIZE) == 0) + transflag = SMK_INODE_TRANSMUTE; + } + } + isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); dput(dp); break; @@ -2406,7 +2429,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) else isp->smk_inode = final; - isp->smk_flags |= SMK_INODE_INSTANT; + isp->smk_flags |= (SMK_INODE_INSTANT | transflag); unlockandout: mutex_unlock(&isp->smk_lock); @@ -2456,6 +2479,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { struct task_smack *tsp; + struct task_smack *oldtsp; struct cred *new; char *newsmack; @@ -2485,6 +2509,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (newsmack == smack_known_web.smk_known) return -EPERM; + oldtsp = p->cred->security; new = prepare_creds(); if (new == NULL) return -ENOMEM; @@ -2494,6 +2519,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, return -ENOMEM; } tsp->smk_task = newsmack; + tsp->smk_forked = oldtsp->smk_forked; new->security = tsp; commit_creds(new); return size; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 01a0be9..362d5ed 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -109,9 +109,12 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION; * SMK_ACCESSLEN: Maximum length for a rule access field * SMK_LOADLEN: Smack rule length */ -#define SMK_ACCESS "rwxa" -#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) -#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) +#define SMK_OACCESS "rwxa" +#define SMK_ACCESS "rwxat" +#define SMK_OACCESSLEN (sizeof(SMK_OACCESS) - 1) +#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) +#define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) +#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) /** * smk_netlabel_audit_set - fill a netlbl_audit struct @@ -175,6 +178,8 @@ static int load_seq_show(struct seq_file *s, void *v) seq_putc(s, 'x'); if (srp->smk_access & MAY_APPEND) seq_putc(s, 'a'); + if (srp->smk_access & MAY_TRANSMUTE) + seq_putc(s, 't'); if (srp->smk_access == 0) seq_putc(s, '-'); @@ -273,10 +278,15 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, if (!capable(CAP_MAC_ADMIN)) return -EPERM; - if (*ppos != 0 || count != SMK_LOADLEN) + if (*ppos != 0) + return -EINVAL; + /* + * Minor hack for backward compatability + */ + if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) return -EINVAL; - data = kzalloc(count, GFP_KERNEL); + data = kzalloc(SMK_LOADLEN, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -285,6 +295,12 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, goto out; } + /* + * More on the minor hack for backward compatability + */ + if (count == (SMK_OLOADLEN)) + data[SMK_OLOADLEN] = '-'; + rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (rule == NULL) { rc = -ENOMEM; @@ -345,6 +361,17 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, goto out_free_rule; } + switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { + case '-': + break; + case 't': + case 'T': + rule->smk_access |= MAY_TRANSMUTE; + break; + default: + goto out_free_rule; + } + rc = smk_set_access(rule); if (!rc) commit 676dac4b1bee0469d6932f698aeb77e8489f5861 Author: Casey Schaufler <[email protected]> Date: Thu Dec 2 06:43:39 2010 -0800 This patch adds a new security attribute to Smack called SMACK64EXEC. It defines label that is used while task is running. Exception: in smack_task_wait() child task is checked for write access to parent task using label inherited from the task that forked it. Fixed issues from previous submit: - SMACK64EXEC was not read when SMACK64 was not set. - inode security blob was not updated after setting SMACK64EXEC - inode security blob was not updated when removing SMACK64EXEC --- include/linux/xattr.h | 2 + security/smack/smack.h | 30 +++++++ security/smack/smack_access.c | 4 +- security/smack/smack_lsm.c | 192 ++++++++++++++++++++++++++++++----------- security/smack/smackfs.c | 4 +- 5 files changed, 178 insertions(+), 54 deletions(-) diff --git a/include/linux/xattr.h b/include/linux/xattr.h index f1e5bde..351c790 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -40,9 +40,11 @@ #define XATTR_SMACK_SUFFIX "SMACK64" #define XATTR_SMACK_IPIN "SMACK64IPIN" #define XATTR_SMACK_IPOUT "SMACK64IPOUT" +#define XATTR_SMACK_EXEC "SMACK64EXEC" #define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX #define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT +#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC #define XATTR_CAPS_SUFFIX "capability" #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX diff --git a/security/smack/smack.h b/security/smack/smack.h index 43ae747..a2e2cdf 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -51,10 +51,16 @@ struct socket_smack { */ struct inode_smack { char *smk_inode; /* label of the fso */ + char *smk_task; /* label of the task */ struct mutex smk_lock; /* initialization lock */ int smk_flags; /* smack inode flags */ }; +struct task_smack { + char *smk_task; /* label used for access control */ + char *smk_forked; /* label when forked */ +}; + #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ /* @@ -243,6 +249,30 @@ static inline char *smk_of_inode(const struct inode *isp) } /* + * Present a pointer to the smack label in an task blob. + */ +static inline char *smk_of_task(const struct task_smack *tsp) +{ + return tsp->smk_task; +} + +/* + * Present a pointer to the forked smack label in an task blob. + */ +static inline char *smk_of_forked(const struct task_smack *tsp) +{ + return tsp->smk_forked; +} + +/* + * Present a pointer to the smack label in the curren task blob. + */ +static inline char *smk_of_current(void) +{ + return smk_of_task(current_security()); +} + +/* * logging functions */ #define SMACK_AUDIT_DENIED 0x1 diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index f4fac64..42becbc 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -185,7 +185,7 @@ out_audit: int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) { int rc; - char *sp = current_security(); + char *sp = smk_of_current(); rc = smk_access(sp, obj_label, mode, NULL); if (rc == 0) @@ -196,7 +196,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) * only one that gets privilege and current does not * have that label. */ - if (smack_onlycap != NULL && smack_onlycap != current->cred->security) + if (smack_onlycap != NULL && smack_onlycap != sp) goto out_audit; if (capable(CAP_MAC_OVERRIDE)) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 04a98c3..7e19afe 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -43,7 +43,7 @@ * Returns a pointer to the master list entry for the Smack label * or NULL if there was no label to fetch. */ -static char *smk_fetch(struct inode *ip, struct dentry *dp) +static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) { int rc; char in[SMK_LABELLEN]; @@ -51,7 +51,7 @@ static char *smk_fetch(struct inode *ip, struct dentry *dp) if (ip->i_op->getxattr == NULL) return NULL; - rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, in, SMK_LABELLEN); + rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); if (rc < 0) return NULL; @@ -103,8 +103,8 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) if (rc != 0) return rc; - sp = current_security(); - tsp = task_security(ctp); + sp = smk_of_current(); + tsp = smk_of_task(task_security(ctp)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ctp); @@ -138,8 +138,8 @@ static int smack_ptrace_traceme(struct task_struct *ptp) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ptp); - sp = current_security(); - tsp = task_security(ptp); + sp = smk_of_current(); + tsp = smk_of_task(task_security(ptp)); /* we won't log here, because rc can be overriden */ rc = smk_access(tsp, sp, MAY_READWRITE, NULL); if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) @@ -160,7 +160,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) static int smack_syslog(int typefrom_file) { int rc = 0; - char *sp = current_security(); + char *sp = smk_of_current(); if (capable(CAP_MAC_OVERRIDE)) return 0; @@ -391,6 +391,40 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags) } /* + * BPRM hooks + */ + +static int smack_bprm_set_creds(struct linux_binprm *bprm) +{ + struct task_smack *tsp = bprm->cred->security; + struct inode_smack *isp; + struct dentry *dp; + int rc; + + rc = cap_bprm_set_creds(bprm); + if (rc != 0) + return rc; + + if (bprm->cred_prepared) + return 0; + + if (bprm->file == NULL || bprm->file->f_dentry == NULL) + return 0; + + dp = bprm->file->f_dentry; + + if (dp->d_inode == NULL) + return 0; + + isp = dp->d_inode->i_security; + + if (isp->smk_task != NULL) + tsp->smk_task = isp->smk_task; + + return 0; +} + +/* * Inode hooks */ @@ -402,7 +436,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags) */ static int smack_inode_alloc_security(struct inode *inode) { - inode->i_security = new_inode_smack(current_security()); + inode->i_security = new_inode_smack(smk_of_current()); if (inode->i_security == NULL) return -ENOMEM; return 0; @@ -664,7 +698,8 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, if (strcmp(name, XATTR_NAME_SMACK) == 0 || strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || - strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { + strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || + strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; /* @@ -704,9 +739,10 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, char *nsp; /* - * Not SMACK + * Not SMACK or SMACKEXEC */ - if (strcmp(name, XATTR_NAME_SMACK)) + if (strcmp(name, XATTR_NAME_SMACK) && + strcmp(name, XATTR_NAME_SMACKEXEC)) return; isp = dentry->d_inode->i_security; @@ -716,10 +752,18 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, * assignment. */ nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_inode = nsp; - else - isp->smk_inode = smack_known_invalid.smk_known; + + if (strcmp(name, XATTR_NAME_SMACK) == 0) { + if (nsp != NULL) + isp->smk_inode = nsp; + else + isp->smk_inode = smack_known_invalid.smk_known; + } else { + if (nsp != NULL) + isp->smk_task = nsp; + else + isp->smk_task = smack_known_invalid.smk_known; + } return; } @@ -752,12 +796,14 @@ 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 smk_audit_info ad; int rc = 0; if (strcmp(name, XATTR_NAME_SMACK) == 0 || strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || - strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { + strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || + strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; } else @@ -768,6 +814,11 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) if (rc == 0) rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); + if (rc == 0) { + isp = dentry->d_inode->i_security; + isp->smk_task = NULL; + } + return rc; } @@ -895,7 +946,7 @@ static int smack_file_permission(struct file *file, int mask) */ static int smack_file_alloc_security(struct file *file) { - file->f_security = current_security(); + file->f_security = smk_of_current(); return 0; } @@ -1005,7 +1056,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, */ static int smack_file_set_fowner(struct file *file) { - file->f_security = current_security(); + file->f_security = smk_of_current(); return 0; } @@ -1025,7 +1076,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, { struct file *file; int rc; - char *tsp = tsk->cred->security; + char *tsp = smk_of_task(tsk->cred->security); struct smk_audit_info ad; /* @@ -1082,7 +1133,9 @@ static int smack_file_receive(struct file *file) */ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) { - cred->security = NULL; + cred->security = kzalloc(sizeof(struct task_smack), gfp); + if (cred->security == NULL) + return -ENOMEM; return 0; } @@ -1097,7 +1150,7 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) */ static void smack_cred_free(struct cred *cred) { - cred->security = NULL; + kfree(cred->security); } /** @@ -1111,7 +1164,16 @@ static void smack_cred_free(struct cred *cred) static int smack_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - new->security = old->security; + struct task_smack *old_tsp = old->security; + struct task_smack *new_tsp; + + new_tsp = kzalloc(sizeof(struct task_smack), gfp); + if (new_tsp == NULL) + return -ENOMEM; + + new_tsp->smk_task = old_tsp->smk_task; + new_tsp->smk_forked = old_tsp->smk_task; + new->security = new_tsp; return 0; } @@ -1124,7 +1186,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, */ static void smack_cred_transfer(struct cred *new, const struct cred *old) { - new->security = old->security; + struct task_smack *old_tsp = old->security; + struct task_smack *new_tsp = new->security; + + new_tsp->smk_task = old_tsp->smk_task; + new_tsp->smk_forked = old_tsp->smk_task; } /** @@ -1136,12 +1202,13 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) */ static int smack_kernel_act_as(struct cred *new, u32 secid) { + struct task_smack *new_tsp = new->security; char *smack = smack_from_secid(secid); if (smack == NULL) return -EINVAL; - new->security = smack; + new_tsp->smk_task = smack; return 0; } @@ -1157,8 +1224,10 @@ static int smack_kernel_create_files_as(struct cred *new, struct inode *inode) { struct inode_smack *isp = inode->i_security; + struct task_smack *tsp = new->security; - new->security = isp->smk_inode; + tsp->smk_forked = isp->smk_inode; + tsp->smk_task = isp->smk_inode; return 0; } @@ -1175,7 +1244,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - return smk_curacc(task_security(p), access, &ad); + return smk_curacc(smk_of_task(task_security(p)), access, &ad); } /** @@ -1221,7 +1290,7 @@ static int smack_task_getsid(struct task_struct *p) */ static void smack_task_getsecid(struct task_struct *p, u32 *secid) { - *secid = smack_to_secid(task_security(p)); + *secid = smack_to_secid(smk_of_task(task_security(p))); } /** @@ -1333,14 +1402,15 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * can write the receiver. */ if (secid == 0) - return smk_curacc(task_security(p), MAY_WRITE, &ad); + return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE, + &ad); /* * If the secid isn't 0 we're dealing with some USB IO * specific behavior. This is not clean. For one thing * we can't take privilege into account. */ - return smk_access(smack_from_secid(secid), task_security(p), - MAY_WRITE, &ad); + return smk_access(smack_from_secid(secid), + smk_of_task(task_security(p)), MAY_WRITE, &ad); } /** @@ -1352,12 +1422,12 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, static int smack_task_wait(struct task_struct *p) { struct smk_audit_info ad; - char *sp = current_security(); - char *tsp = task_security(p); + char *sp = smk_of_current(); + char *tsp = smk_of_forked(task_security(p)); int rc; /* we don't log here, we can be overriden */ - rc = smk_access(sp, tsp, MAY_WRITE, NULL); + rc = smk_access(tsp, sp, MAY_WRITE, NULL); if (rc == 0) goto out_log; @@ -1378,7 +1448,7 @@ static int smack_task_wait(struct task_struct *p) out_log: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - smack_log(sp, tsp, MAY_WRITE, rc, &ad); + smack_log(tsp, sp, MAY_WRITE, rc, &ad); return rc; } @@ -1392,7 +1462,7 @@ static int smack_task_wait(struct task_struct *p) static void smack_task_to_inode(struct task_struct *p, struct inode *inode) { struct inode_smack *isp = inode->i_security; - isp->smk_inode = task_security(p); + isp->smk_inode = smk_of_task(task_security(p)); } /* @@ -1411,7 +1481,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) { - char *csp = current_security(); + char *csp = smk_of_current(); struct socket_smack *ssp; ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); @@ -1752,7 +1822,7 @@ static int smack_flags_to_may(int flags) */ static int smack_msg_msg_alloc_security(struct msg_msg *msg) { - msg->security = current_security(); + msg->security = smk_of_current(); return 0; } @@ -1788,7 +1858,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp) { struct kern_ipc_perm *isp = &shp->shm_perm; - isp->security = current_security(); + isp->security = smk_of_current(); return 0; } @@ -1911,7 +1981,7 @@ static int smack_sem_alloc_security(struct sem_array *sma) { struct kern_ipc_perm *isp = &sma->sem_perm; - isp->security = current_security(); + isp->security = smk_of_current(); return 0; } @@ -2029,7 +2099,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq) { struct kern_ipc_perm *kisp = &msq->q_perm; - kisp->security = current_security(); + kisp->security = smk_of_current(); return 0; } @@ -2201,7 +2271,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) struct super_block *sbp; struct superblock_smack *sbsp; struct inode_smack *isp; - char *csp = current_security(); + char *csp = smk_of_current(); char *fetched; char *final; struct dentry *dp; @@ -2321,9 +2391,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * Get the dentry for xattr. */ dp = dget(opt_dentry); - fetched = smk_fetch(inode, dp); + fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); if (fetched != NULL) final = fetched; + isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, + dp); + dput(dp); break; } @@ -2358,7 +2431,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) if (strcmp(name, "current") != 0) return -EINVAL; - cp = kstrdup(task_security(p), GFP_KERNEL); + cp = kstrdup(smk_of_task(task_security(p)), GFP_KERNEL); if (cp == NULL) return -ENOMEM; @@ -2382,6 +2455,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) static int smack_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { + struct task_smack *tsp; struct cred *new; char *newsmack; @@ -2414,7 +2488,13 @@ static int smack_setprocattr(struct task_struct *p, char *name, new = prepare_creds(); if (new == NULL) return -ENOMEM; - new->security = newsmack; + tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL); + if (tsp == NULL) { + kfree(new); + return -ENOMEM; + } + tsp->smk_task = newsmack; + new->security = tsp; commit_creds(new); return size; } @@ -2715,7 +2795,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) return; ssp = sk->sk_security; - ssp->smk_in = ssp->smk_out = current_security(); + ssp->smk_in = ssp->smk_out = smk_of_current(); /* cssp->smk_packet is already set in smack_inet_csk_clone() */ } @@ -2836,7 +2916,7 @@ static void smack_inet_csk_clone(struct sock *sk, static int smack_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { - key->security = cred->security; + key->security = smk_of_task(cred->security); return 0; } @@ -2865,6 +2945,7 @@ static int smack_key_permission(key_ref_t key_ref, { struct key *keyp; struct smk_audit_info ad; + char *tsp = smk_of_task(cred->security); keyp = key_ref_to_ptr(key_ref); if (keyp == NULL) @@ -2878,14 +2959,14 @@ static int smack_key_permission(key_ref_t key_ref, /* * This should not occur */ - if (cred->security == NULL) + if (tsp == NULL) return -EACCES; #ifdef CONFIG_AUDIT smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); ad.a.u.key_struct.key = keyp->serial; ad.a.u.key_struct.key_desc = keyp->description; #endif - return smk_access(cred->security, keyp->security, + return smk_access(tsp, keyp->security, MAY_READWRITE, &ad); } #endif /* CONFIG_KEYS */ @@ -3087,6 +3168,8 @@ struct security_operations smack_ops = { .sb_mount = smack_sb_mount, .sb_umount = smack_sb_umount, + .bprm_set_creds = smack_bprm_set_creds, + .inode_alloc_security = smack_inode_alloc_security, .inode_free_security = smack_inode_free_security, .inode_init_security = smack_inode_init_security, @@ -3223,9 +3306,16 @@ static __init void init_smack_know_list(void) static __init int smack_init(void) { struct cred *cred; + struct task_smack *tsp; - if (!security_module_enable(&smack_ops)) + tsp = kzalloc(sizeof(struct task_smack), GFP_KERNEL); + if (tsp == NULL) + return -ENOMEM; + + if (!security_module_enable(&smack_ops)) { + kfree(tsp); return 0; + } printk(KERN_INFO "Smack: Initializing.\n"); @@ -3233,7 +3323,9 @@ static __init int smack_init(void) * Set the security state for the initial task. */ cred = (struct cred *) current->cred; - cred->security = &smack_known_floor.smk_known; + tsp->smk_forked = smack_known_floor.smk_known; + tsp->smk_task = smack_known_floor.smk_known; + cred->security = tsp; /* initialize the smack_know_list */ init_smack_know_list(); diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index dc1fd62..01a0be9 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -121,7 +121,7 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) { nap->loginuid = audit_get_loginuid(current); nap->sessionid = audit_get_sessionid(current); - nap->secid = smack_to_secid(current_security()); + nap->secid = smack_to_secid(smk_of_current()); } /* @@ -1160,7 +1160,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char in[SMK_LABELLEN]; - char *sp = current->cred->security; + char *sp = smk_of_task(current->cred->security); if (!capable(CAP_MAC_ADMIN)) return -EPERM; commit b4e0d5f0791bd6dd12a1c1edea0340969c7c1f90 Author: Casey Schaufler <[email protected]> Date: Wed Nov 24 17:12:10 2010 -0800 Smack: UDS revision This patch addresses a number of long standing issues with the way Smack treats UNIX domain sockets. All access control was being done based on the label of the file system object. This is inconsistant with the internet domain, in which access is done based on the IPIN and IPOUT attributes of the socket. As a result of the inode label policy it was not possible to use a UDS socket for label cognizant services, including dbus and the X11 server. Support for SCM_PEERSEC on UDS sockets is also provided. Signed-off-by: Casey Schaufler <[email protected]> Signed-off-by: James Morris <[email protected]> --- security/smack/smack_lsm.c | 106 ++++++++++++++++++++++++++------------------ 1 files changed, 63 insertions(+), 43 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 489a85a..04a98c3 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1667,10 +1667,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ssp->smk_in = sp; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { ssp->smk_out = sp; - rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); - if (rc != 0) - printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", - __func__, -rc); + if (sock->sk->sk_family != PF_UNIX) { + rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); + if (rc != 0) + printk(KERN_WARNING + "Smack: \"%s\" netlbl error %d.\n", + __func__, -rc); + } } else return -EOPNOTSUPP; @@ -2267,9 +2270,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) break; case SOCKFS_MAGIC: /* - * Casey says sockets get the smack of the task. + * Socket access is controlled by the socket + * structures associated with the task involved. */ - final = csp; + final = smack_known_star.smk_known; break; case PROC_SUPER_MAGIC: /* @@ -2296,7 +2300,16 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) /* * This isn't an understood special case. * Get the value from the xattr. - * + */ + + /* + * UNIX domain sockets use lower level socket data. + */ + if (S_ISSOCK(inode->i_mode)) { + final = smack_known_star.smk_known; + break; + } + /* * No xattr support means, alas, no SMACK label. * Use the aforeapplied default. * It would be curious if the label of the task @@ -2418,14 +2431,18 @@ static int smack_setprocattr(struct task_struct *p, char *name, static int smack_unix_stream_connect(struct socket *sock, struct socket *other, struct sock *newsk) { - struct inode *sp = SOCK_INODE(sock); - struct inode *op = SOCK_INODE(other); + struct socket_smack *ssp = sock->sk->sk_security; + struct socket_smack *osp = other->sk->sk_security; struct smk_audit_info ad; + int rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other->sk); - return smk_access(smk_of_inode(sp), smk_of_inode(op), - MAY_READWRITE, &ad); + + if (!capable(CAP_MAC_OVERRIDE)) + rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + + return rc; } /** @@ -2438,13 +2455,18 @@ static int smack_unix_stream_connect(struct socket *sock, */ static int smack_unix_may_send(struct socket *sock, struct socket *other) { - struct inode *sp = SOCK_INODE(sock); - struct inode *op = SOCK_INODE(other); + struct socket_smack *ssp = sock->sk->sk_security; + struct socket_smack *osp = other->sk->sk_security; struct smk_audit_info ad; + int rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other->sk); - return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad); + + if (!capable(CAP_MAC_OVERRIDE)) + rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + + return rc; } /** @@ -2629,7 +2651,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock, /** * smack_socket_getpeersec_dgram - pull in packet label - * @sock: the socket + * @sock: the peer socket * @skb: packet data * @secid: pointer to where to put the secid of the packet * @@ -2640,41 +2662,39 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, { struct netlbl_lsm_secattr secattr; - struct sock *sk; + struct socket_smack *sp; char smack[SMK_LABELLEN]; - int family = PF_INET; - u32 s; + int family = PF_UNSPEC; + u32 s = 0; /* 0 is the invalid secid */ int rc; - /* - * Only works for families with packets. - */ - if (sock != NULL) { - sk = sock->sk; - if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) - return 0; - family = sk->sk_family; + if (skb != NULL) { + if (skb->protocol == htons(ETH_P_IP)) + family = PF_INET; + else if (skb->protocol == htons(ETH_P_IPV6)) + family = PF_INET6; } - /* - * Translate what netlabel gave us. - */ - netlbl_secattr_init(&secattr); - rc = netlbl_skbuff_getattr(skb, family, &secattr); - if (rc == 0) - smack_from_secattr(&secattr, smack); - netlbl_secattr_destroy(&secattr); - - /* - * Give up if we couldn't get anything - */ - if (rc != 0) - return rc; + if (family == PF_UNSPEC && sock != NULL) + family = sock->sk->sk_family; - s = smack_to_secid(smack); + if (family == PF_UNIX) { + sp = sock->sk->sk_security; + s = smack_to_secid(sp->smk_out); + } else if (family == PF_INET || family == PF_INET6) { + /* + * Translate what netlabel gave us. + */ + netlbl_secattr_init(&secattr); + rc = netlbl_skbuff_getattr(skb, family, &secattr); + if (rc == 0) { + smack_from_secattr(&secattr, smack); + s = smack_to_secid(smack); + } + netlbl_secattr_destroy(&secattr); + } + *secid = s; if (s == 0) return -EINVAL; - - *secid = s; return 0; } _______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
