Merge tag 'apparmor-pr-2023-11-03' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / security / apparmor / policy_unpack.c
index 913ec8d0eb6392c517bc948e50bfb5bf7fdf1e7f..47ec097d6741fe0fc6c33bfc0c844f331f704f17 100644 (file)
 static void audit_cb(struct audit_buffer *ab, void *va)
 {
        struct common_audit_data *sa = va;
+       struct apparmor_audit_data *ad = aad(sa);
 
-       if (aad(sa)->iface.ns) {
+       if (ad->iface.ns) {
                audit_log_format(ab, " ns=");
-               audit_log_untrustedstring(ab, aad(sa)->iface.ns);
+               audit_log_untrustedstring(ab, ad->iface.ns);
        }
-       if (aad(sa)->name) {
+       if (ad->name) {
                audit_log_format(ab, " name=");
-               audit_log_untrustedstring(ab, aad(sa)->name);
+               audit_log_untrustedstring(ab, ad->name);
        }
-       if (aad(sa)->iface.pos)
-               audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos);
+       if (ad->iface.pos)
+               audit_log_format(ab, " offset=%ld", ad->iface.pos);
 }
 
 /**
@@ -63,18 +64,18 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
                       int error)
 {
        struct aa_profile *profile = labels_profile(aa_current_raw_label());
-       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
+       DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
        if (e)
-               aad(&sa)->iface.pos = e->pos - e->start;
-       aad(&sa)->iface.ns = ns_name;
+               ad.iface.pos = e->pos - e->start;
+       ad.iface.ns = ns_name;
        if (new)
-               aad(&sa)->name = new->base.hname;
+               ad.name = new->base.hname;
        else
-               aad(&sa)->name = name;
-       aad(&sa)->info = info;
-       aad(&sa)->error = error;
+               ad.name = name;
+       ad.info = info;
+       ad.error = error;
 
-       return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb);
+       return aa_audit(AUDIT_APPARMOR_STATUS, profile, &ad, audit_cb);
 }
 
 void __aa_loaddata_update(struct aa_loaddata *data, long revision)
@@ -705,24 +706,29 @@ fail_reset:
        return -EPROTO;
 }
 
-static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
+static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
                      bool required_dfa, bool required_trans,
                      const char **info)
 {
+       struct aa_policydb *pdb;
        void *pos = e->pos;
        int i, flags, error = -EPROTO;
        ssize_t size;
 
-       size = unpack_perms_table(e, &policy->perms);
+       pdb = aa_alloc_pdb(GFP_KERNEL);
+       if (!pdb)
+               return -ENOMEM;
+
+       size = unpack_perms_table(e, &pdb->perms);
        if (size < 0) {
                error = size;
-               policy->perms = NULL;
+               pdb->perms = NULL;
                *info = "failed to unpack - perms";
                goto fail;
        }
-       policy->size = size;
+       pdb->size = size;
 
-       if (policy->perms) {
+       if (pdb->perms) {
                /* perms table present accept is index */
                flags = TO_ACCEPT1_FLAG(YYTD_DATA32);
        } else {
@@ -731,13 +737,13 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
                        TO_ACCEPT2_FLAG(YYTD_DATA32);
        }
 
-       policy->dfa = unpack_dfa(e, flags);
-       if (IS_ERR(policy->dfa)) {
-               error = PTR_ERR(policy->dfa);
-               policy->dfa = NULL;
+       pdb->dfa = unpack_dfa(e, flags);
+       if (IS_ERR(pdb->dfa)) {
+               error = PTR_ERR(pdb->dfa);
+               pdb->dfa = NULL;
                *info = "failed to unpack - dfa";
                goto fail;
-       } else if (!policy->dfa) {
+       } else if (!pdb->dfa) {
                if (required_dfa) {
                        *info = "missing required dfa";
                        goto fail;
@@ -751,18 +757,18 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
         * sadly start was given different names for file and policydb
         * but since it is optional we can try both
         */
-       if (!aa_unpack_u32(e, &policy->start[0], "start"))
+       if (!aa_unpack_u32(e, &pdb->start[0], "start"))
                /* default start state */
-               policy->start[0] = DFA_START;
-       if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) {
+               pdb->start[0] = DFA_START;
+       if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], "dfa_start")) {
                /* default start state for xmatch and file dfa */
-               policy->start[AA_CLASS_FILE] = DFA_START;
+               pdb->start[AA_CLASS_FILE] = DFA_START;
        }       /* setup class index */
        for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) {
-               policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0],
+               pdb->start[i] = aa_dfa_next(pdb->dfa, pdb->start[0],
                                               i);
        }
-       if (!unpack_trans_table(e, &policy->trans) && required_trans) {
+       if (!unpack_trans_table(e, &pdb->trans) && required_trans) {
                *info = "failed to unpack profile transition table";
                goto fail;
        }
@@ -770,9 +776,11 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
        /* TODO: move compat mapping here, requires dfa merging first */
        /* TODO: move verify here, it has to be done after compat mappings */
 out:
+       *policy = pdb;
        return 0;
 
 fail:
+       aa_put_pdb(pdb);
        e->pos = pos;
        return error;
 }
@@ -807,7 +815,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
        const char *info = "failed to unpack profile";
        size_t ns_len;
        struct rhashtable_params params = { 0 };
-       char *key = NULL;
+       char *key = NULL, *disconnected = NULL;
        struct aa_data *data;
        int error = -EPROTO;
        kernel_cap_t tmpcap;
@@ -856,15 +864,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
        }
 
        /* neither xmatch_len not xmatch_perms are optional if xmatch is set */
-       if (profile->attach.xmatch.dfa) {
+       if (profile->attach.xmatch->dfa) {
                if (!aa_unpack_u32(e, &tmp, NULL)) {
                        info = "missing xmatch len";
                        goto fail;
                }
                profile->attach.xmatch_len = tmp;
-               profile->attach.xmatch.start[AA_CLASS_XMATCH] = DFA_START;
-               if (!profile->attach.xmatch.perms) {
-                       error = aa_compat_map_xmatch(&profile->attach.xmatch);
+               profile->attach.xmatch->start[AA_CLASS_XMATCH] = DFA_START;
+               if (!profile->attach.xmatch->perms) {
+                       error = aa_compat_map_xmatch(profile->attach.xmatch);
                        if (error) {
                                info = "failed to convert xmatch permission table";
                                goto fail;
@@ -873,7 +881,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
        }
 
        /* disconnected attachment string is optional */
-       (void) aa_unpack_str(e, &profile->disconnected, "disconnected");
+       (void) aa_unpack_strdup(e, &disconnected, "disconnected");
+       profile->disconnected = disconnected;
 
        /* per profile debug flags (complain, audit) */
        if (!aa_unpack_nameX(e, AA_STRUCT, "flags")) {
@@ -980,16 +989,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                if (error)
                        goto fail;
                /* Fixup: drop when we get rid of start array */
-               if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0],
+               if (aa_dfa_next(rules->policy->dfa, rules->policy->start[0],
                                AA_CLASS_FILE))
-                       rules->policy.start[AA_CLASS_FILE] =
-                         aa_dfa_next(rules->policy.dfa,
-                                     rules->policy.start[0],
+                       rules->policy->start[AA_CLASS_FILE] =
+                         aa_dfa_next(rules->policy->dfa,
+                                     rules->policy->start[0],
                                      AA_CLASS_FILE);
                if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
                        goto fail;
-               if (!rules->policy.perms) {
-                       error = aa_compat_map_policy(&rules->policy,
+               if (!rules->policy->perms) {
+                       error = aa_compat_map_policy(rules->policy,
                                                     e->version);
                        if (error) {
                                info = "failed to remap policydb permission table";
@@ -997,44 +1006,25 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                        }
                }
        } else {
-               rules->policy.dfa = aa_get_dfa(nulldfa);
-               rules->policy.perms = kcalloc(2, sizeof(struct aa_perms),
-                                             GFP_KERNEL);
-               if (!rules->policy.perms)
-                       goto fail;
-               rules->policy.size = 2;
+               rules->policy = aa_get_pdb(nullpdb);
        }
        /* get file rules */
        error = unpack_pdb(e, &rules->file, false, true, &info);
        if (error) {
                goto fail;
-       } else if (rules->file.dfa) {
-               if (!rules->file.perms) {
-                       error = aa_compat_map_file(&rules->file);
+       } else if (rules->file->dfa) {
+               if (!rules->file->perms) {
+                       error = aa_compat_map_file(rules->file);
                        if (error) {
                                info = "failed to remap file permission table";
                                goto fail;
                        }
                }
-       } else if (rules->policy.dfa &&
-                  rules->policy.start[AA_CLASS_FILE]) {
-               rules->file.dfa = aa_get_dfa(rules->policy.dfa);
-               rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE];
-               rules->file.perms = kcalloc(rules->policy.size,
-                                           sizeof(struct aa_perms),
-                                           GFP_KERNEL);
-               if (!rules->file.perms)
-                       goto fail;
-               memcpy(rules->file.perms, rules->policy.perms,
-                      rules->policy.size * sizeof(struct aa_perms));
-               rules->file.size = rules->policy.size;
+       } else if (rules->policy->dfa &&
+                  rules->policy->start[AA_CLASS_FILE]) {
+               rules->file = aa_get_pdb(rules->policy);
        } else {
-               rules->file.dfa = aa_get_dfa(nulldfa);
-               rules->file.perms = kcalloc(2, sizeof(struct aa_perms),
-                                           GFP_KERNEL);
-               if (!rules->file.perms)
-                       goto fail;
-               rules->file.size = 2;
+               rules->file = aa_get_pdb(nullpdb);
        }
        error = -EPROTO;
        if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
@@ -1170,7 +1160,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
 /**
  * verify_dfa_accept_index - verify accept indexes are in range of perms table
  * @dfa: the dfa to check accept indexes are in range
- * table_size: the permission table size the indexes should be within
+ * @table_size: the permission table size the indexes should be within
  */
 static bool verify_dfa_accept_index(struct aa_dfa *dfa, int table_size)
 {
@@ -1241,26 +1231,32 @@ static int verify_profile(struct aa_profile *profile)
        if (!rules)
                return 0;
 
-       if ((rules->file.dfa && !verify_dfa_accept_index(rules->file.dfa,
-                                                        rules->file.size)) ||
-           (rules->policy.dfa &&
-            !verify_dfa_accept_index(rules->policy.dfa, rules->policy.size))) {
+       if (rules->file->dfa && !verify_dfa_accept_index(rules->file->dfa,
+                                                       rules->file->size)) {
+               audit_iface(profile, NULL, NULL,
+                           "Unpack: file Invalid named transition", NULL,
+                           -EPROTO);
+               return -EPROTO;
+       }
+       if (rules->policy->dfa &&
+           !verify_dfa_accept_index(rules->policy->dfa, rules->policy->size)) {
                audit_iface(profile, NULL, NULL,
-                           "Unpack: Invalid named transition", NULL, -EPROTO);
+                           "Unpack: policy Invalid named transition", NULL,
+                           -EPROTO);
                return -EPROTO;
        }
 
-       if (!verify_perms(&rules->file)) {
+       if (!verify_perms(rules->file)) {
                audit_iface(profile, NULL, NULL,
                            "Unpack: Invalid perm index", NULL, -EPROTO);
                return -EPROTO;
        }
-       if (!verify_perms(&rules->policy)) {
+       if (!verify_perms(rules->policy)) {
                audit_iface(profile, NULL, NULL,
                            "Unpack: Invalid perm index", NULL, -EPROTO);
                return -EPROTO;
        }
-       if (!verify_perms(&profile->attach.xmatch)) {
+       if (!verify_perms(profile->attach.xmatch)) {
                audit_iface(profile, NULL, NULL,
                            "Unpack: Invalid perm index", NULL, -EPROTO);
                return -EPROTO;