diff options
Diffstat (limited to 'kernel/auditfilter.c')
-rw-r--r-- | kernel/auditfilter.c | 137 |
1 files changed, 118 insertions, 19 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index a6c3f1abd206..c4bcdbaf4d4d 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
@@ -342,6 +342,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) | |||
342 | 342 | ||
343 | f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS); | 343 | f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS); |
344 | f->val = rule->values[i]; | 344 | f->val = rule->values[i]; |
345 | f->uid = INVALID_UID; | ||
346 | f->gid = INVALID_GID; | ||
345 | 347 | ||
346 | err = -EINVAL; | 348 | err = -EINVAL; |
347 | if (f->op == Audit_bad) | 349 | if (f->op == Audit_bad) |
@@ -350,16 +352,32 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) | |||
350 | switch(f->type) { | 352 | switch(f->type) { |
351 | default: | 353 | default: |
352 | goto exit_free; | 354 | goto exit_free; |
353 | case AUDIT_PID: | ||
354 | case AUDIT_UID: | 355 | case AUDIT_UID: |
355 | case AUDIT_EUID: | 356 | case AUDIT_EUID: |
356 | case AUDIT_SUID: | 357 | case AUDIT_SUID: |
357 | case AUDIT_FSUID: | 358 | case AUDIT_FSUID: |
359 | case AUDIT_LOGINUID: | ||
360 | /* bit ops not implemented for uid comparisons */ | ||
361 | if (f->op == Audit_bitmask || f->op == Audit_bittest) | ||
362 | goto exit_free; | ||
363 | |||
364 | f->uid = make_kuid(current_user_ns(), f->val); | ||
365 | if (!uid_valid(f->uid)) | ||
366 | goto exit_free; | ||
367 | break; | ||
358 | case AUDIT_GID: | 368 | case AUDIT_GID: |
359 | case AUDIT_EGID: | 369 | case AUDIT_EGID: |
360 | case AUDIT_SGID: | 370 | case AUDIT_SGID: |
361 | case AUDIT_FSGID: | 371 | case AUDIT_FSGID: |
362 | case AUDIT_LOGINUID: | 372 | /* bit ops not implemented for gid comparisons */ |
373 | if (f->op == Audit_bitmask || f->op == Audit_bittest) | ||
374 | goto exit_free; | ||
375 | |||
376 | f->gid = make_kgid(current_user_ns(), f->val); | ||
377 | if (!gid_valid(f->gid)) | ||
378 | goto exit_free; | ||
379 | break; | ||
380 | case AUDIT_PID: | ||
363 | case AUDIT_PERS: | 381 | case AUDIT_PERS: |
364 | case AUDIT_MSGTYPE: | 382 | case AUDIT_MSGTYPE: |
365 | case AUDIT_PPID: | 383 | case AUDIT_PPID: |
@@ -437,19 +455,39 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, | |||
437 | 455 | ||
438 | f->type = data->fields[i]; | 456 | f->type = data->fields[i]; |
439 | f->val = data->values[i]; | 457 | f->val = data->values[i]; |
458 | f->uid = INVALID_UID; | ||
459 | f->gid = INVALID_GID; | ||
440 | f->lsm_str = NULL; | 460 | f->lsm_str = NULL; |
441 | f->lsm_rule = NULL; | 461 | f->lsm_rule = NULL; |
442 | switch(f->type) { | 462 | switch(f->type) { |
443 | case AUDIT_PID: | ||
444 | case AUDIT_UID: | 463 | case AUDIT_UID: |
445 | case AUDIT_EUID: | 464 | case AUDIT_EUID: |
446 | case AUDIT_SUID: | 465 | case AUDIT_SUID: |
447 | case AUDIT_FSUID: | 466 | case AUDIT_FSUID: |
467 | case AUDIT_LOGINUID: | ||
468 | case AUDIT_OBJ_UID: | ||
469 | /* bit ops not implemented for uid comparisons */ | ||
470 | if (f->op == Audit_bitmask || f->op == Audit_bittest) | ||
471 | goto exit_free; | ||
472 | |||
473 | f->uid = make_kuid(current_user_ns(), f->val); | ||
474 | if (!uid_valid(f->uid)) | ||
475 | goto exit_free; | ||
476 | break; | ||
448 | case AUDIT_GID: | 477 | case AUDIT_GID: |
449 | case AUDIT_EGID: | 478 | case AUDIT_EGID: |
450 | case AUDIT_SGID: | 479 | case AUDIT_SGID: |
451 | case AUDIT_FSGID: | 480 | case AUDIT_FSGID: |
452 | case AUDIT_LOGINUID: | 481 | case AUDIT_OBJ_GID: |
482 | /* bit ops not implemented for gid comparisons */ | ||
483 | if (f->op == Audit_bitmask || f->op == Audit_bittest) | ||
484 | goto exit_free; | ||
485 | |||
486 | f->gid = make_kgid(current_user_ns(), f->val); | ||
487 | if (!gid_valid(f->gid)) | ||
488 | goto exit_free; | ||
489 | break; | ||
490 | case AUDIT_PID: | ||
453 | case AUDIT_PERS: | 491 | case AUDIT_PERS: |
454 | case AUDIT_MSGTYPE: | 492 | case AUDIT_MSGTYPE: |
455 | case AUDIT_PPID: | 493 | case AUDIT_PPID: |
@@ -461,8 +499,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, | |||
461 | case AUDIT_ARG1: | 499 | case AUDIT_ARG1: |
462 | case AUDIT_ARG2: | 500 | case AUDIT_ARG2: |
463 | case AUDIT_ARG3: | 501 | case AUDIT_ARG3: |
464 | case AUDIT_OBJ_UID: | ||
465 | case AUDIT_OBJ_GID: | ||
466 | break; | 502 | break; |
467 | case AUDIT_ARCH: | 503 | case AUDIT_ARCH: |
468 | entry->rule.arch_f = f; | 504 | entry->rule.arch_f = f; |
@@ -707,6 +743,23 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b) | |||
707 | if (strcmp(a->filterkey, b->filterkey)) | 743 | if (strcmp(a->filterkey, b->filterkey)) |
708 | return 1; | 744 | return 1; |
709 | break; | 745 | break; |
746 | case AUDIT_UID: | ||
747 | case AUDIT_EUID: | ||
748 | case AUDIT_SUID: | ||
749 | case AUDIT_FSUID: | ||
750 | case AUDIT_LOGINUID: | ||
751 | case AUDIT_OBJ_UID: | ||
752 | if (!uid_eq(a->fields[i].uid, b->fields[i].uid)) | ||
753 | return 1; | ||
754 | break; | ||
755 | case AUDIT_GID: | ||
756 | case AUDIT_EGID: | ||
757 | case AUDIT_SGID: | ||
758 | case AUDIT_FSGID: | ||
759 | case AUDIT_OBJ_GID: | ||
760 | if (!gid_eq(a->fields[i].gid, b->fields[i].gid)) | ||
761 | return 1; | ||
762 | break; | ||
710 | default: | 763 | default: |
711 | if (a->fields[i].val != b->fields[i].val) | 764 | if (a->fields[i].val != b->fields[i].val) |
712 | return 1; | 765 | return 1; |
@@ -1056,7 +1109,7 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) | |||
1056 | } | 1109 | } |
1057 | 1110 | ||
1058 | /* Log rule additions and removals */ | 1111 | /* Log rule additions and removals */ |
1059 | static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid, | 1112 | static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid, |
1060 | char *action, struct audit_krule *rule, | 1113 | char *action, struct audit_krule *rule, |
1061 | int res) | 1114 | int res) |
1062 | { | 1115 | { |
@@ -1068,7 +1121,8 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid, | |||
1068 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); | 1121 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); |
1069 | if (!ab) | 1122 | if (!ab) |
1070 | return; | 1123 | return; |
1071 | audit_log_format(ab, "auid=%u ses=%u", loginuid, sessionid); | 1124 | audit_log_format(ab, "auid=%u ses=%u", |
1125 | from_kuid(&init_user_ns, loginuid), sessionid); | ||
1072 | if (sid) { | 1126 | if (sid) { |
1073 | char *ctx = NULL; | 1127 | char *ctx = NULL; |
1074 | u32 len; | 1128 | u32 len; |
@@ -1098,8 +1152,8 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid, | |||
1098 | * @sessionid: sessionid for netlink audit message | 1152 | * @sessionid: sessionid for netlink audit message |
1099 | * @sid: SE Linux Security ID of sender | 1153 | * @sid: SE Linux Security ID of sender |
1100 | */ | 1154 | */ |
1101 | int audit_receive_filter(int type, int pid, int uid, int seq, void *data, | 1155 | int audit_receive_filter(int type, int pid, int seq, void *data, |
1102 | size_t datasz, uid_t loginuid, u32 sessionid, u32 sid) | 1156 | size_t datasz, kuid_t loginuid, u32 sessionid, u32 sid) |
1103 | { | 1157 | { |
1104 | struct task_struct *tsk; | 1158 | struct task_struct *tsk; |
1105 | struct audit_netlink_list *dest; | 1159 | struct audit_netlink_list *dest; |
@@ -1198,6 +1252,52 @@ int audit_comparator(u32 left, u32 op, u32 right) | |||
1198 | } | 1252 | } |
1199 | } | 1253 | } |
1200 | 1254 | ||
1255 | int audit_uid_comparator(kuid_t left, u32 op, kuid_t right) | ||
1256 | { | ||
1257 | switch (op) { | ||
1258 | case Audit_equal: | ||
1259 | return uid_eq(left, right); | ||
1260 | case Audit_not_equal: | ||
1261 | return !uid_eq(left, right); | ||
1262 | case Audit_lt: | ||
1263 | return uid_lt(left, right); | ||
1264 | case Audit_le: | ||
1265 | return uid_lte(left, right); | ||
1266 | case Audit_gt: | ||
1267 | return uid_gt(left, right); | ||
1268 | case Audit_ge: | ||
1269 | return uid_gte(left, right); | ||
1270 | case Audit_bitmask: | ||
1271 | case Audit_bittest: | ||
1272 | default: | ||
1273 | BUG(); | ||
1274 | return 0; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | int audit_gid_comparator(kgid_t left, u32 op, kgid_t right) | ||
1279 | { | ||
1280 | switch (op) { | ||
1281 | case Audit_equal: | ||
1282 | return gid_eq(left, right); | ||
1283 | case Audit_not_equal: | ||
1284 | return !gid_eq(left, right); | ||
1285 | case Audit_lt: | ||
1286 | return gid_lt(left, right); | ||
1287 | case Audit_le: | ||
1288 | return gid_lte(left, right); | ||
1289 | case Audit_gt: | ||
1290 | return gid_gt(left, right); | ||
1291 | case Audit_ge: | ||
1292 | return gid_gte(left, right); | ||
1293 | case Audit_bitmask: | ||
1294 | case Audit_bittest: | ||
1295 | default: | ||
1296 | BUG(); | ||
1297 | return 0; | ||
1298 | } | ||
1299 | } | ||
1300 | |||
1201 | /* Compare given dentry name with last component in given path, | 1301 | /* Compare given dentry name with last component in given path, |
1202 | * return of 0 indicates a match. */ | 1302 | * return of 0 indicates a match. */ |
1203 | int audit_compare_dname_path(const char *dname, const char *path, | 1303 | int audit_compare_dname_path(const char *dname, const char *path, |
@@ -1236,8 +1336,7 @@ int audit_compare_dname_path(const char *dname, const char *path, | |||
1236 | return strncmp(p, dname, dlen); | 1336 | return strncmp(p, dname, dlen); |
1237 | } | 1337 | } |
1238 | 1338 | ||
1239 | static int audit_filter_user_rules(struct netlink_skb_parms *cb, | 1339 | static int audit_filter_user_rules(struct audit_krule *rule, |
1240 | struct audit_krule *rule, | ||
1241 | enum audit_state *state) | 1340 | enum audit_state *state) |
1242 | { | 1341 | { |
1243 | int i; | 1342 | int i; |
@@ -1249,17 +1348,17 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb, | |||
1249 | 1348 | ||
1250 | switch (f->type) { | 1349 | switch (f->type) { |
1251 | case AUDIT_PID: | 1350 | case AUDIT_PID: |
1252 | result = audit_comparator(cb->creds.pid, f->op, f->val); | 1351 | result = audit_comparator(task_pid_vnr(current), f->op, f->val); |
1253 | break; | 1352 | break; |
1254 | case AUDIT_UID: | 1353 | case AUDIT_UID: |
1255 | result = audit_comparator(cb->creds.uid, f->op, f->val); | 1354 | result = audit_uid_comparator(current_uid(), f->op, f->uid); |
1256 | break; | 1355 | break; |
1257 | case AUDIT_GID: | 1356 | case AUDIT_GID: |
1258 | result = audit_comparator(cb->creds.gid, f->op, f->val); | 1357 | result = audit_gid_comparator(current_gid(), f->op, f->gid); |
1259 | break; | 1358 | break; |
1260 | case AUDIT_LOGINUID: | 1359 | case AUDIT_LOGINUID: |
1261 | result = audit_comparator(audit_get_loginuid(current), | 1360 | result = audit_uid_comparator(audit_get_loginuid(current), |
1262 | f->op, f->val); | 1361 | f->op, f->uid); |
1263 | break; | 1362 | break; |
1264 | case AUDIT_SUBJ_USER: | 1363 | case AUDIT_SUBJ_USER: |
1265 | case AUDIT_SUBJ_ROLE: | 1364 | case AUDIT_SUBJ_ROLE: |
@@ -1287,7 +1386,7 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb, | |||
1287 | return 1; | 1386 | return 1; |
1288 | } | 1387 | } |
1289 | 1388 | ||
1290 | int audit_filter_user(struct netlink_skb_parms *cb) | 1389 | int audit_filter_user(void) |
1291 | { | 1390 | { |
1292 | enum audit_state state = AUDIT_DISABLED; | 1391 | enum audit_state state = AUDIT_DISABLED; |
1293 | struct audit_entry *e; | 1392 | struct audit_entry *e; |
@@ -1295,7 +1394,7 @@ int audit_filter_user(struct netlink_skb_parms *cb) | |||
1295 | 1394 | ||
1296 | rcu_read_lock(); | 1395 | rcu_read_lock(); |
1297 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { | 1396 | list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { |
1298 | if (audit_filter_user_rules(cb, &e->rule, &state)) { | 1397 | if (audit_filter_user_rules(&e->rule, &state)) { |
1299 | if (state == AUDIT_DISABLED) | 1398 | if (state == AUDIT_DISABLED) |
1300 | ret = 0; | 1399 | ret = 0; |
1301 | break; | 1400 | break; |