@@ -1090,4 +1090,347 @@ TEST_F(enclave, augment_via_eaccept)
10901090 munmap (addr , PAGE_SIZE );
10911091}
10921092
1093+ /*
1094+ * SGX2 page type modification test in two phases:
1095+ * Phase 1:
1096+ * Create a new TCS, consisting out of three new pages (stack page with regular
1097+ * page type, SSA page with regular page type, and TCS page with TCS page
1098+ * type) in an initialized enclave and run a simple workload within it.
1099+ * Phase 2:
1100+ * Remove the three pages added in phase 1, add a new regular page at the
1101+ * same address that previously hosted the TCS page and verify that it can
1102+ * be modified.
1103+ */
1104+ TEST_F (enclave , tcs_create )
1105+ {
1106+ struct encl_op_init_tcs_page init_tcs_page_op ;
1107+ struct sgx_enclave_remove_pages remove_ioc ;
1108+ struct encl_op_get_from_addr get_addr_op ;
1109+ struct sgx_enclave_modify_types modt_ioc ;
1110+ struct encl_op_put_to_addr put_addr_op ;
1111+ struct encl_op_get_from_buf get_buf_op ;
1112+ struct encl_op_put_to_buf put_buf_op ;
1113+ void * addr , * tcs , * stack_end , * ssa ;
1114+ struct encl_op_eaccept eaccept_op ;
1115+ size_t total_size = 0 ;
1116+ uint64_t val_64 ;
1117+ int errno_save ;
1118+ int ret , i ;
1119+
1120+ ASSERT_TRUE (setup_test_encl (ENCL_HEAP_SIZE_DEFAULT , & self -> encl ,
1121+ _metadata ));
1122+
1123+ memset (& self -> run , 0 , sizeof (self -> run ));
1124+ self -> run .tcs = self -> encl .encl_base ;
1125+
1126+ /*
1127+ * Hardware (SGX2) and kernel support is needed for this test. Start
1128+ * with check that test has a chance of succeeding.
1129+ */
1130+ memset (& modt_ioc , 0 , sizeof (modt_ioc ));
1131+ ret = ioctl (self -> encl .fd , SGX_IOC_ENCLAVE_MODIFY_TYPES , & modt_ioc );
1132+
1133+ if (ret == -1 ) {
1134+ if (errno == ENOTTY )
1135+ SKIP (return ,
1136+ "Kernel does not support SGX_IOC_ENCLAVE_MODIFY_TYPES ioctl()" );
1137+ else if (errno == ENODEV )
1138+ SKIP (return , "System does not support SGX2" );
1139+ }
1140+
1141+ /*
1142+ * Invalid parameters were provided during sanity check,
1143+ * expect command to fail.
1144+ */
1145+ EXPECT_EQ (ret , -1 );
1146+
1147+ /*
1148+ * Add three regular pages via EAUG: one will be the TCS stack, one
1149+ * will be the TCS SSA, and one will be the new TCS. The stack and
1150+ * SSA will remain as regular pages, the TCS page will need its
1151+ * type changed after populated with needed data.
1152+ */
1153+ for (i = 0 ; i < self -> encl .nr_segments ; i ++ ) {
1154+ struct encl_segment * seg = & self -> encl .segment_tbl [i ];
1155+
1156+ total_size += seg -> size ;
1157+ }
1158+
1159+ /*
1160+ * Actual enclave size is expected to be larger than the loaded
1161+ * test enclave since enclave size must be a power of 2 in bytes while
1162+ * test_encl does not consume it all.
1163+ */
1164+ EXPECT_LT (total_size + 3 * PAGE_SIZE , self -> encl .encl_size );
1165+
1166+ /*
1167+ * mmap() three pages at end of existing enclave to be used for the
1168+ * three new pages.
1169+ */
1170+ addr = mmap ((void * )self -> encl .encl_base + total_size , 3 * PAGE_SIZE ,
1171+ PROT_READ | PROT_WRITE , MAP_SHARED | MAP_FIXED ,
1172+ self -> encl .fd , 0 );
1173+ EXPECT_NE (addr , MAP_FAILED );
1174+
1175+ self -> run .exception_vector = 0 ;
1176+ self -> run .exception_error_code = 0 ;
1177+ self -> run .exception_addr = 0 ;
1178+
1179+ stack_end = (void * )self -> encl .encl_base + total_size ;
1180+ tcs = (void * )self -> encl .encl_base + total_size + PAGE_SIZE ;
1181+ ssa = (void * )self -> encl .encl_base + total_size + 2 * PAGE_SIZE ;
1182+
1183+ /*
1184+ * Run EACCEPT on each new page to trigger the
1185+ * EACCEPT->(#PF)->EAUG->EACCEPT(again without a #PF) flow.
1186+ */
1187+
1188+ eaccept_op .epc_addr = (unsigned long )stack_end ;
1189+ eaccept_op .flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING ;
1190+ eaccept_op .ret = 0 ;
1191+ eaccept_op .header .type = ENCL_OP_EACCEPT ;
1192+
1193+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1194+
1195+ if (self -> run .exception_vector == 14 &&
1196+ self -> run .exception_error_code == 4 &&
1197+ self -> run .exception_addr == (unsigned long )stack_end ) {
1198+ munmap (addr , 3 * PAGE_SIZE );
1199+ SKIP (return , "Kernel does not support adding pages to initialized enclave" );
1200+ }
1201+
1202+ EXPECT_EEXIT (& self -> run );
1203+ EXPECT_EQ (self -> run .exception_vector , 0 );
1204+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1205+ EXPECT_EQ (self -> run .exception_addr , 0 );
1206+ EXPECT_EQ (eaccept_op .ret , 0 );
1207+
1208+ eaccept_op .epc_addr = (unsigned long )ssa ;
1209+
1210+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1211+
1212+ EXPECT_EEXIT (& self -> run );
1213+ EXPECT_EQ (self -> run .exception_vector , 0 );
1214+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1215+ EXPECT_EQ (self -> run .exception_addr , 0 );
1216+ EXPECT_EQ (eaccept_op .ret , 0 );
1217+
1218+ eaccept_op .epc_addr = (unsigned long )tcs ;
1219+
1220+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1221+
1222+ EXPECT_EEXIT (& self -> run );
1223+ EXPECT_EQ (self -> run .exception_vector , 0 );
1224+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1225+ EXPECT_EQ (self -> run .exception_addr , 0 );
1226+ EXPECT_EQ (eaccept_op .ret , 0 );
1227+
1228+ /*
1229+ * Three new pages added to enclave. Now populate the TCS page with
1230+ * needed data. This should be done from within enclave. Provide
1231+ * the function that will do the actual data population with needed
1232+ * data.
1233+ */
1234+
1235+ /*
1236+ * New TCS will use the "encl_dyn_entry" entrypoint that expects
1237+ * stack to begin in page before TCS page.
1238+ */
1239+ val_64 = encl_get_entry (& self -> encl , "encl_dyn_entry" );
1240+ EXPECT_NE (val_64 , 0 );
1241+
1242+ init_tcs_page_op .tcs_page = (unsigned long )tcs ;
1243+ init_tcs_page_op .ssa = (unsigned long )total_size + 2 * PAGE_SIZE ;
1244+ init_tcs_page_op .entry = val_64 ;
1245+ init_tcs_page_op .header .type = ENCL_OP_INIT_TCS_PAGE ;
1246+
1247+ EXPECT_EQ (ENCL_CALL (& init_tcs_page_op , & self -> run , true), 0 );
1248+
1249+ EXPECT_EEXIT (& self -> run );
1250+ EXPECT_EQ (self -> run .exception_vector , 0 );
1251+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1252+ EXPECT_EQ (self -> run .exception_addr , 0 );
1253+
1254+ /* Change TCS page type to TCS. */
1255+ memset (& modt_ioc , 0 , sizeof (modt_ioc ));
1256+
1257+ modt_ioc .offset = total_size + PAGE_SIZE ;
1258+ modt_ioc .length = PAGE_SIZE ;
1259+ modt_ioc .page_type = SGX_PAGE_TYPE_TCS ;
1260+
1261+ ret = ioctl (self -> encl .fd , SGX_IOC_ENCLAVE_MODIFY_TYPES , & modt_ioc );
1262+ errno_save = ret == -1 ? errno : 0 ;
1263+
1264+ EXPECT_EQ (ret , 0 );
1265+ EXPECT_EQ (errno_save , 0 );
1266+ EXPECT_EQ (modt_ioc .result , 0 );
1267+ EXPECT_EQ (modt_ioc .count , 4096 );
1268+
1269+ /* EACCEPT new TCS page from enclave. */
1270+ eaccept_op .epc_addr = (unsigned long )tcs ;
1271+ eaccept_op .flags = SGX_SECINFO_TCS | SGX_SECINFO_MODIFIED ;
1272+ eaccept_op .ret = 0 ;
1273+ eaccept_op .header .type = ENCL_OP_EACCEPT ;
1274+
1275+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1276+
1277+ EXPECT_EEXIT (& self -> run );
1278+ EXPECT_EQ (self -> run .exception_vector , 0 );
1279+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1280+ EXPECT_EQ (self -> run .exception_addr , 0 );
1281+ EXPECT_EQ (eaccept_op .ret , 0 );
1282+
1283+ /* Run workload from new TCS. */
1284+ self -> run .tcs = (unsigned long )tcs ;
1285+
1286+ /*
1287+ * Simple workload to write to data buffer and read value back.
1288+ */
1289+ put_buf_op .header .type = ENCL_OP_PUT_TO_BUFFER ;
1290+ put_buf_op .value = MAGIC ;
1291+
1292+ EXPECT_EQ (ENCL_CALL (& put_buf_op , & self -> run , true), 0 );
1293+
1294+ EXPECT_EEXIT (& self -> run );
1295+ EXPECT_EQ (self -> run .exception_vector , 0 );
1296+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1297+ EXPECT_EQ (self -> run .exception_addr , 0 );
1298+
1299+ get_buf_op .header .type = ENCL_OP_GET_FROM_BUFFER ;
1300+ get_buf_op .value = 0 ;
1301+
1302+ EXPECT_EQ (ENCL_CALL (& get_buf_op , & self -> run , true), 0 );
1303+
1304+ EXPECT_EQ (get_buf_op .value , MAGIC );
1305+ EXPECT_EEXIT (& self -> run );
1306+ EXPECT_EQ (self -> run .exception_vector , 0 );
1307+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1308+ EXPECT_EQ (self -> run .exception_addr , 0 );
1309+
1310+ /*
1311+ * Phase 2 of test:
1312+ * Remove pages associated with new TCS, create a regular page
1313+ * where TCS page used to be and verify it can be used as a regular
1314+ * page.
1315+ */
1316+
1317+ /* Start page removal by requesting change of page type to PT_TRIM. */
1318+ memset (& modt_ioc , 0 , sizeof (modt_ioc ));
1319+
1320+ modt_ioc .offset = total_size ;
1321+ modt_ioc .length = 3 * PAGE_SIZE ;
1322+ modt_ioc .page_type = SGX_PAGE_TYPE_TRIM ;
1323+
1324+ ret = ioctl (self -> encl .fd , SGX_IOC_ENCLAVE_MODIFY_TYPES , & modt_ioc );
1325+ errno_save = ret == -1 ? errno : 0 ;
1326+
1327+ EXPECT_EQ (ret , 0 );
1328+ EXPECT_EQ (errno_save , 0 );
1329+ EXPECT_EQ (modt_ioc .result , 0 );
1330+ EXPECT_EQ (modt_ioc .count , 3 * PAGE_SIZE );
1331+
1332+ /*
1333+ * Enter enclave via TCS #1 and approve page removal by sending
1334+ * EACCEPT for each of three removed pages.
1335+ */
1336+ self -> run .tcs = self -> encl .encl_base ;
1337+
1338+ eaccept_op .epc_addr = (unsigned long )stack_end ;
1339+ eaccept_op .flags = SGX_SECINFO_TRIM | SGX_SECINFO_MODIFIED ;
1340+ eaccept_op .ret = 0 ;
1341+ eaccept_op .header .type = ENCL_OP_EACCEPT ;
1342+
1343+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1344+
1345+ EXPECT_EEXIT (& self -> run );
1346+ EXPECT_EQ (self -> run .exception_vector , 0 );
1347+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1348+ EXPECT_EQ (self -> run .exception_addr , 0 );
1349+ EXPECT_EQ (eaccept_op .ret , 0 );
1350+
1351+ eaccept_op .epc_addr = (unsigned long )tcs ;
1352+ eaccept_op .ret = 0 ;
1353+
1354+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1355+
1356+ EXPECT_EEXIT (& self -> run );
1357+ EXPECT_EQ (self -> run .exception_vector , 0 );
1358+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1359+ EXPECT_EQ (self -> run .exception_addr , 0 );
1360+ EXPECT_EQ (eaccept_op .ret , 0 );
1361+
1362+ eaccept_op .epc_addr = (unsigned long )ssa ;
1363+ eaccept_op .ret = 0 ;
1364+
1365+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1366+
1367+ EXPECT_EEXIT (& self -> run );
1368+ EXPECT_EQ (self -> run .exception_vector , 0 );
1369+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1370+ EXPECT_EQ (self -> run .exception_addr , 0 );
1371+ EXPECT_EQ (eaccept_op .ret , 0 );
1372+
1373+ /* Send final ioctl() to complete page removal. */
1374+ memset (& remove_ioc , 0 , sizeof (remove_ioc ));
1375+
1376+ remove_ioc .offset = total_size ;
1377+ remove_ioc .length = 3 * PAGE_SIZE ;
1378+
1379+ ret = ioctl (self -> encl .fd , SGX_IOC_ENCLAVE_REMOVE_PAGES , & remove_ioc );
1380+ errno_save = ret == -1 ? errno : 0 ;
1381+
1382+ EXPECT_EQ (ret , 0 );
1383+ EXPECT_EQ (errno_save , 0 );
1384+ EXPECT_EQ (remove_ioc .count , 3 * PAGE_SIZE );
1385+
1386+ /*
1387+ * Enter enclave via TCS #1 and access location where TCS #3 was to
1388+ * trigger dynamic add of regular page at that location.
1389+ */
1390+ eaccept_op .epc_addr = (unsigned long )tcs ;
1391+ eaccept_op .flags = SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_REG | SGX_SECINFO_PENDING ;
1392+ eaccept_op .ret = 0 ;
1393+ eaccept_op .header .type = ENCL_OP_EACCEPT ;
1394+
1395+ EXPECT_EQ (ENCL_CALL (& eaccept_op , & self -> run , true), 0 );
1396+
1397+ EXPECT_EEXIT (& self -> run );
1398+ EXPECT_EQ (self -> run .exception_vector , 0 );
1399+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1400+ EXPECT_EQ (self -> run .exception_addr , 0 );
1401+ EXPECT_EQ (eaccept_op .ret , 0 );
1402+
1403+ /*
1404+ * New page should be accessible from within enclave - write to it.
1405+ */
1406+ put_addr_op .value = MAGIC ;
1407+ put_addr_op .addr = (unsigned long )tcs ;
1408+ put_addr_op .header .type = ENCL_OP_PUT_TO_ADDRESS ;
1409+
1410+ EXPECT_EQ (ENCL_CALL (& put_addr_op , & self -> run , true), 0 );
1411+
1412+ EXPECT_EEXIT (& self -> run );
1413+ EXPECT_EQ (self -> run .exception_vector , 0 );
1414+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1415+ EXPECT_EQ (self -> run .exception_addr , 0 );
1416+
1417+ /*
1418+ * Read memory from newly added page that was just written to,
1419+ * confirming that data previously written (MAGIC) is present.
1420+ */
1421+ get_addr_op .value = 0 ;
1422+ get_addr_op .addr = (unsigned long )tcs ;
1423+ get_addr_op .header .type = ENCL_OP_GET_FROM_ADDRESS ;
1424+
1425+ EXPECT_EQ (ENCL_CALL (& get_addr_op , & self -> run , true), 0 );
1426+
1427+ EXPECT_EQ (get_addr_op .value , MAGIC );
1428+ EXPECT_EEXIT (& self -> run );
1429+ EXPECT_EQ (self -> run .exception_vector , 0 );
1430+ EXPECT_EQ (self -> run .exception_error_code , 0 );
1431+ EXPECT_EQ (self -> run .exception_addr , 0 );
1432+
1433+ munmap (addr , 3 * PAGE_SIZE );
1434+ }
1435+
10931436TEST_HARNESS_MAIN
0 commit comments