aboutsummaryrefslogtreecommitdiffstats
path: root/security/apparmor/policy_unpack.c
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2013-07-11 00:05:43 -0400
committerJohn Johansen <john.johansen@canonical.com>2013-08-14 14:42:06 -0400
commitdd51c84857630e77c139afe4d9bba65fc051dc3f (patch)
tree2dbfb9435feadac6123600aef75004ee2197f6af /security/apparmor/policy_unpack.c
parent9d910a3bc01008d432b3bb79a69e7e3cdb4821b2 (diff)
apparmor: provide base for multiple profiles to be replaced at once
previously profiles had to be loaded one at a time, which could result in cases where a replacement of a set would partially succeed, and then fail resulting in inconsistent policy. Allow multiple profiles to replaced "atomically" so that the replacement either succeeds or fails for the entire set of profiles. Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/policy_unpack.c')
-rw-r--r--security/apparmor/policy_unpack.c114
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 */
629static int verify_header(struct aa_ext *e, const char **ns) 632static 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
710void 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
720struct 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 */
706struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns) 741int 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
783fail:
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}