@@ -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