@@ -1294,39 +1294,49 @@ async function userland() {
1294
1294
await chain . add_syscall_ret ( test_store_buf , SYSCALL_LISTEN , elf_loader_sock_fd , 5 ) ;
1295
1295
await chain . run ( ) ;
1296
1296
1297
- // Accept and process connections
1297
+ // ELF sizes and offsets
1298
1298
let SIZE_ELF_HEADER = 0x40 ;
1299
1299
let SIZE_ELF_PROGRAM_HEADER = 0x38 ;
1300
+
1300
1301
let OFFSET_ELF_HEADER_ENTRY = 0x18 ;
1301
1302
let OFFSET_ELF_HEADER_PHOFF = 0x20 ;
1302
1303
let OFFSET_ELF_HEADER_PHNUM = 0x38 ;
1304
+
1303
1305
let OFFSET_PROGRAM_HEADER_TYPE = 0x00 ;
1304
1306
let OFFSET_PROGRAM_HEADER_FLAGS = 0x04 ;
1305
1307
let OFFSET_PROGRAM_HEADER_OFFSET = 0x08 ;
1306
1308
let OFFSET_PROGRAM_HEADER_VADDR = 0x10 ;
1307
- let OFFSET_PROGRAM_HEADER_FILESZ = 0x20 ;
1308
1309
let OFFSET_PROGRAM_HEADER_MEMSZ = 0x28 ;
1309
- let ELF_PT_NULL = 0x00 ;
1310
+
1311
+ let OFFSET_RELA_OFFSET = 0x00 ;
1312
+ let OFFSET_RELA_INFO = 0x08 ;
1313
+ let OFFSET_RELA_ADDEND = 0x10 ;
1314
+
1315
+ // ELF program header types
1310
1316
let ELF_PT_LOAD = 0x01 ;
1317
+ let ELF_PT_DYNAMIC = 0x02 ;
1318
+
1319
+ // ELF dynamic table types
1320
+ let ELF_DT_NULL = 0x00 ;
1321
+ let ELF_DT_RELA = 0x07 ;
1322
+ let ELF_DT_RELASZ = 0x08 ;
1323
+ let ELF_DT_RELAENT = 0x09 ;
1324
+ let ELF_R_AMD64_RELATIVE = 0x08 ;
1311
1325
1326
+ // Accept clients
1312
1327
let conn_fd_store = p . malloc ( 0x4 ) ;
1313
1328
let conn_addr_store = p . malloc ( 0x10 ) ;
1314
1329
let conn_addr_sz_store = p . malloc ( 0x4 ) ;
1315
1330
let conn_ret_store = p . malloc ( 0x8 ) ;
1316
- let segment_text_addr_store = p . malloc ( 0x8 ) ;
1317
- let segment_data_addr_store = p . malloc ( 0x8 ) ;
1318
1331
let elf_store_size = SIZE_ELF_HEADER + ( SIZE_ELF_PROGRAM_HEADER * 0x10 ) + 0x200000 ;
1319
1332
let elf_store = p . malloc ( elf_store_size ) ;
1320
1333
1321
1334
let shadow_mapping_addr = new int64 ( 0x20100000 , 0x00000009 ) ;
1322
1335
let mapping_addr = new int64 ( 0x26100000 , 0x00000009 ) ;
1323
- let data_mapping_addr ;
1324
1336
1325
1337
let elf_program_headers_offset = 0 ;
1326
1338
let elf_program_headers_num = 0 ;
1327
1339
1328
- let elf_mapped_addr = 0 ;
1329
-
1330
1340
p . write4 ( conn_addr_sz_store , 0x10 ) ;
1331
1341
1332
1342
for ( ; ; ) {
@@ -1362,8 +1372,13 @@ async function userland() {
1362
1372
1363
1373
await log ( "[+] Received ELF file (" + total_sz . toString ( 10 ) + " bytes), loading..." ) ;
1364
1374
1365
- let text_segment_sz = 0 ;
1366
- let data_segment_sz = 0 ;
1375
+ let text_segment_sz = 0 ;
1376
+ let data_segment_sz = 0 ;
1377
+ let rela_table_offset = 0 ;
1378
+ let rela_table_count = 0 ;
1379
+ let rela_table_size = 0 ;
1380
+ let rela_table_entsize = 0 ;
1381
+ let shadow_write_mapping = 0 ;
1367
1382
1368
1383
// Parse program headers and map segments
1369
1384
for ( let i = 0 ; i < elf_program_headers_num ; i ++ ) {
@@ -1381,7 +1396,7 @@ async function userland() {
1381
1396
// Also, the mapping size is fixed at 0x100000. This is because jitshm requires to be aligned this way... for some dumb reason.
1382
1397
if ( ( program_flags & 1 ) == 1 ) {
1383
1398
// Executable segment
1384
- text_segment_sz = aligned_memsz ;
1399
+ text_segment_sz = program_memsz ;
1385
1400
1386
1401
// Get exec
1387
1402
await chain . add_syscall_ret ( jit_handle_store , SYSCALL_JITSHM_CREATE , 0x0 , aligned_memsz , 0x7 ) ;
@@ -1396,6 +1411,7 @@ async function userland() {
1396
1411
// Map to shadow mapping
1397
1412
await chain . add_syscall_ret ( conn_ret_store , SYSCALL_MMAP , shadow_mapping_addr , aligned_memsz , 0x3 , 0x11 , write_handle , 0 ) ;
1398
1413
await chain . run ( ) ;
1414
+ shadow_write_mapping = p . read8 ( conn_ret_store ) ;
1399
1415
1400
1416
// Copy in segment data
1401
1417
let dest = p . read8 ( conn_ret_store ) ;
@@ -1424,7 +1440,65 @@ async function userland() {
1424
1440
}
1425
1441
}
1426
1442
1427
- // TODO: Dynamic / relocations
1443
+ if ( program_type == ELF_PT_DYNAMIC ) {
1444
+ // Parse dynamic tags, the ones we truly care about are rela-related.
1445
+ for ( let j = 0x00 ; ; j += 0x10 ) {
1446
+ let d_tag = p . read8 ( elf_store . add32 ( program_offset + j ) ) . low ;
1447
+ let d_val = p . read8 ( elf_store . add32 ( program_offset + j + 0x08 ) ) ;
1448
+
1449
+ // DT_NULL means we reached the end of the table
1450
+ if ( d_tag == ELF_DT_NULL || j > 0x100 ) {
1451
+ break ;
1452
+ }
1453
+
1454
+ switch ( d_tag ) {
1455
+ case ELF_DT_RELA :
1456
+ rela_table_offset = d_val . low ;
1457
+ break ;
1458
+ case ELF_DT_RELASZ :
1459
+ rela_table_size = d_val . low ;
1460
+ break ;
1461
+ case ELF_DT_RELAENT :
1462
+ rela_table_entsize = d_val . low ;
1463
+ break ;
1464
+ }
1465
+ }
1466
+ }
1467
+ }
1468
+
1469
+ // Process relocations if they exist
1470
+ if ( rela_table_offset != 0 ) {
1471
+ let base_address = 0x1000 ;
1472
+
1473
+ // The rela table offset from dynamic table is relative to the LOAD segment offset not file offset.
1474
+ // The linker script should guarantee it ends up in the first LOAD segment (code).
1475
+ rela_table_offset += base_address ;
1476
+
1477
+ // Rela count can be gotten from dividing the table size by entry size
1478
+ rela_table_count = rela_table_size / rela_table_entsize ;
1479
+
1480
+ // Parse relocs and apply them
1481
+ for ( let i = 0 ; i < rela_table_count ; i ++ ) {
1482
+ let r_offset = p . read8 ( elf_store . add32 ( rela_table_offset + ( i * rela_table_entsize ) +
1483
+ OFFSET_RELA_OFFSET ) ) ;
1484
+ let r_info = p . read8 ( elf_store . add32 ( rela_table_offset + ( i * rela_table_entsize ) +
1485
+ OFFSET_RELA_INFO ) ) ;
1486
+ let r_addend = p . read8 ( elf_store . add32 ( rela_table_offset + ( i * rela_table_entsize ) +
1487
+ OFFSET_RELA_ADDEND ) ) ;
1488
+
1489
+ let reloc_addr = mapping_addr . add32 ( r_offset . low ) ;
1490
+
1491
+ // If the relocation falls in the executable section, we need to redirect the write to the
1492
+ // writable shadow mapping or we'll crash
1493
+ if ( r_offset . low <= text_segment_sz ) {
1494
+ reloc_addr = shadow_write_mapping . add32 ( r_offset . low ) ;
1495
+ }
1496
+
1497
+ if ( ( r_info . low & 0xFF ) == ELF_R_AMD64_RELATIVE ) {
1498
+ let reloc_value = mapping_addr . add32 ( r_addend . low ) ; // B + A
1499
+ p . write8 ( reloc_addr , reloc_value ) ;
1500
+ }
1501
+ }
1428
1502
}
1429
1503
1430
1504
let rwpair_mem = p . malloc ( 0x8 ) ;
0 commit comments