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