proc-cmdline: filter PID1 arguments when we are running in a container
Otherwise, PID1 arguments e.g. "--deserialize 16" may be parsed unexpectedly by generators. Fixes the issue reported at https://github.com/systemd/systemd/issues/24452#issuecomment-1475004433.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#define SYSTEMD_GETOPT_SHORT_OPTIONS "hDbsz:"
|
||||
|
||||
#define COMMON_GETOPT_ARGS \
|
||||
ARG_LOG_LEVEL = 0x100, \
|
||||
ARG_LOG_TARGET, \
|
||||
ARG_LOG_COLOR, \
|
||||
ARG_LOG_LOCATION, \
|
||||
ARG_LOG_TIME
|
||||
|
||||
#define SYSTEMD_GETOPT_ARGS \
|
||||
ARG_UNIT, \
|
||||
ARG_SYSTEM, \
|
||||
ARG_USER, \
|
||||
ARG_TEST, \
|
||||
ARG_NO_PAGER, \
|
||||
ARG_VERSION, \
|
||||
ARG_DUMP_CONFIGURATION_ITEMS, \
|
||||
ARG_DUMP_BUS_PROPERTIES, \
|
||||
ARG_BUS_INTROSPECT, \
|
||||
ARG_DUMP_CORE, \
|
||||
ARG_CRASH_CHVT, \
|
||||
ARG_CRASH_SHELL, \
|
||||
ARG_CRASH_REBOOT, \
|
||||
ARG_CONFIRM_SPAWN, \
|
||||
ARG_SHOW_STATUS, \
|
||||
ARG_DESERIALIZE, \
|
||||
ARG_SWITCHED_ROOT, \
|
||||
ARG_DEFAULT_STD_OUTPUT, \
|
||||
ARG_DEFAULT_STD_ERROR, \
|
||||
ARG_MACHINE_ID, \
|
||||
ARG_SERVICE_WATCHDOGS
|
||||
|
||||
#define SHUTDOWN_GETOPT_ARGS \
|
||||
ARG_EXIT_CODE, \
|
||||
ARG_TIMEOUT
|
||||
|
||||
#define COMMON_GETOPT_OPTIONS \
|
||||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL }, \
|
||||
{ "log-target", required_argument, NULL, ARG_LOG_TARGET }, \
|
||||
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR }, \
|
||||
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION }, \
|
||||
{ "log-time", optional_argument, NULL, ARG_LOG_TIME }
|
||||
|
||||
#define SYSTEMD_GETOPT_OPTIONS \
|
||||
{ "unit", required_argument, NULL, ARG_UNIT }, \
|
||||
{ "system", no_argument, NULL, ARG_SYSTEM }, \
|
||||
{ "user", no_argument, NULL, ARG_USER }, \
|
||||
{ "test", no_argument, NULL, ARG_TEST }, \
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER }, \
|
||||
{ "help", no_argument, NULL, 'h' }, \
|
||||
{ "version", no_argument, NULL, ARG_VERSION }, \
|
||||
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, \
|
||||
{ "dump-bus-properties", no_argument, NULL, ARG_DUMP_BUS_PROPERTIES }, \
|
||||
{ "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT }, \
|
||||
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, \
|
||||
{ "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, \
|
||||
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, \
|
||||
{ "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, \
|
||||
{ "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, \
|
||||
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, \
|
||||
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE }, \
|
||||
{ "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT }, \
|
||||
{ "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, }, \
|
||||
{ "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, }, \
|
||||
{ "machine-id", required_argument, NULL, ARG_MACHINE_ID }, \
|
||||
{ "service-watchdogs", required_argument, NULL, ARG_SERVICE_WATCHDOGS }
|
||||
|
||||
#define SHUTDOWN_GETOPT_OPTIONS \
|
||||
{ "exit-code", required_argument, NULL, ARG_EXIT_CODE }, \
|
||||
{ "timeout", required_argument, NULL, ARG_TIMEOUT }
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "efivars.h"
|
||||
#include "extract-word.h"
|
||||
#include "fileio.h"
|
||||
#include "getopt-defs.h"
|
||||
#include "initrd-util.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
@@ -16,6 +17,66 @@
|
||||
#include "strv.h"
|
||||
#include "virt.h"
|
||||
|
||||
int proc_cmdline_filter_pid1_args(
|
||||
char **argv, /* input, may be reordered by this function. */
|
||||
char ***ret) {
|
||||
|
||||
enum {
|
||||
COMMON_GETOPT_ARGS,
|
||||
SYSTEMD_GETOPT_ARGS,
|
||||
SHUTDOWN_GETOPT_ARGS,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
COMMON_GETOPT_OPTIONS,
|
||||
SYSTEMD_GETOPT_OPTIONS,
|
||||
SHUTDOWN_GETOPT_OPTIONS,
|
||||
{}
|
||||
};
|
||||
|
||||
int saved_optind, saved_opterr, saved_optopt, argc;
|
||||
char *saved_optarg;
|
||||
char **filtered;
|
||||
size_t idx;
|
||||
|
||||
assert(argv);
|
||||
assert(ret);
|
||||
|
||||
/* Backup global variables. */
|
||||
saved_optind = optind;
|
||||
saved_opterr = opterr;
|
||||
saved_optopt = optopt;
|
||||
saved_optarg = optarg;
|
||||
|
||||
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
||||
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). Here, we do not use
|
||||
* the GNU extensions, but might be used previously. Hence, we need to always reset it. */
|
||||
optind = 0;
|
||||
|
||||
/* Do not print an error message. */
|
||||
opterr = 0;
|
||||
|
||||
/* Filter out all known options. */
|
||||
argc = strv_length(argv);
|
||||
while (getopt_long(argc, argv, SYSTEMD_GETOPT_SHORT_OPTIONS, options, NULL) >= 0)
|
||||
;
|
||||
|
||||
idx = optind;
|
||||
|
||||
/* Restore global variables. */
|
||||
optind = saved_optind;
|
||||
opterr = saved_opterr;
|
||||
optopt = saved_optopt;
|
||||
optarg = saved_optarg;
|
||||
|
||||
filtered = strv_copy(strv_skip(argv, idx));
|
||||
if (!filtered)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = filtered;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_cmdline(char **ret) {
|
||||
const char *e;
|
||||
|
||||
@@ -40,7 +101,7 @@ int proc_cmdline(char **ret) {
|
||||
return read_one_line_file("/proc/cmdline", ret);
|
||||
}
|
||||
|
||||
int proc_cmdline_strv(char ***ret) {
|
||||
static int proc_cmdline_strv_internal(char ***ret, bool filter_pid1_args) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
@@ -51,9 +112,20 @@ int proc_cmdline_strv(char ***ret) {
|
||||
if (e)
|
||||
return strv_split_full(ret, e, NULL, EXTRACT_UNQUOTE|EXTRACT_RELAX|EXTRACT_RETAIN_ESCAPE);
|
||||
|
||||
if (detect_container() > 0)
|
||||
return get_process_cmdline_strv(1, /* flags = */ 0, ret);
|
||||
else {
|
||||
if (detect_container() > 0) {
|
||||
_cleanup_strv_free_ char **args = NULL;
|
||||
|
||||
r = get_process_cmdline_strv(1, /* flags = */ 0, &args);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (filter_pid1_args)
|
||||
return proc_cmdline_filter_pid1_args(args, ret);
|
||||
|
||||
*ret = TAKE_PTR(args);
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
|
||||
r = read_one_line_file("/proc/cmdline", &s);
|
||||
@@ -64,6 +136,10 @@ int proc_cmdline_strv(char ***ret) {
|
||||
}
|
||||
}
|
||||
|
||||
int proc_cmdline_strv(char ***ret) {
|
||||
return proc_cmdline_strv_internal(ret, /* filter_pid1_args = */ false);
|
||||
}
|
||||
|
||||
static char *mangle_word(const char *word, ProcCmdlineFlags flags) {
|
||||
char *c;
|
||||
|
||||
@@ -140,7 +216,7 @@ int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, ProcCmdlineF
|
||||
}
|
||||
}
|
||||
|
||||
r = proc_cmdline_strv(&args);
|
||||
r = proc_cmdline_strv_internal(&args, /* filter_pid1_args = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -249,7 +325,7 @@ int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_val
|
||||
if (FLAGS_SET(flags, PROC_CMDLINE_VALUE_OPTIONAL) && !ret_value)
|
||||
return -EINVAL;
|
||||
|
||||
r = proc_cmdline_strv(&args);
|
||||
r = proc_cmdline_strv_internal(&args, /* filter_pid1_args = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ typedef enum ProcCmdlineFlags {
|
||||
|
||||
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
|
||||
|
||||
int proc_cmdline_filter_pid1_args(char **argv, char ***ret);
|
||||
|
||||
int proc_cmdline(char **ret);
|
||||
int proc_cmdline_strv(char ***ret);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user