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: Etienne Basset <etienne.basset@numericable.fr> Acked-by: Casey Schaufler <casey@schaufler-ca.com>
This commit is contained in:
parent
703a3cd728
commit
7198e2eeb4
4 changed files with 168 additions and 122 deletions
|
@ -18,6 +18,8 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/in.h>
|
#include <linux/in.h>
|
||||||
#include <net/netlabel.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
|
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
|
||||||
|
@ -59,17 +61,10 @@ struct inode_smack {
|
||||||
* A label access rule.
|
* A label access rule.
|
||||||
*/
|
*/
|
||||||
struct smack_rule {
|
struct smack_rule {
|
||||||
char *smk_subject;
|
struct list_head list;
|
||||||
char *smk_object;
|
char *smk_subject;
|
||||||
int smk_access;
|
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,7 +80,7 @@ struct smack_cipso {
|
||||||
* An entry in the table identifying hosts.
|
* An entry in the table identifying hosts.
|
||||||
*/
|
*/
|
||||||
struct smk_netlbladdr {
|
struct smk_netlbladdr {
|
||||||
struct smk_netlbladdr *smk_next;
|
struct list_head list;
|
||||||
struct sockaddr_in smk_host; /* network address */
|
struct sockaddr_in smk_host; /* network address */
|
||||||
struct in_addr smk_mask; /* network mask */
|
struct in_addr smk_mask; /* network mask */
|
||||||
char *smk_label; /* label */
|
char *smk_label; /* label */
|
||||||
|
@ -113,7 +108,7 @@ struct smk_netlbladdr {
|
||||||
* the cipso direct mapping in used internally.
|
* the cipso direct mapping in used internally.
|
||||||
*/
|
*/
|
||||||
struct smack_known {
|
struct smack_known {
|
||||||
struct smack_known *smk_next;
|
struct list_head list;
|
||||||
char smk_known[SMK_LABELLEN];
|
char smk_known[SMK_LABELLEN];
|
||||||
u32 smk_secid;
|
u32 smk_secid;
|
||||||
struct smack_cipso *smk_cipso;
|
struct smack_cipso *smk_cipso;
|
||||||
|
@ -206,7 +201,6 @@ extern int smack_cipso_direct;
|
||||||
extern char *smack_net_ambient;
|
extern char *smack_net_ambient;
|
||||||
extern char *smack_onlycap;
|
extern char *smack_onlycap;
|
||||||
|
|
||||||
extern struct smack_known *smack_known;
|
|
||||||
extern struct smack_known smack_known_floor;
|
extern struct smack_known smack_known_floor;
|
||||||
extern struct smack_known smack_known_hat;
|
extern struct smack_known smack_known_hat;
|
||||||
extern struct smack_known smack_known_huh;
|
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_star;
|
||||||
extern struct smack_known smack_known_web;
|
extern struct smack_known smack_known_web;
|
||||||
|
|
||||||
extern struct smk_list_entry *smack_list;
|
extern struct list_head smack_known_list;
|
||||||
extern struct smk_netlbladdr *smack_netlbladdrs;
|
extern struct list_head smack_rule_list;
|
||||||
|
extern struct list_head smk_netlbladdr_list;
|
||||||
|
|
||||||
extern struct security_operations smack_ops;
|
extern struct security_operations smack_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -16,48 +16,42 @@
|
||||||
#include "smack.h"
|
#include "smack.h"
|
||||||
|
|
||||||
struct smack_known smack_known_huh = {
|
struct smack_known smack_known_huh = {
|
||||||
.smk_next = NULL,
|
|
||||||
.smk_known = "?",
|
.smk_known = "?",
|
||||||
.smk_secid = 2,
|
.smk_secid = 2,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_hat = {
|
struct smack_known smack_known_hat = {
|
||||||
.smk_next = &smack_known_huh,
|
|
||||||
.smk_known = "^",
|
.smk_known = "^",
|
||||||
.smk_secid = 3,
|
.smk_secid = 3,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_star = {
|
struct smack_known smack_known_star = {
|
||||||
.smk_next = &smack_known_hat,
|
|
||||||
.smk_known = "*",
|
.smk_known = "*",
|
||||||
.smk_secid = 4,
|
.smk_secid = 4,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_floor = {
|
struct smack_known smack_known_floor = {
|
||||||
.smk_next = &smack_known_star,
|
|
||||||
.smk_known = "_",
|
.smk_known = "_",
|
||||||
.smk_secid = 5,
|
.smk_secid = 5,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_invalid = {
|
struct smack_known smack_known_invalid = {
|
||||||
.smk_next = &smack_known_floor,
|
|
||||||
.smk_known = "",
|
.smk_known = "",
|
||||||
.smk_secid = 6,
|
.smk_secid = 6,
|
||||||
.smk_cipso = NULL,
|
.smk_cipso = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smack_known smack_known_web = {
|
struct smack_known smack_known_web = {
|
||||||
.smk_next = &smack_known_invalid,
|
|
||||||
.smk_known = "@",
|
.smk_known = "@",
|
||||||
.smk_secid = 7,
|
.smk_secid = 7,
|
||||||
.smk_cipso = NULL,
|
.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
|
* 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)
|
int smk_access(char *subject_label, char *object_label, int request)
|
||||||
{
|
{
|
||||||
u32 may = MAY_NOT;
|
u32 may = MAY_NOT;
|
||||||
struct smk_list_entry *sp;
|
|
||||||
struct smack_rule *srp;
|
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
|
* access (e.g. read is included in readwrite) it's
|
||||||
* good.
|
* good.
|
||||||
*/
|
*/
|
||||||
for (sp = smack_list; sp != NULL; sp = sp->smk_next) {
|
rcu_read_lock();
|
||||||
srp = &sp->smk_rule;
|
list_for_each_entry_rcu(srp, &smack_rule_list, list) {
|
||||||
|
|
||||||
if (srp->smk_subject == subject_label ||
|
if (srp->smk_subject == subject_label ||
|
||||||
strcmp(srp->smk_subject, subject_label) == 0) {
|
strcmp(srp->smk_subject, subject_label) == 0) {
|
||||||
if (srp->smk_object == object_label ||
|
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.
|
* 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);
|
mutex_lock(&smack_known_lock);
|
||||||
|
|
||||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
found = 0;
|
||||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
|
list_for_each_entry_rcu(skp, &smack_known_list, list) {
|
||||||
|
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) {
|
||||||
|
found = 1;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (skp == NULL) {
|
if (found == 0) {
|
||||||
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
|
skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL);
|
||||||
if (skp != NULL) {
|
if (skp != NULL) {
|
||||||
skp->smk_next = smack_known;
|
|
||||||
strncpy(skp->smk_known, smack, SMK_MAXLEN);
|
strncpy(skp->smk_known, smack, SMK_MAXLEN);
|
||||||
skp->smk_secid = smack_next_secid++;
|
skp->smk_secid = smack_next_secid++;
|
||||||
skp->smk_cipso = NULL;
|
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
|
* Make sure that the entry is actually
|
||||||
* filled before putting it on the list.
|
* filled before putting it on the list.
|
||||||
*/
|
*/
|
||||||
smp_mb();
|
list_add_rcu(&skp->list, &smack_known_list);
|
||||||
smack_known = skp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,14 +278,19 @@ char *smack_from_secid(const u32 secid)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
rcu_read_lock();
|
||||||
if (skp->smk_secid == secid)
|
list_for_each_entry_rcu(skp, &smack_known_list, list) {
|
||||||
|
if (skp->smk_secid == secid) {
|
||||||
|
rcu_read_unlock();
|
||||||
return skp->smk_known;
|
return skp->smk_known;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we got this far someone asked for the translation
|
* If we got this far someone asked for the translation
|
||||||
* of a secid that is not on the list.
|
* of a secid that is not on the list.
|
||||||
*/
|
*/
|
||||||
|
rcu_read_unlock();
|
||||||
return smack_known_invalid.smk_known;
|
return smack_known_invalid.smk_known;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,9 +305,14 @@ u32 smack_to_secid(const char *smack)
|
||||||
{
|
{
|
||||||
struct smack_known *skp;
|
struct smack_known *skp;
|
||||||
|
|
||||||
for (skp = smack_known; skp != NULL; skp = skp->smk_next)
|
rcu_read_lock();
|
||||||
if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0)
|
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;
|
return skp->smk_secid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +337,8 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
||||||
struct smack_known *kp;
|
struct smack_known *kp;
|
||||||
char *final = NULL;
|
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)
|
if (kp->smk_cipso == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -344,6 +350,7 @@ void smack_from_cipso(u32 level, char *cp, char *result)
|
||||||
|
|
||||||
spin_unlock_bh(&kp->smk_cipsolock);
|
spin_unlock_bh(&kp->smk_cipsolock);
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
if (final == NULL)
|
if (final == NULL)
|
||||||
final = smack_known_huh.smk_known;
|
final = smack_known_huh.smk_known;
|
||||||
strncpy(result, final, SMK_MAXLEN);
|
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)
|
int smack_to_cipso(const char *smack, struct smack_cipso *cp)
|
||||||
{
|
{
|
||||||
struct smack_known *kp;
|
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 ||
|
if (kp->smk_known == smack ||
|
||||||
strcmp(kp->smk_known, smack) == 0)
|
strcmp(kp->smk_known, smack) == 0) {
|
||||||
|
found = 1;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (kp == NULL || kp->smk_cipso == NULL)
|
if (found == 0 || kp->smk_cipso == NULL)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
|
memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso));
|
||||||
|
|
|
@ -1508,7 +1508,8 @@ static char *smack_host_label(struct sockaddr_in *sip)
|
||||||
if (siap->s_addr == 0)
|
if (siap->s_addr == 0)
|
||||||
return NULL;
|
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
|
* we break after finding the first match because
|
||||||
* the list is sorted from longest to shortest mask
|
* 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 ==
|
if ((&snp->smk_host.sin_addr)->s_addr ==
|
||||||
(siap->s_addr & (&snp->smk_mask)->s_addr)) {
|
(siap->s_addr & (&snp->smk_mask)->s_addr)) {
|
||||||
|
rcu_read_unlock();
|
||||||
return snp->smk_label;
|
return snp->smk_label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2930,6 +2932,17 @@ struct security_operations smack_ops = {
|
||||||
.release_secctx = smack_release_secctx,
|
.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
|
* smack_init - initialize the smack system
|
||||||
*
|
*
|
||||||
|
@ -2950,6 +2963,8 @@ static __init int smack_init(void)
|
||||||
cred = (struct cred *) current->cred;
|
cred = (struct cred *) current->cred;
|
||||||
cred->security = &smack_known_floor.smk_known;
|
cred->security = &smack_known_floor.smk_known;
|
||||||
|
|
||||||
|
/* initilize the smack_know_list */
|
||||||
|
init_smack_know_list();
|
||||||
/*
|
/*
|
||||||
* Initialize locks
|
* Initialize locks
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -80,10 +80,11 @@ char *smack_onlycap;
|
||||||
* Packets are sent there unlabeled, but only from tasks that
|
* Packets are sent there unlabeled, but only from tasks that
|
||||||
* can write to the specified label.
|
* 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;
|
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
||||||
struct smk_list_entry *smack_list;
|
|
||||||
|
|
||||||
#define SEQ_READ_FINISHED 1
|
#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)
|
if (*pos == SEQ_READ_FINISHED)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (list_empty(&smack_rule_list))
|
||||||
return smack_list;
|
return NULL;
|
||||||
|
return smack_rule_list.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
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;
|
*pos = SEQ_READ_FINISHED;
|
||||||
|
return NULL;
|
||||||
return skp;
|
}
|
||||||
|
return list->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_seq_show(struct seq_file *s, void *v)
|
static int load_seq_show(struct seq_file *s, void *v)
|
||||||
{
|
{
|
||||||
struct smk_list_entry *slp = (struct smk_list_entry *) v;
|
struct list_head *list = v;
|
||||||
struct smack_rule *srp = &slp->smk_rule;
|
struct smack_rule *srp =
|
||||||
|
list_entry(list, struct smack_rule, list);
|
||||||
|
|
||||||
seq_printf(s, "%s %s", (char *)srp->smk_subject,
|
seq_printf(s, "%s %s", (char *)srp->smk_subject,
|
||||||
(char *)srp->smk_object);
|
(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)
|
static int smk_set_access(struct smack_rule *srp)
|
||||||
{
|
{
|
||||||
struct smk_list_entry *sp;
|
struct smack_rule *sp;
|
||||||
struct smk_list_entry *newp;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int found;
|
||||||
mutex_lock(&smack_list_lock);
|
mutex_lock(&smack_list_lock);
|
||||||
|
|
||||||
for (sp = smack_list; sp != NULL; sp = sp->smk_next)
|
found = 0;
|
||||||
if (sp->smk_rule.smk_subject == srp->smk_subject &&
|
list_for_each_entry_rcu(sp, &smack_rule_list, list) {
|
||||||
sp->smk_rule.smk_object == srp->smk_object) {
|
if (sp->smk_subject == srp->smk_subject &&
|
||||||
sp->smk_rule.smk_access = srp->smk_access;
|
sp->smk_object == srp->smk_object) {
|
||||||
|
found = 1;
|
||||||
|
sp->smk_access = srp->smk_access;
|
||||||
break;
|
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);
|
mutex_unlock(&smack_list_lock);
|
||||||
|
|
||||||
return ret;
|
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,
|
static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct smack_rule rule;
|
struct smack_rule *rule;
|
||||||
char *data;
|
char *data;
|
||||||
int rc = -EINVAL;
|
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))
|
if (!capable(CAP_MAC_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (*ppos != 0)
|
|
||||||
return -EINVAL;
|
if (*ppos != 0 || count != SMK_LOADLEN)
|
||||||
if (count != SMK_LOADLEN)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
data = kzalloc(count, GFP_KERNEL);
|
data = kzalloc(count, GFP_KERNEL);
|
||||||
|
@ -286,25 +280,31 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.smk_subject = smk_import(data, 0);
|
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
|
||||||
if (rule.smk_subject == NULL)
|
if (rule == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
rule.smk_object = smk_import(data + SMK_LABELLEN, 0);
|
rule->smk_subject = smk_import(data, 0);
|
||||||
if (rule.smk_object == NULL)
|
if (rule->smk_subject == NULL)
|
||||||
goto out;
|
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]) {
|
switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
|
||||||
case '-':
|
case '-':
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'R':
|
case 'R':
|
||||||
rule.smk_access |= MAY_READ;
|
rule->smk_access |= MAY_READ;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
|
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;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
case 'W':
|
case 'W':
|
||||||
rule.smk_access |= MAY_WRITE;
|
rule->smk_access |= MAY_WRITE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
|
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;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
rule.smk_access |= MAY_EXEC;
|
rule->smk_access |= MAY_EXEC;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
|
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;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
case 'A':
|
case 'A':
|
||||||
rule.smk_access |= MAY_APPEND;
|
rule->smk_access |= MAY_APPEND;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out_free_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = smk_set_access(&rule);
|
rc = smk_set_access(rule);
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = count;
|
rc = count;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
out_free_rule:
|
||||||
|
kfree(rule);
|
||||||
out:
|
out:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -433,24 +436,26 @@ static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
|
||||||
{
|
{
|
||||||
if (*pos == SEQ_READ_FINISHED)
|
if (*pos == SEQ_READ_FINISHED)
|
||||||
return NULL;
|
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)
|
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)
|
if (list_is_last(list, &smack_known_list)) {
|
||||||
skp = skp->smk_next;
|
|
||||||
|
|
||||||
if (skp == NULL)
|
|
||||||
*pos = SEQ_READ_FINISHED;
|
*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)
|
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;
|
struct smack_cipso *scp = skp->smk_cipso;
|
||||||
char *cbp;
|
char *cbp;
|
||||||
char sep = '/';
|
char sep = '/';
|
||||||
|
@ -638,18 +645,21 @@ static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
|
||||||
{
|
{
|
||||||
if (*pos == SEQ_READ_FINISHED)
|
if (*pos == SEQ_READ_FINISHED)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (list_empty(&smk_netlbladdr_list))
|
||||||
return smack_netlbladdrs;
|
return NULL;
|
||||||
|
return smk_netlbladdr_list.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
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;
|
*pos = SEQ_READ_FINISHED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return skp;
|
return list->next;
|
||||||
}
|
}
|
||||||
#define BEBITS (sizeof(__be32) * 8)
|
#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)
|
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;
|
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
|
||||||
int maskn;
|
int maskn;
|
||||||
u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
|
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
|
* This helper insert netlabel in the smack_netlbladdrs list
|
||||||
* sorted by netmask length (longest to smallest)
|
* 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)
|
static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
|
||||||
{
|
{
|
||||||
struct smk_netlbladdr *m;
|
struct smk_netlbladdr *m, *m_next;
|
||||||
|
|
||||||
if (smack_netlbladdrs == NULL) {
|
if (list_empty(&smk_netlbladdr_list)) {
|
||||||
smack_netlbladdrs = new;
|
list_add_rcu(&new->list, &smk_netlbladdr_list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m = list_entry(rcu_dereference(smk_netlbladdr_list.next),
|
||||||
|
struct smk_netlbladdr, list);
|
||||||
|
|
||||||
/* the comparison '>' is a bit hacky, but works */
|
/* the comparison '>' is a bit hacky, but works */
|
||||||
if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
|
if (new->smk_mask.s_addr > m->smk_mask.s_addr) {
|
||||||
new->smk_next = smack_netlbladdrs;
|
list_add_rcu(&new->list, &smk_netlbladdr_list);
|
||||||
smack_netlbladdrs = new;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
|
|
||||||
if (m->smk_next == NULL) {
|
list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) {
|
||||||
m->smk_next = new;
|
if (list_is_last(&m->list, &smk_netlbladdr_list)) {
|
||||||
|
list_add_rcu(&new->list, &m->list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
|
m_next = list_entry(rcu_dereference(m->list.next),
|
||||||
new->smk_next = m->smk_next;
|
struct smk_netlbladdr, list);
|
||||||
m->smk_next = new;
|
if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) {
|
||||||
|
list_add_rcu(&new->list, &m->list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -755,6 +773,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||||
struct netlbl_audit audit_info;
|
struct netlbl_audit audit_info;
|
||||||
struct in_addr mask;
|
struct in_addr mask;
|
||||||
unsigned int m;
|
unsigned int m;
|
||||||
|
int found;
|
||||||
u32 mask_bits = (1<<31);
|
u32 mask_bits = (1<<31);
|
||||||
__be32 nsa;
|
__be32 nsa;
|
||||||
u32 temp_mask;
|
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;
|
nsa = newname.sin_addr.s_addr;
|
||||||
/* try to find if the prefix is already in the list */
|
/* 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 &&
|
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;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
smk_netlabel_audit_set(&audit_info);
|
smk_netlabel_audit_set(&audit_info);
|
||||||
|
|
||||||
if (skp == NULL) {
|
if (found == 0) {
|
||||||
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
||||||
if (skp == NULL)
|
if (skp == NULL)
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
|
Loading…
Reference in a new issue