]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/libsystemd/sd-journal/sd-journal.c
Merge pull request #22098 from DaanDeMeyer/journal-corrupt-2
[thirdparty/systemd.git] / src / libsystemd / sd-journal / sd-journal.c
index 8b7415f0db47c933824071caee725be3688886af..7a6cc4aca35491925c3860e8142b3ccaa57933f8 100644 (file)
@@ -212,7 +212,7 @@ static Match *match_new(Match *p, MatchType t) {
         return m;
 }
 
-static void match_free(Match *m) {
+static Match *match_free(Match *m) {
         assert(m);
 
         while (m->matches)
@@ -222,18 +222,18 @@ static void match_free(Match *m) {
                 LIST_REMOVE(matches, m->parent->matches, m);
 
         free(m->data);
-        free(m);
+        return mfree(m);
 }
 
-static void match_free_if_empty(Match *m) {
+static Match *match_free_if_empty(Match *m) {
         if (!m || m->matches)
-                return;
+                return m;
 
-        match_free(m);
+        return match_free(m);
 }
 
 _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size) {
-        Match *l3, *l4, *add_here = NULL, *m;
+        Match *l3, *l4, *add_here = NULL, *m = NULL;
         uint64_t hash;
 
         assert_return(j, -EINVAL);
@@ -322,10 +322,11 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size)
         return 0;
 
 fail:
+        match_free(m);
         match_free_if_empty(add_here);
-        match_free_if_empty(j->level2);
-        match_free_if_empty(j->level1);
-        match_free_if_empty(j->level0);
+        j->level2 = match_free_if_empty(j->level2);
+        j->level1 = match_free_if_empty(j->level1);
+        j->level0 = match_free_if_empty(j->level0);
 
         return -ENOMEM;
 }
@@ -610,9 +611,9 @@ static int find_location_for_match(
                 /* FIXME: missing: find by monotonic */
 
                 if (j->current_location.type == LOCATION_HEAD)
-                        return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_DOWN, ret, offset);
+                        return journal_file_next_entry_for_data(f, dp, DIRECTION_DOWN, ret, offset);
                 if (j->current_location.type == LOCATION_TAIL)
-                        return journal_file_next_entry_for_data(f, NULL, 0, dp, DIRECTION_UP, ret, offset);
+                        return journal_file_next_entry_for_data(f, dp, DIRECTION_UP, ret, offset);
                 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
                         return journal_file_move_to_entry_by_seqnum_for_data(f, dp, j->current_location.seqnum, direction, ret, offset);
                 if (j->current_location.monotonic_set) {
@@ -623,7 +624,7 @@ static int find_location_for_match(
                 if (j->current_location.realtime_set)
                         return journal_file_move_to_entry_by_realtime_for_data(f, dp, j->current_location.realtime, direction, ret, offset);
 
-                return journal_file_next_entry_for_data(f, NULL, 0, dp, direction, ret, offset);
+                return journal_file_next_entry_for_data(f, dp, direction, ret, offset);
 
         } else if (m->type == MATCH_OR_TERM) {
                 uint64_t np = 0;
@@ -1334,7 +1335,7 @@ static int add_any_file(
                 goto finish;
         }
 
-        r = journal_file_open(fd, path, O_RDONLY, 0, false, 0, false, NULL, j->mmap, NULL, NULL, &f);
+        r = journal_file_open(fd, path, O_RDONLY, 0, false, 0, false, NULL, j->mmap, NULL, &f);
         if (r < 0) {
                 log_debug_errno(r, "Failed to open journal file %s: %m", path);
                 goto finish;
@@ -1468,7 +1469,7 @@ static int dirname_is_machine_id(const char *fn) {
                 if (!log_namespace_name_valid(e + 1))
                         return false;
 
-                k = strndupa(fn, e - fn);
+                k = strndupa_safe(fn, e - fn);
                 r = sd_id128_from_string(k, &id);
         } else
                 r = sd_id128_from_string(fn, &id);
@@ -1493,7 +1494,7 @@ static int dirname_has_namespace(const char *fn, const char *namespace) {
                 if (!streq(e + 1, namespace))
                         return false;
 
-                k = strndupa(fn, e - fn);
+                k = strndupa_safe(fn, e - fn);
                 return id128_is_valid(k);
         }
 
@@ -1530,7 +1531,7 @@ static bool dirent_is_journal_subdir(const struct dirent *de) {
         if (!e)
                 return id128_is_valid(de->d_name); /* No namespace */
 
-        n = strndupa(de->d_name, e - de->d_name);
+        n = strndupa_safe(de->d_name, e - de->d_name);
         if (!id128_is_valid(n))
                 return false;
 
@@ -1560,14 +1561,11 @@ static int directory_open(sd_journal *j, const char *path, DIR **ret) {
 static int add_directory(sd_journal *j, const char *prefix, const char *dirname);
 
 static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
-        struct dirent *de;
-
         assert(j);
         assert(m);
         assert(d);
 
         FOREACH_DIRENT_ALL(de, d, goto fail) {
-
                 if (dirent_is_journal_file(de))
                         (void) add_file_by_name(j, m->path, de->d_name);
 
@@ -1576,7 +1574,6 @@ static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
         }
 
         return;
-
 fail:
         log_debug_errno(errno, "Failed to enumerate directory %s, ignoring: %m", m->path);
 }
@@ -2297,6 +2294,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
 
         n = journal_file_entry_n_items(o);
         for (i = 0; i < n; i++) {
+                Object *d;
                 uint64_t p, l;
                 le64_t le_hash;
                 size_t t;
@@ -2304,20 +2302,26 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
 
                 p = le64toh(o->entry.items[i].object_offset);
                 le_hash = o->entry.items[i].hash;
-                r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
+                r = journal_file_move_to_object(f, OBJECT_DATA, p, &d);
+                if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
+                        log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", i);
+                        continue;
+                }
                 if (r < 0)
                         return r;
 
-                if (le_hash != o->data.hash)
-                        return -EBADMSG;
+                if (le_hash != d->data.hash) {
+                        log_debug("Entry item %"PRIu64" hash is bad, skipping over it.", i);
+                        continue;
+                }
 
-                l = le64toh(o->object.size) - offsetof(Object, data.payload);
+                l = le64toh(d->object.size) - offsetof(Object, data.payload);
 
-                compression = o->object.flags & OBJECT_COMPRESSION_MASK;
+                compression = d->object.flags & OBJECT_COMPRESSION_MASK;
                 if (compression) {
 #if HAVE_COMPRESSION
                         r = decompress_startswith(compression,
-                                                  o->data.payload, l,
+                                                  d->data.payload, l,
                                                   &f->compress_buffer,
                                                   field, field_length, '=');
                         if (r < 0)
@@ -2328,7 +2332,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
                                 size_t rsize;
 
                                 r = decompress_blob(compression,
-                                                    o->data.payload, l,
+                                                    d->data.payload, l,
                                                     &f->compress_buffer, &rsize,
                                                     j->data_threshold);
                                 if (r < 0)
@@ -2343,23 +2347,19 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
                         return -EPROTONOSUPPORT;
 #endif
                 } else if (l >= field_length+1 &&
-                           memcmp(o->data.payload, field, field_length) == 0 &&
-                           o->data.payload[field_length] == '=') {
+                           memcmp(d->data.payload, field, field_length) == 0 &&
+                           d->data.payload[field_length] == '=') {
 
                         t = (size_t) l;
 
                         if ((uint64_t) t != l)
                                 return -E2BIG;
 
-                        *data = o->data.payload;
+                        *data = d->data.payload;
                         *size = t;
 
                         return 0;
                 }
-
-                r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
-                if (r < 0)
-                        return r;
         }
 
         return -ENOENT;
@@ -2422,10 +2422,8 @@ static int return_data(
 
 _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t *size) {
         JournalFile *f;
-        uint64_t p, n;
-        le64_t le_hash;
-        int r;
         Object *o;
+        int r;
 
         assert_return(j, -EINVAL);
         assert_return(!journal_pid_changed(j), -ECHILD);
@@ -2443,26 +2441,39 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t
         if (r < 0)
                 return r;
 
-        n = journal_file_entry_n_items(o);
-        if (j->current_field >= n)
-                return 0;
+        for (uint64_t n = journal_file_entry_n_items(o); j->current_field < n; j->current_field++) {
+                uint64_t p;
+                le64_t le_hash;
 
-        p = le64toh(o->entry.items[j->current_field].object_offset);
-        le_hash = o->entry.items[j->current_field].hash;
-        r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
-        if (r < 0)
-                return r;
+                p = le64toh(o->entry.items[j->current_field].object_offset);
+                le_hash = o->entry.items[j->current_field].hash;
+                r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
+                if (IN_SET(r, -EADDRNOTAVAIL, -EBADMSG)) {
+                        log_debug_errno(r, "Entry item %"PRIu64" data object is bad, skipping over it: %m", j->current_field);
+                        continue;
+                }
+                if (r < 0)
+                        return r;
 
-        if (le_hash != o->data.hash)
-                return -EBADMSG;
+                if (le_hash != o->data.hash) {
+                        log_debug("Entry item %"PRIu64" hash is bad, skipping over it.", j->current_field);
+                        continue;
+                }
 
-        r = return_data(j, f, o, data, size);
-        if (r < 0)
-                return r;
+                r = return_data(j, f, o, data, size);
+                if (r == -EBADMSG) {
+                        log_debug("Entry item %"PRIu64" data payload is bad, skipping over it.", j->current_field);
+                        continue;
+                }
+                if (r < 0)
+                        return r;
 
-        j->current_field++;
+                j->current_field++;
 
-        return 1;
+                return 1;
+        }
+
+        return 0;
 }
 
 _public_ int sd_journal_enumerate_available_data(sd_journal *j, const void **data, size_t *size) {
@@ -2684,7 +2695,7 @@ _public_ int sd_journal_process(sd_journal *j) {
 
                 l = read(j->inotify_fd, &buffer, sizeof(buffer));
                 if (l < 0) {
-                        if (IN_SET(errno, EAGAIN, EINTR))
+                        if (ERRNO_IS_TRANSIENT(errno))
                                 return got_something ? determine_change(j) : SD_JOURNAL_NOP;
 
                         return -errno;