#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
int smk_access(char *subject_label, char *object_label, int request)
{
u32 may = MAY_NOT;
- struct smk_list_entry *sp;
struct smack_rule *srp;
/*
* 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 ||
}
}
}
+ rcu_read_unlock();
/*
* This is a bit map operation.
*/
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;
* 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);
}
}
{
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;
}
{
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;
}
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;
spin_unlock_bh(&kp->smk_cipsolock);
}
+ rcu_read_unlock();
if (final == NULL)
final = smack_known_huh.smk_known;
strncpy(result, final, SMK_MAXLEN);
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));
* 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
{
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);
*/
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;
- }
-
- newp->smk_rule = *srp;
- newp->smk_next = smack_list;
- smack_list = newp;
}
+ if (found == 0)
+ list_add_rcu(&srp->list, &smack_rule_list);
-out:
mutex_unlock(&smack_list_lock);
return ret;
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;
*/
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);
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]) {
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]) {
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]) {
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;
{
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;
}
/*
*/
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 = '/';
{
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)
*/
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);
*
* 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;
}
}
struct netlbl_audit audit_info;
struct in_addr mask;
unsigned int m;
+ int found;
u32 mask_bits = (1<<31);
__be32 nsa;
u32 temp_mask;
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;