Add netdevice ioctl command

This commit is contained in:
He Sun 2020-08-18 11:40:26 +08:00 committed by Tate, Hongliang Tian
parent 5e9a617350
commit e13242e7e5
9 changed files with 215 additions and 24 deletions

@ -200,6 +200,14 @@ enclave {
void occlum_ocall_print_log(uint32_t level, [in, string] const char* msg); void occlum_ocall_print_log(uint32_t level, [in, string] const char* msg);
void occlum_ocall_flush_log(void); void occlum_ocall_flush_log(void);
int occlum_ocall_ioctl_repack(
int fd,
int request,
[in, out, size=len] char *buf,
int len,
[out] int* recv_len
) propagate_errno;
int occlum_ocall_ioctl( int occlum_ocall_ioctl(
int fd, int fd,
int request, int request,

@ -10,3 +10,18 @@ pub struct WinSize {
pub ws_xpixel: u16, pub ws_xpixel: u16,
pub ws_ypixel: u16, pub ws_ypixel: u16,
} }
#[derive(Debug)]
#[repr(C)]
pub struct IfConf {
pub ifc_len: i32,
pub ifc_buf: *const u8,
}
const IFNAMSIZ: usize = 16;
#[derive(Debug)]
#[repr(C)]
pub struct IfReq {
pub ifr_name: [u8; IFNAMSIZ],
pub ifr_union: [u8; 24],
}

@ -6,7 +6,7 @@
use super::*; use super::*;
pub use self::builtin::WinSize; pub use self::builtin::*;
pub use self::non_builtin::{NonBuiltinIoctlCmd, StructuredIoctlArgType, StructuredIoctlNum}; pub use self::non_builtin::{NonBuiltinIoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
#[macro_use] #[macro_use]
@ -37,6 +37,21 @@ impl_ioctl_nums_and_cmds! {
TIOCNOTTY => (0x5422, ()), TIOCNOTTY => (0x5422, ()),
// Get the number of bytes in the input buffer // Get the number of bytes in the input buffer
FIONREAD => (0x541B, mut i32), FIONREAD => (0x541B, mut i32),
// Low-level access to Linux network devices on man7/netdevice.7
// Only non-privileged operations are supported for now
SIOCGIFNAME => (0x8910, mut IfReq),
SIOCGIFCONF => (0x8912, mut IfConf),
SIOCGIFFLAGS => (0x8913, mut IfReq),
SIOCGIFADDR => (0x8915, mut IfReq),
SIOCGIFDSTADDR => (0x8917, mut IfReq),
SIOCGIFBRDADDR => (0x8919, mut IfReq),
SIOCGIFNETMASK => (0x891B, mut IfReq),
SIOCGIFMTU => (0x8921, mut IfReq),
SIOCGIFHWADDR => (0x8927, mut IfReq),
SIOCGIFINDEX => (0x8933, mut IfReq),
SIOCGIFPFLAGS => (0x8935, mut IfReq),
SIOCGIFTXQLEN => (0x8942, mut IfReq),
SIOCGIFMAP => (0x8970, mut IfReq),
} }
/// This is the centralized place to add sanity checks for the argument values /// This is the centralized place to add sanity checks for the argument values

@ -14,7 +14,8 @@ pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
pub use self::flock::{Flock, FlockType}; pub use self::flock::{Flock, FlockType};
pub use self::fsync::{do_fdatasync, do_fsync}; pub use self::fsync::{do_fdatasync, do_fsync};
pub use self::ioctl::{ pub use self::ioctl::{
do_ioctl, occlum_ocall_ioctl, IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum, do_ioctl, occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd, StructuredIoctlArgType,
StructuredIoctlNum,
}; };
pub use self::link::do_link; pub use self::link::do_link;
pub use self::lseek::do_lseek; pub use self::lseek::do_lseek;

@ -14,8 +14,8 @@ pub use self::dev_fs::AsDevRandom;
pub use self::event_file::{AsEvent, EventCreationFlags, EventFile}; pub use self::event_file::{AsEvent, EventCreationFlags, EventFile};
pub use self::file::{File, FileRef}; pub use self::file::{File, FileRef};
pub use self::file_ops::{ pub use self::file_ops::{
occlum_ocall_ioctl, AccessMode, CreationFlags, FileMode, Flock, FlockType, IoctlCmd, Stat, occlum_ocall_ioctl, AccessMode, BuiltinIoctlNum, CreationFlags, FileMode, Flock, FlockType,
StatusFlags, StructuredIoctlArgType, StructuredIoctlNum, IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
}; };
pub use self::file_table::{FileDesc, FileTable}; pub use self::file_table::{FileDesc, FileTable};
pub use self::fs_view::FsView; pub use self::fs_view::FsView;

@ -0,0 +1,82 @@
use super::*;
use fs::{occlum_ocall_ioctl, BuiltinIoctlNum, IoctlCmd};
impl SocketFile {
pub(super) fn ioctl_impl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
if let IoctlCmd::SIOCGIFCONF(arg_ref) = cmd {
return self.ioctl_getifconf(arg_ref);
}
let cmd_num = cmd.cmd_num() as c_int;
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
let ret = try_libc!({
let mut retval: i32 = 0;
let status = occlum_ocall_ioctl(
&mut retval as *mut i32,
self.fd(),
cmd_num,
cmd_arg_ptr,
cmd.arg_len(),
);
assert!(status == sgx_status_t::SGX_SUCCESS);
retval
});
// FIXME: add sanity checks for results returned for socket-related ioctls
cmd.validate_arg_and_ret_vals(ret)?;
Ok(ret)
}
fn ioctl_getifconf(&self, arg_ref: &mut IfConf) -> Result<i32> {
if !arg_ref.ifc_buf.is_null() && arg_ref.ifc_len == 0 {
return Ok(0);
}
let ret = try_libc!({
let mut recv_len: i32 = 0;
let mut retval: i32 = 0;
let status = occlum_ocall_ioctl_repack(
&mut retval as *mut i32,
self.fd(),
BuiltinIoctlNum::SIOCGIFCONF as i32,
arg_ref.ifc_buf,
arg_ref.ifc_len,
&mut recv_len as *mut i32,
);
assert!(status == sgx_status_t::SGX_SUCCESS);
// If ifc_req is NULL, SIOCGIFCONF returns the necessary buffer
// size in bytes for receiving all available addresses in ifc_len
// which is irrelevant to the orginal ifc_len.
if !arg_ref.ifc_buf.is_null() {
assert!(arg_ref.ifc_len >= recv_len);
}
arg_ref.ifc_len = recv_len;
retval
});
Ok(ret)
}
}
extern "C" {
// Used to ioctl arguments with pointer members.
//
// Before the call the area the pointers points to should be assembled into
// one continous memory block. Then the block is repacked to ioctl arguments
// in the ocall implementation in host.
//
// ret: holds the return value of ioctl in host
// fd: the host fd for the device
// cmd_num: request number of the ioctl
// buf: the data to exchange with host
// len: the size of the buf
// recv_len: accepts transferred data length when buf is used to get data from host
//
fn occlum_ocall_ioctl_repack(
ret: *mut i32,
fd: c_int,
cmd_num: c_int,
buf: *const u8,
len: i32,
recv_len: *mut i32,
) -> sgx_status_t;
}

@ -1,9 +1,11 @@
use super::*; use super::*;
use crate::fs::IfConf;
mod ioctl_impl;
mod recv; mod recv;
mod send; mod send;
use fs::{occlum_ocall_ioctl, AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags}; use fs::{AccessMode, CreationFlags, File, FileRef, IoctlCmd, StatusFlags};
use std::any::Any; use std::any::Any;
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
@ -107,23 +109,7 @@ impl File for SocketFile {
} }
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> { fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<i32> {
let cmd_num = cmd.cmd_num() as c_int; self.ioctl_impl(cmd)
let cmd_arg_ptr = cmd.arg_ptr() as *mut c_void;
let ret = try_libc!({
let mut retval: i32 = 0;
let status = occlum_ocall_ioctl(
&mut retval as *mut i32,
self.fd(),
cmd_num,
cmd_arg_ptr,
cmd.arg_len(),
);
assert!(status == sgx_status_t::SGX_SUCCESS);
retval
});
// FIXME: add sanity checks for results returned for socket-related ioctls
cmd.validate_arg_and_ret_vals(ret)?;
Ok(ret)
} }
fn get_access_mode(&self) -> Result<AccessMode> { fn get_access_mode(&self) -> Result<AccessMode> {

@ -1,5 +1,6 @@
#include "ocalls.h" #include "ocalls.h"
#include <errno.h> #include <errno.h>
#include <net/if.h>
#include <unistd.h> #include <unistd.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -12,9 +13,33 @@ int occlum_ocall_eventfd(unsigned int initval, int flags) {
return eventfd(initval, flags); return eventfd(initval, flags);
} }
int occlum_ocall_ioctl_repack(int fd, int request, char *buf, int len, int *recv_len) {
int ret = 0;
switch (request) {
case SIOCGIFCONF:
if (recv_len == NULL) {
errno = EINVAL;
return -1;
}
struct ifconf config = { .ifc_len = len, .ifc_buf = buf };
ret = ioctl(fd, SIOCGIFCONF, &config);
if (ret == 0) {
*recv_len = config.ifc_len;
}
break;
default:
errno = EINVAL;
return -1;
}
return ret;
}
int occlum_ocall_ioctl(int fd, int request, void *arg, size_t len) { int occlum_ocall_ioctl(int fd, int request, void *arg, size_t len) {
if (((arg == NULL) ^ (len == 0)) == 1) { if (((arg == NULL) ^ (len == 0)) == 1) {
printf("invalid ioctl parameters\n");
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }

@ -1,3 +1,5 @@
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -216,6 +218,62 @@ int test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT(void) {
return do_sgx_ioctl_test(do_SGXIOC_CREATE_AND_VERIFY_REPORT); 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[CONFIG_SIZE];
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;
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;
}
// ============================================================================ // ============================================================================
// Test suite // Test suite
// ============================================================================ // ============================================================================
@ -226,7 +284,8 @@ static test_case_t test_cases[] = {
TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID), TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID),
TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_QUOTE), TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_QUOTE),
TEST_CASE(test_sgx_ioctl_SGXIOC_SELF_TARGET), TEST_CASE(test_sgx_ioctl_SGXIOC_SELF_TARGET),
TEST_CASE(test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT) TEST_CASE(test_sgx_ioctl_SGXIOC_CREATE_AND_VERIFY_REPORT),
TEST_CASE(test_ioctl_SIOCGIFCONF),
}; };
int main() { int main() {