Skip to content

Commit

Permalink
ioctl patch of li xun (gramineproject#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShanSimu authored May 22, 2023
1 parent 8a4edcc commit 4e86e76
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 12 deletions.
18 changes: 18 additions & 0 deletions common/include/linux_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,21 @@ struct linger {
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2

/* Length of interface name. */
#define IFNAMSIZ 16
struct ifreq {
char ifr_name[IFNAMSIZ]; /* Interface name */
char ifr_ifru[24];
};

struct ifconf {
int ifc_len; /* size of buffer */
union {
char *ifc_buf; /* buffer address */
struct ifreq *ifc_req; /* array of structures */
};
};

#define SIOCGIFCONF 0x8912 /* get iface list */
#define SIOCGIFHWADDR 0x8927 /* Get hardware address */
40 changes: 40 additions & 0 deletions libos/src/fs/socket/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,46 @@ static int ioctl(struct libos_handle* handle, unsigned int cmd, unsigned long ar
}
*(int*)arg = size;
return 0;
case SIOCGIFCONF:;
PAL_HANDLE pal_handle = __atomic_load_n(&handle->info.sock.pal_handle, __ATOMIC_ACQUIRE);
if (!pal_handle) {
return -EINVAL;
}
if (!is_user_memory_writable((void*)arg, sizeof(struct ifconf))) {
return -PAL_ERROR_INVAL;
}
struct ifconf ifc;
memcpy((void*)&ifc, (void*)arg, sizeof(struct ifconf));
if (ifc.ifc_buf != NULL && !is_user_memory_writable(ifc.ifc_buf, ifc.ifc_len)) {
return -PAL_ERROR_INVAL;
}
int cmd_ret;
ret = PalSocketIoControl(pal_handle, cmd, (unsigned long)&ifc, &cmd_ret);
if (ret < 0) {
return pal_to_unix_errno(ret);
}

memcpy((void*)arg, (void*)&ifc, sizeof(struct ifconf));
assert(ret == 0);
return cmd_ret;
case SIOCGIFHWADDR:;
pal_handle = __atomic_load_n(&handle->info.sock.pal_handle, __ATOMIC_ACQUIRE);
if (!pal_handle) {
return -EINVAL;
}
if (!is_user_memory_writable((void*)arg, sizeof(struct ifreq))) {
return -PAL_ERROR_INVAL;
}
struct ifreq ifr;
memcpy((void*)&ifr, (void*)arg, sizeof(struct ifreq));
ret = PalSocketIoControl(pal_handle, cmd, (unsigned long)&ifr, &cmd_ret);
if (ret < 0) {
return pal_to_unix_errno(ret);
}

memcpy((void*)arg, (void*)&ifr, sizeof(struct ifreq));
assert(ret == 0);
return cmd_ret;
default:
return -ENOTTY;
}
Expand Down
28 changes: 16 additions & 12 deletions libos/src/sys/libos_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "libos_process.h"
#include "libos_signal.h"
#include "libos_table.h"
#include "socket_utils.h"
#include "pal.h"

static void signal_io(IDTYPE caller, void* arg) {
Expand Down Expand Up @@ -133,23 +134,26 @@ long libos_syscall_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) {
break;
}
case SIOCGIFCONF:
case SIOCGIFHWADDR:
if (hdl->type == TYPE_SOCK) {
/* LibOS doesn't know how to handle this IOCTL, forward it to the host */
int cmd_ret;
ret = PalDeviceIoControl(hdl->pal_handle, cmd, arg, &cmd_ret);
if (ret < 0) {
ret = pal_to_unix_errno(ret);
break;
}
/* fallthrough */
case SIOCGIFHWADDR:{
if (!is_user_memory_writable((void*)arg, sizeof(int))) {
ret = -EFAULT;
break;
}

struct libos_fs* fs = hdl->fs;
if (!fs || !fs->fs_ops) {
ret = -ENOTTY;
break;
}

assert(ret == 0);
ret = cmd_ret;
if (fs->fs_ops->ioctl) {
ret = fs->fs_ops->ioctl(hdl, cmd, arg);
} else {
ret = -ENOSYS;
}
break;

}
default:
ret = -ENOSYS;
break;
Expand Down
16 changes: 16 additions & 0 deletions pal/include/pal/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,22 @@ int PalVirtualMemoryFree(void* addr, size_t size);
*/
int PalVirtualMemoryProtect(void* addr, size_t size, pal_prot_flags_t prot);

/*!
* \brief Perform a socket-specific operation `cmd`.
*
* \param handle Handle of the socket.
* \param cmd socket-specific 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.
* \param[out] out_ret Typically zero.
*
* \returns 0 on success, negative error value on failure.
*
* This function corresponds to ioctl() in UNIX systems.
*/
int PalSocketIoControl(PAL_HANDLE handle, uint32_t cmd, unsigned long arg, int* out_ret);

/*
* PROCESS CREATION
*/
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 @@ -195,6 +195,7 @@ int _PalSocketSend(PAL_HANDLE handle, struct pal_iovec* iov, size_t iov_len, siz
struct pal_socket_addr* addr, bool force_nonblocking);
int _PalSocketRecv(PAL_HANDLE handle, struct pal_iovec* iov, size_t iov_len, size_t* out_total_size,
struct pal_socket_addr* addr, bool force_nonblocking);
int _PalSocketIoControl(PAL_HANDLE handle, uint32_t cmd, unsigned long arg, int* out_ret);

/* PalProcess and PalThread calls */
int _PalThreadCreate(PAL_HANDLE* handle, int (*callback)(void*), void* param);
Expand Down
94 changes: 94 additions & 0 deletions pal/src/host/linux-sgx/pal_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -648,3 +648,97 @@ int _PalSocketRecv(PAL_HANDLE handle, struct pal_iovec* iov, size_t iov_len, siz
}
return handle->sock.ops->recv(handle, iov, iov_len, out_total_size, addr, force_nonblocking);
}


int _PalSocketIoControl(PAL_HANDLE handle, uint32_t cmd, unsigned long arg, int* out_ret) {
assert(handle->hdr.type == PAL_TYPE_SOCKET);
int ret;

if (handle->sock.fd == PAL_IDX_POISON)
return -PAL_ERROR_DENIED;

void* untrusted_addr = NULL;
size_t untrusted_size = 0;
switch (cmd) {
case SIOCGIFCONF:{
if (((struct ifconf *)arg)->ifc_buf == NULL)
untrusted_size = sizeof(struct ifconf);
else
untrusted_size = sizeof(struct ifconf) + ((struct ifconf *)arg)->ifc_len;

ret = ocall_mmap_untrusted(&untrusted_addr, ALLOC_ALIGN_UP(untrusted_size),
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, /*fd=*/-1,
/*offset=*/0);
if (ret < 0) {
ret = unix_to_pal_error(ret);
break;
}
assert(untrusted_addr);
if (((struct ifconf *)arg)->ifc_buf != NULL) {
((struct ifconf *)untrusted_addr)->ifc_buf = untrusted_addr + sizeof(struct ifconf);
if (!memcpy(&((struct ifconf *)untrusted_addr)->ifc_len,
&((struct ifconf *)arg)->ifc_len, sizeof(int))) {
ret = -PAL_ERROR_DENIED;
break;
}
}

int ioctl_ret = ocall_ioctl(handle->sock.fd, cmd, (unsigned long)untrusted_addr);
if (ioctl_ret < 0) {
ret = unix_to_pal_error(ioctl_ret);
break;
}
int ifc_len = COPY_UNTRUSTED_VALUE(&((struct ifconf *)untrusted_addr)->ifc_len);
if (ifc_len % sizeof(struct ifreq) != 0) {
ret = -PAL_ERROR_INVAL;
break;
}
if (((struct ifconf *)arg)->ifc_buf != NULL) {
if (ifc_len > ((struct ifconf *)arg)->ifc_len) {
ret = -PAL_ERROR_INVAL;
break;
}
sgx_copy_to_enclave_verified(((struct ifconf *)arg)->ifc_buf,
untrusted_addr + sizeof(struct ifconf), ifc_len);
}
((struct ifconf *)arg)->ifc_len = ifc_len;
*out_ret = ioctl_ret;
ret = 0;
break;
}
case SIOCGIFHWADDR:{
untrusted_size = sizeof(struct ifreq);
ret = ocall_mmap_untrusted(&untrusted_addr, ALLOC_ALIGN_UP(untrusted_size),
PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
/*fd=*/-1, /*offset=*/0);
if (ret < 0) {
ret = unix_to_pal_error(ret);
break;
}

assert(untrusted_addr);
if (!memcpy(untrusted_addr, (void*)arg,
sizeof((struct ifreq*)arg)->ifr_name)) {
ret = -PAL_ERROR_DENIED;
break;
}
int ioctl_ret = ocall_ioctl(handle->sock.fd, cmd, (unsigned long)untrusted_addr);
if (ioctl_ret < 0) {
ret = unix_to_pal_error(ioctl_ret);
break;
}
sgx_copy_to_enclave_verified(&((struct ifreq*)arg)->ifr_ifru,
&((struct ifreq*)untrusted_addr)->ifr_ifru,
sizeof((struct ifreq*)arg)->ifr_ifru);
*out_ret = ioctl_ret;
break;
}
default:
ret = -ENOSYS;
break;
}

if (untrusted_addr)
ocall_munmap_untrusted(untrusted_addr, ALLOC_ALIGN_UP(untrusted_size));
return ret;
}
13 changes: 13 additions & 0 deletions pal/src/host/linux/pal_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,3 +698,16 @@ int _PalSocketRecv(PAL_HANDLE handle, struct pal_iovec* iov, size_t iov_len, siz
}
return handle->sock.ops->recv(handle, iov, iov_len, out_total_size, addr, force_nonblocking);
}

int _PalSocketIoControl(PAL_HANDLE handle, uint32_t cmd, unsigned long arg, int* out_ret) {
assert(handle->hdr.type == PAL_TYPE_SOCKET);
if (handle->sock.fd == PAL_IDX_POISON)
return -PAL_ERROR_DENIED;

int ret = DO_SYSCALL(ioctl, handle->sock.fd, cmd, arg);
if (ret < 0)
return unix_to_pal_error(ret);

*out_ret = ret;
return 0;
}
4 changes: 4 additions & 0 deletions pal/src/host/skeleton/pal_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@ int _PalSocketRecv(PAL_HANDLE handle, struct pal_iovec* iov, size_t iov_len, siz
struct pal_socket_addr* addr, bool force_nonblocking) {
return -PAL_ERROR_NOTIMPLEMENTED;
}

int _PalSocketIoControl(PAL_HANDLE handle, uint32_t cmd, unsigned long arg, int* out_ret) {
return -PAL_ERROR_NOTIMPLEMENTED;
}
5 changes: 5 additions & 0 deletions pal/src/pal_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ int PalSocketRecv(PAL_HANDLE handle, struct pal_iovec* iov, size_t iov_len, size
assert(handle->hdr.type == PAL_TYPE_SOCKET);
return _PalSocketRecv(handle, iov, iov_len, out_total_size, addr, force_nonblocking);
}

int PalSocketIoControl(PAL_HANDLE handle, uint32_t cmd, unsigned long arg, int* out_ret) {
assert(handle->hdr.type == PAL_TYPE_SOCKET);
return _PalSocketIoControl(handle, cmd, arg, out_ret);
}
1 change: 1 addition & 0 deletions pal/src/pal_symbols
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ PalSocketAccept
PalSocketConnect
PalSocketSend
PalSocketRecv
PalSocketIoControl
PalSendHandle
PalReceiveHandle
PalStreamWaitForClient
Expand Down

0 comments on commit 4e86e76

Please sign in to comment.