diff --git a/src/libos/Cargo.lock b/src/libos/Cargo.lock index 8628dd6b..9e9792fb 100644 --- a/src/libos/Cargo.lock +++ b/src/libos/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Occlum" version = "0.27.0" @@ -22,6 +24,7 @@ dependencies = [ "rcore-fs-ramfs", "rcore-fs-sefs", "rcore-fs-unionfs", + "regex", "resolv-conf", "ringbuf", "scroll", @@ -518,6 +521,23 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "regex" +version = "1.3.1" +source = "git+https://github.com/mesalock-linux/regex-sgx#76aef86f9836532d17764523d0fa23bb7d2e31cf" +dependencies = [ + "regex-syntax", + "sgx_tstd", +] + +[[package]] +name = "regex-syntax" +version = "0.6.12" +source = "git+https://github.com/mesalock-linux/regex-sgx#76aef86f9836532d17764523d0fa23bb7d2e31cf" +dependencies = [ + "sgx_tstd", +] + [[package]] name = "resolv-conf" version = "0.7.0" diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index 9af551a2..ca5fb4c7 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -29,6 +29,7 @@ memoffset = "0.6.1" scroll = { version = "0.10.2", default-features = false } itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] } ctor = "0.1" +regex = { git = "https://github.com/mesalock-linux/regex-sgx", default-features = false, features = ["std", "unicode", "mesalock_sgx"] } [patch.'https://github.com/apache/teaclave-sgx-sdk.git'] sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd" } diff --git a/src/libos/include/edl/occlum_edl_types.h b/src/libos/include/edl/occlum_edl_types.h index 5079bdbc..4f100e2e 100644 --- a/src/libos/include/edl/occlum_edl_types.h +++ b/src/libos/include/edl/occlum_edl_types.h @@ -29,11 +29,11 @@ typedef struct itimerspec{ struct _timespec it_value; } itimerspec_t; -// todo: more detailed description +// The host_file_buffer struct includes /etc/resolv.conf, /etc/hosts and /etc/hostname buffer struct host_file_buffer { - const char* resolv_conf_ptr; - const char* hosts_ptr; - const char* hostname_ptr; + const char* resolv_conf_buf; + const char* hosts_buf; + const char* hostname_buf; }; #define FD_SETSIZE 1024 diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index e89e19af..0549f008 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -98,7 +98,7 @@ pub extern "C" fn occlum_ecall_init( }); // Parse host file - let resolv_conf_ptr = unsafe { (*file_buffer).resolv_conf_ptr }; + let resolv_conf_ptr = unsafe { (*file_buffer).resolv_conf_buf }; match parse_host_file(HostFile::RESOLV_CONF, resolv_conf_ptr) { Err(e) => { error!("failed to parse /etc/resolv.conf: {}", e.backtrace()); @@ -111,12 +111,13 @@ pub extern "C" fn occlum_ecall_init( } } - let hostname_ptr = unsafe { (*file_buffer).hostname_ptr }; + let hostname_ptr = unsafe { (*file_buffer).hostname_buf }; match parse_host_file(HostFile::HOSTNAME, hostname_ptr) { Err(e) => { error!("failed to parse /etc/hostname: {}", e.backtrace()); } Ok(hostname_str) => { + misc::init_nodename(&hostname_str); *HOSTNAME_STR.write().unwrap() = Some(hostname_str); if let Err(e) = write_host_file(HostFile::HOSTNAME) { error!("failed to write /etc/hostname: {}", e.backtrace()); @@ -124,7 +125,7 @@ pub extern "C" fn occlum_ecall_init( } } - let hosts_ptr = unsafe { (*file_buffer).hosts_ptr }; + let hosts_ptr = unsafe { (*file_buffer).hosts_buf }; match parse_host_file(HostFile::HOSTS, hosts_ptr) { Err(e) => { error!("failed to parse /etc/hosts: {}", e.backtrace()); diff --git a/src/libos/src/misc/mod.rs b/src/libos/src/misc/mod.rs index 34923189..e6280a9e 100644 --- a/src/libos/src/misc/mod.rs +++ b/src/libos/src/misc/mod.rs @@ -10,4 +10,4 @@ mod uname; pub use self::random::{do_getrandom, get_random, RandFlags}; pub use self::rlimit::{do_prlimit, resource_t, rlimit_t, ResourceLimits}; pub use self::sysinfo::{do_sysinfo, sysinfo_t}; -pub use self::uname::{do_uname, utsname_t}; +pub use self::uname::{do_uname, init_nodename, utsname_t}; diff --git a/src/libos/src/misc/uname.rs b/src/libos/src/misc/uname.rs index 0dd1ad8b..a6cd01ba 100644 --- a/src/libos/src/misc/uname.rs +++ b/src/libos/src/misc/uname.rs @@ -1,7 +1,5 @@ use super::*; -use crate::fs::{AccessMode, CreationFlags, FileMode, FsView}; use std::ffi::{CStr, CString}; -use std::str; /// A sample of `struct utsname` /// ``` /// sysname = Linux @@ -26,7 +24,7 @@ pub struct utsname_t { pub fn do_uname(name: &mut utsname_t) -> Result<()> { copy_from_cstr_to_u8_array(&SYSNAME, &mut name.sysname); - obtain_nodename(&mut name.nodename); + copy_from_cstr_to_u8_array(&NODENAME.read().unwrap(), &mut name.nodename); copy_from_cstr_to_u8_array(&RELEASE, &mut name.release); copy_from_cstr_to_u8_array(&VERSION, &mut name.version); copy_from_cstr_to_u8_array(&MACHINE, &mut name.machine); @@ -36,7 +34,7 @@ pub fn do_uname(name: &mut utsname_t) -> Result<()> { lazy_static! { static ref SYSNAME: CString = CString::new("Occlum").unwrap(); - static ref NODENAME: CString = CString::new("occlum-node").unwrap(); + static ref NODENAME: RwLock = RwLock::new(CString::new("occlum-node").unwrap()); static ref RELEASE: CString = CString::new("0.1").unwrap(); static ref VERSION: CString = CString::new("0.1").unwrap(); static ref MACHINE: CString = CString::new("x86-64").unwrap(); @@ -50,31 +48,8 @@ fn copy_from_cstr_to_u8_array(src: &CStr, dst: &mut [u8]) { dst[len] = 0; } -fn obtain_nodename(dst: &mut [u8]) { - const HOSTNAME_PATH: &'static str = "/etc/hostname"; - - let fs_view = FsView::new(); - - let hostname_file = match fs_view.open_file( - HOSTNAME_PATH, - AccessMode::O_RDONLY as u32, - FileMode::from_bits(0o666).unwrap(), - ) { - Ok(file) => file, - Err(e) => { - // If failed to open hostname file, use "occlum-node" nodename. - error!("failed to open /etc/hostname: {}", e.backtrace()); - copy_from_cstr_to_u8_array(&NODENAME, dst); - return; - } - }; - - let mut nodename: [u8; 65] = [0; 65]; - hostname_file.read(&mut nodename); - - // The \n need to be eliminated. - let nodename_string = str::from_utf8(&nodename).unwrap().replace("\n", ""); - let len = nodename_string.len(); - dst[..len].copy_from_slice(&nodename_string.into_bytes()); - dst[len] = 0; +pub fn init_nodename(nodename_str: &str) { + let nodename_cstr = CString::new(nodename_str).unwrap(); + let mut nodename = NODENAME.write().unwrap(); + *nodename = nodename_cstr; } diff --git a/src/libos/src/util/host_file_util.rs b/src/libos/src/util/host_file_util.rs index d9190be8..6b8a55b3 100644 --- a/src/libos/src/util/host_file_util.rs +++ b/src/libos/src/util/host_file_util.rs @@ -6,9 +6,9 @@ use std::str; #[repr(C)] pub struct host_file_buffer { - pub resolv_conf_ptr: *const c_char, - pub hosts_ptr: *const c_char, - pub hostname_ptr: *const c_char, + pub resolv_conf_buf: *const c_char, + pub hosts_buf: *const c_char, + pub hostname_buf: *const c_char, } pub enum HostFile { @@ -57,15 +57,22 @@ pub fn parse_host_file(host_file: HostFile, host_file_ptr: *const c_char) -> Res let host_file_str = str::from_utf8(host_file_bytes) .map_err(|_| errno!(EINVAL, "host file contains non UTF-8 characters"))?; + // Parse and inspect host file match host_file { HostFile::HOSTS => { - // TODO: Parsing hosts - } - HostFile::HOSTNAME => { - // TODO: Parsing hostname + if let Err(_) = hosts_parser_util::parse_hosts_buffer(host_file_bytes) { + return_errno!(EINVAL, "malformated host /etc/hosts"); + } } + HostFile::HOSTNAME => match hosts_parser_util::parse_hostname_buffer(host_file_bytes) { + Err(_) => { + return_errno!(EINVAL, "malformated host /etc/hostname"); + } + Ok(hostname_str) => { + return Ok(hostname_str); + } + }, HostFile::RESOLV_CONF => { - // Parse and inspect host file if let Err(_) = resolv_conf::Config::parse(host_file_bytes) { return_errno!(EINVAL, "malformated host /etc/resolv.conf"); } diff --git a/src/libos/src/util/hosts_parser_util.rs b/src/libos/src/util/hosts_parser_util.rs new file mode 100644 index 00000000..a457eaca --- /dev/null +++ b/src/libos/src/util/hosts_parser_util.rs @@ -0,0 +1,103 @@ +use super::*; +use regex::Regex; +use std::net::IpAddr; +use std::path::Path; +use std::str; +use std::str::FromStr; + +lazy_static! { + // The hostname regex is compliant with RFC1123 + static ref HOSTNAME_RE: Regex = Regex::new(r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$").unwrap(); +} + +#[derive(Debug, Default, Clone)] +pub struct HostEntry { + ip: String, + hostname: Vec, +} + +#[derive(Debug, Default, Clone)] +pub struct Hosts { + pub entries: Vec, +} + +impl FromStr for HostEntry { + type Err = error::Error; + fn from_str(line: &str) -> Result { + let slice: Vec = line.split_whitespace().map(|s| s.to_string()).collect(); + + // check IP: + let ip = match slice.first() { + Some(ip) => ip, + None => { + return_errno!(EINVAL, "malformated ip in hosts file"); + } + }; + + let _ip_addr: IpAddr = match ip.parse() { + Ok(ip) => ip, + Err(_) => { + return_errno!(EINVAL, "malformated ip in hosts file"); + } + }; + + let mut hostname: Vec = Vec::new(); + for i in slice[1..].to_vec() { + if !HOSTNAME_RE.is_match(&i) { + return_errno!(EINVAL, "malformated hostname in hosts file"); + } + hostname.push(i.to_owned()); + } + + if hostname.is_empty() { + return_errno!(EINVAL, "malformated hostname in hosts file"); + } + Ok(HostEntry { + ip: ip.to_string(), + hostname, + }) + } +} + +pub fn parse_hosts_buffer(bytes: &[u8]) -> Result { + let mut hosts: Hosts = Default::default(); + for (_, line) in bytes.split(|&x| x == b'\n').enumerate() { + let line = str::from_utf8(line).unwrap(); + let line = line.trim_start(); + match line.chars().next() { + // comment + Some('#') => continue, + // empty line + None => continue, + // valid line + Some(_) => {} + } + hosts.entries.push(line.parse()?); + } + Ok(hosts) +} + +pub fn parse_hostname_buffer(bytes: &[u8]) -> Result { + let mut hostname: Vec = Vec::new(); + for (_, line) in bytes.split(|&x| x == b'\n').enumerate() { + let line = str::from_utf8(line).unwrap(); + let line = line.trim_start(); + match line.chars().next() { + // comment + Some('#') => continue, + // empty line + None => continue, + // valid line + Some(_) => {} + } + if (!HOSTNAME_RE.is_match(&line)) | (line.len() > 64) { + return_errno!(EINVAL, "malformated hostname in /etc/hostname file"); + } + hostname.push(line.to_owned()); + } + + if hostname.len() != 1 { + return_errno!(EINVAL, "malformated hostname in /etc/hostname file"); + } + Ok(hostname[0].clone()) +} diff --git a/src/libos/src/util/mod.rs b/src/libos/src/util/mod.rs index 4a4e3c68..d7c4cd1f 100644 --- a/src/libos/src/util/mod.rs +++ b/src/libos/src/util/mod.rs @@ -2,6 +2,7 @@ use super::*; pub mod dirty; pub mod host_file_util; +pub mod hosts_parser_util; pub mod log; pub mod mem_util; pub mod mpx_util; diff --git a/src/pal/include/occlum_pal_api.h b/src/pal/include/occlum_pal_api.h index dfbece25..1e689a07 100644 --- a/src/pal/include/occlum_pal_api.h +++ b/src/pal/include/occlum_pal_api.h @@ -93,11 +93,10 @@ struct occlum_pal_create_process_args { int *pid; }; -// todo: more detailed description struct host_file_buffer { - const char *resolv_conf_ptr; - const char *hosts_ptr; - const char *hostname_ptr; + const char *resolv_conf_buf; + const char *hosts_buf; + const char *hostname_buf; }; /* @@ -165,6 +164,8 @@ int occlum_pal_kill(int pid, int sig); */ int occlum_pal_destroy(void); +void free_host_file_buffer(struct host_file_buffer file_buffer); + #ifdef __cplusplus } #endif diff --git a/src/pal/src/pal_api.c b/src/pal/src/pal_api.c index 6b8ea9de..26aaa8da 100644 --- a/src/pal/src/pal_api.c +++ b/src/pal/src/pal_api.c @@ -108,9 +108,9 @@ int occlum_pal_init(const struct occlum_pal_attr *attr) { int ecall_ret = 0; struct host_file_buffer file_buffer = { - .hostname_ptr = pal_load_file("/etc/hostname"), - .hosts_ptr = pal_load_file("/etc/hosts"), - .resolv_conf_ptr = pal_load_file("/etc/resolv.conf"), + .hostname_buf = pal_load_file_to_string("/etc/hostname"), + .hosts_buf = pal_load_file_to_string("/etc/hosts"), + .resolv_conf_buf = pal_load_file_to_string("/etc/resolv.conf"), }; const struct host_file_buffer *file_buffer_ptr = &file_buffer; @@ -118,12 +118,7 @@ int occlum_pal_init(const struct occlum_pal_attr *attr) { sgx_status_t ecall_status = occlum_ecall_init(eid, &ecall_ret, attr->log_level, resolved_path, file_buffer_ptr); - free((void *)file_buffer.hostname_ptr); - file_buffer.hostname_ptr = NULL; - free((void *)file_buffer.hosts_ptr); - file_buffer.hosts_ptr = NULL; - free((void *)file_buffer.resolv_conf_ptr); - file_buffer.resolv_conf_ptr = NULL; + free_host_file_buffer(file_buffer); if (ecall_status != SGX_SUCCESS) { const char *sgx_err = pal_get_sgx_error_msg(ecall_status); @@ -285,6 +280,17 @@ int occlum_pal_destroy(void) { return ret; } +void free_host_file_buffer(struct host_file_buffer file_buffer) { + free((void *)file_buffer.hostname_buf); + file_buffer.hostname_buf = NULL; + + free((void *)file_buffer.hosts_buf); + file_buffer.hosts_buf = NULL; + + free((void *)file_buffer.resolv_conf_buf); + file_buffer.resolv_conf_buf = NULL; +} + int pal_get_version(void) __attribute__((weak, alias ("occlum_pal_get_version"))); int pal_init(const struct occlum_pal_attr *attr)\ diff --git a/src/pal/src/pal_load_file.c b/src/pal/src/pal_load_file.c index 941e0a22..ce547381 100644 --- a/src/pal/src/pal_load_file.c +++ b/src/pal/src/pal_load_file.c @@ -2,7 +2,7 @@ #include #include "pal_log.h" -char *pal_load_file(const char *filename) { +char *pal_load_file_to_string(const char *filename) { FILE *fp = fopen(filename, "rb"); if (fp == NULL) { @@ -18,7 +18,7 @@ char *pal_load_file(const char *filename) { return NULL; } fread(file_buffer, 1, fsize, fp); - file_buffer[fsize] = 0; + file_buffer[fsize] = '\0'; fclose(fp); return file_buffer; } diff --git a/src/pal/src/pal_load_file.h b/src/pal/src/pal_load_file.h index 467c5083..2d5f7f7b 100644 --- a/src/pal/src/pal_load_file.h +++ b/src/pal/src/pal_load_file.h @@ -1,6 +1,6 @@ #ifndef __PAL_LOAD_FILE_H__ #define __PAL_LOAD_FILE_H__ -char *pal_load_file(const char *filename); +char *pal_load_file_to_string(const char *filename); #endif /* __PAL_LOAD_FILE_H__ */