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:
Lennart Poettering
2018-10-26 10:52:41 +02:00
parent cdd620e346
commit d68c645bd3
31 changed files with 519 additions and 462 deletions
+28 -19
View File
@@ -2,9 +2,11 @@
#include <string.h>
#include "def.h"
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "serialize.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -304,52 +306,59 @@ static void test_env_assignment_is_valid(void) {
}
static void test_deserialize_environment(void) {
_cleanup_strv_free_ char **env = strv_new("A=1", NULL);
_cleanup_strv_free_ char **env;
assert_se(deserialize_environment(&env, "env=B=2") >= 0);
assert_se(deserialize_environment(&env, "env=FOO%%=a\\177b\\nc\\td e") >= 0);
assert_se(env = strv_new("A=1", NULL));
assert_se(deserialize_environment("B=2", &env) >= 0);
assert_se(deserialize_environment("FOO%%=a\\177b\\nc\\td e", &env) >= 0);
assert_se(strv_equal(env, STRV_MAKE("A=1", "B=2", "FOO%%=a\177b\nc\td e")));
assert_se(deserialize_environment(&env, "env=foo\\") < 0);
assert_se(deserialize_environment(&env, "env=bar\\_baz") < 0);
assert_se(deserialize_environment("foo\\", &env) < 0);
assert_se(deserialize_environment("bar\\_baz", &env) < 0);
}
static void test_serialize_environment(void) {
_cleanup_strv_free_ char **env = NULL, **env2 = NULL;
char fn[] = "/tmp/test-env-util.XXXXXXX";
int fd, r;
_cleanup_fclose_ FILE *f = NULL;
int fd, r;
_cleanup_strv_free_ char **env = strv_new("A=1",
"B=2",
"C=ąęółń",
"D=D=a\\x0Ab",
"FOO%%=a\177b\nc\td e",
NULL);
_cleanup_strv_free_ char **env2 = NULL;
assert_se(env = strv_new("A=1",
"B=2",
"C=ąęółń",
"D=D=a\\x0Ab",
"FOO%%=a\177b\nc\td e",
NULL));
fd = mkostemp_safe(fn);
assert_se(fd >= 0);
assert_se(f = fdopen(fd, "r+"));
assert_se(serialize_environment(f, env) == 0);
assert_se(serialize_strv(f, "env", env) > 0);
assert_se(fflush_and_check(f) == 0);
rewind(f);
for (;;) {
char line[LINE_MAX];
_cleanup_free_ char *line = NULL;
const char *l;
if (!fgets(line, sizeof line, f))
r = read_line(f, LONG_LINE_MAX, &line);
assert_se(r >= 0);
if (r == 0)
break;
char_array_0(line);
l = strstrip(line);
r = deserialize_environment(&env2, l);
assert_se(r == 1);
assert_se(startswith(l, "env="));
r = deserialize_environment(l+4, &env2);
assert_se(r >= 0);
}
assert_se(feof(f));
+10 -9
View File
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "random-util.h"
#include "serialize.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@@ -340,40 +341,40 @@ static void test_format_timestamp_utc(void) {
test_format_timestamp_utc_one(USEC_INFINITY, NULL);
}
static void test_dual_timestamp_deserialize(void) {
static void test_deserialize_dual_timestamp(void) {
int r;
dual_timestamp t;
log_info("/* %s */", __func__);
r = dual_timestamp_deserialize("1234 5678", &t);
r = deserialize_dual_timestamp("1234 5678", &t);
assert_se(r == 0);
assert_se(t.realtime == 1234);
assert_se(t.monotonic == 5678);
r = dual_timestamp_deserialize("1234x 5678", &t);
r = deserialize_dual_timestamp("1234x 5678", &t);
assert_se(r == -EINVAL);
r = dual_timestamp_deserialize("1234 5678y", &t);
r = deserialize_dual_timestamp("1234 5678y", &t);
assert_se(r == -EINVAL);
r = dual_timestamp_deserialize("-1234 5678", &t);
r = deserialize_dual_timestamp("-1234 5678", &t);
assert_se(r == -EINVAL);
r = dual_timestamp_deserialize("1234 -5678", &t);
r = deserialize_dual_timestamp("1234 -5678", &t);
assert_se(r == -EINVAL);
/* Check that output wasn't modified. */
assert_se(t.realtime == 1234);
assert_se(t.monotonic == 5678);
r = dual_timestamp_deserialize("+123 567", &t);
r = deserialize_dual_timestamp("+123 567", &t);
assert_se(r == 0);
assert_se(t.realtime == 123);
assert_se(t.monotonic == 567);
/* Check that we get "infinity" on overflow. */
r = dual_timestamp_deserialize("18446744073709551617 0", &t);
r = deserialize_dual_timestamp("18446744073709551617 0", &t);
assert_se(r == 0);
assert_se(t.realtime == USEC_INFINITY);
assert_se(t.monotonic == 0);
@@ -461,7 +462,7 @@ int main(int argc, char *argv[]) {
test_usec_sub_unsigned();
test_format_timestamp();
test_format_timestamp_utc();
test_dual_timestamp_deserialize();
test_deserialize_dual_timestamp();
test_usec_shift_clock();
test_in_utc_timezone();