diff options
Diffstat (limited to 'security/apparmor/policy_unpack.c')
-rw-r--r-- | security/apparmor/policy_unpack.c | 105 |
1 files changed, 87 insertions, 18 deletions
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index c600f4dd1783..5a2aec358322 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
@@ -85,9 +85,9 @@ static void audit_cb(struct audit_buffer *ab, void *va) | |||
85 | audit_log_format(ab, " ns="); | 85 | audit_log_format(ab, " ns="); |
86 | audit_log_untrustedstring(ab, aad(sa)->iface.ns); | 86 | audit_log_untrustedstring(ab, aad(sa)->iface.ns); |
87 | } | 87 | } |
88 | if (aad(sa)->iface.name) { | 88 | if (aad(sa)->name) { |
89 | audit_log_format(ab, " name="); | 89 | audit_log_format(ab, " name="); |
90 | audit_log_untrustedstring(ab, aad(sa)->iface.name); | 90 | audit_log_untrustedstring(ab, aad(sa)->name); |
91 | } | 91 | } |
92 | if (aad(sa)->iface.pos) | 92 | if (aad(sa)->iface.pos) |
93 | audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos); | 93 | audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos); |
@@ -114,9 +114,9 @@ static int audit_iface(struct aa_profile *new, const char *ns_name, | |||
114 | aad(&sa)->iface.pos = e->pos - e->start; | 114 | aad(&sa)->iface.pos = e->pos - e->start; |
115 | aad(&sa)->iface.ns = ns_name; | 115 | aad(&sa)->iface.ns = ns_name; |
116 | if (new) | 116 | if (new) |
117 | aad(&sa)->iface.name = new->base.hname; | 117 | aad(&sa)->name = new->base.hname; |
118 | else | 118 | else |
119 | aad(&sa)->iface.name = name; | 119 | aad(&sa)->name = name; |
120 | aad(&sa)->info = info; | 120 | aad(&sa)->info = info; |
121 | aad(&sa)->error = error; | 121 | aad(&sa)->error = error; |
122 | 122 | ||
@@ -275,6 +275,19 @@ fail: | |||
275 | return 0; | 275 | return 0; |
276 | } | 276 | } |
277 | 277 | ||
278 | static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) | ||
279 | { | ||
280 | if (unpack_nameX(e, AA_U16, name)) { | ||
281 | if (!inbounds(e, sizeof(u16))) | ||
282 | return 0; | ||
283 | if (data) | ||
284 | *data = le16_to_cpu(get_unaligned((__le16 *) e->pos)); | ||
285 | e->pos += sizeof(u16); | ||
286 | return 1; | ||
287 | } | ||
288 | return 0; | ||
289 | } | ||
290 | |||
278 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) | 291 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) |
279 | { | 292 | { |
280 | if (unpack_nameX(e, AA_U32, name)) { | 293 | if (unpack_nameX(e, AA_U32, name)) { |
@@ -448,7 +461,7 @@ fail: | |||
448 | */ | 461 | */ |
449 | static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile) | 462 | static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile) |
450 | { | 463 | { |
451 | void *pos = e->pos; | 464 | void *saved_pos = e->pos; |
452 | 465 | ||
453 | /* exec table is optional */ | 466 | /* exec table is optional */ |
454 | if (unpack_nameX(e, AA_STRUCT, "xtable")) { | 467 | if (unpack_nameX(e, AA_STRUCT, "xtable")) { |
@@ -511,7 +524,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile) | |||
511 | 524 | ||
512 | fail: | 525 | fail: |
513 | aa_free_domain_entries(&profile->file.trans); | 526 | aa_free_domain_entries(&profile->file.trans); |
514 | e->pos = pos; | 527 | e->pos = saved_pos; |
515 | return 0; | 528 | return 0; |
516 | } | 529 | } |
517 | 530 | ||
@@ -583,7 +596,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
583 | { | 596 | { |
584 | struct aa_profile *profile = NULL; | 597 | struct aa_profile *profile = NULL; |
585 | const char *tmpname, *tmpns = NULL, *name = NULL; | 598 | const char *tmpname, *tmpns = NULL, *name = NULL; |
586 | size_t ns_len; | 599 | const char *info = "failed to unpack profile"; |
600 | size_t size = 0, ns_len; | ||
587 | struct rhashtable_params params = { 0 }; | 601 | struct rhashtable_params params = { 0 }; |
588 | char *key = NULL; | 602 | char *key = NULL; |
589 | struct aa_data *data; | 603 | struct aa_data *data; |
@@ -604,8 +618,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
604 | tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len); | 618 | tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len); |
605 | if (tmpns) { | 619 | if (tmpns) { |
606 | *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL); | 620 | *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL); |
607 | if (!*ns_name) | 621 | if (!*ns_name) { |
622 | info = "out of memory"; | ||
608 | goto fail; | 623 | goto fail; |
624 | } | ||
609 | name = tmpname; | 625 | name = tmpname; |
610 | } | 626 | } |
611 | 627 | ||
@@ -624,12 +640,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
624 | if (IS_ERR(profile->xmatch)) { | 640 | if (IS_ERR(profile->xmatch)) { |
625 | error = PTR_ERR(profile->xmatch); | 641 | error = PTR_ERR(profile->xmatch); |
626 | profile->xmatch = NULL; | 642 | profile->xmatch = NULL; |
643 | info = "bad xmatch"; | ||
627 | goto fail; | 644 | goto fail; |
628 | } | 645 | } |
629 | /* xmatch_len is not optional if xmatch is set */ | 646 | /* xmatch_len is not optional if xmatch is set */ |
630 | if (profile->xmatch) { | 647 | if (profile->xmatch) { |
631 | if (!unpack_u32(e, &tmp, NULL)) | 648 | if (!unpack_u32(e, &tmp, NULL)) { |
649 | info = "missing xmatch len"; | ||
632 | goto fail; | 650 | goto fail; |
651 | } | ||
633 | profile->xmatch_len = tmp; | 652 | profile->xmatch_len = tmp; |
634 | } | 653 | } |
635 | 654 | ||
@@ -637,8 +656,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
637 | (void) unpack_str(e, &profile->disconnected, "disconnected"); | 656 | (void) unpack_str(e, &profile->disconnected, "disconnected"); |
638 | 657 | ||
639 | /* per profile debug flags (complain, audit) */ | 658 | /* per profile debug flags (complain, audit) */ |
640 | if (!unpack_nameX(e, AA_STRUCT, "flags")) | 659 | if (!unpack_nameX(e, AA_STRUCT, "flags")) { |
660 | info = "profile missing flags"; | ||
641 | goto fail; | 661 | goto fail; |
662 | } | ||
663 | info = "failed to unpack profile flags"; | ||
642 | if (!unpack_u32(e, &tmp, NULL)) | 664 | if (!unpack_u32(e, &tmp, NULL)) |
643 | goto fail; | 665 | goto fail; |
644 | if (tmp & PACKED_FLAG_HAT) | 666 | if (tmp & PACKED_FLAG_HAT) |
@@ -667,6 +689,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
667 | /* set a default value if path_flags field is not present */ | 689 | /* set a default value if path_flags field is not present */ |
668 | profile->path_flags = PATH_MEDIATE_DELETED; | 690 | profile->path_flags = PATH_MEDIATE_DELETED; |
669 | 691 | ||
692 | info = "failed to unpack profile capabilities"; | ||
670 | if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL)) | 693 | if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL)) |
671 | goto fail; | 694 | goto fail; |
672 | if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL)) | 695 | if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL)) |
@@ -676,6 +699,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
676 | if (!unpack_u32(e, &tmpcap.cap[0], NULL)) | 699 | if (!unpack_u32(e, &tmpcap.cap[0], NULL)) |
677 | goto fail; | 700 | goto fail; |
678 | 701 | ||
702 | info = "failed to unpack upper profile capabilities"; | ||
679 | if (unpack_nameX(e, AA_STRUCT, "caps64")) { | 703 | if (unpack_nameX(e, AA_STRUCT, "caps64")) { |
680 | /* optional upper half of 64 bit caps */ | 704 | /* optional upper half of 64 bit caps */ |
681 | if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL)) | 705 | if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL)) |
@@ -690,6 +714,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
690 | goto fail; | 714 | goto fail; |
691 | } | 715 | } |
692 | 716 | ||
717 | info = "failed to unpack extended profile capabilities"; | ||
693 | if (unpack_nameX(e, AA_STRUCT, "capsx")) { | 718 | if (unpack_nameX(e, AA_STRUCT, "capsx")) { |
694 | /* optional extended caps mediation mask */ | 719 | /* optional extended caps mediation mask */ |
695 | if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL)) | 720 | if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL)) |
@@ -700,11 +725,46 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
700 | goto fail; | 725 | goto fail; |
701 | } | 726 | } |
702 | 727 | ||
703 | if (!unpack_rlimits(e, profile)) | 728 | if (!unpack_rlimits(e, profile)) { |
729 | info = "failed to unpack profile rlimits"; | ||
704 | goto fail; | 730 | goto fail; |
731 | } | ||
732 | |||
733 | size = unpack_array(e, "net_allowed_af"); | ||
734 | if (size) { | ||
735 | |||
736 | for (i = 0; i < size; i++) { | ||
737 | /* discard extraneous rules that this kernel will | ||
738 | * never request | ||
739 | */ | ||
740 | if (i >= AF_MAX) { | ||
741 | u16 tmp; | ||
742 | |||
743 | if (!unpack_u16(e, &tmp, NULL) || | ||
744 | !unpack_u16(e, &tmp, NULL) || | ||
745 | !unpack_u16(e, &tmp, NULL)) | ||
746 | goto fail; | ||
747 | continue; | ||
748 | } | ||
749 | if (!unpack_u16(e, &profile->net.allow[i], NULL)) | ||
750 | goto fail; | ||
751 | if (!unpack_u16(e, &profile->net.audit[i], NULL)) | ||
752 | goto fail; | ||
753 | if (!unpack_u16(e, &profile->net.quiet[i], NULL)) | ||
754 | goto fail; | ||
755 | } | ||
756 | if (!unpack_nameX(e, AA_ARRAYEND, NULL)) | ||
757 | goto fail; | ||
758 | } | ||
759 | if (VERSION_LT(e->version, v7)) { | ||
760 | /* pre v7 policy always allowed these */ | ||
761 | profile->net.allow[AF_UNIX] = 0xffff; | ||
762 | profile->net.allow[AF_NETLINK] = 0xffff; | ||
763 | } | ||
705 | 764 | ||
706 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { | 765 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { |
707 | /* generic policy dfa - optional and may be NULL */ | 766 | /* generic policy dfa - optional and may be NULL */ |
767 | info = "failed to unpack policydb"; | ||
708 | profile->policy.dfa = unpack_dfa(e); | 768 | profile->policy.dfa = unpack_dfa(e); |
709 | if (IS_ERR(profile->policy.dfa)) { | 769 | if (IS_ERR(profile->policy.dfa)) { |
710 | error = PTR_ERR(profile->policy.dfa); | 770 | error = PTR_ERR(profile->policy.dfa); |
@@ -734,6 +794,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
734 | if (IS_ERR(profile->file.dfa)) { | 794 | if (IS_ERR(profile->file.dfa)) { |
735 | error = PTR_ERR(profile->file.dfa); | 795 | error = PTR_ERR(profile->file.dfa); |
736 | profile->file.dfa = NULL; | 796 | profile->file.dfa = NULL; |
797 | info = "failed to unpack profile file rules"; | ||
737 | goto fail; | 798 | goto fail; |
738 | } else if (profile->file.dfa) { | 799 | } else if (profile->file.dfa) { |
739 | if (!unpack_u32(e, &profile->file.start, "dfa_start")) | 800 | if (!unpack_u32(e, &profile->file.start, "dfa_start")) |
@@ -746,10 +807,13 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
746 | } else | 807 | } else |
747 | profile->file.dfa = aa_get_dfa(nulldfa); | 808 | profile->file.dfa = aa_get_dfa(nulldfa); |
748 | 809 | ||
749 | if (!unpack_trans_table(e, profile)) | 810 | if (!unpack_trans_table(e, profile)) { |
811 | info = "failed to unpack profile transition table"; | ||
750 | goto fail; | 812 | goto fail; |
813 | } | ||
751 | 814 | ||
752 | if (unpack_nameX(e, AA_STRUCT, "data")) { | 815 | if (unpack_nameX(e, AA_STRUCT, "data")) { |
816 | info = "out of memory"; | ||
753 | profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL); | 817 | profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL); |
754 | if (!profile->data) | 818 | if (!profile->data) |
755 | goto fail; | 819 | goto fail; |
@@ -761,8 +825,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
761 | params.hashfn = strhash; | 825 | params.hashfn = strhash; |
762 | params.obj_cmpfn = datacmp; | 826 | params.obj_cmpfn = datacmp; |
763 | 827 | ||
764 | if (rhashtable_init(profile->data, ¶ms)) | 828 | if (rhashtable_init(profile->data, ¶ms)) { |
829 | info = "failed to init key, value hash table"; | ||
765 | goto fail; | 830 | goto fail; |
831 | } | ||
766 | 832 | ||
767 | while (unpack_strdup(e, &key, NULL)) { | 833 | while (unpack_strdup(e, &key, NULL)) { |
768 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 834 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
@@ -784,12 +850,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
784 | profile->data->p); | 850 | profile->data->p); |
785 | } | 851 | } |
786 | 852 | ||
787 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) | 853 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) { |
854 | info = "failed to unpack end of key, value data table"; | ||
788 | goto fail; | 855 | goto fail; |
856 | } | ||
789 | } | 857 | } |
790 | 858 | ||
791 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) | 859 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) { |
860 | info = "failed to unpack end of profile"; | ||
792 | goto fail; | 861 | goto fail; |
862 | } | ||
793 | 863 | ||
794 | return profile; | 864 | return profile; |
795 | 865 | ||
@@ -798,8 +868,7 @@ fail: | |||
798 | name = NULL; | 868 | name = NULL; |
799 | else if (!name) | 869 | else if (!name) |
800 | name = "unknown"; | 870 | name = "unknown"; |
801 | audit_iface(profile, NULL, name, "failed to unpack profile", e, | 871 | audit_iface(profile, NULL, name, info, e, error); |
802 | error); | ||
803 | aa_free_profile(profile); | 872 | aa_free_profile(profile); |
804 | 873 | ||
805 | return ERR_PTR(error); | 874 | return ERR_PTR(error); |
@@ -832,7 +901,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns) | |||
832 | * if not specified use previous version | 901 | * if not specified use previous version |
833 | * Mask off everything that is not kernel abi version | 902 | * Mask off everything that is not kernel abi version |
834 | */ | 903 | */ |
835 | if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) { | 904 | if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) { |
836 | audit_iface(NULL, NULL, NULL, "unsupported interface version", | 905 | audit_iface(NULL, NULL, NULL, "unsupported interface version", |
837 | e, error); | 906 | e, error); |
838 | return error; | 907 | return error; |