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:
+28
-19
@@ -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));
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user