diff options
33 files changed, 2890 insertions, 471 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy new file mode 100644 index 00000000000..6434f0df012 --- /dev/null +++ b/Documentation/ABI/testing/ima_policy | |||
@@ -0,0 +1,61 @@ | |||
1 | What: security/ima/policy | ||
2 | Date: May 2008 | ||
3 | Contact: Mimi Zohar <zohar@us.ibm.com> | ||
4 | Description: | ||
5 | The Trusted Computing Group(TCG) runtime Integrity | ||
6 | Measurement Architecture(IMA) maintains a list of hash | ||
7 | values of executables and other sensitive system files | ||
8 | loaded into the run-time of this system. At runtime, | ||
9 | the policy can be constrained based on LSM specific data. | ||
10 | Policies are loaded into the securityfs file ima/policy | ||
11 | by opening the file, writing the rules one at a time and | ||
12 | then closing the file. The new policy takes effect after | ||
13 | the file ima/policy is closed. | ||
14 | |||
15 | rule format: action [condition ...] | ||
16 | |||
17 | action: measure | dont_measure | ||
18 | condition:= base | lsm | ||
19 | base: [[func=] [mask=] [fsmagic=] [uid=]] | ||
20 | lsm: [[subj_user=] [subj_role=] [subj_type=] | ||
21 | [obj_user=] [obj_role=] [obj_type=]] | ||
22 | |||
23 | base: func:= [BPRM_CHECK][FILE_MMAP][INODE_PERMISSION] | ||
24 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] | ||
25 | fsmagic:= hex value | ||
26 | uid:= decimal value | ||
27 | lsm: are LSM specific | ||
28 | |||
29 | default policy: | ||
30 | # PROC_SUPER_MAGIC | ||
31 | dont_measure fsmagic=0x9fa0 | ||
32 | # SYSFS_MAGIC | ||
33 | dont_measure fsmagic=0x62656572 | ||
34 | # DEBUGFS_MAGIC | ||
35 | dont_measure fsmagic=0x64626720 | ||
36 | # TMPFS_MAGIC | ||
37 | dont_measure fsmagic=0x01021994 | ||
38 | # SECURITYFS_MAGIC | ||
39 | dont_measure fsmagic=0x73636673 | ||
40 | |||
41 | measure func=BPRM_CHECK | ||
42 | measure func=FILE_MMAP mask=MAY_EXEC | ||
43 | measure func=INODE_PERM mask=MAY_READ uid=0 | ||
44 | |||
45 | The default policy measures all executables in bprm_check, | ||
46 | all files mmapped executable in file_mmap, and all files | ||
47 | open for read by root in inode_permission. | ||
48 | |||
49 | Examples of LSM specific definitions: | ||
50 | |||
51 | SELinux: | ||
52 | # SELINUX_MAGIC | ||
53 | dont_measure fsmagic=0xF97CFF8C | ||
54 | |||
55 | dont_measure obj_type=var_log_t | ||
56 | dont_measure obj_type=auditd_log_t | ||
57 | measure subj_user=system_u func=INODE_PERM mask=MAY_READ | ||
58 | measure subj_role=system_r func=INODE_PERM mask=MAY_READ | ||
59 | |||
60 | Smack: | ||
61 | measure subj_user=_ func=INODE_PERM mask=MAY_READ | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d8362cf9909..8cc40a1bee0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -44,6 +44,7 @@ parameter is applicable: | |||
44 | FB The frame buffer device is enabled. | 44 | FB The frame buffer device is enabled. |
45 | HW Appropriate hardware is enabled. | 45 | HW Appropriate hardware is enabled. |
46 | IA-64 IA-64 architecture is enabled. | 46 | IA-64 IA-64 architecture is enabled. |
47 | IMA Integrity measurement architecture is enabled. | ||
47 | IOSCHED More than one I/O scheduler is enabled. | 48 | IOSCHED More than one I/O scheduler is enabled. |
48 | IP_PNP IP DHCP, BOOTP, or RARP is enabled. | 49 | IP_PNP IP DHCP, BOOTP, or RARP is enabled. |
49 | ISAPNP ISA PnP code is enabled. | 50 | ISAPNP ISA PnP code is enabled. |
@@ -900,6 +901,15 @@ and is between 256 and 4096 characters. It is defined in the file | |||
900 | ihash_entries= [KNL] | 901 | ihash_entries= [KNL] |
901 | Set number of hash buckets for inode cache. | 902 | Set number of hash buckets for inode cache. |
902 | 903 | ||
904 | ima_audit= [IMA] | ||
905 | Format: { "0" | "1" } | ||
906 | 0 -- integrity auditing messages. (Default) | ||
907 | 1 -- enable informational integrity auditing messages. | ||
908 | |||
909 | ima_hash= [IMA] | ||
910 | Formt: { "sha1" | "md5" } | ||
911 | default: "sha1" | ||
912 | |||
903 | in2000= [HW,SCSI] | 913 | in2000= [HW,SCSI] |
904 | See header of drivers/scsi/in2000.c. | 914 | See header of drivers/scsi/in2000.c. |
905 | 915 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 421504b59c2..a781f2ec082 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2201,6 +2201,11 @@ M: stefanr@s5r6.in-berlin.de | |||
2201 | L: linux1394-devel@lists.sourceforge.net | 2201 | L: linux1394-devel@lists.sourceforge.net |
2202 | S: Maintained | 2202 | S: Maintained |
2203 | 2203 | ||
2204 | INTEGRITY MEASUREMENT ARCHITECTURE (IMA) | ||
2205 | P: Mimi Zohar | ||
2206 | M: zohar@us.ibm.com | ||
2207 | S: Supported | ||
2208 | |||
2204 | IMS TWINTURBO FRAMEBUFFER DRIVER | 2209 | IMS TWINTURBO FRAMEBUFFER DRIVER |
2205 | L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers) | 2210 | L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers) |
2206 | S: Orphan | 2211 | S: Orphan |
@@ -3825,6 +3830,7 @@ M: jmorris@namei.org | |||
3825 | L: linux-kernel@vger.kernel.org | 3830 | L: linux-kernel@vger.kernel.org |
3826 | L: linux-security-module@vger.kernel.org (suggested Cc:) | 3831 | L: linux-security-module@vger.kernel.org (suggested Cc:) |
3827 | T: git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git | 3832 | T: git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git |
3833 | W: http://security.wiki.kernel.org/ | ||
3828 | S: Supported | 3834 | S: Supported |
3829 | 3835 | ||
3830 | SECURITY CONTACT | 3836 | SECURITY CONTACT |
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 9c47dc48c9f..ccdd828adce 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -429,134 +429,148 @@ out: | |||
429 | #define TPM_DIGEST_SIZE 20 | 429 | #define TPM_DIGEST_SIZE 20 |
430 | #define TPM_ERROR_SIZE 10 | 430 | #define TPM_ERROR_SIZE 10 |
431 | #define TPM_RET_CODE_IDX 6 | 431 | #define TPM_RET_CODE_IDX 6 |
432 | #define TPM_GET_CAP_RET_SIZE_IDX 10 | ||
433 | #define TPM_GET_CAP_RET_UINT32_1_IDX 14 | ||
434 | #define TPM_GET_CAP_RET_UINT32_2_IDX 18 | ||
435 | #define TPM_GET_CAP_RET_UINT32_3_IDX 22 | ||
436 | #define TPM_GET_CAP_RET_UINT32_4_IDX 26 | ||
437 | #define TPM_GET_CAP_PERM_DISABLE_IDX 16 | ||
438 | #define TPM_GET_CAP_PERM_INACTIVE_IDX 18 | ||
439 | #define TPM_GET_CAP_RET_BOOL_1_IDX 14 | ||
440 | #define TPM_GET_CAP_TEMP_INACTIVE_IDX 16 | ||
441 | |||
442 | #define TPM_CAP_IDX 13 | ||
443 | #define TPM_CAP_SUBCAP_IDX 21 | ||
444 | 432 | ||
445 | enum tpm_capabilities { | 433 | enum tpm_capabilities { |
446 | TPM_CAP_FLAG = 4, | 434 | TPM_CAP_FLAG = cpu_to_be32(4), |
447 | TPM_CAP_PROP = 5, | 435 | TPM_CAP_PROP = cpu_to_be32(5), |
436 | CAP_VERSION_1_1 = cpu_to_be32(0x06), | ||
437 | CAP_VERSION_1_2 = cpu_to_be32(0x1A) | ||
448 | }; | 438 | }; |
449 | 439 | ||
450 | enum tpm_sub_capabilities { | 440 | enum tpm_sub_capabilities { |
451 | TPM_CAP_PROP_PCR = 0x1, | 441 | TPM_CAP_PROP_PCR = cpu_to_be32(0x101), |
452 | TPM_CAP_PROP_MANUFACTURER = 0x3, | 442 | TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), |
453 | TPM_CAP_FLAG_PERM = 0x8, | 443 | TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), |
454 | TPM_CAP_FLAG_VOL = 0x9, | 444 | TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), |
455 | TPM_CAP_PROP_OWNER = 0x11, | 445 | TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), |
456 | TPM_CAP_PROP_TIS_TIMEOUT = 0x15, | 446 | TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), |
457 | TPM_CAP_PROP_TIS_DURATION = 0x20, | 447 | TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), |
458 | }; | ||
459 | 448 | ||
460 | /* | ||
461 | * This is a semi generic GetCapability command for use | ||
462 | * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG | ||
463 | * and their associated sub_capabilities. | ||
464 | */ | ||
465 | |||
466 | static const u8 tpm_cap[] = { | ||
467 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
468 | 0, 0, 0, 22, /* length */ | ||
469 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | ||
470 | 0, 0, 0, 0, /* TPM_CAP_<TYPE> */ | ||
471 | 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */ | ||
472 | 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */ | ||
473 | }; | 449 | }; |
474 | 450 | ||
475 | static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, | 451 | static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, |
476 | char *desc) | 452 | int len, const char *desc) |
477 | { | 453 | { |
478 | int err; | 454 | int err; |
479 | 455 | ||
480 | len = tpm_transmit(chip, data, len); | 456 | len = tpm_transmit(chip,(u8 *) cmd, len); |
481 | if (len < 0) | 457 | if (len < 0) |
482 | return len; | 458 | return len; |
483 | if (len == TPM_ERROR_SIZE) { | 459 | if (len == TPM_ERROR_SIZE) { |
484 | err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); | 460 | err = be32_to_cpu(cmd->header.out.return_code); |
485 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | 461 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); |
486 | return err; | 462 | return err; |
487 | } | 463 | } |
488 | return 0; | 464 | return 0; |
489 | } | 465 | } |
490 | 466 | ||
467 | #define TPM_INTERNAL_RESULT_SIZE 200 | ||
468 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | ||
469 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | ||
470 | |||
471 | static const struct tpm_input_header tpm_getcap_header = { | ||
472 | .tag = TPM_TAG_RQU_COMMAND, | ||
473 | .length = cpu_to_be32(22), | ||
474 | .ordinal = TPM_ORD_GET_CAP | ||
475 | }; | ||
476 | |||
477 | ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, | ||
478 | const char *desc) | ||
479 | { | ||
480 | struct tpm_cmd_t tpm_cmd; | ||
481 | int rc; | ||
482 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
483 | |||
484 | tpm_cmd.header.in = tpm_getcap_header; | ||
485 | if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) { | ||
486 | tpm_cmd.params.getcap_in.cap = subcap_id; | ||
487 | /*subcap field not necessary */ | ||
488 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); | ||
489 | tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); | ||
490 | } else { | ||
491 | if (subcap_id == TPM_CAP_FLAG_PERM || | ||
492 | subcap_id == TPM_CAP_FLAG_VOL) | ||
493 | tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG; | ||
494 | else | ||
495 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | ||
496 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | ||
497 | tpm_cmd.params.getcap_in.subcap = subcap_id; | ||
498 | } | ||
499 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); | ||
500 | if (!rc) | ||
501 | *cap = tpm_cmd.params.getcap_out.cap; | ||
502 | return rc; | ||
503 | } | ||
504 | |||
491 | void tpm_gen_interrupt(struct tpm_chip *chip) | 505 | void tpm_gen_interrupt(struct tpm_chip *chip) |
492 | { | 506 | { |
493 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | 507 | struct tpm_cmd_t tpm_cmd; |
494 | ssize_t rc; | 508 | ssize_t rc; |
495 | 509 | ||
496 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 510 | tpm_cmd.header.in = tpm_getcap_header; |
497 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 511 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
498 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | 512 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
513 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
499 | 514 | ||
500 | rc = transmit_cmd(chip, data, sizeof(data), | 515 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
501 | "attempting to determine the timeouts"); | 516 | "attempting to determine the timeouts"); |
502 | } | 517 | } |
503 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | 518 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); |
504 | 519 | ||
505 | void tpm_get_timeouts(struct tpm_chip *chip) | 520 | void tpm_get_timeouts(struct tpm_chip *chip) |
506 | { | 521 | { |
507 | u8 data[max_t(int, ARRAY_SIZE(tpm_cap), 30)]; | 522 | struct tpm_cmd_t tpm_cmd; |
523 | struct timeout_t *timeout_cap; | ||
524 | struct duration_t *duration_cap; | ||
508 | ssize_t rc; | 525 | ssize_t rc; |
509 | u32 timeout; | 526 | u32 timeout; |
510 | 527 | ||
511 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 528 | tpm_cmd.header.in = tpm_getcap_header; |
512 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 529 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
513 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_TIMEOUT; | 530 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
531 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
514 | 532 | ||
515 | rc = transmit_cmd(chip, data, sizeof(data), | 533 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
516 | "attempting to determine the timeouts"); | 534 | "attempting to determine the timeouts"); |
517 | if (rc) | 535 | if (rc) |
518 | goto duration; | 536 | goto duration; |
519 | 537 | ||
520 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | 538 | if (be32_to_cpu(tpm_cmd.header.out.length) |
521 | != 4 * sizeof(u32)) | 539 | != 4 * sizeof(u32)) |
522 | goto duration; | 540 | goto duration; |
523 | 541 | ||
542 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; | ||
524 | /* Don't overwrite default if value is 0 */ | 543 | /* Don't overwrite default if value is 0 */ |
525 | timeout = | 544 | timeout = be32_to_cpu(timeout_cap->a); |
526 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX))); | ||
527 | if (timeout) | 545 | if (timeout) |
528 | chip->vendor.timeout_a = usecs_to_jiffies(timeout); | 546 | chip->vendor.timeout_a = usecs_to_jiffies(timeout); |
529 | timeout = | 547 | timeout = be32_to_cpu(timeout_cap->b); |
530 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX))); | ||
531 | if (timeout) | 548 | if (timeout) |
532 | chip->vendor.timeout_b = usecs_to_jiffies(timeout); | 549 | chip->vendor.timeout_b = usecs_to_jiffies(timeout); |
533 | timeout = | 550 | timeout = be32_to_cpu(timeout_cap->c); |
534 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX))); | ||
535 | if (timeout) | 551 | if (timeout) |
536 | chip->vendor.timeout_c = usecs_to_jiffies(timeout); | 552 | chip->vendor.timeout_c = usecs_to_jiffies(timeout); |
537 | timeout = | 553 | timeout = be32_to_cpu(timeout_cap->d); |
538 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX))); | ||
539 | if (timeout) | 554 | if (timeout) |
540 | chip->vendor.timeout_d = usecs_to_jiffies(timeout); | 555 | chip->vendor.timeout_d = usecs_to_jiffies(timeout); |
541 | 556 | ||
542 | duration: | 557 | duration: |
543 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 558 | tpm_cmd.header.in = tpm_getcap_header; |
544 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | 559 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
545 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_TIS_DURATION; | 560 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
561 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; | ||
546 | 562 | ||
547 | rc = transmit_cmd(chip, data, sizeof(data), | 563 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
548 | "attempting to determine the durations"); | 564 | "attempting to determine the durations"); |
549 | if (rc) | 565 | if (rc) |
550 | return; | 566 | return; |
551 | 567 | ||
552 | if (be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_SIZE_IDX))) | 568 | if (be32_to_cpu(tpm_cmd.header.out.return_code) |
553 | != 3 * sizeof(u32)) | 569 | != 3 * sizeof(u32)) |
554 | return; | 570 | return; |
555 | 571 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; | |
556 | chip->vendor.duration[TPM_SHORT] = | 572 | chip->vendor.duration[TPM_SHORT] = |
557 | usecs_to_jiffies(be32_to_cpu | 573 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); |
558 | (*((__be32 *) (data + | ||
559 | TPM_GET_CAP_RET_UINT32_1_IDX)))); | ||
560 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above | 574 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above |
561 | * value wrong and apparently reports msecs rather than usecs. So we | 575 | * value wrong and apparently reports msecs rather than usecs. So we |
562 | * fix up the resulting too-small TPM_SHORT value to make things work. | 576 | * fix up the resulting too-small TPM_SHORT value to make things work. |
@@ -565,13 +579,9 @@ duration: | |||
565 | chip->vendor.duration[TPM_SHORT] = HZ; | 579 | chip->vendor.duration[TPM_SHORT] = HZ; |
566 | 580 | ||
567 | chip->vendor.duration[TPM_MEDIUM] = | 581 | chip->vendor.duration[TPM_MEDIUM] = |
568 | usecs_to_jiffies(be32_to_cpu | 582 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); |
569 | (*((__be32 *) (data + | ||
570 | TPM_GET_CAP_RET_UINT32_2_IDX)))); | ||
571 | chip->vendor.duration[TPM_LONG] = | 583 | chip->vendor.duration[TPM_LONG] = |
572 | usecs_to_jiffies(be32_to_cpu | 584 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); |
573 | (*((__be32 *) (data + | ||
574 | TPM_GET_CAP_RET_UINT32_3_IDX)))); | ||
575 | } | 585 | } |
576 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 586 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
577 | 587 | ||
@@ -587,36 +597,18 @@ void tpm_continue_selftest(struct tpm_chip *chip) | |||
587 | } | 597 | } |
588 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | 598 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); |
589 | 599 | ||
590 | #define TPM_INTERNAL_RESULT_SIZE 200 | ||
591 | |||
592 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | 600 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, |
593 | char *buf) | 601 | char *buf) |
594 | { | 602 | { |
595 | u8 *data; | 603 | cap_t cap; |
596 | ssize_t rc; | 604 | ssize_t rc; |
597 | 605 | ||
598 | struct tpm_chip *chip = dev_get_drvdata(dev); | 606 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, |
599 | if (chip == NULL) | 607 | "attempting to determine the permanent enabled state"); |
600 | return -ENODEV; | 608 | if (rc) |
601 | |||
602 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
603 | if (!data) | ||
604 | return -ENOMEM; | ||
605 | |||
606 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
607 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
608 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
609 | |||
610 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
611 | "attemtping to determine the permanent enabled state"); | ||
612 | if (rc) { | ||
613 | kfree(data); | ||
614 | return 0; | 609 | return 0; |
615 | } | ||
616 | |||
617 | rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_DISABLE_IDX]); | ||
618 | 610 | ||
619 | kfree(data); | 611 | rc = sprintf(buf, "%d\n", !cap.perm_flags.disable); |
620 | return rc; | 612 | return rc; |
621 | } | 613 | } |
622 | EXPORT_SYMBOL_GPL(tpm_show_enabled); | 614 | EXPORT_SYMBOL_GPL(tpm_show_enabled); |
@@ -624,31 +616,15 @@ EXPORT_SYMBOL_GPL(tpm_show_enabled); | |||
624 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, | 616 | ssize_t tpm_show_active(struct device * dev, struct device_attribute * attr, |
625 | char *buf) | 617 | char *buf) |
626 | { | 618 | { |
627 | u8 *data; | 619 | cap_t cap; |
628 | ssize_t rc; | 620 | ssize_t rc; |
629 | 621 | ||
630 | struct tpm_chip *chip = dev_get_drvdata(dev); | 622 | rc = tpm_getcap(dev, TPM_CAP_FLAG_PERM, &cap, |
631 | if (chip == NULL) | 623 | "attempting to determine the permanent active state"); |
632 | return -ENODEV; | 624 | if (rc) |
633 | |||
634 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
635 | if (!data) | ||
636 | return -ENOMEM; | ||
637 | |||
638 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
639 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | ||
640 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_PERM; | ||
641 | |||
642 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
643 | "attemtping to determine the permanent active state"); | ||
644 | if (rc) { | ||
645 | kfree(data); | ||
646 | return 0; | 625 | return 0; |
647 | } | ||
648 | 626 | ||
649 | rc = sprintf(buf, "%d\n", !data[TPM_GET_CAP_PERM_INACTIVE_IDX]); | 627 | rc = sprintf(buf, "%d\n", !cap.perm_flags.deactivated); |
650 | |||
651 | kfree(data); | ||
652 | return rc; | 628 | return rc; |
653 | } | 629 | } |
654 | EXPORT_SYMBOL_GPL(tpm_show_active); | 630 | EXPORT_SYMBOL_GPL(tpm_show_active); |
@@ -656,31 +632,15 @@ EXPORT_SYMBOL_GPL(tpm_show_active); | |||
656 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, | 632 | ssize_t tpm_show_owned(struct device * dev, struct device_attribute * attr, |
657 | char *buf) | 633 | char *buf) |
658 | { | 634 | { |
659 | u8 *data; | 635 | cap_t cap; |
660 | ssize_t rc; | 636 | ssize_t rc; |
661 | 637 | ||
662 | struct tpm_chip *chip = dev_get_drvdata(dev); | 638 | rc = tpm_getcap(dev, TPM_CAP_PROP_OWNER, &cap, |
663 | if (chip == NULL) | 639 | "attempting to determine the owner state"); |
664 | return -ENODEV; | 640 | if (rc) |
665 | |||
666 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
667 | if (!data) | ||
668 | return -ENOMEM; | ||
669 | |||
670 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
671 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
672 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_OWNER; | ||
673 | |||
674 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
675 | "attempting to determine the owner state"); | ||
676 | if (rc) { | ||
677 | kfree(data); | ||
678 | return 0; | 641 | return 0; |
679 | } | ||
680 | |||
681 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_RET_BOOL_1_IDX]); | ||
682 | 642 | ||
683 | kfree(data); | 643 | rc = sprintf(buf, "%d\n", cap.owned); |
684 | return rc; | 644 | return rc; |
685 | } | 645 | } |
686 | EXPORT_SYMBOL_GPL(tpm_show_owned); | 646 | EXPORT_SYMBOL_GPL(tpm_show_owned); |
@@ -688,116 +648,180 @@ EXPORT_SYMBOL_GPL(tpm_show_owned); | |||
688 | ssize_t tpm_show_temp_deactivated(struct device * dev, | 648 | ssize_t tpm_show_temp_deactivated(struct device * dev, |
689 | struct device_attribute * attr, char *buf) | 649 | struct device_attribute * attr, char *buf) |
690 | { | 650 | { |
691 | u8 *data; | 651 | cap_t cap; |
692 | ssize_t rc; | 652 | ssize_t rc; |
693 | 653 | ||
694 | struct tpm_chip *chip = dev_get_drvdata(dev); | 654 | rc = tpm_getcap(dev, TPM_CAP_FLAG_VOL, &cap, |
695 | if (chip == NULL) | 655 | "attempting to determine the temporary state"); |
696 | return -ENODEV; | 656 | if (rc) |
657 | return 0; | ||
697 | 658 | ||
698 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | 659 | rc = sprintf(buf, "%d\n", cap.stclear_flags.deactivated); |
699 | if (!data) | 660 | return rc; |
700 | return -ENOMEM; | 661 | } |
662 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
701 | 663 | ||
702 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | 664 | /* |
703 | data[TPM_CAP_IDX] = TPM_CAP_FLAG; | 665 | * tpm_chip_find_get - return tpm_chip for given chip number |
704 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_FLAG_VOL; | 666 | */ |
667 | static struct tpm_chip *tpm_chip_find_get(int chip_num) | ||
668 | { | ||
669 | struct tpm_chip *pos, *chip = NULL; | ||
705 | 670 | ||
706 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | 671 | rcu_read_lock(); |
707 | "attempting to determine the temporary state"); | 672 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { |
708 | if (rc) { | 673 | if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) |
709 | kfree(data); | 674 | continue; |
710 | return 0; | 675 | |
676 | if (try_module_get(pos->dev->driver->owner)) { | ||
677 | chip = pos; | ||
678 | break; | ||
679 | } | ||
711 | } | 680 | } |
681 | rcu_read_unlock(); | ||
682 | return chip; | ||
683 | } | ||
712 | 684 | ||
713 | rc = sprintf(buf, "%d\n", data[TPM_GET_CAP_TEMP_INACTIVE_IDX]); | 685 | #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) |
686 | #define READ_PCR_RESULT_SIZE 30 | ||
687 | static struct tpm_input_header pcrread_header = { | ||
688 | .tag = TPM_TAG_RQU_COMMAND, | ||
689 | .length = cpu_to_be32(14), | ||
690 | .ordinal = TPM_ORDINAL_PCRREAD | ||
691 | }; | ||
714 | 692 | ||
715 | kfree(data); | 693 | int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) |
694 | { | ||
695 | int rc; | ||
696 | struct tpm_cmd_t cmd; | ||
697 | |||
698 | cmd.header.in = pcrread_header; | ||
699 | cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); | ||
700 | BUILD_BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE); | ||
701 | rc = transmit_cmd(chip, &cmd, cmd.header.in.length, | ||
702 | "attempting to read a pcr value"); | ||
703 | |||
704 | if (rc == 0) | ||
705 | memcpy(res_buf, cmd.params.pcrread_out.pcr_result, | ||
706 | TPM_DIGEST_SIZE); | ||
716 | return rc; | 707 | return rc; |
717 | } | 708 | } |
718 | EXPORT_SYMBOL_GPL(tpm_show_temp_deactivated); | ||
719 | 709 | ||
720 | static const u8 pcrread[] = { | 710 | /** |
721 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 711 | * tpm_pcr_read - read a pcr value |
722 | 0, 0, 0, 14, /* length */ | 712 | * @chip_num: tpm idx # or ANY |
723 | 0, 0, 0, 21, /* TPM_ORD_PcrRead */ | 713 | * @pcr_idx: pcr idx to retrieve |
724 | 0, 0, 0, 0 /* PCR index */ | 714 | * @res_buf: TPM_PCR value |
715 | * size of res_buf is 20 bytes (or NULL if you don't care) | ||
716 | * | ||
717 | * The TPM driver should be built-in, but for whatever reason it | ||
718 | * isn't, protect against the chip disappearing, by incrementing | ||
719 | * the module usage count. | ||
720 | */ | ||
721 | int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) | ||
722 | { | ||
723 | struct tpm_chip *chip; | ||
724 | int rc; | ||
725 | |||
726 | chip = tpm_chip_find_get(chip_num); | ||
727 | if (chip == NULL) | ||
728 | return -ENODEV; | ||
729 | rc = __tpm_pcr_read(chip, pcr_idx, res_buf); | ||
730 | module_put(chip->dev->driver->owner); | ||
731 | return rc; | ||
732 | } | ||
733 | EXPORT_SYMBOL_GPL(tpm_pcr_read); | ||
734 | |||
735 | /** | ||
736 | * tpm_pcr_extend - extend pcr value with hash | ||
737 | * @chip_num: tpm idx # or AN& | ||
738 | * @pcr_idx: pcr idx to extend | ||
739 | * @hash: hash value used to extend pcr value | ||
740 | * | ||
741 | * The TPM driver should be built-in, but for whatever reason it | ||
742 | * isn't, protect against the chip disappearing, by incrementing | ||
743 | * the module usage count. | ||
744 | */ | ||
745 | #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) | ||
746 | #define EXTEND_PCR_SIZE 34 | ||
747 | static struct tpm_input_header pcrextend_header = { | ||
748 | .tag = TPM_TAG_RQU_COMMAND, | ||
749 | .length = cpu_to_be32(34), | ||
750 | .ordinal = TPM_ORD_PCR_EXTEND | ||
725 | }; | 751 | }; |
726 | 752 | ||
753 | int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) | ||
754 | { | ||
755 | struct tpm_cmd_t cmd; | ||
756 | int rc; | ||
757 | struct tpm_chip *chip; | ||
758 | |||
759 | chip = tpm_chip_find_get(chip_num); | ||
760 | if (chip == NULL) | ||
761 | return -ENODEV; | ||
762 | |||
763 | cmd.header.in = pcrextend_header; | ||
764 | BUILD_BUG_ON(be32_to_cpu(cmd.header.in.length) > EXTEND_PCR_SIZE); | ||
765 | cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); | ||
766 | memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); | ||
767 | rc = transmit_cmd(chip, &cmd, cmd.header.in.length, | ||
768 | "attempting extend a PCR value"); | ||
769 | |||
770 | module_put(chip->dev->driver->owner); | ||
771 | return rc; | ||
772 | } | ||
773 | EXPORT_SYMBOL_GPL(tpm_pcr_extend); | ||
774 | |||
727 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 775 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
728 | char *buf) | 776 | char *buf) |
729 | { | 777 | { |
730 | u8 *data; | 778 | cap_t cap; |
779 | u8 digest[TPM_DIGEST_SIZE]; | ||
731 | ssize_t rc; | 780 | ssize_t rc; |
732 | int i, j, num_pcrs; | 781 | int i, j, num_pcrs; |
733 | __be32 index; | ||
734 | char *str = buf; | 782 | char *str = buf; |
735 | |||
736 | struct tpm_chip *chip = dev_get_drvdata(dev); | 783 | struct tpm_chip *chip = dev_get_drvdata(dev); |
737 | if (chip == NULL) | ||
738 | return -ENODEV; | ||
739 | 784 | ||
740 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | 785 | rc = tpm_getcap(dev, TPM_CAP_PROP_PCR, &cap, |
741 | if (!data) | ||
742 | return -ENOMEM; | ||
743 | |||
744 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
745 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
746 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; | ||
747 | |||
748 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
749 | "attempting to determine the number of PCRS"); | 786 | "attempting to determine the number of PCRS"); |
750 | if (rc) { | 787 | if (rc) |
751 | kfree(data); | ||
752 | return 0; | 788 | return 0; |
753 | } | ||
754 | 789 | ||
755 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); | 790 | num_pcrs = be32_to_cpu(cap.num_pcrs); |
756 | for (i = 0; i < num_pcrs; i++) { | 791 | for (i = 0; i < num_pcrs; i++) { |
757 | memcpy(data, pcrread, sizeof(pcrread)); | 792 | rc = __tpm_pcr_read(chip, i, digest); |
758 | index = cpu_to_be32(i); | ||
759 | memcpy(data + 10, &index, 4); | ||
760 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
761 | "attempting to read a PCR"); | ||
762 | if (rc) | 793 | if (rc) |
763 | goto out; | 794 | break; |
764 | str += sprintf(str, "PCR-%02d: ", i); | 795 | str += sprintf(str, "PCR-%02d: ", i); |
765 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | 796 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
766 | str += sprintf(str, "%02X ", *(data + 10 + j)); | 797 | str += sprintf(str, "%02X ", digest[j]); |
767 | str += sprintf(str, "\n"); | 798 | str += sprintf(str, "\n"); |
768 | } | 799 | } |
769 | out: | ||
770 | kfree(data); | ||
771 | return str - buf; | 800 | return str - buf; |
772 | } | 801 | } |
773 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); | 802 | EXPORT_SYMBOL_GPL(tpm_show_pcrs); |
774 | 803 | ||
775 | #define READ_PUBEK_RESULT_SIZE 314 | 804 | #define READ_PUBEK_RESULT_SIZE 314 |
776 | static const u8 readpubek[] = { | 805 | #define TPM_ORD_READPUBEK cpu_to_be32(124) |
777 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 806 | struct tpm_input_header tpm_readpubek_header = { |
778 | 0, 0, 0, 30, /* length */ | 807 | .tag = TPM_TAG_RQU_COMMAND, |
779 | 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ | 808 | .length = cpu_to_be32(30), |
809 | .ordinal = TPM_ORD_READPUBEK | ||
780 | }; | 810 | }; |
781 | 811 | ||
782 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | 812 | ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, |
783 | char *buf) | 813 | char *buf) |
784 | { | 814 | { |
785 | u8 *data; | 815 | u8 *data; |
816 | struct tpm_cmd_t tpm_cmd; | ||
786 | ssize_t err; | 817 | ssize_t err; |
787 | int i, rc; | 818 | int i, rc; |
788 | char *str = buf; | 819 | char *str = buf; |
789 | 820 | ||
790 | struct tpm_chip *chip = dev_get_drvdata(dev); | 821 | struct tpm_chip *chip = dev_get_drvdata(dev); |
791 | if (chip == NULL) | ||
792 | return -ENODEV; | ||
793 | 822 | ||
794 | data = kzalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); | 823 | tpm_cmd.header.in = tpm_readpubek_header; |
795 | if (!data) | 824 | err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, |
796 | return -ENOMEM; | ||
797 | |||
798 | memcpy(data, readpubek, sizeof(readpubek)); | ||
799 | |||
800 | err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, | ||
801 | "attempting to read the PUBEK"); | 825 | "attempting to read the PUBEK"); |
802 | if (err) | 826 | if (err) |
803 | goto out; | 827 | goto out; |
@@ -812,7 +836,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
812 | 256 byte modulus | 836 | 256 byte modulus |
813 | ignore checksum 20 bytes | 837 | ignore checksum 20 bytes |
814 | */ | 838 | */ |
815 | 839 | data = tpm_cmd.params.readpubek_out_buffer; | |
816 | str += | 840 | str += |
817 | sprintf(str, | 841 | sprintf(str, |
818 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" | 842 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" |
@@ -832,65 +856,33 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
832 | } | 856 | } |
833 | out: | 857 | out: |
834 | rc = str - buf; | 858 | rc = str - buf; |
835 | kfree(data); | ||
836 | return rc; | 859 | return rc; |
837 | } | 860 | } |
838 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | 861 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
839 | 862 | ||
840 | #define CAP_VERSION_1_1 6 | ||
841 | #define CAP_VERSION_1_2 0x1A | ||
842 | #define CAP_VERSION_IDX 13 | ||
843 | static const u8 cap_version[] = { | ||
844 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
845 | 0, 0, 0, 18, /* length */ | ||
846 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | ||
847 | 0, 0, 0, 0, | ||
848 | 0, 0, 0, 0 | ||
849 | }; | ||
850 | 863 | ||
851 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 864 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
852 | char *buf) | 865 | char *buf) |
853 | { | 866 | { |
854 | u8 *data; | 867 | cap_t cap; |
855 | ssize_t rc; | 868 | ssize_t rc; |
856 | char *str = buf; | 869 | char *str = buf; |
857 | 870 | ||
858 | struct tpm_chip *chip = dev_get_drvdata(dev); | 871 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, |
859 | if (chip == NULL) | ||
860 | return -ENODEV; | ||
861 | |||
862 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
863 | if (!data) | ||
864 | return -ENOMEM; | ||
865 | |||
866 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
867 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
868 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
869 | |||
870 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
871 | "attempting to determine the manufacturer"); | 872 | "attempting to determine the manufacturer"); |
872 | if (rc) { | 873 | if (rc) |
873 | kfree(data); | ||
874 | return 0; | 874 | return 0; |
875 | } | ||
876 | |||
877 | str += sprintf(str, "Manufacturer: 0x%x\n", | 875 | str += sprintf(str, "Manufacturer: 0x%x\n", |
878 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 876 | be32_to_cpu(cap.manufacturer_id)); |
879 | 877 | ||
880 | memcpy(data, cap_version, sizeof(cap_version)); | 878 | rc = tpm_getcap(dev, CAP_VERSION_1_1, &cap, |
881 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; | 879 | "attempting to determine the 1.1 version"); |
882 | rc = transmit_cmd(chip, data, TPM_INTERNAL_RESULT_SIZE, | ||
883 | "attempting to determine the 1.1 version"); | ||
884 | if (rc) | 880 | if (rc) |
885 | goto out; | 881 | return 0; |
886 | |||
887 | str += sprintf(str, | 882 | str += sprintf(str, |
888 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | 883 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
889 | (int) data[14], (int) data[15], (int) data[16], | 884 | cap.tpm_version.Major, cap.tpm_version.Minor, |
890 | (int) data[17]); | 885 | cap.tpm_version.revMajor, cap.tpm_version.revMinor); |
891 | |||
892 | out: | ||
893 | kfree(data); | ||
894 | return str - buf; | 886 | return str - buf; |
895 | } | 887 | } |
896 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 888 | EXPORT_SYMBOL_GPL(tpm_show_caps); |
@@ -898,51 +890,25 @@ EXPORT_SYMBOL_GPL(tpm_show_caps); | |||
898 | ssize_t tpm_show_caps_1_2(struct device * dev, | 890 | ssize_t tpm_show_caps_1_2(struct device * dev, |
899 | struct device_attribute * attr, char *buf) | 891 | struct device_attribute * attr, char *buf) |
900 | { | 892 | { |
901 | u8 *data; | 893 | cap_t cap; |
902 | ssize_t len; | 894 | ssize_t rc; |
903 | char *str = buf; | 895 | char *str = buf; |
904 | 896 | ||
905 | struct tpm_chip *chip = dev_get_drvdata(dev); | 897 | rc = tpm_getcap(dev, TPM_CAP_PROP_MANUFACTURER, &cap, |
906 | if (chip == NULL) | 898 | "attempting to determine the manufacturer"); |
907 | return -ENODEV; | 899 | if (rc) |
908 | |||
909 | data = kzalloc(TPM_INTERNAL_RESULT_SIZE, GFP_KERNEL); | ||
910 | if (!data) | ||
911 | return -ENOMEM; | ||
912 | |||
913 | memcpy(data, tpm_cap, sizeof(tpm_cap)); | ||
914 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
915 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
916 | |||
917 | len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); | ||
918 | if (len <= TPM_ERROR_SIZE) { | ||
919 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | ||
920 | "attempting to determine the manufacturer\n", | ||
921 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
922 | kfree(data); | ||
923 | return 0; | 900 | return 0; |
924 | } | ||
925 | |||
926 | str += sprintf(str, "Manufacturer: 0x%x\n", | 901 | str += sprintf(str, "Manufacturer: 0x%x\n", |
927 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); | 902 | be32_to_cpu(cap.manufacturer_id)); |
928 | 903 | rc = tpm_getcap(dev, CAP_VERSION_1_2, &cap, | |
929 | memcpy(data, cap_version, sizeof(cap_version)); | 904 | "attempting to determine the 1.2 version"); |
930 | data[CAP_VERSION_IDX] = CAP_VERSION_1_2; | 905 | if (rc) |
931 | 906 | return 0; | |
932 | len = tpm_transmit(chip, data, TPM_INTERNAL_RESULT_SIZE); | ||
933 | if (len <= TPM_ERROR_SIZE) { | ||
934 | dev_err(chip->dev, "A TPM error (%d) occurred " | ||
935 | "attempting to determine the 1.2 version\n", | ||
936 | be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX)))); | ||
937 | goto out; | ||
938 | } | ||
939 | str += sprintf(str, | 907 | str += sprintf(str, |
940 | "TCG version: %d.%d\nFirmware version: %d.%d\n", | 908 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
941 | (int) data[16], (int) data[17], (int) data[18], | 909 | cap.tpm_version_1_2.Major, cap.tpm_version_1_2.Minor, |
942 | (int) data[19]); | 910 | cap.tpm_version_1_2.revMajor, |
943 | 911 | cap.tpm_version_1_2.revMinor); | |
944 | out: | ||
945 | kfree(data); | ||
946 | return str - buf; | 912 | return str - buf; |
947 | } | 913 | } |
948 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | 914 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8e30df4a438..8e00b4ddd08 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/miscdevice.h> | 26 | #include <linux/miscdevice.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/tpm.h> | ||
29 | 30 | ||
30 | enum tpm_timeout { | 31 | enum tpm_timeout { |
31 | TPM_TIMEOUT = 5, /* msecs */ | 32 | TPM_TIMEOUT = 5, /* msecs */ |
@@ -123,6 +124,147 @@ static inline void tpm_write_index(int base, int index, int value) | |||
123 | outb(index, base); | 124 | outb(index, base); |
124 | outb(value & 0xFF, base+1); | 125 | outb(value & 0xFF, base+1); |
125 | } | 126 | } |
127 | struct tpm_input_header { | ||
128 | __be16 tag; | ||
129 | __be32 length; | ||
130 | __be32 ordinal; | ||
131 | }__attribute__((packed)); | ||
132 | |||
133 | struct tpm_output_header { | ||
134 | __be16 tag; | ||
135 | __be32 length; | ||
136 | __be32 return_code; | ||
137 | }__attribute__((packed)); | ||
138 | |||
139 | struct stclear_flags_t { | ||
140 | __be16 tag; | ||
141 | u8 deactivated; | ||
142 | u8 disableForceClear; | ||
143 | u8 physicalPresence; | ||
144 | u8 physicalPresenceLock; | ||
145 | u8 bGlobalLock; | ||
146 | }__attribute__((packed)); | ||
147 | |||
148 | struct tpm_version_t { | ||
149 | u8 Major; | ||
150 | u8 Minor; | ||
151 | u8 revMajor; | ||
152 | u8 revMinor; | ||
153 | }__attribute__((packed)); | ||
154 | |||
155 | struct tpm_version_1_2_t { | ||
156 | __be16 tag; | ||
157 | u8 Major; | ||
158 | u8 Minor; | ||
159 | u8 revMajor; | ||
160 | u8 revMinor; | ||
161 | }__attribute__((packed)); | ||
162 | |||
163 | struct timeout_t { | ||
164 | __be32 a; | ||
165 | __be32 b; | ||
166 | __be32 c; | ||
167 | __be32 d; | ||
168 | }__attribute__((packed)); | ||
169 | |||
170 | struct duration_t { | ||
171 | __be32 tpm_short; | ||
172 | __be32 tpm_medium; | ||
173 | __be32 tpm_long; | ||
174 | }__attribute__((packed)); | ||
175 | |||
176 | struct permanent_flags_t { | ||
177 | __be16 tag; | ||
178 | u8 disable; | ||
179 | u8 ownership; | ||
180 | u8 deactivated; | ||
181 | u8 readPubek; | ||
182 | u8 disableOwnerClear; | ||
183 | u8 allowMaintenance; | ||
184 | u8 physicalPresenceLifetimeLock; | ||
185 | u8 physicalPresenceHWEnable; | ||
186 | u8 physicalPresenceCMDEnable; | ||
187 | u8 CEKPUsed; | ||
188 | u8 TPMpost; | ||
189 | u8 TPMpostLock; | ||
190 | u8 FIPS; | ||
191 | u8 operator; | ||
192 | u8 enableRevokeEK; | ||
193 | u8 nvLocked; | ||
194 | u8 readSRKPub; | ||
195 | u8 tpmEstablished; | ||
196 | u8 maintenanceDone; | ||
197 | u8 disableFullDALogicInfo; | ||
198 | }__attribute__((packed)); | ||
199 | |||
200 | typedef union { | ||
201 | struct permanent_flags_t perm_flags; | ||
202 | struct stclear_flags_t stclear_flags; | ||
203 | bool owned; | ||
204 | __be32 num_pcrs; | ||
205 | struct tpm_version_t tpm_version; | ||
206 | struct tpm_version_1_2_t tpm_version_1_2; | ||
207 | __be32 manufacturer_id; | ||
208 | struct timeout_t timeout; | ||
209 | struct duration_t duration; | ||
210 | } cap_t; | ||
211 | |||
212 | struct tpm_getcap_params_in { | ||
213 | __be32 cap; | ||
214 | __be32 subcap_size; | ||
215 | __be32 subcap; | ||
216 | }__attribute__((packed)); | ||
217 | |||
218 | struct tpm_getcap_params_out { | ||
219 | __be32 cap_size; | ||
220 | cap_t cap; | ||
221 | }__attribute__((packed)); | ||
222 | |||
223 | struct tpm_readpubek_params_out { | ||
224 | u8 algorithm[4]; | ||
225 | u8 encscheme[2]; | ||
226 | u8 sigscheme[2]; | ||
227 | u8 parameters[12]; /*assuming RSA*/ | ||
228 | __be32 keysize; | ||
229 | u8 modulus[256]; | ||
230 | u8 checksum[20]; | ||
231 | }__attribute__((packed)); | ||
232 | |||
233 | typedef union { | ||
234 | struct tpm_input_header in; | ||
235 | struct tpm_output_header out; | ||
236 | } tpm_cmd_header; | ||
237 | |||
238 | #define TPM_DIGEST_SIZE 20 | ||
239 | struct tpm_pcrread_out { | ||
240 | u8 pcr_result[TPM_DIGEST_SIZE]; | ||
241 | }__attribute__((packed)); | ||
242 | |||
243 | struct tpm_pcrread_in { | ||
244 | __be32 pcr_idx; | ||
245 | }__attribute__((packed)); | ||
246 | |||
247 | struct tpm_pcrextend_in { | ||
248 | __be32 pcr_idx; | ||
249 | u8 hash[TPM_DIGEST_SIZE]; | ||
250 | }__attribute__((packed)); | ||
251 | |||
252 | typedef union { | ||
253 | struct tpm_getcap_params_out getcap_out; | ||
254 | struct tpm_readpubek_params_out readpubek_out; | ||
255 | u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)]; | ||
256 | struct tpm_getcap_params_in getcap_in; | ||
257 | struct tpm_pcrread_in pcrread_in; | ||
258 | struct tpm_pcrread_out pcrread_out; | ||
259 | struct tpm_pcrextend_in pcrextend_in; | ||
260 | } tpm_cmd_params; | ||
261 | |||
262 | struct tpm_cmd_t { | ||
263 | tpm_cmd_header header; | ||
264 | tpm_cmd_params params; | ||
265 | }__attribute__((packed)); | ||
266 | |||
267 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); | ||
126 | 268 | ||
127 | extern void tpm_get_timeouts(struct tpm_chip *); | 269 | extern void tpm_get_timeouts(struct tpm_chip *); |
128 | extern void tpm_gen_interrupt(struct tpm_chip *); | 270 | extern void tpm_gen_interrupt(struct tpm_chip *); |
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/proc_fs.h> | 45 | #include <linux/proc_fs.h> |
46 | #include <linux/mount.h> | 46 | #include <linux/mount.h> |
47 | #include <linux/security.h> | 47 | #include <linux/security.h> |
48 | #include <linux/ima.h> | ||
48 | #include <linux/syscalls.h> | 49 | #include <linux/syscalls.h> |
49 | #include <linux/tsacct_kern.h> | 50 | #include <linux/tsacct_kern.h> |
50 | #include <linux/cn_proc.h> | 51 | #include <linux/cn_proc.h> |
@@ -127,6 +128,9 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) | |||
127 | MAY_READ | MAY_EXEC | MAY_OPEN); | 128 | MAY_READ | MAY_EXEC | MAY_OPEN); |
128 | if (error) | 129 | if (error) |
129 | goto exit; | 130 | goto exit; |
131 | error = ima_path_check(&nd.path, MAY_READ | MAY_EXEC | MAY_OPEN); | ||
132 | if (error) | ||
133 | goto exit; | ||
130 | 134 | ||
131 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); | 135 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); |
132 | error = PTR_ERR(file); | 136 | error = PTR_ERR(file); |
@@ -674,6 +678,9 @@ struct file *open_exec(const char *name) | |||
674 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); | 678 | err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN); |
675 | if (err) | 679 | if (err) |
676 | goto out_path_put; | 680 | goto out_path_put; |
681 | err = ima_path_check(&nd.path, MAY_EXEC | MAY_OPEN); | ||
682 | if (err) | ||
683 | goto out_path_put; | ||
677 | 684 | ||
678 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); | 685 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); |
679 | if (IS_ERR(file)) | 686 | if (IS_ERR(file)) |
@@ -1168,6 +1175,9 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
1168 | retval = security_bprm_check(bprm); | 1175 | retval = security_bprm_check(bprm); |
1169 | if (retval) | 1176 | if (retval) |
1170 | return retval; | 1177 | return retval; |
1178 | retval = ima_bprm_check(bprm); | ||
1179 | if (retval) | ||
1180 | return retval; | ||
1171 | 1181 | ||
1172 | /* kernel module loader fixup */ | 1182 | /* kernel module loader fixup */ |
1173 | /* so we don't try to load run modprobe in kernel space. */ | 1183 | /* so we don't try to load run modprobe in kernel space. */ |
diff --git a/fs/file_table.c b/fs/file_table.c index bbeeac6efa1..da806aceae3 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/security.h> | 15 | #include <linux/security.h> |
16 | #include <linux/ima.h> | ||
16 | #include <linux/eventpoll.h> | 17 | #include <linux/eventpoll.h> |
17 | #include <linux/rcupdate.h> | 18 | #include <linux/rcupdate.h> |
18 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
@@ -279,6 +280,7 @@ void __fput(struct file *file) | |||
279 | if (file->f_op && file->f_op->release) | 280 | if (file->f_op && file->f_op->release) |
280 | file->f_op->release(inode, file); | 281 | file->f_op->release(inode, file); |
281 | security_file_free(file); | 282 | security_file_free(file); |
283 | ima_file_free(file); | ||
282 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) | 284 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) |
283 | cdev_put(inode->i_cdev); | 285 | cdev_put(inode->i_cdev); |
284 | fops_put(file->f_op); | 286 | fops_put(file->f_op); |
diff --git a/fs/inode.c b/fs/inode.c index 913ab2d9a5d..40e37c02656 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/hash.h> | 17 | #include <linux/hash.h> |
18 | #include <linux/swap.h> | 18 | #include <linux/swap.h> |
19 | #include <linux/security.h> | 19 | #include <linux/security.h> |
20 | #include <linux/ima.h> | ||
20 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
21 | #include <linux/cdev.h> | 22 | #include <linux/cdev.h> |
22 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
@@ -147,13 +148,13 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
147 | inode->i_cdev = NULL; | 148 | inode->i_cdev = NULL; |
148 | inode->i_rdev = 0; | 149 | inode->i_rdev = 0; |
149 | inode->dirtied_when = 0; | 150 | inode->dirtied_when = 0; |
150 | if (security_inode_alloc(inode)) { | 151 | |
151 | if (inode->i_sb->s_op->destroy_inode) | 152 | if (security_inode_alloc(inode)) |
152 | inode->i_sb->s_op->destroy_inode(inode); | 153 | goto out_free_inode; |
153 | else | 154 | |
154 | kmem_cache_free(inode_cachep, (inode)); | 155 | /* allocate and initialize an i_integrity */ |
155 | return NULL; | 156 | if (ima_inode_alloc(inode)) |
156 | } | 157 | goto out_free_security; |
157 | 158 | ||
158 | spin_lock_init(&inode->i_lock); | 159 | spin_lock_init(&inode->i_lock); |
159 | lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); | 160 | lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); |
@@ -189,6 +190,15 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
189 | inode->i_mapping = mapping; | 190 | inode->i_mapping = mapping; |
190 | 191 | ||
191 | return inode; | 192 | return inode; |
193 | |||
194 | out_free_security: | ||
195 | security_inode_free(inode); | ||
196 | out_free_inode: | ||
197 | if (inode->i_sb->s_op->destroy_inode) | ||
198 | inode->i_sb->s_op->destroy_inode(inode); | ||
199 | else | ||
200 | kmem_cache_free(inode_cachep, (inode)); | ||
201 | return NULL; | ||
192 | } | 202 | } |
193 | EXPORT_SYMBOL(inode_init_always); | 203 | EXPORT_SYMBOL(inode_init_always); |
194 | 204 | ||
diff --git a/fs/namei.c b/fs/namei.c index bbc15c23755..199317642ad 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/fsnotify.h> | 24 | #include <linux/fsnotify.h> |
25 | #include <linux/personality.h> | 25 | #include <linux/personality.h> |
26 | #include <linux/security.h> | 26 | #include <linux/security.h> |
27 | #include <linux/ima.h> | ||
27 | #include <linux/syscalls.h> | 28 | #include <linux/syscalls.h> |
28 | #include <linux/mount.h> | 29 | #include <linux/mount.h> |
29 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
@@ -850,6 +851,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd) | |||
850 | if (err == -EAGAIN) | 851 | if (err == -EAGAIN) |
851 | err = inode_permission(nd->path.dentry->d_inode, | 852 | err = inode_permission(nd->path.dentry->d_inode, |
852 | MAY_EXEC); | 853 | MAY_EXEC); |
854 | if (!err) | ||
855 | err = ima_path_check(&nd->path, MAY_EXEC); | ||
853 | if (err) | 856 | if (err) |
854 | break; | 857 | break; |
855 | 858 | ||
@@ -1509,6 +1512,11 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
1509 | error = inode_permission(inode, acc_mode); | 1512 | error = inode_permission(inode, acc_mode); |
1510 | if (error) | 1513 | if (error) |
1511 | return error; | 1514 | return error; |
1515 | |||
1516 | error = ima_path_check(path, | ||
1517 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
1518 | if (error) | ||
1519 | return error; | ||
1512 | /* | 1520 | /* |
1513 | * An append-only file must be opened in append mode for writing. | 1521 | * An append-only file must be opened in append mode for writing. |
1514 | */ | 1522 | */ |
diff --git a/include/linux/audit.h b/include/linux/audit.h index 67e5dbfc296..930939abfbc 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h | |||
@@ -125,6 +125,11 @@ | |||
125 | #define AUDIT_LAST_KERN_ANOM_MSG 1799 | 125 | #define AUDIT_LAST_KERN_ANOM_MSG 1799 |
126 | #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ | 126 | #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ |
127 | #define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */ | 127 | #define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */ |
128 | #define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */ | ||
129 | #define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */ | ||
130 | #define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */ | ||
131 | #define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */ | ||
132 | #define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */ | ||
128 | 133 | ||
129 | #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ | 134 | #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ |
130 | 135 | ||
diff --git a/include/linux/ima.h b/include/linux/ima.h new file mode 100644 index 00000000000..6db30a328d9 --- /dev/null +++ b/include/linux/ima.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, version 2 of the License. | ||
8 | */ | ||
9 | |||
10 | #include <linux/fs.h> | ||
11 | |||
12 | #ifndef _LINUX_IMA_H | ||
13 | #define _LINUX_IMA_H | ||
14 | |||
15 | #ifdef CONFIG_IMA | ||
16 | extern int ima_bprm_check(struct linux_binprm *bprm); | ||
17 | extern int ima_inode_alloc(struct inode *inode); | ||
18 | extern void ima_inode_free(struct inode *inode); | ||
19 | extern int ima_path_check(struct path *path, int mask); | ||
20 | extern void ima_file_free(struct file *file); | ||
21 | extern int ima_file_mmap(struct file *file, unsigned long prot); | ||
22 | extern void ima_shm_check(struct file *file); | ||
23 | |||
24 | #else | ||
25 | static inline int ima_bprm_check(struct linux_binprm *bprm) | ||
26 | { | ||
27 | return 0; | ||
28 | } | ||
29 | |||
30 | static inline int ima_inode_alloc(struct inode *inode) | ||
31 | { | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static inline void ima_inode_free(struct inode *inode) | ||
36 | { | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | static inline int ima_path_check(struct path *path, int mask) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static inline void ima_file_free(struct file *file) | ||
46 | { | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | static inline int ima_file_mmap(struct file *file, unsigned long prot) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static inline void ima_shm_check(struct file *file) | ||
56 | { | ||
57 | return; | ||
58 | } | ||
59 | #endif /* CONFIG_IMA_H */ | ||
60 | #endif /* _LINUX_IMA_H */ | ||
diff --git a/include/linux/tpm.h b/include/linux/tpm.h new file mode 100644 index 00000000000..3338b3f5c21 --- /dev/null +++ b/include/linux/tpm.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Leendert van Doorn <leendert@watson.ibm.com> | ||
6 | * Dave Safford <safford@watson.ibm.com> | ||
7 | * Reiner Sailer <sailer@watson.ibm.com> | ||
8 | * Kylene Hall <kjhall@us.ibm.com> | ||
9 | * Debora Velarde <dvelarde@us.ibm.com> | ||
10 | * | ||
11 | * Maintained by: <tpmdd_devel@lists.sourceforge.net> | ||
12 | * | ||
13 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
14 | * Specifications at www.trustedcomputinggroup.org | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License as | ||
18 | * published by the Free Software Foundation, version 2 of the | ||
19 | * License. | ||
20 | * | ||
21 | */ | ||
22 | #ifndef __LINUX_TPM_H__ | ||
23 | #define __LINUX_TPM_H__ | ||
24 | |||
25 | /* | ||
26 | * Chip num is this value or a valid tpm idx | ||
27 | */ | ||
28 | #define TPM_ANY_NUM 0xFFFF | ||
29 | |||
30 | #if defined(CONFIG_TCG_TPM) | ||
31 | |||
32 | extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); | ||
33 | extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); | ||
34 | #endif | ||
35 | #endif | ||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/nsproxy.h> | 39 | #include <linux/nsproxy.h> |
40 | #include <linux/mount.h> | 40 | #include <linux/mount.h> |
41 | #include <linux/ipc_namespace.h> | 41 | #include <linux/ipc_namespace.h> |
42 | #include <linux/ima.h> | ||
42 | 43 | ||
43 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
44 | 45 | ||
@@ -381,6 +382,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) | |||
381 | error = PTR_ERR(file); | 382 | error = PTR_ERR(file); |
382 | if (IS_ERR(file)) | 383 | if (IS_ERR(file)) |
383 | goto no_file; | 384 | goto no_file; |
385 | ima_shm_check(file); | ||
384 | 386 | ||
385 | id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); | 387 | id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); |
386 | if (id < 0) { | 388 | if (id < 0) { |
@@ -885,6 +887,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
885 | file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); | 887 | file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); |
886 | if (!file) | 888 | if (!file) |
887 | goto out_free; | 889 | goto out_free; |
890 | ima_shm_check(file); | ||
888 | 891 | ||
889 | file->private_data = sfd; | 892 | file->private_data = sfd; |
890 | file->f_mapping = shp->shm_file->f_mapping; | 893 | file->f_mapping = shp->shm_file->f_mapping; |
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/personality.h> | 21 | #include <linux/personality.h> |
22 | #include <linux/security.h> | 22 | #include <linux/security.h> |
23 | #include <linux/ima.h> | ||
23 | #include <linux/hugetlb.h> | 24 | #include <linux/hugetlb.h> |
24 | #include <linux/profile.h> | 25 | #include <linux/profile.h> |
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -1052,6 +1053,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, | |||
1052 | error = security_file_mmap(file, reqprot, prot, flags, addr, 0); | 1053 | error = security_file_mmap(file, reqprot, prot, flags, addr, 0); |
1053 | if (error) | 1054 | if (error) |
1054 | return error; | 1055 | return error; |
1056 | error = ima_file_mmap(file, prot); | ||
1057 | if (error) | ||
1058 | return error; | ||
1055 | 1059 | ||
1056 | return mmap_region(file, addr, len, flags, vm_flags, pgoff, | 1060 | return mmap_region(file, addr, len, flags, vm_flags, pgoff, |
1057 | accountable); | 1061 | accountable); |
diff --git a/mm/shmem.c b/mm/shmem.c index 19d566ccdee..75199888a6b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -59,6 +59,7 @@ static struct vfsmount *shm_mnt; | |||
59 | #include <linux/highmem.h> | 59 | #include <linux/highmem.h> |
60 | #include <linux/seq_file.h> | 60 | #include <linux/seq_file.h> |
61 | #include <linux/magic.h> | 61 | #include <linux/magic.h> |
62 | #include <linux/ima.h> | ||
62 | 63 | ||
63 | #include <asm/uaccess.h> | 64 | #include <asm/uaccess.h> |
64 | #include <asm/div64.h> | 65 | #include <asm/div64.h> |
@@ -2666,6 +2667,7 @@ int shmem_zero_setup(struct vm_area_struct *vma) | |||
2666 | if (IS_ERR(file)) | 2667 | if (IS_ERR(file)) |
2667 | return PTR_ERR(file); | 2668 | return PTR_ERR(file); |
2668 | 2669 | ||
2670 | ima_shm_check(file); | ||
2669 | if (vma->vm_file) | 2671 | if (vma->vm_file) |
2670 | fput(vma->vm_file); | 2672 | fput(vma->vm_file); |
2671 | vma->vm_file = file; | 2673 | vma->vm_file = file; |
diff --git a/security/Kconfig b/security/Kconfig index 9438535d7fd..bf129f87de7 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -55,7 +55,8 @@ config SECURITYFS | |||
55 | bool "Enable the securityfs filesystem" | 55 | bool "Enable the securityfs filesystem" |
56 | help | 56 | help |
57 | This will build the securityfs filesystem. It is currently used by | 57 | This will build the securityfs filesystem. It is currently used by |
58 | the TPM bios character driver. It is not used by SELinux or SMACK. | 58 | the TPM bios character driver and IMA, an integrity provider. It is |
59 | not used by SELinux or SMACK. | ||
59 | 60 | ||
60 | If you are unsure how to answer this question, answer N. | 61 | If you are unsure how to answer this question, answer N. |
61 | 62 | ||
@@ -135,5 +136,7 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR | |||
135 | source security/selinux/Kconfig | 136 | source security/selinux/Kconfig |
136 | source security/smack/Kconfig | 137 | source security/smack/Kconfig |
137 | 138 | ||
139 | source security/integrity/ima/Kconfig | ||
140 | |||
138 | endmenu | 141 | endmenu |
139 | 142 | ||
diff --git a/security/Makefile b/security/Makefile index c05c127fff9..595536cbffb 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -17,3 +17,7 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | |||
17 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o | 17 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o |
18 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o | 18 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o |
19 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 19 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
20 | |||
21 | # Object integrity file lists | ||
22 | subdir-$(CONFIG_IMA) += integrity/ima | ||
23 | obj-$(CONFIG_IMA) += integrity/ima/built-in.o | ||
diff --git a/security/inode.c b/security/inode.c index 007ef252dde..f3b91bfbe4c 100644 --- a/security/inode.c +++ b/security/inode.c | |||
@@ -202,12 +202,11 @@ static int create_by_name(const char *name, mode_t mode, | |||
202 | * This function returns a pointer to a dentry if it succeeds. This | 202 | * This function returns a pointer to a dentry if it succeeds. This |
203 | * pointer must be passed to the securityfs_remove() function when the file is | 203 | * pointer must be passed to the securityfs_remove() function when the file is |
204 | * to be removed (no automatic cleanup happens if your module is unloaded, | 204 | * to be removed (no automatic cleanup happens if your module is unloaded, |
205 | * you are responsible here). If an error occurs, %NULL is returned. | 205 | * you are responsible here). If an error occurs, the function will return |
206 | * the erorr value (via ERR_PTR). | ||
206 | * | 207 | * |
207 | * If securityfs is not enabled in the kernel, the value %-ENODEV is | 208 | * If securityfs is not enabled in the kernel, the value %-ENODEV is |
208 | * returned. It is not wise to check for this value, but rather, check for | 209 | * returned. |
209 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | ||
210 | * code. | ||
211 | */ | 210 | */ |
212 | struct dentry *securityfs_create_file(const char *name, mode_t mode, | 211 | struct dentry *securityfs_create_file(const char *name, mode_t mode, |
213 | struct dentry *parent, void *data, | 212 | struct dentry *parent, void *data, |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig new file mode 100644 index 00000000000..3d2b6ee778a --- /dev/null +++ b/security/integrity/ima/Kconfig | |||
@@ -0,0 +1,55 @@ | |||
1 | # IBM Integrity Measurement Architecture | ||
2 | # | ||
3 | config IMA | ||
4 | bool "Integrity Measurement Architecture(IMA)" | ||
5 | depends on ACPI | ||
6 | select SECURITYFS | ||
7 | select CRYPTO | ||
8 | select CRYPTO_HMAC | ||
9 | select CRYPTO_MD5 | ||
10 | select CRYPTO_SHA1 | ||
11 | select TCG_TPM | ||
12 | select TCG_TIS | ||
13 | help | ||
14 | The Trusted Computing Group(TCG) runtime Integrity | ||
15 | Measurement Architecture(IMA) maintains a list of hash | ||
16 | values of executables and other sensitive system files, | ||
17 | as they are read or executed. If an attacker manages | ||
18 | to change the contents of an important system file | ||
19 | being measured, we can tell. | ||
20 | |||
21 | If your system has a TPM chip, then IMA also maintains | ||
22 | an aggregate integrity value over this list inside the | ||
23 | TPM hardware, so that the TPM can prove to a third party | ||
24 | whether or not critical system files have been modified. | ||
25 | Read <http://www.usenix.org/events/sec04/tech/sailer.html> | ||
26 | to learn more about IMA. | ||
27 | If unsure, say N. | ||
28 | |||
29 | config IMA_MEASURE_PCR_IDX | ||
30 | int | ||
31 | depends on IMA | ||
32 | range 8 14 | ||
33 | default 10 | ||
34 | help | ||
35 | IMA_MEASURE_PCR_IDX determines the TPM PCR register index | ||
36 | that IMA uses to maintain the integrity aggregate of the | ||
37 | measurement list. If unsure, use the default 10. | ||
38 | |||
39 | config IMA_AUDIT | ||
40 | bool | ||
41 | depends on IMA | ||
42 | default y | ||
43 | help | ||
44 | This option adds a kernel parameter 'ima_audit', which | ||
45 | allows informational auditing messages to be enabled | ||
46 | at boot. If this option is selected, informational integrity | ||
47 | auditing messages can be enabled with 'ima_audit=1' on | ||
48 | the kernel command line. | ||
49 | |||
50 | config IMA_LSM_RULES | ||
51 | bool | ||
52 | depends on IMA && (SECURITY_SELINUX || SECURITY_SMACK) | ||
53 | default y | ||
54 | help | ||
55 | Disabling this option will disregard LSM based policy rules | ||
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile new file mode 100644 index 00000000000..787c4cb916c --- /dev/null +++ b/security/integrity/ima/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for building Trusted Computing Group's(TCG) runtime Integrity | ||
3 | # Measurement Architecture(IMA). | ||
4 | # | ||
5 | |||
6 | obj-$(CONFIG_IMA) += ima.o | ||
7 | |||
8 | ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ | ||
9 | ima_policy.o ima_iint.o ima_audit.o | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h new file mode 100644 index 00000000000..e3c16a21a38 --- /dev/null +++ b/security/integrity/ima/ima.h | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Reiner Sailer <sailer@watson.ibm.com> | ||
6 | * Mimi Zohar <zohar@us.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation, version 2 of the | ||
11 | * License. | ||
12 | * | ||
13 | * File: ima.h | ||
14 | * internal Integrity Measurement Architecture (IMA) definitions | ||
15 | */ | ||
16 | |||
17 | #ifndef __LINUX_IMA_H | ||
18 | #define __LINUX_IMA_H | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/crypto.h> | ||
22 | #include <linux/security.h> | ||
23 | #include <linux/hash.h> | ||
24 | #include <linux/tpm.h> | ||
25 | #include <linux/audit.h> | ||
26 | |||
27 | enum ima_show_type { IMA_SHOW_BINARY, IMA_SHOW_ASCII }; | ||
28 | enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; | ||
29 | |||
30 | /* digest size for IMA, fits SHA1 or MD5 */ | ||
31 | #define IMA_DIGEST_SIZE 20 | ||
32 | #define IMA_EVENT_NAME_LEN_MAX 255 | ||
33 | |||
34 | #define IMA_HASH_BITS 9 | ||
35 | #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS) | ||
36 | |||
37 | /* set during initialization */ | ||
38 | extern int ima_initialized; | ||
39 | extern int ima_used_chip; | ||
40 | extern char *ima_hash; | ||
41 | |||
42 | /* IMA inode template definition */ | ||
43 | struct ima_template_data { | ||
44 | u8 digest[IMA_DIGEST_SIZE]; /* sha1/md5 measurement hash */ | ||
45 | char file_name[IMA_EVENT_NAME_LEN_MAX + 1]; /* name + \0 */ | ||
46 | }; | ||
47 | |||
48 | struct ima_template_entry { | ||
49 | u8 digest[IMA_DIGEST_SIZE]; /* sha1 or md5 measurement hash */ | ||
50 | char *template_name; | ||
51 | int template_len; | ||
52 | struct ima_template_data template; | ||
53 | }; | ||
54 | |||
55 | struct ima_queue_entry { | ||
56 | struct hlist_node hnext; /* place in hash collision list */ | ||
57 | struct list_head later; /* place in ima_measurements list */ | ||
58 | struct ima_template_entry *entry; | ||
59 | }; | ||
60 | extern struct list_head ima_measurements; /* list of all measurements */ | ||
61 | |||
62 | /* declarations */ | ||
63 | void integrity_audit_msg(int audit_msgno, struct inode *inode, | ||
64 | const unsigned char *fname, const char *op, | ||
65 | const char *cause, int result, int info); | ||
66 | |||
67 | /* Internal IMA function definitions */ | ||
68 | void ima_iintcache_init(void); | ||
69 | int ima_init(void); | ||
70 | void ima_cleanup(void); | ||
71 | int ima_fs_init(void); | ||
72 | void ima_fs_cleanup(void); | ||
73 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | ||
74 | const char *op, struct inode *inode); | ||
75 | int ima_calc_hash(struct file *file, char *digest); | ||
76 | int ima_calc_template_hash(int template_len, void *template, char *digest); | ||
77 | int ima_calc_boot_aggregate(char *digest); | ||
78 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | ||
79 | const char *op, const char *cause); | ||
80 | |||
81 | /* | ||
82 | * used to protect h_table and sha_table | ||
83 | */ | ||
84 | extern spinlock_t ima_queue_lock; | ||
85 | |||
86 | struct ima_h_table { | ||
87 | atomic_long_t len; /* number of stored measurements in the list */ | ||
88 | atomic_long_t violations; | ||
89 | struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; | ||
90 | }; | ||
91 | extern struct ima_h_table ima_htable; | ||
92 | |||
93 | static inline unsigned long ima_hash_key(u8 *digest) | ||
94 | { | ||
95 | return hash_long(*digest, IMA_HASH_BITS); | ||
96 | } | ||
97 | |||
98 | /* iint cache flags */ | ||
99 | #define IMA_MEASURED 1 | ||
100 | #define IMA_IINT_DUMP_STACK 512 | ||
101 | |||
102 | /* integrity data associated with an inode */ | ||
103 | struct ima_iint_cache { | ||
104 | u64 version; /* track inode changes */ | ||
105 | unsigned long flags; | ||
106 | u8 digest[IMA_DIGEST_SIZE]; | ||
107 | struct mutex mutex; /* protects: version, flags, digest */ | ||
108 | long readcount; /* measured files readcount */ | ||
109 | long writecount; /* measured files writecount */ | ||
110 | long opencount; /* opens reference count */ | ||
111 | struct kref refcount; /* ima_iint_cache reference count */ | ||
112 | struct rcu_head rcu; | ||
113 | }; | ||
114 | |||
115 | /* LIM API function definitions */ | ||
116 | int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | ||
117 | int mask, int function); | ||
118 | int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file); | ||
119 | void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, | ||
120 | const unsigned char *filename); | ||
121 | int ima_store_template(struct ima_template_entry *entry, int violation, | ||
122 | struct inode *inode); | ||
123 | void ima_template_show(struct seq_file *m, void *e, | ||
124 | enum ima_show_type show); | ||
125 | |||
126 | /* radix tree calls to lookup, insert, delete | ||
127 | * integrity data associated with an inode. | ||
128 | */ | ||
129 | struct ima_iint_cache *ima_iint_insert(struct inode *inode); | ||
130 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode); | ||
131 | struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode); | ||
132 | void ima_iint_delete(struct inode *inode); | ||
133 | void iint_free(struct kref *kref); | ||
134 | void iint_rcu_free(struct rcu_head *rcu); | ||
135 | |||
136 | /* IMA policy related functions */ | ||
137 | enum ima_hooks { PATH_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | ||
138 | |||
139 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | ||
140 | void ima_init_policy(void); | ||
141 | void ima_update_policy(void); | ||
142 | int ima_parse_add_rule(char *); | ||
143 | void ima_delete_rules(void); | ||
144 | |||
145 | /* LSM based policy rules require audit */ | ||
146 | #ifdef CONFIG_IMA_LSM_RULES | ||
147 | |||
148 | #define security_filter_rule_init security_audit_rule_init | ||
149 | #define security_filter_rule_match security_audit_rule_match | ||
150 | |||
151 | #else | ||
152 | |||
153 | static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr, | ||
154 | void **lsmrule) | ||
155 | { | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | |||
159 | static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, | ||
160 | void *lsmrule, | ||
161 | struct audit_context *actx) | ||
162 | { | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | #endif /* CONFIG_IMA_LSM_RULES */ | ||
166 | #endif | ||
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c new file mode 100644 index 00000000000..a148a25804f --- /dev/null +++ b/security/integrity/ima/ima_api.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * | ||
4 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2 of the | ||
9 | * License. | ||
10 | * | ||
11 | * File: ima_api.c | ||
12 | * Implements must_measure, collect_measurement, store_measurement, | ||
13 | * and store_template. | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | #include "ima.h" | ||
18 | static char *IMA_TEMPLATE_NAME = "ima"; | ||
19 | |||
20 | /* | ||
21 | * ima_store_template - store ima template measurements | ||
22 | * | ||
23 | * Calculate the hash of a template entry, add the template entry | ||
24 | * to an ordered list of measurement entries maintained inside the kernel, | ||
25 | * and also update the aggregate integrity value (maintained inside the | ||
26 | * configured TPM PCR) over the hashes of the current list of measurement | ||
27 | * entries. | ||
28 | * | ||
29 | * Applications retrieve the current kernel-held measurement list through | ||
30 | * the securityfs entries in /sys/kernel/security/ima. The signed aggregate | ||
31 | * TPM PCR (called quote) can be retrieved using a TPM user space library | ||
32 | * and is used to validate the measurement list. | ||
33 | * | ||
34 | * Returns 0 on success, error code otherwise | ||
35 | */ | ||
36 | int ima_store_template(struct ima_template_entry *entry, | ||
37 | int violation, struct inode *inode) | ||
38 | { | ||
39 | const char *op = "add_template_measure"; | ||
40 | const char *audit_cause = "hashing_error"; | ||
41 | int result; | ||
42 | |||
43 | memset(entry->digest, 0, sizeof(entry->digest)); | ||
44 | entry->template_name = IMA_TEMPLATE_NAME; | ||
45 | entry->template_len = sizeof(entry->template); | ||
46 | |||
47 | if (!violation) { | ||
48 | result = ima_calc_template_hash(entry->template_len, | ||
49 | &entry->template, | ||
50 | entry->digest); | ||
51 | if (result < 0) { | ||
52 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, | ||
53 | entry->template_name, op, | ||
54 | audit_cause, result, 0); | ||
55 | return result; | ||
56 | } | ||
57 | } | ||
58 | result = ima_add_template_entry(entry, violation, op, inode); | ||
59 | return result; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * ima_add_violation - add violation to measurement list. | ||
64 | * | ||
65 | * Violations are flagged in the measurement list with zero hash values. | ||
66 | * By extending the PCR with 0xFF's instead of with zeroes, the PCR | ||
67 | * value is invalidated. | ||
68 | */ | ||
69 | void ima_add_violation(struct inode *inode, const unsigned char *filename, | ||
70 | const char *op, const char *cause) | ||
71 | { | ||
72 | struct ima_template_entry *entry; | ||
73 | int violation = 1; | ||
74 | int result; | ||
75 | |||
76 | /* can overflow, only indicator */ | ||
77 | atomic_long_inc(&ima_htable.violations); | ||
78 | |||
79 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
80 | if (!entry) { | ||
81 | result = -ENOMEM; | ||
82 | goto err_out; | ||
83 | } | ||
84 | memset(&entry->template, 0, sizeof(entry->template)); | ||
85 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
86 | result = ima_store_template(entry, violation, inode); | ||
87 | if (result < 0) | ||
88 | kfree(entry); | ||
89 | err_out: | ||
90 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | ||
91 | op, cause, result, 0); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * ima_must_measure - measure decision based on policy. | ||
96 | * @inode: pointer to inode to measure | ||
97 | * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) | ||
98 | * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP) | ||
99 | * | ||
100 | * The policy is defined in terms of keypairs: | ||
101 | * subj=, obj=, type=, func=, mask=, fsmagic= | ||
102 | * subj,obj, and type: are LSM specific. | ||
103 | * func: PATH_CHECK | BPRM_CHECK | FILE_MMAP | ||
104 | * mask: contains the permission mask | ||
105 | * fsmagic: hex value | ||
106 | * | ||
107 | * Must be called with iint->mutex held. | ||
108 | * | ||
109 | * Return 0 to measure. Return 1 if already measured. | ||
110 | * For matching a DONT_MEASURE policy, no policy, or other | ||
111 | * error, return an error code. | ||
112 | */ | ||
113 | int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode, | ||
114 | int mask, int function) | ||
115 | { | ||
116 | int must_measure; | ||
117 | |||
118 | if (iint->flags & IMA_MEASURED) | ||
119 | return 1; | ||
120 | |||
121 | must_measure = ima_match_policy(inode, function, mask); | ||
122 | return must_measure ? 0 : -EACCES; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * ima_collect_measurement - collect file measurement | ||
127 | * | ||
128 | * Calculate the file hash, if it doesn't already exist, | ||
129 | * storing the measurement and i_version in the iint. | ||
130 | * | ||
131 | * Must be called with iint->mutex held. | ||
132 | * | ||
133 | * Return 0 on success, error code otherwise | ||
134 | */ | ||
135 | int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file) | ||
136 | { | ||
137 | int result = -EEXIST; | ||
138 | |||
139 | if (!(iint->flags & IMA_MEASURED)) { | ||
140 | u64 i_version = file->f_dentry->d_inode->i_version; | ||
141 | |||
142 | memset(iint->digest, 0, IMA_DIGEST_SIZE); | ||
143 | result = ima_calc_hash(file, iint->digest); | ||
144 | if (!result) | ||
145 | iint->version = i_version; | ||
146 | } | ||
147 | return result; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * ima_store_measurement - store file measurement | ||
152 | * | ||
153 | * Create an "ima" template and then store the template by calling | ||
154 | * ima_store_template. | ||
155 | * | ||
156 | * We only get here if the inode has not already been measured, | ||
157 | * but the measurement could already exist: | ||
158 | * - multiple copies of the same file on either the same or | ||
159 | * different filesystems. | ||
160 | * - the inode was previously flushed as well as the iint info, | ||
161 | * containing the hashing info. | ||
162 | * | ||
163 | * Must be called with iint->mutex held. | ||
164 | */ | ||
165 | void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, | ||
166 | const unsigned char *filename) | ||
167 | { | ||
168 | const char *op = "add_template_measure"; | ||
169 | const char *audit_cause = "ENOMEM"; | ||
170 | int result = -ENOMEM; | ||
171 | struct inode *inode = file->f_dentry->d_inode; | ||
172 | struct ima_template_entry *entry; | ||
173 | int violation = 0; | ||
174 | |||
175 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
176 | if (!entry) { | ||
177 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename, | ||
178 | op, audit_cause, result, 0); | ||
179 | return; | ||
180 | } | ||
181 | memset(&entry->template, 0, sizeof(entry->template)); | ||
182 | memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE); | ||
183 | strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); | ||
184 | |||
185 | result = ima_store_template(entry, violation, inode); | ||
186 | if (!result) | ||
187 | iint->flags |= IMA_MEASURED; | ||
188 | else | ||
189 | kfree(entry); | ||
190 | } | ||
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c new file mode 100644 index 00000000000..8a0f1e23ccf --- /dev/null +++ b/security/integrity/ima/ima_audit.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, version 2 of the License. | ||
8 | * | ||
9 | * File: integrity_audit.c | ||
10 | * Audit calls for the integrity subsystem | ||
11 | */ | ||
12 | |||
13 | #include <linux/fs.h> | ||
14 | #include <linux/audit.h> | ||
15 | #include "ima.h" | ||
16 | |||
17 | static int ima_audit; | ||
18 | |||
19 | #ifdef CONFIG_IMA_AUDIT | ||
20 | |||
21 | /* ima_audit_setup - enable informational auditing messages */ | ||
22 | static int __init ima_audit_setup(char *str) | ||
23 | { | ||
24 | unsigned long audit; | ||
25 | int rc; | ||
26 | char *op; | ||
27 | |||
28 | rc = strict_strtoul(str, 0, &audit); | ||
29 | if (rc || audit > 1) | ||
30 | printk(KERN_INFO "ima: invalid ima_audit value\n"); | ||
31 | else | ||
32 | ima_audit = audit; | ||
33 | op = ima_audit ? "ima_audit_enabled" : "ima_audit_not_enabled"; | ||
34 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, NULL, op, 0, 0); | ||
35 | return 1; | ||
36 | } | ||
37 | __setup("ima_audit=", ima_audit_setup); | ||
38 | #endif | ||
39 | |||
40 | void integrity_audit_msg(int audit_msgno, struct inode *inode, | ||
41 | const unsigned char *fname, const char *op, | ||
42 | const char *cause, int result, int audit_info) | ||
43 | { | ||
44 | struct audit_buffer *ab; | ||
45 | |||
46 | if (!ima_audit && audit_info == 1) /* Skip informational messages */ | ||
47 | return; | ||
48 | |||
49 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); | ||
50 | audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u", | ||
51 | current->pid, current->cred->uid, | ||
52 | audit_get_loginuid(current)); | ||
53 | audit_log_task_context(ab); | ||
54 | switch (audit_msgno) { | ||
55 | case AUDIT_INTEGRITY_DATA: | ||
56 | case AUDIT_INTEGRITY_METADATA: | ||
57 | case AUDIT_INTEGRITY_PCR: | ||
58 | audit_log_format(ab, " op=%s cause=%s", op, cause); | ||
59 | break; | ||
60 | case AUDIT_INTEGRITY_HASH: | ||
61 | audit_log_format(ab, " op=%s hash=%s", op, cause); | ||
62 | break; | ||
63 | case AUDIT_INTEGRITY_STATUS: | ||
64 | default: | ||
65 | audit_log_format(ab, " op=%s", op); | ||
66 | } | ||
67 | audit_log_format(ab, " comm="); | ||
68 | audit_log_untrustedstring(ab, current->comm); | ||
69 | if (fname) { | ||
70 | audit_log_format(ab, " name="); | ||
71 | audit_log_untrustedstring(ab, fname); | ||
72 | } | ||
73 | if (inode) | ||
74 | audit_log_format(ab, " dev=%s ino=%lu", | ||
75 | inode->i_sb->s_id, inode->i_ino); | ||
76 | audit_log_format(ab, " res=%d", result); | ||
77 | audit_log_end(ab); | ||
78 | } | ||
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c new file mode 100644 index 00000000000..c2a46e40999 --- /dev/null +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Mimi Zohar <zohar@us.ibm.com> | ||
6 | * Kylene Hall <kjhall@us.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation, version 2 of the License. | ||
11 | * | ||
12 | * File: ima_crypto.c | ||
13 | * Calculates md5/sha1 file hash, template hash, boot-aggreate hash | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/file.h> | ||
18 | #include <linux/crypto.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/err.h> | ||
21 | #include "ima.h" | ||
22 | |||
23 | static int init_desc(struct hash_desc *desc) | ||
24 | { | ||
25 | int rc; | ||
26 | |||
27 | desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC); | ||
28 | if (IS_ERR(desc->tfm)) { | ||
29 | pr_info("failed to load %s transform: %ld\n", | ||
30 | ima_hash, PTR_ERR(desc->tfm)); | ||
31 | rc = PTR_ERR(desc->tfm); | ||
32 | return rc; | ||
33 | } | ||
34 | desc->flags = 0; | ||
35 | rc = crypto_hash_init(desc); | ||
36 | if (rc) | ||
37 | crypto_free_hash(desc->tfm); | ||
38 | return rc; | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * Calculate the MD5/SHA1 file digest | ||
43 | */ | ||
44 | int ima_calc_hash(struct file *file, char *digest) | ||
45 | { | ||
46 | struct hash_desc desc; | ||
47 | struct scatterlist sg[1]; | ||
48 | loff_t i_size; | ||
49 | char *rbuf; | ||
50 | int rc, offset = 0; | ||
51 | |||
52 | rc = init_desc(&desc); | ||
53 | if (rc != 0) | ||
54 | return rc; | ||
55 | |||
56 | rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
57 | if (!rbuf) { | ||
58 | rc = -ENOMEM; | ||
59 | goto out; | ||
60 | } | ||
61 | i_size = i_size_read(file->f_dentry->d_inode); | ||
62 | while (offset < i_size) { | ||
63 | int rbuf_len; | ||
64 | |||
65 | rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE); | ||
66 | if (rbuf_len < 0) { | ||
67 | rc = rbuf_len; | ||
68 | break; | ||
69 | } | ||
70 | offset += rbuf_len; | ||
71 | sg_set_buf(sg, rbuf, rbuf_len); | ||
72 | |||
73 | rc = crypto_hash_update(&desc, sg, rbuf_len); | ||
74 | if (rc) | ||
75 | break; | ||
76 | } | ||
77 | kfree(rbuf); | ||
78 | if (!rc) | ||
79 | rc = crypto_hash_final(&desc, digest); | ||
80 | out: | ||
81 | crypto_free_hash(desc.tfm); | ||
82 | return rc; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Calculate the hash of a given template | ||
87 | */ | ||
88 | int ima_calc_template_hash(int template_len, void *template, char *digest) | ||
89 | { | ||
90 | struct hash_desc desc; | ||
91 | struct scatterlist sg[1]; | ||
92 | int rc; | ||
93 | |||
94 | rc = init_desc(&desc); | ||
95 | if (rc != 0) | ||
96 | return rc; | ||
97 | |||
98 | sg_set_buf(sg, template, template_len); | ||
99 | rc = crypto_hash_update(&desc, sg, template_len); | ||
100 | if (!rc) | ||
101 | rc = crypto_hash_final(&desc, digest); | ||
102 | crypto_free_hash(desc.tfm); | ||
103 | return rc; | ||
104 | } | ||
105 | |||
106 | static void ima_pcrread(int idx, u8 *pcr) | ||
107 | { | ||
108 | if (!ima_used_chip) | ||
109 | return; | ||
110 | |||
111 | if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) | ||
112 | pr_err("Error Communicating to TPM chip\n"); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Calculate the boot aggregate hash | ||
117 | */ | ||
118 | int ima_calc_boot_aggregate(char *digest) | ||
119 | { | ||
120 | struct hash_desc desc; | ||
121 | struct scatterlist sg; | ||
122 | u8 pcr_i[IMA_DIGEST_SIZE]; | ||
123 | int rc, i; | ||
124 | |||
125 | rc = init_desc(&desc); | ||
126 | if (rc != 0) | ||
127 | return rc; | ||
128 | |||
129 | /* cumulative sha1 over tpm registers 0-7 */ | ||
130 | for (i = TPM_PCR0; i < TPM_PCR8; i++) { | ||
131 | ima_pcrread(i, pcr_i); | ||
132 | /* now accumulate with current aggregate */ | ||
133 | sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE); | ||
134 | rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE); | ||
135 | } | ||
136 | if (!rc) | ||
137 | crypto_hash_final(&desc, digest); | ||
138 | crypto_free_hash(desc.tfm); | ||
139 | return rc; | ||
140 | } | ||
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c new file mode 100644 index 00000000000..573780c76f1 --- /dev/null +++ b/security/integrity/ima/ima_fs.c | |||
@@ -0,0 +1,376 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Kylene Hall <kjhall@us.ibm.com> | ||
6 | * Reiner Sailer <sailer@us.ibm.com> | ||
7 | * Mimi Zohar <zohar@us.ibm.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation, version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | * File: ima_fs.c | ||
15 | * implemenents security file system for reporting | ||
16 | * current measurement list and IMA statistics | ||
17 | */ | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/rculist.h> | ||
21 | #include <linux/rcupdate.h> | ||
22 | #include <linux/parser.h> | ||
23 | |||
24 | #include "ima.h" | ||
25 | |||
26 | static int valid_policy = 1; | ||
27 | #define TMPBUFLEN 12 | ||
28 | static ssize_t ima_show_htable_value(char __user *buf, size_t count, | ||
29 | loff_t *ppos, atomic_long_t *val) | ||
30 | { | ||
31 | char tmpbuf[TMPBUFLEN]; | ||
32 | ssize_t len; | ||
33 | |||
34 | len = scnprintf(tmpbuf, TMPBUFLEN, "%li\n", atomic_long_read(val)); | ||
35 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); | ||
36 | } | ||
37 | |||
38 | static ssize_t ima_show_htable_violations(struct file *filp, | ||
39 | char __user *buf, | ||
40 | size_t count, loff_t *ppos) | ||
41 | { | ||
42 | return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); | ||
43 | } | ||
44 | |||
45 | static struct file_operations ima_htable_violations_ops = { | ||
46 | .read = ima_show_htable_violations | ||
47 | }; | ||
48 | |||
49 | static ssize_t ima_show_measurements_count(struct file *filp, | ||
50 | char __user *buf, | ||
51 | size_t count, loff_t *ppos) | ||
52 | { | ||
53 | return ima_show_htable_value(buf, count, ppos, &ima_htable.len); | ||
54 | |||
55 | } | ||
56 | |||
57 | static struct file_operations ima_measurements_count_ops = { | ||
58 | .read = ima_show_measurements_count | ||
59 | }; | ||
60 | |||
61 | /* returns pointer to hlist_node */ | ||
62 | static void *ima_measurements_start(struct seq_file *m, loff_t *pos) | ||
63 | { | ||
64 | loff_t l = *pos; | ||
65 | struct ima_queue_entry *qe; | ||
66 | |||
67 | /* we need a lock since pos could point beyond last element */ | ||
68 | rcu_read_lock(); | ||
69 | list_for_each_entry_rcu(qe, &ima_measurements, later) { | ||
70 | if (!l--) { | ||
71 | rcu_read_unlock(); | ||
72 | return qe; | ||
73 | } | ||
74 | } | ||
75 | rcu_read_unlock(); | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos) | ||
80 | { | ||
81 | struct ima_queue_entry *qe = v; | ||
82 | |||
83 | /* lock protects when reading beyond last element | ||
84 | * against concurrent list-extension | ||
85 | */ | ||
86 | rcu_read_lock(); | ||
87 | qe = list_entry(rcu_dereference(qe->later.next), | ||
88 | struct ima_queue_entry, later); | ||
89 | rcu_read_unlock(); | ||
90 | (*pos)++; | ||
91 | |||
92 | return (&qe->later == &ima_measurements) ? NULL : qe; | ||
93 | } | ||
94 | |||
95 | static void ima_measurements_stop(struct seq_file *m, void *v) | ||
96 | { | ||
97 | } | ||
98 | |||
99 | static void ima_putc(struct seq_file *m, void *data, int datalen) | ||
100 | { | ||
101 | while (datalen--) | ||
102 | seq_putc(m, *(char *)data++); | ||
103 | } | ||
104 | |||
105 | /* print format: | ||
106 | * 32bit-le=pcr# | ||
107 | * char[20]=template digest | ||
108 | * 32bit-le=template name size | ||
109 | * char[n]=template name | ||
110 | * eventdata[n]=template specific data | ||
111 | */ | ||
112 | static int ima_measurements_show(struct seq_file *m, void *v) | ||
113 | { | ||
114 | /* the list never shrinks, so we don't need a lock here */ | ||
115 | struct ima_queue_entry *qe = v; | ||
116 | struct ima_template_entry *e; | ||
117 | int namelen; | ||
118 | u32 pcr = CONFIG_IMA_MEASURE_PCR_IDX; | ||
119 | |||
120 | /* get entry */ | ||
121 | e = qe->entry; | ||
122 | if (e == NULL) | ||
123 | return -1; | ||
124 | |||
125 | /* | ||
126 | * 1st: PCRIndex | ||
127 | * PCR used is always the same (config option) in | ||
128 | * little-endian format | ||
129 | */ | ||
130 | ima_putc(m, &pcr, sizeof pcr); | ||
131 | |||
132 | /* 2nd: template digest */ | ||
133 | ima_putc(m, e->digest, IMA_DIGEST_SIZE); | ||
134 | |||
135 | /* 3rd: template name size */ | ||
136 | namelen = strlen(e->template_name); | ||
137 | ima_putc(m, &namelen, sizeof namelen); | ||
138 | |||
139 | /* 4th: template name */ | ||
140 | ima_putc(m, e->template_name, namelen); | ||
141 | |||
142 | /* 5th: template specific data */ | ||
143 | ima_template_show(m, (struct ima_template_data *)&e->template, | ||
144 | IMA_SHOW_BINARY); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static struct seq_operations ima_measurments_seqops = { | ||
149 | .start = ima_measurements_start, | ||
150 | .next = ima_measurements_next, | ||
151 | .stop = ima_measurements_stop, | ||
152 | .show = ima_measurements_show | ||
153 | }; | ||
154 | |||
155 | static int ima_measurements_open(struct inode *inode, struct file *file) | ||
156 | { | ||
157 | return seq_open(file, &ima_measurments_seqops); | ||
158 | } | ||
159 | |||
160 | static struct file_operations ima_measurements_ops = { | ||
161 | .open = ima_measurements_open, | ||
162 | .read = seq_read, | ||
163 | .llseek = seq_lseek, | ||
164 | .release = seq_release, | ||
165 | }; | ||
166 | |||
167 | static void ima_print_digest(struct seq_file *m, u8 *digest) | ||
168 | { | ||
169 | int i; | ||
170 | |||
171 | for (i = 0; i < IMA_DIGEST_SIZE; i++) | ||
172 | seq_printf(m, "%02x", *(digest + i)); | ||
173 | } | ||
174 | |||
175 | void ima_template_show(struct seq_file *m, void *e, enum ima_show_type show) | ||
176 | { | ||
177 | struct ima_template_data *entry = e; | ||
178 | int namelen; | ||
179 | |||
180 | switch (show) { | ||
181 | case IMA_SHOW_ASCII: | ||
182 | ima_print_digest(m, entry->digest); | ||
183 | seq_printf(m, " %s\n", entry->file_name); | ||
184 | break; | ||
185 | case IMA_SHOW_BINARY: | ||
186 | ima_putc(m, entry->digest, IMA_DIGEST_SIZE); | ||
187 | |||
188 | namelen = strlen(entry->file_name); | ||
189 | ima_putc(m, &namelen, sizeof namelen); | ||
190 | ima_putc(m, entry->file_name, namelen); | ||
191 | default: | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | /* print in ascii */ | ||
197 | static int ima_ascii_measurements_show(struct seq_file *m, void *v) | ||
198 | { | ||
199 | /* the list never shrinks, so we don't need a lock here */ | ||
200 | struct ima_queue_entry *qe = v; | ||
201 | struct ima_template_entry *e; | ||
202 | |||
203 | /* get entry */ | ||
204 | e = qe->entry; | ||
205 | if (e == NULL) | ||
206 | return -1; | ||
207 | |||
208 | /* 1st: PCR used (config option) */ | ||
209 | seq_printf(m, "%2d ", CONFIG_IMA_MEASURE_PCR_IDX); | ||
210 | |||
211 | /* 2nd: SHA1 template hash */ | ||
212 | ima_print_digest(m, e->digest); | ||
213 | |||
214 | /* 3th: template name */ | ||
215 | seq_printf(m, " %s ", e->template_name); | ||
216 | |||
217 | /* 4th: template specific data */ | ||
218 | ima_template_show(m, (struct ima_template_data *)&e->template, | ||
219 | IMA_SHOW_ASCII); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static struct seq_operations ima_ascii_measurements_seqops = { | ||
224 | .start = ima_measurements_start, | ||
225 | .next = ima_measurements_next, | ||
226 | .stop = ima_measurements_stop, | ||
227 | .show = ima_ascii_measurements_show | ||
228 | }; | ||
229 | |||
230 | static int ima_ascii_measurements_open(struct inode *inode, struct file *file) | ||
231 | { | ||
232 | return seq_open(file, &ima_ascii_measurements_seqops); | ||
233 | } | ||
234 | |||
235 | static struct file_operations ima_ascii_measurements_ops = { | ||
236 | .open = ima_ascii_measurements_open, | ||
237 | .read = seq_read, | ||
238 | .llseek = seq_lseek, | ||
239 | .release = seq_release, | ||
240 | }; | ||
241 | |||
242 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, | ||
243 | size_t datalen, loff_t *ppos) | ||
244 | { | ||
245 | char *data; | ||
246 | int rc; | ||
247 | |||
248 | if (datalen >= PAGE_SIZE) | ||
249 | return -ENOMEM; | ||
250 | if (*ppos != 0) { | ||
251 | /* No partial writes. */ | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | data = kmalloc(datalen + 1, GFP_KERNEL); | ||
255 | if (!data) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | if (copy_from_user(data, buf, datalen)) { | ||
259 | kfree(data); | ||
260 | return -EFAULT; | ||
261 | } | ||
262 | *(data + datalen) = '\0'; | ||
263 | rc = ima_parse_add_rule(data); | ||
264 | if (rc < 0) { | ||
265 | datalen = -EINVAL; | ||
266 | valid_policy = 0; | ||
267 | } | ||
268 | |||
269 | kfree(data); | ||
270 | return datalen; | ||
271 | } | ||
272 | |||
273 | static struct dentry *ima_dir; | ||
274 | static struct dentry *binary_runtime_measurements; | ||
275 | static struct dentry *ascii_runtime_measurements; | ||
276 | static struct dentry *runtime_measurements_count; | ||
277 | static struct dentry *violations; | ||
278 | static struct dentry *ima_policy; | ||
279 | |||
280 | static atomic_t policy_opencount = ATOMIC_INIT(1); | ||
281 | /* | ||
282 | * ima_open_policy: sequentialize access to the policy file | ||
283 | */ | ||
284 | int ima_open_policy(struct inode * inode, struct file * filp) | ||
285 | { | ||
286 | if (atomic_dec_and_test(&policy_opencount)) | ||
287 | return 0; | ||
288 | return -EBUSY; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * ima_release_policy - start using the new measure policy rules. | ||
293 | * | ||
294 | * Initially, ima_measure points to the default policy rules, now | ||
295 | * point to the new policy rules, and remove the securityfs policy file, | ||
296 | * assuming a valid policy. | ||
297 | */ | ||
298 | static int ima_release_policy(struct inode *inode, struct file *file) | ||
299 | { | ||
300 | if (!valid_policy) { | ||
301 | ima_delete_rules(); | ||
302 | valid_policy = 1; | ||
303 | atomic_set(&policy_opencount, 1); | ||
304 | return 0; | ||
305 | } | ||
306 | ima_update_policy(); | ||
307 | securityfs_remove(ima_policy); | ||
308 | ima_policy = NULL; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static struct file_operations ima_measure_policy_ops = { | ||
313 | .open = ima_open_policy, | ||
314 | .write = ima_write_policy, | ||
315 | .release = ima_release_policy | ||
316 | }; | ||
317 | |||
318 | int ima_fs_init(void) | ||
319 | { | ||
320 | ima_dir = securityfs_create_dir("ima", NULL); | ||
321 | if (IS_ERR(ima_dir)) | ||
322 | return -1; | ||
323 | |||
324 | binary_runtime_measurements = | ||
325 | securityfs_create_file("binary_runtime_measurements", | ||
326 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
327 | &ima_measurements_ops); | ||
328 | if (IS_ERR(binary_runtime_measurements)) | ||
329 | goto out; | ||
330 | |||
331 | ascii_runtime_measurements = | ||
332 | securityfs_create_file("ascii_runtime_measurements", | ||
333 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
334 | &ima_ascii_measurements_ops); | ||
335 | if (IS_ERR(ascii_runtime_measurements)) | ||
336 | goto out; | ||
337 | |||
338 | runtime_measurements_count = | ||
339 | securityfs_create_file("runtime_measurements_count", | ||
340 | S_IRUSR | S_IRGRP, ima_dir, NULL, | ||
341 | &ima_measurements_count_ops); | ||
342 | if (IS_ERR(runtime_measurements_count)) | ||
343 | goto out; | ||
344 | |||
345 | violations = | ||
346 | securityfs_create_file("violations", S_IRUSR | S_IRGRP, | ||
347 | ima_dir, NULL, &ima_htable_violations_ops); | ||
348 | if (IS_ERR(violations)) | ||
349 | goto out; | ||
350 | |||
351 | ima_policy = securityfs_create_file("policy", | ||
352 | S_IRUSR | S_IRGRP | S_IWUSR, | ||
353 | ima_dir, NULL, | ||
354 | &ima_measure_policy_ops); | ||
355 | if (IS_ERR(ima_policy)) | ||
356 | goto out; | ||
357 | |||
358 | return 0; | ||
359 | out: | ||
360 | securityfs_remove(runtime_measurements_count); | ||
361 | securityfs_remove(ascii_runtime_measurements); | ||
362 | securityfs_remove(binary_runtime_measurements); | ||
363 | securityfs_remove(ima_dir); | ||
364 | securityfs_remove(ima_policy); | ||
365 | return -1; | ||
366 | } | ||
367 | |||
368 | void __exit ima_fs_cleanup(void) | ||
369 | { | ||
370 | securityfs_remove(violations); | ||
371 | securityfs_remove(runtime_measurements_count); | ||
372 | securityfs_remove(ascii_runtime_measurements); | ||
373 | securityfs_remove(binary_runtime_measurements); | ||
374 | securityfs_remove(ima_dir); | ||
375 | securityfs_remove(ima_policy); | ||
376 | } | ||
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c new file mode 100644 index 00000000000..1f035e8d29c --- /dev/null +++ b/security/integrity/ima/ima_iint.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Mimi Zohar <zohar@us.ibm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation, version 2 of the | ||
10 | * License. | ||
11 | * | ||
12 | * File: ima_iint.c | ||
13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free | ||
14 | * - cache integrity information associated with an inode | ||
15 | * using a radix tree. | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/radix-tree.h> | ||
20 | #include "ima.h" | ||
21 | |||
22 | #define ima_iint_delete ima_inode_free | ||
23 | |||
24 | RADIX_TREE(ima_iint_store, GFP_ATOMIC); | ||
25 | DEFINE_SPINLOCK(ima_iint_lock); | ||
26 | |||
27 | static struct kmem_cache *iint_cache __read_mostly; | ||
28 | |||
29 | /* ima_iint_find_get - return the iint associated with an inode | ||
30 | * | ||
31 | * ima_iint_find_get gets a reference to the iint. Caller must | ||
32 | * remember to put the iint reference. | ||
33 | */ | ||
34 | struct ima_iint_cache *ima_iint_find_get(struct inode *inode) | ||
35 | { | ||
36 | struct ima_iint_cache *iint; | ||
37 | |||
38 | rcu_read_lock(); | ||
39 | iint = radix_tree_lookup(&ima_iint_store, (unsigned long)inode); | ||
40 | if (!iint) | ||
41 | goto out; | ||
42 | kref_get(&iint->refcount); | ||
43 | out: | ||
44 | rcu_read_unlock(); | ||
45 | return iint; | ||
46 | } | ||
47 | |||
48 | /* Allocate memory for the iint associated with the inode | ||
49 | * from the iint_cache slab, initialize the iint, and | ||
50 | * insert it into the radix tree. | ||
51 | * | ||
52 | * On success return a pointer to the iint; on failure return NULL. | ||
53 | */ | ||
54 | struct ima_iint_cache *ima_iint_insert(struct inode *inode) | ||
55 | { | ||
56 | struct ima_iint_cache *iint = NULL; | ||
57 | int rc = 0; | ||
58 | |||
59 | if (!ima_initialized) | ||
60 | return iint; | ||
61 | iint = kmem_cache_alloc(iint_cache, GFP_KERNEL); | ||
62 | if (!iint) | ||
63 | return iint; | ||
64 | |||
65 | rc = radix_tree_preload(GFP_KERNEL); | ||
66 | if (rc < 0) | ||
67 | goto out; | ||
68 | |||
69 | spin_lock(&ima_iint_lock); | ||
70 | rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint); | ||
71 | spin_unlock(&ima_iint_lock); | ||
72 | out: | ||
73 | if (rc < 0) { | ||
74 | kmem_cache_free(iint_cache, iint); | ||
75 | if (rc == -EEXIST) { | ||
76 | iint = radix_tree_lookup(&ima_iint_store, | ||
77 | (unsigned long)inode); | ||
78 | } else | ||
79 | iint = NULL; | ||
80 | } | ||
81 | radix_tree_preload_end(); | ||
82 | return iint; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * ima_inode_alloc - allocate an iint associated with an inode | ||
87 | * @inode: pointer to the inode | ||
88 | * | ||
89 | * Return 0 on success, 1 on failure. | ||
90 | */ | ||
91 | int ima_inode_alloc(struct inode *inode) | ||
92 | { | ||
93 | struct ima_iint_cache *iint; | ||
94 | |||
95 | if (!ima_initialized) | ||
96 | return 0; | ||
97 | |||
98 | iint = ima_iint_insert(inode); | ||
99 | if (!iint) | ||
100 | return 1; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* ima_iint_find_insert_get - get the iint associated with an inode | ||
105 | * | ||
106 | * Most insertions are done at inode_alloc, except those allocated | ||
107 | * before late_initcall. When the iint does not exist, allocate it, | ||
108 | * initialize and insert it, and increment the iint refcount. | ||
109 | * | ||
110 | * (Can't initialize at security_initcall before any inodes are | ||
111 | * allocated, got to wait at least until proc_init.) | ||
112 | * | ||
113 | * Return the iint. | ||
114 | */ | ||
115 | struct ima_iint_cache *ima_iint_find_insert_get(struct inode *inode) | ||
116 | { | ||
117 | struct ima_iint_cache *iint = NULL; | ||
118 | |||
119 | iint = ima_iint_find_get(inode); | ||
120 | if (iint) | ||
121 | return iint; | ||
122 | |||
123 | iint = ima_iint_insert(inode); | ||
124 | if (iint) | ||
125 | kref_get(&iint->refcount); | ||
126 | |||
127 | return iint; | ||
128 | } | ||
129 | EXPORT_SYMBOL_GPL(ima_iint_find_insert_get); | ||
130 | |||
131 | /* iint_free - called when the iint refcount goes to zero */ | ||
132 | void iint_free(struct kref *kref) | ||
133 | { | ||
134 | struct ima_iint_cache *iint = container_of(kref, struct ima_iint_cache, | ||
135 | refcount); | ||
136 | iint->version = 0; | ||
137 | iint->flags = 0UL; | ||
138 | if (iint->readcount != 0) { | ||
139 | printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__, | ||
140 | iint->readcount); | ||
141 | iint->readcount = 0; | ||
142 | } | ||
143 | if (iint->writecount != 0) { | ||
144 | printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__, | ||
145 | iint->writecount); | ||
146 | iint->writecount = 0; | ||
147 | } | ||
148 | if (iint->opencount != 0) { | ||
149 | printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__, | ||
150 | iint->opencount); | ||
151 | iint->opencount = 0; | ||
152 | } | ||
153 | kref_set(&iint->refcount, 1); | ||
154 | kmem_cache_free(iint_cache, iint); | ||
155 | } | ||
156 | |||
157 | void iint_rcu_free(struct rcu_head *rcu_head) | ||
158 | { | ||
159 | struct ima_iint_cache *iint = container_of(rcu_head, | ||
160 | struct ima_iint_cache, rcu); | ||
161 | kref_put(&iint->refcount, iint_free); | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * ima_iint_delete - called on integrity_inode_free | ||
166 | * @inode: pointer to the inode | ||
167 | * | ||
168 | * Free the integrity information(iint) associated with an inode. | ||
169 | */ | ||
170 | void ima_iint_delete(struct inode *inode) | ||
171 | { | ||
172 | struct ima_iint_cache *iint; | ||
173 | |||
174 | if (!ima_initialized) | ||
175 | return; | ||
176 | spin_lock(&ima_iint_lock); | ||
177 | iint = radix_tree_delete(&ima_iint_store, (unsigned long)inode); | ||
178 | spin_unlock(&ima_iint_lock); | ||
179 | if (iint) | ||
180 | call_rcu(&iint->rcu, iint_rcu_free); | ||
181 | } | ||
182 | |||
183 | static void init_once(void *foo) | ||
184 | { | ||
185 | struct ima_iint_cache *iint = foo; | ||
186 | |||
187 | memset(iint, 0, sizeof *iint); | ||
188 | iint->version = 0; | ||
189 | iint->flags = 0UL; | ||
190 | mutex_init(&iint->mutex); | ||
191 | iint->readcount = 0; | ||
192 | iint->writecount = 0; | ||
193 | iint->opencount = 0; | ||
194 | kref_set(&iint->refcount, 1); | ||
195 | } | ||
196 | |||
197 | void ima_iintcache_init(void) | ||
198 | { | ||
199 | iint_cache = | ||
200 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | ||
201 | SLAB_PANIC, init_once); | ||
202 | } | ||
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c new file mode 100644 index 00000000000..cf227dbfac2 --- /dev/null +++ b/security/integrity/ima/ima_init.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Reiner Sailer <sailer@watson.ibm.com> | ||
6 | * Leendert van Doorn <leendert@watson.ibm.com> | ||
7 | * Mimi Zohar <zohar@us.ibm.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation, version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | * File: ima_init.c | ||
15 | * initialization and cleanup functions | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/scatterlist.h> | ||
19 | #include <linux/err.h> | ||
20 | #include "ima.h" | ||
21 | |||
22 | /* name for boot aggregate entry */ | ||
23 | static char *boot_aggregate_name = "boot_aggregate"; | ||
24 | int ima_used_chip; | ||
25 | |||
26 | /* Add the boot aggregate to the IMA measurement list and extend | ||
27 | * the PCR register. | ||
28 | * | ||
29 | * Calculate the boot aggregate, a SHA1 over tpm registers 0-7, | ||
30 | * assuming a TPM chip exists, and zeroes if the TPM chip does not | ||
31 | * exist. Add the boot aggregate measurement to the measurement | ||
32 | * list and extend the PCR register. | ||
33 | * | ||
34 | * If a tpm chip does not exist, indicate the core root of trust is | ||
35 | * not hardware based by invalidating the aggregate PCR value. | ||
36 | * (The aggregate PCR value is invalidated by adding one value to | ||
37 | * the measurement list and extending the aggregate PCR value with | ||
38 | * a different value.) Violations add a zero entry to the measurement | ||
39 | * list and extend the aggregate PCR value with ff...ff's. | ||
40 | */ | ||
41 | static void ima_add_boot_aggregate(void) | ||
42 | { | ||
43 | struct ima_template_entry *entry; | ||
44 | const char *op = "add_boot_aggregate"; | ||
45 | const char *audit_cause = "ENOMEM"; | ||
46 | int result = -ENOMEM; | ||
47 | int violation = 1; | ||
48 | |||
49 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
50 | if (!entry) | ||
51 | goto err_out; | ||
52 | |||
53 | memset(&entry->template, 0, sizeof(entry->template)); | ||
54 | strncpy(entry->template.file_name, boot_aggregate_name, | ||
55 | IMA_EVENT_NAME_LEN_MAX); | ||
56 | if (ima_used_chip) { | ||
57 | violation = 0; | ||
58 | result = ima_calc_boot_aggregate(entry->template.digest); | ||
59 | if (result < 0) { | ||
60 | audit_cause = "hashing_error"; | ||
61 | kfree(entry); | ||
62 | goto err_out; | ||
63 | } | ||
64 | } | ||
65 | result = ima_store_template(entry, violation, NULL); | ||
66 | if (result < 0) | ||
67 | kfree(entry); | ||
68 | return; | ||
69 | err_out: | ||
70 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op, | ||
71 | audit_cause, result, 0); | ||
72 | } | ||
73 | |||
74 | int ima_init(void) | ||
75 | { | ||
76 | u8 pcr_i[IMA_DIGEST_SIZE]; | ||
77 | int rc; | ||
78 | |||
79 | ima_used_chip = 0; | ||
80 | rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i); | ||
81 | if (rc == 0) | ||
82 | ima_used_chip = 1; | ||
83 | |||
84 | if (!ima_used_chip) | ||
85 | pr_info("No TPM chip found, activating TPM-bypass!\n"); | ||
86 | |||
87 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ | ||
88 | ima_init_policy(); | ||
89 | |||
90 | return ima_fs_init(); | ||
91 | } | ||
92 | |||
93 | void __exit ima_cleanup(void) | ||
94 | { | ||
95 | ima_fs_cleanup(); | ||
96 | } | ||
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c new file mode 100644 index 00000000000..f4e7266f5ae --- /dev/null +++ b/security/integrity/ima/ima_main.c | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Reiner Sailer <sailer@watson.ibm.com> | ||
6 | * Serge Hallyn <serue@us.ibm.com> | ||
7 | * Kylene Hall <kylene@us.ibm.com> | ||
8 | * Mimi Zohar <zohar@us.ibm.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation, version 2 of the | ||
13 | * License. | ||
14 | * | ||
15 | * File: ima_main.c | ||
16 | * implements the IMA hooks: ima_bprm_check, ima_file_mmap, | ||
17 | * and ima_path_check. | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/file.h> | ||
21 | #include <linux/binfmts.h> | ||
22 | #include <linux/mount.h> | ||
23 | #include <linux/mman.h> | ||
24 | |||
25 | #include "ima.h" | ||
26 | |||
27 | int ima_initialized; | ||
28 | |||
29 | char *ima_hash = "sha1"; | ||
30 | static int __init hash_setup(char *str) | ||
31 | { | ||
32 | const char *op = "hash_setup"; | ||
33 | const char *hash = "sha1"; | ||
34 | int result = 0; | ||
35 | int audit_info = 0; | ||
36 | |||
37 | if (strncmp(str, "md5", 3) == 0) { | ||
38 | hash = "md5"; | ||
39 | ima_hash = str; | ||
40 | } else if (strncmp(str, "sha1", 4) != 0) { | ||
41 | hash = "invalid_hash_type"; | ||
42 | result = 1; | ||
43 | } | ||
44 | integrity_audit_msg(AUDIT_INTEGRITY_HASH, NULL, NULL, op, hash, | ||
45 | result, audit_info); | ||
46 | return 1; | ||
47 | } | ||
48 | __setup("ima_hash=", hash_setup); | ||
49 | |||
50 | /** | ||
51 | * ima_file_free - called on __fput() | ||
52 | * @file: pointer to file structure being freed | ||
53 | * | ||
54 | * Flag files that changed, based on i_version; | ||
55 | * and decrement the iint readcount/writecount. | ||
56 | */ | ||
57 | void ima_file_free(struct file *file) | ||
58 | { | ||
59 | struct inode *inode = file->f_dentry->d_inode; | ||
60 | struct ima_iint_cache *iint; | ||
61 | |||
62 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
63 | return; | ||
64 | iint = ima_iint_find_get(inode); | ||
65 | if (!iint) | ||
66 | return; | ||
67 | |||
68 | mutex_lock(&iint->mutex); | ||
69 | if (iint->opencount <= 0) { | ||
70 | printk(KERN_INFO | ||
71 | "%s: %s open/free imbalance (r:%ld w:%ld o:%ld f:%ld)\n", | ||
72 | __FUNCTION__, file->f_dentry->d_name.name, | ||
73 | iint->readcount, iint->writecount, | ||
74 | iint->opencount, atomic_long_read(&file->f_count)); | ||
75 | if (!(iint->flags & IMA_IINT_DUMP_STACK)) { | ||
76 | dump_stack(); | ||
77 | iint->flags |= IMA_IINT_DUMP_STACK; | ||
78 | } | ||
79 | } | ||
80 | iint->opencount--; | ||
81 | |||
82 | if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) | ||
83 | iint->readcount--; | ||
84 | |||
85 | if (file->f_mode & FMODE_WRITE) { | ||
86 | iint->writecount--; | ||
87 | if (iint->writecount == 0) { | ||
88 | if (iint->version != inode->i_version) | ||
89 | iint->flags &= ~IMA_MEASURED; | ||
90 | } | ||
91 | } | ||
92 | mutex_unlock(&iint->mutex); | ||
93 | kref_put(&iint->refcount, iint_free); | ||
94 | } | ||
95 | |||
96 | /* ima_read_write_check - reflect possible reading/writing errors in the PCR. | ||
97 | * | ||
98 | * When opening a file for read, if the file is already open for write, | ||
99 | * the file could change, resulting in a file measurement error. | ||
100 | * | ||
101 | * Opening a file for write, if the file is already open for read, results | ||
102 | * in a time of measure, time of use (ToMToU) error. | ||
103 | * | ||
104 | * In either case invalidate the PCR. | ||
105 | */ | ||
106 | enum iint_pcr_error { TOMTOU, OPEN_WRITERS }; | ||
107 | static void ima_read_write_check(enum iint_pcr_error error, | ||
108 | struct ima_iint_cache *iint, | ||
109 | struct inode *inode, | ||
110 | const unsigned char *filename) | ||
111 | { | ||
112 | switch (error) { | ||
113 | case TOMTOU: | ||
114 | if (iint->readcount > 0) | ||
115 | ima_add_violation(inode, filename, "invalid_pcr", | ||
116 | "ToMToU"); | ||
117 | break; | ||
118 | case OPEN_WRITERS: | ||
119 | if (iint->writecount > 0) | ||
120 | ima_add_violation(inode, filename, "invalid_pcr", | ||
121 | "open_writers"); | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static int get_path_measurement(struct ima_iint_cache *iint, struct file *file, | ||
127 | const unsigned char *filename) | ||
128 | { | ||
129 | int rc = 0; | ||
130 | |||
131 | if (IS_ERR(file)) { | ||
132 | pr_info("%s dentry_open failed\n", filename); | ||
133 | return rc; | ||
134 | } | ||
135 | iint->opencount++; | ||
136 | iint->readcount++; | ||
137 | |||
138 | rc = ima_collect_measurement(iint, file); | ||
139 | if (!rc) | ||
140 | ima_store_measurement(iint, file, filename); | ||
141 | return rc; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * ima_path_check - based on policy, collect/store measurement. | ||
146 | * @path: contains a pointer to the path to be measured | ||
147 | * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE | ||
148 | * | ||
149 | * Measure the file being open for readonly, based on the | ||
150 | * ima_must_measure() policy decision. | ||
151 | * | ||
152 | * Keep read/write counters for all files, but only | ||
153 | * invalidate the PCR for measured files: | ||
154 | * - Opening a file for write when already open for read, | ||
155 | * results in a time of measure, time of use (ToMToU) error. | ||
156 | * - Opening a file for read when already open for write, | ||
157 | * could result in a file measurement error. | ||
158 | * | ||
159 | * Return 0 on success, an error code on failure. | ||
160 | * (Based on the results of appraise_measurement().) | ||
161 | */ | ||
162 | int ima_path_check(struct path *path, int mask) | ||
163 | { | ||
164 | struct inode *inode = path->dentry->d_inode; | ||
165 | struct ima_iint_cache *iint; | ||
166 | struct file *file = NULL; | ||
167 | int rc; | ||
168 | |||
169 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
170 | return 0; | ||
171 | iint = ima_iint_find_insert_get(inode); | ||
172 | if (!iint) | ||
173 | return 0; | ||
174 | |||
175 | mutex_lock(&iint->mutex); | ||
176 | iint->opencount++; | ||
177 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
178 | iint->writecount++; | ||
179 | else if (mask & (MAY_READ | MAY_EXEC)) | ||
180 | iint->readcount++; | ||
181 | |||
182 | rc = ima_must_measure(iint, inode, MAY_READ, PATH_CHECK); | ||
183 | if (rc < 0) | ||
184 | goto out; | ||
185 | |||
186 | if ((mask & MAY_WRITE) || (mask == 0)) | ||
187 | ima_read_write_check(TOMTOU, iint, inode, | ||
188 | path->dentry->d_name.name); | ||
189 | |||
190 | if ((mask & (MAY_WRITE | MAY_READ | MAY_EXEC)) != MAY_READ) | ||
191 | goto out; | ||
192 | |||
193 | ima_read_write_check(OPEN_WRITERS, iint, inode, | ||
194 | path->dentry->d_name.name); | ||
195 | if (!(iint->flags & IMA_MEASURED)) { | ||
196 | struct dentry *dentry = dget(path->dentry); | ||
197 | struct vfsmount *mnt = mntget(path->mnt); | ||
198 | |||
199 | file = dentry_open(dentry, mnt, O_RDONLY, current->cred); | ||
200 | rc = get_path_measurement(iint, file, dentry->d_name.name); | ||
201 | } | ||
202 | out: | ||
203 | mutex_unlock(&iint->mutex); | ||
204 | if (file) | ||
205 | fput(file); | ||
206 | kref_put(&iint->refcount, iint_free); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int process_measurement(struct file *file, const unsigned char *filename, | ||
211 | int mask, int function) | ||
212 | { | ||
213 | struct inode *inode = file->f_dentry->d_inode; | ||
214 | struct ima_iint_cache *iint; | ||
215 | int rc; | ||
216 | |||
217 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
218 | return 0; | ||
219 | iint = ima_iint_find_insert_get(inode); | ||
220 | if (!iint) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | mutex_lock(&iint->mutex); | ||
224 | rc = ima_must_measure(iint, inode, mask, function); | ||
225 | if (rc != 0) | ||
226 | goto out; | ||
227 | |||
228 | rc = ima_collect_measurement(iint, file); | ||
229 | if (!rc) | ||
230 | ima_store_measurement(iint, file, filename); | ||
231 | out: | ||
232 | mutex_unlock(&iint->mutex); | ||
233 | kref_put(&iint->refcount, iint_free); | ||
234 | return rc; | ||
235 | } | ||
236 | |||
237 | static void opencount_get(struct file *file) | ||
238 | { | ||
239 | struct inode *inode = file->f_dentry->d_inode; | ||
240 | struct ima_iint_cache *iint; | ||
241 | |||
242 | if (!ima_initialized || !S_ISREG(inode->i_mode)) | ||
243 | return; | ||
244 | iint = ima_iint_find_insert_get(inode); | ||
245 | if (!iint) | ||
246 | return; | ||
247 | mutex_lock(&iint->mutex); | ||
248 | iint->opencount++; | ||
249 | mutex_unlock(&iint->mutex); | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * ima_file_mmap - based on policy, collect/store measurement. | ||
254 | * @file: pointer to the file to be measured (May be NULL) | ||
255 | * @prot: contains the protection that will be applied by the kernel. | ||
256 | * | ||
257 | * Measure files being mmapped executable based on the ima_must_measure() | ||
258 | * policy decision. | ||
259 | * | ||
260 | * Return 0 on success, an error code on failure. | ||
261 | * (Based on the results of appraise_measurement().) | ||
262 | */ | ||
263 | int ima_file_mmap(struct file *file, unsigned long prot) | ||
264 | { | ||
265 | int rc; | ||
266 | |||
267 | if (!file) | ||
268 | return 0; | ||
269 | if (prot & PROT_EXEC) | ||
270 | rc = process_measurement(file, file->f_dentry->d_name.name, | ||
271 | MAY_EXEC, FILE_MMAP); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * ima_shm_check - IPC shm and shmat create/fput a file | ||
277 | * | ||
278 | * Maintain the opencount for these files to prevent unnecessary | ||
279 | * imbalance messages. | ||
280 | */ | ||
281 | void ima_shm_check(struct file *file) | ||
282 | { | ||
283 | opencount_get(file); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * ima_bprm_check - based on policy, collect/store measurement. | ||
289 | * @bprm: contains the linux_binprm structure | ||
290 | * | ||
291 | * The OS protects against an executable file, already open for write, | ||
292 | * from being executed in deny_write_access() and an executable file, | ||
293 | * already open for execute, from being modified in get_write_access(). | ||
294 | * So we can be certain that what we verify and measure here is actually | ||
295 | * what is being executed. | ||
296 | * | ||
297 | * Return 0 on success, an error code on failure. | ||
298 | * (Based on the results of appraise_measurement().) | ||
299 | */ | ||
300 | int ima_bprm_check(struct linux_binprm *bprm) | ||
301 | { | ||
302 | int rc; | ||
303 | |||
304 | rc = process_measurement(bprm->file, bprm->filename, | ||
305 | MAY_EXEC, BPRM_CHECK); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int __init init_ima(void) | ||
310 | { | ||
311 | int error; | ||
312 | |||
313 | ima_iintcache_init(); | ||
314 | error = ima_init(); | ||
315 | ima_initialized = 1; | ||
316 | return error; | ||
317 | } | ||
318 | |||
319 | static void __exit cleanup_ima(void) | ||
320 | { | ||
321 | ima_cleanup(); | ||
322 | } | ||
323 | |||
324 | late_initcall(init_ima); /* Start IMA after the TPM is available */ | ||
325 | |||
326 | MODULE_DESCRIPTION("Integrity Measurement Architecture"); | ||
327 | MODULE_LICENSE("GPL"); | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c new file mode 100644 index 00000000000..23810e0bfc6 --- /dev/null +++ b/security/integrity/ima/ima_policy.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 IBM Corporation | ||
3 | * Author: Mimi Zohar <zohar@us.ibm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, version 2 of the License. | ||
8 | * | ||
9 | * ima_policy.c | ||
10 | * - initialize default measure policy rules | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <linux/audit.h> | ||
16 | #include <linux/security.h> | ||
17 | #include <linux/magic.h> | ||
18 | #include <linux/parser.h> | ||
19 | |||
20 | #include "ima.h" | ||
21 | |||
22 | /* flags definitions */ | ||
23 | #define IMA_FUNC 0x0001 | ||
24 | #define IMA_MASK 0x0002 | ||
25 | #define IMA_FSMAGIC 0x0004 | ||
26 | #define IMA_UID 0x0008 | ||
27 | |||
28 | enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; | ||
29 | |||
30 | #define MAX_LSM_RULES 6 | ||
31 | enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, | ||
32 | LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE | ||
33 | }; | ||
34 | |||
35 | struct ima_measure_rule_entry { | ||
36 | struct list_head list; | ||
37 | enum ima_action action; | ||
38 | unsigned int flags; | ||
39 | enum ima_hooks func; | ||
40 | int mask; | ||
41 | unsigned long fsmagic; | ||
42 | uid_t uid; | ||
43 | struct { | ||
44 | void *rule; /* LSM file metadata specific */ | ||
45 | int type; /* audit type */ | ||
46 | } lsm[MAX_LSM_RULES]; | ||
47 | }; | ||
48 | |||
49 | /* Without LSM specific knowledge, the default policy can only be | ||
50 | * written in terms of .action, .func, .mask, .fsmagic, and .uid | ||
51 | */ | ||
52 | static struct ima_measure_rule_entry default_rules[] = { | ||
53 | {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, | ||
54 | .flags = IMA_FSMAGIC}, | ||
55 | {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
56 | {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
57 | {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, | ||
58 | {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC, | ||
59 | .flags = IMA_FSMAGIC}, | ||
60 | {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC}, | ||
61 | {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, | ||
62 | .flags = IMA_FUNC | IMA_MASK}, | ||
63 | {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, | ||
64 | .flags = IMA_FUNC | IMA_MASK}, | ||
65 | {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, | ||
66 | .flags = IMA_FUNC | IMA_MASK | IMA_UID} | ||
67 | }; | ||
68 | |||
69 | static LIST_HEAD(measure_default_rules); | ||
70 | static LIST_HEAD(measure_policy_rules); | ||
71 | static struct list_head *ima_measure; | ||
72 | |||
73 | static DEFINE_MUTEX(ima_measure_mutex); | ||
74 | |||
75 | /** | ||
76 | * ima_match_rules - determine whether an inode matches the measure rule. | ||
77 | * @rule: a pointer to a rule | ||
78 | * @inode: a pointer to an inode | ||
79 | * @func: LIM hook identifier | ||
80 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | ||
81 | * | ||
82 | * Returns true on rule match, false on failure. | ||
83 | */ | ||
84 | static bool ima_match_rules(struct ima_measure_rule_entry *rule, | ||
85 | struct inode *inode, enum ima_hooks func, int mask) | ||
86 | { | ||
87 | struct task_struct *tsk = current; | ||
88 | int i; | ||
89 | |||
90 | if ((rule->flags & IMA_FUNC) && rule->func != func) | ||
91 | return false; | ||
92 | if ((rule->flags & IMA_MASK) && rule->mask != mask) | ||
93 | return false; | ||
94 | if ((rule->flags & IMA_FSMAGIC) | ||
95 | && rule->fsmagic != inode->i_sb->s_magic) | ||
96 | return false; | ||
97 | if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) | ||
98 | return false; | ||
99 | for (i = 0; i < MAX_LSM_RULES; i++) { | ||
100 | int rc; | ||
101 | u32 osid, sid; | ||
102 | |||
103 | if (!rule->lsm[i].rule) | ||
104 | continue; | ||
105 | |||
106 | switch (i) { | ||
107 | case LSM_OBJ_USER: | ||
108 | case LSM_OBJ_ROLE: | ||
109 | case LSM_OBJ_TYPE: | ||
110 | security_inode_getsecid(inode, &osid); | ||
111 | rc = security_filter_rule_match(osid, | ||
112 | rule->lsm[i].type, | ||
113 | AUDIT_EQUAL, | ||
114 | rule->lsm[i].rule, | ||
115 | NULL); | ||
116 | break; | ||
117 | case LSM_SUBJ_USER: | ||
118 | case LSM_SUBJ_ROLE: | ||
119 | case LSM_SUBJ_TYPE: | ||
120 | security_task_getsecid(tsk, &sid); | ||
121 | rc = security_filter_rule_match(sid, | ||
122 | rule->lsm[i].type, | ||
123 | AUDIT_EQUAL, | ||
124 | rule->lsm[i].rule, | ||
125 | NULL); | ||
126 | default: | ||
127 | break; | ||
128 | } | ||
129 | if (!rc) | ||
130 | return false; | ||
131 | } | ||
132 | return true; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * ima_match_policy - decision based on LSM and other conditions | ||
137 | * @inode: pointer to an inode for which the policy decision is being made | ||
138 | * @func: IMA hook identifier | ||
139 | * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) | ||
140 | * | ||
141 | * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type) | ||
142 | * conditions. | ||
143 | * | ||
144 | * (There is no need for locking when walking the policy list, | ||
145 | * as elements in the list are never deleted, nor does the list | ||
146 | * change.) | ||
147 | */ | ||
148 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask) | ||
149 | { | ||
150 | struct ima_measure_rule_entry *entry; | ||
151 | |||
152 | list_for_each_entry(entry, ima_measure, list) { | ||
153 | bool rc; | ||
154 | |||
155 | rc = ima_match_rules(entry, inode, func, mask); | ||
156 | if (rc) | ||
157 | return entry->action; | ||
158 | } | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * ima_init_policy - initialize the default measure rules. | ||
164 | * | ||
165 | * ima_measure points to either the measure_default_rules or the | ||
166 | * the new measure_policy_rules. | ||
167 | */ | ||
168 | void ima_init_policy(void) | ||
169 | { | ||
170 | int i; | ||
171 | |||
172 | for (i = 0; i < ARRAY_SIZE(default_rules); i++) | ||
173 | list_add_tail(&default_rules[i].list, &measure_default_rules); | ||
174 | ima_measure = &measure_default_rules; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * ima_update_policy - update default_rules with new measure rules | ||
179 | * | ||
180 | * Called on file .release to update the default rules with a complete new | ||
181 | * policy. Once updated, the policy is locked, no additional rules can be | ||
182 | * added to the policy. | ||
183 | */ | ||
184 | void ima_update_policy(void) | ||
185 | { | ||
186 | const char *op = "policy_update"; | ||
187 | const char *cause = "already exists"; | ||
188 | int result = 1; | ||
189 | int audit_info = 0; | ||
190 | |||
191 | if (ima_measure == &measure_default_rules) { | ||
192 | ima_measure = &measure_policy_rules; | ||
193 | cause = "complete"; | ||
194 | result = 0; | ||
195 | } | ||
196 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
197 | NULL, op, cause, result, audit_info); | ||
198 | } | ||
199 | |||
200 | enum { | ||
201 | Opt_err = -1, | ||
202 | Opt_measure = 1, Opt_dont_measure, | ||
203 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | ||
204 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | ||
205 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid | ||
206 | }; | ||
207 | |||
208 | static match_table_t policy_tokens = { | ||
209 | {Opt_measure, "measure"}, | ||
210 | {Opt_dont_measure, "dont_measure"}, | ||
211 | {Opt_obj_user, "obj_user=%s"}, | ||
212 | {Opt_obj_role, "obj_role=%s"}, | ||
213 | {Opt_obj_type, "obj_type=%s"}, | ||
214 | {Opt_subj_user, "subj_user=%s"}, | ||
215 | {Opt_subj_role, "subj_role=%s"}, | ||
216 | {Opt_subj_type, "subj_type=%s"}, | ||
217 | {Opt_func, "func=%s"}, | ||
218 | {Opt_mask, "mask=%s"}, | ||
219 | {Opt_fsmagic, "fsmagic=%s"}, | ||
220 | {Opt_uid, "uid=%s"}, | ||
221 | {Opt_err, NULL} | ||
222 | }; | ||
223 | |||
224 | static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | ||
225 | char *args, int lsm_rule, int audit_type) | ||
226 | { | ||
227 | int result; | ||
228 | |||
229 | entry->lsm[lsm_rule].type = audit_type; | ||
230 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, | ||
231 | AUDIT_EQUAL, args, | ||
232 | &entry->lsm[lsm_rule].rule); | ||
233 | return result; | ||
234 | } | ||
235 | |||
236 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | ||
237 | { | ||
238 | struct audit_buffer *ab; | ||
239 | char *p; | ||
240 | int result = 0; | ||
241 | |||
242 | ab = audit_log_start(current->audit_context, GFP_KERNEL, | ||
243 | AUDIT_INTEGRITY_STATUS); | ||
244 | |||
245 | entry->action = -1; | ||
246 | while ((p = strsep(&rule, " \n")) != NULL) { | ||
247 | substring_t args[MAX_OPT_ARGS]; | ||
248 | int token; | ||
249 | unsigned long lnum; | ||
250 | |||
251 | if (result < 0) | ||
252 | break; | ||
253 | if (!*p) | ||
254 | continue; | ||
255 | token = match_token(p, policy_tokens, args); | ||
256 | switch (token) { | ||
257 | case Opt_measure: | ||
258 | audit_log_format(ab, "%s ", "measure"); | ||
259 | entry->action = MEASURE; | ||
260 | break; | ||
261 | case Opt_dont_measure: | ||
262 | audit_log_format(ab, "%s ", "dont_measure"); | ||
263 | entry->action = DONT_MEASURE; | ||
264 | break; | ||
265 | case Opt_func: | ||
266 | audit_log_format(ab, "func=%s ", args[0].from); | ||
267 | if (strcmp(args[0].from, "PATH_CHECK") == 0) | ||
268 | entry->func = PATH_CHECK; | ||
269 | else if (strcmp(args[0].from, "FILE_MMAP") == 0) | ||
270 | entry->func = FILE_MMAP; | ||
271 | else if (strcmp(args[0].from, "BPRM_CHECK") == 0) | ||
272 | entry->func = BPRM_CHECK; | ||
273 | else | ||
274 | result = -EINVAL; | ||
275 | if (!result) | ||
276 | entry->flags |= IMA_FUNC; | ||
277 | break; | ||
278 | case Opt_mask: | ||
279 | audit_log_format(ab, "mask=%s ", args[0].from); | ||
280 | if ((strcmp(args[0].from, "MAY_EXEC")) == 0) | ||
281 | entry->mask = MAY_EXEC; | ||
282 | else if (strcmp(args[0].from, "MAY_WRITE") == 0) | ||
283 | entry->mask = MAY_WRITE; | ||
284 | else if (strcmp(args[0].from, "MAY_READ") == 0) | ||
285 | entry->mask = MAY_READ; | ||
286 | else if (strcmp(args[0].from, "MAY_APPEND") == 0) | ||
287 | entry->mask = MAY_APPEND; | ||
288 | else | ||
289 | result = -EINVAL; | ||
290 | if (!result) | ||
291 | entry->flags |= IMA_MASK; | ||
292 | break; | ||
293 | case Opt_fsmagic: | ||
294 | audit_log_format(ab, "fsmagic=%s ", args[0].from); | ||
295 | result = strict_strtoul(args[0].from, 16, | ||
296 | &entry->fsmagic); | ||
297 | if (!result) | ||
298 | entry->flags |= IMA_FSMAGIC; | ||
299 | break; | ||
300 | case Opt_uid: | ||
301 | audit_log_format(ab, "uid=%s ", args[0].from); | ||
302 | result = strict_strtoul(args[0].from, 10, &lnum); | ||
303 | if (!result) { | ||
304 | entry->uid = (uid_t) lnum; | ||
305 | if (entry->uid != lnum) | ||
306 | result = -EINVAL; | ||
307 | else | ||
308 | entry->flags |= IMA_UID; | ||
309 | } | ||
310 | break; | ||
311 | case Opt_obj_user: | ||
312 | audit_log_format(ab, "obj_user=%s ", args[0].from); | ||
313 | result = ima_lsm_rule_init(entry, args[0].from, | ||
314 | LSM_OBJ_USER, | ||
315 | AUDIT_OBJ_USER); | ||
316 | break; | ||
317 | case Opt_obj_role: | ||
318 | audit_log_format(ab, "obj_role=%s ", args[0].from); | ||
319 | result = ima_lsm_rule_init(entry, args[0].from, | ||
320 | LSM_OBJ_ROLE, | ||
321 | AUDIT_OBJ_ROLE); | ||
322 | break; | ||
323 | case Opt_obj_type: | ||
324 | audit_log_format(ab, "obj_type=%s ", args[0].from); | ||
325 | result = ima_lsm_rule_init(entry, args[0].from, | ||
326 | LSM_OBJ_TYPE, | ||
327 | AUDIT_OBJ_TYPE); | ||
328 | break; | ||
329 | case Opt_subj_user: | ||
330 | audit_log_format(ab, "subj_user=%s ", args[0].from); | ||
331 | result = ima_lsm_rule_init(entry, args[0].from, | ||
332 | LSM_SUBJ_USER, | ||
333 | AUDIT_SUBJ_USER); | ||
334 | break; | ||
335 | case Opt_subj_role: | ||
336 | audit_log_format(ab, "subj_role=%s ", args[0].from); | ||
337 | result = ima_lsm_rule_init(entry, args[0].from, | ||
338 | LSM_SUBJ_ROLE, | ||
339 | AUDIT_SUBJ_ROLE); | ||
340 | break; | ||
341 | case Opt_subj_type: | ||
342 | audit_log_format(ab, "subj_type=%s ", args[0].from); | ||
343 | result = ima_lsm_rule_init(entry, args[0].from, | ||
344 | LSM_SUBJ_TYPE, | ||
345 | AUDIT_SUBJ_TYPE); | ||
346 | break; | ||
347 | case Opt_err: | ||
348 | printk(KERN_INFO "%s: unknown token: %s\n", | ||
349 | __FUNCTION__, p); | ||
350 | break; | ||
351 | } | ||
352 | } | ||
353 | if (entry->action == UNKNOWN) | ||
354 | result = -EINVAL; | ||
355 | |||
356 | audit_log_format(ab, "res=%d", result); | ||
357 | audit_log_end(ab); | ||
358 | return result; | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * ima_parse_add_rule - add a rule to measure_policy_rules | ||
363 | * @rule - ima measurement policy rule | ||
364 | * | ||
365 | * Uses a mutex to protect the policy list from multiple concurrent writers. | ||
366 | * Returns 0 on success, an error code on failure. | ||
367 | */ | ||
368 | int ima_parse_add_rule(char *rule) | ||
369 | { | ||
370 | const char *op = "add_rule"; | ||
371 | struct ima_measure_rule_entry *entry; | ||
372 | int result = 0; | ||
373 | int audit_info = 0; | ||
374 | |||
375 | /* Prevent installed policy from changing */ | ||
376 | if (ima_measure != &measure_default_rules) { | ||
377 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
378 | NULL, op, "already exists", | ||
379 | -EACCES, audit_info); | ||
380 | return -EACCES; | ||
381 | } | ||
382 | |||
383 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
384 | if (!entry) { | ||
385 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | ||
386 | NULL, op, "-ENOMEM", -ENOMEM, audit_info); | ||
387 | return -ENOMEM; | ||
388 | } | ||
389 | |||
390 | INIT_LIST_HEAD(&entry->list); | ||
391 | |||
392 | result = ima_parse_rule(rule, entry); | ||
393 | if (!result) { | ||
394 | mutex_lock(&ima_measure_mutex); | ||
395 | list_add_tail(&entry->list, &measure_policy_rules); | ||
396 | mutex_unlock(&ima_measure_mutex); | ||
397 | } else | ||
398 | kfree(entry); | ||
399 | return result; | ||
400 | } | ||
401 | |||
402 | /* ima_delete_rules called to cleanup invalid policy */ | ||
403 | void ima_delete_rules(void) | ||
404 | { | ||
405 | struct ima_measure_rule_entry *entry, *tmp; | ||
406 | |||
407 | mutex_lock(&ima_measure_mutex); | ||
408 | list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { | ||
409 | list_del(&entry->list); | ||
410 | kfree(entry); | ||
411 | } | ||
412 | mutex_unlock(&ima_measure_mutex); | ||
413 | } | ||
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c new file mode 100644 index 00000000000..7ec94314ac0 --- /dev/null +++ b/security/integrity/ima/ima_queue.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005,2006,2007,2008 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Serge Hallyn <serue@us.ibm.com> | ||
6 | * Reiner Sailer <sailer@watson.ibm.com> | ||
7 | * Mimi Zohar <zohar@us.ibm.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation, version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | * File: ima_queue.c | ||
15 | * Implements queues that store template measurements and | ||
16 | * maintains aggregate over the stored measurements | ||
17 | * in the pre-configured TPM PCR (if available). | ||
18 | * The measurement list is append-only. No entry is | ||
19 | * ever removed or changed during the boot-cycle. | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/rculist.h> | ||
23 | #include "ima.h" | ||
24 | |||
25 | LIST_HEAD(ima_measurements); /* list of all measurements */ | ||
26 | |||
27 | /* key: inode (before secure-hashing a file) */ | ||
28 | struct ima_h_table ima_htable = { | ||
29 | .len = ATOMIC_LONG_INIT(0), | ||
30 | .violations = ATOMIC_LONG_INIT(0), | ||
31 | .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT | ||
32 | }; | ||
33 | |||
34 | /* mutex protects atomicity of extending measurement list | ||
35 | * and extending the TPM PCR aggregate. Since tpm_extend can take | ||
36 | * long (and the tpm driver uses a mutex), we can't use the spinlock. | ||
37 | */ | ||
38 | static DEFINE_MUTEX(ima_extend_list_mutex); | ||
39 | |||
40 | /* lookup up the digest value in the hash table, and return the entry */ | ||
41 | static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value) | ||
42 | { | ||
43 | struct ima_queue_entry *qe, *ret = NULL; | ||
44 | unsigned int key; | ||
45 | struct hlist_node *pos; | ||
46 | int rc; | ||
47 | |||
48 | key = ima_hash_key(digest_value); | ||
49 | rcu_read_lock(); | ||
50 | hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) { | ||
51 | rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE); | ||
52 | if (rc == 0) { | ||
53 | ret = qe; | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | rcu_read_unlock(); | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | /* ima_add_template_entry helper function: | ||
62 | * - Add template entry to measurement list and hash table. | ||
63 | * | ||
64 | * (Called with ima_extend_list_mutex held.) | ||
65 | */ | ||
66 | static int ima_add_digest_entry(struct ima_template_entry *entry) | ||
67 | { | ||
68 | struct ima_queue_entry *qe; | ||
69 | unsigned int key; | ||
70 | |||
71 | qe = kmalloc(sizeof(*qe), GFP_KERNEL); | ||
72 | if (qe == NULL) { | ||
73 | pr_err("OUT OF MEMORY ERROR creating queue entry.\n"); | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | qe->entry = entry; | ||
77 | |||
78 | INIT_LIST_HEAD(&qe->later); | ||
79 | list_add_tail_rcu(&qe->later, &ima_measurements); | ||
80 | |||
81 | atomic_long_inc(&ima_htable.len); | ||
82 | key = ima_hash_key(entry->digest); | ||
83 | hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int ima_pcr_extend(const u8 *hash) | ||
88 | { | ||
89 | int result = 0; | ||
90 | |||
91 | if (!ima_used_chip) | ||
92 | return result; | ||
93 | |||
94 | result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); | ||
95 | if (result != 0) | ||
96 | pr_err("Error Communicating to TPM chip\n"); | ||
97 | return result; | ||
98 | } | ||
99 | |||
100 | /* Add template entry to the measurement list and hash table, | ||
101 | * and extend the pcr. | ||
102 | */ | ||
103 | int ima_add_template_entry(struct ima_template_entry *entry, int violation, | ||
104 | const char *op, struct inode *inode) | ||
105 | { | ||
106 | u8 digest[IMA_DIGEST_SIZE]; | ||
107 | const char *audit_cause = "hash_added"; | ||
108 | int audit_info = 1; | ||
109 | int result = 0; | ||
110 | |||
111 | mutex_lock(&ima_extend_list_mutex); | ||
112 | if (!violation) { | ||
113 | memcpy(digest, entry->digest, sizeof digest); | ||
114 | if (ima_lookup_digest_entry(digest)) { | ||
115 | audit_cause = "hash_exists"; | ||
116 | goto out; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | result = ima_add_digest_entry(entry); | ||
121 | if (result < 0) { | ||
122 | audit_cause = "ENOMEM"; | ||
123 | audit_info = 0; | ||
124 | goto out; | ||
125 | } | ||
126 | |||
127 | if (violation) /* invalidate pcr */ | ||
128 | memset(digest, 0xff, sizeof digest); | ||
129 | |||
130 | result = ima_pcr_extend(digest); | ||
131 | if (result != 0) { | ||
132 | audit_cause = "TPM error"; | ||
133 | audit_info = 0; | ||
134 | } | ||
135 | out: | ||
136 | mutex_unlock(&ima_extend_list_mutex); | ||
137 | integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, entry->template_name, | ||
138 | op, audit_cause, result, audit_info); | ||
139 | return result; | ||
140 | } | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 00815973d41..a69d6f8970c 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -89,7 +89,7 @@ | |||
89 | #define XATTR_SELINUX_SUFFIX "selinux" | 89 | #define XATTR_SELINUX_SUFFIX "selinux" |
90 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX | 90 | #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX |
91 | 91 | ||
92 | #define NUM_SEL_MNT_OPTS 4 | 92 | #define NUM_SEL_MNT_OPTS 5 |
93 | 93 | ||
94 | extern unsigned int policydb_loaded_version; | 94 | extern unsigned int policydb_loaded_version; |
95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
@@ -353,6 +353,7 @@ enum { | |||
353 | Opt_fscontext = 2, | 353 | Opt_fscontext = 2, |
354 | Opt_defcontext = 3, | 354 | Opt_defcontext = 3, |
355 | Opt_rootcontext = 4, | 355 | Opt_rootcontext = 4, |
356 | Opt_labelsupport = 5, | ||
356 | }; | 357 | }; |
357 | 358 | ||
358 | static const match_table_t tokens = { | 359 | static const match_table_t tokens = { |
@@ -360,6 +361,7 @@ static const match_table_t tokens = { | |||
360 | {Opt_fscontext, FSCONTEXT_STR "%s"}, | 361 | {Opt_fscontext, FSCONTEXT_STR "%s"}, |
361 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, | 362 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, |
362 | {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, | 363 | {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, |
364 | {Opt_labelsupport, LABELSUPP_STR}, | ||
363 | {Opt_error, NULL}, | 365 | {Opt_error, NULL}, |
364 | }; | 366 | }; |
365 | 367 | ||
@@ -431,7 +433,7 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
431 | } | 433 | } |
432 | } | 434 | } |
433 | 435 | ||
434 | sbsec->initialized = 1; | 436 | sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP); |
435 | 437 | ||
436 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | 438 | if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) |
437 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", | 439 | printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", |
@@ -441,6 +443,12 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
441 | sb->s_id, sb->s_type->name, | 443 | sb->s_id, sb->s_type->name, |
442 | labeling_behaviors[sbsec->behavior-1]); | 444 | labeling_behaviors[sbsec->behavior-1]); |
443 | 445 | ||
446 | if (sbsec->behavior == SECURITY_FS_USE_GENFS || | ||
447 | sbsec->behavior == SECURITY_FS_USE_MNTPOINT || | ||
448 | sbsec->behavior == SECURITY_FS_USE_NONE || | ||
449 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | ||
450 | sbsec->flags &= ~SE_SBLABELSUPP; | ||
451 | |||
444 | /* Initialize the root inode. */ | 452 | /* Initialize the root inode. */ |
445 | rc = inode_doinit_with_dentry(root_inode, root); | 453 | rc = inode_doinit_with_dentry(root_inode, root); |
446 | 454 | ||
@@ -487,23 +495,22 @@ static int selinux_get_mnt_opts(const struct super_block *sb, | |||
487 | 495 | ||
488 | security_init_mnt_opts(opts); | 496 | security_init_mnt_opts(opts); |
489 | 497 | ||
490 | if (!sbsec->initialized) | 498 | if (!(sbsec->flags & SE_SBINITIALIZED)) |
491 | return -EINVAL; | 499 | return -EINVAL; |
492 | 500 | ||
493 | if (!ss_initialized) | 501 | if (!ss_initialized) |
494 | return -EINVAL; | 502 | return -EINVAL; |
495 | 503 | ||
496 | /* | 504 | tmp = sbsec->flags & SE_MNTMASK; |
497 | * if we ever use sbsec flags for anything other than tracking mount | ||
498 | * settings this is going to need a mask | ||
499 | */ | ||
500 | tmp = sbsec->flags; | ||
501 | /* count the number of mount options for this sb */ | 505 | /* count the number of mount options for this sb */ |
502 | for (i = 0; i < 8; i++) { | 506 | for (i = 0; i < 8; i++) { |
503 | if (tmp & 0x01) | 507 | if (tmp & 0x01) |
504 | opts->num_mnt_opts++; | 508 | opts->num_mnt_opts++; |
505 | tmp >>= 1; | 509 | tmp >>= 1; |
506 | } | 510 | } |
511 | /* Check if the Label support flag is set */ | ||
512 | if (sbsec->flags & SE_SBLABELSUPP) | ||
513 | opts->num_mnt_opts++; | ||
507 | 514 | ||
508 | opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); | 515 | opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); |
509 | if (!opts->mnt_opts) { | 516 | if (!opts->mnt_opts) { |
@@ -549,6 +556,10 @@ static int selinux_get_mnt_opts(const struct super_block *sb, | |||
549 | opts->mnt_opts[i] = context; | 556 | opts->mnt_opts[i] = context; |
550 | opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; | 557 | opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; |
551 | } | 558 | } |
559 | if (sbsec->flags & SE_SBLABELSUPP) { | ||
560 | opts->mnt_opts[i] = NULL; | ||
561 | opts->mnt_opts_flags[i++] = SE_SBLABELSUPP; | ||
562 | } | ||
552 | 563 | ||
553 | BUG_ON(i != opts->num_mnt_opts); | 564 | BUG_ON(i != opts->num_mnt_opts); |
554 | 565 | ||
@@ -562,8 +573,10 @@ out_free: | |||
562 | static int bad_option(struct superblock_security_struct *sbsec, char flag, | 573 | static int bad_option(struct superblock_security_struct *sbsec, char flag, |
563 | u32 old_sid, u32 new_sid) | 574 | u32 old_sid, u32 new_sid) |
564 | { | 575 | { |
576 | char mnt_flags = sbsec->flags & SE_MNTMASK; | ||
577 | |||
565 | /* check if the old mount command had the same options */ | 578 | /* check if the old mount command had the same options */ |
566 | if (sbsec->initialized) | 579 | if (sbsec->flags & SE_SBINITIALIZED) |
567 | if (!(sbsec->flags & flag) || | 580 | if (!(sbsec->flags & flag) || |
568 | (old_sid != new_sid)) | 581 | (old_sid != new_sid)) |
569 | return 1; | 582 | return 1; |
@@ -571,8 +584,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, | |||
571 | /* check if we were passed the same options twice, | 584 | /* check if we were passed the same options twice, |
572 | * aka someone passed context=a,context=b | 585 | * aka someone passed context=a,context=b |
573 | */ | 586 | */ |
574 | if (!sbsec->initialized) | 587 | if (!(sbsec->flags & SE_SBINITIALIZED)) |
575 | if (sbsec->flags & flag) | 588 | if (mnt_flags & flag) |
576 | return 1; | 589 | return 1; |
577 | return 0; | 590 | return 0; |
578 | } | 591 | } |
@@ -626,7 +639,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
626 | * this sb does not set any security options. (The first options | 639 | * this sb does not set any security options. (The first options |
627 | * will be used for both mounts) | 640 | * will be used for both mounts) |
628 | */ | 641 | */ |
629 | if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) | 642 | if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) |
630 | && (num_opts == 0)) | 643 | && (num_opts == 0)) |
631 | goto out; | 644 | goto out; |
632 | 645 | ||
@@ -637,6 +650,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
637 | */ | 650 | */ |
638 | for (i = 0; i < num_opts; i++) { | 651 | for (i = 0; i < num_opts; i++) { |
639 | u32 sid; | 652 | u32 sid; |
653 | |||
654 | if (flags[i] == SE_SBLABELSUPP) | ||
655 | continue; | ||
640 | rc = security_context_to_sid(mount_options[i], | 656 | rc = security_context_to_sid(mount_options[i], |
641 | strlen(mount_options[i]), &sid); | 657 | strlen(mount_options[i]), &sid); |
642 | if (rc) { | 658 | if (rc) { |
@@ -690,19 +706,19 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
690 | } | 706 | } |
691 | } | 707 | } |
692 | 708 | ||
693 | if (sbsec->initialized) { | 709 | if (sbsec->flags & SE_SBINITIALIZED) { |
694 | /* previously mounted with options, but not on this attempt? */ | 710 | /* previously mounted with options, but not on this attempt? */ |
695 | if (sbsec->flags && !num_opts) | 711 | if ((sbsec->flags & SE_MNTMASK) && !num_opts) |
696 | goto out_double_mount; | 712 | goto out_double_mount; |
697 | rc = 0; | 713 | rc = 0; |
698 | goto out; | 714 | goto out; |
699 | } | 715 | } |
700 | 716 | ||
701 | if (strcmp(sb->s_type->name, "proc") == 0) | 717 | if (strcmp(sb->s_type->name, "proc") == 0) |
702 | sbsec->proc = 1; | 718 | sbsec->flags |= SE_SBPROC; |
703 | 719 | ||
704 | /* Determine the labeling behavior to use for this filesystem type. */ | 720 | /* Determine the labeling behavior to use for this filesystem type. */ |
705 | rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); | 721 | rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); |
706 | if (rc) { | 722 | if (rc) { |
707 | printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", | 723 | printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", |
708 | __func__, sb->s_type->name, rc); | 724 | __func__, sb->s_type->name, rc); |
@@ -806,10 +822,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
806 | } | 822 | } |
807 | 823 | ||
808 | /* how can we clone if the old one wasn't set up?? */ | 824 | /* how can we clone if the old one wasn't set up?? */ |
809 | BUG_ON(!oldsbsec->initialized); | 825 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); |
810 | 826 | ||
811 | /* if fs is reusing a sb, just let its options stand... */ | 827 | /* if fs is reusing a sb, just let its options stand... */ |
812 | if (newsbsec->initialized) | 828 | if (newsbsec->flags & SE_SBINITIALIZED) |
813 | return; | 829 | return; |
814 | 830 | ||
815 | mutex_lock(&newsbsec->lock); | 831 | mutex_lock(&newsbsec->lock); |
@@ -917,7 +933,8 @@ static int selinux_parse_opts_str(char *options, | |||
917 | goto out_err; | 933 | goto out_err; |
918 | } | 934 | } |
919 | break; | 935 | break; |
920 | 936 | case Opt_labelsupport: | |
937 | break; | ||
921 | default: | 938 | default: |
922 | rc = -EINVAL; | 939 | rc = -EINVAL; |
923 | printk(KERN_WARNING "SELinux: unknown mount option\n"); | 940 | printk(KERN_WARNING "SELinux: unknown mount option\n"); |
@@ -999,7 +1016,12 @@ static void selinux_write_opts(struct seq_file *m, | |||
999 | char *prefix; | 1016 | char *prefix; |
1000 | 1017 | ||
1001 | for (i = 0; i < opts->num_mnt_opts; i++) { | 1018 | for (i = 0; i < opts->num_mnt_opts; i++) { |
1002 | char *has_comma = strchr(opts->mnt_opts[i], ','); | 1019 | char *has_comma; |
1020 | |||
1021 | if (opts->mnt_opts[i]) | ||
1022 | has_comma = strchr(opts->mnt_opts[i], ','); | ||
1023 | else | ||
1024 | has_comma = NULL; | ||
1003 | 1025 | ||
1004 | switch (opts->mnt_opts_flags[i]) { | 1026 | switch (opts->mnt_opts_flags[i]) { |
1005 | case CONTEXT_MNT: | 1027 | case CONTEXT_MNT: |
@@ -1014,6 +1036,10 @@ static void selinux_write_opts(struct seq_file *m, | |||
1014 | case DEFCONTEXT_MNT: | 1036 | case DEFCONTEXT_MNT: |
1015 | prefix = DEFCONTEXT_STR; | 1037 | prefix = DEFCONTEXT_STR; |
1016 | break; | 1038 | break; |
1039 | case SE_SBLABELSUPP: | ||
1040 | seq_putc(m, ','); | ||
1041 | seq_puts(m, LABELSUPP_STR); | ||
1042 | continue; | ||
1017 | default: | 1043 | default: |
1018 | BUG(); | 1044 | BUG(); |
1019 | }; | 1045 | }; |
@@ -1209,7 +1235,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1209 | goto out_unlock; | 1235 | goto out_unlock; |
1210 | 1236 | ||
1211 | sbsec = inode->i_sb->s_security; | 1237 | sbsec = inode->i_sb->s_security; |
1212 | if (!sbsec->initialized) { | 1238 | if (!(sbsec->flags & SE_SBINITIALIZED)) { |
1213 | /* Defer initialization until selinux_complete_init, | 1239 | /* Defer initialization until selinux_complete_init, |
1214 | after the initial policy is loaded and the security | 1240 | after the initial policy is loaded and the security |
1215 | server is ready to handle calls. */ | 1241 | server is ready to handle calls. */ |
@@ -1326,7 +1352,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1326 | /* Default to the fs superblock SID. */ | 1352 | /* Default to the fs superblock SID. */ |
1327 | isec->sid = sbsec->sid; | 1353 | isec->sid = sbsec->sid; |
1328 | 1354 | ||
1329 | if (sbsec->proc && !S_ISLNK(inode->i_mode)) { | 1355 | if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) { |
1330 | struct proc_inode *proci = PROC_I(inode); | 1356 | struct proc_inode *proci = PROC_I(inode); |
1331 | if (proci->pde) { | 1357 | if (proci->pde) { |
1332 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1358 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
@@ -1587,7 +1613,7 @@ static int may_create(struct inode *dir, | |||
1587 | if (rc) | 1613 | if (rc) |
1588 | return rc; | 1614 | return rc; |
1589 | 1615 | ||
1590 | if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { | 1616 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
1591 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); | 1617 | rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); |
1592 | if (rc) | 1618 | if (rc) |
1593 | return rc; | 1619 | return rc; |
@@ -1866,6 +1892,16 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
1866 | return cred_has_perm(old, new, PROCESS__SETCAP); | 1892 | return cred_has_perm(old, new, PROCESS__SETCAP); |
1867 | } | 1893 | } |
1868 | 1894 | ||
1895 | /* | ||
1896 | * (This comment used to live with the selinux_task_setuid hook, | ||
1897 | * which was removed). | ||
1898 | * | ||
1899 | * Since setuid only affects the current process, and since the SELinux | ||
1900 | * controls are not based on the Linux identity attributes, SELinux does not | ||
1901 | * need to control this operation. However, SELinux does control the use of | ||
1902 | * the CAP_SETUID and CAP_SETGID capabilities using the capable hook. | ||
1903 | */ | ||
1904 | |||
1869 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, | 1905 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, |
1870 | int cap, int audit) | 1906 | int cap, int audit) |
1871 | { | 1907 | { |
@@ -2156,11 +2192,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2156 | return 0; | 2192 | return 0; |
2157 | } | 2193 | } |
2158 | 2194 | ||
2159 | static int selinux_bprm_check_security(struct linux_binprm *bprm) | ||
2160 | { | ||
2161 | return secondary_ops->bprm_check_security(bprm); | ||
2162 | } | ||
2163 | |||
2164 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) | 2195 | static int selinux_bprm_secureexec(struct linux_binprm *bprm) |
2165 | { | 2196 | { |
2166 | const struct cred *cred = current_cred(); | 2197 | const struct cred *cred = current_cred(); |
@@ -2290,8 +2321,6 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) | |||
2290 | struct rlimit *rlim, *initrlim; | 2321 | struct rlimit *rlim, *initrlim; |
2291 | int rc, i; | 2322 | int rc, i; |
2292 | 2323 | ||
2293 | secondary_ops->bprm_committing_creds(bprm); | ||
2294 | |||
2295 | new_tsec = bprm->cred->security; | 2324 | new_tsec = bprm->cred->security; |
2296 | if (new_tsec->sid == new_tsec->osid) | 2325 | if (new_tsec->sid == new_tsec->osid) |
2297 | return; | 2326 | return; |
@@ -2337,8 +2366,6 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) | |||
2337 | int rc, i; | 2366 | int rc, i; |
2338 | unsigned long flags; | 2367 | unsigned long flags; |
2339 | 2368 | ||
2340 | secondary_ops->bprm_committed_creds(bprm); | ||
2341 | |||
2342 | osid = tsec->osid; | 2369 | osid = tsec->osid; |
2343 | sid = tsec->sid; | 2370 | sid = tsec->sid; |
2344 | 2371 | ||
@@ -2400,7 +2427,8 @@ static inline int selinux_option(char *option, int len) | |||
2400 | return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || | 2427 | return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || |
2401 | match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || | 2428 | match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || |
2402 | match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || | 2429 | match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || |
2403 | match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len)); | 2430 | match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) || |
2431 | match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len)); | ||
2404 | } | 2432 | } |
2405 | 2433 | ||
2406 | static inline void take_option(char **to, char *from, int *first, int len) | 2434 | static inline void take_option(char **to, char *from, int *first, int len) |
@@ -2513,11 +2541,6 @@ static int selinux_mount(char *dev_name, | |||
2513 | void *data) | 2541 | void *data) |
2514 | { | 2542 | { |
2515 | const struct cred *cred = current_cred(); | 2543 | const struct cred *cred = current_cred(); |
2516 | int rc; | ||
2517 | |||
2518 | rc = secondary_ops->sb_mount(dev_name, path, type, flags, data); | ||
2519 | if (rc) | ||
2520 | return rc; | ||
2521 | 2544 | ||
2522 | if (flags & MS_REMOUNT) | 2545 | if (flags & MS_REMOUNT) |
2523 | return superblock_has_perm(cred, path->mnt->mnt_sb, | 2546 | return superblock_has_perm(cred, path->mnt->mnt_sb, |
@@ -2530,11 +2553,6 @@ static int selinux_mount(char *dev_name, | |||
2530 | static int selinux_umount(struct vfsmount *mnt, int flags) | 2553 | static int selinux_umount(struct vfsmount *mnt, int flags) |
2531 | { | 2554 | { |
2532 | const struct cred *cred = current_cred(); | 2555 | const struct cred *cred = current_cred(); |
2533 | int rc; | ||
2534 | |||
2535 | rc = secondary_ops->sb_umount(mnt, flags); | ||
2536 | if (rc) | ||
2537 | return rc; | ||
2538 | 2556 | ||
2539 | return superblock_has_perm(cred, mnt->mnt_sb, | 2557 | return superblock_has_perm(cred, mnt->mnt_sb, |
2540 | FILESYSTEM__UNMOUNT, NULL); | 2558 | FILESYSTEM__UNMOUNT, NULL); |
@@ -2570,7 +2588,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2570 | sid = tsec->sid; | 2588 | sid = tsec->sid; |
2571 | newsid = tsec->create_sid; | 2589 | newsid = tsec->create_sid; |
2572 | 2590 | ||
2573 | if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { | 2591 | if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { |
2574 | rc = security_transition_sid(sid, dsec->sid, | 2592 | rc = security_transition_sid(sid, dsec->sid, |
2575 | inode_mode_to_security_class(inode->i_mode), | 2593 | inode_mode_to_security_class(inode->i_mode), |
2576 | &newsid); | 2594 | &newsid); |
@@ -2585,14 +2603,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2585 | } | 2603 | } |
2586 | 2604 | ||
2587 | /* Possibly defer initialization to selinux_complete_init. */ | 2605 | /* Possibly defer initialization to selinux_complete_init. */ |
2588 | if (sbsec->initialized) { | 2606 | if (sbsec->flags & SE_SBINITIALIZED) { |
2589 | struct inode_security_struct *isec = inode->i_security; | 2607 | struct inode_security_struct *isec = inode->i_security; |
2590 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 2608 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
2591 | isec->sid = newsid; | 2609 | isec->sid = newsid; |
2592 | isec->initialized = 1; | 2610 | isec->initialized = 1; |
2593 | } | 2611 | } |
2594 | 2612 | ||
2595 | if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 2613 | if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP)) |
2596 | return -EOPNOTSUPP; | 2614 | return -EOPNOTSUPP; |
2597 | 2615 | ||
2598 | if (name) { | 2616 | if (name) { |
@@ -2622,21 +2640,11 @@ static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int ma | |||
2622 | 2640 | ||
2623 | static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2641 | static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
2624 | { | 2642 | { |
2625 | int rc; | ||
2626 | |||
2627 | rc = secondary_ops->inode_link(old_dentry, dir, new_dentry); | ||
2628 | if (rc) | ||
2629 | return rc; | ||
2630 | return may_link(dir, old_dentry, MAY_LINK); | 2643 | return may_link(dir, old_dentry, MAY_LINK); |
2631 | } | 2644 | } |
2632 | 2645 | ||
2633 | static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) | 2646 | static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) |
2634 | { | 2647 | { |
2635 | int rc; | ||
2636 | |||
2637 | rc = secondary_ops->inode_unlink(dir, dentry); | ||
2638 | if (rc) | ||
2639 | return rc; | ||
2640 | return may_link(dir, dentry, MAY_UNLINK); | 2648 | return may_link(dir, dentry, MAY_UNLINK); |
2641 | } | 2649 | } |
2642 | 2650 | ||
@@ -2657,12 +2665,6 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) | |||
2657 | 2665 | ||
2658 | static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | 2666 | static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) |
2659 | { | 2667 | { |
2660 | int rc; | ||
2661 | |||
2662 | rc = secondary_ops->inode_mknod(dir, dentry, mode, dev); | ||
2663 | if (rc) | ||
2664 | return rc; | ||
2665 | |||
2666 | return may_create(dir, dentry, inode_mode_to_security_class(mode)); | 2668 | return may_create(dir, dentry, inode_mode_to_security_class(mode)); |
2667 | } | 2669 | } |
2668 | 2670 | ||
@@ -2682,22 +2684,13 @@ static int selinux_inode_readlink(struct dentry *dentry) | |||
2682 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) | 2684 | static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) |
2683 | { | 2685 | { |
2684 | const struct cred *cred = current_cred(); | 2686 | const struct cred *cred = current_cred(); |
2685 | int rc; | ||
2686 | 2687 | ||
2687 | rc = secondary_ops->inode_follow_link(dentry, nameidata); | ||
2688 | if (rc) | ||
2689 | return rc; | ||
2690 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); | 2688 | return dentry_has_perm(cred, NULL, dentry, FILE__READ); |
2691 | } | 2689 | } |
2692 | 2690 | ||
2693 | static int selinux_inode_permission(struct inode *inode, int mask) | 2691 | static int selinux_inode_permission(struct inode *inode, int mask) |
2694 | { | 2692 | { |
2695 | const struct cred *cred = current_cred(); | 2693 | const struct cred *cred = current_cred(); |
2696 | int rc; | ||
2697 | |||
2698 | rc = secondary_ops->inode_permission(inode, mask); | ||
2699 | if (rc) | ||
2700 | return rc; | ||
2701 | 2694 | ||
2702 | if (!mask) { | 2695 | if (!mask) { |
2703 | /* No permission to check. Existence test. */ | 2696 | /* No permission to check. Existence test. */ |
@@ -2711,11 +2704,6 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2711 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2704 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
2712 | { | 2705 | { |
2713 | const struct cred *cred = current_cred(); | 2706 | const struct cred *cred = current_cred(); |
2714 | int rc; | ||
2715 | |||
2716 | rc = secondary_ops->inode_setattr(dentry, iattr); | ||
2717 | if (rc) | ||
2718 | return rc; | ||
2719 | 2707 | ||
2720 | if (iattr->ia_valid & ATTR_FORCE) | 2708 | if (iattr->ia_valid & ATTR_FORCE) |
2721 | return 0; | 2709 | return 0; |
@@ -2769,7 +2757,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2769 | return selinux_inode_setotherxattr(dentry, name); | 2757 | return selinux_inode_setotherxattr(dentry, name); |
2770 | 2758 | ||
2771 | sbsec = inode->i_sb->s_security; | 2759 | sbsec = inode->i_sb->s_security; |
2772 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 2760 | if (!(sbsec->flags & SE_SBLABELSUPP)) |
2773 | return -EOPNOTSUPP; | 2761 | return -EOPNOTSUPP; |
2774 | 2762 | ||
2775 | if (!is_owner_or_cap(inode)) | 2763 | if (!is_owner_or_cap(inode)) |
@@ -2931,16 +2919,6 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t | |||
2931 | return len; | 2919 | return len; |
2932 | } | 2920 | } |
2933 | 2921 | ||
2934 | static int selinux_inode_need_killpriv(struct dentry *dentry) | ||
2935 | { | ||
2936 | return secondary_ops->inode_need_killpriv(dentry); | ||
2937 | } | ||
2938 | |||
2939 | static int selinux_inode_killpriv(struct dentry *dentry) | ||
2940 | { | ||
2941 | return secondary_ops->inode_killpriv(dentry); | ||
2942 | } | ||
2943 | |||
2944 | static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) | 2922 | static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) |
2945 | { | 2923 | { |
2946 | struct inode_security_struct *isec = inode->i_security; | 2924 | struct inode_security_struct *isec = inode->i_security; |
@@ -3078,18 +3056,13 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
3078 | unsigned long prot) | 3056 | unsigned long prot) |
3079 | { | 3057 | { |
3080 | const struct cred *cred = current_cred(); | 3058 | const struct cred *cred = current_cred(); |
3081 | int rc; | ||
3082 | |||
3083 | rc = secondary_ops->file_mprotect(vma, reqprot, prot); | ||
3084 | if (rc) | ||
3085 | return rc; | ||
3086 | 3059 | ||
3087 | if (selinux_checkreqprot) | 3060 | if (selinux_checkreqprot) |
3088 | prot = reqprot; | 3061 | prot = reqprot; |
3089 | 3062 | ||
3090 | #ifndef CONFIG_PPC32 | 3063 | #ifndef CONFIG_PPC32 |
3091 | if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { | 3064 | if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { |
3092 | rc = 0; | 3065 | int rc = 0; |
3093 | if (vma->vm_start >= vma->vm_mm->start_brk && | 3066 | if (vma->vm_start >= vma->vm_mm->start_brk && |
3094 | vma->vm_end <= vma->vm_mm->brk) { | 3067 | vma->vm_end <= vma->vm_mm->brk) { |
3095 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); | 3068 | rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP); |
@@ -3239,12 +3212,6 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3239 | 3212 | ||
3240 | static int selinux_task_create(unsigned long clone_flags) | 3213 | static int selinux_task_create(unsigned long clone_flags) |
3241 | { | 3214 | { |
3242 | int rc; | ||
3243 | |||
3244 | rc = secondary_ops->task_create(clone_flags); | ||
3245 | if (rc) | ||
3246 | return rc; | ||
3247 | |||
3248 | return current_has_perm(current, PROCESS__FORK); | 3215 | return current_has_perm(current, PROCESS__FORK); |
3249 | } | 3216 | } |
3250 | 3217 | ||
@@ -3278,14 +3245,6 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, | |||
3278 | } | 3245 | } |
3279 | 3246 | ||
3280 | /* | 3247 | /* |
3281 | * commit new credentials | ||
3282 | */ | ||
3283 | static void selinux_cred_commit(struct cred *new, const struct cred *old) | ||
3284 | { | ||
3285 | secondary_ops->cred_commit(new, old); | ||
3286 | } | ||
3287 | |||
3288 | /* | ||
3289 | * set the security data for a kernel service | 3248 | * set the security data for a kernel service |
3290 | * - all the creation contexts are set to unlabelled | 3249 | * - all the creation contexts are set to unlabelled |
3291 | */ | 3250 | */ |
@@ -3329,29 +3288,6 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
3329 | return 0; | 3288 | return 0; |
3330 | } | 3289 | } |
3331 | 3290 | ||
3332 | static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | ||
3333 | { | ||
3334 | /* Since setuid only affects the current process, and | ||
3335 | since the SELinux controls are not based on the Linux | ||
3336 | identity attributes, SELinux does not need to control | ||
3337 | this operation. However, SELinux does control the use | ||
3338 | of the CAP_SETUID and CAP_SETGID capabilities using the | ||
3339 | capable hook. */ | ||
3340 | return 0; | ||
3341 | } | ||
3342 | |||
3343 | static int selinux_task_fix_setuid(struct cred *new, const struct cred *old, | ||
3344 | int flags) | ||
3345 | { | ||
3346 | return secondary_ops->task_fix_setuid(new, old, flags); | ||
3347 | } | ||
3348 | |||
3349 | static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | ||
3350 | { | ||
3351 | /* See the comment for setuid above. */ | ||
3352 | return 0; | ||
3353 | } | ||
3354 | |||
3355 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) | 3291 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) |
3356 | { | 3292 | { |
3357 | return current_has_perm(p, PROCESS__SETPGID); | 3293 | return current_has_perm(p, PROCESS__SETPGID); |
@@ -3372,12 +3308,6 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid) | |||
3372 | *secid = task_sid(p); | 3308 | *secid = task_sid(p); |
3373 | } | 3309 | } |
3374 | 3310 | ||
3375 | static int selinux_task_setgroups(struct group_info *group_info) | ||
3376 | { | ||
3377 | /* See the comment for setuid above. */ | ||
3378 | return 0; | ||
3379 | } | ||
3380 | |||
3381 | static int selinux_task_setnice(struct task_struct *p, int nice) | 3311 | static int selinux_task_setnice(struct task_struct *p, int nice) |
3382 | { | 3312 | { |
3383 | int rc; | 3313 | int rc; |
@@ -3408,11 +3338,6 @@ static int selinux_task_getioprio(struct task_struct *p) | |||
3408 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) | 3338 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) |
3409 | { | 3339 | { |
3410 | struct rlimit *old_rlim = current->signal->rlim + resource; | 3340 | struct rlimit *old_rlim = current->signal->rlim + resource; |
3411 | int rc; | ||
3412 | |||
3413 | rc = secondary_ops->task_setrlimit(resource, new_rlim); | ||
3414 | if (rc) | ||
3415 | return rc; | ||
3416 | 3341 | ||
3417 | /* Control the ability to change the hard limit (whether | 3342 | /* Control the ability to change the hard limit (whether |
3418 | lowering or raising it), so that the hard limit can | 3343 | lowering or raising it), so that the hard limit can |
@@ -3451,10 +3376,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | |||
3451 | u32 perm; | 3376 | u32 perm; |
3452 | int rc; | 3377 | int rc; |
3453 | 3378 | ||
3454 | rc = secondary_ops->task_kill(p, info, sig, secid); | ||
3455 | if (rc) | ||
3456 | return rc; | ||
3457 | |||
3458 | if (!sig) | 3379 | if (!sig) |
3459 | perm = PROCESS__SIGNULL; /* null signal; existence test */ | 3380 | perm = PROCESS__SIGNULL; /* null signal; existence test */ |
3460 | else | 3381 | else |
@@ -3467,18 +3388,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | |||
3467 | return rc; | 3388 | return rc; |
3468 | } | 3389 | } |
3469 | 3390 | ||
3470 | static int selinux_task_prctl(int option, | ||
3471 | unsigned long arg2, | ||
3472 | unsigned long arg3, | ||
3473 | unsigned long arg4, | ||
3474 | unsigned long arg5) | ||
3475 | { | ||
3476 | /* The current prctl operations do not appear to require | ||
3477 | any SELinux controls since they merely observe or modify | ||
3478 | the state of the current process. */ | ||
3479 | return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5); | ||
3480 | } | ||
3481 | |||
3482 | static int selinux_task_wait(struct task_struct *p) | 3391 | static int selinux_task_wait(struct task_struct *p) |
3483 | { | 3392 | { |
3484 | return task_has_perm(p, current, PROCESS__SIGCHLD); | 3393 | return task_has_perm(p, current, PROCESS__SIGCHLD); |
@@ -4047,10 +3956,6 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
4047 | struct avc_audit_data ad; | 3956 | struct avc_audit_data ad; |
4048 | int err; | 3957 | int err; |
4049 | 3958 | ||
4050 | err = secondary_ops->unix_stream_connect(sock, other, newsk); | ||
4051 | if (err) | ||
4052 | return err; | ||
4053 | |||
4054 | isec = SOCK_INODE(sock)->i_security; | 3959 | isec = SOCK_INODE(sock)->i_security; |
4055 | other_isec = SOCK_INODE(other)->i_security; | 3960 | other_isec = SOCK_INODE(other)->i_security; |
4056 | 3961 | ||
@@ -5167,11 +5072,6 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, | |||
5167 | char __user *shmaddr, int shmflg) | 5072 | char __user *shmaddr, int shmflg) |
5168 | { | 5073 | { |
5169 | u32 perms; | 5074 | u32 perms; |
5170 | int rc; | ||
5171 | |||
5172 | rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg); | ||
5173 | if (rc) | ||
5174 | return rc; | ||
5175 | 5075 | ||
5176 | if (shmflg & SHM_RDONLY) | 5076 | if (shmflg & SHM_RDONLY) |
5177 | perms = SHM__READ; | 5077 | perms = SHM__READ; |
@@ -5581,7 +5481,6 @@ static struct security_operations selinux_ops = { | |||
5581 | .netlink_recv = selinux_netlink_recv, | 5481 | .netlink_recv = selinux_netlink_recv, |
5582 | 5482 | ||
5583 | .bprm_set_creds = selinux_bprm_set_creds, | 5483 | .bprm_set_creds = selinux_bprm_set_creds, |
5584 | .bprm_check_security = selinux_bprm_check_security, | ||
5585 | .bprm_committing_creds = selinux_bprm_committing_creds, | 5484 | .bprm_committing_creds = selinux_bprm_committing_creds, |
5586 | .bprm_committed_creds = selinux_bprm_committed_creds, | 5485 | .bprm_committed_creds = selinux_bprm_committed_creds, |
5587 | .bprm_secureexec = selinux_bprm_secureexec, | 5486 | .bprm_secureexec = selinux_bprm_secureexec, |
@@ -5623,8 +5522,6 @@ static struct security_operations selinux_ops = { | |||
5623 | .inode_getsecurity = selinux_inode_getsecurity, | 5522 | .inode_getsecurity = selinux_inode_getsecurity, |
5624 | .inode_setsecurity = selinux_inode_setsecurity, | 5523 | .inode_setsecurity = selinux_inode_setsecurity, |
5625 | .inode_listsecurity = selinux_inode_listsecurity, | 5524 | .inode_listsecurity = selinux_inode_listsecurity, |
5626 | .inode_need_killpriv = selinux_inode_need_killpriv, | ||
5627 | .inode_killpriv = selinux_inode_killpriv, | ||
5628 | .inode_getsecid = selinux_inode_getsecid, | 5525 | .inode_getsecid = selinux_inode_getsecid, |
5629 | 5526 | ||
5630 | .file_permission = selinux_file_permission, | 5527 | .file_permission = selinux_file_permission, |
@@ -5644,17 +5541,12 @@ static struct security_operations selinux_ops = { | |||
5644 | .task_create = selinux_task_create, | 5541 | .task_create = selinux_task_create, |
5645 | .cred_free = selinux_cred_free, | 5542 | .cred_free = selinux_cred_free, |
5646 | .cred_prepare = selinux_cred_prepare, | 5543 | .cred_prepare = selinux_cred_prepare, |
5647 | .cred_commit = selinux_cred_commit, | ||
5648 | .kernel_act_as = selinux_kernel_act_as, | 5544 | .kernel_act_as = selinux_kernel_act_as, |
5649 | .kernel_create_files_as = selinux_kernel_create_files_as, | 5545 | .kernel_create_files_as = selinux_kernel_create_files_as, |
5650 | .task_setuid = selinux_task_setuid, | ||
5651 | .task_fix_setuid = selinux_task_fix_setuid, | ||
5652 | .task_setgid = selinux_task_setgid, | ||
5653 | .task_setpgid = selinux_task_setpgid, | 5546 | .task_setpgid = selinux_task_setpgid, |
5654 | .task_getpgid = selinux_task_getpgid, | 5547 | .task_getpgid = selinux_task_getpgid, |
5655 | .task_getsid = selinux_task_getsid, | 5548 | .task_getsid = selinux_task_getsid, |
5656 | .task_getsecid = selinux_task_getsecid, | 5549 | .task_getsecid = selinux_task_getsecid, |
5657 | .task_setgroups = selinux_task_setgroups, | ||
5658 | .task_setnice = selinux_task_setnice, | 5550 | .task_setnice = selinux_task_setnice, |
5659 | .task_setioprio = selinux_task_setioprio, | 5551 | .task_setioprio = selinux_task_setioprio, |
5660 | .task_getioprio = selinux_task_getioprio, | 5552 | .task_getioprio = selinux_task_getioprio, |
@@ -5664,7 +5556,6 @@ static struct security_operations selinux_ops = { | |||
5664 | .task_movememory = selinux_task_movememory, | 5556 | .task_movememory = selinux_task_movememory, |
5665 | .task_kill = selinux_task_kill, | 5557 | .task_kill = selinux_task_kill, |
5666 | .task_wait = selinux_task_wait, | 5558 | .task_wait = selinux_task_wait, |
5667 | .task_prctl = selinux_task_prctl, | ||
5668 | .task_to_inode = selinux_task_to_inode, | 5559 | .task_to_inode = selinux_task_to_inode, |
5669 | 5560 | ||
5670 | .ipc_permission = selinux_ipc_permission, | 5561 | .ipc_permission = selinux_ipc_permission, |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 3cc45168f67..c4e062336ef 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -60,9 +60,7 @@ struct superblock_security_struct { | |||
60 | u32 def_sid; /* default SID for labeling */ | 60 | u32 def_sid; /* default SID for labeling */ |
61 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ | 61 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ |
62 | unsigned int behavior; /* labeling behavior */ | 62 | unsigned int behavior; /* labeling behavior */ |
63 | unsigned char initialized; /* initialization flag */ | ||
64 | unsigned char flags; /* which mount options were specified */ | 63 | unsigned char flags; /* which mount options were specified */ |
65 | unsigned char proc; /* proc fs */ | ||
66 | struct mutex lock; | 64 | struct mutex lock; |
67 | struct list_head isec_head; | 65 | struct list_head isec_head; |
68 | spinlock_t isec_lock; | 66 | spinlock_t isec_lock; |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 72447370bc9..e1d9db77998 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -37,15 +37,23 @@ | |||
37 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY | 37 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | /* Mask for just the mount related flags */ | ||
41 | #define SE_MNTMASK 0x0f | ||
42 | /* Super block security struct flags for mount options */ | ||
40 | #define CONTEXT_MNT 0x01 | 43 | #define CONTEXT_MNT 0x01 |
41 | #define FSCONTEXT_MNT 0x02 | 44 | #define FSCONTEXT_MNT 0x02 |
42 | #define ROOTCONTEXT_MNT 0x04 | 45 | #define ROOTCONTEXT_MNT 0x04 |
43 | #define DEFCONTEXT_MNT 0x08 | 46 | #define DEFCONTEXT_MNT 0x08 |
47 | /* Non-mount related flags */ | ||
48 | #define SE_SBINITIALIZED 0x10 | ||
49 | #define SE_SBPROC 0x20 | ||
50 | #define SE_SBLABELSUPP 0x40 | ||
44 | 51 | ||
45 | #define CONTEXT_STR "context=" | 52 | #define CONTEXT_STR "context=" |
46 | #define FSCONTEXT_STR "fscontext=" | 53 | #define FSCONTEXT_STR "fscontext=" |
47 | #define ROOTCONTEXT_STR "rootcontext=" | 54 | #define ROOTCONTEXT_STR "rootcontext=" |
48 | #define DEFCONTEXT_STR "defcontext=" | 55 | #define DEFCONTEXT_STR "defcontext=" |
56 | #define LABELSUPP_STR "seclabel" | ||
49 | 57 | ||
50 | struct netlbl_lsm_secattr; | 58 | struct netlbl_lsm_secattr; |
51 | 59 | ||