1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-08 08:58:27 +03:00

Merge pull request #12079 from keszybz/fuzz-nspawn-oci

Add fuzzer for nspawn-oci
This commit is contained in:
Lennart Poettering 2019-03-22 21:06:17 +01:00 committed by GitHub
commit 83276695c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 365 additions and 114 deletions

View File

@ -0,0 +1,28 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include "alloc-util.h"
#include "fd-util.h"
#include "fuzz.h"
#include "nspawn-oci.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(settings_freep) Settings *s = NULL;
if (size == 0)
return 0;
f = fmemopen((char*) data, size, "re");
assert_se(f);
/* We don't want to fill the logs with messages about parse errors.
* Disable most logging if not running standalone */
if (!getenv("SYSTEMD_LOG_LEVEL"))
log_set_max_level(LOG_CRIT);
(void) oci_load(f, "/dev/null", &s);
return 0;
}

View File

@ -130,6 +130,11 @@ fuzzers += [
libnspawn_core],
[]],
[['src/fuzz/fuzz-nspawn-oci.c'],
[libshared,
libnspawn_core],
[]],
[['src/fuzz/fuzz-calendarspec.c'],
[libshared],
[]],

View File

@ -517,6 +517,20 @@ static bool oci_exclude_mount(const char *path) {
return false;
}
typedef struct oci_mount_data {
char *destination;
char *source;
char *type;
char **options;
} oci_mount_data;
static void cleanup_oci_mount_data(oci_mount_data *data) {
free(data->destination);
free(data->source);
strv_free(data->options);
free(data->type);
}
static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
Settings *s = userdata;
JsonVariant *e;
@ -525,56 +539,42 @@ static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags,
assert(s);
JSON_VARIANT_ARRAY_FOREACH(e, v) {
struct mount_data {
char *destination;
char *source;
char *type;
char **options;
} data = {};
static const JsonDispatch table[] = {
{ "destination", JSON_VARIANT_STRING, oci_absolute_path, offsetof(struct mount_data, destination), JSON_MANDATORY },
{ "source", JSON_VARIANT_STRING, json_dispatch_string, offsetof(struct mount_data, source), 0 },
{ "options", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(struct mount_data, options), 0, },
{ "type", JSON_VARIANT_STRING, json_dispatch_string, offsetof(struct mount_data, type), 0 },
{ "destination", JSON_VARIANT_STRING, oci_absolute_path, offsetof(oci_mount_data, destination), JSON_MANDATORY },
{ "source", JSON_VARIANT_STRING, json_dispatch_string, offsetof(oci_mount_data, source), 0 },
{ "options", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(oci_mount_data, options), 0, },
{ "type", JSON_VARIANT_STRING, json_dispatch_string, offsetof(oci_mount_data, type), 0 },
{}
};
_cleanup_free_ char *joined_options = NULL;
CustomMount *m;
_cleanup_(cleanup_oci_mount_data) oci_mount_data data = {};
r = json_dispatch(e, table, oci_unexpected, flags, &data);
if (r < 0)
goto fail_item;
return r;
if (!path_is_absolute(data.destination)) {
r = json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
"Mount destination not an absolute path: %s", data.destination);
goto fail_item;
}
if (!path_is_absolute(data.destination))
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
"Mount destination not an absolute path: %s", data.destination);
if (oci_exclude_mount(data.destination))
goto skip_item;
continue;
if (data.options) {
joined_options = strv_join(data.options, ",");
if (!joined_options) {
r = log_oom();
goto fail_item;
}
if (!joined_options)
return log_oom();
}
if (!data.type || streq(data.type, "bind")) {
if (!path_is_absolute(data.source)) {
if (data.source && !path_is_absolute(data.source)) {
char *joined;
joined = path_join(s->bundle, data.source);
if (!joined) {
r = log_oom();
goto fail_item;
}
if (!joined)
return log_oom();
free_and_replace(data.source, joined);
}
@ -584,32 +584,13 @@ static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags,
m = custom_mount_add(&s->custom_mounts, &s->n_custom_mounts, CUSTOM_MOUNT_BIND);
} else
m = custom_mount_add(&s->custom_mounts, &s->n_custom_mounts, CUSTOM_MOUNT_ARBITRARY);
if (!m) {
r = log_oom();
goto fail_item;
}
if (!m)
return log_oom();
m->destination = TAKE_PTR(data.destination);
m->source = TAKE_PTR(data.source);
m->options = TAKE_PTR(joined_options);
m->type_argument = TAKE_PTR(data.type);
strv_free(data.options);
continue;
fail_item:
free(data.destination);
free(data.source);
strv_free(data.options);
free(data.type);
return r;
skip_item:
free(data.destination);
free(data.source);
strv_free(data.options);
free(data.type);
}
return 0;

View File

@ -110,7 +110,7 @@ static void free_oci_hooks(OciHook *h, size_t n) {
free(h);
}
void device_node_free_many(DeviceNode *node, size_t n) {
void device_node_array_free(DeviceNode *node, size_t n) {
size_t i;
for (i = 0; i < n; i++)
@ -156,8 +156,7 @@ Settings* settings_free(Settings *s) {
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);
device_node_array_free(s->extra_nodes, s->n_extra_nodes);
free(s->network_namespace_path);
strv_free(s->sysctl);

View File

@ -254,4 +254,4 @@ 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);
void device_node_array_free(DeviceNode *node, size_t n);

View File

@ -3958,7 +3958,7 @@ static int merge_settings(Settings *settings, const char *path) {
arg_console_width = settings->console_width;
arg_console_height = settings->console_height;
device_node_free_many(arg_extra_nodes, arg_n_extra_nodes);
device_node_array_free(arg_extra_nodes, arg_n_extra_nodes);
arg_extra_nodes = TAKE_PTR(settings->extra_nodes);
arg_n_extra_nodes = settings->n_extra_nodes;
@ -5066,7 +5066,7 @@ finish:
custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
expose_port_free_all(arg_expose_ports);
rlimit_free_all(arg_rlimit);
device_node_free_many(arg_extra_nodes, arg_n_extra_nodes);
device_node_array_free(arg_extra_nodes, arg_n_extra_nodes);
if (r < 0)
return r;

View File

@ -70,7 +70,7 @@ int main(int argc, char **argv) {
test_table(kill_who, KILL_WHO);
test_table(locale_variable, VARIABLE_LC);
test_table(log_target, LOG_TARGET);
test_table(mac_policy, MACPOLICY);
test_table(mac_address_policy, MAC_ADDRESS_POLICY);
test_table(manager_state, MANAGER_STATE);
test_table(manager_timestamp, MANAGER_TIMESTAMP);
test_table(mount_exec_command, MOUNT_EXEC_COMMAND);

View File

@ -19,36 +19,36 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac)
Match.OriginalName, config_parse_ifnames, 0, offsetof(link_config, match_name)
Match.Path, config_parse_strv, 0, offsetof(link_config, match_path)
Match.Driver, config_parse_strv, 0, offsetof(link_config, match_driver)
Match.Type, config_parse_strv, 0, offsetof(link_config, match_type)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions)
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions)
Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(link_config, conditions)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, conditions)
Link.Description, config_parse_string, 0, offsetof(link_config, description)
Link.MACAddressPolicy, config_parse_mac_policy, 0, offsetof(link_config, mac_policy)
Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)
Link.BitsPerSecond, config_parse_si_size, 0, offsetof(link_config, speed)
Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex)
Link.AutoNegotiation, config_parse_tristate, 0, offsetof(link_config, autonegotiation)
Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol)
Link.Port, config_parse_port, 0, offsetof(link_config, port)
Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO])
Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO])
Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO6])
Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0
Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
Link.RxChannels, config_parse_channel, 0, 0
Link.TxChannels, config_parse_channel, 0, 0
Link.OtherChannels, config_parse_channel, 0, 0
Link.CombinedChannels, config_parse_channel, 0, 0
Link.Advertise, config_parse_advertise, 0, 0
Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac)
Match.OriginalName, config_parse_ifnames, 0, offsetof(link_config, match_name)
Match.Path, config_parse_strv, 0, offsetof(link_config, match_path)
Match.Driver, config_parse_strv, 0, offsetof(link_config, match_driver)
Match.Type, config_parse_strv, 0, offsetof(link_config, match_type)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions)
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions)
Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(link_config, conditions)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, conditions)
Link.Description, config_parse_string, 0, offsetof(link_config, description)
Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(link_config, mac_address_policy)
Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)
Link.BitsPerSecond, config_parse_si_size, 0, offsetof(link_config, speed)
Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex)
Link.AutoNegotiation, config_parse_tristate, 0, offsetof(link_config, autonegotiation)
Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol)
Link.Port, config_parse_port, 0, offsetof(link_config, port)
Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO])
Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO])
Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO6])
Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0
Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
Link.RxChannels, config_parse_channel, 0, 0
Link.TxChannels, config_parse_channel, 0, 0
Link.OtherChannels, config_parse_channel, 0, 0
Link.CombinedChannels, config_parse_channel, 0, 0
Link.Advertise, config_parse_advertise, 0, 0

View File

@ -139,7 +139,7 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
*link = (link_config) {
.filename = TAKE_PTR(name),
.mac_policy = _MACPOLICY_INVALID,
.mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
.wol = _WOL_INVALID,
.duplex = _DUP_INVALID,
.port = _NET_DEV_PORT_INVALID,
@ -280,12 +280,12 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
return -ENOENT;
}
static int get_mac(sd_device *device, MACPolicy policy, struct ether_addr *mac) {
static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
unsigned addr_type;
bool want_random = policy == MACPOLICY_RANDOM;
bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
int r;
assert(IN_SET(policy, MACPOLICY_RANDOM, MACPOLICY_PERSISTENT));
assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
if (r < 0)
@ -304,7 +304,7 @@ static int get_mac(sd_device *device, MACPolicy policy, struct ether_addr *mac)
if (want_random == (addr_type == NET_ADDR_RANDOM))
return log_device_debug(device, "MAC on the device already matches policy *%s*",
mac_policy_to_string(policy));
mac_address_policy_to_string(policy));
if (want_random) {
log_device_debug(device, "Using random bytes to generate MAC");
@ -444,8 +444,8 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
no_rename:
if (IN_SET(config->mac_policy, MACPOLICY_PERSISTENT, MACPOLICY_RANDOM)) {
if (get_mac(device, config->mac_policy, &generated_mac) > 0)
if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
mac = &generated_mac;
} else
mac = config->mac;
@ -476,14 +476,14 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
return 0;
}
static const char* const mac_policy_table[_MACPOLICY_MAX] = {
[MACPOLICY_PERSISTENT] = "persistent",
[MACPOLICY_RANDOM] = "random",
[MACPOLICY_NONE] = "none",
static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
[MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
[MAC_ADDRESS_POLICY_RANDOM] = "random",
[MAC_ADDRESS_POLICY_NONE] = "none",
};
DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_address_policy, mac_address_policy, MACAddressPolicy,
"Failed to parse MAC address policy");
static const char* const name_policy_table[_NAMEPOLICY_MAX] = {

View File

@ -12,13 +12,13 @@
typedef struct link_config_ctx link_config_ctx;
typedef struct link_config link_config;
typedef enum MACPolicy {
MACPOLICY_PERSISTENT,
MACPOLICY_RANDOM,
MACPOLICY_NONE,
_MACPOLICY_MAX,
_MACPOLICY_INVALID = -1
} MACPolicy;
typedef enum MACAddressPolicy {
MAC_ADDRESS_POLICY_PERSISTENT,
MAC_ADDRESS_POLICY_RANDOM,
MAC_ADDRESS_POLICY_NONE,
_MAC_ADDRESS_POLICY_MAX,
_MAC_ADDRESS_POLICY_INVALID = -1
} MACAddressPolicy;
typedef enum NamePolicy {
NAMEPOLICY_KERNEL,
@ -44,7 +44,7 @@ struct link_config {
char *description;
struct ether_addr *mac;
MACPolicy mac_policy;
MACAddressPolicy mac_address_policy;
NamePolicy *name_policy;
char *name;
char *alias;
@ -76,11 +76,11 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret);
const char *name_policy_to_string(NamePolicy p) _const_;
NamePolicy name_policy_from_string(const char *p) _pure_;
const char *mac_policy_to_string(MACPolicy p) _const_;
MACPolicy mac_policy_from_string(const char *p) _pure_;
const char *mac_address_policy_to_string(MACAddressPolicy p) _const_;
MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_;
/* gperf lookup function */
const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
CONFIG_PARSER_PROTOTYPE(config_parse_mac_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_name_policy);

View File

@ -0,0 +1,141 @@
{
"ociVersion": "1.0.0",
"root": {
"path": "rootfs",
"readonly": true
},
"process": {
"terminal": false,
"consoleSize": {
"height":6667,
"width":6668
},
"user": {
"uid": 14,
"gid": 14,
"additionalGids": [59, 81]
},
"args": [
"/tmp/verify.sh"
],
"env": [
"FOO=BAR",
"WITHSPACES=FOO BAR",
"WITHSHELLCHARS=$ASDF \\\"asdf asdf\\\" !",
"WITHCONTROLCHARS=\\123\\125\\010\\020",
"TERM=xterm"
],
"cwd": "/tmp/src",
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1020,
"soft": 1020
}
]
},
"mounts": [
{
"destination": "/tmp/src",
"source": "src",
"options": ["ro"]
},
{
"destination": "/tmp/verify.sh",
"source": "verify.sh",
"options": ["ro"]
},
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"mode=777"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"mode=777"
]
},
{
"destination": "/dev/shm",
"type": "tmpfs",
"source": "shm",
"options": [
"mode=777"
]
},
{
"destination": "/dev/mqueue",
"type": "mqueue",
"source": "mqueue",
"options": [
"mode=777"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"mode=777"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"mode=777"
]
}
],
"hooks": {},
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
]
},
"namespaces": [
{
"type": "pid"
},
{
"type": "ipc"
},
{
"type": "mount"
}
]
},
"annotations": {
"com.example.key1": "value1",
"com.example.key2": "value2"
}
}

View File

@ -0,0 +1,5 @@
{"ociVersion": "1.0.0",
"linux": {"devices": [ { "access": "mmmw;r"}
] }, "e": "}e"
}

View File

@ -0,0 +1,92 @@
{
"ociVersion": "1.0.0",
"root": {
"path": "rootfs",
"readonly": true
},
"process": {
"terminal": false,
"consoleSize": {
"height":6667,
"width":6668
},
"user": {
"uid": 14,
"gid": 14,
"additionalGids": [59, 81]
},
"args": [
"/tmp/verify.sh"
],
"env": [
"FOO=BAR",
"WITHSPACES=FOO BAR",
"WITHSHELLCHARS=$ASDF \\\"asdf asdf\\\" !",
"WITHCONTROLCHARS=\\123\\125\\010\\020",
"TERM=xterm"
],
"cwd": "/tmp/src",
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1020,
"soft": 1020
}
]
},
"mounts": [
{
"destination": "/tmp/src" },
{
"source": "sysfs",
"options": [
"mode=777"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"mode=777"
]
}
],
"hooks": {},
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
]
},
"namespaces": [
{
"type": "pid"
},
{
"type": "ipc"
},
{
"type": "mount"
}
]
},
"annotations": {
"com.example.key1": "value1",
"com.example.key2": "value2"
}
}