Skip to content

Commit

Permalink
Xun's patch to add ioctl support (gramineproject#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
gc-fu authored Oct 8, 2022
1 parent a9186a3 commit f798acc
Show file tree
Hide file tree
Showing 18 changed files with 1,266 additions and 4 deletions.
12 changes: 11 additions & 1 deletion libos/src/sys/libos_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <asm/ioctls.h>
#include <sys/ioctl.h>

#include "libos_handle.h"
#include "libos_internal.h"
Expand Down Expand Up @@ -37,7 +38,7 @@ long libos_syscall_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) {
if (!hdl)
return -EBADF;

int ret;
int ret = 0;
switch (cmd) {
case TIOCGPGRP:
if (!hdl->uri || strcmp(hdl->uri, "dev:tty") != 0) {
Expand Down Expand Up @@ -131,6 +132,15 @@ long libos_syscall_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) {
ret = 0;
break;
}
case SIOCGIFCONF:
case SIOCGIFHWADDR:
if (hdl->type == TYPE_SOCK) {
/* LibOS doesn't know how to handle this IOCTL, forward it to the host */
ret = PalDeviceIoControl(hdl->pal_handle, cmd, arg);
if (ret < 0)
ret = pal_to_unix_errno(ret);
}
break;
default:
ret = -ENOSYS;
break;
Expand Down
52 changes: 52 additions & 0 deletions libos/test/regression/ioctl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <sys/ioctl.h>
#include <string.h>
#include <malloc.h>
#include <stddef.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#define MAX_IFS 64
int main(int argc, char **argv) {
struct ifreq *ifr, *ifend;
struct ifreq ifreq;
struct ifconf ifc;
int SockFD;
SockFD = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifc, 1, sizeof(ifc));
ifc.ifc_req = NULL;
if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
printf("ioctl(SIOCGIFCONF): %m\n");
return 0;
}
//ifc.ifc_len = sizeof(ifs);
ifc.ifc_req =(struct ifreq*) malloc(ifc.ifc_len);
struct ifreq *ifs = ifc.ifc_req;
if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
printf("ioctl(SIOCGIFCONF): %m\n");
return 0;
}
ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
if (ifr->ifr_addr.sa_family == AF_INET) {
strncpy(ifreq.ifr_name, ifr->ifr_name,sizeof(ifreq.ifr_name));
if (ioctl (SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
printf("SIOCGIFHWADDR(%s): %m\n", ifreq.ifr_name);
return 0;
}
printf("Ip Address %s\n", inet_ntoa( ( (struct sockaddr_in *) &ifr->ifr_addr)->sin_addr));
printf("Device %s -> Ethernet %02x:%02x:%02x:%02x:%02x:%02x\n", ifreq.ifr_name,
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[0],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[1],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[2],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[3],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[4],
(int) ((unsigned char *) &ifreq.ifr_hwaddr.sa_data)[5]);
}
}
free(ifc.ifc_req);
return 0;
}
72 changes: 72 additions & 0 deletions libos/test/regression/ioctl.manifest.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
loader.entrypoint = "file:{{ gramine.libos }}"
libos.entrypoint = "{{ entrypoint }}"
loader.argv0_override = "{{ entrypoint }}"

loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr/{{ arch_libdir }}"
loader.insecure__use_cmdline_argv = true

# for eventfd test
sys.insecure__allow_eventfd = true

fs.mounts = [
{ path = "/lib", uri = "file:{{ gramine.runtimedir(libc) }}" },
{ path = "/{{ entrypoint }}", uri = "file:{{ binary_dir }}/{{ entrypoint }}" },
{ path = "/exec_victim", uri = "file:{{ binary_dir }}/exec_victim" },
{ path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" },
{ path = "/usr/{{ arch_libdir }}", uri = "file:/usr/{{ arch_libdir }}" },
{ path = "/bin", uri = "file:/bin" },

{ type = "tmpfs", path = "/mnt/tmpfs" },
{ type = "encrypted", path = "/tmp_enc", uri = "file:tmp_enc", key_name = "my_custom_key" },
{ type = "encrypted", path = "/encrypted_file_mrenclave.dat", uri = "file:encrypted_file_mrenclave.dat", key_name = "_sgx_mrenclave" },
{ type = "encrypted", path = "/encrypted_file_mrsigner.dat", uri = "file:encrypted_file_mrsigner.dat", key_name = "_sgx_mrsigner" },
]

#sgx.ioctl_structs.ifconf = [ {name = "ifc_len",size = 8, align = 8, type= "out" }, { ptr=[ {name="ifcu_req", size= "ifc_len", type="inout"} ] } ]
sgx.ioctl_structs.ifconf = [ {name = "ifc_len",size = 4, align = 4, type= "inout" }, {size = 4, type= "inout"}, { ptr=[ {name="ifcu_req", size= "ifc_len", type="in"} ] } ]
sgx.allowed_ioctls.io1.request = 0x8912
sgx.allowed_ioctls.io1.struct = "ifconf"

sgx.ioctl_structs.ifreq = [ { name ="ifreq", size=40, type="inout"} ]
sgx.allowed_ioctls.io2.request = 0x8927
sgx.allowed_ioctls.io2.struct = "ifreq"

sgx.thread_num = 16
sgx.nonpie_binary = true
sgx.debug = true

sgx.allowed_files = [
"file:tmp/",
"file:root", # for getdents test
"file:testfile", # for mmap_file test
"file:scripts/", # for exec_script test
]

sgx.trusted_files = [
"file:{{ gramine.libos }}",
"file:{{ gramine.runtimedir(libc) }}/",
"file:{{ arch_libdir }}/libgcc_s.so.1",
"file:/usr{{ arch_libdir }}/libstdc++.so.6",
"file:{{ binary_dir }}/{{ entrypoint }}",
"file:{{ binary_dir }}/exec_victim",
"file:/bin/sh",
]

sgx.insecure__protected_files_key = "ffeeddccbbaa99887766554433221100"
sgx.protected_files = [
"file:tmp/pf/",
]

# See the `keys.c` test.
fs.insecure__keys.default = "ffeeddccbbaa99887766554433221100"
fs.insecure__keys.my_custom_key = "00112233445566778899aabbccddeeff"

# for sealed_file_mrenclave* tests
sgx.protected_mrenclave_files = [
"file:sealed_file_mrenclave.dat",
]

# for sealed_file_mrsigner test
sgx.protected_mrsigner_files = [
"file:sealed_file_mrsigner.dat",
]
3 changes: 3 additions & 0 deletions libos/test/regression/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ if host_machine.cpu_family() == 'x86_64'
'bootstrap_cpp': {
'source': 'bootstrap_cpp.cpp',
},
'ioctl': {
'source': 'ioctl.cpp',
},
}
endif

Expand Down
6 changes: 6 additions & 0 deletions libos/test/regression/test_libos.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,12 @@ def test_310_socket_tcp_ipv6_v6only(self):
stdout, _ = self.run_binary(['tcp_ipv6_v6only'], timeout=50)
self.assertIn('test completed successfully', stdout)

@unittest.skipIf(USES_MUSL, 'C++ is not supported with musl')
def test_320_ioctl(self):
stdout, _ = self.run_binary(['ioctl'])
self.assertIn('Ip Address 127.0.0.1', stdout)
self.assertIn('Device lo -> Ethernet 00:00:00:00:00:00', stdout)

@unittest.skipUnless(HAS_SGX,
'This test is only meaningful on SGX PAL because only SGX emulates CPUID.')
class TC_90_CpuidSGX(RegressionTestCase):
Expand Down
1 change: 1 addition & 0 deletions libos/test/regression/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ manifests = [
"debug_regs_x86_64",
"rdtsc",
"bootstrap_cpp",
"ioctl",
"sighandler_divbyzero",
]

Expand Down
17 changes: 17 additions & 0 deletions pal/include/pal/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,23 @@ int PalSegmentBaseSet(enum pal_segment_reg reg, uintptr_t addr);
*/
size_t PalMemoryAvailableQuota(void);

/*!
* \brief Perform a device-specific operation `cmd`.
*
* This function corresponds to ioctl() in UNIX systems and DeviceIoControl() in Windows.
*
* \param[in] handle Handle of the device.
* \param[in] cmd Device-dependent request/control code.
* \param[in,out] arg Arbitrary argument to `cmd`. May be unused or used as a 64-bit integer
* or used as a pointer to a buffer that contains the data required to
* perform the operation as well as the data returned by the operation. For
* some PALs (e.g., Linux-SGX PAL), the manifest must describe the layout of
* this buffer in order to correctly copy the data to/from the host.
*
* \return Returns 1 on success, 0 on failure. Use PAL_ERRNO() to get the actual error code.
*/
bool PalDeviceIoControl(PAL_HANDLE handle, unsigned int cmd, uint64_t arg);

/*!
* \brief Obtain the attestation report (local) with `user_report_data` embedded into it.
*
Expand Down
1 change: 1 addition & 0 deletions pal/include/pal_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ double _PalGetBogomips(void);
int _PalSegmentBaseGet(enum pal_segment_reg reg, uintptr_t* addr);
int _PalSegmentBaseSet(enum pal_segment_reg reg, uintptr_t addr);
int _PalCpuIdRetrieve(uint32_t leaf, uint32_t subleaf, uint32_t values[4]);
int _PalDeviceIoControl(PAL_HANDLE handle, unsigned int cmd, uint64_t arg);
int _PalAttestationReport(const void* user_report_data, size_t* user_report_data_size,
void* target_info, size_t* target_info_size, void* report,
size_t* report_size);
Expand Down
25 changes: 23 additions & 2 deletions pal/src/host/linux-sgx/enclave_ocalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ int ocall_munmap_untrusted(const void* addr, size_t size) {
* handling do not use the cache and always explicitly mmap/munmap untrusted memory; 'need_munmap'
* indicates whether explicit munmap is needed at the end of such OCALL.
*/
static int ocall_mmap_untrusted_cache(size_t size, void** addrptr, bool* need_munmap) {
int ocall_mmap_untrusted_cache(size_t size, void** addrptr, bool* need_munmap) {
int ret;

*addrptr = NULL;
Expand Down Expand Up @@ -330,7 +330,7 @@ static int ocall_mmap_untrusted_cache(size_t size, void** addrptr, bool* need_mu
return ret;
}

static void ocall_munmap_untrusted_cache(void* addr, size_t size, bool need_munmap) {
void ocall_munmap_untrusted_cache(void* addr, size_t size, bool need_munmap) {
if (need_munmap) {
ocall_munmap_untrusted(addr, size);
/* there is not much we can do in case of error */
Expand Down Expand Up @@ -2178,3 +2178,24 @@ int ocall_sched_getaffinity(void* tcs, unsigned long* cpu_mask, size_t cpu_mask_
sgx_reset_ustack(old_ustack);
return retval;
}

int ocall_ioctl(int fd, unsigned int cmd, unsigned long arg) {
int retval = 0;
ms_ocall_ioctl_t* ms;

void* old_ustack = sgx_prepare_ustack();
ms = sgx_alloc_on_ustack_aligned(sizeof(*ms), alignof(*ms));
if (!ms) {
sgx_reset_ustack(old_ustack);
return -EPERM;
}

WRITE_ONCE(ms->ms_fd, fd);
WRITE_ONCE(ms->ms_cmd, cmd);
WRITE_ONCE(ms->ms_arg, arg);

retval = sgx_exitless_ocall(OCALL_IOCTL, ms);

sgx_reset_ustack(old_ustack);
return retval;
}
6 changes: 6 additions & 0 deletions pal/src/host/linux-sgx/enclave_ocalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ int ocall_mmap_untrusted(void** addrptr, size_t size, int prot, int flags, int f

int ocall_munmap_untrusted(const void* addr, size_t size);

int ocall_mmap_untrusted_cache(size_t size, void** mem, bool* need_munmap);

void ocall_munmap_untrusted_cache(void* mem, size_t size, bool need_munmap);

int ocall_cpuid(unsigned int leaf, unsigned int subleaf, unsigned int values[4]);

int ocall_open(const char* pathname, int flags, unsigned short mode);
Expand Down Expand Up @@ -105,6 +109,8 @@ int ocall_debug_describe_location(uintptr_t addr, char* buf, size_t buf_size);

int ocall_eventfd(int flags);

int ocall_ioctl(int fd, unsigned int cmd, unsigned long arg);

/*!
* \brief Execute untrusted code in PAL to obtain a quote from the Quoting Enclave.
*
Expand Down
20 changes: 19 additions & 1 deletion pal/src/host/linux-sgx/host_ocalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ static long sgx_ocall_send(void* pms) {
hdr.msg_controllen = ms->ms_controllen;
hdr.msg_flags = 0;

ret = DO_SYSCALL_INTERRUPTIBLE(sendmsg, ms->ms_sockfd, &hdr, MSG_NOSIGNAL | ms->ms_flags);
ret = DO_SYSCALL_INTERRUPTIBLE(sendmsg, ms->ms_sockfd, &hdr, MSG_NOSIGNAL | ms->ms_flags);////
return ret;
}

Expand Down Expand Up @@ -691,6 +691,23 @@ static long sgx_ocall_eventfd(void* pms) {
return ret;
}

static long sgx_ocall_ioctl(void* pms) {
ms_ocall_ioctl_t* ms = (ms_ocall_ioctl_t*)pms;
long ret;
if(ms->ms_fd)
ret = DO_SYSCALL(ioctl, ms->ms_fd, ms->ms_cmd, ms->ms_arg);
else {
ret = DO_SYSCALL(socket, AF_UNIX, SOCK_STREAM, 0);
if (ret < 0)
goto err;
long fd = ret;
ret = DO_SYSCALL(ioctl, fd, ms->ms_cmd, ms->ms_arg);
DO_SYSCALL(close, fd);
}
err:
return ret;
}

static long sgx_ocall_debug_map_add(void* pms) {
ms_ocall_debug_map_add_t* ms = (ms_ocall_debug_map_add_t*)pms;

Expand Down Expand Up @@ -781,6 +798,7 @@ sgx_ocall_fn_t ocall_table[OCALL_NR] = {
[OCALL_DEBUG_MAP_REMOVE] = sgx_ocall_debug_map_remove,
[OCALL_DEBUG_DESCRIBE_LOCATION] = sgx_ocall_debug_describe_location,
[OCALL_EVENTFD] = sgx_ocall_eventfd,
[OCALL_IOCTL] = sgx_ocall_ioctl,
[OCALL_GET_QUOTE] = sgx_ocall_get_quote,
};

Expand Down
Loading

0 comments on commit f798acc

Please sign in to comment.