Merge pull request #25718 from yuwata/locale-cleanups
locale: avoid TOCTOU in reading config files
This commit is contained in:
+70
-6
@@ -12,11 +12,17 @@
|
||||
#include "tmpfile-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
typedef int (*push_env_func_t)(
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *key,
|
||||
char *value,
|
||||
void *userdata);
|
||||
|
||||
static int parse_env_file_internal(
|
||||
FILE *f,
|
||||
const char *fname,
|
||||
int (*push) (const char *filename, unsigned line,
|
||||
const char *key, char *value, void *userdata),
|
||||
push_env_func_t push,
|
||||
void *userdata) {
|
||||
|
||||
size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
|
||||
@@ -37,6 +43,9 @@ static int parse_env_file_internal(
|
||||
COMMENT_ESCAPE
|
||||
} state = PRE_KEY;
|
||||
|
||||
assert(f || fname);
|
||||
assert(push);
|
||||
|
||||
if (f)
|
||||
r = read_full_stream(f, &contents, NULL);
|
||||
else
|
||||
@@ -274,6 +283,8 @@ static int check_utf8ness_and_warn(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value) {
|
||||
|
||||
assert(key);
|
||||
|
||||
if (!utf8_is_valid(key)) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
@@ -304,6 +315,8 @@ static int parse_env_file_push(
|
||||
va_list aq, *ap = userdata;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -338,6 +351,8 @@ int parse_env_filev(
|
||||
int r;
|
||||
va_list aq;
|
||||
|
||||
assert(f || fname);
|
||||
|
||||
va_copy(aq, ap);
|
||||
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
|
||||
va_end(aq);
|
||||
@@ -352,6 +367,37 @@ int parse_env_file_sentinel(
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
assert(f || fname);
|
||||
|
||||
va_start(ap, fname);
|
||||
r = parse_env_filev(f, fname, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int parse_env_file_fd_sentinel(
|
||||
int fd,
|
||||
const char *fname, /* only used for logging */
|
||||
...) {
|
||||
|
||||
_cleanup_close_ int fd_ro = -EBADFD;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
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);
|
||||
|
||||
va_start(ap, fname);
|
||||
r = parse_env_filev(f, fname, ap);
|
||||
va_end(ap);
|
||||
@@ -363,10 +409,13 @@ static int load_env_file_push(
|
||||
const char *filename, unsigned line,
|
||||
const char *key, char *value,
|
||||
void *userdata) {
|
||||
|
||||
char ***m = userdata;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -383,15 +432,18 @@ static int load_env_file_push(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_env_file(FILE *f, const char *fname, char ***rl) {
|
||||
int load_env_file(FILE *f, const char *fname, char ***ret) {
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
int r;
|
||||
|
||||
assert(f || fname);
|
||||
assert(ret);
|
||||
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*rl = TAKE_PTR(m);
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -403,6 +455,8 @@ static int load_env_file_push_pairs(
|
||||
char ***m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
r = check_utf8ness_and_warn(filename, line, key, value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -426,15 +480,17 @@ static int load_env_file_push_pairs(
|
||||
return strv_extend(m, "");
|
||||
}
|
||||
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***ret) {
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
int r;
|
||||
|
||||
assert(f || fname);
|
||||
|
||||
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*rl = TAKE_PTR(m);
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -446,6 +502,8 @@ static int merge_env_file_push(
|
||||
char ***env = ASSERT_PTR(userdata);
|
||||
char *expanded_value;
|
||||
|
||||
assert(key);
|
||||
|
||||
if (!value) {
|
||||
log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
|
||||
return 0;
|
||||
@@ -476,6 +534,9 @@ int merge_env_file(
|
||||
FILE *f,
|
||||
const char *fname) {
|
||||
|
||||
assert(env);
|
||||
assert(f || fname);
|
||||
|
||||
/* NOTE: this function supports braceful and braceless variable expansions,
|
||||
* plus "extended" substitutions, unlike other exported parsing functions.
|
||||
*/
|
||||
@@ -486,6 +547,9 @@ int merge_env_file(
|
||||
static void write_env_var(FILE *f, const char *v) {
|
||||
const char *p;
|
||||
|
||||
assert(f);
|
||||
assert(v);
|
||||
|
||||
p = strchr(v, '=');
|
||||
if (!p) {
|
||||
/* Fallback */
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
int parse_env_filev(FILE *f, const char *fname, va_list ap);
|
||||
int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
|
||||
#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
|
||||
int load_env_file(FILE *f, const char *fname, char ***l);
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***l);
|
||||
int parse_env_file_fd_sentinel(int fd, const char *fname, ...) _sentinel_;
|
||||
#define parse_env_file_fd(fd, fname, ...) parse_env_file_fd_sentinel(fd, fname, __VA_ARGS__, NULL)
|
||||
int load_env_file(FILE *f, const char *fname, char ***ret);
|
||||
int load_env_file_pairs(FILE *f, const char *fname, char ***ret);
|
||||
|
||||
int merge_env_file(char ***env, FILE *f, const char *fname);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user