591 lines
18 KiB
C
591 lines
18 KiB
C
#include <net/if.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#include <spawn.h>
|
|
#include <sys/wait.h>
|
|
#include <sgx_report.h>
|
|
#include <sgx_quote.h>
|
|
#ifndef OCCLUM_DISABLE_DCAP
|
|
#include <sgx_ql_quote.h>
|
|
#include <sgx_qve_header.h>
|
|
#endif
|
|
#include "test.h"
|
|
|
|
// ============================================================================
|
|
// Test cases for TTY ioctls
|
|
// ============================================================================
|
|
|
|
int test_tty_ioctl_TIOCGWINSZ(void) {
|
|
struct winsize winsize;
|
|
if (isatty(STDOUT_FILENO)) {
|
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) < 0) {
|
|
THROW_ERROR("failed to ioctl TIOCGWINSZ");
|
|
}
|
|
} else {
|
|
// FIXME: /dev/tty should be opened. But it has not been implemented in Occlum yet.
|
|
// So we just skip this test if STDOUT is redirected.
|
|
printf("Warning: test_tty_ioctl_TIOCGWINSZ is skipped\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int test_ioctl_TCGETS_TCSETS(void) {
|
|
struct termios term;
|
|
// FIXME: /dev/tty should be opened. But it has not been implemented in Occlum yet.
|
|
// So we just skip this test if STDOUT is redirected.
|
|
if (!isatty(STDOUT_FILENO)) {
|
|
printf("Warning: test_tty_ioctl_TIOCGWINSZ is skipped\n");
|
|
return 0;
|
|
}
|
|
|
|
if (ioctl(STDOUT_FILENO, TCGETS, &term) < 0) {
|
|
THROW_ERROR("failed to ioctl TCGETS");
|
|
}
|
|
|
|
if (ioctl(STDOUT_FILENO, TCSETS, &term) < 0) {
|
|
THROW_ERROR("failed to ioctl TCSETS");
|
|
}
|
|
|
|
const char *file_path = "/root/test_ioctl.txt";
|
|
int flags = O_RDONLY | O_CREAT | O_TRUNC;
|
|
int mode = 00666;
|
|
int fd = open(file_path, flags, mode);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open test file");
|
|
}
|
|
|
|
int pipefds[2];
|
|
int ret = pipe(pipefds);
|
|
if (ret != 0) {
|
|
THROW_ERROR("failed to create pipe");
|
|
}
|
|
|
|
ret = ioctl(fd, TCGETS, &term);
|
|
if (ret != -1 || errno != ENOTTY) {
|
|
THROW_ERROR("failed catch error");
|
|
}
|
|
|
|
ret = ioctl(pipefds[0], TCGETS, &term);
|
|
if (ret != -1 || errno != ENOTTY) {
|
|
THROW_ERROR("failed catch error");
|
|
}
|
|
|
|
close(fd);
|
|
close(pipefds[0]);
|
|
close(pipefds[1]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test cases for SGX ioctls
|
|
// ============================================================================
|
|
|
|
typedef struct {
|
|
sgx_report_data_t report_data; // input
|
|
sgx_quote_sign_type_t quote_type; // input
|
|
sgx_spid_t spid; // input
|
|
sgx_quote_nonce_t nonce; // input
|
|
const uint8_t *sigrl_ptr; // input (optional)
|
|
uint32_t sigrl_len; // input (optional)
|
|
uint32_t quote_buf_len; // input
|
|
union {
|
|
uint8_t *as_buf;
|
|
sgx_quote_t *as_quote;
|
|
} quote; // output
|
|
} sgxioc_gen_epid_quote_arg_t;
|
|
|
|
typedef struct {
|
|
const sgx_target_info_t *target_info; // input (optinal)
|
|
const sgx_report_data_t *report_data; // input (optional)
|
|
sgx_report_t *report; // output
|
|
} sgxioc_create_report_arg_t;
|
|
|
|
#ifndef OCCLUM_DISABLE_DCAP
|
|
typedef struct {
|
|
sgx_report_data_t *report_data; // input
|
|
uint32_t *quote_len; // input/output
|
|
uint8_t *quote_buf; // output
|
|
} sgxioc_gen_dcap_quote_arg_t;
|
|
|
|
typedef struct {
|
|
const uint8_t *quote_buf; // input
|
|
uint32_t quote_size; // input
|
|
uint32_t *collateral_expiration_status; // output
|
|
sgx_ql_qv_result_t *quote_verification_result; // output
|
|
uint32_t supplemental_data_size; // input
|
|
uint8_t *supplemental_data; // output
|
|
} sgxioc_ver_dcap_quote_arg_t;
|
|
#endif
|
|
|
|
#define SGXIOC_IS_EDMM_SUPPORTED _IOR('s', 0, int)
|
|
#define SGXIOC_GET_EPID_GROUP_ID _IOR('s', 1, sgx_epid_group_id_t)
|
|
#define SGXIOC_GEN_EPID_QUOTE _IOWR('s', 2, sgxioc_gen_epid_quote_arg_t)
|
|
#define SGXIOC_SELF_TARGET _IOR('s', 3, sgx_target_info_t)
|
|
#define SGXIOC_CREATE_REPORT _IOWR('s', 4, sgxioc_create_report_arg_t)
|
|
#define SGXIOC_VERIFY_REPORT _IOW('s', 5, sgx_report_t)
|
|
#define SGXIOC_DETECT_DCAP_DRIVER _IOR('s', 6, int)
|
|
|
|
#ifndef OCCLUM_DISABLE_DCAP
|
|
#define SGXIOC_GET_DCAP_QUOTE_SIZE _IOR('s', 7, uint32_t)
|
|
#define SGXIOC_GEN_DCAP_QUOTE _IOWR('s', 8, sgxioc_gen_dcap_quote_arg_t)
|
|
#define SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE _IOR('s', 9, uint32_t)
|
|
#define SGXIOC_VER_DCAP_QUOTE _IOWR('s', 10, sgxioc_ver_dcap_quote_arg_t)
|
|
#endif
|
|
|
|
// The max number of retries if ioctl returns EBUSY
|
|
#define IOCTL_MAX_RETRIES 20
|
|
|
|
typedef int(*sgx_ioctl_test_body_t)(int sgx_fd);
|
|
|
|
static int do_SGXIOC_IS_EDMM_SUPPORTED(int sgx_fd) {
|
|
int is_edmm_supported = 0;
|
|
if (ioctl(sgx_fd, SGXIOC_IS_EDMM_SUPPORTED, &is_edmm_supported) < 0) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
|
}
|
|
|
|
printf(" SGX EDMM support: %d\n", is_edmm_supported);
|
|
return 0;
|
|
}
|
|
|
|
static int do_SGXIOC_GET_EPID_GROUP_ID(int sgx_fd) {
|
|
int nretries = 0;
|
|
while (nretries < IOCTL_MAX_RETRIES) {
|
|
sgx_epid_group_id_t epid_group_id = { 0 };
|
|
int ret = ioctl(sgx_fd, SGXIOC_GET_EPID_GROUP_ID, &epid_group_id);
|
|
if (ret == 0) {
|
|
break;
|
|
} else if (errno != EBUSY) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
|
}
|
|
|
|
printf("WARN: /dev/sgx is temporarily busy. Try again after 1 second.");
|
|
sleep(1);
|
|
nretries++;
|
|
}
|
|
if (nretries == IOCTL_MAX_RETRIES) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx due to timeout");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_SGXIOC_GEN_QUOTE(int sgx_fd) {
|
|
uint8_t quote_buf[2048] = { 0 };
|
|
sgxioc_gen_epid_quote_arg_t gen_quote_arg = {
|
|
.report_data = { { 0 } }, // input (empty is ok)
|
|
.quote_type = SGX_LINKABLE_SIGNATURE, // input
|
|
.spid = { { 0 } }, // input (empty is ok)
|
|
.nonce = { { 0 } }, // input (empty is ok)
|
|
.sigrl_ptr = NULL, // input (optional)
|
|
.sigrl_len = 0, // input (optional)
|
|
.quote_buf_len = sizeof(quote_buf), // input
|
|
.quote = { .as_buf = (uint8_t *) quote_buf } // output
|
|
};
|
|
int nretries = 0;
|
|
while (nretries < IOCTL_MAX_RETRIES) {
|
|
int ret = ioctl(sgx_fd, SGXIOC_GEN_EPID_QUOTE, &gen_quote_arg);
|
|
if (ret == 0) {
|
|
break;
|
|
} else if (errno != EBUSY) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
|
}
|
|
|
|
printf("WARN: /dev/sgx is temporarily busy. Try again after 1 second.");
|
|
sleep(1);
|
|
nretries++;
|
|
}
|
|
if (nretries == IOCTL_MAX_RETRIES) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx due to timeout");
|
|
}
|
|
|
|
sgx_quote_t *quote = (sgx_quote_t *)quote_buf;
|
|
if (quote->sign_type != SGX_LINKABLE_SIGNATURE) {
|
|
THROW_ERROR("invalid quote: wrong sign type");
|
|
}
|
|
if (quote->signature_len == 0) {
|
|
THROW_ERROR("invalid quote: zero-length signature");
|
|
}
|
|
if (memcmp(&gen_quote_arg.report_data, "e->report_body.report_data,
|
|
sizeof(sgx_report_data_t)) != 0) {
|
|
THROW_ERROR("invalid quote: wrong report data");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_sgx_ioctl_test(sgx_ioctl_test_body_t test_body) {
|
|
// Init test
|
|
int sgx_fd;
|
|
if ((sgx_fd = open("/dev/sgx", O_RDONLY)) < 0) {
|
|
THROW_ERROR("failed to open /dev/sgx ");
|
|
}
|
|
|
|
// Do test
|
|
int ret = test_body(sgx_fd);
|
|
|
|
// Clean up test
|
|
close(sgx_fd);
|
|
return ret;
|
|
}
|
|
|
|
static int do_SGXIOC_SELF_TARGET(int sgx_fd) {
|
|
sgx_target_info_t target_info;
|
|
if (ioctl(sgx_fd, SGXIOC_SELF_TARGET, &target_info) < 0) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int do_SGXIOC_CREATE_AND_VERIFY_REPORT(int sgx_fd) {
|
|
sgx_target_info_t target_info;
|
|
if (ioctl(sgx_fd, SGXIOC_SELF_TARGET, &target_info) < 0) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
|
}
|
|
sgx_report_data_t report_data;
|
|
sgx_report_t report;
|
|
|
|
sgxioc_create_report_arg_t args[] = {
|
|
{
|
|
.target_info = (const sgx_target_info_t *) &target_info,
|
|
.report_data = NULL,
|
|
.report = &report
|
|
},
|
|
{
|
|
.target_info = (const sgx_target_info_t *) &target_info,
|
|
.report_data = (const sgx_report_data_t *) &report_data,
|
|
.report = &report
|
|
}
|
|
};
|
|
for (int arg_i = 0; arg_i < ARRAY_SIZE(args); arg_i++) {
|
|
memset(&report, 0, sizeof(report));
|
|
sgxioc_create_report_arg_t *arg = &args[arg_i];
|
|
if (ioctl(sgx_fd, SGXIOC_CREATE_REPORT, arg) < 0) {
|
|
THROW_ERROR("failed to create report");
|
|
}
|
|
if (ioctl(sgx_fd, SGXIOC_VERIFY_REPORT, &report) < 0) {
|
|
THROW_ERROR("failed to verify report");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifndef OCCLUM_DISABLE_DCAP
|
|
#define REPORT_BODY_OFFSET 48
|
|
static int generate_and_verify_dcap_quote(int sgx_fd) {
|
|
// get quote size
|
|
uint32_t quote_size = 0;
|
|
if (ioctl(sgx_fd, SGXIOC_GET_DCAP_QUOTE_SIZE, "e_size) < 0) {
|
|
THROW_ERROR("failed to get quote size");
|
|
}
|
|
|
|
// get quote
|
|
uint8_t *quote_buffer = (uint8_t *)malloc(quote_size);
|
|
if (NULL == quote_buffer) {
|
|
THROW_ERROR("Couldn't allocate quote_buffer");
|
|
}
|
|
memset(quote_buffer, 0, quote_size);
|
|
|
|
sgx_report_data_t report_data = { 0 };
|
|
char *data = "ioctl DCAP report data example";
|
|
memcpy(report_data.d, data, strlen(data));
|
|
|
|
sgxioc_gen_dcap_quote_arg_t gen_quote_arg = {
|
|
.report_data = &report_data,
|
|
.quote_len = "e_size,
|
|
.quote_buf = quote_buffer
|
|
};
|
|
|
|
if (ioctl(sgx_fd, SGXIOC_GEN_DCAP_QUOTE, &gen_quote_arg) < 0) {
|
|
THROW_ERROR("failed to get quote");
|
|
}
|
|
|
|
if (memcmp((void *) & ((sgx_report_body_t *)(quote_buffer +
|
|
REPORT_BODY_OFFSET))->report_data,
|
|
(void *)&report_data, sizeof(sgx_report_data_t)) != 0) {
|
|
THROW_ERROR("mismathced report data");
|
|
}
|
|
|
|
uint32_t collateral_expiration_status = 1;
|
|
sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED;
|
|
|
|
uint32_t supplemental_size = 0;
|
|
if (ioctl(sgx_fd, SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE, &supplemental_size) < 0) {
|
|
THROW_ERROR("failed to get supplemental data size");
|
|
}
|
|
uint8_t *supplemental_buffer = (uint8_t *)malloc(supplemental_size);
|
|
if (NULL == supplemental_buffer) {
|
|
THROW_ERROR("Couldn't allocate quote_buffer");
|
|
}
|
|
memset(supplemental_buffer, 0, supplemental_size);
|
|
|
|
sgxioc_ver_dcap_quote_arg_t ver_quote_arg = {
|
|
.quote_buf = quote_buffer,
|
|
.quote_size = quote_size,
|
|
.collateral_expiration_status = &collateral_expiration_status,
|
|
.quote_verification_result = "e_verification_result,
|
|
.supplemental_data_size = supplemental_size,
|
|
.supplemental_data = supplemental_buffer
|
|
};
|
|
|
|
if (ioctl(sgx_fd, SGXIOC_VER_DCAP_QUOTE, &ver_quote_arg) < 0) {
|
|
THROW_ERROR("failed to verify quote");
|
|
}
|
|
|
|
switch (quote_verification_result) {
|
|
case SGX_QL_QV_RESULT_OK:
|
|
return 0;
|
|
case SGX_QL_QV_RESULT_CONFIG_NEEDED:
|
|
case SGX_QL_QV_RESULT_OUT_OF_DATE:
|
|
case SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED:
|
|
case SGX_QL_QV_RESULT_SW_HARDENING_NEEDED:
|
|
case SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED:
|
|
printf("WARN: App: Verification completed with Non-terminal result: %x\n",
|
|
quote_verification_result);
|
|
return 0;
|
|
case SGX_QL_QV_RESULT_INVALID_SIGNATURE:
|
|
case SGX_QL_QV_RESULT_REVOKED:
|
|
case SGX_QL_QV_RESULT_UNSPECIFIED:
|
|
default:
|
|
THROW_ERROR("\tError: App: Verification completed with Terminal result: %x\n",
|
|
quote_verification_result);
|
|
}
|
|
}
|
|
|
|
static int do_SGXIOC_GENERATE_AND_VERIFY_DCAP_QUOTE(int sgx_fd) {
|
|
int is_dcap_driver_installed = 0;
|
|
if (ioctl(sgx_fd, SGXIOC_DETECT_DCAP_DRIVER, &is_dcap_driver_installed) < 0) {
|
|
THROW_ERROR("failed to detect DCAP driver");
|
|
}
|
|
|
|
if (is_dcap_driver_installed == 0) {
|
|
printf("Warning: test_sgx_ioctl_SGXIOC_GENERATE_AND_VERIFY_DCAP_QUOTE is skipped\n");
|
|
return 0;
|
|
}
|
|
|
|
int nretries = 0;
|
|
while (nretries < IOCTL_MAX_RETRIES) {
|
|
int ret = generate_and_verify_dcap_quote(sgx_fd);
|
|
if (ret == 0) {
|
|
break;
|
|
} else if (errno != EBUSY) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
|
}
|
|
|
|
printf("WARN: /dev/sgx is temporarily busy. Try again after 1 second.");
|
|
sleep(1);
|
|
nretries++;
|
|
}
|
|
if (nretries == IOCTL_MAX_RETRIES) {
|
|
THROW_ERROR("failed to ioctl /dev/sgx due to timeout");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int test_sgx_ioctl_SGXIOC_GENERATE_AND_VERIFY_DCAP_QUOTE(void) {
|
|
return do_sgx_ioctl_test(do_SGXIOC_GENERATE_AND_VERIFY_DCAP_QUOTE);
|
|
}
|
|
#endif
|
|
|
|
int test_sgx_ioctl_SGXIOC_IS_EDMM_SUPPORTED(void) {
|
|
return do_sgx_ioctl_test(do_SGXIOC_IS_EDMM_SUPPORTED);
|
|
}
|
|
|
|
int test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID(void) {
|
|
return do_sgx_ioctl_test(do_SGXIOC_GET_EPID_GROUP_ID);
|
|
}
|
|
|
|
int test_sgx_ioctl_SGXIOC_GEN_EPID_QUOTE(void) {
|
|
return do_sgx_ioctl_test(do_SGXIOC_GEN_QUOTE);
|
|
}
|
|
|
|
int test_sgx_ioctl_SGXIOC_SELF_TARGET(void) {
|
|
return do_sgx_ioctl_test(do_SGXIOC_SELF_TARGET);
|
|
}
|
|
|
|
int test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT(void) {
|
|
return do_sgx_ioctl_test(do_SGXIOC_CREATE_AND_VERIFY_REPORT);
|
|
}
|
|
|
|
#define CONFIG_SIZE 512
|
|
int test_ioctl_SIOCGIFCONF(void) {
|
|
struct ifreq *req;
|
|
struct ifconf conf;
|
|
char *buf = (char *)malloc(CONFIG_SIZE);
|
|
if (buf == NULL) {
|
|
THROW_ERROR("malloc failed");
|
|
}
|
|
memset(buf, 0, CONFIG_SIZE);
|
|
|
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
conf.ifc_len = 0;
|
|
conf.ifc_buf = buf;
|
|
if (ioctl(sock, SIOCGIFCONF, &conf) < 0) {
|
|
close(sock);
|
|
THROW_ERROR("empty length ioctl failed");
|
|
}
|
|
|
|
if (conf.ifc_len != 0) {
|
|
close(sock);
|
|
THROW_ERROR("wrong returned length");
|
|
}
|
|
|
|
conf.ifc_len = CONFIG_SIZE;
|
|
conf.ifc_buf = 0;
|
|
if (ioctl(sock, SIOCGIFCONF, &conf) < 0) {
|
|
close(sock);
|
|
THROW_ERROR("empty buffer ioctl failed");
|
|
}
|
|
|
|
int ret_len = conf.ifc_len;
|
|
|
|
// use a larger buffer when the original one is insufficient
|
|
if (ret_len > CONFIG_SIZE) {
|
|
free(buf);
|
|
|
|
char *new_buf = (char *)malloc(ret_len);
|
|
if (new_buf == NULL) {
|
|
close(sock);
|
|
THROW_ERROR("malloc failed");
|
|
}
|
|
buf = new_buf;
|
|
memset(buf, 0, ret_len);
|
|
} else {
|
|
conf.ifc_len = CONFIG_SIZE;
|
|
}
|
|
|
|
conf.ifc_buf = buf;
|
|
if (ioctl(sock, SIOCGIFCONF, &conf) < 0) {
|
|
close(sock);
|
|
THROW_ERROR("buffer passed ioctl failed");
|
|
}
|
|
|
|
if (conf.ifc_len != ret_len) {
|
|
close(sock);
|
|
THROW_ERROR("wrong return length");
|
|
}
|
|
|
|
close(sock);
|
|
|
|
req = (struct ifreq *)buf;
|
|
int num = conf.ifc_len / sizeof (struct ifreq);
|
|
|
|
printf(" interface names got:\n");
|
|
for (int i = 0; i < num; i++) {
|
|
printf(" %d: %s\n", i + 1, req->ifr_name);
|
|
req ++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int test_ioctl_FIONBIO(void) {
|
|
int test_sock[2], sock;
|
|
test_sock[0] = socket(AF_INET, SOCK_STREAM, 0);
|
|
test_sock[1] = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
sock = test_sock[i];
|
|
int on = 1;
|
|
if (ioctl(sock, FIONBIO, &on) < 0) {
|
|
close(sock);
|
|
THROW_ERROR("ioctl FIONBIO failed");
|
|
}
|
|
|
|
int actual_flags = fcntl(sock, F_GETFL);
|
|
if ((actual_flags & O_NONBLOCK) == 0) {
|
|
close(sock);
|
|
THROW_ERROR("failed to check the O_NONBLOCK flag after FIONBIO");
|
|
}
|
|
|
|
close(sock);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int test_ioctl_FIOCLEX(void) {
|
|
// Open a file with O_CLOEXEC (close-on-exec)
|
|
char *tmp_file = "/tmp/test_fioclex";
|
|
int fd = open(tmp_file, O_CREAT | O_CLOEXEC, 0666);
|
|
if (fd < 0) {
|
|
THROW_ERROR("failed to open the tmp file");
|
|
}
|
|
|
|
// change this fd to "no close-on-exec"
|
|
int ret = ioctl(fd, FIONCLEX, NULL);
|
|
if (ret != 0) {
|
|
THROW_ERROR("ioctl FIONCLEX failed");
|
|
}
|
|
|
|
int pipefds[2];
|
|
ret = pipe(pipefds);
|
|
if (ret != 0) {
|
|
THROW_ERROR("failed to create pipe");
|
|
}
|
|
|
|
// set close on exec on reader end
|
|
ret = ioctl(pipefds[0], FIOCLEX, NULL);
|
|
if (ret != 0) {
|
|
THROW_ERROR("ioctl FIOCLEX failed");
|
|
}
|
|
|
|
// construct child process args
|
|
int child_pid, status;
|
|
int child_argc =
|
|
6; // ./nauty_child -t fioclex regular_file_fd pipe_reader_fd pipe_writer_fd
|
|
char **child_argv = calloc(1, sizeof(char *) * (child_argc + 1));
|
|
child_argv[0] = strdup("naughty_child");
|
|
child_argv[1] = strdup("-t");
|
|
child_argv[2] = strdup("fioclex");
|
|
asprintf(&child_argv[3], "%d", fd);
|
|
asprintf(&child_argv[4], "%d", pipefds[0]);
|
|
asprintf(&child_argv[5], "%d", pipefds[1]);
|
|
|
|
ret = posix_spawn(&child_pid, "/bin/naughty_child", NULL, NULL, child_argv, NULL);
|
|
if (ret != 0) {
|
|
THROW_ERROR("failed to spawn a child process\n");
|
|
}
|
|
|
|
ret = waitpid(child_pid, &status, 0);
|
|
if (ret < 0) {
|
|
THROW_ERROR("failed to wait4 the child process");
|
|
}
|
|
printf("child process %d exit status = %d\n", child_pid, status);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test suite
|
|
// ============================================================================
|
|
|
|
static test_case_t test_cases[] = {
|
|
TEST_CASE(test_tty_ioctl_TIOCGWINSZ),
|
|
TEST_CASE(test_ioctl_TCGETS_TCSETS),
|
|
TEST_CASE(test_sgx_ioctl_SGXIOC_IS_EDMM_SUPPORTED),
|
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID),
|
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_EPID_QUOTE),
|
|
TEST_CASE(test_sgx_ioctl_SGXIOC_SELF_TARGET),
|
|
TEST_CASE(test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT),
|
|
#ifndef OCCLUM_DISABLE_DCAP
|
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GENERATE_AND_VERIFY_DCAP_QUOTE),
|
|
#endif
|
|
TEST_CASE(test_ioctl_SIOCGIFCONF),
|
|
TEST_CASE(test_ioctl_FIONBIO),
|
|
TEST_CASE(test_ioctl_FIOCLEX),
|
|
};
|
|
|
|
int main() {
|
|
return test_suite_run(test_cases, ARRAY_SIZE(test_cases));
|
|
}
|