Smack: check permissions from user space (v2)
Adds a new file into SmackFS called 'access'. Wanted Smack permission is written into /smack/access. After that result can be read from the opened file. If access applies result contains 1 and otherwise 0. File access is protected from race conditions by using simple_transaction_get()/set() API. Fixes from the previous version: - Removed smack.h changes, refactoring left-over from previous version. - Removed #include <linux/smack.h>, refactoring left-over from previous version. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com> Signed-off-by: Casey Schaufler <cschaufler@cschaufler-intel.(none)>
This commit is contained in:
parent
545a726034
commit
828716c28f
1 changed files with 117 additions and 63 deletions
|
@ -44,6 +44,7 @@ enum smk_inos {
|
|||
SMK_ONLYCAP = 9, /* the only "capable" label */
|
||||
SMK_LOGGING = 10, /* logging */
|
||||
SMK_LOAD_SELF = 11, /* task specific rules */
|
||||
SMK_ACCESSES = 12, /* access policy */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -175,6 +176,81 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
|
|||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_parse_rule - parse subject, object and access type
|
||||
* @data: string to be parsed whose size is SMK_LOADLEN
|
||||
* @rule: parsed entities are stored in here
|
||||
*/
|
||||
static int smk_parse_rule(const char *data, struct smack_rule *rule)
|
||||
{
|
||||
rule->smk_subject = smk_import(data, 0);
|
||||
if (rule->smk_subject == NULL)
|
||||
return -1;
|
||||
|
||||
rule->smk_object = smk_import(data + SMK_LABELLEN, 0);
|
||||
if (rule->smk_object == NULL)
|
||||
return -1;
|
||||
|
||||
rule->smk_access = 0;
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'r':
|
||||
case 'R':
|
||||
rule->smk_access |= MAY_READ;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'w':
|
||||
case 'W':
|
||||
rule->smk_access |= MAY_WRITE;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
rule->smk_access |= MAY_EXEC;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
rule->smk_access |= MAY_APPEND;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
|
||||
case '-':
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
rule->smk_access |= MAY_TRANSMUTE;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_load_list - write() for any /smack/load
|
||||
* @file: file pointer, not actually used
|
||||
|
@ -234,71 +310,9 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rule->smk_subject = smk_import(data, 0);
|
||||
if (rule->smk_subject == NULL)
|
||||
if (smk_parse_rule(data, rule))
|
||||
goto out_free_rule;
|
||||
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'w':
|
||||
case 'W':
|
||||
rule->smk_access |= MAY_WRITE;
|
||||
break;
|
||||
default:
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
rule->smk_access |= MAY_EXEC;
|
||||
break;
|
||||
default:
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) {
|
||||
case '-':
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
rule->smk_access |= MAY_APPEND;
|
||||
break;
|
||||
default:
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) {
|
||||
case '-':
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
rule->smk_access |= MAY_TRANSMUTE;
|
||||
break;
|
||||
default:
|
||||
goto out_free_rule;
|
||||
}
|
||||
|
||||
rc = count;
|
||||
/*
|
||||
* smk_set_access returns true if there was already a rule
|
||||
|
@ -1425,6 +1439,44 @@ static const struct file_operations smk_load_self_ops = {
|
|||
.write = smk_write_load_self,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_write_access - handle access check transaction
|
||||
* @file: file pointer
|
||||
* @buf: data from user space
|
||||
* @count: bytes sent
|
||||
* @ppos: where to start - must be 0
|
||||
*/
|
||||
static ssize_t smk_write_access(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct smack_rule rule;
|
||||
char *data;
|
||||
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
data = simple_transaction_get(file, buf, count);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
if (count < SMK_LOADLEN || smk_parse_rule(data, &rule))
|
||||
return -EINVAL;
|
||||
|
||||
data[0] = smk_access(rule.smk_subject, rule.smk_object,
|
||||
rule.smk_access, NULL) == 0;
|
||||
|
||||
simple_transaction_set(file, 1);
|
||||
return SMK_LOADLEN;
|
||||
}
|
||||
|
||||
static const struct file_operations smk_access_ops = {
|
||||
.write = smk_write_access,
|
||||
.read = simple_transaction_read,
|
||||
.release = simple_transaction_release,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_fill_super - fill the /smackfs superblock
|
||||
* @sb: the empty superblock
|
||||
|
@ -1459,6 +1511,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
|||
"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_LOAD_SELF] = {
|
||||
"load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
|
||||
[SMK_ACCESSES] = {
|
||||
"access", &smk_access_ops, S_IRUGO|S_IWUSR},
|
||||
/* last one */
|
||||
{""}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue