summaryrefslogtreecommitdiffstats
path: root/src/basic/proc-cmdline.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2023-03-19 07:43:43 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2023-03-29 03:34:41 +0200
commit6339d3e6021f31a8a8907c2613f1aaac279fe745 (patch)
tree73dc4a1337afb23e17cee4cca1b1c84582ed75cf /src/basic/proc-cmdline.c
parenttree-wide: reset optind to 0 when GNU extensions in optstring are used (diff)
downloadsystemd-6339d3e6021f31a8a8907c2613f1aaac279fe745.tar.xz
systemd-6339d3e6021f31a8a8907c2613f1aaac279fe745.zip
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.
Diffstat (limited to 'src/basic/proc-cmdline.c')
-rw-r--r--src/basic/proc-cmdline.c88
1 files changed, 82 insertions, 6 deletions
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c
index 010bb762c4..39e9f2c668 100644
--- a/src/basic/proc-cmdline.c
+++ b/src/basic/proc-cmdline.c
@@ -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;