|
@@ -368,56 +368,43 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
|
|
|
* @data: string to be parsed, null terminated
|
|
|
* @rule: Will be filled with Smack parsed rule
|
|
|
* @import: if non-zero, import labels
|
|
|
- * @change: if non-zero, data is from /smack/change-rule
|
|
|
+ * @tokens: numer of substrings expected in data
|
|
|
*
|
|
|
- * Returns 0 on success, -1 on failure
|
|
|
+ * Returns number of processed bytes on success, -1 on failure.
|
|
|
*/
|
|
|
-static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
|
|
|
- int import, int change)
|
|
|
+static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
|
|
|
+ int import, int tokens)
|
|
|
{
|
|
|
- char *subject;
|
|
|
- char *object;
|
|
|
- char *access1;
|
|
|
- char *access2;
|
|
|
- int datalen;
|
|
|
- int rc = -1;
|
|
|
+ ssize_t cnt = 0;
|
|
|
+ char *tok[4];
|
|
|
+ int i;
|
|
|
|
|
|
- /* This is inefficient */
|
|
|
- datalen = strlen(data);
|
|
|
+ /*
|
|
|
+ * Parsing the rule in-place, filling all white-spaces with '\0'
|
|
|
+ */
|
|
|
+ for (i = 0; i < tokens; ++i) {
|
|
|
+ while (isspace(data[cnt]))
|
|
|
+ data[cnt++] = '\0';
|
|
|
|
|
|
- /* Our first element can be 64 + \0 with no spaces */
|
|
|
- subject = kzalloc(datalen + 1, GFP_KERNEL);
|
|
|
- if (subject == NULL)
|
|
|
- return -1;
|
|
|
- object = kzalloc(datalen, GFP_KERNEL);
|
|
|
- if (object == NULL)
|
|
|
- goto free_out_s;
|
|
|
- access1 = kzalloc(datalen, GFP_KERNEL);
|
|
|
- if (access1 == NULL)
|
|
|
- goto free_out_o;
|
|
|
- access2 = kzalloc(datalen, GFP_KERNEL);
|
|
|
- if (access2 == NULL)
|
|
|
- goto free_out_a;
|
|
|
-
|
|
|
- if (change) {
|
|
|
- if (sscanf(data, "%s %s %s %s",
|
|
|
- subject, object, access1, access2) == 4)
|
|
|
- rc = smk_fill_rule(subject, object, access1, access2,
|
|
|
- rule, import, 0);
|
|
|
- } else {
|
|
|
- if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
|
|
|
- rc = smk_fill_rule(subject, object, access1, NULL,
|
|
|
- rule, import, 0);
|
|
|
+ if (data[cnt] == '\0')
|
|
|
+ /* Unexpected end of data */
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ tok[i] = data + cnt;
|
|
|
+
|
|
|
+ while (data[cnt] && !isspace(data[cnt]))
|
|
|
+ ++cnt;
|
|
|
}
|
|
|
+ while (isspace(data[cnt]))
|
|
|
+ data[cnt++] = '\0';
|
|
|
|
|
|
- kfree(access2);
|
|
|
-free_out_a:
|
|
|
- kfree(access1);
|
|
|
-free_out_o:
|
|
|
- kfree(object);
|
|
|
-free_out_s:
|
|
|
- kfree(subject);
|
|
|
- return rc;
|
|
|
+ while (i < 4)
|
|
|
+ tok[i++] = NULL;
|
|
|
+
|
|
|
+ if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ return cnt;
|
|
|
}
|
|
|
|
|
|
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
|
|
@@ -449,9 +436,10 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
|
|
{
|
|
|
struct smack_parsed_rule rule;
|
|
|
char *data;
|
|
|
- int datalen;
|
|
|
- int rc = -EINVAL;
|
|
|
- int load = 0;
|
|
|
+ int rc;
|
|
|
+ int trunc = 0;
|
|
|
+ int tokens;
|
|
|
+ ssize_t cnt = 0;
|
|
|
|
|
|
/*
|
|
|
* No partial writes.
|
|
@@ -466,11 +454,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
|
|
*/
|
|
|
if (count != SMK_OLOADLEN && count != SMK_LOADLEN)
|
|
|
return -EINVAL;
|
|
|
- datalen = SMK_LOADLEN;
|
|
|
- } else
|
|
|
- datalen = count + 1;
|
|
|
+ } else {
|
|
|
+ if (count >= PAGE_SIZE) {
|
|
|
+ count = PAGE_SIZE - 1;
|
|
|
+ trunc = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- data = kzalloc(datalen, GFP_KERNEL);
|
|
|
+ data = kmalloc(count + 1, GFP_KERNEL);
|
|
|
if (data == NULL)
|
|
|
return -ENOMEM;
|
|
|
|
|
@@ -479,36 +470,49 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (format == SMK_LONG_FMT) {
|
|
|
- /*
|
|
|
- * Be sure the data string is terminated.
|
|
|
- */
|
|
|
- data[count] = '\0';
|
|
|
- if (smk_parse_long_rule(data, &rule, 1, 0))
|
|
|
- goto out;
|
|
|
- } else if (format == SMK_CHANGE_FMT) {
|
|
|
- data[count] = '\0';
|
|
|
- if (smk_parse_long_rule(data, &rule, 1, 1))
|
|
|
- goto out;
|
|
|
- } else {
|
|
|
- /*
|
|
|
- * More on the minor hack for backward compatibility
|
|
|
- */
|
|
|
- if (count == (SMK_OLOADLEN))
|
|
|
- data[SMK_OLOADLEN] = '-';
|
|
|
- if (smk_parse_rule(data, &rule, 1))
|
|
|
+ /*
|
|
|
+ * In case of parsing only part of user buf,
|
|
|
+ * avoid having partial rule at the data buffer
|
|
|
+ */
|
|
|
+ if (trunc) {
|
|
|
+ while (count > 0 && (data[count - 1] != '\n'))
|
|
|
+ --count;
|
|
|
+ if (count == 0) {
|
|
|
+ rc = -EINVAL;
|
|
|
goto out;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (rule_list == NULL) {
|
|
|
- load = 1;
|
|
|
- rule_list = &rule.smk_subject->smk_rules;
|
|
|
- rule_lock = &rule.smk_subject->smk_rules_lock;
|
|
|
+ data[count] = '\0';
|
|
|
+ tokens = (format == SMK_CHANGE_FMT ? 4 : 3);
|
|
|
+ while (cnt < count) {
|
|
|
+ if (format == SMK_FIXED24_FMT) {
|
|
|
+ rc = smk_parse_rule(data, &rule, 1);
|
|
|
+ if (rc != 0) {
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ cnt = count;
|
|
|
+ } else {
|
|
|
+ rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens);
|
|
|
+ if (rc <= 0) {
|
|
|
+ rc = -EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ cnt += rc;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rule_list == NULL)
|
|
|
+ rc = smk_set_access(&rule, &rule.smk_subject->smk_rules,
|
|
|
+ &rule.smk_subject->smk_rules_lock, 1);
|
|
|
+ else
|
|
|
+ rc = smk_set_access(&rule, rule_list, rule_lock, 0);
|
|
|
+
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
- rc = smk_set_access(&rule, rule_list, rule_lock, load);
|
|
|
- if (rc == 0)
|
|
|
- rc = count;
|
|
|
+ rc = cnt;
|
|
|
out:
|
|
|
kfree(data);
|
|
|
return rc;
|
|
@@ -1829,7 +1833,6 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
|
|
{
|
|
|
struct smack_parsed_rule rule;
|
|
|
char *data;
|
|
|
- char *cod;
|
|
|
int res;
|
|
|
|
|
|
data = simple_transaction_get(file, buf, count);
|
|
@@ -1842,18 +1845,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
|
|
res = smk_parse_rule(data, &rule, 0);
|
|
|
} else {
|
|
|
/*
|
|
|
- * Copy the data to make sure the string is terminated.
|
|
|
+ * simple_transaction_get() returns null-terminated data
|
|
|
*/
|
|
|
- cod = kzalloc(count + 1, GFP_KERNEL);
|
|
|
- if (cod == NULL)
|
|
|
- return -ENOMEM;
|
|
|
- memcpy(cod, data, count);
|
|
|
- cod[count] = '\0';
|
|
|
- res = smk_parse_long_rule(cod, &rule, 0, 0);
|
|
|
- kfree(cod);
|
|
|
+ res = smk_parse_long_rule(data, &rule, 0, 3);
|
|
|
}
|
|
|
|
|
|
- if (res)
|
|
|
+ if (res < 0)
|
|
|
return -EINVAL;
|
|
|
|
|
|
res = smk_access(rule.smk_subject, rule.smk_object,
|