diff options
Diffstat (limited to 'security/smack')
| -rw-r--r-- | security/smack/smack.h | 110 | ||||
| -rw-r--r-- | security/smack/smack_access.c | 43 | ||||
| -rw-r--r-- | security/smack/smack_lsm.c | 684 | ||||
| -rw-r--r-- | security/smack/smackfs.c | 53 |
4 files changed, 610 insertions, 280 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index 8ad30955e15d..339614c76e63 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -29,6 +29,38 @@ #define SMK_LONGLABEL 256 /* + * This is the repository for labels seen so that it is + * not necessary to keep allocating tiny chuncks of memory + * and so that they can be shared. + * + * Labels are never modified in place. Anytime a label + * is imported (e.g. xattrset on a file) the list is checked + * for it and it is added if it doesn't exist. The address + * is passed out in either case. Entries are added, but + * never deleted. + * + * Since labels are hanging around anyway it doesn't + * hurt to maintain a secid for those awkward situations + * where kernel components that ought to use LSM independent + * interfaces don't. The secid should go away when all of + * these components have been repaired. + * + * The cipso value associated with the label gets stored here, too. + * + * Keep the access rules for this subject label here so that + * the entire set of rules does not need to be examined every + * time. + */ +struct smack_known { + struct list_head list; + char *smk_known; + u32 smk_secid; + struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ + struct list_head smk_rules; /* access rules */ + struct mutex smk_rules_lock; /* lock for rules */ +}; + +/* * Maximum number of bytes for the levels in a CIPSO IP option. * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is * bigger than can be used, and 24 is the next lower multiple @@ -46,25 +78,25 @@ struct superblock_smack { }; struct socket_smack { - char *smk_out; /* outbound label */ - char *smk_in; /* inbound label */ - char *smk_packet; /* TCP peer label */ + struct smack_known *smk_out; /* outbound label */ + char *smk_in; /* inbound label */ + char *smk_packet; /* TCP peer label */ }; /* * Inode smack data */ struct inode_smack { - char *smk_inode; /* label of the fso */ - char *smk_task; /* label of the task */ - char *smk_mmap; /* label of the mmap domain */ - struct mutex smk_lock; /* initialization lock */ - int smk_flags; /* smack inode flags */ + char *smk_inode; /* label of the fso */ + struct smack_known *smk_task; /* label of the task */ + struct smack_known *smk_mmap; /* label of the mmap domain */ + struct mutex smk_lock; /* initialization lock */ + int smk_flags; /* smack inode flags */ }; struct task_smack { - char *smk_task; /* label for access control */ - char *smk_forked; /* label when forked */ + struct smack_known *smk_task; /* label for access control */ + struct smack_known *smk_forked; /* label when forked */ struct list_head smk_rules; /* per task access rules */ struct mutex smk_rules_lock; /* lock for the rules */ }; @@ -78,7 +110,7 @@ struct task_smack { */ struct smack_rule { struct list_head list; - char *smk_subject; + struct smack_known *smk_subject; char *smk_object; int smk_access; }; @@ -94,35 +126,14 @@ struct smk_netlbladdr { }; /* - * This is the repository for labels seen so that it is - * not necessary to keep allocating tiny chuncks of memory - * and so that they can be shared. - * - * Labels are never modified in place. Anytime a label - * is imported (e.g. xattrset on a file) the list is checked - * for it and it is added if it doesn't exist. The address - * is passed out in either case. Entries are added, but - * never deleted. - * - * Since labels are hanging around anyway it doesn't - * hurt to maintain a secid for those awkward situations - * where kernel components that ought to use LSM independent - * interfaces don't. The secid should go away when all of - * these components have been repaired. - * - * The cipso value associated with the label gets stored here, too. - * - * Keep the access rules for this subject label here so that - * the entire set of rules does not need to be examined every - * time. + * An entry in the table identifying ports. */ -struct smack_known { - struct list_head list; - char *smk_known; - u32 smk_secid; - struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ - struct list_head smk_rules; /* access rules */ - struct mutex smk_rules_lock; /* lock for rules */ +struct smk_port_label { + struct list_head list; + struct sock *smk_sock; /* socket initialized on */ + unsigned short smk_port; /* the port number */ + char *smk_in; /* incoming label */ + struct smack_known *smk_out; /* outgoing label */ }; /* @@ -132,6 +143,7 @@ struct smack_known { #define SMK_FSFLOOR "smackfsfloor=" #define SMK_FSHAT "smackfshat=" #define SMK_FSROOT "smackfsroot=" +#define SMK_FSTRANS "smackfstransmute=" #define SMACK_CIPSO_OPTION "-CIPSO" @@ -203,9 +215,9 @@ struct inode_smack *new_inode_smack(char *); * These functions are in smack_access.c */ int smk_access_entry(char *, char *, struct list_head *); -int smk_access(char *, char *, int, struct smk_audit_info *); +int smk_access(struct smack_known *, char *, int, struct smk_audit_info *); int smk_curacc(char *, u32, struct smk_audit_info *); -char *smack_from_secid(const u32); +struct smack_known *smack_from_secid(const u32); char *smk_parse_smack(const char *string, int len); int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); char *smk_import(const char *, int); @@ -218,7 +230,7 @@ u32 smack_to_secid(const char *); */ extern int smack_cipso_direct; extern int smack_cipso_mapped; -extern char *smack_net_ambient; +extern struct smack_known *smack_net_ambient; extern char *smack_onlycap; extern const char *smack_cipso_option; @@ -254,17 +266,17 @@ static inline char *smk_of_inode(const struct inode *isp) } /* - * Present a pointer to the smack label in an task blob. + * Present a pointer to the smack label entry in an task blob. */ -static inline char *smk_of_task(const struct task_smack *tsp) +static inline struct smack_known *smk_of_task(const struct task_smack *tsp) { return tsp->smk_task; } /* - * Present a pointer to the forked smack label in an task blob. + * Present a pointer to the forked smack label entry in an task blob. */ -static inline char *smk_of_forked(const struct task_smack *tsp) +static inline struct smack_known *smk_of_forked(const struct task_smack *tsp) { return tsp->smk_forked; } @@ -272,7 +284,7 @@ static inline char *smk_of_forked(const struct task_smack *tsp) /* * Present a pointer to the smack label in the current task blob. */ -static inline char *smk_of_current(void) +static inline struct smack_known *smk_of_current(void) { return smk_of_task(current_security()); } @@ -283,9 +295,11 @@ static inline char *smk_of_current(void) */ static inline int smack_privileged(int cap) { + struct smack_known *skp = smk_of_current(); + if (!capable(cap)) return 0; - if (smack_onlycap == NULL || smack_onlycap == smk_of_current()) + if (smack_onlycap == NULL || smack_onlycap == skp->smk_known) return 1; return 0; } diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 2e397a88d410..6a0377f38620 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -93,7 +93,7 @@ int smk_access_entry(char *subject_label, char *object_label, list_for_each_entry_rcu(srp, rule_list, list) { if (srp->smk_object == object_label && - srp->smk_subject == subject_label) { + srp->smk_subject->smk_known == subject_label) { may = srp->smk_access; break; } @@ -104,7 +104,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_label: a pointer to the subject's Smack label + * @subject_known: a pointer to the subject's Smack label entry * @object_label: a pointer to the object's Smack label * @request: the access requested, in "MAY" format * @a : a pointer to the audit data @@ -115,10 +115,9 @@ int smk_access_entry(char *subject_label, char *object_label, * * Smack labels are shared on smack_list */ -int smk_access(char *subject_label, char *object_label, int request, - struct smk_audit_info *a) +int smk_access(struct smack_known *subject_known, char *object_label, + int request, struct smk_audit_info *a) { - struct smack_known *skp; int may = MAY_NOT; int rc = 0; @@ -127,7 +126,7 @@ int smk_access(char *subject_label, char *object_label, int request, * * A star subject can't access any object. */ - if (subject_label == smack_known_star.smk_known) { + if (subject_known == &smack_known_star) { rc = -EACCES; goto out_audit; } @@ -137,7 +136,7 @@ int smk_access(char *subject_label, char *object_label, int request, * An internet subject can access any object. */ if (object_label == smack_known_web.smk_known || - subject_label == smack_known_web.smk_known) + subject_known == &smack_known_web) goto out_audit; /* * A star object can be accessed by any subject. @@ -148,7 +147,7 @@ int smk_access(char *subject_label, char *object_label, int request, * An object can be accessed in any way by a subject * with the same label. */ - if (subject_label == object_label) + if (subject_known->smk_known == object_label) goto out_audit; /* * A hat subject can read any object. @@ -157,7 +156,7 @@ int smk_access(char *subject_label, char *object_label, int request, if ((request & MAY_ANYREAD) == request) { if (object_label == smack_known_floor.smk_known) goto out_audit; - if (subject_label == smack_known_hat.smk_known) + if (subject_known == &smack_known_hat) goto out_audit; } /* @@ -167,9 +166,9 @@ int smk_access(char *subject_label, char *object_label, int request, * good. A negative response from smk_access_entry() * indicates there is no entry for this pair. */ - skp = smk_find_entry(subject_label); rcu_read_lock(); - may = smk_access_entry(subject_label, object_label, &skp->smk_rules); + may = smk_access_entry(subject_known->smk_known, object_label, + &subject_known->smk_rules); rcu_read_unlock(); if (may > 0 && (request & may) == request) @@ -179,7 +178,8 @@ int smk_access(char *subject_label, char *object_label, int request, out_audit: #ifdef CONFIG_AUDIT if (a) - smack_log(subject_label, object_label, request, rc, a); + smack_log(subject_known->smk_known, object_label, request, + rc, a); #endif return rc; } @@ -198,20 +198,21 @@ out_audit: int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) { struct task_smack *tsp = current_security(); - char *sp = smk_of_task(tsp); + struct smack_known *skp = smk_of_task(tsp); int may; int rc; /* * Check the global rule list */ - rc = smk_access(sp, obj_label, mode, NULL); + rc = smk_access(skp, obj_label, mode, NULL); if (rc == 0) { /* * If there is an entry in the task's rule list * it can further restrict access. */ - may = smk_access_entry(sp, obj_label, &tsp->smk_rules); + may = smk_access_entry(skp->smk_known, obj_label, + &tsp->smk_rules); if (may < 0) goto out_audit; if ((mode & may) == mode) @@ -228,7 +229,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) out_audit: #ifdef CONFIG_AUDIT if (a) - smack_log(sp, obj_label, mode, rc, a); + smack_log(skp->smk_known, obj_label, mode, rc, a); #endif return rc; } @@ -402,6 +403,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, sap->flags |= NETLBL_SECATTR_MLS_CAT; sap->attr.mls.lvl = level; sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + if (!sap->attr.mls.cat) + return -ENOMEM; sap->attr.mls.cat->startbit = 0; for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) @@ -513,10 +516,10 @@ char *smk_import(const char *string, int len) * smack_from_secid - find the Smack label associated with a secid * @secid: an integer that might be associated with a Smack label * - * Returns a pointer to the appropriate Smack label if there is one, + * Returns a pointer to the appropriate Smack label entry if there is one, * otherwise a pointer to the invalid Smack label. */ -char *smack_from_secid(const u32 secid) +struct smack_known *smack_from_secid(const u32 secid) { struct smack_known *skp; @@ -524,7 +527,7 @@ char *smack_from_secid(const u32 secid) list_for_each_entry_rcu(skp, &smack_known_list, list) { if (skp->smk_secid == secid) { rcu_read_unlock(); - return skp->smk_known; + return skp; } } @@ -533,7 +536,7 @@ char *smack_from_secid(const u32 secid) * of a secid that is not on the list. */ rcu_read_unlock(); - return smack_known_invalid.smk_known; + return &smack_known_invalid; } /** diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d52c780bdb78..6a083303501d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -27,10 +27,13 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> +#include <linux/dccp.h> #include <linux/slab.h> #include <linux/mutex.h> #include <linux/pipe_fs_i.h> #include <net/cipso_ipv4.h> +#include <net/ip.h> +#include <net/ipv6.h> #include <linux/audit.h> #include <linux/magic.h> #include <linux/dcache.h> @@ -45,6 +48,12 @@ #define TRANS_TRUE "TRUE" #define TRANS_TRUE_SIZE 4 +#define SMK_CONNECTING 0 +#define SMK_RECEIVING 1 +#define SMK_SENDING 2 + +LIST_HEAD(smk_ipv6_port_list); + /** * smk_fetch - Fetch the smack label from a file. * @ip: a pointer to the inode @@ -53,11 +62,12 @@ * 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(const char *name, struct inode *ip, struct dentry *dp) +static struct smack_known *smk_fetch(const char *name, struct inode *ip, + struct dentry *dp) { int rc; char *buffer; - char *result = NULL; + struct smack_known *skp = NULL; if (ip->i_op->getxattr == NULL) return NULL; @@ -68,11 +78,11 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); if (rc > 0) - result = smk_import(buffer, rc); + skp = smk_import_entry(buffer, rc); kfree(buffer); - return result; + return skp; } /** @@ -102,7 +112,8 @@ struct inode_smack *new_inode_smack(char *smack) * * Returns the new blob or NULL if there's no memory available */ -static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp) +static struct task_smack *new_task_smack(struct smack_known *task, + struct smack_known *forked, gfp_t gfp) { struct task_smack *tsp; @@ -164,17 +175,17 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) { int rc; struct smk_audit_info ad; - char *tsp; + struct smack_known *skp; rc = cap_ptrace_access_check(ctp, mode); if (rc != 0) return rc; - tsp = smk_of_task(task_security(ctp)); + skp = smk_of_task(task_security(ctp)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ctp); - rc = smk_curacc(tsp, MAY_READWRITE, &ad); + rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad); return rc; } @@ -190,17 +201,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp) { int rc; struct smk_audit_info ad; - char *tsp; + struct smack_known *skp; rc = cap_ptrace_traceme(ptp); if (rc != 0) return rc; - tsp = smk_of_task(task_security(ptp)); + skp = smk_of_task(task_security(ptp)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, ptp); - rc = smk_curacc(tsp, MAY_READWRITE, &ad); + rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad); return rc; } @@ -215,12 +226,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp) static int smack_syslog(int typefrom_file) { int rc = 0; - char *sp = smk_of_current(); + struct smack_known *skp = smk_of_current(); if (smack_privileged(CAP_MAC_OVERRIDE)) return 0; - if (sp != smack_known_floor.smk_known) + if (skp != &smack_known_floor) rc = -EACCES; return rc; @@ -250,8 +261,9 @@ static int smack_sb_alloc_security(struct super_block *sb) sbsp->smk_default = smack_known_floor.smk_known; sbsp->smk_floor = smack_known_floor.smk_known; sbsp->smk_hat = smack_known_hat.smk_known; - sbsp->smk_initialized = 0; - + /* + * smk_initialized will be zero from kzalloc. + */ sb->s_security = sbsp; return 0; @@ -295,6 +307,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts) dp = smackopts; else if (strstr(cp, SMK_FSROOT) == cp) dp = smackopts; + else if (strstr(cp, SMK_FSTRANS) == cp) + dp = smackopts; else dp = otheropts; @@ -330,8 +344,9 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) char *op; char *commap; char *nsp; + int transmute = 0; - if (sp->smk_initialized != 0) + if (sp->smk_initialized) return 0; sp->smk_initialized = 1; @@ -362,6 +377,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) nsp = smk_import(op, 0); if (nsp != NULL) sp->smk_root = nsp; + } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { + op += strlen(SMK_FSTRANS); + nsp = smk_import(op, 0); + if (nsp != NULL) { + sp->smk_root = nsp; + transmute = 1; + } } } @@ -369,11 +391,15 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) * Initialize the root inode. */ isp = inode->i_security; - if (isp == NULL) + if (inode->i_security == NULL) { inode->i_security = new_inode_smack(sp->smk_root); - else + isp = inode->i_security; + } else isp->smk_inode = sp->smk_root; + if (transmute) + isp->smk_flags |= SMK_INODE_TRANSMUTE; + return 0; } @@ -524,7 +550,9 @@ static int smack_bprm_secureexec(struct linux_binprm *bprm) */ static int smack_inode_alloc_security(struct inode *inode) { - inode->i_security = new_inode_smack(smk_of_current()); + struct smack_known *skp = smk_of_current(); + + inode->i_security = new_inode_smack(skp->smk_known); if (inode->i_security == NULL) return -ENOMEM; return 0; @@ -557,9 +585,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, char **name, void **value, size_t *len) { - struct smack_known *skp; struct inode_smack *issp = inode->i_security; - char *csp = smk_of_current(); + struct smack_known *skp = smk_of_current(); char *isp = smk_of_inode(inode); char *dsp = smk_of_inode(dir); int may; @@ -571,9 +598,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, } if (value) { - skp = smk_find_entry(csp); rcu_read_lock(); - may = smk_access_entry(csp, dsp, &skp->smk_rules); + may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules); rcu_read_unlock(); /* @@ -862,29 +888,31 @@ 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) { - char *nsp; + struct smack_known *skp; struct inode_smack *isp = dentry->d_inode->i_security; + if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { + isp->smk_flags |= SMK_INODE_TRANSMUTE; + return; + } + + skp = smk_import_entry(value, size); if (strcmp(name, XATTR_NAME_SMACK) == 0) { - nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_inode = nsp; + if (skp != NULL) + isp->smk_inode = skp->smk_known; else isp->smk_inode = smack_known_invalid.smk_known; } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { - nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_task = nsp; + if (skp != NULL) + isp->smk_task = skp; else - isp->smk_task = smack_known_invalid.smk_known; + isp->smk_task = &smack_known_invalid; } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { - nsp = smk_import(value, size); - if (nsp != NULL) - isp->smk_mmap = nsp; + if (skp != NULL) + isp->smk_mmap = skp; else - isp->smk_mmap = smack_known_invalid.smk_known; - } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) - isp->smk_flags |= SMK_INODE_TRANSMUTE; + isp->smk_mmap = &smack_known_invalid; + } return; } @@ -990,7 +1018,7 @@ static int smack_inode_getsecurity(const struct inode *inode, if (strcmp(name, XATTR_SMACK_IPIN) == 0) isp = ssp->smk_in; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) - isp = ssp->smk_out; + isp = ssp->smk_out->smk_known; else return -EOPNOTSUPP; @@ -1070,7 +1098,9 @@ static int smack_file_permission(struct file *file, int mask) */ static int smack_file_alloc_security(struct file *file) { - file->f_security = smk_of_current(); + struct smack_known *skp = smk_of_current(); + + file->f_security = skp->smk_known; return 0; } @@ -1181,10 +1211,9 @@ static int smack_mmap_file(struct file *file, unsigned long flags) { struct smack_known *skp; + struct smack_known *mkp; struct smack_rule *srp; struct task_smack *tsp; - char *sp; - char *msmack; char *osmack; struct inode_smack *isp; int may; @@ -1198,11 +1227,10 @@ static int smack_mmap_file(struct file *file, isp = file_inode(file)->i_security; if (isp->smk_mmap == NULL) return 0; - msmack = isp->smk_mmap; + mkp = isp->smk_mmap; tsp = current_security(); - sp = smk_of_current(); - skp = smk_find_entry(sp); + skp = smk_of_current(); rc = 0; rcu_read_lock(); @@ -1216,13 +1244,13 @@ static int smack_mmap_file(struct file *file, /* * Matching labels always allows access. */ - if (msmack == osmack) + if (mkp->smk_known == osmack) continue; /* * If there is a matching local rule take * that into account as well. */ - may = smk_access_entry(srp->smk_subject, osmack, + may = smk_access_entry(srp->smk_subject->smk_known, osmack, &tsp->smk_rules); if (may == -ENOENT) may = srp->smk_access; @@ -1240,8 +1268,8 @@ static int smack_mmap_file(struct file *file, * If there isn't one a SMACK64MMAP subject * can't have as much access as current. */ - skp = smk_find_entry(msmack); - mmay = smk_access_entry(msmack, osmack, &skp->smk_rules); + mmay = smk_access_entry(mkp->smk_known, osmack, + &mkp->smk_rules); if (mmay == -ENOENT) { rc = -EACCES; break; @@ -1250,7 +1278,8 @@ static int smack_mmap_file(struct file *file, * If there is a local entry it modifies the * potential access, too. */ - tmay = smk_access_entry(msmack, osmack, &tsp->smk_rules); + tmay = smk_access_entry(mkp->smk_known, osmack, + &tsp->smk_rules); if (tmay != -ENOENT) mmay &= tmay; @@ -1279,7 +1308,9 @@ static int smack_mmap_file(struct file *file, */ static int smack_file_set_fowner(struct file *file) { - file->f_security = smk_of_current(); + struct smack_known *skp = smk_of_current(); + + file->f_security = skp->smk_known; return 0; } @@ -1297,9 +1328,10 @@ static int smack_file_set_fowner(struct file *file) 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 file *file; int rc; - char *tsp = smk_of_task(tsk->cred->security); struct smk_audit_info ad; /* @@ -1308,13 +1340,14 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, file = container_of(fown, struct file, f_owner); /* we don't log here as rc can be overriden */ - rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); + skp = smk_find_entry(file->f_security); + rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, tsk); - smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad); + smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad); return rc; } @@ -1469,12 +1502,12 @@ 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); + struct smack_known *skp = smack_from_secid(secid); - if (smack == NULL) + if (skp == NULL) return -EINVAL; - new_tsp->smk_task = smack; + new_tsp->smk_task = skp; return 0; } @@ -1492,8 +1525,8 @@ static int smack_kernel_create_files_as(struct cred *new, struct inode_smack *isp = inode->i_security; struct task_smack *tsp = new->security; - tsp->smk_forked = isp->smk_inode; - tsp->smk_task = isp->smk_inode; + tsp->smk_forked = smk_find_entry(isp->smk_inode); + tsp->smk_task = tsp->smk_forked; return 0; } @@ -1509,10 +1542,11 @@ 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(task_security(p)); smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); - return smk_curacc(smk_of_task(task_security(p)), access, &ad); + return smk_curacc(skp->smk_known, access, &ad); } /** @@ -1558,7 +1592,9 @@ static int smack_task_getsid(struct task_struct *p) */ static void smack_task_getsecid(struct task_struct *p, u32 *secid) { - *secid = smack_to_secid(smk_of_task(task_security(p))); + struct smack_known *skp = smk_of_task(task_security(p)); + + *secid = skp->smk_secid; } /** @@ -1662,6 +1698,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { struct smk_audit_info ad; + struct smack_known *skp; + struct smack_known *tkp = smk_of_task(task_security(p)); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); @@ -1670,15 +1708,14 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, * can write the receiver. */ if (secid == 0) - return smk_curacc(smk_of_task(task_security(p)), MAY_WRITE, - &ad); + return smk_curacc(tkp->smk_known, 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), - smk_of_task(task_security(p)), MAY_WRITE, &ad); + skp = smack_from_secid(secid); + return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad); } /** @@ -1710,7 +1747,9 @@ 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 = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task(task_security(p)); + + isp->smk_inode = skp->smk_known; } /* @@ -1729,15 +1768,15 @@ 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 = smk_of_current(); + struct smack_known *skp = smk_of_current(); struct socket_smack *ssp; ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); if (ssp == NULL) return -ENOMEM; - ssp->smk_in = csp; - ssp->smk_out = csp; + ssp->smk_in = skp->smk_known; + ssp->smk_out = skp; ssp->smk_packet = NULL; sk->sk_security = ssp; @@ -1824,7 +1863,7 @@ static int smack_netlabel(struct sock *sk, int labeled) labeled == SMACK_UNLABELED_SOCKET) netlbl_sock_delattr(sk); else { - skp = smk_find_entry(ssp->smk_out); + skp = ssp->smk_out; rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); } @@ -1847,6 +1886,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; int rc; int sk_lbl; char *hostsp; @@ -1865,7 +1905,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr; #endif sk_lbl = SMACK_UNLABELED_SOCKET; - rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); + skp = ssp->smk_out; + rc = smk_access(skp, hostsp, MAY_WRITE, &ad); } else { sk_lbl = SMACK_CIPSO_SOCKET; rc = 0; @@ -1878,6 +1919,155 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) } /** + * smk_ipv6_port_label - Smack port access table management + * @sock: socket + * @address: address + * + * Create or update the port list entry + */ +static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) +{ + struct sock *sk = sock->sk; + struct sockaddr_in6 *addr6; + struct socket_smack *ssp = sock->sk->sk_security; + struct smk_port_label *spp; + unsigned short port = 0; + + if (address == NULL) { + /* + * This operation is changing the Smack information + * on the bound socket. Take the changes to the port + * as well. + */ + list_for_each_entry(spp, &smk_ipv6_port_list, list) { + if (sk != spp->smk_sock) + continue; + spp->smk_in = ssp->smk_in; + spp->smk_out = ssp->smk_out; + return; + } + /* + * A NULL address is only used for updating existing + * bound entries. If there isn't one, it's OK. + */ + return; + } + + addr6 = (struct sockaddr_in6 *)address; + port = ntohs(addr6->sin6_port); + /* + * This is a special case that is safely ignored. + */ + if (port == 0) + return; + + /* + * Look for an existing port list entry. + * This is an indication that a port is getting reused. + */ + list_for_each_entry(spp, &smk_ipv6_port_list, list) { + if (spp->smk_port != port) + continue; + spp->smk_port = port; + spp->smk_sock = sk; + spp->smk_in = ssp->smk_in; + spp->smk_out = ssp->smk_out; + return; + } + + /* + * A new port entry is required. + */ + spp = kzalloc(sizeof(*spp), GFP_KERNEL); + if (spp == NULL) + return; + + spp->smk_port = port; + spp->smk_sock = sk; + spp->smk_in = ssp->smk_in; + spp->smk_out = ssp->smk_out; + + list_add(&spp->list, &smk_ipv6_port_list); + return; +} + +/** + * smk_ipv6_port_check - check Smack port access + * @sock: socket + * @address: address + * + * Create or update the port list entry + */ +static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address, + int act) +{ + __be16 *bep; + __be32 *be32p; + struct sockaddr_in6 *addr6; + struct smk_port_label *spp; + struct socket_smack *ssp = sk->sk_security; + struct smack_known *skp; + unsigned short port = 0; + char *object; + struct smk_audit_info ad; +#ifdef CONFIG_AUDIT + struct lsm_network_audit net; +#endif + + if (act == SMK_RECEIVING) { + skp = smack_net_ambient; + object = ssp->smk_in; + } else { + skp = ssp->smk_out; + object = smack_net_ambient->smk_known; + } + + /* + * Get the IP address and port from the address. + */ + addr6 = (struct sockaddr_in6 *)address; + port = ntohs(addr6->sin6_port); + bep = (__be16 *)(&addr6->sin6_addr); + be32p = (__be32 *)(&addr6->sin6_addr); + + /* + * It's remote, so port lookup does no good. + */ + if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1) + goto auditout; + + /* + * It's local so the send check has to have passed. + */ + if (act == SMK_RECEIVING) { + skp = &smack_known_web; + goto auditout; + } + + list_for_each_entry(spp, &smk_ipv6_port_list, list) { + if (spp->smk_port != port) + continue; + object = spp->smk_in; + if (act == SMK_CONNECTING) + ssp->smk_packet = spp->smk_out->smk_known; + break; + } + +auditout: + +#ifdef CONFIG_AUDIT + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); + ad.a.u.net->family = sk->sk_family; + ad.a.u.net->dport = port; + if (act == SMK_RECEIVING) + ad.a.u.net->v6info.saddr = addr6->sin6_addr; + else + ad.a.u.net->v6info.daddr = addr6->sin6_addr; +#endif + return smk_access(skp, object, MAY_WRITE, &ad); +} + +/** * smack_inode_setsecurity - set smack xattrs * @inode: the object * @name: attribute name @@ -1892,7 +2082,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) static int smack_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { - char *sp; + struct smack_known *skp; struct inode_smack *nsp = inode->i_security; struct socket_smack *ssp; struct socket *sock; @@ -1901,12 +2091,12 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, if (value == NULL || size > SMK_LONGLABEL || size == 0) return -EACCES; - sp = smk_import(value, size); - if (sp == NULL) + skp = smk_import_entry(value, size); + if (skp == NULL) return -EINVAL; if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { - nsp->smk_inode = sp; + nsp->smk_inode = skp->smk_known; nsp->smk_flags |= SMK_INODE_INSTANT; return 0; } @@ -1923,10 |
