Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First iteration of etc passthrough #850

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Documentation/manifest-syntax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,20 @@ arguments to be provided at runtime from an external (trusted) source.
If none of the above arguments-handling manifest options is specified in the
manifest, the application will get ``argv = [ <libos.entrypoint value> ]``.

etc passthrough
^^^^^^^^^^^^^^^

::

libos.passthrough_etc_files = [true|false]
(Default: false)

This specifies whether to passthrough extra runtime files from ``/etc``.
Before the files are available to the application, they will be sanitized.
The set of extra runtime files is limited to:

- ``/etc/hostname``

Environment variables
^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions libos/include/libos_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ extern struct libos_dentry* g_dentry_root;
int init_fs(void);
int init_mount_root(void);
int init_mount(void);
int init_mount_etc(void);

/* file system operations */

Expand Down
3 changes: 3 additions & 0 deletions libos/include/libos_fs_pseudo.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,6 @@ int sys_print_as_ranges(char* buf, size_t buf_size, size_t count,
int sys_print_as_bitmask(char* buf, size_t buf_size, size_t count,
bool (*is_present)(size_t ind, const void* arg),
const void* callback_arg);

/* etcfs */
int init_etc(void);
2 changes: 2 additions & 0 deletions libos/include/libos_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ bool handle_signal(PAL_CONTEXT* context);
*/
long pal_to_unix_errno(long err);

long libos_set_hostname(char* name, size_t len);

void warn_unsupported_syscall(unsigned long sysno);
void debug_print_syscall_before(unsigned long sysno, ...);
void debug_print_syscall_after(unsigned long sysno, ...);
Expand Down
78 changes: 78 additions & 0 deletions libos/src/fs/etc/fs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2022 Intel Corporation
* Mariusz Zaborski <[email protected]>
*/

/*
* This file contains the implementation of `etc` passthrough.
*/

#include "libos_checkpoint.h"
#include "libos_fs.h"
#include "libos_fs_pseudo.h"

static int provide_etc_hostname(struct libos_dentry* dent, char** out_data, size_t* out_size) {
__UNUSED(dent);
/* Use the string (without null terminator) as file data */
size_t size = strlen(g_pal_public_state->hostname);
char* data = malloc(size);
if (!data)
return -ENOMEM;
memcpy(data, g_pal_public_state->hostname, size);
*out_data = data;
*out_size = size;
return 0;
}

int init_etc(void) {
pseudo_add_str(NULL, "hostname", &provide_etc_hostname);
return 0;
}

int init_mount_etc(void) {
int ret;

if (!g_pal_public_state->passthrough_etc_files)
return 0;

ret = mount_fs(&(struct libos_mount_params){
.type = "pseudo",
.path = "/etc/hostname",
.uri = "hostname",
});
if (ret < 0)
return ret;

return 0;
}

BEGIN_CP_FUNC(etc_info) {
__UNUSED(size);
__UNUSED(obj);
__UNUSED(objp);

/* Propagate hostname */
size_t off = ADD_CP_OFFSET(sizeof(g_pal_public_state->hostname) +
sizeof(g_pal_public_state->passthrough_etc_files));
char* new_hostname = (char*)(base + off);
memcpy(new_hostname, g_pal_public_state->hostname, sizeof(g_pal_public_state->hostname));

/* Propagate passthrough_etc_files */
bool* new_passthrough_etc_files = (bool*)(new_hostname +
sizeof(g_pal_public_state->hostname));
*new_passthrough_etc_files = g_pal_public_state->passthrough_etc_files;
ADD_CP_FUNC_ENTRY(off);
}
END_CP_FUNC(etc_info)

BEGIN_RS_FUNC(etc_info) {
__UNUSED(offset);
__UNUSED(rebase);

const char* hostname = (const char*)(base + GET_CP_FUNC_ENTRY());
memcpy(&g_pal_public_state->hostname, hostname, sizeof(g_pal_public_state->hostname));

g_pal_public_state->passthrough_etc_files = *(bool*)(hostname +
sizeof(g_pal_public_state->hostname));
}
END_RS_FUNC(etc_info)
3 changes: 3 additions & 0 deletions libos/src/fs/libos_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ int init_fs(void) {
if ((ret = init_sysfs()) < 0)
goto err;

if ((ret = init_etc()) < 0)
goto err;

return 0;

err:
Expand Down
4 changes: 4 additions & 0 deletions libos/src/libos_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ noreturn void libos_init(const char* const* argv, const char* const* envp) {
RUN_INIT(init_threading);
RUN_INIT(init_mount);
RUN_INIT(init_std_handles);
RUN_INIT(init_mount_etc);

char** expanded_argv = NULL;
RUN_INIT(init_exec_handle, argv, &expanded_argv);
Expand Down Expand Up @@ -487,6 +488,9 @@ noreturn void libos_init(const char* const* argv, const char* const* envp) {
* communicates with server over a "loopback" IPC connection. */
RUN_INIT(init_sync_client);

RUN_INIT(libos_set_hostname, g_pal_public_state->hostname,
strlen(g_pal_public_state->hostname) + 1);

log_debug("LibOS initialized");

libos_tcb_t* cur_tcb = libos_get_tcb();
Expand Down
1 change: 1 addition & 0 deletions libos/src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ libos_sources = files(
'fs/chroot/fs.c',
'fs/dev/attestation.c',
'fs/dev/fs.c',
'fs/etc/fs.c',
'fs/eventfd/fs.c',
'fs/libos_dcache.c',
'fs/libos_fs.c',
Expand Down
1 change: 1 addition & 0 deletions libos/src/sys/libos_clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ static BEGIN_MIGRATION_DEF(fork, struct libos_process* process_description,
DEFINE_MIGRATE(brk, NULL, 0);
DEFINE_MIGRATE(loaded_elf_objects, NULL, 0);
DEFINE_MIGRATE(topo_info, NULL, 0);
DEFINE_MIGRATE(etc_info, NULL, 0);
#ifdef DEBUG
DEFINE_MIGRATE(gdb_map, NULL, 0);
#endif
Expand Down
14 changes: 11 additions & 3 deletions libos/src/sys/libos_uname.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,24 @@ long libos_syscall_uname(struct new_utsname* buf) {
return 0;
}

long libos_set_hostname(char* name, size_t len) {
if (len >= sizeof(g_current_uname.nodename))
return -EINVAL;

memcpy(&g_current_uname.nodename, name, len);
memset(&g_current_uname.nodename[len], 0, sizeof(g_current_uname.nodename) - len);

return 0;
}

long libos_syscall_sethostname(char* name, int len) {
if (len < 0 || (size_t)len >= sizeof(g_current_uname.nodename))
return -EINVAL;

if (!is_user_memory_readable(name, len))
return -EFAULT;

memcpy(&g_current_uname.nodename, name, len);
memset(&g_current_uname.nodename[len], 0, sizeof(g_current_uname.nodename) - len);
return 0;
return libos_set_hostname(name, len);
}

long libos_syscall_setdomainname(char* name, int len) {
Expand Down
108 changes: 108 additions & 0 deletions libos/test/regression/hostname.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#define _DEFAULT_SOURCE BSD /* This is required for gethostname */

#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void test_fork(const char* tag, const char* name, void (*f)(const char*, const char*)) {
int status;

pid_t pid = fork();
if (pid == -1) {
printf("Unable to fork %s\n", tag);
exit(1);
}

if (pid == 0) {
f(tag, name);
exit(0);
}

if (wait(&status) == -1) {
printf("Wait failed %s\n", tag);
exit(1);
}

if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
printf("Test failed %s\n", tag);
exit(1);
}
}

static void test_gethostname(const char* tag, const char* name) {
char buf[512] = {0};

if (gethostname(buf, sizeof(buf)) != 0) {
printf("%sgethostname: failed %d\n", tag, errno);
exit(1);
}

if (strcmp(buf, name) != 0) {
printf("%sgethostname dosen't match hostname (expected: %s, got: %s)\n",
tag, name, buf);
exit(1);
}
}

static void test_etc_hostname(const char* tag, const char* name) {
char buf[512] = {0};
int fd;

fd = open("/etc/hostname", O_RDONLY);

/*
* If the etc hostname was not provided, assume that etc shouldn't exists.
*/
if (strcmp(name, "") == 0) {
if (fd != -1 || errno != ENOENT) {
printf("The etc file shouldn't exists, but exists\n");
exit(1);
}
return;
}

if (fd == -1) {
printf("Unable to open /etc/hostname in %s\n", tag);
exit(1);
}

int ret = read(fd, buf, sizeof(buf));
if (ret <= 0) {
printf("Unable to read /etc/hostname in %s\n", tag);
exit(1);
}

/*
* Sometimes etc hostname might have a trailing '\n', gramine is romving it,
* do the same in the test.
*/
size_t len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n') {
buf[len - 1] = '\0';
}

if (strcmp(buf, name) != 0) {
printf("%s etc don't have a expected value (expected: %s, got: %s)\n",
tag, name, buf);
exit(1);
}
}

int main(int argc, char** argv) {
if (argc != 3) {
printf("Usage: %s [hostname] [etc_hostname]\n", argv[0]);
return 1;
}

test_gethostname("", argv[1]);
test_etc_hostname("", argv[2]);
test_fork("fork gethostname", argv[1], test_gethostname);
test_fork("fork etc gethostname", argv[2], test_etc_hostname);

printf("hostname test passed\n");
return 0;
}
22 changes: 22 additions & 0 deletions libos/test/regression/hostname_pass_etc.manifest.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
loader.entrypoint = "file:{{ gramine.libos }}"
libos.entrypoint = "hostname"

loader.env.LD_LIBRARY_PATH = "/lib"
loader.insecure__use_cmdline_argv = true

fs.mounts = [
{ path = "/lib", uri = "file:{{ gramine.runtimedir(libc) }}" },
{ path = "/hostname", uri = "file:{{ binary_dir }}/hostname" },
]

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

sgx.trusted_files = [
"file:{{ gramine.libos }}",
"file:{{ gramine.runtimedir(libc) }}/",
"file:{{ binary_dir }}/hostname",
]

libos.passthrough_etc_files = true
1 change: 1 addition & 0 deletions libos/test/regression/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ tests = {
'groups': {},
'helloworld': {},
'host_root_fs': {},
'hostname': {},
'init_fail': {},
'keys': {},
'kill_all': {},
Expand Down
10 changes: 10 additions & 0 deletions libos/test/regression/test_libos.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import subprocess
import unittest

from socket import gethostname

from graminelibos.regression import (
HAS_SGX,
ON_X86,
Expand Down Expand Up @@ -1119,6 +1121,14 @@ def test_060_synthetic(self):
stdout, _ = self.run_binary(['synthetic'])
self.assertIn("TEST OK", stdout)

def test_070_hostname_localhost(self):
stdout, _ = self.run_binary(['hostname', 'localhost', ''])
self.assertIn("hostname test passed", stdout)

def test_071_hostname_pass_etc(self):
stdout, _ = self.run_binary(['hostname_pass_etc', gethostname(), gethostname()])
self.assertIn("hostname test passed", stdout)


class TC_50_GDB(RegressionTestCase):
def setUp(self):
Expand Down
2 changes: 2 additions & 0 deletions libos/test/regression/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ manifests = [
"gettimeofday",
"groups",
"helloworld",
"hostname",
"hostname_pass_etc",
"host_root_fs",
"init_fail",
"keys",
Expand Down
2 changes: 2 additions & 0 deletions libos/test/regression/tests_musl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ manifests = [
"gettimeofday",
"groups",
"helloworld",
"hostname",
"hostname_pass_etc",
"host_root_fs",
"init_fail",
"keys",
Expand Down
11 changes: 11 additions & 0 deletions pal/include/host/linux-common/host_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2022 Intel Corporation
* Mariusz Zaborski <[email protected]>
*/

#pragma once

#include "pal.h"

/* Function to fetch the hostname */
int get_hostname(char* hostname, size_t size);
Loading