diff options
Diffstat (limited to 'security/apparmor/policy_unpack.c')
-rw-r--r-- | security/apparmor/policy_unpack.c | 114 |
1 files changed, 86 insertions, 28 deletions
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 6dac7d77cb4d..080a26b11f01 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
@@ -333,8 +333,10 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e) | |||
333 | /* | 333 | /* |
334 | * The dfa is aligned with in the blob to 8 bytes | 334 | * The dfa is aligned with in the blob to 8 bytes |
335 | * from the beginning of the stream. | 335 | * from the beginning of the stream. |
336 | * alignment adjust needed by dfa unpack | ||
336 | */ | 337 | */ |
337 | size_t sz = blob - (char *)e->start; | 338 | size_t sz = blob - (char *) e->start - |
339 | ((e->pos - e->start) & 7); | ||
338 | size_t pad = ALIGN(sz, 8) - sz; | 340 | size_t pad = ALIGN(sz, 8) - sz; |
339 | int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | | 341 | int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | |
340 | TO_ACCEPT2_FLAG(YYTD_DATA32); | 342 | TO_ACCEPT2_FLAG(YYTD_DATA32); |
@@ -622,29 +624,41 @@ fail: | |||
622 | /** | 624 | /** |
623 | * verify_head - unpack serialized stream header | 625 | * verify_head - unpack serialized stream header |
624 | * @e: serialized data read head (NOT NULL) | 626 | * @e: serialized data read head (NOT NULL) |
627 | * @required: whether the header is required or optional | ||
625 | * @ns: Returns - namespace if one is specified else NULL (NOT NULL) | 628 | * @ns: Returns - namespace if one is specified else NULL (NOT NULL) |
626 | * | 629 | * |
627 | * Returns: error or 0 if header is good | 630 | * Returns: error or 0 if header is good |
628 | */ | 631 | */ |
629 | static int verify_header(struct aa_ext *e, const char **ns) | 632 | static int verify_header(struct aa_ext *e, int required, const char **ns) |
630 | { | 633 | { |
631 | int error = -EPROTONOSUPPORT; | 634 | int error = -EPROTONOSUPPORT; |
635 | const char *name = NULL; | ||
636 | *ns = NULL; | ||
637 | |||
632 | /* get the interface version */ | 638 | /* get the interface version */ |
633 | if (!unpack_u32(e, &e->version, "version")) { | 639 | if (!unpack_u32(e, &e->version, "version")) { |
634 | audit_iface(NULL, NULL, "invalid profile format", e, error); | 640 | if (required) { |
635 | return error; | 641 | audit_iface(NULL, NULL, "invalid profile format", e, |
636 | } | 642 | error); |
643 | return error; | ||
644 | } | ||
637 | 645 | ||
638 | /* check that the interface version is currently supported */ | 646 | /* check that the interface version is currently supported */ |
639 | if (e->version != 5) { | 647 | if (e->version != 5) { |
640 | audit_iface(NULL, NULL, "unsupported interface version", e, | 648 | audit_iface(NULL, NULL, "unsupported interface version", |
641 | error); | 649 | e, error); |
642 | return error; | 650 | return error; |
651 | } | ||
643 | } | 652 | } |
644 | 653 | ||
654 | |||
645 | /* read the namespace if present */ | 655 | /* read the namespace if present */ |
646 | if (!unpack_str(e, ns, "namespace")) | 656 | if (unpack_str(e, &name, "namespace")) { |
647 | *ns = NULL; | 657 | if (*ns && strcmp(*ns, name)) |
658 | audit_iface(NULL, NULL, "invalid ns change", e, error); | ||
659 | else if (!*ns) | ||
660 | *ns = name; | ||
661 | } | ||
648 | 662 | ||
649 | return 0; | 663 | return 0; |
650 | } | 664 | } |
@@ -693,18 +707,40 @@ static int verify_profile(struct aa_profile *profile) | |||
693 | return 0; | 707 | return 0; |
694 | } | 708 | } |
695 | 709 | ||
710 | void aa_load_ent_free(struct aa_load_ent *ent) | ||
711 | { | ||
712 | if (ent) { | ||
713 | aa_put_profile(ent->rename); | ||
714 | aa_put_profile(ent->old); | ||
715 | aa_put_profile(ent->new); | ||
716 | kzfree(ent); | ||
717 | } | ||
718 | } | ||
719 | |||
720 | struct aa_load_ent *aa_load_ent_alloc(void) | ||
721 | { | ||
722 | struct aa_load_ent *ent = kzalloc(sizeof(*ent), GFP_KERNEL); | ||
723 | if (ent) | ||
724 | INIT_LIST_HEAD(&ent->list); | ||
725 | return ent; | ||
726 | } | ||
727 | |||
696 | /** | 728 | /** |
697 | * aa_unpack - unpack packed binary profile data loaded from user space | 729 | * aa_unpack - unpack packed binary profile(s) data loaded from user space |
698 | * @udata: user data copied to kmem (NOT NULL) | 730 | * @udata: user data copied to kmem (NOT NULL) |
699 | * @size: the size of the user data | 731 | * @size: the size of the user data |
732 | * @lh: list to place unpacked profiles in a aa_repl_ws | ||
700 | * @ns: Returns namespace profile is in if specified else NULL (NOT NULL) | 733 | * @ns: Returns namespace profile is in if specified else NULL (NOT NULL) |
701 | * | 734 | * |
702 | * Unpack user data and return refcounted allocated profile or ERR_PTR | 735 | * Unpack user data and return refcounted allocated profile(s) stored in |
736 | * @lh in order of discovery, with the list chain stored in base.list | ||
737 | * or error | ||
703 | * | 738 | * |
704 | * Returns: profile else error pointer if fails to unpack | 739 | * Returns: profile(s) on @lh else error pointer if fails to unpack |
705 | */ | 740 | */ |
706 | struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns) | 741 | int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) |
707 | { | 742 | { |
743 | struct aa_load_ent *tmp, *ent; | ||
708 | struct aa_profile *profile = NULL; | 744 | struct aa_profile *profile = NULL; |
709 | int error; | 745 | int error; |
710 | struct aa_ext e = { | 746 | struct aa_ext e = { |
@@ -713,20 +749,42 @@ struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns) | |||
713 | .pos = udata, | 749 | .pos = udata, |
714 | }; | 750 | }; |
715 | 751 | ||
716 | error = verify_header(&e, ns); | 752 | *ns = NULL; |
717 | if (error) | 753 | while (e.pos < e.end) { |
718 | return ERR_PTR(error); | 754 | error = verify_header(&e, e.pos == e.start, ns); |
755 | if (error) | ||
756 | goto fail; | ||
719 | 757 | ||
720 | profile = unpack_profile(&e); | 758 | profile = unpack_profile(&e); |
721 | if (IS_ERR(profile)) | 759 | if (IS_ERR(profile)) { |
722 | return profile; | 760 | error = PTR_ERR(profile); |
761 | goto fail; | ||
762 | } | ||
763 | |||
764 | error = verify_profile(profile); | ||
765 | if (error) { | ||
766 | aa_put_profile(profile); | ||
767 | goto fail; | ||
768 | } | ||
769 | |||
770 | ent = aa_load_ent_alloc(); | ||
771 | if (!ent) { | ||
772 | error = -ENOMEM; | ||
773 | aa_put_profile(profile); | ||
774 | goto fail; | ||
775 | } | ||
723 | 776 | ||
724 | error = verify_profile(profile); | 777 | ent->new = profile; |
725 | if (error) { | 778 | list_add_tail(&ent->list, lh); |
726 | aa_put_profile(profile); | ||
727 | profile = ERR_PTR(error); | ||
728 | } | 779 | } |
729 | 780 | ||
730 | /* return refcount */ | 781 | return 0; |
731 | return profile; | 782 | |
783 | fail: | ||
784 | list_for_each_entry_safe(ent, tmp, lh, list) { | ||
785 | list_del_init(&ent->list); | ||
786 | aa_load_ent_free(ent); | ||
787 | } | ||
788 | |||
789 | return error; | ||
732 | } | 790 | } |