4
4
scopeguard:: defer,
5
5
solana_loader_v3_interface:: instruction as bpf_loader_upgradeable,
6
6
solana_measure:: measure:: Measure ,
7
- solana_program_runtime:: {
8
- invoke_context:: SerializedAccountMetadata , serialization:: account_data_region_memory_state,
9
- } ,
10
- solana_sbpf:: {
11
- ebpf,
12
- memory_region:: { MemoryRegion , MemoryState } ,
13
- } ,
7
+ solana_program_runtime:: invoke_context:: SerializedAccountMetadata ,
8
+ solana_sbpf:: { ebpf, memory_region:: MemoryRegion } ,
14
9
solana_stable_layout:: stable_instruction:: StableInstruction ,
15
10
solana_transaction_context:: BorrowedAccount ,
16
11
std:: { mem, ptr} ,
@@ -365,7 +360,7 @@ impl<'a> CallerAccount<'a> {
365
360
& self ,
366
361
memory_mapping : & ' a MemoryMapping < ' _ > ,
367
362
is_loader_deprecated : bool ,
368
- ) -> Result < Option < & ' a MemoryRegion > , Error > {
363
+ ) -> Result < Option < ( usize , & ' a MemoryRegion ) > , Error > {
369
364
account_realloc_region (
370
365
memory_mapping,
371
366
self . vm_data_addr ,
@@ -1076,7 +1071,7 @@ fn cpi_common<S: SyscallInvokeSigned>(
1076
1071
account_infos_len : u64 ,
1077
1072
signers_seeds_addr : u64 ,
1078
1073
signers_seeds_len : u64 ,
1079
- memory_mapping : & MemoryMapping ,
1074
+ memory_mapping : & mut MemoryMapping ,
1080
1075
) -> Result < u64 , Error > {
1081
1076
// CPI entry.
1082
1077
//
@@ -1148,12 +1143,12 @@ fn cpi_common<S: SyscallInvokeSigned>(
1148
1143
// it's better to be safe than sorry.
1149
1144
for ( index_in_caller, caller_account) in accounts. iter ( ) {
1150
1145
if let Some ( caller_account) = caller_account {
1151
- let callee_account = instruction_context
1146
+ let mut callee_account = instruction_context
1152
1147
. try_borrow_instruction_account ( transaction_context, * index_in_caller) ?;
1153
1148
update_caller_account_perms (
1154
1149
memory_mapping,
1155
1150
caller_account,
1156
- & callee_account,
1151
+ & mut callee_account,
1157
1152
is_loader_deprecated,
1158
1153
) ?;
1159
1154
}
@@ -1266,9 +1261,9 @@ fn update_callee_account(
1266
1261
}
1267
1262
1268
1263
fn update_caller_account_perms (
1269
- memory_mapping : & MemoryMapping ,
1264
+ memory_mapping : & mut MemoryMapping ,
1270
1265
caller_account : & CallerAccount ,
1271
- callee_account : & BorrowedAccount < ' _ > ,
1266
+ callee_account : & mut BorrowedAccount < ' _ > ,
1272
1267
is_loader_deprecated : bool ,
1273
1268
) -> Result < ( ) , Error > {
1274
1269
let CallerAccount {
@@ -1277,26 +1272,66 @@ fn update_caller_account_perms(
1277
1272
..
1278
1273
} = caller_account;
1279
1274
1280
- let data_region = account_data_region ( memory_mapping, * vm_data_addr, * original_data_len) ?;
1281
- if let Some ( region) = data_region {
1282
- region
1283
- . state
1284
- . set ( account_data_region_memory_state ( callee_account) ) ;
1275
+ if let Some ( ( region_index, region) ) =
1276
+ account_data_region ( memory_mapping, * vm_data_addr, * original_data_len) ?
1277
+ {
1278
+ let writable = callee_account. can_data_be_changed ( ) . is_ok ( ) ;
1279
+ let shared = callee_account. is_shared ( ) ;
1280
+ let mut new_region = if writable && !shared {
1281
+ MemoryRegion :: new_writable (
1282
+ unsafe {
1283
+ std:: slice:: from_raw_parts_mut (
1284
+ region. host_addr . get ( ) as * mut u8 ,
1285
+ region. len as usize ,
1286
+ )
1287
+ } ,
1288
+ region. vm_addr ,
1289
+ )
1290
+ } else {
1291
+ MemoryRegion :: new_readonly (
1292
+ unsafe {
1293
+ std:: slice:: from_raw_parts (
1294
+ region. host_addr . get ( ) as * const u8 ,
1295
+ region. len as usize ,
1296
+ )
1297
+ } ,
1298
+ region. vm_addr ,
1299
+ )
1300
+ } ;
1301
+ if writable && shared {
1302
+ new_region. cow_callback_payload = callee_account. get_index_in_transaction ( ) as u32 ;
1303
+ }
1304
+ memory_mapping. replace_region ( region_index, new_region) ?;
1285
1305
}
1286
- let realloc_region = account_realloc_region (
1306
+
1307
+ if let Some ( ( region_index, region) ) = account_realloc_region (
1287
1308
memory_mapping,
1288
1309
* vm_data_addr,
1289
1310
* original_data_len,
1290
1311
is_loader_deprecated,
1291
- ) ?;
1292
- if let Some ( region) = realloc_region {
1293
- region
1294
- . state
1295
- . set ( if callee_account. can_data_be_changed ( ) . is_ok ( ) {
1296
- MemoryState :: Writable
1297
- } else {
1298
- MemoryState :: Readable
1299
- } ) ;
1312
+ ) ? {
1313
+ let new_region = if callee_account. can_data_be_changed ( ) . is_ok ( ) {
1314
+ MemoryRegion :: new_writable (
1315
+ unsafe {
1316
+ std:: slice:: from_raw_parts_mut (
1317
+ region. host_addr . get ( ) as * mut u8 ,
1318
+ region. len as usize ,
1319
+ )
1320
+ } ,
1321
+ region. vm_addr ,
1322
+ )
1323
+ } else {
1324
+ MemoryRegion :: new_readonly (
1325
+ unsafe {
1326
+ std:: slice:: from_raw_parts (
1327
+ region. host_addr . get ( ) as * const u8 ,
1328
+ region. len as usize ,
1329
+ )
1330
+ } ,
1331
+ region. vm_addr ,
1332
+ )
1333
+ } ;
1334
+ memory_mapping. replace_region ( region_index, new_region) ?;
1300
1335
}
1301
1336
1302
1337
Ok ( ( ) )
@@ -1323,7 +1358,7 @@ fn update_caller_account(
1323
1358
1324
1359
let mut zero_all_mapped_spare_capacity = false ;
1325
1360
if direct_mapping {
1326
- if let Some ( region) = account_data_region (
1361
+ if let Some ( ( _region_index , region) ) = account_data_region (
1327
1362
memory_mapping,
1328
1363
caller_account. vm_data_addr ,
1329
1364
caller_account. original_data_len ,
@@ -1412,12 +1447,12 @@ fn update_caller_account(
1412
1447
1413
1448
// Temporarily configure the realloc region as writable then set it back to
1414
1449
// whatever state it had.
1415
- let realloc_region = caller_account
1450
+ let ( _realloc_region_index , realloc_region) = caller_account
1416
1451
. realloc_region ( memory_mapping, is_loader_deprecated) ?
1417
1452
. unwrap ( ) ; // unwrapping here is fine, we already asserted !is_loader_deprecated
1418
- let original_state = realloc_region. state . replace ( MemoryState :: Writable ) ;
1453
+ let original_state = realloc_region. writable . replace ( true ) ;
1419
1454
defer ! {
1420
- realloc_region. state . set( original_state) ;
1455
+ realloc_region. writable . set( original_state) ;
1421
1456
} ;
1422
1457
1423
1458
// We need to zero the unused space in the realloc region, starting after the
@@ -1521,12 +1556,12 @@ fn update_caller_account(
1521
1556
//
1522
1557
// Therefore we temporarily configure the realloc region as writable
1523
1558
// then set it back to whatever state it had.
1524
- let realloc_region = caller_account
1559
+ let ( _realloc_region_index , realloc_region) = caller_account
1525
1560
. realloc_region ( memory_mapping, is_loader_deprecated) ?
1526
1561
. unwrap ( ) ; // unwrapping here is fine, we asserted !is_loader_deprecated
1527
- let original_state = realloc_region. state . replace ( MemoryState :: Writable ) ;
1562
+ let original_state = realloc_region. writable . replace ( true ) ;
1528
1563
defer ! {
1529
- realloc_region. state . set( original_state) ;
1564
+ realloc_region. writable . set( original_state) ;
1530
1565
} ;
1531
1566
1532
1567
translate_slice_mut :: < u8 > (
@@ -1566,37 +1601,38 @@ fn account_data_region<'a>(
1566
1601
memory_mapping : & ' a MemoryMapping < ' _ > ,
1567
1602
vm_data_addr : u64 ,
1568
1603
original_data_len : usize ,
1569
- ) -> Result < Option < & ' a MemoryRegion > , Error > {
1604
+ ) -> Result < Option < ( usize , & ' a MemoryRegion ) > , Error > {
1570
1605
if original_data_len == 0 {
1571
1606
return Ok ( None ) ;
1572
1607
}
1573
1608
1574
1609
// We can trust vm_data_addr to point to the correct region because we
1575
1610
// enforce that in CallerAccount::from_(sol_)account_info.
1576
- let data_region = memory_mapping. region ( AccessType :: Load , vm_data_addr) ?;
1611
+ let ( data_region_index , data_region) = memory_mapping. region ( AccessType :: Load , vm_data_addr) ?;
1577
1612
// vm_data_addr must always point to the beginning of the region
1578
1613
debug_assert_eq ! ( data_region. vm_addr, vm_data_addr) ;
1579
- Ok ( Some ( data_region) )
1614
+ Ok ( Some ( ( data_region_index , data_region) ) )
1580
1615
}
1581
1616
1582
1617
fn account_realloc_region < ' a > (
1583
1618
memory_mapping : & ' a MemoryMapping < ' _ > ,
1584
1619
vm_data_addr : u64 ,
1585
1620
original_data_len : usize ,
1586
1621
is_loader_deprecated : bool ,
1587
- ) -> Result < Option < & ' a MemoryRegion > , Error > {
1622
+ ) -> Result < Option < ( usize , & ' a MemoryRegion ) > , Error > {
1588
1623
if is_loader_deprecated {
1589
1624
return Ok ( None ) ;
1590
1625
}
1591
1626
1592
1627
let realloc_vm_addr = vm_data_addr. saturating_add ( original_data_len as u64 ) ;
1593
- let realloc_region = memory_mapping. region ( AccessType :: Load , realloc_vm_addr) ?;
1628
+ let ( realloc_region_index, realloc_region) =
1629
+ memory_mapping. region ( AccessType :: Load , realloc_vm_addr) ?;
1594
1630
debug_assert_eq ! ( realloc_region. vm_addr, realloc_vm_addr) ;
1595
1631
debug_assert ! ( ( MAX_PERMITTED_DATA_INCREASE
1596
1632
..MAX_PERMITTED_DATA_INCREASE . saturating_add( BPF_ALIGN_OF_U128 ) )
1597
1633
. contains( & ( realloc_region. len as usize ) ) ) ;
1598
- debug_assert ! ( !matches! ( realloc_region. state . get ( ) , MemoryState :: Cow ( _ ) ) ) ;
1599
- Ok ( Some ( realloc_region) )
1634
+ debug_assert_eq ! ( realloc_region. cow_callback_payload , u32 :: MAX ) ;
1635
+ Ok ( Some ( ( realloc_region_index , realloc_region) ) )
1600
1636
}
1601
1637
1602
1638
#[ allow( clippy:: indexing_slicing) ]
0 commit comments