Commit 12fa8a27 authored by James Morris's avatar James Morris

Merge branch 'for-1205' of http://git.gitorious.org/smack-next/kernel into next

Pull request from Casey.
parents b404aef7 f7112e6c
This diff is collapsed.
...@@ -23,13 +23,19 @@ ...@@ -23,13 +23,19 @@
#include <linux/lsm_audit.h> #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 * 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 * 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 * of 8, and there are too many issues if there isn't space set
* aside for the terminating null byte. * aside for the terminating null byte.
*/ */
#define SMK_MAXLEN 23 #define SMK_CIPSOLEN 24
#define SMK_LABELLEN (SMK_MAXLEN+1)
struct superblock_smack { struct superblock_smack {
char *smk_root; char *smk_root;
...@@ -66,6 +72,7 @@ struct task_smack { ...@@ -66,6 +72,7 @@ struct task_smack {
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
#define SMK_INODE_CHANGED 0x04 /* smack was transmuted */
/* /*
* A label access rule. * A label access rule.
...@@ -77,15 +84,6 @@ struct smack_rule { ...@@ -77,15 +84,6 @@ struct smack_rule {
int smk_access; int smk_access;
}; };
/*
* 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. * An entry in the table identifying hosts.
*/ */
...@@ -113,22 +111,19 @@ struct smk_netlbladdr { ...@@ -113,22 +111,19 @@ struct smk_netlbladdr {
* interfaces don't. The secid should go away when all of * interfaces don't. The secid should go away when all of
* these components have been repaired. * these components have been repaired.
* *
* If there is a cipso value associated with the label it * The cipso value associated with the label gets stored here, too.
* gets stored here, too. This will most likely be rare as
* the cipso direct mapping in used internally.
* *
* Keep the access rules for this subject label here so that * Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every * the entire set of rules does not need to be examined every
* time. * time.
*/ */
struct smack_known { struct smack_known {
struct list_head list; struct list_head list;
char smk_known[SMK_LABELLEN]; char *smk_known;
u32 smk_secid; u32 smk_secid;
struct smack_cipso *smk_cipso; struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
spinlock_t smk_cipsolock; /* for changing cipso map */ struct list_head smk_rules; /* access rules */
struct list_head smk_rules; /* access rules */ struct mutex smk_rules_lock; /* lock for rules */
struct mutex smk_rules_lock; /* lock for the rules */
}; };
/* /*
...@@ -165,6 +160,7 @@ struct smack_known { ...@@ -165,6 +160,7 @@ struct smack_known {
#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
#define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */
#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ #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_MAXCATVAL 63 /* Bigger gets harder */
#define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */
#define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */
...@@ -215,10 +211,9 @@ struct inode_smack *new_inode_smack(char *); ...@@ -215,10 +211,9 @@ struct inode_smack *new_inode_smack(char *);
int smk_access_entry(char *, char *, struct list_head *); int smk_access_entry(char *, char *, struct list_head *);
int smk_access(char *, char *, int, struct smk_audit_info *); int smk_access(char *, char *, int, struct smk_audit_info *);
int smk_curacc(char *, u32, struct smk_audit_info *); int smk_curacc(char *, u32, struct smk_audit_info *);
int smack_to_cipso(const char *, struct smack_cipso *);
char *smack_from_cipso(u32, char *);
char *smack_from_secid(const u32); char *smack_from_secid(const u32);
void smk_parse_smack(const char *string, int len, char *smack); 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); char *smk_import(const char *, int);
struct smack_known *smk_import_entry(const char *, int); struct smack_known *smk_import_entry(const char *, int);
struct smack_known *smk_find_entry(const char *); struct smack_known *smk_find_entry(const char *);
...@@ -228,6 +223,7 @@ u32 smack_to_secid(const char *); ...@@ -228,6 +223,7 @@ u32 smack_to_secid(const char *);
* Shared data. * Shared data.
*/ */
extern int smack_cipso_direct; extern int smack_cipso_direct;
extern int smack_cipso_mapped;
extern char *smack_net_ambient; extern char *smack_net_ambient;
extern char *smack_onlycap; extern char *smack_onlycap;
extern const char *smack_cipso_option; extern const char *smack_cipso_option;
...@@ -239,23 +235,12 @@ extern struct smack_known smack_known_invalid; ...@@ -239,23 +235,12 @@ extern struct smack_known smack_known_invalid;
extern struct smack_known smack_known_star; extern struct smack_known smack_known_star;
extern struct smack_known smack_known_web; 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_known_list;
extern struct list_head smk_netlbladdr_list; extern struct list_head smk_netlbladdr_list;
extern struct security_operations smack_ops; 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? * Is the directory transmuting?
*/ */
......
...@@ -19,37 +19,31 @@ ...@@ -19,37 +19,31 @@
struct smack_known smack_known_huh = { struct smack_known smack_known_huh = {
.smk_known = "?", .smk_known = "?",
.smk_secid = 2, .smk_secid = 2,
.smk_cipso = NULL,
}; };
struct smack_known smack_known_hat = { struct smack_known smack_known_hat = {
.smk_known = "^", .smk_known = "^",
.smk_secid = 3, .smk_secid = 3,
.smk_cipso = NULL,
}; };
struct smack_known smack_known_star = { struct smack_known smack_known_star = {
.smk_known = "*", .smk_known = "*",
.smk_secid = 4, .smk_secid = 4,
.smk_cipso = NULL,
}; };
struct smack_known smack_known_floor = { struct smack_known smack_known_floor = {
.smk_known = "_", .smk_known = "_",
.smk_secid = 5, .smk_secid = 5,
.smk_cipso = NULL,
}; };
struct smack_known smack_known_invalid = { struct smack_known smack_known_invalid = {
.smk_known = "", .smk_known = "",
.smk_secid = 6, .smk_secid = 6,
.smk_cipso = NULL,
}; };
struct smack_known smack_known_web = { struct smack_known smack_known_web = {
.smk_known = "@", .smk_known = "@",
.smk_secid = 7, .smk_secid = 7,
.smk_cipso = NULL,
}; };
LIST_HEAD(smack_known_list); LIST_HEAD(smack_known_list);
...@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request, ...@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request,
} }
#endif #endif
static DEFINE_MUTEX(smack_known_lock); DEFINE_MUTEX(smack_known_lock);
/** /**
* smk_find_entry - find a label on the list, return the list entry * smk_find_entry - find a label on the list, return the list entry
...@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string) ...@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string)
struct smack_known *skp; struct smack_known *skp;
list_for_each_entry_rcu(skp, &smack_known_list, list) { list_for_each_entry_rcu(skp, &smack_known_list, list) {
if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0) if (strcmp(skp->smk_known, string) == 0)
return skp; return skp;
} }
...@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string) ...@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string)
* smk_parse_smack - parse smack label from a text string * smk_parse_smack - parse smack label from a text string
* @string: a text string that might contain a Smack label * @string: a text string that might contain a Smack label
* @len: the maximum size, or zero if it is NULL terminated. * @len: the maximum size, or zero if it is NULL terminated.
* @smack: parsed smack label, or NULL if parse error *
* Returns a pointer to the clean label, or NULL
*/ */
void smk_parse_smack(const char *string, int len, char *smack) char *smk_parse_smack(const char *string, int len)
{ {
int found; char *smack;
int i; int i;
if (len <= 0 || len > SMK_MAXLEN) if (len <= 0)
len = SMK_MAXLEN; len = strlen(string) + 1;
for (i = 0, found = 0; i < SMK_LABELLEN; i++) { /*
if (found) * Reserve a leading '-' as an indicator that
smack[i] = '\0'; * this isn't a label, but an option to interfaces
else if (i >= len || string[i] > '~' || string[i] <= ' ' || * including /smack/cipso and /smack/cipso2
string[i] == '/' || string[i] == '"' || */
string[i] == '\\' || string[i] == '\'') { if (string[0] == '-')
smack[i] = '\0'; return NULL;
found = 1;
} else for (i = 0; i < len; i++)
smack[i] = string[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;
} }
/** /**
...@@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack) ...@@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack)
struct smack_known *smk_import_entry(const char *string, int len) struct smack_known *smk_import_entry(const char *string, int len)
{ {
struct smack_known *skp; struct smack_known *skp;
char smack[SMK_LABELLEN]; char *smack;
int slen;
int rc;
smk_parse_smack(string, len, smack); smack = smk_parse_smack(string, len);
if (smack[0] == '\0') if (smack == NULL)
return NULL; return NULL;
mutex_lock(&smack_known_lock); mutex_lock(&smack_known_lock);
skp = smk_find_entry(smack); skp = smk_find_entry(smack);
if (skp != NULL)
goto freeout;
if (skp == NULL) { skp = kzalloc(sizeof(*skp), GFP_KERNEL);
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); if (skp == NULL)
if (skp != NULL) { goto freeout;
strncpy(skp->smk_known, smack, SMK_MAXLEN);
skp->smk_secid = smack_next_secid++;
skp->smk_cipso = NULL;
INIT_LIST_HEAD(&skp->smk_rules);
spin_lock_init(&skp->smk_cipsolock);
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);
}
}
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;
}
/*
* smk_netlbl_mls failed.
*/
kfree(skp);
skp = NULL;
freeout:
kfree(smack);
unlockout:
mutex_unlock(&smack_known_lock); mutex_unlock(&smack_known_lock);
return skp; return skp;
...@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid) ...@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid)
*/ */
u32 smack_to_secid(const char *smack) u32 smack_to_secid(const char *smack)
{ {
struct smack_known *skp; struct smack_known *skp = smk_find_entry(smack);
rcu_read_lock(); if (skp == NULL)
list_for_each_entry_rcu(skp, &smack_known_list, list) { return 0;
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { return skp->smk_secid;
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
*
* This is a simple lookup in the label table.
*
* Return the matching label from the label list or NULL.
*/
char *smack_from_cipso(u32 level, char *cp)
{
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);
if (final != NULL)
break;
}
rcu_read_unlock();
return final;
}
/**
* 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;
} }
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment