]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
coredump,analyze: use read_full_file() for reading various top-level /proc/ files
authorLennart Poettering <lennart@poettering.net>
Thu, 13 Mar 2025 08:30:23 +0000 (09:30 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 13 Mar 2025 13:18:46 +0000 (14:18 +0100)
Kernel API file systems typically use either "raw" or "seq_file" to
implement their various interface files. The former are really simple
(to point I'd call them broken), in that they have no understanding of
file offsets, and return their contents again and again on every read(),
and thus EOF is indicated by a short read, not by a zero read. The
latter otoh works like a typical file: you read until you get a
zero-sized read back.

We have read_virtual_file() to read the "raw" files, and can use regular
read_full_file() to read the "seq_file" ones.

Apparently all files in the top-level /proc/ directory use 'seq_file'.
but we accidentally used read_virtual_file() for them. Fix that.

Also clarify in a comment what the rules are.

Fixes: #36131
src/analyze/analyze-filesystems.c
src/basic/fileio.c
src/basic/proc-cmdline.c
src/coredump/coredump.c

index 582e04eac9132866368b806df11ca05bbbd5041c..b09cd9fa0ee87ee4fa547b3b6a9a5f8fdfd07715 100644 (file)
@@ -17,7 +17,7 @@ static int load_available_kernel_filesystems(Set **ret) {
 
         /* Let's read the available filesystems */
 
-        r = read_virtual_file("/proc/filesystems", SIZE_MAX, &t, NULL);
+        r = read_full_file("/proc/filesystems", &t, /* ret_size= */ NULL);
         if (r < 0)
                 return r;
 
index 25b4c352355280e1b5558147c1fac0b96bb8d3cb..b3fdc05c127c45df93c99c619cae377192206eed 100644 (file)
@@ -491,7 +491,11 @@ int read_virtual_file_at(
          * max_size specifies a limit on the bytes read. If max_size is SIZE_MAX, the full file is read. If
          * the full file is too large to read, an error is returned. For other values of max_size, *partial
          * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on
-         * partial success, 1 if untruncated contents were read. */
+         * partial success, 1 if untruncated contents were read.
+         *
+         * Rule: for kernfs files using "seq_file" → use regular read_full_file_at()
+         *       for kernfs files using "raw" → use read_virtual_file_at()
+         */
 
         assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
         assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX);
index 93d2d0e2026347216e1ad2d654a9725badd7ec17..7f8e32f679520f7bff852ece6971f10cfa528da3 100644 (file)
@@ -122,7 +122,7 @@ int proc_cmdline(char **ret) {
         if (detect_container() > 0)
                 return pid_get_cmdline(1, SIZE_MAX, 0, ret);
 
-        return read_virtual_file("/proc/cmdline", SIZE_MAX, ret, NULL);
+        return read_full_file("/proc/cmdline", ret, /* ret_size= */  NULL);
 }
 
 static int proc_cmdline_strv_internal(char ***ret, bool filter_pid1_args) {
index 21fb48a9ac79795eae6f5d966d6f76bec9e51c94..03690a0837bf89521932afbbd65a557cf1a23e83 100644 (file)
@@ -1399,28 +1399,28 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context *
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_OPEN_FDS=", t);
 
         p = procfs_file_alloca(pid, "status");
-        if (read_full_virtual_file(p, &t, NULL) >= 0)
+        if (read_full_file(p, &t, /* ret_size= */ NULL) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_STATUS=", t);
 
         p = procfs_file_alloca(pid, "maps");
-        if (read_full_virtual_file(p, &t, NULL) >= 0)
+        if (read_full_file(p, &t, /* ret_size= */ NULL) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MAPS=", t);
 
-        p = procfs_file_alloca(pid, "limits");
-        if (read_full_virtual_file(p, &t, NULL) >= 0)
+        p = procfs_file_alloca(pid, "limits"); /* this uses 'seq_file' in kernel, use read_full_file_at() */
+        if (read_full_file(p, &t, /* ret_size= */ NULL) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t);
 
         p = procfs_file_alloca(pid, "cgroup");
-        if (read_full_virtual_file(p, &t, NULL) >= 0)
+        if (read_full_file(p, &t, /* ret_size= */ NULL) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t);
 
         p = procfs_file_alloca(pid, "mountinfo");
-        if (read_full_virtual_file(p, &t, NULL) >= 0)
+        if (read_full_file(p, &t, /* ret_size= */ NULL) >= 0)
                 (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MOUNTINFO=", t);
 
         /* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
         p = procfs_file_alloca(pid, "auxv");
-        if (read_full_virtual_file(p, &t, &size) >= 0) {
+        if (read_full_file(p, &t, &size) >= 0) {
                 char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
                 if (buf) {
                         /* Add a dummy terminator to make context_parse_iovw() happy. */