[ I don't know why this static checker warning is showing up only now
  two years later...  -dan ]

Hello John Johansen,

Commit 2e12c5f06017 ("apparmor: add additional flags to extended
permission.") from Jul 23, 2023 (linux-next), leads to the following
Smatch static checker warning:

security/apparmor/policy_unpack.c:780 unpack_pdb()
error: we previously assumed 'pdb->dfa' could be null (see line 753)

security/apparmor/policy_unpack.c
    712 static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
    713                       bool required_dfa, bool required_trans,
    714                       const char **info)
    715 {
    716         struct aa_policydb *pdb;
    717         void *pos = e->pos;
    718         int i, flags, error = -EPROTO;
    719         ssize_t size;
    720         u32 version = 0;
    721 
    722         pdb = aa_alloc_pdb(GFP_KERNEL);
    723         if (!pdb)
    724                 return -ENOMEM;
    725 
    726         size = unpack_perms_table(e, &pdb->perms);
    727         if (size < 0) {
    728                 error = size;
    729                 pdb->perms = NULL;
    730                 *info = "failed to unpack - perms";
    731                 goto fail;
    732         }
    733         pdb->size = size;
    734 
    735         if (pdb->perms) {
    736                 /* perms table present accept is index */
    737                 flags = TO_ACCEPT1_FLAG(YYTD_DATA32);
    738                 if (aa_unpack_u32(e, &version, "permsv") && version > 2)
    739                         /* accept2 used for dfa flags */
    740                         flags |= TO_ACCEPT2_FLAG(YYTD_DATA32);
    741         } else {
    742                 /* packed perms in accept1 and accept2 */
    743                 flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
    744                         TO_ACCEPT2_FLAG(YYTD_DATA32);
    745         }
    746 
    747         pdb->dfa = unpack_dfa(e, flags);
    748         if (IS_ERR(pdb->dfa)) {
    749                 error = PTR_ERR(pdb->dfa);
    750                 pdb->dfa = NULL;
    751                 *info = "failed to unpack - dfa";
    752                 goto fail;
    753         } else if (!pdb->dfa) {
    754                 if (required_dfa) {
    755                         *info = "missing required dfa";
    756                         goto fail;
    757                 }

Assume required_dfa is false.


    758         } else {
    759                 /*
    760                  * only unpack the following if a dfa is present
    761                  *
    762                  * sadly start was given different names for file and 
policydb
    763                  * but since it is optional we can try both
    764                  */
    765                 if (!aa_unpack_u32(e, &pdb->start[0], "start"))
    766                         /* default start state */
    767                         pdb->start[0] = DFA_START;
    768                 if (!aa_unpack_u32(e, &pdb->start[AA_CLASS_FILE], 
"dfa_start")) {
    769                         /* default start state for xmatch and file dfa 
*/
    770                         pdb->start[AA_CLASS_FILE] = DFA_START;
    771                 }        /* setup class index */
    772                 for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) {
    773                         pdb->start[i] = aa_dfa_next(pdb->dfa, 
pdb->start[0],
    774                                                     i);
    775                 }
    776         }
    777 
    778         if (pdb->perms && version <= 2) {
    779                 /* add dfa flags table missing in v2 */
--> 780                 u32 noents = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_lolen;
                                     ^^^^^^^^^^
Potential NULL pointer dereference

    781                 u16 tdflags = 
pdb->dfa->tables[YYTD_ID_ACCEPT]->td_flags;
    782                 size_t tsize = table_size(noents, tdflags);
    783 
    784                 pdb->dfa->tables[YYTD_ID_ACCEPT2] = kvzalloc(tsize, 
GFP_KERNEL);
    785                 if (!pdb->dfa->tables[YYTD_ID_ACCEPT2]) {
    786                         *info = "failed to alloc dfa flags table";
    787                         goto out;
    788                 }
    789                 pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_lolen = noents;
    790                 pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_flags = tdflags;
    791         }
    792         /*
    793          * Unfortunately due to a bug in earlier userspaces, a
    794          * transition table may be present even when the dfa is
    795          * not. For compatibility reasons unpack and discard.
    796          */
    797         if (!unpack_trans_table(e, &pdb->trans) && required_trans) {
    798                 *info = "failed to unpack profile transition table";
    799                 goto fail;
    800         }
    801 
    802         if (!pdb->dfa && pdb->trans.table)
    803                 aa_free_str_table(&pdb->trans);
    804 
    805         /* TODO: move compat mapping here, requires dfa merging first */
    806         /* TODO: move verify here, it has to be done after compat 
mappings */
    807 out:
    808         *policy = pdb;
    809         return 0;
    810 
    811 fail:
    812         aa_put_pdb(pdb);
    813         e->pos = pos;
    814         return error;
    815 }

regards,
dan carpenter

Reply via email to