diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-25 02:46:49 +0200 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-25 02:46:49 +0200 |
commit | 549367162dfdc75d573f74f4e2891f2dba41582f (patch) | |
tree | 7f95551ed7b4f3e4289dbbfac689f5728616f3f1 /security | |
parent | 328aa7a45af61bc0060c80847daa67fef7b9c0d0 (diff) | |
download | kernel_samsung_smdk4412-549367162dfdc75d573f74f4e2891f2dba41582f.zip kernel_samsung_smdk4412-549367162dfdc75d573f74f4e2891f2dba41582f.tar.gz kernel_samsung_smdk4412-549367162dfdc75d573f74f4e2891f2dba41582f.tar.bz2 |
remove galaxys2 initramsfs files and busybox binary, get sound merged with 3.0.101 (samsung code untouched), remove compat, scripts and security merged
Diffstat (limited to 'security')
-rw-r--r-- | security/security.c | 1 | ||||
-rw-r--r-- | security/smack/smack.h | 84 | ||||
-rw-r--r-- | security/smack/smack_access.c | 346 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 480 | ||||
-rw-r--r-- | security/smack/smackfs.c | 1337 |
5 files changed, 719 insertions, 1529 deletions
diff --git a/security/security.c b/security/security.c index f19f945..4ba6d4c 100644 --- a/security/security.c +++ b/security/security.c @@ -626,7 +626,6 @@ int security_file_permission(struct file *file, int mask) return fsnotify_perm(file, mask); } -EXPORT_SYMBOL_GPL(security_file_permission); int security_file_alloc(struct file *file) { diff --git a/security/smack/smack.h b/security/smack/smack.h index 618de1f..2b6c6a5 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -23,19 +23,13 @@ #include <linux/lsm_audit.h> /* - * Smack labels were limited to 23 characters for a long time. - */ -#define SMK_LABELLEN 24 -#define SMK_LONGLABEL 256 - -/* - * 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 * of 8, and there are too many issues if there isn't space set * aside for the terminating null byte. */ -#define SMK_CIPSOLEN 24 +#define SMK_MAXLEN 23 +#define SMK_LABELLEN (SMK_MAXLEN+1) struct superblock_smack { char *smk_root; @@ -47,9 +41,9 @@ struct superblock_smack { }; struct socket_smack { - char *smk_out; /* outbound label */ - char *smk_in; /* inbound label */ - char *smk_packet; /* TCP peer label */ + char *smk_out; /* outbound label */ + char *smk_in; /* inbound label */ + char smk_packet[SMK_LABELLEN]; /* TCP peer label */ }; /* @@ -72,7 +66,6 @@ struct task_smack { #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ -#define SMK_INODE_CHANGED 0x04 /* smack was transmuted */ /* * A label access rule. @@ -85,6 +78,15 @@ struct smack_rule { }; /* + * An entry in the table mapping smack values to + * CIPSO level/category-set values. + */ +struct smack_cipso { + int smk_level; + char smk_catset[SMK_LABELLEN]; +}; + +/* * An entry in the table identifying hosts. */ struct smk_netlbladdr { @@ -111,19 +113,16 @@ struct smk_netlbladdr { * 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. + * If there is a cipso value associated with the label it + * gets stored here, too. This will most likely be rare as + * the cipso direct mapping in used internally. */ 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 list_head list; + char smk_known[SMK_LABELLEN]; + u32 smk_secid; + struct smack_cipso *smk_cipso; + spinlock_t smk_cipsolock; /* for changing cipso map */ }; /* @@ -151,6 +150,7 @@ struct smack_known { /* * smackfs magic number + * smackfs macic number */ #define SMACK_MAGIC 0x43415d53 /* "SMAC" */ @@ -160,7 +160,6 @@ struct smack_known { #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ -#define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ @@ -177,9 +176,9 @@ struct smack_known { #define MAY_NOT 0 /* - * Number of access types used by Smack (rwxat) + * Number of access types used by Smack (rwxa) */ -#define SMK_NUM_ACCESS_TYPE 5 +#define SMK_NUM_ACCESS_TYPE 4 /* * Smack audit data; is empty if CONFIG_AUDIT not set @@ -201,19 +200,17 @@ struct inode_smack *new_inode_smack(char *); int smk_access_entry(char *, char *, struct list_head *); 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 *); +void smack_from_cipso(u32, char *, char *); char *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); struct smack_known *smk_import_entry(const char *, int); -struct smack_known *smk_find_entry(const char *); u32 smack_to_secid(const char *); /* * Shared data. */ extern int smack_cipso_direct; -extern int smack_cipso_mapped; extern char *smack_net_ambient; extern char *smack_onlycap; extern const char *smack_cipso_option; @@ -225,13 +222,25 @@ extern struct smack_known smack_known_invalid; extern struct smack_known smack_known_star; extern struct smack_known smack_known_web; -extern struct mutex smack_known_lock; extern struct list_head smack_known_list; +extern struct list_head smack_rule_list; extern struct list_head smk_netlbladdr_list; extern struct security_operations smack_ops; /* + * Stricly for CIPSO level manipulation. + * Set the category bit number in a smack label sized buffer. + */ +static inline void smack_catset_bit(int cat, char *catsetp) +{ + if (cat > SMK_LABELLEN * 8) + return; + + catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); +} + +/* * Is the directory transmuting? */ static inline int smk_inode_transmutable(const struct inode *isp) @@ -274,19 +283,6 @@ static inline char *smk_of_current(void) } /* - * Is the task privileged and allowed to be privileged - * by the onlycap rule. - */ -static inline int smack_privileged(int cap) -{ - if (!capable(cap)) - return 0; - if (smack_onlycap == NULL || smack_onlycap == smk_of_current()) - return 1; - return 0; -} - -/* * logging functions */ #define SMACK_AUDIT_DENIED 0x1 diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 425a6a2..9637e10 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -19,31 +19,37 @@ struct smack_known smack_known_huh = { .smk_known = "?", .smk_secid = 2, + .smk_cipso = NULL, }; struct smack_known smack_known_hat = { .smk_known = "^", .smk_secid = 3, + .smk_cipso = NULL, }; struct smack_known smack_known_star = { .smk_known = "*", .smk_secid = 4, + .smk_cipso = NULL, }; struct smack_known smack_known_floor = { .smk_known = "_", .smk_secid = 5, + .smk_cipso = NULL, }; struct smack_known smack_known_invalid = { .smk_known = "", .smk_secid = 6, + .smk_cipso = NULL, }; struct smack_known smack_known_web = { .smk_known = "@", .smk_secid = 7, + .smk_cipso = NULL, }; LIST_HEAD(smack_known_list); @@ -71,19 +77,14 @@ int log_policy = SMACK_AUDIT_DENIED; * entry is found returns -ENOENT. * * 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. * - * Earlier versions of this function allowed for labels that - * were not on the label list. This was done to allow for - * labels to come over the network that had never been seen - * before on this host. Unless the receiving socket has the - * star label this will always result in a failure check. The - * star labeled socket case is now handled in the networking - * hooks so there is no case where the label is not on the - * label list. Checking to see if the address of two labels - * is the same is now a reliable test. - * - * Do the object check first because that is more - * likely to differ. + * 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, struct list_head *rule_list) @@ -92,10 +93,13 @@ int smk_access_entry(char *subject_label, char *object_label, struct smack_rule *srp; list_for_each_entry_rcu(srp, rule_list, list) { - if (srp->smk_object == object_label && - srp->smk_subject == subject_label) { - may = srp->smk_access; - break; + 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; + } } } @@ -113,12 +117,18 @@ int smk_access_entry(char *subject_label, char *object_label, * access rule list and returns 0 if the access is permitted, * non zero otherwise. * - * Smack labels are shared on smack_list + * 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(char *subject_label, char *object_label, int request, struct smk_audit_info *a) { - struct smack_known *skp; int may = MAY_NOT; int rc = 0; @@ -127,7 +137,8 @@ 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_label == smack_known_star.smk_known || + strcmp(subject_label, smack_known_star.smk_known) == 0) { rc = -EACCES; goto out_audit; } @@ -137,27 +148,33 @@ 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_label == smack_known_web.smk_known || + strcmp(object_label, smack_known_web.smk_known) == 0 || + strcmp(subject_label, smack_known_web.smk_known) == 0) goto out_audit; /* * A star object can be accessed by any subject. */ - if (object_label == smack_known_star.smk_known) + if (object_label == smack_known_star.smk_known || + strcmp(object_label, smack_known_star.smk_known) == 0) goto out_audit; /* * An object can be accessed in any way by a subject * with the same label. */ - if (subject_label == object_label) + if (subject_label == object_label || + strcmp(subject_label, object_label) == 0) goto out_audit; /* * A hat subject can read any object. * A floor object can be read by any subject. */ if ((request & MAY_ANYREAD) == request) { - if (object_label == smack_known_floor.smk_known) + if (object_label == smack_known_floor.smk_known || + strcmp(object_label, smack_known_floor.smk_known) == 0) goto out_audit; - if (subject_label == smack_known_hat.smk_known) + if (subject_label == smack_known_hat.smk_known || + strcmp(subject_label, smack_known_hat.smk_known) == 0) goto out_audit; } /* @@ -167,9 +184,8 @@ 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_label, object_label, &smack_rule_list); rcu_read_unlock(); if (may > 0 && (request & may) == request) @@ -220,9 +236,14 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) } /* - * Allow for priviliged to override policy. + * Return if a specific label has been designated as the + * only one that gets privilege and current does not + * have that label. */ - if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE)) + if (smack_onlycap != NULL && smack_onlycap != sp) + goto out_audit; + + if (capable(CAP_MAC_OVERRIDE)) rc = 0; out_audit: @@ -252,8 +273,6 @@ static inline void smack_str_from_perm(char *string, int access) string[i++] = 'x'; if (access & MAY_APPEND) string[i++] = 'a'; - if (access & MAY_TRANSMUTE) - string[i++] = 't'; string[i] = '\0'; } /** @@ -322,102 +341,7 @@ void smack_log(char *subject_label, char *object_label, int request, } #endif -DEFINE_MUTEX(smack_known_lock); - -/** - * smk_find_entry - find a label on the list, return the list entry - * @string: a text string that might be a Smack label - * - * Returns a pointer to the entry in the label list that - * matches the passed string. - */ -struct smack_known *smk_find_entry(const char *string) -{ - struct smack_known *skp; - - list_for_each_entry_rcu(skp, &smack_known_list, list) { - if (strcmp(skp->smk_known, string) == 0) - return skp; - } - - return NULL; -} - -/** - * smk_parse_smack - parse smack label from a text string - * @string: a text string that might contain a Smack label - * @len: the maximum size, or zero if it is NULL terminated. - * - * Returns a pointer to the clean label, or NULL - */ -char *smk_parse_smack(const char *string, int len) -{ - char *smack; - int i; - - if (len <= 0) - len = strlen(string) + 1; - - /* - * Reserve a leading '-' as an indicator that - * this isn't a label, but an option to interfaces - * including /smack/cipso and /smack/cipso2 - */ - if (string[0] == '-') - return NULL; - - for (i = 0; i < len; i++) - if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || - string[i] == '"' || string[i] == '\\' || string[i] == '\'') - break; - - if (i == 0 || i >= SMK_LONGLABEL) - return NULL; - - smack = kzalloc(i + 1, GFP_KERNEL); - if (smack != NULL) { - strncpy(smack, string, i + 1); - smack[i] = '\0'; - } - return smack; -} - -/** - * smk_netlbl_mls - convert a catset to netlabel mls categories - * @catset: the Smack categories - * @sap: where to put the netlabel categories - * - * Allocates and fills attr.mls - * Returns 0 on success, error code on failure. - */ -int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, - int len) -{ - unsigned char *cp; - unsigned char m; - int cat; - int rc; - int byte; - - sap->flags |= NETLBL_SECATTR_MLS_CAT; - sap->attr.mls.lvl = level; - sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - sap->attr.mls.cat->startbit = 0; - - for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) - for (m = 0x80; m != 0; m >>= 1, cat++) { - if ((m & *cp) == 0) - continue; - rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, - cat, GFP_ATOMIC); - if (rc < 0) { - netlbl_secattr_catmap_free(sap->attr.mls.cat); - return rc; - } - } - - return 0; -} +static DEFINE_MUTEX(smack_known_lock); /** * smk_import_entry - import a label, return the list entry @@ -430,59 +354,53 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, struct smack_known *smk_import_entry(const char *string, int len) { struct smack_known *skp; - char *smack; - int slen; - int rc; + char smack[SMK_LABELLEN]; + int found; + int i; - smack = smk_parse_smack(string, len); - if (smack == NULL) + if (len <= 0 || len > SMK_MAXLEN) + len = SMK_MAXLEN; + + for (i = 0, found = 0; i < SMK_LABELLEN; i++) { + if (found) + smack[i] = '\0'; + else if (i >= len || string[i] > '~' || string[i] <= ' ' || + string[i] == '/' || string[i] == '"' || + string[i] == '\\' || string[i] == '\'') { + smack[i] = '\0'; + found = 1; + } else + smack[i] = string[i]; + } + + if (smack[0] == '\0') return NULL; mutex_lock(&smack_known_lock); - skp = smk_find_entry(smack); - if (skp != NULL) - goto freeout; - - skp = kzalloc(sizeof(*skp), GFP_KERNEL); - if (skp == NULL) - goto freeout; + found = 0; + list_for_each_entry_rcu(skp, &smack_known_list, list) { + if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { + found = 1; + break; + } + } - skp->smk_known = smack; - skp->smk_secid = smack_next_secid++; - skp->smk_netlabel.domain = skp->smk_known; - skp->smk_netlabel.flags = - NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; - /* - * If direct labeling works use it. - * Otherwise use mapped labeling. - */ - slen = strlen(smack); - if (slen < SMK_CIPSOLEN) - rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known, - &skp->smk_netlabel, slen); - else - rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid, - &skp->smk_netlabel, sizeof(skp->smk_secid)); - - if (rc >= 0) { - INIT_LIST_HEAD(&skp->smk_rules); - mutex_init(&skp->smk_rules_lock); - /* - * Make sure that the entry is actually - * filled before putting it on the list. - */ - list_add_rcu(&skp->list, &smack_known_list); - goto unlockout; + if (found == 0) { + skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); + if (skp != NULL) { + strncpy(skp->smk_known, smack, SMK_MAXLEN); + skp->smk_secid = smack_next_secid++; + skp->smk_cipso = NULL; + spin_lock_init(&skp->smk_cipsolock); + /* + * Make sure that the entry is actually + * filled before putting it on the list. + */ + list_add_rcu(&skp->list, &smack_known_list); + } } - /* - * smk_netlbl_mls failed. - */ - kfree(skp); - skp = NULL; -freeout: - kfree(smack); -unlockout: + mutex_unlock(&smack_known_lock); return skp; @@ -545,9 +463,85 @@ char *smack_from_secid(const u32 secid) */ u32 smack_to_secid(const char *smack) { - struct smack_known *skp = smk_find_entry(smack); + struct smack_known *skp; - if (skp == NULL) - return 0; - return skp->smk_secid; + rcu_read_lock(); + list_for_each_entry_rcu(skp, &smack_known_list, list) { + if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { + rcu_read_unlock(); + return skp->smk_secid; + } + } + rcu_read_unlock(); + return 0; +} + +/** + * smack_from_cipso - find the Smack label associated with a CIPSO option + * @level: Bell & LaPadula level from the network + * @cp: Bell & LaPadula categories from the network + * @result: where to put the Smack value + * + * This is a simple lookup in the label table. + * + * This is an odd duck as far as smack handling goes in that + * it sends back a copy of the smack label rather than a pointer + * to the master list. This is done because it is possible for + * a foreign host to send a smack label that is new to this + * machine and hence not on the list. That would not be an + * issue except that adding an entry to the master list can't + * be done at that point. + */ +void smack_from_cipso(u32 level, char *cp, char *result) +{ + struct smack_known *kp; + char *final = NULL; + + rcu_read_lock(); + list_for_each_entry(kp, &smack_known_list, list) { + if (kp->smk_cipso == NULL) + continue; + + spin_lock_bh(&kp->smk_cipsolock); + + if (kp->smk_cipso->smk_level == level && + memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) + final = kp->smk_known; + + spin_unlock_bh(&kp->smk_cipsolock); + } + rcu_read_unlock(); + if (final == NULL) + final = smack_known_huh.smk_known; + strncpy(result, final, SMK_MAXLEN); + return; +} + +/** + * smack_to_cipso - find the CIPSO option to go with a Smack label + * @smack: a pointer to the smack label in question + * @cp: where to put the result + * + * Returns zero if a value is available, non-zero otherwise. + */ +int smack_to_cipso(const char *smack, struct smack_cipso *cp) +{ + struct smack_known *kp; + int found = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(kp, &smack_known_list, list) { + if (kp->smk_known == smack || + strcmp(kp->smk_known, smack) == 0) { + found = 1; + break; + } + } + rcu_read_unlock(); + + if (found == 0 || kp->smk_cipso == NULL) + return -ENOENT; + + memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); + return 0; } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c43f73b..9831a39 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -5,13 +5,12 @@ * * Authors: * Casey Schaufler <casey@schaufler-ca.com> - * Jarkko Sakkinen <jarkko.sakkinen@intel.com> + * Jarkko Sakkinen <ext-jarkko.2.sakkinen@nokia.com> * * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * Paul Moore <paul@paul-moore.com> + * Paul Moore <paul.moore@hp.com> * Copyright (C) 2010 Nokia Corporation - * Copyright (C) 2011 Intel 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, @@ -30,11 +29,11 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/pipe_fs_i.h> +#include <net/netlabel.h> #include <net/cipso_ipv4.h> #include <linux/audit.h> #include <linux/magic.h> #include <linux/dcache.h> -#include <linux/personality.h> #include "smack.h" #define task_security(task) (task_cred_xxx((task), security)) @@ -53,23 +52,16 @@ static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) { int rc; - char *buffer; - char *result = NULL; + char in[SMK_LABELLEN]; if (ip->i_op->getxattr == NULL) return NULL; - buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); - if (buffer == NULL) + rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); + if (rc < 0) return NULL; - rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); - if (rc > 0) - result = smk_import(buffer, rc); - - kfree(buffer); - - return result; + return smk_import(in, rc); } /** @@ -214,7 +206,7 @@ static int smack_syslog(int typefrom_file) int rc = 0; char *sp = smk_of_current(); - if (smack_privileged(CAP_MAC_OVERRIDE)) + if (capable(CAP_MAC_OVERRIDE)) return 0; if (sp != smack_known_floor.smk_known) @@ -449,17 +441,11 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags) * BPRM hooks */ -/** - * smack_bprm_set_creds - set creds for exec - * @bprm: the exec information - * - * Returns 0 if it gets a blob, -ENOMEM otherwise - */ static int smack_bprm_set_creds(struct linux_binprm *bprm) { - struct inode *inode = bprm->file->f_path.dentry->d_inode; - struct task_smack *bsp = bprm->cred->security; + struct task_smack *tsp = bprm->cred->security; struct inode_smack *isp; + struct dentry *dp; int rc; rc = cap_bprm_set_creds(bprm); @@ -469,48 +455,20 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) if (bprm->cred_prepared) return 0; - isp = inode->i_security; - if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) + if (bprm->file == NULL || bprm->file->f_dentry == NULL) return 0; - if (bprm->unsafe) - return -EPERM; - - bsp->smk_task = isp->smk_task; - bprm->per_clear |= PER_CLEAR_ON_SETID; - - return 0; -} - -/** - * smack_bprm_committing_creds - Prepare to install the new credentials - * from bprm. - * - * @bprm: binprm for exec - */ -static void smack_bprm_committing_creds(struct linux_binprm *bprm) -{ - struct task_smack *bsp = bprm->cred->security; + dp = bprm->file->f_dentry; - if (bsp->smk_task != bsp->smk_forked) - current->pdeath_signal = 0; -} + if (dp->d_inode == NULL) + return 0; -/** - * smack_bprm_secureexec - Return the decision to use secureexec. - * @bprm: binprm for exec - * - * Returns 0 on success. - */ -static int smack_bprm_secureexec(struct linux_binprm *bprm) -{ - struct task_smack *tsp = current_security(); - int ret = cap_bprm_secureexec(bprm); + isp = dp->d_inode->i_security; - if (!ret && (tsp->smk_task != tsp->smk_forked)) - ret = 1; + if (isp->smk_task != NULL) + tsp->smk_task = isp->smk_task; - return ret; + return 0; } /* @@ -558,9 +516,6 @@ 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(); char *isp = smk_of_inode(inode); char *dsp = smk_of_inode(dir); int may; @@ -572,22 +527,18 @@ 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(smk_of_current(), dsp, &smack_rule_list); rcu_read_unlock(); /* * If the access rule allows transmutation and * the directory requests transmutation then * by all means transmute. - * Mark the inode as changed. */ if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && - smk_inode_transmutable(dir)) { + smk_inode_transmutable(dir)) isp = dsp; - issp->smk_flags |= SMK_INODE_CHANGED; - } *value = kstrdup(isp, GFP_KERNEL); if (*value == NULL) @@ -733,7 +684,6 @@ static int smack_inode_rename(struct inode *old_inode, * smack_inode_permission - Smack version of permission() * @inode: the inode in question * @mask: the access requested - * @flags: special case * * This is the important Smack hook. * @@ -753,7 +703,6 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags) /* May be droppable after audit */ if (flags & IPERM_FLAG_RCU) return -ECHILD; - smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); smk_ad_setfield_u_fs_inode(&ad, inode); return smk_curacc(smk_of_inode(inode), mask, &ad); @@ -823,17 +772,17 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; /* * check label validity here so import wont fail on * post_setxattr */ - if (size == 0 || size >= SMK_LONGLABEL || + if (size == 0 || size >= SMK_LABELLEN || smk_import(value, size) == NULL) rc = -EINVAL; } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; if (size != TRANS_TRUE_SIZE || strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) @@ -891,7 +840,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, return; } -/** +/* * smack_inode_getxattr - Smack check on getxattr * @dentry: the object * @name: unused @@ -908,7 +857,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name) return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad); } -/** +/* * smack_inode_removexattr - Smack check on removexattr * @dentry: the object * @name: name of the attribute @@ -929,7 +878,7 @@ 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)) { - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) rc = -EPERM; } else rc = cap_inode_removexattr(dentry, name); @@ -1138,31 +1087,36 @@ static int smack_file_lock(struct file *file, unsigned int cmd) * @cmd: what action to check * @arg: unused * - * Generally these operations are harmless. - * File locking operations present an obvious mechanism - * for passing information, so they require write access. - * * Returns 0 if current has access, error code otherwise */ static int smack_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { struct smk_audit_info ad; - int rc = 0; + int rc; + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); + smk_ad_setfield_u_fs_path(&ad, file->f_path); switch (cmd) { + case F_DUPFD: + case F_GETFD: + case F_GETFL: case F_GETLK: + case F_GETOWN: + case F_GETSIG: + rc = smk_curacc(file->f_security, MAY_READ, &ad); + break; + case F_SETFD: + case F_SETFL: case F_SETLK: case F_SETLKW: 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(file->f_security, MAY_WRITE, &ad); break; default: - break; + rc = smk_curacc(file->f_security, MAY_READWRITE, &ad); } return rc; @@ -1183,7 +1137,6 @@ static int smack_file_mmap(struct file *file, unsigned long flags, unsigned long addr, unsigned long addr_only) { - struct smack_known *skp; struct smack_rule *srp; struct task_smack *tsp; char *sp; @@ -1216,7 +1169,6 @@ static int smack_file_mmap(struct file *file, tsp = current_security(); sp = smk_of_current(); - skp = smk_find_entry(sp); rc = 0; rcu_read_lock(); @@ -1224,8 +1176,15 @@ static int smack_file_mmap(struct file *file, * For each Smack rule associated with the subject * label verify that the SMACK64MMAP also has access * to that rule's object label. + * + * Because neither of the labels comes + * from the networking code it is sufficient + * to compare pointers. */ - list_for_each_entry_rcu(srp, &skp->smk_rules, list) { + list_for_each_entry_rcu(srp, &smack_rule_list, list) { + if (srp->smk_subject != sp) + continue; + osmack = srp->smk_object; /* * Matching labels always allows access. @@ -1254,8 +1213,7 @@ static int smack_file_mmap(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(msmack, osmack, &smack_rule_list); if (mmay == -ENOENT) { rc = -EACCES; break; @@ -1356,24 +1314,6 @@ static int smack_file_receive(struct file *file) return smk_curacc(file->f_security, may, &ad); } -/** - * smack_dentry_open - Smack dentry open processing - * @file: the object - * @cred: unused - * - * Set the security blob in the file structure. - * - * Returns 0 - */ -static int smack_dentry_open(struct file *file, const struct cred *cred) -{ - struct inode_smack *isp = file->f_path.dentry->d_inode->i_security; - - file->f_security = isp->smk_inode; - - return 0; -} - /* * Task hooks */ @@ -1514,17 +1454,15 @@ static int smack_kernel_create_files_as(struct cred *new, /** * smk_curacc_on_task - helper to log task related access * @p: the task object - * @access: the access requested - * @caller: name of the calling function for audit + * @access : the access requested * * Return 0 if access is permitted */ -static int smk_curacc_on_task(struct task_struct *p, int access, - const char *caller) +static int smk_curacc_on_task(struct task_struct *p, int access) { struct smk_audit_info ad; - smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); smk_ad_setfield_u_tsk(&ad, p); return smk_curacc(smk_of_task(task_security(p)), access, &ad); } @@ -1538,7 +1476,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access, */ static int smack_task_setpgid(struct task_struct *p, pid_t pgid) { - return smk_curacc_on_task(p, MAY_WRITE, __func__); + return smk_curacc_on_task(p, MAY_WRITE); } /** @@ -1549,7 +1487,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid) */ static int smack_task_getpgid(struct task_struct *p) { - return smk_curacc_on_task(p, MAY_READ, __func__); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1560,7 +1498,7 @@ static int smack_task_getpgid(struct task_struct *p) */ static int smack_task_getsid(struct task_struct *p) { - return smk_curacc_on_task(p, MAY_READ, __func__); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1588,7 +1526,7 @@ static int smack_task_setnice(struct task_struct *p, int nice) rc = cap_task_setnice(p, nice); if (rc == 0) - rc = smk_curacc_on_task(p, MAY_WRITE, __func__); + rc = smk_curacc_on_task(p, MAY_WRITE); return rc; } @@ -1605,7 +1543,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio) rc = cap_task_setioprio(p, ioprio); if (rc == 0) - rc = smk_curacc_on_task(p, MAY_WRITE, __func__); + rc = smk_curacc_on_task(p, MAY_WRITE); return rc; } @@ -1617,7 +1555,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio) */ static int smack_task_getioprio(struct task_struct *p) { - return smk_curacc_on_task(p, MAY_READ, __func__); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1634,7 +1572,7 @@ static int smack_task_setscheduler(struct task_struct *p) rc = cap_task_setscheduler(p); if (rc == 0) - rc = smk_curacc_on_task(p, MAY_WRITE, __func__); + rc = smk_curacc_on_task(p, MAY_WRITE); return rc; } @@ -1646,7 +1584,7 @@ static int smack_task_setscheduler(struct task_struct *p) */ static int smack_task_getscheduler(struct task_struct *p) { - return smk_curacc_on_task(p, MAY_READ, __func__); + return smk_curacc_on_task(p, MAY_READ); } /** @@ -1657,7 +1595,7 @@ static int smack_task_getscheduler(struct task_struct *p) */ static int smack_task_movememory(struct task_struct *p) { - return smk_curacc_on_task(p, MAY_WRITE, __func__); + return smk_curacc_on_task(p, MAY_WRITE); } /** @@ -1724,8 +1662,7 @@ static int smack_task_wait(struct task_struct *p) * state into account in the decision as well as * the smack value. */ - if (smack_privileged(CAP_MAC_OVERRIDE) || - has_capability(p, CAP_MAC_OVERRIDE)) + if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) rc = 0; /* we log only if we didn't get overriden */ out_log: @@ -1773,7 +1710,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) ssp->smk_in = csp; ssp->smk_out = csp; - ssp->smk_packet = NULL; + ssp->smk_packet[0] = '\0'; sk->sk_security = ssp; @@ -1829,6 +1766,65 @@ static char *smack_host_label(struct sockaddr_in *sip) } /** + * smack_set_catset - convert a capset to netlabel mls categories + * @catset: the Smack categories + * @sap: where to put the netlabel categories + * + * Allocates and fills attr.mls.cat + */ +static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) +{ + unsigned char *cp; + unsigned char m; + int cat; + int rc; + int byte; + + if (!catset) + return; + + sap->flags |= NETLBL_SECATTR_MLS_CAT; + sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); + sap->attr.mls.cat->startbit = 0; + + for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++) + for (m = 0x80; m != 0; m >>= 1, cat++) { + if ((m & *cp) == 0) + continue; + rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, + cat, GFP_ATOMIC); + } +} + +/** + * smack_to_secattr - fill a secattr from a smack value + * @smack: the smack value + * @nlsp: where the result goes + * + * Casey says that CIPSO is good enough for now. + * It can be used to effect. + * It can also be abused to effect when necessary. + * Apologies to the TSIG group in general and GW in particular. + */ +static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) +{ + struct smack_cipso cipso; + int rc; + + nlsp->domain = smack; + nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; + + rc = smack_to_cipso(smack, &cipso); + if (rc == 0) { + nlsp->attr.mls.lvl = cipso.smk_level; + smack_set_catset(cipso.smk_catset, nlsp); + } else { + nlsp->attr.mls.lvl = smack_cipso_direct; + smack_set_catset(smack, nlsp); + } +} + +/** * smack_netlabel - Set the secattr on a socket * @sk: the socket * @labeled: socket label scheme @@ -1840,8 +1836,8 @@ static char *smack_host_label(struct sockaddr_in *sip) */ static int smack_netlabel(struct sock *sk, int labeled) { - struct smack_known *skp; struct socket_smack *ssp = sk->sk_security; + struct netlbl_lsm_secattr secattr; int rc = 0; /* @@ -1859,8 +1855,10 @@ 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); - rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); + netlbl_secattr_init(&secattr); + smack_to_secattr(ssp->smk_out, &secattr); + rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); + netlbl_secattr_destroy(&secattr); } bh_unlock_sock(sk); @@ -1931,7 +1929,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, struct socket *sock; int rc = 0; - if (value == NULL || size > SMK_LONGLABEL || size == 0) + if (value == NULL || size > SMK_LABELLEN || size == 0) return -EACCES; sp = smk_import(value, size); @@ -2498,7 +2496,6 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) char *final; char trattr[TRANS_TRUE_SIZE]; int transflag = 0; - int rc; struct dentry *dp; if (inode == NULL) @@ -2617,38 +2614,17 @@ 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; - - /* - * Transmuting directory - */ - if (S_ISDIR(inode->i_mode)) { - /* - * If this is a new directory and the label was - * transmuted when the inode was initialized - * set the transmute attribute on the directory - * and mark the inode. - * - * If there is a transmute attribute on the - * directory mark the inode. - */ - if (isp->smk_flags & SMK_INODE_CHANGED) { - isp->smk_flags &= ~SMK_INODE_CHANGED; - rc = inode->i_op->setxattr(dp, + if (S_ISDIR(inode->i_mode)) { + trattr[0] = '\0'; + inode->i_op->getxattr(dp, XATTR_NAME_SMACKTRANSMUTE, - TRANS_TRUE, TRANS_TRUE_SIZE, - 0); - } else { - rc = inode->i_op->getxattr(dp, - XATTR_NAME_SMACKTRANSMUTE, trattr, - TRANS_TRUE_SIZE); - if (rc >= 0 && strncmp(trattr, TRANS_TRUE, - TRANS_TRUE_SIZE) != 0) - rc = -EINVAL; + trattr, TRANS_TRUE_SIZE); + if (strncmp(trattr, TRANS_TRUE, + TRANS_TRUE_SIZE) == 0) + transflag = SMK_INODE_TRANSMUTE; } - if (rc >= 0) - transflag = SMK_INODE_TRANSMUTE; } isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); @@ -2724,10 +2700,10 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (p != current) return -EPERM; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; - if (value == NULL || size == 0 || size >= SMK_LONGLABEL) + if (value == NULL || size == 0 || size >= SMK_LABELLEN) return -EINVAL; if (strcmp(name, "current") != 0) @@ -2776,24 +2752,15 @@ static int smack_unix_stream_connect(struct sock *sock, { struct socket_smack *ssp = sock->sk_security; struct socket_smack *osp = other->sk_security; - struct socket_smack *nsp = newsk->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); - if (!smack_privileged(CAP_MAC_OVERRIDE)) + if (!capable(CAP_MAC_OVERRIDE)) rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); - /* - * Cross reference the peer labels for SO_PEERSEC. - */ - if (rc == 0) { - nsp->smk_packet = ssp->smk_out; - ssp->smk_packet = osp->smk_out; - } - return rc; } @@ -2815,7 +2782,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other->sk); - if (!smack_privileged(CAP_MAC_OVERRIDE)) + if (!capable(CAP_MAC_OVERRIDE)) rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); return rc; @@ -2845,19 +2812,19 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, return smack_netlabel_send(sock->sk, sip); } + /** * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack * @sap: netlabel secattr - * @ssp: socket security information + * @sip: where to put the result * - * Returns a pointer to a Smack label found on the label list. + * Copies a smack label into sip */ -static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, - struct socket_smack *ssp) +static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) { - struct smack_known *kp; + char smack[SMK_LABELLEN]; char *sp; - int found = 0; + int pcat; if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { /* @@ -2865,30 +2832,34 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, * If there are flags but no level netlabel isn't * behaving the way we expect it to. * - * Look it up in the label table + * Get the categories, if any * Without guidance regarding the smack value * for the packet fall back on the network * ambient value. */ - rcu_read_lock(); - list_for_each_entry(kp, &smack_known_list, list) { - if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) - continue; - if (memcmp(sap->attr.mls.cat, - kp->smk_netlabel.attr.mls.cat, - SMK_CIPSOLEN) != 0) - continue; - found = 1; - break; + memset(smack, '\0', SMK_LABELLEN); + if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) + for (pcat = -1;;) { + pcat = netlbl_secattr_catmap_walk( + sap->attr.mls.cat, pcat + 1); + if (pcat < 0) + break; + smack_catset_bit(pcat, smack); + } + /* + * If it is CIPSO using smack direct mapping + * we are already done. WeeHee. + */ + if (sap->attr.mls.lvl == smack_cipso_direct) { + memcpy(sip, smack, SMK_MAXLEN); + return; } - rcu_read_unlock(); - - if (found) - return kp->smk_known; - - if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) - return smack_known_web.smk_known; - return smack_known_star.smk_known; + /* + * Look it up in the supplied table if it is not + * a direct mapping. + */ + smack_from_cipso(sap->attr.mls.lvl, smack, sip); + return; } if ((sap->flags & NETLBL_SECATTR_SECID) != 0) { /* @@ -2903,14 +2874,16 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, * secid is from a fallback. */ BUG_ON(sp == NULL); - return sp; + strncpy(sip, sp, SMK_MAXLEN); + return; } /* * Without guidance regarding the smack value * for the packet fall back on the network * ambient value. */ - return smack_net_ambient; + strncpy(sip, smack_net_ambient, SMK_MAXLEN); + return; } /** @@ -2924,6 +2897,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) { struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = sk->sk_security; + char smack[SMK_LABELLEN]; char *csp; int rc; struct smk_audit_info ad; @@ -2936,9 +2910,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); - if (rc == 0) - csp = smack_from_secattr(&secattr, ssp); - else + if (rc == 0) { + smack_from_secattr(&secattr, smack); + csp = smack; + } else csp = smack_net_ambient; netlbl_secattr_destroy(&secattr); @@ -2975,19 +2950,15 @@ static int smack_socket_getpeersec_stream(struct socket *sock, int __user *optlen, unsigned len) { struct socket_smack *ssp; - char *rcp = ""; - int slen = 1; + int slen; int rc = 0; ssp = sock->sk->sk_security; - if (ssp->smk_packet != NULL) { - rcp = ssp->smk_packet; - slen = strlen(rcp) + 1; - } + slen = strlen(ssp->smk_packet) + 1; if (slen > len) rc = -ERANGE; - else if (copy_to_user(optval, rcp, slen) != 0) + else if (copy_to_user(optval, ssp->smk_packet, slen) != 0) rc = -EFAULT; if (put_user(slen, optlen) != 0) @@ -3010,8 +2981,8 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, { struct netlbl_lsm_secattr secattr; - struct socket_smack *ssp = NULL; - char *sp; + struct socket_smack *sp; + char smack[SMK_LABELLEN]; int family = PF_UNSPEC; u32 s = 0; /* 0 is the invalid secid */ int rc; @@ -3026,19 +2997,17 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, family = sock->sk->sk_family; if (family == PF_UNIX) { - ssp = sock->sk->sk_security; - s = smack_to_secid(ssp->smk_out); + 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. */ - if (sock != NULL && sock->sk != NULL) - ssp = sock->sk->sk_security; netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); if (rc == 0) { - sp = smack_from_secattr(&secattr, ssp); - s = smack_to_secid(sp); + smack_from_secattr(&secattr, smack); + s = smack_to_secid(smack); } netlbl_secattr_destroy(&secattr); } @@ -3082,13 +3051,11 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct request_sock *req) { u16 family = sk->sk_family; - struct smack_known *skp; struct socket_smack *ssp = sk->sk_security; struct netlbl_lsm_secattr secattr; struct sockaddr_in addr; struct iphdr *hdr; - char *sp; - char *hsp; + char smack[SMK_LABELLEN]; int rc; struct smk_audit_info ad; @@ -3099,9 +3066,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); if (rc == 0) - sp = smack_from_secattr(&secattr, ssp); + smack_from_secattr(&secattr, smack); else - sp = smack_known_huh.smk_known; + strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); netlbl_secattr_destroy(&secattr); #ifdef CONFIG_AUDIT @@ -3114,7 +3081,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * Receiving a packet requires that the other end be able to write * here. Read access is not required. */ - rc = smk_access(sp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad); if (rc != 0) return rc; @@ -3122,7 +3089,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * Save the peer's label in the request_sock so we can later setup * smk_packet in the child socket so that SO_PEERCRED can report it. */ - req->peer_secid = smack_to_secid(sp); + req->peer_secid = smack_to_secid(smack); /* * We need to decide if we want to label the incoming connection here @@ -3132,14 +3099,16 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, hdr = ip_hdr(skb); addr.sin_addr.s_addr = hdr->saddr; rcu_read_lock(); - hsp = smack_host_label(&addr); - rcu_read_unlock(); - - if (hsp == NULL) { - skp = smk_find_entry(sp); - rc = netlbl_req_setattr(req, &skp->smk_netlabel); - } else + if (smack_host_label(&addr) == NULL) { + rcu_read_unlock(); + netlbl_secattr_init(&secattr); + smack_to_secattr(smack, &secattr); + rc = netlbl_req_setattr(req, &secattr); + netlbl_secattr_destroy(&secattr); + } else { + rcu_read_unlock(); netlbl_req_delattr(req); + } return rc; } @@ -3155,11 +3124,13 @@ static void smack_inet_csk_clone(struct sock *sk, const struct request_sock *req) { struct socket_smack *ssp = sk->sk_security; + char *smack; - if (req->peer_secid != 0) - ssp->smk_packet = smack_from_secid(req->peer_secid); - else - ssp->smk_packet = NULL; + if (req->peer_secid != 0) { + smack = smack_from_secid(req->peer_secid); + strncpy(ssp->smk_packet, smack, SMK_MAXLEN); + } else + ssp->smk_packet[0] = '\0'; } /* @@ -3437,8 +3408,6 @@ struct security_operations smack_ops = { .sb_umount = smack_sb_umount, .bprm_set_creds = smack_bprm_set_creds, - .bprm_committing_creds = smack_bprm_committing_creds, - .bprm_secureexec = smack_bprm_secureexec, .inode_alloc_security = smack_inode_alloc_security, .inode_free_security = smack_inode_free_security, @@ -3470,8 +3439,6 @@ struct security_operations smack_ops = { .file_send_sigiotask = smack_file_send_sigiotask, .file_receive = smack_file_receive, - .dentry_open = smack_dentry_open, - .cred_alloc_blank = smack_cred_alloc_blank, .cred_free = smack_cred_free, .cred_prepare = smack_cred_prepare, @@ -3561,29 +3528,8 @@ struct security_operations smack_ops = { }; -static __init void init_smack_known_list(void) +static __init void init_smack_know_list(void) { - /* - * Initialize rule list locks - */ - mutex_init(&smack_known_huh.smk_rules_lock); - mutex_init(&smack_known_hat.smk_rules_lock); - mutex_init(&smack_known_floor.smk_rules_lock); - mutex_init(&smack_known_star.smk_rules_lock); - mutex_init(&smack_known_invalid.smk_rules_lock); - mutex_init(&smack_known_web.smk_rules_lock); - /* - * Initialize rule lists - */ - INIT_LIST_HEAD(&smack_known_huh.smk_rules); - INIT_LIST_HEAD(&smack_known_hat.smk_rules); - INIT_LIST_HEAD(&smack_known_star.smk_rules); - INIT_LIST_HEAD(&smack_known_floor.smk_rules); - INIT_LIST_HEAD(&smack_known_invalid.smk_rules); - INIT_LIST_HEAD(&smack_known_web.smk_rules); - /* - * Create the known labels list - */ list_add(&smack_known_huh.list, &smack_known_list); list_add(&smack_known_hat.list, &smack_known_list); list_add(&smack_known_star.list, &smack_known_list); @@ -3618,8 +3564,16 @@ static __init int smack_init(void) cred = (struct cred *) current->cred; cred->security = tsp; - /* initialize the smack_known_list */ - init_smack_known_list(); + /* initialize the smack_know_list */ + init_smack_know_list(); + /* + * Initialize locks + */ + spin_lock_init(&smack_known_huh.smk_cipsolock); + spin_lock_init(&smack_known_hat.smk_cipsolock); + spin_lock_init(&smack_known_star.smk_cipsolock); + spin_lock_init(&smack_known_floor.smk_cipsolock); + spin_lock_init(&smack_known_invalid.smk_cipsolock); /* * Register with LSM diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 5a4ab14..f934601 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -22,6 +22,7 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <net/net_namespace.h> +#include <net/netlabel.h> #include <net/cipso_ipv4.h> #include <linux/seq_file.h> #include <linux/ctype.h> @@ -43,14 +44,6 @@ enum smk_inos { SMK_ONLYCAP = 9, /* the only "capable" label */ SMK_LOGGING = 10, /* logging */ SMK_LOAD_SELF = 11, /* task specific rules */ - SMK_ACCESSES = 12, /* access policy */ - SMK_MAPPED = 13, /* CIPSO level indicating mapped label */ - SMK_LOAD2 = 14, /* load policy with long labels */ - SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */ - SMK_ACCESS2 = 16, /* make an access check with long labels */ - SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ - SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ - SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ }; /* @@ -66,7 +59,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock); * If it isn't somehow marked, use this. * It can be reset via smackfs/ambient */ -char *smack_net_ambient; +char *smack_net_ambient = smack_known_floor.smk_known; /* * This is the level in a CIPSO header that indicates a @@ -76,13 +69,6 @@ char *smack_net_ambient; int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; /* - * This is the level in a CIPSO header that indicates a - * secid is contained directly in the category set. - * It can be reset via smackfs/mapped - */ -int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; - -/* * Unless a process is running with this label even * having CAP_MAC_OVERRIDE isn't enough to grant * privilege to violate MAC policy. If no label is @@ -99,22 +85,15 @@ char *smack_onlycap; */ LIST_HEAD(smk_netlbladdr_list); - -/* - * Rule lists are maintained for each label. - * This master list is just for reading /smack/load and /smack/load2. - */ -struct smack_master_list { - struct list_head list; - struct smack_rule *smk_rule; -}; - LIST_HEAD(smack_rule_list); static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; const char *smack_cipso_option = SMACK_CIPSO_OPTION; + +#define SEQ_READ_FINISHED 1 + /* * Values for parsing cipso rules * SMK_DIGITLEN: Length of a digit field in a rule. @@ -138,18 +117,6 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION; #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) -/* - * Stricly for CIPSO level manipulation. - * Set the category bit number in a smack label sized buffer. - */ -static inline void smack_catset_bit(unsigned int cat, char *catsetp) -{ - if (cat == 0 || cat > (SMK_CIPSOLEN * 8)) - return; - - catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); -} - /** * smk_netlabel_audit_set - fill a netlbl_audit struct * @nap: structure to fill @@ -162,10 +129,12 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) } /* - * Value for parsing single label host rules + * Values for parsing single label host rules * "1.2.3.4 X" + * "192.168.138.129/32 abcdefghijklmnopqrstuvw" */ #define SMK_NETLBLADDRMIN 9 +#define SMK_NETLBLADDRMAX 42 /** * smk_set_access - add a rule to the rule list @@ -190,13 +159,9 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, mutex_lock(rule_lock); - /* - * Because the object label is less likely to match - * than the subject label check it first - */ list_for_each_entry_rcu(sp, rule_list, list) { - if (sp->smk_object == srp->smk_object && - sp->smk_subject == srp->smk_subject) { + if (sp->smk_subject == srp->smk_subject && + sp->smk_object == srp->smk_object) { found = 1; sp->smk_access = srp->smk_access; break; @@ -211,212 +176,30 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, } /** - * smk_perm_from_str - parse smack accesses from a text string - * @string: a text string that contains a Smack accesses code - * - * Returns an integer with respective bits set for specified accesses. - */ -static int smk_perm_from_str(const char *string) -{ - int perm = 0; - const char *cp; - - for (cp = string; ; cp++) - switch (*cp) { - case '-': - break; - case 'r': - case 'R': - perm |= MAY_READ; - break; - case 'w': - case 'W': - perm |= MAY_WRITE; - break; - case 'x': - case 'X': - perm |= MAY_EXEC; - break; - case 'a': - case 'A': - perm |= MAY_APPEND; - break; - case 't': - case 'T': - perm |= MAY_TRANSMUTE; - break; - default: - return perm; - } -} - -/** - * smk_fill_rule - Fill Smack rule from strings - * @subject: subject label string - * @object: object label string - * @access: access string - * @access_remove: string with permissions to be removed - * @rule: Smack rule - * @import: if non-zero, import labels - * - * Returns 0 on success, -1 on failure - */ -static int smk_fill_rule(const char *subject, const char *object, - const char *access, const char *access_remove, - struct smack_rule *rule, int import) -{ - int rc = -1; - const char *cp; - struct smack_known *skp; - - if (import) { - rule->smk_subject = smk_import(subject, 0); - if (rule->smk_subject == NULL) - return -1; - - rule->smk_object = smk_import(object, 0); - if (rule->smk_object == NULL) - return -1; - } else { - cp = smk_parse_smack(subject, 0); - if (cp == NULL) - return -1; - skp = smk_find_entry(cp); - kfree(cp); - if (skp == NULL) - return -1; - rule->smk_subject = skp->smk_known; - - cp = smk_parse_smack(object, 0); - if (cp == NULL) - return -1; - skp = smk_find_entry(cp); - kfree(cp); - if (skp == NULL) - return -1; - rule->smk_object = skp->smk_known; - } - - if (access_remove) { - rule->smk_access |= smk_perm_from_str(access); - rule->smk_access &= ~smk_perm_from_str(access_remove); - } else - rule->smk_access = smk_perm_from_str(access); - - rc = 0; - - return rc; -} - -/** - * smk_parse_rule - parse Smack rule from load string - * @data: string to be parsed whose size is SMK_LOADLEN - * @rule: Smack rule - * @import: if non-zero, import labels - * - * Returns 0 on success, -1 on errors. - */ -static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) -{ - int rc; - - rc = smk_fill_rule(data, data + SMK_LABELLEN, - data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule, - import); - return rc; -} - -/** - * smk_parse_long_rule - parse Smack rule from rule string - * @data: string to be parsed, null terminated - * @rule: Smack rule - * @import: if non-zero, import labels - * @change: if non-zero, data is from /smack/change-rule - * - * Returns 0 on success, -1 on failure - */ -static int smk_parse_long_rule(const char *data, struct smack_rule *rule, - int import, int change) -{ - char *subject; - char *object; - char *access; - char *access_remove; - int datalen; - int rc = -1; - - /* - * This is probably inefficient, but safe. - */ - datalen = strlen(data); - subject = kzalloc(datalen, GFP_KERNEL); - if (subject == NULL) - return -1; - object = kzalloc(datalen, GFP_KERNEL); - if (object == NULL) - goto free_out_s; - access = kzalloc(datalen, GFP_KERNEL); - if (access == NULL) - goto free_out_o; - access_remove = kzalloc(datalen, GFP_KERNEL); - if (access_remove == NULL) - goto free_out_a; - - if (change) { - if (sscanf(data, "%s %s %s %s", - subject, object, access, access_remove) == 4) - rc = smk_fill_rule(subject, object, access, - access_remove, rule, import); - } else { - if (sscanf(data, "%s %s %s", subject, object, access) == 3) - rc = smk_fill_rule(subject, object, access, - NULL, rule, import); - } - - kfree(access_remove); -free_out_a: - kfree(access); -free_out_o: - kfree(object); -free_out_s: - kfree(subject); - return rc; -} - -#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ -#define SMK_LONG_FMT 1 /* Variable long label format */ -#define SMK_CHANGE_FMT 2 /* Rule modification format */ -/** - * smk_write_rules_list - write() for any /smack rule file + * smk_write_load_list - write() for any /smack/load * @file: file pointer, not actually used * @buf: where to get the data from * @count: bytes sent * @ppos: where to start - must be 0 * @rule_list: the list of rules to write to * @rule_lock: lock for the rule list - * @format: /smack/load or /smack/load2 or /smack/change-rule format. * * Get one smack access rule from above. - * The format for SMK_LONG_FMT is: - * "subject<whitespace>object<whitespace>access[<whitespace>...]" - * The format for SMK_FIXED24_FMT is exactly: - * "subject object rwxat" - * The format for SMK_CHANGE_FMT is: - * "subject<whitespace>object<whitespace> - * acc_enable<whitespace>acc_disable[<whitespace>...]" + * The format is exactly: + * char subject[SMK_LABELLEN] + * char object[SMK_LABELLEN] + * char access[SMK_ACCESSLEN] + * + * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. */ -static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, - size_t count, loff_t *ppos, - struct list_head *rule_list, - struct mutex *rule_lock, int format) +static ssize_t smk_write_load_list(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, + struct list_head *rule_list, + struct mutex *rule_lock) { - struct smack_master_list *smlp; - struct smack_known *skp; struct smack_rule *rule; char *data; - int datalen; int rc = -EINVAL; - int load = 0; /* * No partial writes. @@ -424,18 +207,13 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, */ if (*ppos != 0) return -EINVAL; + /* + * Minor hack for backward compatibility + */ + if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) + return -EINVAL; - if (format == SMK_FIXED24_FMT) { - /* - * Minor hack for backward compatibility - */ - if (count != SMK_OLOADLEN && count != SMK_LOADLEN) - return -EINVAL; - datalen = SMK_LOADLEN; - } else - datalen = count + 1; - - data = kzalloc(datalen, GFP_KERNEL); + data = kzalloc(SMK_LOADLEN, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -444,59 +222,90 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, goto out; } + /* + * More on the minor hack for backward compatibility + */ + if (count == (SMK_OLOADLEN)) + data[SMK_OLOADLEN] = '-'; + rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (rule == NULL) { rc = -ENOMEM; goto out; } - if (format == SMK_LONG_FMT) { - /* - * Be sure the data string is terminated. - */ - data[count] = '\0'; - if (smk_parse_long_rule(data, rule, 1, 0)) - goto out_free_rule; - } else if (format == SMK_CHANGE_FMT) { - data[count] = '\0'; - if (smk_parse_long_rule(data, rule, 1, 1)) - goto out_free_rule; - } else { - /* - * More on the minor hack for backward compatibility - */ - if (count == (SMK_OLOADLEN)) - data[SMK_OLOADLEN] = '-'; - if (smk_parse_rule(data, rule, 1)) - goto out_free_rule; + rule->smk_subject = smk_import(data, 0); + if (rule->smk_subject == NULL) + goto out_free_rule; + + rule->smk_object = smk_import(data + SMK_LABELLEN, 0); + if (rule->smk_object == NULL) + goto out_free_rule; + + rule->smk_access = 0; + + switch (data[SMK_LABELLEN + SMK_LABELLEN]) { + case '-': + break; + case 'r': + case 'R': + rule->smk_access |= MAY_READ; + break; + default: + goto out_free_rule; } + switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { + case '-': + break; + case 'w': + case 'W': + rule->smk_access |= MAY_WRITE; + break; + default: + goto out_free_rule; + } + + switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { + case '-': + break; + case 'x': + case 'X': + rule->smk_access |= MAY_EXEC; + break; + default: + goto out_free_rule; + } + + switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { + case '-': + break; + case 'a': + case 'A': + rule->smk_access |= MAY_APPEND; + break; + default: + goto out_free_rule; + } - if (rule_list == NULL) { - load = 1; - skp = smk_find_entry(rule->smk_subject); - rule_list = &skp->smk_rules; - rule_lock = &skp->smk_rules_lock; + 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 = count; /* - * If this is a global as opposed to self and a new rule - * it needs to get added for reporting. * smk_set_access returns true if there was already a rule * for the subject/object pair, and false if it was new. */ - if (!smk_set_access(rule, rule_list, rule_lock)) { - if (load) { - smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); - if (smlp != NULL) { - smlp->smk_rule = rule; - list_add_rcu(&smlp->list, &smack_rule_list); - } else - rc = -ENOMEM; - } + if (!smk_set_access(rule, rule_list, rule_lock)) goto out; - } out_free_rule: kfree(rule); @@ -505,66 +314,39 @@ out: return rc; } + /* - * Core logic for smackfs seq list operations. + * Seq_file read operations for /smack/load */ -static void *smk_seq_start(struct seq_file *s, loff_t *pos, - struct list_head *head) +static void *load_seq_start(struct seq_file *s, loff_t *pos) { - struct list_head *list; - - /* - * This is 0 the first time through. - */ - if (s->index == 0) - s->private = head; - - if (s->private == NULL) + if (*pos == SEQ_READ_FINISHED) return NULL; - - list = s->private; - if (list_empty(list)) + if (list_empty(&smack_rule_list)) return NULL; - - if (s->index == 0) - return list->next; - return list; + return smack_rule_list.next; } -static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos, - struct list_head *head) +static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) { struct list_head *list = v; - if (list_is_last(list, head)) { - s->private = NULL; + if (list_is_last(list, &smack_rule_list)) { + *pos = SEQ_READ_FINISHED; return NULL; } - s->private = list->next; return list->next; } -static void smk_seq_stop(struct seq_file *s, void *v) -{ - /* No-op */ -} - -static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) +static int load_seq_show(struct seq_file *s, void *v) { - /* - * Don't show any rules with label names too long for - * interface file (/smack/load or /smack/load2) - * because you should expect to be able to write - * anything you read back. - */ - if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max) - return; - - if (srp->smk_access == 0) - return; + struct list_head *list = v; + struct smack_rule *srp = + list_entry(list, struct smack_rule, list); - seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object); + seq_printf(s, "%s %s", (char *)srp->smk_subject, + (char *)srp->smk_object); seq_putc(s, ' '); @@ -578,40 +360,24 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) seq_putc(s, 'a'); if (srp->smk_access & MAY_TRANSMUTE) seq_putc(s, 't'); + if (srp->smk_access == 0) + seq_putc(s, '-'); seq_putc(s, '\n'); -} - -/* - * Seq_file read operations for /smack/load - */ - -static void *load2_seq_start(struct seq_file *s, loff_t *pos) -{ - return smk_seq_start(s, pos, &smack_rule_list); -} -static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - return smk_seq_next(s, v, pos, &smack_rule_list); + return 0; } -static int load_seq_show(struct seq_file *s, void *v) +static void load_seq_stop(struct seq_file *s, void *v) { - struct list_head *list = v; - struct smack_master_list *smlp = - list_entry(list, struct smack_master_list, list); - - smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); - - return 0; + /* No-op */ } static const struct seq_operations load_seq_ops = { - .start = load2_seq_start, - .next = load2_seq_next, + .start = load_seq_start, + .next = load_seq_next, .show = load_seq_show, - .stop = smk_seq_stop, + .stop = load_seq_stop, }; /** @@ -637,16 +403,17 @@ static int smk_open_load(struct inode *inode, struct file *file) static ssize_t smk_write_load(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + /* * Must have privilege. * No partial writes. * Enough data must be present. */ - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; - return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, - SMK_FIXED24_FMT); + return smk_write_load_list(file, buf, count, ppos, &smack_rule_list, + &smack_list_lock); } static const struct file_operations smk_load_ops = { @@ -716,8 +483,6 @@ static void smk_unlbl_ambient(char *oldambient) printk(KERN_WARNING "%s:%d remove rc = %d\n", __func__, __LINE__, rc); } - if (smack_net_ambient == NULL) - smack_net_ambient = smack_known_floor.smk_known; rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, NULL, NULL, &nai); @@ -732,12 +497,28 @@ static void smk_unlbl_ambient(char *oldambient) static void *cipso_seq_start(struct seq_file *s, loff_t *pos) { - return smk_seq_start(s, pos, &smack_known_list); + if (*pos == SEQ_READ_FINISHED) + return NULL; + if (list_empty(&smack_known_list)) + return NULL; + + return smack_known_list.next; } static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos) { - return smk_seq_next(s, v, pos, &smack_known_list); + struct list_head *list = v; + + /* + * labels with no associated cipso value wont be printed + * in cipso_seq_show + */ + if (list_is_last(list, &smack_known_list)) { + *pos = SEQ_READ_FINISHED; + return NULL; + } + + return list->next; } /* @@ -749,39 +530,43 @@ static int cipso_seq_show(struct seq_file *s, void *v) struct list_head *list = v; struct smack_known *skp = list_entry(list, struct smack_known, list); - struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; + struct smack_cipso *scp = skp->smk_cipso; + char *cbp; char sep = '/'; + int cat = 1; int i; + unsigned char m; - /* - * Don't show a label that could not have been set using - * /smack/cipso. This is in support of the notion that - * anything read from /smack/cipso ought to be writeable - * to /smack/cipso. - * - * /smack/cipso2 should be used instead. - */ - if (strlen(skp->smk_known) >= SMK_LABELLEN) + if (scp == NULL) return 0; - seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); + seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level); - for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; - i = netlbl_secattr_catmap_walk(cmp, i + 1)) { - seq_printf(s, "%c%d", sep, i); - sep = ','; - } + cbp = scp->smk_catset; + for (i = 0; i < SMK_LABELLEN; i++) + for (m = 0x80; m != 0; m >>= 1) { + if (m & cbp[i]) { + seq_printf(s, "%c%d", sep, cat); + sep = ','; + } + cat++; + } seq_putc(s, '\n'); return 0; } +static void cipso_seq_stop(struct seq_file *s, void *v) +{ + /* No-op */ +} + static const struct seq_operations cipso_seq_ops = { .start = cipso_seq_start, + .stop = cipso_seq_stop, .next = cipso_seq_next, .show = cipso_seq_show, - .stop = smk_seq_stop, }; /** @@ -798,24 +583,23 @@ static int smk_open_cipso(struct inode *inode, struct file *file) } /** - * smk_set_cipso - do the work for write() for cipso and cipso2 + * smk_write_cipso - write() for /smack/cipso * @file: file pointer, not actually used * @buf: where to get the data from * @count: bytes sent * @ppos: where to start - * @format: /smack/cipso or /smack/cipso2 * * Accepts only one cipso rule per write call. * Returns number of bytes written or error code, as appropriate */ -static ssize_t smk_set_cipso(struct file *file, const char __user *buf, - size_t count, loff_t *ppos, int format) +static ssize_t smk_write_cipso(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { struct smack_known *skp; - struct netlbl_lsm_secattr ncats; - char mapcatset[SMK_CIPSOLEN]; + struct smack_cipso *scp = NULL; + char mapcatset[SMK_LABELLEN]; int maplevel; - unsigned int cat; + int cat; int catlen; ssize_t rc = -EINVAL; char *data = NULL; @@ -828,12 +612,11 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, * No partial writes. * Enough data must be present. */ - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; if (*ppos != 0) return -EINVAL; - if (format == SMK_FIXED24_FMT && - (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)) + if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX) return -EINVAL; data = kzalloc(count + 1, GFP_KERNEL); @@ -845,6 +628,11 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, goto unlockedout; } + /* labels cannot begin with a '-' */ + if (data[0] == '-') { + rc = -EINVAL; + goto unlockedout; + } data[count] = '\0'; rule = data; /* @@ -857,11 +645,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, if (skp == NULL) goto out; - if (format == SMK_FIXED24_FMT) - rule += SMK_LABELLEN; - else - rule += strlen(skp->smk_known); - + rule += SMK_LABELLEN; ret = sscanf(rule, "%d", &maplevel); if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) goto out; @@ -871,29 +655,41 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) goto out; - if (format == SMK_FIXED24_FMT && - count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) + if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) goto out; memset(mapcatset, 0, sizeof(mapcatset)); for (i = 0; i < catlen; i++) { rule += SMK_DIGITLEN; - ret = sscanf(rule, "%u", &cat); + ret = sscanf(rule, "%d", &cat); if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) goto out; smack_catset_bit(cat, mapcatset); } - rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); - if (rc >= 0) { - netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); - skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; - skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; - rc = count; + if (skp->smk_cipso == NULL) { + scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL); + if (scp == NULL) { + rc = -ENOMEM; + goto out; + } } + spin_lock_bh(&skp->smk_cipsolock); + + if (scp == NULL) + scp = skp->smk_cipso; + else + skp->smk_cipso = scp; + + scp->smk_level = maplevel; + memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset)); + + spin_unlock_bh(&skp->smk_cipsolock); + + rc = count; out: mutex_unlock(&smack_cipso_lock); unlockedout: @@ -901,22 +697,6 @@ unlockedout: return rc; } -/** - * smk_write_cipso - write() for /smack/cipso - * @file: file pointer, not actually used - * @buf: where to get the data from - * @count: bytes sent - * @ppos: where to start - * - * Accepts only one cipso rule per write call. - * Returns number of bytes written or error code, as appropriate - */ -static ssize_t smk_write_cipso(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return smk_set_cipso(file, buf, count, ppos, SMK_FIXED24_FMT); -} - static const struct file_operations smk_cipso_ops = { .open = smk_open_cipso, .read = seq_read, @@ -926,91 +706,28 @@ static const struct file_operations smk_cipso_ops = { }; /* - * Seq_file read operations for /smack/cipso2 - */ - -/* - * Print cipso labels in format: - * label level[/cat[,cat]] - */ -static int cipso2_seq_show(struct seq_file *s, void *v) -{ - struct list_head *list = v; - struct smack_known *skp = - list_entry(list, struct smack_known, list); - struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; - char sep = '/'; - int i; - - seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); - - for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; - i = netlbl_secattr_catmap_walk(cmp, i + 1)) { - seq_printf(s, "%c%d", sep, i); - sep = ','; - } - - seq_putc(s, '\n'); - - return 0; -} - -static const struct seq_operations cipso2_seq_ops = { - .start = cipso_seq_start, - .next = cipso_seq_next, - .show = cipso2_seq_show, - .stop = smk_seq_stop, -}; - -/** - * smk_open_cipso2 - open() for /smack/cipso2 - * @inode: inode structure representing file - * @file: "cipso2" file pointer - * - * Connect our cipso_seq_* operations with /smack/cipso2 - * file_operations - */ -static int smk_open_cipso2(struct inode *inode, struct file *file) -{ - return seq_open(file, &cipso2_seq_ops); -} - -/** - * smk_write_cipso2 - write() for /smack/cipso2 - * @file: file pointer, not actually used - * @buf: where to get the data from - * @count: bytes sent - * @ppos: where to start - * - * Accepts only one cipso rule per write call. - * Returns number of bytes written or error code, as appropriate - */ -static ssize_t smk_write_cipso2(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return smk_set_cipso(file, buf, count, ppos, SMK_LONG_FMT); -} - -static const struct file_operations smk_cipso2_ops = { - .open = smk_open_cipso2, - .read = seq_read, - .llseek = seq_lseek, - .write = smk_write_cipso2, - .release = seq_release, -}; - -/* * Seq_file read operations for /smack/netlabel */ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) { - return smk_seq_start(s, pos, &smk_netlbladdr_list); + if (*pos == SEQ_READ_FINISHED) + return NULL; + if (list_empty(&smk_netlbladdr_list)) + return NULL; + return smk_netlbladdr_list.next; } static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) { - return smk_seq_next(s, v, pos, &smk_netlbladdr_list); + struct list_head *list = v; + + if (list_is_last(list, &smk_netlbladdr_list)) { + *pos = SEQ_READ_FINISHED; + return NULL; + } + + return list->next; } #define BEBITS (sizeof(__be32) * 8) @@ -1034,11 +751,16 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v) return 0; } +static void netlbladdr_seq_stop(struct seq_file *s, void *v) +{ + /* No-op */ +} + static const struct seq_operations netlbladdr_seq_ops = { .start = netlbladdr_seq_start, + .stop = netlbladdr_seq_stop, .next = netlbladdr_seq_next, .show = netlbladdr_seq_show, - .stop = smk_seq_stop, }; /** @@ -1111,9 +833,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, { struct smk_netlbladdr *skp; struct sockaddr_in newname; - char *smack; + char smack[SMK_LABELLEN]; char *sp; - char *data; + char data[SMK_NETLBLADDRMAX + 1]; char *host = (char *)&newname.sin_addr.s_addr; int rc; struct netlbl_audit audit_info; @@ -1131,27 +853,14 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, * "<addr/mask, as a.b.c.d/e><space><label>" * "<addr, as a.b.c.d><space><label>" */ - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; if (*ppos != 0) return -EINVAL; - if (count < SMK_NETLBLADDRMIN) + if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX) return -EINVAL; - - data = kzalloc(count + 1, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - if (copy_from_user(data, buf, count) != 0) { - rc = -EFAULT; - goto free_data_out; - } - - smack = kzalloc(count + 1, GFP_KERNEL); - if (smack == NULL) { - rc = -ENOMEM; - goto free_data_out; - } + if (copy_from_user(data, buf, count) != 0) + return -EFAULT; data[count] = '\0'; @@ -1160,34 +869,24 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, if (rc != 6) { rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", &host[0], &host[1], &host[2], &host[3], smack); - if (rc != 5) { - rc = -EINVAL; - goto free_out; - } + if (rc != 5) + return -EINVAL; m = BEBITS; } - if (m > BEBITS) { - rc = -EINVAL; - goto free_out; - } + if (m > BEBITS) + return -EINVAL; - /* - * If smack begins with '-', it is an option, don't import it - */ + /* if smack begins with '-', its an option, don't import it */ if (smack[0] != '-') { sp = smk_import(smack, 0); - if (sp == NULL) { - rc = -EINVAL; - goto free_out; - } + if (sp == NULL) + return -EINVAL; } else { /* check known options */ if (strcmp(smack, smack_cipso_option) == 0) sp = (char *)smack_cipso_option; - else { - rc = -EINVAL; - goto free_out; - } + else + return -EINVAL; } for (temp_mask = 0; m > 0; m--) { @@ -1253,11 +952,6 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, mutex_unlock(&smk_netlbladdr_lock); -free_out: - kfree(smack); -free_data_out: - kfree(data); - return rc; } @@ -1308,7 +1002,7 @@ static ssize_t smk_write_doi(struct file *file, const char __user *buf, char temp[80]; int i; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; if (count >= sizeof(temp) || count == 0) @@ -1371,11 +1065,10 @@ static ssize_t smk_read_direct(struct file *filp, char __user *buf, static ssize_t smk_write_direct(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct smack_known *skp; char temp[80]; int i; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; if (count >= sizeof(temp) || count == 0) @@ -1389,20 +1082,7 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, if (sscanf(temp, "%d", &i) != 1) return -EINVAL; - /* - * Don't do anything if the value hasn't actually changed. - * If it is changing reset the level on entries that were - * set up to be direct when they were created. - */ - if (smack_cipso_direct != i) { - mutex_lock(&smack_known_lock); - list_for_each_entry_rcu(skp, &smack_known_list, list) - if (skp->smk_netlabel.attr.mls.lvl == - smack_cipso_direct) - skp->smk_netlabel.attr.mls.lvl = i; - smack_cipso_direct = i; - mutex_unlock(&smack_known_lock); - } + smack_cipso_direct = i; return count; } @@ -1414,84 +1094,6 @@ static const struct file_operations smk_direct_ops = { }; /** - * smk_read_mapped - read() for /smack/mapped - * @filp: file pointer, not actually used - * @buf: where to put the result - * @count: maximum to send along - * @ppos: where to start - * - * Returns number of bytes read or error code, as appropriate - */ -static ssize_t smk_read_mapped(struct file *filp, char __user *buf, - size_t count, loff_t *ppos) -{ - char temp[80]; - ssize_t rc; - - if (*ppos != 0) - return 0; - - sprintf(temp, "%d", smack_cipso_mapped); - rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); - - return rc; -} - -/** - * smk_write_mapped - write() for /smack/mapped - * @file: file pointer, not actually used - * @buf: where to get the data from - * @count: bytes sent - * @ppos: where to start - * - * Returns number of bytes written or error code, as appropriate - */ -static ssize_t smk_write_mapped(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct smack_known *skp; - char temp[80]; - int i; - - if (!smack_privileged(CAP_MAC_ADMIN)) - return -EPERM; - - if (count >= sizeof(temp) || count == 0) - return -EINVAL; - - if (copy_from_user(temp, buf, count) != 0) - return -EFAULT; - - temp[count] = '\0'; - - if (sscanf(temp, "%d", &i) != 1) - return -EINVAL; - - /* - * Don't do anything if the value hasn't actually changed. - * If it is changing reset the level on entries that were - * set up to be mapped when they were created. - */ - if (smack_cipso_mapped != i) { - mutex_lock(&smack_known_lock); - list_for_each_entry_rcu(skp, &smack_known_list, list) - if (skp->smk_netlabel.attr.mls.lvl == - smack_cipso_mapped) - skp->smk_netlabel.attr.mls.lvl = i; - smack_cipso_mapped = i; - mutex_unlock(&smack_known_lock); - } - - return count; -} - -static const struct file_operations smk_mapped_ops = { - .read = smk_read_mapped, - .write = smk_write_mapped, - .llseek = default_llseek, -}; - -/** * smk_read_ambient - read() for /smack/ambient * @filp: file pointer, not actually used * @buf: where to put the result @@ -1539,28 +1141,22 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, static ssize_t smk_write_ambient(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + char in[SMK_LABELLEN]; char *oldambient; - char *smack = NULL; - char *data; - int rc = count; + char *smack; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; - data = kzalloc(count + 1, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; + if (count >= SMK_LABELLEN) + return -EINVAL; - if (copy_from_user(data, buf, count) != 0) { - rc = -EFAULT; - goto out; - } + if (copy_from_user(in, buf, count) != 0) + return -EFAULT; - smack = smk_import(data, count); - if (smack == NULL) { - rc = -EINVAL; - goto out; - } + smack = smk_import(in, count); + if (smack == NULL) + return -EINVAL; mutex_lock(&smack_ambient_lock); @@ -1570,9 +1166,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, mutex_unlock(&smack_ambient_lock); -out: - kfree(data); - return rc; + return count; } static const struct file_operations smk_ambient_ops = { @@ -1623,11 +1217,10 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - char *data; + char in[SMK_LABELLEN]; char *sp = smk_of_task(current->cred->security); - int rc = count; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; /* @@ -1638,9 +1231,11 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, if (smack_onlycap != NULL && smack_onlycap != sp) return -EPERM; - data = kzalloc(count, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; + if (count >= SMK_LABELLEN) + return -EINVAL; + + if (copy_from_user(in, buf, count) != 0) + return -EFAULT; /* * Should the null string be passed in unset the onlycap value. @@ -1648,17 +1243,10 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, * smk_import only expects to return NULL for errors. It * is usually the case that a nullstring or "\n" would be * bad to pass to smk_import but in fact this is useful here. - * - * smk_import will also reject a label beginning with '-', - * so "-usecapabilities" will also work. */ - if (copy_from_user(data, buf, count) != 0) - rc = -EFAULT; - else - smack_onlycap = smk_import(data, count); + smack_onlycap = smk_import(in, count); - kfree(data); - return rc; + return count; } static const struct file_operations smk_onlycap_ops = { @@ -1705,7 +1293,7 @@ static ssize_t smk_write_logging(struct file *file, const char __user *buf, char temp[32]; int i; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!capable(CAP_MAC_ADMIN)) return -EPERM; if (count >= sizeof(temp) || count == 0) @@ -1740,14 +1328,23 @@ static void *load_self_seq_start(struct seq_file *s, loff_t *pos) { struct task_smack *tsp = current_security(); - return smk_seq_start(s, pos, &tsp->smk_rules); + if (*pos == SEQ_READ_FINISHED) + return NULL; + if (list_empty(&tsp->smk_rules)) + return NULL; + return tsp->smk_rules.next; } static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos) { struct task_smack *tsp = current_security(); + struct list_head *list = v; - return smk_seq_next(s, v, pos, &tsp->smk_rules); + if (list_is_last(list, &tsp->smk_rules)) { + *pos = SEQ_READ_FINISHED; + return NULL; + } + return list->next; } static int load_self_seq_show(struct seq_file *s, void *v) @@ -1756,21 +1353,44 @@ static int load_self_seq_show(struct seq_file *s, void *v) struct smack_rule *srp = list_entry(list, struct smack_rule, list); - smk_rule_show(s, srp, SMK_LABELLEN); + seq_printf(s, "%s %s", (char *)srp->smk_subject, + (char *)srp->smk_object); + + seq_putc(s, ' '); + + if (srp->smk_access & MAY_READ) + seq_putc(s, 'r'); + if (srp->smk_access & MAY_WRITE) + seq_putc(s, 'w'); + if (srp->smk_access & MAY_EXEC) + 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, '-'); + + seq_putc(s, '\n'); return 0; } +static void load_self_seq_stop(struct seq_file *s, void *v) +{ + /* No-op */ +} + static const struct seq_operations load_self_seq_ops = { .start = load_self_seq_start, .next = load_self_seq_next, .show = load_self_seq_show, - .stop = smk_seq_stop, + .stop = load_self_seq_stop, }; /** - * smk_open_load_self - open() for /smack/load-self2 + * smk_open_load_self - open() for /smack/load-self * @inode: inode structure representing file * @file: "load" file pointer * @@ -1794,8 +1414,8 @@ static ssize_t smk_write_load_self(struct file *file, const char __user *buf, { struct task_smack *tsp = current_security(); - return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, - &tsp->smk_rules_lock, SMK_FIXED24_FMT); + return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules, + &tsp->smk_rules_lock); } static const struct file_operations smk_load_self_ops = { @@ -1805,333 +1425,6 @@ static const struct file_operations smk_load_self_ops = { .write = smk_write_load_self, .release = seq_release, }; - -/** - * smk_user_access - handle access check transaction - * @file: file pointer - * @buf: data from user space - * @count: bytes sent - * @ppos: where to start - must be 0 - */ -static ssize_t smk_user_access(struct file *file, const char __user *buf, - size_t count, loff_t *ppos, int format) -{ - struct smack_rule rule; - char *data; - char *cod; - int res; - - data = simple_transaction_get(file, buf, count); - if (IS_ERR(data)) - return PTR_ERR(data); - - if (format == SMK_FIXED24_FMT) { - if (count < SMK_LOADLEN) - return -EINVAL; - res = smk_parse_rule(data, &rule, 0); - } else { - /* - * Copy the data to make sure the string is terminated. - */ - cod = kzalloc(count + 1, GFP_KERNEL); - if (cod == NULL) - return -ENOMEM; - memcpy(cod, data, count); - cod[count] = '\0'; - res = smk_parse_long_rule(cod, &rule, 0, 0); - kfree(cod); - } - - if (res) - return -EINVAL; - - res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, - NULL); - data[0] = res == 0 ? '1' : '0'; - data[1] = '\0'; - - simple_transaction_set(file, 2); - - if (format == SMK_FIXED24_FMT) - return SMK_LOADLEN; - return count; -} - -/** - * smk_write_access - handle access check transaction - * @file: file pointer - * @buf: data from user space - * @count: bytes sent - * @ppos: where to start - must be 0 - */ -static ssize_t smk_write_access(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return smk_user_access(file, buf, count, ppos, SMK_FIXED24_FMT); -} - -static const struct file_operations smk_access_ops = { - .write = smk_write_access, - .read = simple_transaction_read, - .release = simple_transaction_release, - .llseek = generic_file_llseek, -}; - - -/* - * Seq_file read operations for /smack/load2 - */ - -static int load2_seq_show(struct seq_file *s, void *v) -{ - struct list_head *list = v; - struct smack_master_list *smlp = - list_entry(list, struct smack_master_list, list); - - smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); - - return 0; -} - -static const struct seq_operations load2_seq_ops = { - .start = load2_seq_start, - .next = load2_seq_next, - .show = load2_seq_show, - .stop = smk_seq_stop, -}; - -/** - * smk_open_load2 - open() for /smack/load2 - * @inode: inode structure representing file - * @file: "load2" file pointer - * - * For reading, use load2_seq_* seq_file reading operations. - */ -static int smk_open_load2(struct inode *inode, struct file *file) -{ - return seq_open(file, &load2_seq_ops); -} - -/** - * smk_write_load2 - write() for /smack/load2 - * @file: file pointer, not actually used - * @buf: where to get the data from - * @count: bytes sent - * @ppos: where to start - must be 0 - * - */ -static ssize_t smk_write_load2(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - /* - * Must have privilege. - */ - if (!smack_privileged(CAP_MAC_ADMIN)) - return -EPERM; - - return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, - SMK_LONG_FMT); -} - -static const struct file_operations smk_load2_ops = { - .open = smk_open_load2, - .read = seq_read, - .llseek = seq_lseek, - .write = smk_write_load2, - .release = seq_release, -}; - -/* - * Seq_file read operations for /smack/load-self2 - */ - -static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) -{ - struct task_smack *tsp = current_security(); - - return smk_seq_start(s, pos, &tsp->smk_rules); -} - -static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct task_smack *tsp = current_security(); - - return smk_seq_next(s, v, pos, &tsp->smk_rules); -} - -static int load_self2_seq_show(struct seq_file *s, void *v) -{ - struct list_head *list = v; - struct smack_rule *srp = - list_entry(list, struct smack_rule, list); - - smk_rule_show(s, srp, SMK_LONGLABEL); - - return 0; -} - -static const struct seq_operations load_self2_seq_ops = { - .start = load_self2_seq_start, - .next = load_self2_seq_next, - .show = load_self2_seq_show, - .stop = smk_seq_stop, -}; - -/** - * smk_open_load_self2 - open() for /smack/load-self2 - * @inode: inode structure representing file - * @file: "load" file pointer - * - * For reading, use load_seq_* seq_file reading operations. - */ -static int smk_open_load_self2(struct inode *inode, struct file *file) -{ - return seq_open(file, &load_self2_seq_ops); -} - -/** - * smk_write_load_self2 - write() for /smack/load-self2 - * @file: file pointer, not actually used - * @buf: where to get the data from - * @count: bytes sent - * @ppos: where to start - must be 0 - * - */ -static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct task_smack *tsp = current_security(); - - return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, - &tsp->smk_rules_lock, SMK_LONG_FMT); -} - -static const struct file_operations smk_load_self2_ops = { - .open = smk_open_load_self2, - .read = seq_read, - .llseek = seq_lseek, - .write = smk_write_load_self2, - .release = seq_release, -}; - -/** - * smk_write_access2 - handle access check transaction - * @file: file pointer - * @buf: data from user space - * @count: bytes sent - * @ppos: where to start - must be 0 - */ -static ssize_t smk_write_access2(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return smk_user_access(file, buf, count, ppos, SMK_LONG_FMT); -} - -static const struct file_operations smk_access2_ops = { - .write = smk_write_access2, - .read = simple_transaction_read, - .release = simple_transaction_release, - .llseek = generic_file_llseek, -}; - -/** - * smk_write_revoke_subj - write() for /smack/revoke-subject - * @file: file pointer - * @buf: data from user space - * @count: bytes sent - * @ppos: where to start - must be 0 - */ -static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - char *data = NULL; - const char *cp = NULL; - struct smack_known *skp; - struct smack_rule *sp; - struct list_head *rule_list; - struct mutex *rule_lock; - int rc = count; - - if (*ppos != 0) - return -EINVAL; - - if (!smack_privileged(CAP_MAC_ADMIN)) - return -EPERM; - - if (count == 0 || count > SMK_LONGLABEL) - return -EINVAL; - - data = kzalloc(count, GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - if (copy_from_user(data, buf, count) != 0) { - rc = -EFAULT; - goto free_out; - } - - cp = smk_parse_smack(data, count); - if (cp == NULL) { - rc = -EINVAL; - goto free_out; - } - - skp = smk_find_entry(cp); - if (skp == NULL) { - rc = -EINVAL; - goto free_out; - } - - rule_list = &skp->smk_rules; - rule_lock = &skp->smk_rules_lock; - - mutex_lock(rule_lock); - - list_for_each_entry_rcu(sp, rule_list, list) - sp->smk_access = 0; - - mutex_unlock(rule_lock); - -free_out: - kfree(data); - kfree(cp); - return rc; -} - -static const struct file_operations smk_revoke_subj_ops = { - .write = smk_write_revoke_subj, - .read = simple_transaction_read, - .release = simple_transaction_release, - .llseek = generic_file_llseek, -}; - -/** - * smk_write_change_rule - write() for /smack/change-rule - * @file: file pointer - * @buf: data from user space - * @count: bytes sent - * @ppos: where to start - must be 0 - */ -static ssize_t smk_write_change_rule(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - /* - * Must have privilege. - */ - if (!capable(CAP_MAC_ADMIN)) - return -EPERM; - - return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, - SMK_CHANGE_FMT); -} - -static const struct file_operations smk_change_rule_ops = { - .write = smk_write_change_rule, - .read = simple_transaction_read, - .release = simple_transaction_release, - .llseek = generic_file_llseek, -}; - /** * smk_fill_super - fill the /smackfs superblock * @sb: the empty superblock @@ -2166,23 +1459,6 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) "logging", &smk_logging_ops, S_IRUGO|S_IWUSR}, [SMK_LOAD_SELF] = { "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, - [SMK_ACCESSES] = { - "access", &smk_access_ops, S_IRUGO|S_IWUGO}, - [SMK_MAPPED] = { - "mapped", &smk_mapped_ops, S_IRUGO|S_IWUSR}, - [SMK_LOAD2] = { - "load2", &smk_load2_ops, S_IRUGO|S_IWUSR}, - [SMK_LOAD_SELF2] = { - "load-self2", &smk_load_self2_ops, S_IRUGO|S_IWUGO}, - [SMK_ACCESS2] = { - "access2", &smk_access2_ops, S_IRUGO|S_IWUGO}, - [SMK_CIPSO2] = { - "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR}, - [SMK_REVOKE_SUBJ] = { - "revoke-subject", &smk_revoke_subj_ops, - S_IRUGO|S_IWUSR}, - [SMK_CHANGE_RULE] = { - "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, /* last one */ {""} }; @@ -2225,15 +1501,6 @@ static struct file_system_type smk_fs_type = { static struct vfsmount *smackfs_mount; -static int __init smk_preset_netlabel(struct smack_known *skp) -{ - skp->smk_netlabel.domain = skp->smk_known; - skp->smk_netlabel.flags = - NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; - return smk_netlbl_mls(smack_cipso_direct, skp->smk_known, - &skp->smk_netlabel, strlen(skp->smk_known)); -} - /** * init_smk_fs - get the smackfs superblock * @@ -2250,7 +1517,6 @@ static int __init smk_preset_netlabel(struct smack_known *skp) static int __init init_smk_fs(void) { int err; - int rc; if (!security_module_enable(&smack_ops)) return 0; @@ -2268,25 +1534,6 @@ static int __init init_smk_fs(void) smk_cipso_doi(); smk_unlbl_ambient(NULL); - rc = smk_preset_netlabel(&smack_known_floor); - if (err == 0 && rc < 0) - err = rc; - rc = smk_preset_netlabel(&smack_known_hat); - if (err == 0 && rc < 0) - err = rc; - rc = smk_preset_netlabel(&smack_known_huh); - if (err == 0 && rc < 0) - err = rc; - rc = smk_preset_netlabel(&smack_known_invalid); - if (err == 0 && rc < 0) - err = rc; - rc = smk_preset_netlabel(&smack_known_star); - if (err == 0 && rc < 0) - err = rc; - rc = smk_preset_netlabel(&smack_known_web); - if (err == 0 && rc < 0) - err = rc; - return err; } |