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 @@
#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_MAXLEN 23
#define SMK_LABELLEN (SMK_MAXLEN+1)
#define SMK_CIPSOLEN 24
struct superblock_smack {
char *smk_root;
......@@ -66,6 +72,7 @@ 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.
......@@ -77,15 +84,6 @@ struct smack_rule {
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.
*/
......@@ -113,22 +111,19 @@ struct smk_netlbladdr {
* interfaces don't. The secid should go away when all of
* these components have been repaired.
*
* 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.
* The cipso value associated with the label gets stored here, too.
*
* Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every
* time.
*/
struct smack_known {
struct list_head list;
char smk_known[SMK_LABELLEN];
u32 smk_secid;
struct smack_cipso *smk_cipso;
spinlock_t smk_cipsolock; /* for changing cipso map */
struct list_head smk_rules; /* access rules */
struct mutex smk_rules_lock; /* lock for the rules */
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 */
};
/*
......@@ -165,6 +160,7 @@ 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 */
......@@ -215,10 +211,9 @@ 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 *);
char *smack_from_cipso(u32, char *);
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);
struct smack_known *smk_import_entry(const char *, int);
struct smack_known *smk_find_entry(const char *);
......@@ -228,6 +223,7 @@ 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;
......@@ -239,23 +235,12 @@ 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 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?
*/
......
......@@ -19,37 +19,31 @@
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);
......@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request,
}
#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
......@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string)
struct smack_known *skp;
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;
}
......@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string)
* 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.
* @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;
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 (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;
}
/**
......@@ -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 *skp;
char smack[SMK_LABELLEN];
char *smack;
int slen;
int rc;
smk_parse_smack(string, len, smack);
if (smack[0] == '\0')
smack = smk_parse_smack(string, len);
if (smack == NULL)
return NULL;
mutex_lock(&smack_known_lock);
skp = smk_find_entry(smack);
if (skp != NULL)
goto freeout;
if (skp == NULL) {
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;
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 = kzalloc(sizeof(*skp), GFP_KERNEL);
if (skp == NULL)
goto freeout;
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);
return skp;
......@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid)
*/
u32 smack_to_secid(const char *smack)
{
struct smack_known *skp;
struct smack_known *skp = smk_find_entry(smack);
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
*
* 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;
if (skp == NULL)
return 0;
return skp->smk_secid;
}
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