Skip to content

Commit 6e11542

Browse files
committed
3
1 parent ab85139 commit 6e11542

1 file changed

Lines changed: 39 additions & 18 deletions

File tree

kernel/selinux/sepolicy.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,34 +1218,55 @@ struct selinux_policy *ksu_dup_sepolicy(struct selinux_policy *old_pol)
12181218
{
12191219
int ret;
12201220
size_t len;
1221+
size_t actual_len;
1222+
size_t alloc_len;
12211223
struct selinux_policy *new_pol;
12221224
void *data;
12231225
struct policy_file fp;
1226+
int attempt;
12241227

12251228
len = old_pol->policydb.len;
1229+
alloc_len = len;
12261230
pr_info("sepolicy: duplicating live policy len=%zu\n", len);
1227-
data = vmalloc(len);
1228-
if (!data) {
1229-
pr_err("alloc policy len %ld\n", len);
1230-
ret = -ENOMEM;
1231-
goto out_free_data;
1232-
}
12331231

1234-
fp.data = data;
1235-
fp.len = len;
1232+
data = NULL;
1233+
for (attempt = 0; attempt < 4; attempt++) {
1234+
data = vmalloc(alloc_len);
1235+
if (!data) {
1236+
pr_err("alloc policy len %zu\n", alloc_len);
1237+
ret = -ENOMEM;
1238+
goto out_free_data;
1239+
}
12361240

1237-
ret = policydb_write(&old_pol->policydb, &fp);
1238-
if (ret) {
1239-
pr_err("sepolicy: policydb_write: %d\n", ret);
1240-
goto out_free_data;
1241+
fp.data = data;
1242+
fp.len = alloc_len;
1243+
1244+
ret = policydb_write(&old_pol->policydb, &fp);
1245+
if (!ret)
1246+
break;
1247+
1248+
kvfree(data);
1249+
data = NULL;
1250+
1251+
if (ret != -EINVAL || alloc_len > (SIZE_MAX >> 1)) {
1252+
pr_err("sepolicy: policydb_write: %d\n", ret);
1253+
goto out_free_data;
1254+
}
1255+
1256+
alloc_len <<= 1;
1257+
pr_warn("sepolicy: policydb_write buffer too small, retry with len=%zu\n", alloc_len);
12411258
}
1242-
pr_info("sepolicy: policydb_write complete len=%zu\n", len);
1259+
if (ret)
1260+
goto out_free_data;
1261+
1262+
actual_len = (size_t)((unsigned long)fp.data - (unsigned long)data);
1263+
pr_info("sepolicy: policydb_write complete len=%zu alloc_len=%zu actual_len=%zu\n", len, alloc_len, actual_len);
12431264

12441265
// https://android-review.googlesource.com/c/kernel/common/+/3009995/11/security/selinux/ss/policydb.c
12451266
// fixup config
12461267
// 4*2+8+4
12471268
static const size_t kConfigOff = 20;
1248-
if (len >= kConfigOff + sizeof(u32)) {
1269+
if (actual_len >= kConfigOff + sizeof(u32)) {
12491270
u32 *config_ptr = (u32 *)((unsigned long)data + kConfigOff);
12501271
pr_info("old config: %u\n", *config_ptr);
12511272
if (old_pol->policydb.android_netlink_route) {
@@ -1270,16 +1291,16 @@ struct selinux_policy *ksu_dup_sepolicy(struct selinux_policy *old_pol)
12701291

12711292
// rewind fp
12721293
fp.data = data;
1273-
fp.len = len;
1294+
fp.len = actual_len;
12741295

1275-
pr_info("sepolicy: policydb_read begin len=%zu\n", len);
1296+
pr_info("sepolicy: policydb_read begin len=%zu\n", actual_len);
12761297
ret = policydb_read(&new_pol->policydb, &fp);
12771298
if (ret) {
12781299
pr_err("sepolicy: policydb_read: %d\n", ret);
12791300
goto out_free_policydb;
12801301
}
1281-
pr_info("sepolicy: policydb_read complete len=%zu\n", len);
1282-
new_pol->policydb.len = old_pol->policydb.len;
1302+
pr_info("sepolicy: policydb_read complete len=%zu\n", actual_len);
1303+
new_pol->policydb.len = actual_len;
12831304
kvfree(data);
12841305

12851306
return new_pol;

0 commit comments

Comments
 (0)