diff options
| author | Eric Paris <eparis@redhat.com> | 2013-04-16 13:08:43 -0400 |
|---|---|---|
| committer | Eric Paris <eparis@redhat.com> | 2013-04-16 17:28:49 -0400 |
| commit | 62062cf8a3a99a933efdac549da380f230dbe982 (patch) | |
| tree | 8da676d774d02c3c8f0093e7f2586719072f522f /kernel | |
| parent | 34c474de7b4bd451396d67647ac728b0433379a9 (diff) | |
audit: allow checking the type of audit message in the user filter
When userspace sends messages to the audit system it includes a type.
We want to be able to filter messages based on that type without have to
do the all or nothing option currently available on the
AUDIT_FILTER_TYPE filter list. Instead we should be able to use the
AUDIT_FILTER_USER filter list and just use the message type as one part
of the matching decision.
Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/audit.c | 2 | ||||
| -rw-r--r-- | kernel/auditfilter.c | 28 |
2 files changed, 26 insertions, 4 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index c45e6d2809d7..132271448b89 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
| @@ -737,7 +737,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
| 737 | if (!audit_enabled && msg_type != AUDIT_USER_AVC) | 737 | if (!audit_enabled && msg_type != AUDIT_USER_AVC) |
| 738 | return 0; | 738 | return 0; |
| 739 | 739 | ||
| 740 | err = audit_filter_user(); | 740 | err = audit_filter_user(msg_type); |
| 741 | if (err == 1) { | 741 | if (err == 1) { |
| 742 | err = 0; | 742 | err = 0; |
| 743 | if (msg_type == AUDIT_USER_TTY) { | 743 | if (msg_type == AUDIT_USER_TTY) { |
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index f9fc54bbe06f..9e666004e0dc 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
| @@ -310,6 +310,18 @@ static u32 audit_to_op(u32 op) | |||
| 310 | return n; | 310 | return n; |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | /* check if a field is valid for a given list */ | ||
| 314 | static int audit_field_valid(struct audit_entry *entry, struct audit_field *f) | ||
| 315 | { | ||
| 316 | switch(f->type) { | ||
| 317 | case AUDIT_MSGTYPE: | ||
| 318 | if (entry->rule.listnr != AUDIT_FILTER_TYPE && | ||
| 319 | entry->rule.listnr != AUDIT_FILTER_USER) | ||
| 320 | return -EINVAL; | ||
| 321 | break; | ||
| 322 | }; | ||
| 323 | return 0; | ||
| 324 | } | ||
| 313 | 325 | ||
| 314 | /* Translate struct audit_rule to kernel's rule respresentation. | 326 | /* Translate struct audit_rule to kernel's rule respresentation. |
| 315 | * Exists for backward compatibility with userspace. */ | 327 | * Exists for backward compatibility with userspace. */ |
| @@ -459,6 +471,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, | |||
| 459 | f->gid = INVALID_GID; | 471 | f->gid = INVALID_GID; |
| 460 | f->lsm_str = NULL; | 472 | f->lsm_str = NULL; |
| 461 | f->lsm_rule = NULL; | 473 | f->lsm_rule = NULL; |
| 474 | |||
| 475 | err = audit_field_valid(entry, f); | ||
| 476 | if (err) | ||
| 477 | goto exit_free; | ||
| 478 | |||
| 479 | err = -EINVAL; | ||
| 480 | |||
| 462 | switch(f->type) { | 481 | switch(f->type) { |
| 463 | case AUDIT_UID: | 482 | case AUDIT_UID: |
| 464 | case AUDIT_EUID: | 483 | case AUDIT_EUID: |
| @@ -1354,7 +1373,7 @@ int audit_compare_dname_path(const char *dname, const char *path, int parentlen) | |||
| 1354 | return strncmp(p, dname, dlen); | 1373 | return strncmp(p, dname, dlen); |
| 1355 | } | 1374 | } |
| 1356 | 1375 | ||
| 1357 | static int audit_filter_user_rules(struct audit_krule *rule, | 1376 | static int audit_filter_user_rules(struct audit_krule *rule, int type, |
| 1358 | enum audit_state *state) | 1377 | enum audit_state *state) |
| 1359 | { | 1378 | { |
| 1360 | int i; | 1379 | int i; |
| @@ -1378,6 +1397,9 @@ static int audit_filter_user_rules(struct audit_krule *rule, | |||
| 1378 | result = audit_uid_comparator(audit_get_loginuid(current), | 1397 | result = audit_uid_comparator(audit_get_loginuid(current), |
| 1379 | f->op, f->uid); | 1398 | f->op, f->uid); |
| 1380 | break; | 1399 | break; |
| 1400 | case AUDIT_MSGTYPE: | ||
| 1401 | result = audit_comparator(type, f->op, f->val); | ||
| 1402 | break; | ||
| 1381 | case AUDIT_SUBJ_USER: | 1403 | case AUDIT_SUBJ_USER: |
| 1382 | case AUDIT_SUBJ_ROLE: | 1404 | case AUDIT_SUBJ_ROLE: |
| 1383 | case AUDIT_SUBJ_TYPE: | 1405 | case AUDIT_SUBJ_TYPE: |
| @@ -1404,7 +1426,7 @@ static int audit_filter_user_rules(struct audit_krule *rule, | |||
| 1404 | return 1; | 1426 | return 1; |
| 1405 | } | 1427 | } |
| 1406 | 1428 | ||
| 1407 | int audit_filter_user(void) | 1429 | int audit_filter_user(int type) |
| 1408 | { | 1430 | { |
| 1409 | enum audit_state state = AUDIT_DISABLED; | 1431 | enum audit_state state = AUDIT_DISABLED; |
| 1410 | struct audit_entry *e; | 1432 | struct audit_entry *e; |
| @@ -1412,7 +1434,7 @@ int audit_filter_user(void) | |||
| 1412 | 1434 | ||
| 1413 | rcu_read_lock(); | 1435 | rcu_read_lock(); |
| 1414 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { | 1436 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { |
| 1415 | if (audit_filter_user_rules(&e->rule, &state)) { | 1437 | if (audit_filter_user_rules(&e->rule, type, &state)) { |
| 1416 | if (state == AUDIT_DISABLED) | 1438 | if (state == AUDIT_DISABLED) |
| 1417 | ret = 0; | 1439 | ret = 0; |
| 1418 | break; | 1440 | break; |
