Merge branch 'smack-for-4.2-stacked' of https://github.com/cschaufler/smack-next into next

This commit is contained in:
James Morris
2015-06-03 19:10:29 +10:00
5 changed files with 322 additions and 194 deletions
+9 -16
View File
@@ -138,6 +138,11 @@ struct smk_port_label {
struct smack_known *smk_out; /* outgoing label */
};
struct smack_onlycap {
struct list_head list;
struct smack_known *smk_label;
};
/*
* Mount options
*/
@@ -249,6 +254,7 @@ int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
int smack_privileged(int cap);
/*
* Shared data.
@@ -257,7 +263,6 @@ extern int smack_enabled;
extern int smack_cipso_direct;
extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient;
extern struct smack_known *smack_onlycap;
extern struct smack_known *smack_syslog_label;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
extern struct smack_known *smack_unconfined;
@@ -276,6 +281,9 @@ extern struct mutex smack_known_lock;
extern struct list_head smack_known_list;
extern struct list_head smk_netlbladdr_list;
extern struct mutex smack_onlycap_lock;
extern struct list_head smack_onlycap_list;
#define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
@@ -331,21 +339,6 @@ static inline struct smack_known *smk_of_current(void)
return smk_of_task(current_security());
}
/*
* Is the task privileged and allowed to be privileged
* by the onlycap rule.
*/
static inline int smack_privileged(int cap)
{
struct smack_known *skp = smk_of_current();
if (!capable(cap))
return 0;
if (smack_onlycap == NULL || smack_onlycap == skp)
return 1;
return 0;
}
/*
* logging functions
*/
+57 -11
View File
@@ -425,7 +425,7 @@ void smk_insert_entry(struct smack_known *skp)
* @string: a text string that might be a Smack label
*
* Returns a pointer to the entry in the label list that
* matches the passed string.
* matches the passed string or NULL if not found.
*/
struct smack_known *smk_find_entry(const char *string)
{
@@ -448,7 +448,7 @@ struct smack_known *smk_find_entry(const char *string)
* @string: a text string that might contain a Smack label
* @len: the maximum size, or zero if it is NULL terminated.
*
* Returns a pointer to the clean label, or NULL
* Returns a pointer to the clean label or an error code.
*/
char *smk_parse_smack(const char *string, int len)
{
@@ -464,7 +464,7 @@ char *smk_parse_smack(const char *string, int len)
* including /smack/cipso and /smack/cipso2
*/
if (string[0] == '-')
return NULL;
return ERR_PTR(-EINVAL);
for (i = 0; i < len; i++)
if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
@@ -472,11 +472,13 @@ char *smk_parse_smack(const char *string, int len)
break;
if (i == 0 || i >= SMK_LONGLABEL)
return NULL;
return ERR_PTR(-EINVAL);
smack = kzalloc(i + 1, GFP_KERNEL);
if (smack != NULL)
strncpy(smack, string, i);
if (smack == NULL)
return ERR_PTR(-ENOMEM);
strncpy(smack, string, i);
return smack;
}
@@ -523,7 +525,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
* @len: the maximum size, or zero if it is NULL terminated.
*
* Returns a pointer to the entry in the label list that
* matches the passed string, adding it if necessary.
* matches the passed string, adding it if necessary,
* or an error code.
*/
struct smack_known *smk_import_entry(const char *string, int len)
{
@@ -533,8 +536,8 @@ struct smack_known *smk_import_entry(const char *string, int len)
int rc;
smack = smk_parse_smack(string, len);
if (smack == NULL)
return NULL;
if (IS_ERR(smack))
return ERR_CAST(smack);
mutex_lock(&smack_known_lock);
@@ -543,8 +546,10 @@ struct smack_known *smk_import_entry(const char *string, int len)
goto freeout;
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
if (skp == NULL)
if (skp == NULL) {
skp = ERR_PTR(-ENOMEM);
goto freeout;
}
skp->smk_known = smack;
skp->smk_secid = smack_next_secid++;
@@ -577,7 +582,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
* smk_netlbl_mls failed.
*/
kfree(skp);
skp = NULL;
skp = ERR_PTR(rc);
freeout:
kfree(smack);
unlockout:
@@ -612,3 +617,44 @@ struct smack_known *smack_from_secid(const u32 secid)
rcu_read_unlock();
return &smack_known_invalid;
}
/*
* Unless a process is running with one of these labels
* even having CAP_MAC_OVERRIDE isn't enough to grant
* privilege to violate MAC policy. If no labels are
* designated (the empty list case) capabilities apply to
* everyone.
*/
LIST_HEAD(smack_onlycap_list);
DEFINE_MUTEX(smack_onlycap_lock);
/*
* Is the task privileged and allowed to be privileged
* by the onlycap rule.
*
* Returns 1 if the task is allowed to be privileged, 0 if it's not.
*/
int smack_privileged(int cap)
{
struct smack_known *skp = smk_of_current();
struct smack_onlycap *sop;
if (!capable(cap))
return 0;
rcu_read_lock();
if (list_empty(&smack_onlycap_list)) {
rcu_read_unlock();
return 1;
}
list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
if (sop->smk_label == skp) {
rcu_read_unlock();
return 1;
}
}
rcu_read_unlock();
return 0;
}
+57 -39
View File
@@ -245,8 +245,8 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
* @ip: a pointer to the inode
* @dp: a pointer to the dentry
*
* Returns a pointer to the master list entry for the Smack label
* or NULL if there was no label to fetch.
* Returns a pointer to the master list entry for the Smack label,
* NULL if there was no label to fetch, or an error code.
*/
static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct dentry *dp)
@@ -256,14 +256,18 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct smack_known *skp = NULL;
if (ip->i_op->getxattr == NULL)
return NULL;
return ERR_PTR(-EOPNOTSUPP);
buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL);
if (buffer == NULL)
return NULL;
return ERR_PTR(-ENOMEM);
rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
if (rc > 0)
if (rc < 0)
skp = ERR_PTR(rc);
else if (rc == 0)
skp = NULL;
else
skp = smk_import_entry(buffer, rc);
kfree(buffer);
@@ -605,40 +609,44 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
op += strlen(SMK_FSHAT);
skp = smk_import_entry(op, 0);
if (skp != NULL) {
sp->smk_hat = skp;
specified = 1;
}
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_hat = skp;
specified = 1;
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
op += strlen(SMK_FSFLOOR);
skp = smk_import_entry(op, 0);
if (skp != NULL) {
sp->smk_floor = skp;
specified = 1;
}
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_floor = skp;
specified = 1;
} else if (strncmp(op, SMK_FSDEFAULT,
strlen(SMK_FSDEFAULT)) == 0) {
op += strlen(SMK_FSDEFAULT);
skp = smk_import_entry(op, 0);
if (skp != NULL) {
sp->smk_default = skp;
specified = 1;
}
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_default = skp;
specified = 1;
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
op += strlen(SMK_FSROOT);
skp = smk_import_entry(op, 0);
if (skp != NULL) {
sp->smk_root = skp;
specified = 1;
}
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp;
specified = 1;
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS);
skp = smk_import_entry(op, 0);
if (skp != NULL) {
sp->smk_root = skp;
transmute = 1;
specified = 1;
}
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp;
transmute = 1;
specified = 1;
}
}
@@ -1118,7 +1126,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
if (rc == 0 && check_import) {
skp = size ? smk_import_entry(value, size) : NULL;
if (skp == NULL || (check_star &&
if (IS_ERR(skp))
rc = PTR_ERR(skp);
else if (skp == NULL || (check_star &&
(skp == &smack_known_star || skp == &smack_known_web)))
rc = -EINVAL;
}
@@ -1158,19 +1168,19 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
skp = smk_import_entry(value, size);
if (skp != NULL)
if (!IS_ERR(skp))
isp->smk_inode = skp;
else
isp->smk_inode = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
skp = smk_import_entry(value, size);
if (skp != NULL)
if (!IS_ERR(skp))
isp->smk_task = skp;
else
isp->smk_task = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
skp = smk_import_entry(value, size);
if (skp != NULL)
if (!IS_ERR(skp))
isp->smk_mmap = skp;
else
isp->smk_mmap = &smack_known_invalid;
@@ -1658,6 +1668,9 @@ static int smack_file_receive(struct file *file)
struct smk_audit_info ad;
struct inode *inode = file_inode(file);
if (unlikely(IS_PRIVATE(inode)))
return 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
/*
@@ -2400,8 +2413,8 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
return -EINVAL;
skp = smk_import_entry(value, size);
if (skp == NULL)
return -EINVAL;
if (IS_ERR(skp))
return PTR_ERR(skp);
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
nsp->smk_inode = skp;
@@ -3174,7 +3187,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
dp = dget(opt_dentry);
skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
if (skp != NULL)
if (!IS_ERR_OR_NULL(skp))
final = skp;
/*
@@ -3211,11 +3224,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Don't let the exec or mmap label be "*" or "@".
*/
skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
if (skp == &smack_known_star || skp == &smack_known_web)
if (IS_ERR(skp) || skp == &smack_known_star ||
skp == &smack_known_web)
skp = NULL;
isp->smk_task = skp;
skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
if (skp == &smack_known_star || skp == &smack_known_web)
if (IS_ERR(skp) || skp == &smack_known_star ||
skp == &smack_known_web)
skp = NULL;
isp->smk_mmap = skp;
@@ -3299,8 +3315,8 @@ static int smack_setprocattr(struct task_struct *p, char *name,
return -EINVAL;
skp = smk_import_entry(value, size);
if (skp == NULL)
return -EINVAL;
if (IS_ERR(skp))
return PTR_ERR(skp);
/*
* No process is ever allowed the web ("@") label.
@@ -4075,8 +4091,10 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
return -EINVAL;
skp = smk_import_entry(rulestr, 0);
if (skp)
*rule = skp->smk_known;
if (IS_ERR(skp))
return PTR_ERR(skp);
*rule = skp->smk_known;
return 0;
}
+196 -125
View File
@@ -87,16 +87,6 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
*/
int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT;
/*
* Unless a process is running with this label even
* having CAP_MAC_OVERRIDE isn't enough to grant
* privilege to violate MAC policy. If no label is
* designated (the NULL case) capabilities apply to
* everyone. It is expected that the hat (^) label
* will be used if any label is used.
*/
struct smack_known *smack_onlycap;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
/*
* Allow one label to be unconfined. This is for
@@ -338,8 +328,7 @@ static int smk_perm_from_str(const char *string)
* @import: if non-zero, import labels
* @len: label length limit
*
* Returns 0 on success, -EINVAL on failure and -ENOENT when either subject
* or object is missing.
* Returns 0 on success, appropriate error code on failure.
*/
static int smk_fill_rule(const char *subject, const char *object,
const char *access1, const char *access2,
@@ -351,16 +340,16 @@ static int smk_fill_rule(const char *subject, const char *object,
if (import) {
rule->smk_subject = smk_import_entry(subject, len);
if (rule->smk_subject == NULL)
return -EINVAL;
if (IS_ERR(rule->smk_subject))
return PTR_ERR(rule->smk_subject);
rule->smk_object = smk_import_entry(object, len);
if (rule->smk_object == NULL)
return -EINVAL;
if (IS_ERR(rule->smk_object))
return PTR_ERR(rule->smk_object);
} else {
cp = smk_parse_smack(subject, len);
if (cp == NULL)
return -EINVAL;
if (IS_ERR(cp))
return PTR_ERR(cp);
skp = smk_find_entry(cp);
kfree(cp);
if (skp == NULL)
@@ -368,8 +357,8 @@ static int smk_fill_rule(const char *subject, const char *object,
rule->smk_subject = skp;
cp = smk_parse_smack(object, len);
if (cp == NULL)
return -EINVAL;
if (IS_ERR(cp))
return PTR_ERR(cp);
skp = smk_find_entry(cp);
kfree(cp);
if (skp == NULL)
@@ -412,7 +401,7 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
* @import: if non-zero, import labels
* @tokens: numer of substrings expected in data
*
* Returns number of processed bytes on success, -1 on failure.
* Returns number of processed bytes on success, -ERRNO on failure.
*/
static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
int import, int tokens)
@@ -431,7 +420,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
if (data[cnt] == '\0')
/* Unexpected end of data */
return -1;
return -EINVAL;
tok[i] = data + cnt;
@@ -529,14 +518,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
while (cnt < count) {
if (format == SMK_FIXED24_FMT) {
rc = smk_parse_rule(data, &rule, 1);
if (rc != 0) {
rc = -EINVAL;
if (rc < 0)
goto out;
}
cnt = count;
} else {
rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens);
if (rc <= 0) {
if (rc < 0)
goto out;
if (rc == 0) {
rc = -EINVAL;
goto out;
}
@@ -567,23 +556,17 @@ static void *smk_seq_start(struct seq_file *s, loff_t *pos,
struct list_head *head)
{
struct list_head *list;
int i = *pos;
/*
* This is 0 the first time through.
*/
if (s->index == 0)
s->private = head;
rcu_read_lock();
for (list = rcu_dereference(list_next_rcu(head));
list != head;
list = rcu_dereference(list_next_rcu(list))) {
if (i-- == 0)
return list;
}
if (s->private == NULL)
return NULL;
list = s->private;
if (list_empty(list))
return NULL;
if (s->index == 0)
return list->next;
return list;
return NULL;
}
static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
@@ -591,17 +574,15 @@ static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
{
struct list_head *list = v;
if (list_is_last(list, head)) {
s->private = NULL;
return NULL;
}
s->private = list->next;
return list->next;
++*pos;
list = rcu_dereference(list_next_rcu(list));
return (list == head) ? NULL : list;
}
static void smk_seq_stop(struct seq_file *s, void *v)
{
/* No-op */
rcu_read_unlock();
}
static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
@@ -661,7 +642,7 @@ static int load_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_master_list *smlp =
list_entry(list, struct smack_master_list, list);
list_entry_rcu(list, struct smack_master_list, list);
smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN);
@@ -809,7 +790,7 @@ static int cipso_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_known *skp =
list_entry(list, struct smack_known, list);
list_entry_rcu(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
int i;
@@ -915,8 +896,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
mutex_lock(&smack_cipso_lock);
skp = smk_import_entry(rule, 0);
if (skp == NULL)
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto out;
}
if (format == SMK_FIXED24_FMT)
rule += SMK_LABELLEN;
@@ -998,7 +981,7 @@ static int cipso2_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_known *skp =
list_entry(list, struct smack_known, list);
list_entry_rcu(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
int i;
@@ -1082,7 +1065,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smk_netlbladdr *skp =
list_entry(list, struct smk_netlbladdr, list);
list_entry_rcu(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);
@@ -1237,8 +1220,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
*/
if (smack[0] != '-') {
skp = smk_import_entry(smack, 0);
if (skp == NULL) {
rc = -EINVAL;
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto free_out;
}
} else {
@@ -1619,8 +1602,8 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
}
skp = smk_import_entry(data, count);
if (skp == NULL) {
rc = -EINVAL;
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto out;
}
@@ -1643,34 +1626,79 @@ static const struct file_operations smk_ambient_ops = {
.llseek = default_llseek,
};
/**
* smk_read_onlycap - read() for smackfs/onlycap
* @filp: file pointer, not actually used
* @buf: where to put the result
* @cn: maximum to send along
* @ppos: where to start
*
* Returns number of bytes read or error code, as appropriate
/*
* Seq_file operations for /smack/onlycap
*/
static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
size_t cn, loff_t *ppos)
static void *onlycap_seq_start(struct seq_file *s, loff_t *pos)
{
char *smack = "";
ssize_t rc = -EINVAL;
int asize;
return smk_seq_start(s, pos, &smack_onlycap_list);
}
if (*ppos != 0)
return 0;
static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
return smk_seq_next(s, v, pos, &smack_onlycap_list);
}
if (smack_onlycap != NULL)
smack = smack_onlycap->smk_known;
static int onlycap_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_onlycap *sop =
list_entry_rcu(list, struct smack_onlycap, list);
asize = strlen(smack) + 1;
seq_puts(s, sop->smk_label->smk_known);
seq_putc(s, ' ');
if (cn >= asize)
rc = simple_read_from_buffer(buf, cn, ppos, smack, asize);
return 0;
}
return rc;
static const struct seq_operations onlycap_seq_ops = {
.start = onlycap_seq_start,
.next = onlycap_seq_next,
.show = onlycap_seq_show,
.stop = smk_seq_stop,
};
static int smk_open_onlycap(struct inode *inode, struct file *file)
{
return seq_open(file, &onlycap_seq_ops);
}
/**
* smk_list_swap_rcu - swap public list with a private one in RCU-safe way
* The caller must hold appropriate mutex to prevent concurrent modifications
* to the public list.
* Private list is assumed to be not accessible to other threads yet.
*
* @public: public list
* @private: private list
*/
static void smk_list_swap_rcu(struct list_head *public,
struct list_head *private)
{
struct list_head *first, *last;
if (list_empty(public)) {
list_splice_init_rcu(private, public, synchronize_rcu);
} else {
/* Remember public list before replacing it */
first = public->next;
last = public->prev;
/* Publish private list in place of public in RCU-safe way */
private->prev->next = public;
private->next->prev = public;
rcu_assign_pointer(public->next, private->next);
public->prev = private->prev;
synchronize_rcu();
/* When all readers are done with the old public list,
* attach it in place of private */
private->next = first;
private->prev = last;
first->prev = private;
last->next = private;
}
}
/**
@@ -1686,47 +1714,79 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *data;
struct smack_known *skp = smk_of_task(current->cred->security);
char *data_parse;
char *tok;
struct smack_known *skp;
struct smack_onlycap *sop;
struct smack_onlycap *sop2;
LIST_HEAD(list_tmp);
int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
/*
* This can be done using smk_access() but is done
* explicitly for clarity. The smk_access() implementation
* would use smk_access(smack_onlycap, MAY_WRITE)
*/
if (smack_onlycap != NULL && smack_onlycap != skp)
return -EPERM;
data = kzalloc(count + 1, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
/*
* Should the null string be passed in unset the onlycap value.
* This seems like something to be careful with as usually
* smk_import only expects to return NULL for errors. It
* is usually the case that a nullstring or "\n" would be
* bad to pass to smk_import but in fact this is useful here.
*
* smk_import will also reject a label beginning with '-',
* so "-usecapabilities" will also work.
*/
if (copy_from_user(data, buf, count) != 0)
rc = -EFAULT;
else
smack_onlycap = smk_import_entry(data, count);
if (copy_from_user(data, buf, count) != 0) {
kfree(data);
return -EFAULT;
}
data_parse = data;
while ((tok = strsep(&data_parse, " ")) != NULL) {
if (!*tok)
continue;
skp = smk_import_entry(tok, 0);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
break;
}
sop = kzalloc(sizeof(*sop), GFP_KERNEL);
if (sop == NULL) {
rc = -ENOMEM;
break;
}
sop->smk_label = skp;
list_add_rcu(&sop->list, &list_tmp);
}
kfree(data);
/*
* Clear the smack_onlycap on invalid label errors. This means
* that we can pass a null string to unset the onlycap value.
*
* Importing will also reject a label beginning with '-',
* so "-usecapabilities" will also work.
*
* But do so only on invalid label, not on system errors.
* The invalid label must be first to count as clearing attempt.
*/
if (rc == -EINVAL && list_empty(&list_tmp))
rc = count;
if (rc >= 0) {
mutex_lock(&smack_onlycap_lock);
smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
mutex_unlock(&smack_onlycap_lock);
}
list_for_each_entry_safe(sop, sop2, &list_tmp, list)
kfree(sop);
return rc;
}
static const struct file_operations smk_onlycap_ops = {
.read = smk_read_onlycap,
.open = smk_open_onlycap,
.read = seq_read,
.write = smk_write_onlycap,
.llseek = default_llseek,
.llseek = seq_lseek,
.release = seq_release,
};
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
@@ -1773,6 +1833,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *data;
struct smack_known *skp;
int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN))
@@ -1782,21 +1843,31 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
if (data == NULL)
return -ENOMEM;
/*
* Should the null string be passed in unset the unconfined value.
* This seems like something to be careful with as usually
* smk_import only expects to return NULL for errors. It
* is usually the case that a nullstring or "\n" would be
* bad to pass to smk_import but in fact this is useful here.
*
* smk_import will also reject a label beginning with '-',
* so "-confine" will also work.
*/
if (copy_from_user(data, buf, count) != 0)
if (copy_from_user(data, buf, count) != 0) {
rc = -EFAULT;
else
smack_unconfined = smk_import_entry(data, count);
goto freeout;
}
/*
* Clear the smack_unconfined on invalid label errors. This means
* that we can pass a null string to unset the unconfined value.
*
* Importing will also reject a label beginning with '-',
* so "-confine" will also work.
*
* But do so only on invalid label, not on system errors.
*/
skp = smk_import_entry(data, count);
if (PTR_ERR(skp) == -EINVAL)
skp = NULL;
else if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto freeout;
}
smack_unconfined = skp;
freeout:
kfree(data);
return rc;
}
@@ -1895,7 +1966,7 @@ static int load_self_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
list_entry(list, struct smack_rule, list);
list_entry_rcu(list, struct smack_rule, list);
smk_rule_show(s, srp, SMK_LABELLEN);
@@ -1980,7 +2051,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
res = smk_access(rule.smk_subject, rule.smk_object,
rule.smk_access1, NULL);
else if (res != -ENOENT)
return -EINVAL;
return res;
/*
* smk_access() can return a value > 0 in the "bringup" case.
@@ -2024,7 +2095,7 @@ static int load2_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_master_list *smlp =
list_entry(list, struct smack_master_list, list);
list_entry_rcu(list, struct smack_master_list, list);
smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL);
@@ -2101,7 +2172,7 @@ static int load_self2_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
list_entry(list, struct smack_rule, list);
list_entry_rcu(list, struct smack_rule, list);
smk_rule_show(s, srp, SMK_LONGLABEL);
@@ -2209,8 +2280,8 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
}
cp = smk_parse_smack(data, count);
if (cp == NULL) {
rc = -EINVAL;
if (IS_ERR(cp)) {
rc = PTR_ERR(cp);
goto free_out;
}
@@ -2341,10 +2412,10 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
rc = -EFAULT;
else {
skp = smk_import_entry(data, count);
if (skp == NULL)
rc = -EINVAL;
if (IS_ERR(skp))
rc = PTR_ERR(skp);
else
smack_syslog_label = smk_import_entry(data, count);
smack_syslog_label = skp;
}
kfree(data);