From d35d98d551bea98174f88fa7b639be79af1caaa9 Mon Sep 17 00:00:00 2001 From: ClawSeven Date: Mon, 19 Jul 2021 17:40:20 +0800 Subject: [PATCH] Add resolv-conf parser --- .gitmodules | 3 + Makefile | 1 + demos/grpc/run_client_on_occlum.sh | 1 - demos/grpc/run_server_on_occlum.sh | 1 - deps/resolv-conf | 1 + deps/resolv-conf.patch | 80 ++++++++++++++++++++++++++ src/Enclave.edl | 2 +- src/libos/Cargo.toml | 1 + src/libos/src/entry.rs | 20 ++++++- src/libos/src/fs/fs_ops/mount.rs | 5 ++ src/libos/src/lib.rs | 1 + src/libos/src/util/mod.rs | 1 + src/libos/src/util/resolv_conf_util.rs | 37 ++++++++++++ src/pal/src/pal_api.c | 6 +- src/pal/src/pal_load_resolv_conf.c | 24 ++++++++ src/pal/src/pal_load_resolv_conf.h | 6 ++ test/Makefile | 2 +- test/resolv_conf/Makefile | 5 ++ test/resolv_conf/main.c | 48 ++++++++++++++++ 19 files changed, 239 insertions(+), 6 deletions(-) create mode 160000 deps/resolv-conf create mode 100644 deps/resolv-conf.patch create mode 100644 src/libos/src/util/resolv_conf_util.rs create mode 100644 src/pal/src/pal_load_resolv_conf.c create mode 100644 src/pal/src/pal_load_resolv_conf.h create mode 100644 test/resolv_conf/Makefile create mode 100644 test/resolv_conf/main.c diff --git a/.gitmodules b/.gitmodules index 04547a9a..4ffe9d8f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "deps/ringbuf"] path = deps/ringbuf url = https://github.com/agerasev/ringbuf.git +[submodule "deps/resolv-conf"] + path = deps/resolv-conf + url = https://github.com/tailhook/resolv-conf.git diff --git a/Makefile b/Makefile index ab5c6cbb..7086c5ca 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,7 @@ submodule: githooks @# Try to apply the patches. If failed, check if the patches are already applied cd deps/serde-json-sgx && git apply ../serde-json-sgx.patch >/dev/null 2>&1 || git apply ../serde-json-sgx.patch -R --check cd deps/ringbuf && git apply ../ringbuf.patch >/dev/null 2>&1 || git apply ../ringbuf.patch -R --check + cd deps/resolv-conf && git apply ../resolv-conf.patch >/dev/null 2>&1 || git apply ../resolv-conf.patch -R --check @# Enclaves used by tools are running in simulation mode by default to run faster. @rm -rf build build_sim diff --git a/demos/grpc/run_client_on_occlum.sh b/demos/grpc/run_client_on_occlum.sh index d8bac2d6..966330d6 100755 --- a/demos/grpc/run_client_on_occlum.sh +++ b/demos/grpc/run_client_on_occlum.sh @@ -24,7 +24,6 @@ then fi mkdir -p image/etc -cp /etc/resolv.conf image/etc cp ../greeter_client image/bin cp $INSTALL_DIR/lib/libprotobuf.so.3.10.0.0 image/lib cp $INSTALL_DIR/lib/libcares.so.2 image/lib diff --git a/demos/grpc/run_server_on_occlum.sh b/demos/grpc/run_server_on_occlum.sh index 2554f486..73db227a 100755 --- a/demos/grpc/run_server_on_occlum.sh +++ b/demos/grpc/run_server_on_occlum.sh @@ -23,7 +23,6 @@ then fi mkdir -p image/etc -cp /etc/resolv.conf image/etc cp ../greeter_server image/bin cp $INSTALL_DIR/lib/libprotobuf.so.3.10.0.0 image/lib cp $INSTALL_DIR/lib/libcares.so.2 image/lib diff --git a/deps/resolv-conf b/deps/resolv-conf new file mode 160000 index 00000000..c0752810 --- /dev/null +++ b/deps/resolv-conf @@ -0,0 +1 @@ +Subproject commit c0752810e748d496c2df161a2a90c3c229b65531 diff --git a/deps/resolv-conf.patch b/deps/resolv-conf.patch new file mode 100644 index 00000000..dcad179c --- /dev/null +++ b/deps/resolv-conf.patch @@ -0,0 +1,80 @@ +From 9faee3943a31e359e76c5dfce23918c35fd8f317 Mon Sep 17 00:00:00 2001 +From: ClawSeven +Date: Fri, 9 Jul 2021 13:28:42 +0800 +Subject: [PATCH] Transplant resolv-conf into sgx-world + +--- + Cargo.toml | 3 ++- + src/config.rs | 2 ++ + src/grammar.rs | 1 + + src/ip.rs | 1 + + src/lib.rs | 3 +++ + 5 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 0022252..617e319 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -14,7 +14,8 @@ version = "0.7.0" + authors = ["paul@colomiets.name"] + + [dependencies] +-quick-error = "1.0.0" ++quick-error = { git = "https://github.com/mesalock-linux/quick-error-sgx.git" } ++sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git" } + hostname = { version = "^0.3", optional = true } + + [features] +diff --git a/src/config.rs b/src/config.rs +index b6b6460..8389064 100644 +--- a/src/config.rs ++++ b/src/config.rs +@@ -3,6 +3,8 @@ use std::iter::{IntoIterator, Iterator}; + use std::slice::Iter; + use {grammar, Network, ParseError, ScopedIp}; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; ++use std::vec::Vec; ++use std::string::String; + + const NAMESERVER_LIMIT:usize = 3; + const SEARCH_LIMIT:usize = 6; +diff --git a/src/grammar.rs b/src/grammar.rs +index 9a274a8..be85081 100644 +--- a/src/grammar.rs ++++ b/src/grammar.rs +@@ -1,5 +1,6 @@ + use std::net::{Ipv4Addr, Ipv6Addr}; + use std::str::{Utf8Error, from_utf8}; ++use std::string::ToString; + + use {AddrParseError, Config, Network, Lookup, Family}; + +diff --git a/src/ip.rs b/src/ip.rs +index c9cfa59..4b4bca2 100644 +--- a/src/ip.rs ++++ b/src/ip.rs +@@ -2,6 +2,7 @@ use std::error::Error; + use std::fmt; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + use std::str::FromStr; ++use std::string::{String, ToString}; + + /// A network, that is an IP address and a mask + #[derive(Clone, Debug, PartialEq, Eq)] +diff --git a/src/lib.rs b/src/lib.rs +index a55a9d7..094a35a 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -91,6 +91,9 @@ + #![warn(missing_debug_implementations)] + #![warn(missing_docs)] + ++#![no_std] ++#[macro_use] ++extern crate sgx_tstd as std; + #[macro_use] + extern crate quick_error; + #[cfg(feature = "system")] +-- +2.17.1 + diff --git a/src/Enclave.edl b/src/Enclave.edl index 4178074f..3b0a9e0f 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -42,7 +42,7 @@ enclave { * EEXIST - The LibOS has already been initialized. * EINVAL - The value of an argument are invalid. */ - public int occlum_ecall_init([in, string] const char* log_level, [in, string] const char* instance_dir); + public int occlum_ecall_init([in, string] const char* log_level, [in, string] const char* instance_dir, [in, string] const char* resolv_conf_ptr); /* * Create a new LibOS process to do the task specified by the given diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index c208826b..a2dfb302 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -22,6 +22,7 @@ rcore-fs-ramfs = { path = "../../deps/sefs/rcore-fs-ramfs" } rcore-fs-mountfs = { path = "../../deps/sefs/rcore-fs-mountfs" } rcore-fs-unionfs = { path = "../../deps/sefs/rcore-fs-unionfs" } rcore-fs-devfs = { path = "../../deps/sefs/rcore-fs-devfs" } +resolv-conf = { path = "../../deps/resolv-conf" } serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] } serde_json = { path = "../../deps/serde-json-sgx" } memoffset = "0.6.1" diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index 789186de..0b895c7f 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -12,6 +12,7 @@ use crate::signal::SigNum; use crate::time::up_time::init; use crate::util::log::LevelFilter; use crate::util::mem_util::from_untrusted::*; +use crate::util::resolv_conf_util::{parse_resolv_conf, write_resolv_conf}; use crate::util::sgx::allow_debug as sgx_allow_debug; use sgx_tse::*; @@ -23,6 +24,7 @@ lazy_static! { static ref HAS_INIT: AtomicBool = AtomicBool::new(false); pub static ref ENTRY_POINTS: RwLock> = RwLock::new(config::LIBOS_CONFIG.entry_points.clone()); + pub static ref RESOLV_CONF_STR: RwLock> = RwLock::new(None); } macro_rules! ecall_errno { @@ -33,7 +35,11 @@ macro_rules! ecall_errno { } #[no_mangle] -pub extern "C" fn occlum_ecall_init(log_level: *const c_char, instance_dir: *const c_char) -> i32 { +pub extern "C" fn occlum_ecall_init( + log_level: *const c_char, + instance_dir: *const c_char, + resolv_conf_ptr: *const c_char, +) -> i32 { if HAS_INIT.load(Ordering::SeqCst) == true { return ecall_errno!(EEXIST); } @@ -87,6 +93,18 @@ pub extern "C" fn occlum_ecall_init(log_level: *const c_char, instance_dir: *con unsafe { backtrace::enable_backtrace(&ENCLAVE_PATH, PrintFormat::Short) }; }); + match parse_resolv_conf(resolv_conf_ptr) { + Err(e) => { + error!("failed to parse /etc/resolv.conf: {}", e.backtrace()); + } + Ok(resolv_conf_str) => { + *RESOLV_CONF_STR.write().unwrap() = Some(resolv_conf_str); + if let Err(e) = write_resolv_conf() { + error!("failed to write /etc/resolv.conf: {}", e.backtrace()); + } + } + } + 0 } diff --git a/src/libos/src/fs/fs_ops/mount.rs b/src/libos/src/fs/fs_ops/mount.rs index 8251b19a..841cb20f 100644 --- a/src/libos/src/fs/fs_ops/mount.rs +++ b/src/libos/src/fs/fs_ops/mount.rs @@ -1,4 +1,5 @@ use std::sync::Once; +use util::resolv_conf_util::write_resolv_conf; use super::rootfs::{mount_nonroot_fs_according_to, open_root_fs_according_to}; use super::*; @@ -27,5 +28,9 @@ pub fn do_mount_rootfs( *root_inode = new_root_inode; *ENTRY_POINTS.write().unwrap() = user_config.entry_points.to_owned(); }); + // Write resolv.conf file into mounted file system + write_resolv_conf()?; + *RESOLV_CONF_STR.write().unwrap() = None; + Ok(()) } diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index bc8531be..15a65d50 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -53,6 +53,7 @@ extern crate serde; extern crate serde_json; #[macro_use] extern crate memoffset; +extern crate resolv_conf; use sgx_trts::libc; use sgx_types::*; diff --git a/src/libos/src/util/mod.rs b/src/libos/src/util/mod.rs index 0ace301e..9a58644c 100644 --- a/src/libos/src/util/mod.rs +++ b/src/libos/src/util/mod.rs @@ -5,5 +5,6 @@ pub mod log; pub mod mem_util; pub mod mpx_util; pub mod random; +pub mod resolv_conf_util; pub mod sgx; pub mod sync; diff --git a/src/libos/src/util/resolv_conf_util.rs b/src/libos/src/util/resolv_conf_util.rs new file mode 100644 index 00000000..4e6f27fd --- /dev/null +++ b/src/libos/src/util/resolv_conf_util.rs @@ -0,0 +1,37 @@ +use super::*; +use crate::fs::{AccessMode, CreationFlags, FsView}; +use resolv_conf::*; +use std::ffi::CStr; +use std::str; + +pub fn write_resolv_conf() -> Result<()> { + const RESOLV_CONF_PATH: &'static str = "/etc/resolv.conf"; + let fs_view = FsView::new(); + // overwrite /etc/resolv.conf if existed + let resolv_conf_file = fs_view.open_file( + RESOLV_CONF_PATH, + AccessMode::O_RDWR as u32 | CreationFlags::O_CREAT.bits() | CreationFlags::O_TRUNC.bits(), + 0o666, + )?; + let resolv_conf_str = RESOLV_CONF_STR.read().unwrap(); + match &*resolv_conf_str { + Some(str) => { + resolv_conf_file.write(str.as_bytes()); + } + None => {} + } + Ok(()) +} + +pub fn parse_resolv_conf(resolv_conf_ptr: *const c_char) -> Result { + // Read resolv.conf file from host + let resolv_conf_bytes = unsafe { CStr::from_ptr(resolv_conf_ptr).to_bytes() }; + let resolv_conf_str = str::from_utf8(resolv_conf_bytes) + .map_err(|_| errno!(EINVAL, "/etc/resolv.conf contains non UTF-8 characters"))?; + + // Parse and inspect resolv.conf file + if let Err(_) = resolv_conf::Config::parse(resolv_conf_bytes) { + return_errno!(EINVAL, "malformated host /etc/resolv.conf"); + } + Ok(resolv_conf_str.to_string()) +} diff --git a/src/pal/src/pal_api.c b/src/pal/src/pal_api.c index 7eedfce8..3ce43548 100644 --- a/src/pal/src/pal_api.c +++ b/src/pal/src/pal_api.c @@ -2,6 +2,7 @@ #include "Enclave_u.h" #include "pal_enclave.h" #include "pal_error.h" +#include "pal_load_resolv_conf.h" #include "pal_interrupt_thread.h" #include "pal_log.h" #include "pal_sig_handler.h" @@ -103,8 +104,11 @@ int occlum_pal_init(const struct occlum_pal_attr *attr) { eid = pal_get_enclave_id(); int ecall_ret = 0; + const char *resolv_conf_ptr = pal_load_resolv_conf(); sgx_status_t ecall_status = occlum_ecall_init(eid, &ecall_ret, attr->log_level, - resolved_path); + resolved_path, resolv_conf_ptr); + free((void *)resolv_conf_ptr); + resolv_conf_ptr = NULL; if (ecall_status != SGX_SUCCESS) { const char *sgx_err = pal_get_sgx_error_msg(ecall_status); PAL_ERROR("Failed to do ECall with error code 0x%x: %s", ecall_status, sgx_err); diff --git a/src/pal/src/pal_load_resolv_conf.c b/src/pal/src/pal_load_resolv_conf.c new file mode 100644 index 00000000..2b9f1019 --- /dev/null +++ b/src/pal/src/pal_load_resolv_conf.c @@ -0,0 +1,24 @@ +#include +#include +#include "pal_log.h" + +char *pal_load_resolv_conf(void) { + FILE *fp = fopen("/etc/resolv.conf", "rb"); + + if (fp == NULL) { + PAL_WARN("Warning: Failed to open /etc/resolv.conf file"); + return NULL; + } + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); + char *resolv_conf_buffer = malloc(fsize + 1); + if (resolv_conf_buffer == NULL) { + PAL_WARN("Warning: Failed to malloc for /etc/resolv.conf buffer"); + return NULL; + } + fread(resolv_conf_buffer, 1, fsize, fp); + resolv_conf_buffer[fsize] = 0; + fclose(fp); + return resolv_conf_buffer; +} diff --git a/src/pal/src/pal_load_resolv_conf.h b/src/pal/src/pal_load_resolv_conf.h new file mode 100644 index 00000000..9501223b --- /dev/null +++ b/src/pal/src/pal_load_resolv_conf.h @@ -0,0 +1,6 @@ +#ifndef __PAL_LOAD_RESOLV_CONF_H__ +#define __PAL_LOAD_RESOLV_CONF_H__ + +char *pal_load_resolv_conf(void); + +#endif /* __PAL_LOAD_RESOLV_CONF_H__ */ diff --git a/test/Makefile b/test/Makefile index 2974fe21..b083b282 100644 --- a/test/Makefile +++ b/test/Makefile @@ -16,7 +16,7 @@ FAIL_LOG = $(BUILD_DIR)/test/.fail TEST_DEPS := client data_sink naughty_child # Tests: need to be compiled and run by test-% target TESTS ?= env empty hello_world malloc mmap file fs_perms getpid spawn sched pipe time timerfd \ - truncate readdir mkdir open stat link symlink chmod chown tls pthread system_info rlimit \ + truncate readdir mkdir open stat link symlink chmod chown tls pthread system_info resolv_conf rlimit \ server server_epoll unix_socket cout hostfs cpuid rdtsc device sleep exit_group \ ioctl fcntl eventfd emulate_syscall access signal sysinfo prctl rename procfs wait \ spawn_attribute exec statfs diff --git a/test/resolv_conf/Makefile b/test/resolv_conf/Makefile new file mode 100644 index 00000000..9e1b6dec --- /dev/null +++ b/test/resolv_conf/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/resolv_conf/main.c b/test/resolv_conf/main.c new file mode 100644 index 00000000..d0fee16b --- /dev/null +++ b/test/resolv_conf/main.c @@ -0,0 +1,48 @@ +#include +#include +#include "test.h" + +// ============================================================================ +// Helper functions +// ============================================================================ +char *read_resolv_conf(void) { + FILE *fp = fopen("/etc/resolv.conf", "rb"); + fseek(fp, 0, SEEK_END); + long fsize = ftell(fp); + fseek(fp, 0, SEEK_SET); + char *resolv_conf_buffer = malloc(fsize + 1); + if (resolv_conf_buffer == NULL) { + printf("ERROR: Failed to malloc for /etc/resolv.conf buffer"); + return NULL; + } + fread(resolv_conf_buffer, 1, fsize, fp); + fclose(fp); + return resolv_conf_buffer; +} + +// ============================================================================ +// Test cases for resolv.conf file +// ============================================================================ + +int test_resolv_conf() { + char *buffer = read_resolv_conf(); + if (buffer == NULL) { + THROW_ERROR("failed to read resolv.conf"); + } + printf("%s", buffer); + free(buffer); + buffer = NULL; + return 0; +} + +static test_case_t test_cases[] = { + TEST_CASE(test_resolv_conf), +}; + +// ============================================================================ +// Test suite main +// ============================================================================ + +int main() { + return test_suite_run(test_cases, ARRAY_SIZE(test_cases)); +} \ No newline at end of file