diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-03-04 11:27:05 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-03-04 11:44:20 +0100 |
commit | 9ef70c06c663a05f7646d690e00e4b4a73af8c61 (patch) | |
tree | 23c0eaec0e0f0d9389098736efa0bbfc5c26cb4e /src/locale | |
parent | shared/kbd-util: return error on resource errors (diff) | |
download | systemd-9ef70c06c663a05f7646d690e00e4b4a73af8c61.tar.xz systemd-9ef70c06c663a05f7646d690e00e4b4a73af8c61.zip |
localed: refuse to set a keymap which is not installed
In https://bugzilla.redhat.com/show_bug.cgi?id=1933873 a keymap was set without
the package that provides it being installed (it2 is in kbd-legacy, which is
not installed by default). Setting a non-installed keymap is problematic,
because it results in nasty failures afterward (*). So let's to the same as
e.g. for locale data, and refuse a setting if the definition doesn't exists in
the filesystem.
The implementation using nftw() is not the most efficient, but I think it's OK
in this case. This is definitely not in any kind of hot path, and I prefer not
to duplicate the filename manipulation logic in a second function.
(*) If the keymap is not found, vconsole-setup.service will fail.
dracut-cmdline-ask.service has Requires=vconsole-setup.service, so it will also
fail, and this breaks boot. dracut-cmdline-ask.service having a hard dependency
is appropriate though: we sadly don't display what the keymap is, and with a wrong
keymap, any attempts to enter a password are likely to fail.
Diffstat (limited to 'src/locale')
-rw-r--r-- | src/locale/localed.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/src/locale/localed.c b/src/locale/localed.c index 9c97313edc..f44c0bab2a 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -19,6 +19,7 @@ #include "bus-polkit.h" #include "def.h" #include "dlfcn-util.h" +#include "kbd-util.h" #include "keymap-util.h" #include "locale-util.h" #include "macro.h" @@ -474,7 +475,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; - const char *keymap, *keymap_toggle; + const char *name, *keymap, *keymap_toggle; int convert, interactive, r; assert(m); @@ -490,17 +491,23 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro r = vconsole_read_data(c, m); if (r < 0) { log_error_errno(r, "Failed to read virtual console keymap data: %m"); - return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read virtual console keymap data"); + return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m"); + } + + FOREACH_STRING(name, keymap ?: keymap_toggle, keymap ? keymap_toggle : NULL) { + r = keymap_exists(name); /* This also verifies that the keymap name is kosher. */ + if (r < 0) { + log_error_errno(r, "Failed to check keymap %s: %m", name); + return sd_bus_error_set_errnof(error, r, "Failed to check keymap %s: %m", name); + } + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Keymap %s is not installed.", name); } if (streq_ptr(keymap, c->vc_keymap) && streq_ptr(keymap_toggle, c->vc_keymap_toggle)) return sd_bus_reply_method_return(m, NULL); - if ((keymap && (!filename_is_valid(keymap) || !string_is_safe(keymap))) || - (keymap_toggle && (!filename_is_valid(keymap_toggle) || !string_is_safe(keymap_toggle)))) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keymap data"); - r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, |