Skip to content

Commit 0256b0a

Browse files
Dan Carpenterpcmoore
authored andcommitted
selinux: fix error handling bugs in security_load_policy()
There are a few bugs in the error handling for security_load_policy(). 1) If the newpolicy->sidtab allocation fails then it leads to a NULL dereference. Also the error code was not set to -ENOMEM on that path. 2) If policydb_read() failed then we call policydb_destroy() twice which meands we call kvfree(p->sym_val_to_name[i]) twice. 3) If policydb_load_isids() failed then we call sidtab_destroy() twice and that results in a double free in the sidtab_destroy_tree() function because entry.ptr_inner and entry.ptr_leaf are not set to NULL. One thing that makes this code nice to deal with is that none of the functions return partially allocated data. In other words, the policydb_read() either allocates everything successfully or it frees all the data it allocates. It never returns a mix of allocated and not allocated data. I re-wrote this to only free the successfully allocated data which avoids the double frees. I also re-ordered selinux_policy_free() so it's in the reverse order of the allocation function. Fixes: c7c556f ("selinux: refactor changing booleans") Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> [PM: partially merged by hand due to merge fuzz] Signed-off-by: Paul Moore <paul@paul-moore.com>
1 parent 1b8b31a commit 0256b0a

1 file changed

Lines changed: 23 additions & 11 deletions

File tree

security/selinux/ss/services.c

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,10 +2145,10 @@ static void selinux_policy_free(struct selinux_policy *policy)
21452145
if (!policy)
21462146
return;
21472147

2148-
policydb_destroy(&policy->policydb);
21492148
sidtab_destroy(policy->sidtab);
2150-
kfree(policy->sidtab);
21512149
kfree(policy->map.mapping);
2150+
policydb_destroy(&policy->policydb);
2151+
kfree(policy->sidtab);
21522152
kfree(policy);
21532153
}
21542154

@@ -2263,23 +2263,25 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
22632263
return -ENOMEM;
22642264

22652265
newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
2266-
if (!newpolicy->sidtab)
2267-
goto err;
2266+
if (!newpolicy->sidtab) {
2267+
rc = -ENOMEM;
2268+
goto err_policy;
2269+
}
22682270

22692271
rc = policydb_read(&newpolicy->policydb, fp);
22702272
if (rc)
2271-
goto err;
2273+
goto err_sidtab;
22722274

22732275
newpolicy->policydb.len = len;
22742276
rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
22752277
&newpolicy->map);
22762278
if (rc)
2277-
goto err;
2279+
goto err_policydb;
22782280

22792281
rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
22802282
if (rc) {
22812283
pr_err("SELinux: unable to load the initial SIDs\n");
2282-
goto err;
2284+
goto err_mapping;
22832285
}
22842286

22852287

@@ -2301,7 +2303,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
23012303
rc = security_preserve_bools(oldpolicy, newpolicy);
23022304
if (rc) {
23032305
pr_err("SELinux: unable to preserve booleans\n");
2304-
goto err;
2306+
goto err_free_isids;
23052307
}
23062308

23072309
/*
@@ -2321,13 +2323,23 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
23212323
pr_err("SELinux: unable to convert the internal"
23222324
" representation of contexts in the new SID"
23232325
" table\n");
2324-
goto err;
2326+
goto err_free_isids;
23252327
}
23262328

23272329
*newpolicyp = newpolicy;
23282330
return 0;
2329-
err:
2330-
selinux_policy_free(newpolicy);
2331+
2332+
err_free_isids:
2333+
sidtab_destroy(newpolicy->sidtab);
2334+
err_mapping:
2335+
kfree(newpolicy->map.mapping);
2336+
err_policydb:
2337+
policydb_destroy(&newpolicy->policydb);
2338+
err_sidtab:
2339+
kfree(newpolicy->sidtab);
2340+
err_policy:
2341+
kfree(newpolicy);
2342+
23312343
return rc;
23322344
}
23332345

0 commit comments

Comments
 (0)