From: dongshengyuan <545258830@qq.com> Date: Mon, 13 Jul 2026 07:33:09 +0000 (+0800) Subject: journalctl: reject field listing with filters X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cb7b533b921d8b3390c361fe1b8bc58a00c05e53;p=thirdparty%2Fsystemd.git journalctl: reject field listing with filters Reproducer: journalctl -F _SYSTEMD_UNIT -u test.service --no-pager journalctl -u test.service --no-pager -n 1 Before, the field listing ignored the unit filter and listed unrelated units, while the normal journal query applied the filter. sd_journal_query_unique() cannot represent journalctl filters such as unit, boot, time, cursor, or grep filters. Walking the journal line by line would make field listing linear in the number of entries and duplicate unique-value handling. Keep the scope-option predicate next to add_filters(), and reject field listings combined with options that actually limit the journal. Display-only options such as --pager-end are left alone. --- diff --git a/src/journal/journalctl-filter.c b/src/journal/journalctl-filter.c index ce2a6cb18c6..01c82ca4059 100644 --- a/src/journal/journalctl-filter.c +++ b/src/journal/journalctl-filter.c @@ -23,6 +23,25 @@ #include "strv.h" #include "unit-name.h" +bool field_list_has_scope_options(void) { + return + arg_boot_filter || + arg_invocation || + arg_dmesg || + arg_cursor || + arg_after_cursor || + arg_cursor_file || + !strv_isempty(arg_system_units) || + !strv_isempty(arg_user_units) || + !strv_isempty(arg_syslog_identifier) || + !strv_isempty(arg_exclude_identifier) || + arg_priorities != 0 || + !set_isempty(arg_facilities) || + arg_since_set || + arg_until_set || + arg_pattern; +} + static int add_invocation(sd_journal *j) { int r; diff --git a/src/journal/journalctl-filter.h b/src/journal/journalctl-filter.h index bf2f7b839cd..f0ac453d3ce 100644 --- a/src/journal/journalctl-filter.h +++ b/src/journal/journalctl-filter.h @@ -11,4 +11,5 @@ int journal_add_unit_matches( uid_t uid, char * const *user_units); +bool field_list_has_scope_options(void); int add_filters(sd_journal *j, char **matches); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index b407a77d970..4bc648ceffe 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -17,6 +17,7 @@ #include "journalctl.h" #include "journalctl-authenticate.h" #include "journalctl-catalog.h" +#include "journalctl-filter.h" #include "journalctl-metrics.h" #include "journalctl-misc.h" #include "journalctl-show.h" @@ -70,6 +71,7 @@ bool arg_merge = false; int arg_boot = -1; /* tristate */ sd_id128_t arg_boot_id = {}; int arg_boot_offset = 0; +bool arg_boot_filter = false; bool arg_dmesg = false; bool arg_no_hostname = false; char *arg_cursor = NULL; @@ -532,6 +534,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { OPTION_LONG("this-boot", NULL, /* help= */ NULL): arg_boot = true; + arg_boot_filter = true; arg_boot_id = SD_ID128_NULL; arg_boot_offset = 0; break; @@ -539,6 +542,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { OPTION_FULL(OPTION_OPTIONAL_ARG, 'b', "boot", "ID", "Show current boot or the specified boot"): arg_boot = true; + arg_boot_filter = true; arg_boot_id = SD_ID128_NULL; arg_boot_offset = 0; @@ -548,6 +552,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { return log_error_errno(r, "Failed to parse boot descriptor '%s'", opts.arg); arg_boot = r; + arg_boot_filter = r > 0; } else { /* Hmm, no argument? Maybe the next word on the command line is supposed to @@ -558,6 +563,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { r = parse_id_descriptor(peek, &arg_boot_id, &arg_boot_offset); if (r >= 0) { arg_boot = r; + arg_boot_filter = r > 0; (void) option_parser_consume_next_arg(&opts); } } @@ -976,6 +982,10 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { "Extraneous arguments starting with '%s'", args[0]); + if (IN_SET(arg_action, ACTION_LIST_FIELDS, ACTION_LIST_FIELD_NAMES) && field_list_has_scope_options()) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "-F/--field= and -N/--fields cannot be combined with options that limit the journal."); + if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Using --boot or --list-boots with --merge is not supported."); diff --git a/src/journal/journalctl.h b/src/journal/journalctl.h index 59353253d49..23535ab0ce8 100644 --- a/src/journal/journalctl.h +++ b/src/journal/journalctl.h @@ -45,6 +45,7 @@ extern bool arg_merge; extern int arg_boot; extern sd_id128_t arg_boot_id; extern int arg_boot_offset; +extern bool arg_boot_filter; extern bool arg_dmesg; extern bool arg_no_hostname; extern char *arg_cursor; diff --git a/test/units/TEST-04-JOURNAL.journal.sh b/test/units/TEST-04-JOURNAL.journal.sh index 03613b5805d..403164016fd 100755 --- a/test/units/TEST-04-JOURNAL.journal.sh +++ b/test/units/TEST-04-JOURNAL.journal.sh @@ -158,6 +158,10 @@ journalctl --root / | grep . >/dev/null journalctl --cursor "t=0;t=-1;t=0;t=0x0" | grep . >/dev/null journalctl --header | grep system.journal journalctl --field _EXE | grep . >/dev/null +journalctl --field _EXE --pager-end | grep . >/dev/null +(! journalctl -q --field _SYSTEMD_UNIT --unit "test-no-such-unit-$RANDOM.service" --no-pager) +(! journalctl -q --field _SYSTEMD_UNIT --since "9999-01-01" --no-pager) +(! journalctl -q --fields --unit "test-no-such-unit-$RANDOM.service" --no-pager) journalctl --no-hostname --utc --catalog | grep . >/dev/null # Exercise executable_is_script() and the related code, e.g. `journalctl -b /path/to/a/script.sh` should turn # into ((_EXE=/usr/bin/bash AND _COMM=script.sh) AND _BOOT_ID=c002e3683ba14fa8b6c1e12878386514)