chiark / gitweb /
journal-remote: reject fields above maximum size
[elogind.git] / src / journal-remote / journal-remote-parse.c
index dbdf02aa3c6ba5d8b6ad67858dedb8a4fbc0f6a7..fe21bd3e1d91baca4a9294076e3617e065f8bfb9 100644 (file)
@@ -49,43 +49,43 @@ static int get_line(RemoteSource *source, char **line, size_t *size) {
         assert(source->filled <= source->size);
         assert(source->buf == NULL || source->size > 0);
 
-        if (source->buf)
-                c = memchr(source->buf, '\n', source->filled);
-
-        if (c != NULL)
-                goto docopy;
-
- resize:
-        if (source->fd < 0)
-                /* we have to wait for some data to come to us */
-                return -EWOULDBLOCK;
+        while (true) {
+                if (source->buf)
+                        c = memchr(source->buf + source->scanned, '\n',
+                                   source->filled - source->scanned);
+                if (c != NULL)
+                        break;
+
+                source->scanned = source->filled;
+                if (source->scanned >= DATA_SIZE_MAX) {
+                        log_error("Entry is bigger than %u bytes.", DATA_SIZE_MAX);
+                        return -E2BIG;
+                }
 
-        if (source->size - source->filled < LINE_CHUNK) {
-                // XXX: add check for maximum line length
+                if (source->fd < 0)
+                        /* we have to wait for some data to come to us */
+                        return -EWOULDBLOCK;
 
-                if (!GREEDY_REALLOC(source->buf, source->size,
-                                    source->filled + LINE_CHUNK))
-                        return log_oom();
-        }
-        assert(source->size - source->filled >= LINE_CHUNK);
+                if (source->size - source->filled < LINE_CHUNK &&
+                    !GREEDY_REALLOC(source->buf, source->size,
+                                    MAX(source->filled + LINE_CHUNK, DATA_SIZE_MAX)))
+                                return log_oom();
 
-        n = read(source->fd, source->buf + source->filled,
-                 source->size - source->filled);
-        if (n < 0) {
-                if (errno != EAGAIN && errno != EWOULDBLOCK)
-                        log_error("read(%d, ..., %zd): %m", source->fd,
-                                  source->size - source->filled);
-                return -errno;
-        } else if (n == 0)
-                return 0;
+                assert(source->size - source->filled >= LINE_CHUNK);
 
-        c = memchr(source->buf + source->filled, '\n', n);
-        source->filled += n;
+                n = read(source->fd, source->buf + source->filled,
+                         MAX(source->size, DATA_SIZE_MAX) - source->filled);
+                if (n < 0) {
+                        if (errno != EAGAIN && errno != EWOULDBLOCK)
+                                log_error("read(%d, ..., %zd): %m", source->fd,
+                                          source->size - source->filled);
+                        return -errno;
+                } else if (n == 0)
+                        return 0;
 
-        if (c == NULL)
-                goto resize;
+                source->filled += n;
+        }
 
- docopy:
         *line = source->buf;
         *size = c + 1 - source->buf;
 
@@ -102,6 +102,7 @@ static int get_line(RemoteSource *source, char **line, size_t *size) {
         source->buf = newbuf;
         source->size = newsize;
         source->filled = remain;
+        source->scanned = 0;
 
         return 1;
 }
@@ -111,8 +112,12 @@ int push_data(RemoteSource *source, const char *data, size_t size) {
         assert(source->state != STATE_EOF);
 
         if (!GREEDY_REALLOC(source->buf, source->size,
-                            source->filled + size))
-                return log_oom();
+                            source->filled + size)) {
+                log_error("Failed to store received data of size %zu "
+                          "(in addition to existing %zu bytes with %zu filled): %s",
+                          size, source->size, source->filled, strerror(ENOMEM));
+                return -ENOMEM;
+        }
 
         memcpy(source->buf + source->filled, data, size);
         source->filled += size;
@@ -131,6 +136,7 @@ static int fill_fixed_size(RemoteSource *source, void **data, size_t size) {
                source->state == STATE_DATA_FINISH);
         assert(size <= DATA_SIZE_MAX);
         assert(source->filled <= source->size);
+        assert(source->scanned <= source->filled);
         assert(source->buf != NULL || source->size == 0);
         assert(source->buf == NULL || source->size > 0);
         assert(data);
@@ -171,6 +177,7 @@ static int fill_fixed_size(RemoteSource *source, void **data, size_t size) {
         source->buf = newbuf;
         source->size = newsize;
         source->filled = remain;
+        source->scanned = 0;
 
         return 1;
 }