1
0
mirror of https://github.com/systemd/systemd.git synced 2024-10-30 23:21:22 +03:00

nspawn: add support for executing OCI runtime bundles with nspawn

This is a pretty large patch, and adds support for OCI runtime bundles
to nspawn. A new switch --oci-bundle= is added that takes a path to an
OCI bundle. The JSON file included therein is read similar to a .nspawn
settings files, however with a different feature set.

Implementation-wise this mostly extends the pre-existing Settings object
to carry additional properties for OCI. However, OCI supports some
concepts .nspawn files did not support yet, which this patch also adds:

1. Support for "masking" files and directories. This functionatly is now
   also available via the new --inaccesible= cmdline command, and
   Inaccessible= in .nspawn files.

2. Support for mounting arbitrary file systems. (not exposed through
   nspawn cmdline nor .nspawn files, because probably not a good idea)

3. Ability to configure the console settings for a container. This
   functionality is now also available on the nspawn cmdline in the new
   --console= switch (not added to .nspawn for now, as it is something
   specific to the invocation really, not a property of the container)

4. Console width/height configuration. Not exposed through
   .nspawn/cmdline, but this may be controlled through $COLUMNS and
   $LINES like in most other UNIX tools.

5. UID/GID configuration by raw numbers. (not exposed in .nspawn and on
   the cmdline, since containers likely have different user tables, and
   the existing --user= switch appears to be the better option)

6. OCI hook commands (no exposed in .nspawn/cmdline, as very specific to
   OCI)

7. Creation of additional devices nodes in /dev. Most likely not a good
   idea, hence not exposed in .nspawn/cmdline. There's already --bind=
   to achieve the same, which is the better alternative.

8. Explicit syscall filters. This is not a good idea, due to the skewed
   arch support, hence not exposed through .nspawn/cmdline.

9. Configuration of some sysctls on a whitelist. Questionnable, not
   supported in .nspawn/cmdline for now.

10. Configuration of all 5 types of capabilities. Not a useful concept,
    since the kernel will reduce the caps on execve() anyway. Not
    exposed through .nspawn/cmdline as this is not very useful hence.

Note that this only implements the OCI runtime logic itself. It does not
provide a runc-compatible command line tool. This is left for a later
PR. Only with that in place tools such as "buildah" can use the OCI
support in nspawn as drop-in replacement.

Currently still missing is OCI hook support, but it's already parsed and
everything, and should be easy to add. Other than that it's OCI is
implemented pretty comprehensively.

There's a list of incompatibilities in the nspawn-oci.c file. In a later
PR I'd like to convert this into proper markdown and add it to the
documentation directory.
This commit is contained in:
Lennart Poettering 2018-04-25 11:23:37 +02:00
parent 5ef4cb7ad0
commit de40a3037a
11 changed files with 3235 additions and 173 deletions

View File

@ -10,6 +10,8 @@ libnspawn_core_sources = files('''
nspawn-mount.h
nspawn-network.c
nspawn-network.h
nspawn-oci.c
nspawn-oci.h
nspawn-patch-uid.c
nspawn-patch-uid.h
nspawn-register.c

View File

@ -62,6 +62,7 @@ Files.Volatile, config_parse_volatile_mode, 0, of
Files.Bind, config_parse_bind, 0, 0
Files.BindReadOnly, config_parse_bind, 1, 0
Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0
Files.Inaccessible, config_parse_inaccessible, 0, 0
Files.Overlay, config_parse_overlay, 0, 0
Files.OverlayReadOnly, config_parse_overlay, 1, 0
Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown)

View File

@ -65,6 +65,7 @@ void custom_mount_free_all(CustomMount *l, size_t n) {
}
strv_free(m->lower);
free(m->type_argument);
}
free(l);
@ -116,32 +117,40 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) {
for (i = 0; i < n; i++) {
CustomMount *m = l + i;
if (m->source) {
char *s;
/* /proc we mount in the inner child, i.e. when we acquired CLONE_NEWPID. All other mounts we mount
* already in the outer child, so that the mounts are already established before CLONE_NEWPID and in
* particular CLONE_NEWUSER. This also means any custom mounts below /proc also need to be mounted in
* the inner child, not the outer one. Determine this here. */
m->in_userns = path_startswith(m->destination, "/proc");
s = resolve_source_path(dest, m->source);
if (!s)
return log_oom();
if (m->type == CUSTOM_MOUNT_BIND) {
if (m->source) {
char *s;
free_and_replace(m->source, s);
} else {
/* No source specified? In that case, use a throw-away temporary directory in /var/tmp */
s = resolve_source_path(dest, m->source);
if (!s)
return log_oom();
m->rm_rf_tmpdir = strdup("/var/tmp/nspawn-temp-XXXXXX");
if (!m->rm_rf_tmpdir)
return log_oom();
free_and_replace(m->source, s);
} else {
/* No source specified? In that case, use a throw-away temporary directory in /var/tmp */
if (!mkdtemp(m->rm_rf_tmpdir)) {
m->rm_rf_tmpdir = mfree(m->rm_rf_tmpdir);
return log_error_errno(errno, "Failed to acquire temporary directory: %m");
m->rm_rf_tmpdir = strdup("/var/tmp/nspawn-temp-XXXXXX");
if (!m->rm_rf_tmpdir)
return log_oom();
if (!mkdtemp(m->rm_rf_tmpdir)) {
m->rm_rf_tmpdir = mfree(m->rm_rf_tmpdir);
return log_error_errno(errno, "Failed to acquire temporary directory: %m");
}
m->source = strjoin(m->rm_rf_tmpdir, "/src");
if (!m->source)
return log_oom();
if (mkdir(m->source, 0755) < 0)
return log_error_errno(errno, "Failed to create %s: %m", m->source);
}
m->source = strjoin(m->rm_rf_tmpdir, "/src");
if (!m->source)
return log_oom();
if (mkdir(m->source, 0755) < 0)
return log_error_errno(errno, "Failed to create %s: %m", m->source);
}
if (m->type == CUSTOM_MOUNT_OVERLAY) {
@ -223,6 +232,7 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only)
m->destination = TAKE_PTR(destination);
m->read_only = read_only;
m->options = TAKE_PTR(opts);
return 0;
}
@ -327,6 +337,29 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
return 0;
}
int inaccessible_mount_parse(CustomMount **l, size_t *n, const char *s) {
_cleanup_free_ char *path = NULL;
CustomMount *m;
assert(l);
assert(n);
assert(s);
if (!path_is_absolute(s))
return -EINVAL;
path = strdup(s);
if (!path)
return -ENOMEM;
m = custom_mount_add(l, n, CUSTOM_MOUNT_INACCESSIBLE);
if (!m)
return -ENOMEM;
m->destination = TAKE_PTR(path);
return 0;
}
int tmpfs_patch_options(
const char *options,
uid_t uid_shift,
@ -494,9 +527,9 @@ int mount_all(const char *dest,
uid_t uid_shift,
const char *selinux_apifs_context) {
#define PROC_INACCESSIBLE(path) \
{ NULL, (path), NULL, NULL, MS_BIND, \
MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO|MOUNT_INACCESSIBLE_REG }, /* Bind mount first ... */ \
#define PROC_INACCESSIBLE_REG(path) \
{ "/run/systemd/inaccessible/reg", (path), NULL, NULL, MS_BIND, \
MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */ \
{ NULL, (path), NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, \
MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO } /* Then, make it r/o */
@ -531,11 +564,11 @@ int mount_all(const char *dest,
/* Make these files inaccessible to container payloads: they potentially leak information about kernel
* internals or the host's execution environment to the container */
PROC_INACCESSIBLE("/proc/kallsyms"),
PROC_INACCESSIBLE("/proc/kcore"),
PROC_INACCESSIBLE("/proc/keys"),
PROC_INACCESSIBLE("/proc/sysrq-trigger"),
PROC_INACCESSIBLE("/proc/timer_list"),
PROC_INACCESSIBLE_REG("/proc/kallsyms"),
PROC_INACCESSIBLE_REG("/proc/kcore"),
PROC_INACCESSIBLE_REG("/proc/keys"),
PROC_INACCESSIBLE_REG("/proc/sysrq-trigger"),
PROC_INACCESSIBLE_REG("/proc/timer_list"),
/* Make these directories read-only to container payloads: they show hardware information, and in some
* cases contain tunables the container really shouldn't have access to. */
@ -573,7 +606,6 @@ int mount_all(const char *dest,
#endif
};
_cleanup_(unlink_and_freep) char *inaccessible = NULL;
bool use_userns = (mount_settings & MOUNT_USE_USERNS);
bool netns = (mount_settings & MOUNT_APPLY_APIVFS_NETNS);
bool ro = (mount_settings & MOUNT_APPLY_APIVFS_RO);
@ -584,7 +616,7 @@ int mount_all(const char *dest,
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
_cleanup_free_ char *where = NULL, *options = NULL;
const char *o, *what;
const char *o;
bool fatal = (mount_table[k].mount_settings & MOUNT_FATAL);
if (in_userns != (bool)(mount_table[k].mount_settings & MOUNT_IN_USERNS))
@ -603,33 +635,14 @@ int mount_all(const char *dest,
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
if (mount_table[k].mount_settings & MOUNT_INACCESSIBLE_REG) {
if (!inaccessible) {
_cleanup_free_ char *np = NULL;
r = tempfn_random_child(NULL, "inaccessible", &np);
if (r < 0)
return log_error_errno(r, "Failed to generate inaccessible file node path: %m");
r = touch_file(np, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0000);
if (r < 0)
return log_error_errno(r, "Failed to create inaccessible file node '%s': %m", np);
inaccessible = TAKE_PTR(np);
}
what = inaccessible;
} else
what = mount_table[k].what;
r = path_is_mount_point(where, NULL, 0);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
/* Skip this entry if it is not a remount. */
if (what && r > 0)
continue;
if (mount_table[k].what) {
r = path_is_mount_point(where, NULL, 0);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
if (r > 0)
continue;
}
r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
if (r < 0 && r != -EEXIST) {
@ -654,7 +667,7 @@ int mount_all(const char *dest,
}
r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
what,
mount_table[k].what,
where,
mount_table[k].type,
mount_table[k].flags,
@ -667,7 +680,6 @@ int mount_all(const char *dest,
}
static int mount_bind(const char *dest, CustomMount *m) {
_cleanup_free_ char *where = NULL;
struct stat source_st, dest_st;
int r;
@ -711,7 +723,6 @@ static int mount_bind(const char *dest, CustomMount *m) {
r = touch(where);
if (r < 0)
return log_error_errno(r, "Failed to create mount point %s: %m", where);
}
r = mount_verbose(LOG_ERR, m->source, where, NULL, MS_BIND | MS_REC, m->options);
@ -773,7 +784,6 @@ static char *joined_and_escaped_lower_dirs(char **lower) {
}
static int mount_overlay(const char *dest, CustomMount *m) {
_cleanup_free_ char *lower = NULL, *where = NULL, *escaped_source = NULL;
const char *options;
int r;
@ -815,11 +825,59 @@ static int mount_overlay(const char *dest, CustomMount *m) {
return mount_verbose(LOG_ERR, "overlay", where, "overlay", m->read_only ? MS_RDONLY : 0, options);
}
static int mount_inaccessible(const char *dest, CustomMount *m) {
_cleanup_free_ char *where = NULL;
const char *source;
struct stat st;
int r;
assert(dest);
assert(m);
r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st);
if (r < 0) {
log_full_errno(m->graceful ? LOG_DEBUG : LOG_ERR, r, "Failed to resolve %s/%s: %m", dest, m->destination);
return m->graceful ? 0 : r;
}
assert_se(source = mode_to_inaccessible_node(st.st_mode));
r = mount_verbose(m->graceful ? LOG_DEBUG : LOG_ERR, source, where, NULL, MS_BIND, NULL);
if (r < 0)
return m->graceful ? 0 : r;
r = mount_verbose(m->graceful ? LOG_DEBUG : LOG_ERR, NULL, where, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
if (r < 0)
return m->graceful ? 0 : r;
return 0;
}
static int mount_arbitrary(const char *dest, CustomMount *m) {
_cleanup_free_ char *where = NULL;
int r;
assert(dest);
assert(m);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
r = mkdir_p_label(where, 0755);
if (r < 0)
return log_error_errno(r, "Creating mount point for mount %s failed: %m", where);
}
return mount_verbose(LOG_ERR, m->source, where, m->type_argument, 0, m->options);
}
int mount_custom(
const char *dest,
CustomMount *mounts, size_t n,
bool userns, uid_t uid_shift, uid_t uid_range,
const char *selinux_apifs_context) {
const char *selinux_apifs_context,
bool in_userns) {
size_t i;
int r;
@ -829,6 +887,9 @@ int mount_custom(
for (i = 0; i < n; i++) {
CustomMount *m = mounts + i;
if (m->in_userns != in_userns)
continue;
switch (m->type) {
case CUSTOM_MOUNT_BIND:
@ -843,6 +904,14 @@ int mount_custom(
r = mount_overlay(dest, m);
break;
case CUSTOM_MOUNT_INACCESSIBLE:
r = mount_inaccessible(dest, m);
break;
case CUSTOM_MOUNT_ARBITRARY:
r = mount_arbitrary(dest, m);
break;
default:
assert_not_reached("Unknown custom mount type");
}

View File

@ -13,14 +13,15 @@ typedef enum MountSettingsMask {
MOUNT_APPLY_APIVFS_RO = 1 << 3, /* if set, /proc/sys, and /sys will be mounted read-only, otherwise read-write. */
MOUNT_APPLY_APIVFS_NETNS = 1 << 4, /* if set, /proc/sys/net will be mounted read-write.
Works only if MOUNT_APPLY_APIVFS_RO is also set. */
MOUNT_INACCESSIBLE_REG = 1 << 5, /* if set, create an inaccessible regular file first and use as bind mount source */
MOUNT_APPLY_TMPFS_TMP = 1 << 6, /* if set, /tmp will be mounted as tmpfs */
MOUNT_APPLY_TMPFS_TMP = 1 << 5, /* if set, /tmp will be mounted as tmpfs */
} MountSettingsMask;
typedef enum CustomMountType {
CUSTOM_MOUNT_BIND,
CUSTOM_MOUNT_TMPFS,
CUSTOM_MOUNT_OVERLAY,
CUSTOM_MOUNT_INACCESSIBLE,
CUSTOM_MOUNT_ARBITRARY,
_CUSTOM_MOUNT_TYPE_MAX,
_CUSTOM_MOUNT_TYPE_INVALID = -1
} CustomMountType;
@ -34,6 +35,9 @@ typedef struct CustomMount {
char *work_dir;
char **lower;
char *rm_rf_tmpdir;
char *type_argument; /* only for CUSTOM_MOUNT_ARBITRARY */
bool graceful;
bool in_userns;
} CustomMount;
CustomMount* custom_mount_add(CustomMount **l, size_t *n, CustomMountType t);
@ -43,11 +47,12 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n);
int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s);
int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
int inaccessible_mount_parse(CustomMount **l, size_t *n, const char *s);
int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, const char *selinux_apifs_context);
int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool in_userns);
int setup_volatile_mode(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);

2352
src/nspawn/nspawn-oci.c Normal file

File diff suppressed because it is too large Load Diff

6
src/nspawn/nspawn-oci.h Normal file
View File

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "nspawn-settings.h"
int oci_load(FILE *f, const char *path, Settings **ret);

View File

@ -112,6 +112,7 @@ int register_machine(
unsigned n_mounts,
int kill_signal,
char **properties,
sd_bus_message *properties_message,
bool keep_unit,
const char *service) {
@ -185,6 +186,12 @@ int register_machine(
if (r < 0)
return r;
if (properties_message) {
r = sd_bus_message_copy(m, properties_message, true);
if (r < 0)
return bus_log_create_error(r);
}
r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
if (r < 0)
return r;
@ -235,7 +242,8 @@ int allocate_scope(
CustomMount *mounts,
unsigned n_mounts,
int kill_signal,
char **properties) {
char **properties,
sd_bus_message *properties_message) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -289,6 +297,12 @@ int allocate_scope(
if (r < 0)
return r;
if (properties_message) {
r = sd_bus_message_copy(m, properties_message, true);
if (r < 0)
return bus_log_create_error(r);
}
r = append_machine_properties(
m,
mounts,

View File

@ -7,8 +7,8 @@
#include "nspawn-mount.h"
int register_machine(sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service);
int register_machine(sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message, bool keep_unit, const char *service);
int terminate_machine(sd_bus *bus, const char *machine_name);
int allocate_scope(sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties);
int allocate_scope(sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message);
int terminate_scope(sd_bus *bus, const char *machine_name);

View File

@ -17,6 +17,50 @@
#include "user-util.h"
#include "util.h"
Settings *settings_new(void) {
Settings *s;
s = new(Settings, 1);
if (!s)
return NULL;
*s = (Settings) {
.start_mode = _START_MODE_INVALID,
.personality = PERSONALITY_INVALID,
.resolv_conf = _RESOLV_CONF_MODE_INVALID,
.link_journal = _LINK_JOURNAL_INVALID,
.timezone = _TIMEZONE_MODE_INVALID,
.userns_mode = _USER_NAMESPACE_MODE_INVALID,
.userns_chown = -1,
.uid_shift = UID_INVALID,
.uid_range = UID_INVALID,
.no_new_privileges = -1,
.read_only = -1,
.volatile_mode = _VOLATILE_MODE_INVALID,
.private_network = -1,
.network_veth = -1,
.full_capabilities = CAPABILITY_QUINTET_NULL,
.uid = UID_INVALID,
.gid = GID_INVALID,
.console_mode = _CONSOLE_MODE_INVALID,
.console_width = (unsigned) -1,
.console_height = (unsigned) -1,
.clone_ns_flags = (unsigned long) -1,
.use_cgns = -1,
};
return s;
}
int settings_load(FILE *f, const char *path, Settings **ret) {
_cleanup_(settings_freep) Settings *s = NULL;
int r;
@ -24,27 +68,10 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
assert(path);
assert(ret);
s = new0(Settings, 1);
s = settings_new();
if (!s)
return -ENOMEM;
s->start_mode = _START_MODE_INVALID;
s->personality = PERSONALITY_INVALID;
s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
s->resolv_conf = _RESOLV_CONF_MODE_INVALID;
s->link_journal = _LINK_JOURNAL_INVALID;
s->timezone = _TIMEZONE_MODE_INVALID;
s->uid_shift = UID_INVALID;
s->uid_range = UID_INVALID;
s->no_new_privileges = -1;
s->read_only = -1;
s->volatile_mode = _VOLATILE_MODE_INVALID;
s->userns_chown = -1;
s->private_network = -1;
s->network_veth = -1;
r = config_parse(NULL, path, f,
"Exec\0"
"Network\0"
@ -66,12 +93,33 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
s->userns_mode = USER_NAMESPACE_NO;
*ret = TAKE_PTR(s);
return 0;
}
Settings* settings_free(Settings *s) {
static void free_oci_hooks(OciHook *h, size_t n) {
size_t i;
assert(h || n == 0);
for (i = 0; i < n; i++) {
free(h[i].path);
strv_free(h[i].args);
strv_free(h[i].env);
}
free(h);
}
void device_node_free_many(DeviceNode *node, size_t n) {
size_t i;
for (i = 0; i < n; i++)
free(node[i].path);
free(node);
}
Settings* settings_free(Settings *s) {
if (!s)
return NULL;
@ -96,6 +144,28 @@ Settings* settings_free(Settings *s) {
expose_port_free_all(s->expose_ports);
custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
free(s->bundle);
free(s->root);
free_oci_hooks(s->oci_hooks_prestart, s->n_oci_hooks_prestart);
free_oci_hooks(s->oci_hooks_poststart, s->n_oci_hooks_poststart);
free_oci_hooks(s->oci_hooks_poststop, s->n_oci_hooks_poststop);
free(s->slice);
sd_bus_message_unref(s->properties);
free(s->supplementary_gids);
device_node_free_many(s->extra_nodes, s->n_extra_nodes);
free(s->extra_nodes);
free(s->network_namespace_path);
strv_free(s->sysctl);
#if HAVE_SECCOMP
seccomp_release(s->seccomp);
#endif
return mfree(s);
}
@ -122,6 +192,26 @@ bool settings_network_veth(Settings *s) {
s->network_zone;
}
int settings_allocate_properties(Settings *s) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
int r;
assert(s);
if (s->properties)
return 0;
r = sd_bus_default_system(&bus);
if (r < 0)
return r;
r = sd_bus_message_new(bus, &s->properties, SD_BUS_MESSAGE_METHOD_CALL);
if (r < 0)
return r;
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
int config_parse_expose_port(
@ -315,6 +405,34 @@ int config_parse_tmpfs(
return 0;
}
int config_parse_inaccessible(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Settings *settings = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
return 0;
}
return 0;
}
int config_parse_overlay(
const char *unit,
const char *filename,

View File

@ -4,8 +4,14 @@
#include <sched.h>
#include <stdio.h>
#if HAVE_SECCOMP
#include <seccomp.h>
#endif
#include "sd-bus.h"
#include "sd-id128.h"
#include "capability-util.h"
#include "conf-parser.h"
#include "macro.h"
#include "missing_resource.h"
@ -60,6 +66,15 @@ typedef enum TimezoneMode {
_TIMEZONE_MODE_INVALID = -1
} TimezoneMode;
typedef enum ConsoleMode {
CONSOLE_INTERACTIVE,
CONSOLE_READ_ONLY,
CONSOLE_PASSIVE,
CONSOLE_PIPE,
_CONSOLE_MODE_MAX,
_CONSOLE_MODE_INVALID = -1,
} ConsoleMode;
typedef enum SettingsMask {
SETTING_START_MODE = UINT64_C(1) << 0,
SETTING_ENVIRONMENT = UINT64_C(1) << 1,
@ -86,9 +101,14 @@ typedef enum SettingsMask {
SETTING_LINK_JOURNAL = UINT64_C(1) << 22,
SETTING_TIMEZONE = UINT64_C(1) << 23,
SETTING_EPHEMERAL = UINT64_C(1) << 24,
SETTING_RLIMIT_FIRST = UINT64_C(1) << 25, /* we define one bit per resource limit here */
SETTING_RLIMIT_LAST = UINT64_C(1) << (25 + _RLIMIT_MAX - 1),
_SETTINGS_MASK_ALL = (UINT64_C(1) << (25 + _RLIMIT_MAX)) -1,
SETTING_SLICE = UINT64_C(1) << 25,
SETTING_DIRECTORY = UINT64_C(1) << 26,
SETTING_USE_CGNS = UINT64_C(1) << 27,
SETTING_CLONE_NS_FLAGS = UINT64_C(1) << 28,
SETTING_CONSOLE_MODE = UINT64_C(1) << 29,
SETTING_RLIMIT_FIRST = UINT64_C(1) << 30, /* we define one bit per resource limit here */
SETTING_RLIMIT_LAST = UINT64_C(1) << (30 + _RLIMIT_MAX - 1),
_SETTINGS_MASK_ALL = (UINT64_C(1) << (30 + _RLIMIT_MAX)) -1,
_SETTING_FORCE_ENUM_WIDTH = UINT64_MAX
} SettingsMask;
@ -101,6 +121,22 @@ assert_cc(sizeof(SettingsMask) == 8);
assert_cc(sizeof(SETTING_RLIMIT_FIRST) == 8);
assert_cc(sizeof(SETTING_RLIMIT_LAST) == 8);
typedef struct DeviceNode {
char *path;
unsigned major;
unsigned minor;
mode_t mode;
uid_t uid;
gid_t gid;
} DeviceNode;
typedef struct OciHook {
char *path;
char **args;
char **env;
usec_t timeout;
} OciHook;
typedef struct Settings {
/* [Run] */
StartMode start_mode;
@ -150,13 +186,39 @@ typedef struct Settings {
char **network_ipvlan;
char **network_veth_extra;
ExposePort *expose_ports;
/* Additional fields, that are specific to OCI runtime case */
char *bundle;
char *root;
OciHook *oci_hooks_prestart, *oci_hooks_poststart, *oci_hooks_poststop;
size_t n_oci_hooks_prestart, n_oci_hooks_poststart, n_oci_hooks_poststop;
char *slice;
sd_bus_message *properties;
CapabilityQuintet full_capabilities;
uid_t uid;
gid_t gid;
gid_t *supplementary_gids;
size_t n_supplementary_gids;
unsigned console_width, console_height;
ConsoleMode console_mode;
DeviceNode *extra_nodes;
size_t n_extra_nodes;
unsigned long clone_ns_flags;
char *network_namespace_path;
int use_cgns;
char **sysctl;
#if HAVE_SECCOMP
scmp_filter_ctx seccomp;
#endif
} Settings;
Settings *settings_new(void);
int settings_load(FILE *f, const char *path, Settings **ret);
Settings* settings_free(Settings *s);
bool settings_network_veth(Settings *s);
bool settings_private_network(Settings *s);
int settings_allocate_properties(Settings *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free);
@ -170,6 +232,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_pivot_root);
CONFIG_PARSER_PROTOTYPE(config_parse_bind);
CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs);
CONFIG_PARSER_PROTOTYPE(config_parse_overlay);
CONFIG_PARSER_PROTOTYPE(config_parse_inaccessible);
CONFIG_PARSER_PROTOTYPE(config_parse_veth_extra);
CONFIG_PARSER_PROTOTYPE(config_parse_network_zone);
CONFIG_PARSER_PROTOTYPE(config_parse_boot);
@ -190,3 +253,5 @@ const char *timezone_mode_to_string(TimezoneMode a) _const_;
TimezoneMode timezone_mode_from_string(const char *s) _pure_;
int parse_link_journal(const char *s, LinkJournal *ret_mode, bool *ret_try);
void device_node_free_many(DeviceNode *node, size_t n);

File diff suppressed because it is too large Load Diff