Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'audit-pr-20200226' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit

Pull audit fixes from Paul Moore:
"Two fixes for problems found by syzbot:

- Moving audit filter structure fields into a union caused some
problems in the code which populates that filter structure.

We keep the union (that idea is a good one), but we are fixing the
code so that it doesn't needlessly set fields in the union and mess
up the error handling.

- The audit_receive_msg() function wasn't validating user input as
well as it should in all cases, we add the necessary checks"

* tag 'audit-pr-20200226' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit:
audit: always check the netlink payload length in audit_receive_msg()
audit: fix error handling in audit_data_to_entry()

+65 -56
+21 -19
kernel/audit.c
··· 1101 1101 audit_log_end(ab); 1102 1102 } 1103 1103 1104 - static int audit_set_feature(struct sk_buff *skb) 1104 + static int audit_set_feature(struct audit_features *uaf) 1105 1105 { 1106 - struct audit_features *uaf; 1107 1106 int i; 1108 1107 1109 1108 BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names)); 1110 - uaf = nlmsg_data(nlmsg_hdr(skb)); 1111 1109 1112 1110 /* if there is ever a version 2 we should handle that here */ 1113 1111 ··· 1173 1175 { 1174 1176 u32 seq; 1175 1177 void *data; 1178 + int data_len; 1176 1179 int err; 1177 1180 struct audit_buffer *ab; 1178 1181 u16 msg_type = nlh->nlmsg_type; ··· 1187 1188 1188 1189 seq = nlh->nlmsg_seq; 1189 1190 data = nlmsg_data(nlh); 1191 + data_len = nlmsg_len(nlh); 1190 1192 1191 1193 switch (msg_type) { 1192 1194 case AUDIT_GET: { ··· 1211 1211 struct audit_status s; 1212 1212 memset(&s, 0, sizeof(s)); 1213 1213 /* guard against past and future API changes */ 1214 - memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); 1214 + memcpy(&s, data, min_t(size_t, sizeof(s), data_len)); 1215 1215 if (s.mask & AUDIT_STATUS_ENABLED) { 1216 1216 err = audit_set_enabled(s.enabled); 1217 1217 if (err < 0) ··· 1315 1315 return err; 1316 1316 break; 1317 1317 case AUDIT_SET_FEATURE: 1318 - err = audit_set_feature(skb); 1318 + if (data_len < sizeof(struct audit_features)) 1319 + return -EINVAL; 1320 + err = audit_set_feature(data); 1319 1321 if (err) 1320 1322 return err; 1321 1323 break; ··· 1329 1327 1330 1328 err = audit_filter(msg_type, AUDIT_FILTER_USER); 1331 1329 if (err == 1) { /* match or error */ 1330 + char *str = data; 1331 + 1332 1332 err = 0; 1333 1333 if (msg_type == AUDIT_USER_TTY) { 1334 1334 err = tty_audit_push(); ··· 1338 1334 break; 1339 1335 } 1340 1336 audit_log_user_recv_msg(&ab, msg_type); 1341 - if (msg_type != AUDIT_USER_TTY) 1337 + if (msg_type != AUDIT_USER_TTY) { 1338 + /* ensure NULL termination */ 1339 + str[data_len - 1] = '\0'; 1342 1340 audit_log_format(ab, " msg='%.*s'", 1343 1341 AUDIT_MESSAGE_TEXT_MAX, 1344 - (char *)data); 1345 - else { 1346 - int size; 1347 - 1342 + str); 1343 + } else { 1348 1344 audit_log_format(ab, " data="); 1349 - size = nlmsg_len(nlh); 1350 - if (size > 0 && 1351 - ((unsigned char *)data)[size - 1] == '\0') 1352 - size--; 1353 - audit_log_n_untrustedstring(ab, data, size); 1345 + if (data_len > 0 && str[data_len - 1] == '\0') 1346 + data_len--; 1347 + audit_log_n_untrustedstring(ab, str, data_len); 1354 1348 } 1355 1349 audit_log_end(ab); 1356 1350 } 1357 1351 break; 1358 1352 case AUDIT_ADD_RULE: 1359 1353 case AUDIT_DEL_RULE: 1360 - if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) 1354 + if (data_len < sizeof(struct audit_rule_data)) 1361 1355 return -EINVAL; 1362 1356 if (audit_enabled == AUDIT_LOCKED) { 1363 1357 audit_log_common_recv_msg(audit_context(), &ab, ··· 1367 1365 audit_log_end(ab); 1368 1366 return -EPERM; 1369 1367 } 1370 - err = audit_rule_change(msg_type, seq, data, nlmsg_len(nlh)); 1368 + err = audit_rule_change(msg_type, seq, data, data_len); 1371 1369 break; 1372 1370 case AUDIT_LIST_RULES: 1373 1371 err = audit_list_rules_send(skb, seq); ··· 1382 1380 case AUDIT_MAKE_EQUIV: { 1383 1381 void *bufp = data; 1384 1382 u32 sizes[2]; 1385 - size_t msglen = nlmsg_len(nlh); 1383 + size_t msglen = data_len; 1386 1384 char *old, *new; 1387 1385 1388 1386 err = -EINVAL; ··· 1458 1456 1459 1457 memset(&s, 0, sizeof(s)); 1460 1458 /* guard against past and future API changes */ 1461 - memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); 1459 + memcpy(&s, data, min_t(size_t, sizeof(s), data_len)); 1462 1460 /* check if new data is valid */ 1463 1461 if ((s.enabled != 0 && s.enabled != 1) || 1464 1462 (s.log_passwd != 0 && s.log_passwd != 1))
+44 -37
kernel/auditfilter.c
··· 456 456 bufp = data->buf; 457 457 for (i = 0; i < data->field_count; i++) { 458 458 struct audit_field *f = &entry->rule.fields[i]; 459 + u32 f_val; 459 460 460 461 err = -EINVAL; 461 462 ··· 465 464 goto exit_free; 466 465 467 466 f->type = data->fields[i]; 468 - f->val = data->values[i]; 467 + f_val = data->values[i]; 469 468 470 469 /* Support legacy tests for a valid loginuid */ 471 - if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) { 470 + if ((f->type == AUDIT_LOGINUID) && (f_val == AUDIT_UID_UNSET)) { 472 471 f->type = AUDIT_LOGINUID_SET; 473 - f->val = 0; 472 + f_val = 0; 474 473 entry->rule.pflags |= AUDIT_LOGINUID_LEGACY; 475 474 } 476 475 ··· 486 485 case AUDIT_SUID: 487 486 case AUDIT_FSUID: 488 487 case AUDIT_OBJ_UID: 489 - f->uid = make_kuid(current_user_ns(), f->val); 488 + f->uid = make_kuid(current_user_ns(), f_val); 490 489 if (!uid_valid(f->uid)) 491 490 goto exit_free; 492 491 break; ··· 495 494 case AUDIT_SGID: 496 495 case AUDIT_FSGID: 497 496 case AUDIT_OBJ_GID: 498 - f->gid = make_kgid(current_user_ns(), f->val); 497 + f->gid = make_kgid(current_user_ns(), f_val); 499 498 if (!gid_valid(f->gid)) 500 499 goto exit_free; 501 500 break; 502 501 case AUDIT_ARCH: 502 + f->val = f_val; 503 503 entry->rule.arch_f = f; 504 504 break; 505 505 case AUDIT_SUBJ_USER: ··· 513 511 case AUDIT_OBJ_TYPE: 514 512 case AUDIT_OBJ_LEV_LOW: 515 513 case AUDIT_OBJ_LEV_HIGH: 516 - str = audit_unpack_string(&bufp, &remain, f->val); 517 - if (IS_ERR(str)) 514 + str = audit_unpack_string(&bufp, &remain, f_val); 515 + if (IS_ERR(str)) { 516 + err = PTR_ERR(str); 518 517 goto exit_free; 519 - entry->rule.buflen += f->val; 520 - 518 + } 519 + entry->rule.buflen += f_val; 520 + f->lsm_str = str; 521 521 err = security_audit_rule_init(f->type, f->op, str, 522 522 (void **)&f->lsm_rule); 523 523 /* Keep currently invalid fields around in case they ··· 528 524 pr_warn("audit rule for LSM \'%s\' is invalid\n", 529 525 str); 530 526 err = 0; 531 - } 532 - if (err) { 533 - kfree(str); 527 + } else if (err) 534 528 goto exit_free; 535 - } else 536 - f->lsm_str = str; 537 529 break; 538 530 case AUDIT_WATCH: 539 - str = audit_unpack_string(&bufp, &remain, f->val); 540 - if (IS_ERR(str)) 531 + str = audit_unpack_string(&bufp, &remain, f_val); 532 + if (IS_ERR(str)) { 533 + err = PTR_ERR(str); 541 534 goto exit_free; 542 - entry->rule.buflen += f->val; 543 - 544 - err = audit_to_watch(&entry->rule, str, f->val, f->op); 535 + } 536 + err = audit_to_watch(&entry->rule, str, f_val, f->op); 545 537 if (err) { 546 538 kfree(str); 547 539 goto exit_free; 548 540 } 541 + entry->rule.buflen += f_val; 549 542 break; 550 543 case AUDIT_DIR: 551 - str = audit_unpack_string(&bufp, &remain, f->val); 552 - if (IS_ERR(str)) 544 + str = audit_unpack_string(&bufp, &remain, f_val); 545 + if (IS_ERR(str)) { 546 + err = PTR_ERR(str); 553 547 goto exit_free; 554 - entry->rule.buflen += f->val; 555 - 548 + } 556 549 err = audit_make_tree(&entry->rule, str, f->op); 557 550 kfree(str); 558 551 if (err) 559 552 goto exit_free; 553 + entry->rule.buflen += f_val; 560 554 break; 561 555 case AUDIT_INODE: 556 + f->val = f_val; 562 557 err = audit_to_inode(&entry->rule, f); 563 558 if (err) 564 559 goto exit_free; 565 560 break; 566 561 case AUDIT_FILTERKEY: 567 - if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN) 562 + if (entry->rule.filterkey || f_val > AUDIT_MAX_KEY_LEN) 568 563 goto exit_free; 569 - str = audit_unpack_string(&bufp, &remain, f->val); 570 - if (IS_ERR(str)) 571 - goto exit_free; 572 - entry->rule.buflen += f->val; 573 - entry->rule.filterkey = str; 574 - break; 575 - case AUDIT_EXE: 576 - if (entry->rule.exe || f->val > PATH_MAX) 577 - goto exit_free; 578 - str = audit_unpack_string(&bufp, &remain, f->val); 564 + str = audit_unpack_string(&bufp, &remain, f_val); 579 565 if (IS_ERR(str)) { 580 566 err = PTR_ERR(str); 581 567 goto exit_free; 582 568 } 583 - entry->rule.buflen += f->val; 584 - 585 - audit_mark = audit_alloc_mark(&entry->rule, str, f->val); 569 + entry->rule.buflen += f_val; 570 + entry->rule.filterkey = str; 571 + break; 572 + case AUDIT_EXE: 573 + if (entry->rule.exe || f_val > PATH_MAX) 574 + goto exit_free; 575 + str = audit_unpack_string(&bufp, &remain, f_val); 576 + if (IS_ERR(str)) { 577 + err = PTR_ERR(str); 578 + goto exit_free; 579 + } 580 + audit_mark = audit_alloc_mark(&entry->rule, str, f_val); 586 581 if (IS_ERR(audit_mark)) { 587 582 kfree(str); 588 583 err = PTR_ERR(audit_mark); 589 584 goto exit_free; 590 585 } 586 + entry->rule.buflen += f_val; 591 587 entry->rule.exe = audit_mark; 588 + break; 589 + default: 590 + f->val = f_val; 592 591 break; 593 592 } 594 593 }