core: rework serialization
Let's be more careful with what we serialize: let's ensure we never serialize strings that are longer than LONG_LINE_MAX, so that we know we can read them back with read_line(…, LONG_LINE_MAX, …) safely. In order to implement this all serialization functions are move to serialize.[ch], and internally will do line size checks. We'd rather skip a serialization line (with a loud warning) than write an overly long line out. Of course, this is just a second level protection, after all the data we serialize shouldn't be this long in the first place. While we are at it also clean up logging: while serializing make sure to always log about errors immediately. Also, (void)ify all calls we don't expect errors in (or catch errors as part of the general fflush_and_check() at the end.
This commit is contained in:
@@ -752,36 +752,3 @@ int getenv_bool_secure(const char *p) {
|
||||
|
||||
return parse_boolean(e);
|
||||
}
|
||||
|
||||
int serialize_environment(FILE *f, char **environment) {
|
||||
char **e;
|
||||
|
||||
STRV_FOREACH(e, environment) {
|
||||
_cleanup_free_ char *ce;
|
||||
|
||||
ce = cescape(*e);
|
||||
if (!ce)
|
||||
return -ENOMEM;
|
||||
|
||||
fprintf(f, "env=%s\n", ce);
|
||||
}
|
||||
|
||||
/* caller should call ferror() */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int deserialize_environment(char ***environment, const char *line) {
|
||||
char *uce;
|
||||
int r;
|
||||
|
||||
assert(line);
|
||||
assert(environment);
|
||||
|
||||
assert(startswith(line, "env="));
|
||||
r = cunescape(line + 4, 0, &uce);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return strv_env_replace(environment, uce);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,3 @@ char *strv_env_get(char **x, const char *n) _pure_;
|
||||
|
||||
int getenv_bool(const char *p);
|
||||
int getenv_bool_secure(const char *p);
|
||||
|
||||
int serialize_environment(FILE *f, char **environment);
|
||||
int deserialize_environment(char ***environment, const char *line);
|
||||
|
||||
+31
-11
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "conf-files.h"
|
||||
#include "def.h"
|
||||
#include "env-util.h"
|
||||
#include "exec-util.h"
|
||||
#include "fd-util.h"
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "hashmap.h"
|
||||
#include "macro.h"
|
||||
#include "process-util.h"
|
||||
#include "serialize.h"
|
||||
#include "set.h"
|
||||
#include "signal-util.h"
|
||||
#include "stat-util.h"
|
||||
@@ -282,7 +284,7 @@ static int gather_environment_collect(int fd, void *arg) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = serialize_environment(f, *env);
|
||||
r = serialize_strv(f, "env", *env);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -294,29 +296,47 @@ static int gather_environment_collect(int fd, void *arg) {
|
||||
}
|
||||
|
||||
static int gather_environment_consume(int fd, void *arg) {
|
||||
char ***env = arg;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char line[LINE_MAX];
|
||||
int r = 0, k;
|
||||
char ***env = arg;
|
||||
int r = 0;
|
||||
|
||||
/* Read a series of env=cescape(VAR=value) assignments from fd into env. */
|
||||
|
||||
assert(env);
|
||||
|
||||
f = fdopen(fd, "r");
|
||||
f = fdopen(fd, "re");
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
FOREACH_LINE(line, f, return -EIO) {
|
||||
truncate_nl(line);
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
const char *v;
|
||||
int k;
|
||||
|
||||
k = deserialize_environment(env, line);
|
||||
k = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (k < 0)
|
||||
log_error_errno(k, "Invalid line \"%s\": %m", line);
|
||||
if (k < 0 && r == 0)
|
||||
r = k;
|
||||
return k;
|
||||
if (k == 0)
|
||||
break;
|
||||
|
||||
v = startswith(line, "env=");
|
||||
if (!v) {
|
||||
log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line);
|
||||
if (r == 0)
|
||||
r = -EINVAL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
k = deserialize_environment(v, env);
|
||||
if (k < 0) {
|
||||
log_debug_errno(k, "Invalid serialization line \"%s\": %m", line);
|
||||
|
||||
if (r == 0)
|
||||
r = k;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
+1
-58
@@ -24,6 +24,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "serialize.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@@ -530,64 +531,6 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
|
||||
|
||||
assert(f);
|
||||
assert(name);
|
||||
assert(t);
|
||||
|
||||
if (!dual_timestamp_is_set(t))
|
||||
return;
|
||||
|
||||
fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
|
||||
name,
|
||||
t->realtime,
|
||||
t->monotonic);
|
||||
}
|
||||
|
||||
int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
|
||||
uint64_t a, b;
|
||||
int r, pos;
|
||||
|
||||
assert(value);
|
||||
assert(t);
|
||||
|
||||
pos = strspn(value, WHITESPACE);
|
||||
if (value[pos] == '-')
|
||||
return -EINVAL;
|
||||
pos += strspn(value + pos, DIGITS);
|
||||
pos += strspn(value + pos, WHITESPACE);
|
||||
if (value[pos] == '-')
|
||||
return -EINVAL;
|
||||
|
||||
r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
|
||||
if (r != 2) {
|
||||
log_debug("Failed to parse dual timestamp value \"%s\".", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value[pos] != '\0')
|
||||
/* trailing garbage */
|
||||
return -EINVAL;
|
||||
|
||||
t->realtime = a;
|
||||
t->monotonic = b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timestamp_deserialize(const char *value, usec_t *timestamp) {
|
||||
int r;
|
||||
|
||||
assert(value);
|
||||
|
||||
r = safe_atou64(value, timestamp);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
||||
static const struct {
|
||||
const char *name;
|
||||
|
||||
@@ -108,10 +108,6 @@ char *format_timestamp_us_utc(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_relative(char *buf, size_t l, usec_t t);
|
||||
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
|
||||
|
||||
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
|
||||
int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
|
||||
int timestamp_deserialize(const char *value, usec_t *timestamp);
|
||||
|
||||
int parse_timestamp(const char *t, usec_t *usec);
|
||||
|
||||
int parse_sec(const char *t, usec_t *usec);
|
||||
|
||||
Reference in New Issue
Block a user