]> git.feebdaed.xyz Git - 0xmirror/radare2.git/commitdiff
Fix r_str_scanf parsing bug and dg coredump on linux-x64 ##debug
authorpancake <trufae@gmail.com>
Tue, 2 Dec 2025 23:50:30 +0000 (00:50 +0100)
committerGitHub <noreply@github.com>
Tue, 2 Dec 2025 23:50:30 +0000 (00:50 +0100)
libr/debug/p/native/linux/linux_coredump.c
libr/util/bscanf.c

index 850e182fefe1c7cd8d52f2b7db6075521415e857..53906c9e585a8b28e2e806ac6abb9a0538c17b68 100644 (file)
@@ -1,4 +1,4 @@
-/* radare - LGPL - Copyright 2016-2023 - Oscar Salvador */
+/* radare - LGPL - Copyright 2016-2025 - Oscar Salvador */
 
 #include <r_debug.h>
 #include <r_util.h>
@@ -807,14 +807,16 @@ static proc_per_process_t *get_proc_process_content(RDebug *dbg) {
 
        /* /proc/[pid]/stat */
        /* we only need few fields which are process-wide */
+       /* fields: pid(1) comm(2) state(3) ppid(4) pgrp(5) sid(6) tty(7) tpgid(8) flags(9) ... nice(19) num_threads(20) */
        {
-               if (r_str_scanf (buff, "%d %*s %c %d %d %*d %*d %lu %ld",
+               int res = r_str_scanf (buff, "%d (%*[^)]) %c %d %d %d %*d %*d %d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d",
                        &p->pid, &p->s_name, &p->ppid, &p->pgrp,
                        &p->sid, &p->flag,
-                       &p->nice, &p->num_threads) < 6) {
-                               free (buff);
-                               return NULL;
-                       }
+                       &p->nice, &p->num_threads);
+               if (res < 8) {
+                       free (buff);
+                       return NULL;
+               }
                free (buff);
        }
        if (!p->num_threads || p->num_threads < 1) {
@@ -892,9 +894,6 @@ static void may_clean_all(elf_proc_note_t *elf_proc_note, proc_content_t *proc_d
 
 static elf_shdr_t *get_extra_sectionhdr(elf_hdr_t *elf_hdr, st64 offset, int n_segments) {
        elf_shdr_t *shdr = R_NEW0 (elf_shdr_t);
-       if (!shdr) {
-               return NULL;
-       }
        elf_hdr->e_shoff = offset;
        elf_hdr->e_shentsize = sizeof (elf_shdr_t);
        elf_hdr->e_shnum = 1;
@@ -1269,7 +1268,7 @@ static ut8 *build_note_section(RDebug *dbg, elf_proc_note_t *elf_proc_note, proc
                        write_note_hdr (type, &note_data);
                        memcpy (note_data, note_info[type].name, note_info[type].size_name);
                        note_data += note_info[type].size_name;
-                       memcpy (note_data, elf_proc_note->thread_note->fp_regset, note_info[type].size);
+                       memcpy (note_data, elf_proc_note->thread_note->siginfo, note_info[type].size);
                        note_data += note_info[type].size_roundedup;
 
 #if __arm__ || __arm64
@@ -1483,6 +1482,7 @@ bool linux_generate_corefile (RDebug *dbg, RBuffer *dest) {
        }
        proc_data->per_process = get_proc_process_content (dbg);
        if (!proc_data->per_process) {
+               R_LOG_ERROR ("linux_generate_corefile: get_proc_process_content failed");
                free (elf_proc_note);
                free (proc_data);
                return false;
@@ -1493,18 +1493,21 @@ bool linux_generate_corefile (RDebug *dbg, RBuffer *dest) {
        /* NT_PRPSINFO */
        elf_proc_note->prpsinfo = linux_get_prpsinfo (dbg, proc_data->per_process);
        if (!elf_proc_note->prpsinfo) {
+               R_LOG_ERROR ("linux_generate_corefile: linux_get_prpsinfo failed");
                error = true;
                goto cleanup;
        }
        /* NT_AUXV */
        elf_proc_note->auxv = linux_get_auxv (dbg);
        if (!elf_proc_note->auxv) {
+               R_LOG_ERROR ("linux_generate_corefile: linux_get_auxv failed");
                error = true;
                goto cleanup;
        }
        /* NT_FILE */
        elf_proc_note->maps = linux_get_mapped_files (dbg, proc_data->per_process->coredump_filter);
        if (!elf_proc_note->maps) {
+               R_LOG_ERROR ("linux_generate_corefile: linux_get_mapped_files failed");
                error = true;
                goto cleanup;
        }
@@ -1513,12 +1516,14 @@ bool linux_generate_corefile (RDebug *dbg, RBuffer *dest) {
        init_note_info_structure(dbg, dbg->pid, elf_proc_note->auxv->size);
        note_data = build_note_section (dbg, elf_proc_note, proc_data, &note_section_size);
        if (!note_data) {
+               R_LOG_ERROR ("linux_generate_corefile: build_note_section failed");
                error = true;
                goto cleanup;
        }
 
        elf_hdr = build_elf_hdr (n_segments);
        if (!elf_hdr) {
+               R_LOG_ERROR ("linux_generate_corefile: build_elf_hdr failed");
                error = true;
                goto cleanup;
        }
index 72ae26ef104dd598df8a1a6964da177da22f2c07..040978a56f40b9fce9abac7e5ef4d5fadae8e6d8 100644 (file)
@@ -318,36 +318,41 @@ R_API int r_str_scanf(const char *buffer, const char *format, ...) {
                                        goto beach;
                                }
                                // process scanset and fill the string
-                               /* String conversion requires a width. */
-                               _BSCANF_CHECK_STRING ();
                                /* '[' conversion specifiers DO NOT consume whitespace. */
-                               char_ptr = va_arg (args, char*);
-                               _BSCANF_CHECK_NULL (char_ptr);
-                               *char_ptr = 0; // null byte the first char before failing
-                               if (max_width < 1) {
-                                       R_LOG_DEBUG ("Missing length specifier for string");
-                               } else {
-                                       for (; *buf_ptr && max_width > 0; max_width--) {
-                                               if (!scanset_check (scanset, *buf_ptr)) {
-                                                       break;
-                                               }
-                                               *char_ptr = *buf_ptr;
-                                               char_ptr++;
+                               if (is_suppressed) {
+                                       /* Consume matching characters and ignore them */
+                                       while (*buf_ptr && scanset_check (scanset, *buf_ptr)) {
                                                buf_ptr++;
                                        }
-                                       if (max_width == 0) {
-                                               R_LOG_DEBUG ("Truncated string in scanf");
+                               } else {
+                                       /* String conversion requires a width. */
+                                       _BSCANF_CHECK_STRING ();
+                                       char_ptr = va_arg (args, char*);
+                                       _BSCANF_CHECK_NULL (char_ptr);
+                                       *char_ptr = 0; // null byte the first char before failing
+                                       if (max_width < 1) {
+                                               R_LOG_DEBUG ("Missing length specifier for string");
+                                       } else {
+                                               for (; *buf_ptr && max_width > 0; max_width--) {
+                                                       if (!scanset_check (scanset, *buf_ptr)) {
+                                                               break;
+                                                       }
+                                                       *char_ptr = *buf_ptr;
+                                                       char_ptr++;
+                                                       buf_ptr++;
+                                               }
+                                               if (max_width == 0) {
+                                                       R_LOG_DEBUG ("Truncated string in scanf");
+                                               }
+                                               /* Strings must be null-terminated. */
+                                               *char_ptr = '\0';
+                                               num_args_set++;
                                        }
-                                       /* Strings must be null-terminated. */
-                                       *char_ptr = '\0';
-                                       num_args_set++;
                                }
                                // reset max width value
                                max_width = 0;
-                               if (*fmt_ptr == 0) {
-                                       // end of string not expecting anything after that
-                                       break;
-                               }
+                               // scanset_parse already advanced fmt_ptr past ']', skip the extra fmt_ptr++ at end of loop
+                               continue;
                        } else if ('i' == *fmt_ptr || 'd' == *fmt_ptr) {
                                /* 'i'/'d': match a integer/decimal integer. */
                                _BSCANF_CONSUME_WSPACE ();
@@ -468,5 +473,11 @@ R_API int r_str_scanf(const char *buffer, const char *format, ...) {
 
 beach:
        va_end (args);
+       /* According to scanf family semantics, return EOF (-1) if no conversions were performed
+        * and an input failure occurred (e.g., buffer ended). Otherwise return number of
+        * successfully assigned inputs. */
+       if (num_args_set == 0 && *buf_ptr == '\0') {
+               return EOF;
+       }
        return num_args_set;
 }