@@ -1090,4 +1090,347 @@ TEST_F(enclave, augment_via_eaccept)
1090
1090
munmap (addr , PAGE_SIZE );
1091
1091
}
1092
1092
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
+
1093
1436
TEST_HARNESS_MAIN
0 commit comments