localed: avoid TOCTOU in loading config

This commit is contained in:
Yu Watanabe
2022-12-14 20:18:58 +09:00
parent 649512b934
commit 7294912f18
3 changed files with 45 additions and 37 deletions
+41 -32
View File
@@ -20,6 +20,7 @@
#include "mkdir-label.h"
#include "nulstr-util.h"
#include "process-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "tmpfile-util.h"
@@ -92,8 +93,8 @@ int locale_read_data(Context *c, sd_bus_message *m) {
}
int vconsole_read_data(Context *c, sd_bus_message *m) {
_cleanup_close_ int fd = -EBADFD;
struct stat st;
usec_t t;
/* Do not try to re-read the file within single bus operation. */
if (m) {
@@ -104,33 +105,35 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
c->vc_cache = sd_bus_message_ref(m);
}
if (stat("/etc/vconsole.conf", &st) < 0) {
if (errno != ENOENT)
return -errno;
c->vc_mtime = USEC_INFINITY;
fd = RET_NERRNO(open("/etc/vconsole.conf", O_CLOEXEC | O_PATH));
if (fd == -ENOENT) {
c->vc_stat = (struct stat) {};
context_free_vconsole(c);
return 0;
}
if (fd < 0)
return fd;
/* If mtime is not changed, then we do not need to re-read */
t = timespec_load(&st.st_mtim);
if (c->vc_mtime != USEC_INFINITY && t == c->vc_mtime)
if (fstat(fd, &st) < 0)
return -errno;
/* If the file is not changed, then we do not need to re-read */
if (stat_inode_unmodified(&c->vc_stat, &st))
return 0;
c->vc_mtime = t;
c->vc_stat = st;
context_free_vconsole(c);
return parse_env_file(NULL, "/etc/vconsole.conf",
"KEYMAP", &c->vc_keymap,
"KEYMAP_TOGGLE", &c->vc_keymap_toggle);
return parse_env_file_fd(fd, "/etc/vconsole.conf",
"KEYMAP", &c->vc_keymap,
"KEYMAP_TOGGLE", &c->vc_keymap_toggle);
}
int x11_read_data(Context *c, sd_bus_message *m) {
_cleanup_close_ int fd = -EBADFD, fd_ro = -EBADFD;
_cleanup_fclose_ FILE *f = NULL;
bool in_section = false;
struct stat st;
usec_t t;
int r;
/* Do not try to re-read the file within single bus operation. */
@@ -142,27 +145,35 @@ int x11_read_data(Context *c, sd_bus_message *m) {
c->x11_cache = sd_bus_message_ref(m);
}
if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) < 0) {
if (errno != ENOENT)
return -errno;
c->x11_mtime = USEC_INFINITY;
fd = RET_NERRNO(open("/etc/X11/xorg.conf.d/00-keyboard.conf", O_CLOEXEC | O_PATH));
if (fd == -ENOENT) {
c->x11_stat = (struct stat) {};
context_free_x11(c);
return 0;
}
if (fd < 0)
return fd;
/* If mtime is not changed, then we do not need to re-read */
t = timespec_load(&st.st_mtim);
if (c->x11_mtime != USEC_INFINITY && t == c->x11_mtime)
if (fstat(fd, &st) < 0)
return -errno;
/* If the file is not changed, then we do not need to re-read */
if (stat_inode_unmodified(&c->x11_stat, &st))
return 0;
c->x11_mtime = t;
c->x11_stat = st;
context_free_x11(c);
f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
fd_ro = fd_reopen(fd, O_CLOEXEC | O_RDONLY);
if (fd_ro < 0)
return fd_ro;
f = fdopen(fd_ro, "re");
if (!f)
return -errno;
TAKE_FD(fd_ro);
for (;;) {
_cleanup_free_ char *line = NULL;
char *l;
@@ -219,7 +230,6 @@ int x11_read_data(Context *c, sd_bus_message *m) {
int vconsole_write_data(Context *c) {
_cleanup_strv_free_ char **l = NULL;
struct stat st;
int r;
r = load_env_file(NULL, "/etc/vconsole.conf", &l);
@@ -238,7 +248,7 @@ int vconsole_write_data(Context *c) {
if (unlink("/etc/vconsole.conf") < 0)
return errno == ENOENT ? 0 : -errno;
c->vc_mtime = USEC_INFINITY;
c->vc_stat = (struct stat) {};
return 0;
}
@@ -246,8 +256,8 @@ int vconsole_write_data(Context *c) {
if (r < 0)
return r;
if (stat("/etc/vconsole.conf", &st) >= 0)
c->vc_mtime = timespec_load(&st.st_mtim);
if (stat("/etc/vconsole.conf", &c->vc_stat) < 0)
return -errno;
return 0;
}
@@ -255,7 +265,6 @@ int vconsole_write_data(Context *c) {
int x11_write_data(Context *c) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
struct stat st;
int r;
if (isempty(c->x11_layout) &&
@@ -266,7 +275,7 @@ int x11_write_data(Context *c) {
if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
return errno == ENOENT ? 0 : -errno;
c->vc_mtime = USEC_INFINITY;
c->x11_stat = (struct stat) {};
return 0;
}
@@ -305,8 +314,8 @@ int x11_write_data(Context *c) {
if (rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
return -errno;
if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) >= 0)
c->x11_mtime = timespec_load(&st.st_mtim);
if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &c->x11_stat) < 0)
return -errno;
return 0;
}
+4 -3
View File
@@ -1,25 +1,26 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/stat.h>
#include "sd-bus.h"
#include "hashmap.h"
#include "locale-setup.h"
#include "time-util.h"
typedef struct Context {
sd_bus_message *locale_cache;
LocaleContext locale_context;
sd_bus_message *x11_cache;
usec_t x11_mtime;
struct stat x11_stat;
char *x11_layout;
char *x11_model;
char *x11_variant;
char *x11_options;
sd_bus_message *vc_cache;
usec_t vc_mtime;
struct stat vc_stat;
char *vc_keymap;
char *vc_keymap_toggle;
-2
View File
@@ -766,8 +766,6 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
static int run(int argc, char *argv[]) {
_cleanup_(context_clear) Context context = {
.locale_context.mtime = USEC_INFINITY,
.vc_mtime = USEC_INFINITY,
.x11_mtime = USEC_INFINITY,
};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;