core: when deserializing state always use read_line(…, LONG_LINE_MAX, …)

This should be much better than fgets(), as we can read substantially
longer lines and overly long lines result in proper errors.

Fixes a vulnerability discovered by Jann Horn at Google.

CVE-2018-15686
LP: #1796402
https://bugzilla.redhat.com/show_bug.cgi?id=1639071
This commit is contained in:
Lennart Poettering
2018-10-26 10:40:01 +02:00
parent 84ac98faa8
commit 8948b3415d
4 changed files with 50 additions and 46 deletions
+11 -8
View File
@@ -10,6 +10,7 @@
#include "dbus-job.h"
#include "dbus.h"
#include "escape.h"
#include "fileio.h"
#include "job.h"
#include "log.h"
#include "macro.h"
@@ -1094,24 +1095,26 @@ int job_serialize(Job *j, FILE *f) {
}
int job_deserialize(Job *j, FILE *f) {
int r;
assert(j);
assert(f);
for (;;) {
char line[LINE_MAX], *l, *v;
_cleanup_free_ char *line = NULL;
char *l, *v;
size_t k;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
return 0;
return -errno;
}
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read serialization line: %m");
if (r == 0)
return 0;
char_array_0(line);
l = strstrip(line);
/* End marker */
if (l[0] == 0)
if (isempty(l))
return 0;
k = strcspn(l, "=");
+20 -21
View File
@@ -3222,20 +3222,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
_cleanup_(manager_reloading_stopp) _unused_ Manager *reloading = manager_reloading_start(m);
for (;;) {
char line[LINE_MAX];
_cleanup_free_ char *line = NULL;
const char *val, *l;
errno = 0;
if (!fgets(line, sizeof(line), f)) {
if (!feof(f))
return -errno ?: -EIO;
return 0;
}
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read serialization line: %m");
if (r == 0)
break;
char_array_0(line);
l = strstrip(line);
if (l[0] == 0)
if (isempty(l)) /* end marker */
break;
if ((val = startswith(l, "current-job-id="))) {
@@ -3405,20 +3402,18 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
}
for (;;) {
Unit *u;
char name[UNIT_NAME_MAX+2];
_cleanup_free_ char *line = NULL;
const char* unit_name;
Unit *u;
/* Start marker */
errno = 0;
if (!fgets(name, sizeof(name), f)) {
if (!feof(f))
return -errno ?: -EIO;
return 0;
}
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read serialization line: %m");
if (r == 0)
break;
char_array_0(name);
unit_name = strstrip(name);
unit_name = strstrip(line);
r = manager_load_unit(m, unit_name, NULL, NULL, &u);
if (r < 0) {
@@ -3426,7 +3421,11 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
return r;
log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", unit_name);
unit_deserialize_skip(f);
r = unit_deserialize_skip(f);
if (r < 0)
return r;
continue;
}
+18 -16
View File
@@ -3400,21 +3400,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
assert(fds);
for (;;) {
char line[LINE_MAX], *l, *v;
_cleanup_free_ char *line = NULL;
CGroupIPAccountingMetric m;
char *l, *v;
size_t k;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
return 0;
return -errno;
}
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read serialization line: %m");
if (r == 0) /* eof */
break;
char_array_0(line);
l = strstrip(line);
/* End marker */
if (isempty(l))
if (isempty(l)) /* End marker */
break;
k = strcspn(l, "=");
@@ -3714,23 +3712,27 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
return 0;
}
void unit_deserialize_skip(FILE *f) {
int unit_deserialize_skip(FILE *f) {
int r;
assert(f);
/* Skip serialized data for this unit. We don't know what it is. */
for (;;) {
char line[LINE_MAX], *l;
_cleanup_free_ char *line = NULL;
char *l;
if (!fgets(line, sizeof line, f))
return;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read serialization line: %m");
if (r == 0)
return 0;
char_array_0(line);
l = strstrip(line);
/* End marker */
if (isempty(l))
return;
return 1;
}
}
+1 -1
View File
@@ -682,7 +682,7 @@ bool unit_can_serialize(Unit *u) _pure_;
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
void unit_deserialize_skip(FILE *f);
int unit_deserialize_skip(FILE *f);
int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);