Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7198e2ee authored by Etienne Basset's avatar Etienne Basset Committed by James Morris
Browse files

smack: convert smack to standard linux lists



the following patch (on top of 2.6.29) converts Smack lists to standard linux lists
Please review and consider for inclusion in 2.6.30-rc

regards,
Etienne

Signed-off-by: default avatarEtienne Basset <etienne.basset@numericable.fr>
Acked-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
parent 703a3cd7
Loading
Loading
Loading
Loading
+12 −16
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#include <linux/security.h>
#include <linux/in.h>
#include <net/netlabel.h>
#include <linux/list.h>
#include <linux/rculist.h>

/*
 * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
@@ -59,19 +61,12 @@ struct inode_smack {
 * A label access rule.
 */
struct smack_rule {
	struct list_head	list;
	char			*smk_subject;
	char			*smk_object;
	int			smk_access;
};

/*
 * An entry in the table of permitted label accesses.
 */
struct smk_list_entry {
	struct smk_list_entry	*smk_next;
	struct smack_rule	smk_rule;
};

/*
 * An entry in the table mapping smack values to
 * CIPSO level/category-set values.
@@ -85,7 +80,7 @@ struct smack_cipso {
 * An entry in the table identifying hosts.
 */
struct smk_netlbladdr {
	struct smk_netlbladdr	*smk_next;
	struct list_head	list;
	struct sockaddr_in	smk_host;	/* network address */
	struct in_addr		smk_mask;	/* network mask */
	char			*smk_label;	/* label */
@@ -113,7 +108,7 @@ struct smk_netlbladdr {
 * the cipso direct mapping in used internally.
 */
struct smack_known {
	struct smack_known	*smk_next;
	struct list_head	list;
	char			smk_known[SMK_LABELLEN];
	u32			smk_secid;
	struct smack_cipso	*smk_cipso;
@@ -206,7 +201,6 @@ extern int smack_cipso_direct;
extern char *smack_net_ambient;
extern char *smack_onlycap;

extern struct smack_known *smack_known;
extern struct smack_known smack_known_floor;
extern struct smack_known smack_known_hat;
extern struct smack_known smack_known_huh;
@@ -214,8 +208,10 @@ extern struct smack_known smack_known_invalid;
extern struct smack_known smack_known_star;
extern struct smack_known smack_known_web;

extern struct smk_list_entry *smack_list;
extern struct smk_netlbladdr *smack_netlbladdrs;
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;

/*
+38 −25
Original line number Diff line number Diff line
@@ -16,48 +16,42 @@
#include "smack.h"

struct smack_known smack_known_huh = {
	.smk_next	= NULL,
	.smk_known	= "?",
	.smk_secid	= 2,
	.smk_cipso	= NULL,
};

struct smack_known smack_known_hat = {
	.smk_next	= &smack_known_huh,
	.smk_known	= "^",
	.smk_secid	= 3,
	.smk_cipso	= NULL,
};

struct smack_known smack_known_star = {
	.smk_next	= &smack_known_hat,
	.smk_known	= "*",
	.smk_secid	= 4,
	.smk_cipso	= NULL,
};

struct smack_known smack_known_floor = {
	.smk_next	= &smack_known_star,
	.smk_known	= "_",
	.smk_secid	= 5,
	.smk_cipso	= NULL,
};

struct smack_known smack_known_invalid = {
	.smk_next	= &smack_known_floor,
	.smk_known	= "",
	.smk_secid	= 6,
	.smk_cipso	= NULL,
};

struct smack_known smack_known_web = {
	.smk_next	= &smack_known_invalid,
	.smk_known	= "@",
	.smk_secid	= 7,
	.smk_cipso	= NULL,
};

struct smack_known *smack_known = &smack_known_web;
LIST_HEAD(smack_known_list);

/*
 * The initial value needs to be bigger than any of the
@@ -87,7 +81,6 @@ static u32 smack_next_secid = 10;
int smk_access(char *subject_label, char *object_label, int request)
{
	u32 may = MAY_NOT;
	struct smk_list_entry *sp;
	struct smack_rule *srp;

	/*
@@ -139,9 +132,8 @@ int smk_access(char *subject_label, char *object_label, int request)
	 * access (e.g. read is included in readwrite) it's
	 * good.
	 */
	for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
		srp = &sp->smk_rule;

	rcu_read_lock();
	list_for_each_entry_rcu(srp, &smack_rule_list, list) {
		if (srp->smk_subject == subject_label ||
		    strcmp(srp->smk_subject, subject_label) == 0) {
			if (srp->smk_object == object_label ||
@@ -151,6 +143,7 @@ int smk_access(char *subject_label, char *object_label, int request)
			}
		}
	}
	rcu_read_unlock();
	/*
	 * This is a bit map operation.
	 */
@@ -228,14 +221,17 @@ struct smack_known *smk_import_entry(const char *string, int len)

	mutex_lock(&smack_known_lock);

	for (skp = smack_known; skp != NULL; skp = skp->smk_next)
		if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
	found = 0;
	list_for_each_entry_rcu(skp, &smack_known_list, list) {
		if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
			found = 1;
			break;
		}
	}

	if (skp == NULL) {
	if (found == 0) {
		skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
		if (skp != NULL) {
			skp->smk_next = smack_known;
			strncpy(skp->smk_known, smack, SMK_MAXLEN);
			skp->smk_secid = smack_next_secid++;
			skp->smk_cipso = NULL;
@@ -244,8 +240,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
			 * Make sure that the entry is actually
			 * filled before putting it on the list.
			 */
			smp_mb();
			smack_known = skp;
			list_add_rcu(&skp->list, &smack_known_list);
		}
	}

@@ -283,14 +278,19 @@ char *smack_from_secid(const u32 secid)
{
	struct smack_known *skp;

	for (skp = smack_known; skp != NULL; skp = skp->smk_next)
		if (skp->smk_secid == secid)
	rcu_read_lock();
	list_for_each_entry_rcu(skp, &smack_known_list, list) {
		if (skp->smk_secid == secid) {
			rcu_read_unlock();
			return skp->smk_known;
		}
	}

	/*
	 * If we got this far someone asked for the translation
	 * of a secid that is not on the list.
	 */
	rcu_read_unlock();
	return smack_known_invalid.smk_known;
}

@@ -305,9 +305,14 @@ u32 smack_to_secid(const char *smack)
{
	struct smack_known *skp;

	for (skp = smack_known; skp != NULL; skp = skp->smk_next)
		if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
	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;
}

@@ -332,7 +337,8 @@ void smack_from_cipso(u32 level, char *cp, char *result)
	struct smack_known *kp;
	char *final = NULL;

	for (kp = smack_known; final == NULL && kp != NULL; kp = kp->smk_next) {
	rcu_read_lock();
	list_for_each_entry(kp, &smack_known_list, list) {
		if (kp->smk_cipso == NULL)
			continue;

@@ -344,6 +350,7 @@ void smack_from_cipso(u32 level, char *cp, char *result)

		spin_unlock_bh(&kp->smk_cipsolock);
	}
	rcu_read_unlock();
	if (final == NULL)
		final = smack_known_huh.smk_known;
	strncpy(result, final, SMK_MAXLEN);
@@ -360,13 +367,19 @@ void smack_from_cipso(u32 level, char *cp, char *result)
int smack_to_cipso(const char *smack, struct smack_cipso *cp)
{
	struct smack_known *kp;
	int found = 0;

	for (kp = smack_known; kp != NULL; kp = kp->smk_next)
	rcu_read_lock();
	list_for_each_entry_rcu(kp, &smack_known_list, list) {
		if (kp->smk_known == smack ||
		    strcmp(kp->smk_known, smack) == 0)
		    strcmp(kp->smk_known, smack) == 0) {
			found = 1;
			break;
		}
	}
	rcu_read_unlock();

	if (kp == NULL || kp->smk_cipso == NULL)
	if (found == 0 || kp->smk_cipso == NULL)
		return -ENOENT;

	memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
+17 −2
Original line number Diff line number Diff line
@@ -1508,7 +1508,8 @@ static char *smack_host_label(struct sockaddr_in *sip)
	if (siap->s_addr == 0)
		return NULL;

	for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
	rcu_read_lock();
	list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) {
		/*
		 * we break after finding the first match because
		 * the list is sorted from longest to shortest mask
@@ -1516,10 +1517,11 @@ static char *smack_host_label(struct sockaddr_in *sip)
		 */
		if ((&snp->smk_host.sin_addr)->s_addr  ==
			(siap->s_addr & (&snp->smk_mask)->s_addr)) {
			rcu_read_unlock();
			return snp->smk_label;
		}
	}

	rcu_read_unlock();
	return NULL;
}

@@ -2930,6 +2932,17 @@ struct security_operations smack_ops = {
	.release_secctx = 		smack_release_secctx,
};


static __init void init_smack_know_list(void)
{
	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);
	list_add(&smack_known_floor.list, &smack_known_list);
	list_add(&smack_known_invalid.list, &smack_known_list);
	list_add(&smack_known_web.list, &smack_known_list);
}

/**
 * smack_init - initialize the smack system
 *
@@ -2950,6 +2963,8 @@ static __init int smack_init(void)
	cred = (struct cred *) current->cred;
	cred->security = &smack_known_floor.smk_known;

	/* initilize the smack_know_list */
	init_smack_know_list();
	/*
	 * Initialize locks
	 */
+101 −79
Original line number Diff line number Diff line
@@ -80,10 +80,11 @@ char *smack_onlycap;
 * Packets are sent there unlabeled, but only from tasks that
 * can write to the specified label.
 */
struct smk_netlbladdr *smack_netlbladdrs;

LIST_HEAD(smk_netlbladdr_list);
LIST_HEAD(smack_rule_list);

static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
struct smk_list_entry *smack_list;

#define	SEQ_READ_FINISHED	1

@@ -134,24 +135,27 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos == SEQ_READ_FINISHED)
		return NULL;

	return smack_list;
	if (list_empty(&smack_rule_list))
		return NULL;
	return smack_rule_list.next;
}

static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	struct smk_list_entry *skp = ((struct smk_list_entry *) v)->smk_next;
	struct list_head *list = v;

	if (skp == NULL)
	if (list_is_last(list, &smack_rule_list)) {
		*pos = SEQ_READ_FINISHED;

	return skp;
		return NULL;
	}
	return list->next;
}

static int load_seq_show(struct seq_file *s, void *v)
{
	struct smk_list_entry *slp = (struct smk_list_entry *) v;
	struct smack_rule *srp = &slp->smk_rule;
	struct list_head *list = v;
	struct smack_rule *srp =
		 list_entry(list, struct smack_rule, list);

	seq_printf(s, "%s %s", (char *)srp->smk_subject,
		   (char *)srp->smk_object);
@@ -212,32 +216,23 @@ static int smk_open_load(struct inode *inode, struct file *file)
 */
static int smk_set_access(struct smack_rule *srp)
{
	struct smk_list_entry *sp;
	struct smk_list_entry *newp;
	struct smack_rule *sp;
	int ret = 0;

	int found;
	mutex_lock(&smack_list_lock);

	for (sp = smack_list; sp != NULL; sp = sp->smk_next)
		if (sp->smk_rule.smk_subject == srp->smk_subject &&
		    sp->smk_rule.smk_object == srp->smk_object) {
			sp->smk_rule.smk_access = srp->smk_access;
	found = 0;
	list_for_each_entry_rcu(sp, &smack_rule_list, list) {
		if (sp->smk_subject == srp->smk_subject &&
		    sp->smk_object == srp->smk_object) {
			found = 1;
			sp->smk_access = srp->smk_access;
			break;
		}

	if (sp == NULL) {
		newp = kzalloc(sizeof(struct smk_list_entry), GFP_KERNEL);
		if (newp == NULL) {
			ret = -ENOMEM;
			goto out;
	}
	if (found == 0)
		list_add_rcu(&srp->list, &smack_rule_list);

		newp->smk_rule = *srp;
		newp->smk_next = smack_list;
		smack_list = newp;
	}

out:
	mutex_unlock(&smack_list_lock);

	return ret;
@@ -261,7 +256,7 @@ static int smk_set_access(struct smack_rule *srp)
static ssize_t smk_write_load(struct file *file, const char __user *buf,
			      size_t count, loff_t *ppos)
{
	struct smack_rule rule;
	struct smack_rule *rule;
	char *data;
	int rc = -EINVAL;

@@ -272,9 +267,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
	 */
	if (!capable(CAP_MAC_ADMIN))
		return -EPERM;
	if (*ppos != 0)
		return -EINVAL;
	if (count != SMK_LOADLEN)

	if (*ppos != 0 || count != SMK_LOADLEN)
		return -EINVAL;

	data = kzalloc(count, GFP_KERNEL);
@@ -286,25 +280,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
		goto out;
	}

	rule.smk_subject = smk_import(data, 0);
	if (rule.smk_subject == NULL)
	rule = kzalloc(sizeof(*rule), GFP_KERNEL);
	if (rule == NULL) {
		rc = -ENOMEM;
		goto out;
	}

	rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
	if (rule.smk_object == NULL)
		goto out;
	rule->smk_subject = smk_import(data, 0);
	if (rule->smk_subject == NULL)
		goto out_free_rule;

	rule.smk_access = 0;
	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;
		rule->smk_access |= MAY_READ;
		break;
	default:
		goto out;
		goto out_free_rule;
	}

	switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
@@ -312,10 +312,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
		break;
	case 'w':
	case 'W':
		rule.smk_access |= MAY_WRITE;
		rule->smk_access |= MAY_WRITE;
		break;
	default:
		goto out;
		goto out_free_rule;
	}

	switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
@@ -323,10 +323,10 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
		break;
	case 'x':
	case 'X':
		rule.smk_access |= MAY_EXEC;
		rule->smk_access |= MAY_EXEC;
		break;
	default:
		goto out;
		goto out_free_rule;
	}

	switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
@@ -334,17 +334,20 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
		break;
	case 'a':
	case 'A':
		rule.smk_access |= MAY_APPEND;
		rule->smk_access |= MAY_APPEND;
		break;
	default:
		goto out;
		goto out_free_rule;
	}

	rc = smk_set_access(&rule);
	rc = smk_set_access(rule);

	if (!rc)
		rc = count;
	goto out;

out_free_rule:
	kfree(rule);
out:
	kfree(data);
	return rc;
@@ -433,24 +436,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos == SEQ_READ_FINISHED)
		return NULL;
	if (list_empty(&smack_known_list))
		return NULL;

	return smack_known;
	return smack_known_list.next;
}

static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	struct smack_known *skp = ((struct smack_known *) v)->smk_next;
	struct list_head  *list = v;

	/*
	 * Omit labels with no associated cipso value
	 * labels with no associated cipso value wont be printed
	 * in cipso_seq_show
	 */
	while (skp != NULL && !skp->smk_cipso)
		skp = skp->smk_next;

	if (skp == NULL)
	if (list_is_last(list, &smack_known_list)) {
		*pos = SEQ_READ_FINISHED;
		return NULL;
	}

	return skp;
	return list->next;
}

/*
@@ -459,7 +464,9 @@ static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
 */
static int cipso_seq_show(struct seq_file *s, void *v)
{
	struct smack_known *skp = (struct smack_known *) v;
	struct list_head  *list = v;
	struct smack_known *skp =
		 list_entry(list, struct smack_known, list);
	struct smack_cipso *scp = skp->smk_cipso;
	char *cbp;
	char sep = '/';
@@ -638,18 +645,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos == SEQ_READ_FINISHED)
		return NULL;

	return smack_netlbladdrs;
	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)
{
	struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
	struct list_head *list = v;

	if (skp == NULL)
	if (list_is_last(list, &smk_netlbladdr_list)) {
		*pos = SEQ_READ_FINISHED;
		return NULL;
	}

	return skp;
	return list->next;
}
#define BEBITS	(sizeof(__be32) * 8)

@@ -658,7 +668,9 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
 */
static int netlbladdr_seq_show(struct seq_file *s, void *v)
{
	struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
	struct list_head *list = v;
	struct smk_netlbladdr *skp =
			 list_entry(list, struct smk_netlbladdr, list);
	unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
	int maskn;
	u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
@@ -702,30 +714,36 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
 *
 * This helper insert netlabel in the smack_netlbladdrs list
 * sorted by netmask length (longest to smallest)
 * locked by &smk_netlbladdr_lock in smk_write_netlbladdr
 *
 */
static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
{
	struct smk_netlbladdr *m;
	struct smk_netlbladdr *m, *m_next;

	if (smack_netlbladdrs == NULL) {
		smack_netlbladdrs = new;
	if (list_empty(&smk_netlbladdr_list)) {
		list_add_rcu(&new->list, &smk_netlbladdr_list);
		return;
	}

	m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
			 struct smk_netlbladdr, list);

	/* the comparison '>' is a bit hacky, but works */
	if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
		new->smk_next = smack_netlbladdrs;
		smack_netlbladdrs = new;
	if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
		list_add_rcu(&new->list, &smk_netlbladdr_list);
		return;
	}
	for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
		if (m->smk_next == NULL) {
			m->smk_next = new;

	list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
		if (list_is_last(&m->list, &smk_netlbladdr_list)) {
			list_add_rcu(&new->list, &m->list);
			return;
		}
		if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
			new->smk_next = m->smk_next;
			m->smk_next = new;
		m_next = list_entry(rcu_dereference(m->list.next),
				 struct smk_netlbladdr, list);
		if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
			list_add_rcu(&new->list, &m->list);
			return;
		}
	}
@@ -755,6 +773,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
	struct netlbl_audit audit_info;
	struct in_addr mask;
	unsigned int m;
	int found;
	u32 mask_bits = (1<<31);
	__be32 nsa;
	u32 temp_mask;
@@ -808,14 +827,17 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,

	nsa = newname.sin_addr.s_addr;
	/* try to find if the prefix is already in the list */
	for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
	found = 0;
	list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
		if (skp->smk_host.sin_addr.s_addr == nsa &&
		    skp->smk_mask.s_addr == mask.s_addr)
		    skp->smk_mask.s_addr == mask.s_addr) {
			found = 1;
			break;

		}
	}
	smk_netlabel_audit_set(&audit_info);

	if (skp == NULL) {
	if (found == 0) {
		skp = kzalloc(sizeof(*skp), GFP_KERNEL);
		if (skp == NULL)
			rc = -ENOMEM;