diff options
author | Eric Paris <eparis@redhat.com> | 2010-04-20 10:20:54 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-04-20 19:58:13 -0400 |
commit | 6ccd045630054c99ba1bb35673db12cfcf1eea58 (patch) | |
tree | bce41e39722ae178807abe2213fd94e582842bae /security/integrity | |
parent | a200005038955057063fc8ea82129ebc785df41c (diff) |
ima: handle multiple rules per write
Currently IMA will only accept one rule per write(). This patch allows IMA to
accept writes which contain multiple rules but only processes one rule per
write. \n is used as the delimiter between rules. IMA will return a short
write indicating that it only accepted up to the first \n.
This allows simple userspace utilities like cat to be used to load an IMA
policy instead of needing a special userspace utility that understood 'one
write per rule'
Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Mimi Zohar <zohar@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/integrity')
-rw-r--r-- | security/integrity/ima/ima.h | 2 | ||||
-rw-r--r-- | security/integrity/ima/ima_fs.c | 38 | ||||
-rw-r--r-- | security/integrity/ima/ima_policy.c | 18 |
3 files changed, 32 insertions, 26 deletions
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 47fb65d1fcbd..16d100d3fc38 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -135,7 +135,7 @@ enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | |||
135 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 135 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); |
136 | void ima_init_policy(void); | 136 | void ima_init_policy(void); |
137 | void ima_update_policy(void); | 137 | void ima_update_policy(void); |
138 | int ima_parse_add_rule(char *); | 138 | ssize_t ima_parse_add_rule(char *); |
139 | void ima_delete_rules(void); | 139 | void ima_delete_rules(void); |
140 | 140 | ||
141 | /* LSM based policy rules require audit */ | 141 | /* LSM based policy rules require audit */ |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 0c72c9c38956..3674a52e1cfb 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -243,32 +243,34 @@ static const struct file_operations ima_ascii_measurements_ops = { | |||
243 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, | 243 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, |
244 | size_t datalen, loff_t *ppos) | 244 | size_t datalen, loff_t *ppos) |
245 | { | 245 | { |
246 | char *data; | 246 | char *data = NULL; |
247 | int rc; | 247 | ssize_t result; |
248 | 248 | ||
249 | if (datalen >= PAGE_SIZE) | 249 | if (datalen >= PAGE_SIZE) |
250 | return -ENOMEM; | 250 | datalen = PAGE_SIZE - 1; |
251 | if (*ppos != 0) { | 251 | |
252 | /* No partial writes. */ | 252 | /* No partial writes. */ |
253 | return -EINVAL; | 253 | result = -EINVAL; |
254 | } | 254 | if (*ppos != 0) |
255 | goto out; | ||
256 | |||
257 | result = -ENOMEM; | ||
255 | data = kmalloc(datalen + 1, GFP_KERNEL); | 258 | data = kmalloc(datalen + 1, GFP_KERNEL); |
256 | if (!data) | 259 | if (!data) |
257 | return -ENOMEM; | 260 | goto out; |
258 | 261 | ||
259 | if (copy_from_user(data, buf, datalen)) { | ||
260 | kfree(data); | ||
261 | return -EFAULT; | ||
262 | } | ||
263 | *(data + datalen) = '\0'; | 262 | *(data + datalen) = '\0'; |
264 | rc = ima_parse_add_rule(data); | ||
265 | if (rc < 0) { | ||
266 | datalen = -EINVAL; | ||
267 | valid_policy = 0; | ||
268 | } | ||
269 | 263 | ||
264 | result = -EFAULT; | ||
265 | if (copy_from_user(data, buf, datalen)) | ||
266 | goto out; | ||
267 | |||
268 | result = ima_parse_add_rule(data); | ||
269 | out: | ||
270 | if (result < 0) | ||
271 | valid_policy = 0; | ||
270 | kfree(data); | 272 | kfree(data); |
271 | return datalen; | 273 | return result; |
272 | } | 274 | } |
273 | 275 | ||
274 | static struct dentry *ima_dir; | 276 | static struct dentry *ima_dir; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 4759d0f99335..49998f90e441 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -261,7 +261,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
261 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); | 261 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
262 | 262 | ||
263 | entry->action = -1; | 263 | entry->action = -1; |
264 | while ((p = strsep(&rule, " \n")) != NULL) { | 264 | while ((p = strsep(&rule, " ")) != NULL) { |
265 | substring_t args[MAX_OPT_ARGS]; | 265 | substring_t args[MAX_OPT_ARGS]; |
266 | int token; | 266 | int token; |
267 | unsigned long lnum; | 267 | unsigned long lnum; |
@@ -269,7 +269,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
269 | if (result < 0) | 269 | if (result < 0) |
270 | break; | 270 | break; |
271 | if (!*p) | 271 | if (!*p) |
272 | continue; | 272 | break; |
273 | token = match_token(p, policy_tokens, args); | 273 | token = match_token(p, policy_tokens, args); |
274 | switch (token) { | 274 | switch (token) { |
275 | case Opt_measure: | 275 | case Opt_measure: |
@@ -373,7 +373,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
373 | if (entry->action == UNKNOWN) | 373 | if (entry->action == UNKNOWN) |
374 | result = -EINVAL; | 374 | result = -EINVAL; |
375 | 375 | ||
376 | audit_log_format(ab, "res=%d", !result ? 0 : 1); | 376 | audit_log_format(ab, "res=%d", !!result); |
377 | audit_log_end(ab); | 377 | audit_log_end(ab); |
378 | return result; | 378 | return result; |
379 | } | 379 | } |
@@ -383,13 +383,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
383 | * @rule - ima measurement policy rule | 383 | * @rule - ima measurement policy rule |
384 | * | 384 | * |
385 | * Uses a mutex to protect the policy list from multiple concurrent writers. | 385 | * Uses a mutex to protect the policy list from multiple concurrent writers. |
386 | * Returns 0 on success, an error code on failure. | 386 | * Returns the length of the rule parsed, an error code on failure |
387 | */ | 387 | */ |
388 | int ima_parse_add_rule(char *rule) | 388 | ssize_t ima_parse_add_rule(char *rule) |
389 | { | 389 | { |
390 | const char *op = "update_policy"; | 390 | const char *op = "update_policy"; |
391 | char *p; | ||
391 | struct ima_measure_rule_entry *entry; | 392 | struct ima_measure_rule_entry *entry; |
392 | int result = 0; | 393 | ssize_t result, len; |
393 | int audit_info = 0; | 394 | int audit_info = 0; |
394 | 395 | ||
395 | /* Prevent installed policy from changing */ | 396 | /* Prevent installed policy from changing */ |
@@ -409,8 +410,11 @@ int ima_parse_add_rule(char *rule) | |||
409 | 410 | ||
410 | INIT_LIST_HEAD(&entry->list); | 411 | INIT_LIST_HEAD(&entry->list); |
411 | 412 | ||
412 | result = ima_parse_rule(rule, entry); | 413 | p = strsep(&rule, "\n"); |
414 | len = strlen(p) + 1; | ||
415 | result = ima_parse_rule(p, entry); | ||
413 | if (!result) { | 416 | if (!result) { |
417 | result = len; | ||
414 | mutex_lock(&ima_measure_mutex); | 418 | mutex_lock(&ima_measure_mutex); |
415 | list_add_tail(&entry->list, &measure_policy_rules); | 419 | list_add_tail(&entry->list, &measure_policy_rules); |
416 | mutex_unlock(&ima_measure_mutex); | 420 | mutex_unlock(&ima_measure_mutex); |