Note that there are some explanatory texts on larger screens.

plurals
  1. POSegfault in libCurl in process that was forked in signal handler
    primarykey
    data
    text
    <p>I'm trying to get native crash reporting on android to work. I use breakpad to create a dump file, and upload it using curl (in a very similar way the minidump_upload tool that comes with breakpad does).</p> <p>For testing i provoke a segfault by trying to write to a dereferenced NULL pointer.</p> <p>In my dump callback function, that is called from breakpad's signal handler after the minidump was created successfully, I fork() and run my uploading code.</p> <p>Setting up libCurl works fine, but it then crashes inside curl_easy_perform with the following backtrace (filenames truncated for readability and frames above 10 removed).</p> <pre><code>Program received signal SIGSEGV, Segmentation fault. 0x7356d700 in dprintf_formatf (data=0x7393ba34, stream=0x65, format=0x739458a4 "l&gt;\016", ap_save=...) at .../lib/mprintf.c:518 518 { (gdb) bt #0 0x7356d700 in dprintf_formatf (data=0x7393ba34, stream=0x65, format=0x739458a4 "l&gt;\016", ap_save=...) at .../lib/mprintf.c:518 #1 0x7356e5fe in curl_mvsnprintf (buffer=0x73860540 "\b\025\206sa", maxlength=4096, format=0x737a1528 "%s; boundary=%s\r\n", ap_save=...) at .../lib/mprintf.c:932 #2 0x7355d092 in AddFormDataf (formp=0x73861780, size=0x0, fmt=0x737a1528 "%s; boundary=%s\r\n") at .../lib/formdata.c:918 #3 0x7355d606 in Curl_getformdata (data=0x75527970, finalform=0x75511ec0, post=0x75482af0, custom_content_type=0x0, sizep=0x75511ec8) at .../lib/formdata.c:1172 #4 0x73561dfc in Curl_http (conn=0x755300a0, done=0x73861928) at .../lib/http.c:1969 #5 0x7356badc in Curl_do (connp=0x75527978, done=0x73861928) at .../lib/url.c:5897 #6 0x735771f0 in multi_runsingle (multi=0x7551dfa0, now=..., data=0x75527970) at .../lib/multi.c:1218 #7 0x73577aac in curl_multi_perform (multi_handle=0x7551dfa0, running_handles=0x738619cc) at .../lib/multi.c:1714 #8 0x73571fa4 in easy_transfer (multi=0x7551dfa0) at .../lib/easy.c:759 #9 0x7357209a in easy_perform (data=0x75527970, events=false) at .../lib/easy.c:838 #10 0x735720c4 in curl_easy_perform (easy=0x75527970) at .../lib/easy.c:857 </code></pre> <p>Let's analyze what we got here, it starts to get interesting at frame 3. Here AddFormDataf is called with</p> <ul> <li>a pointer to a NULL-pointer for the form (expected, the form is still empty)</li> <li>NULL for the size pointer</li> <li>a valid format string "%s; boundary=%s\r\n"</li> <li>and two string arguments into the variadic part: "Content-Type: multipart/form-data" and "------------------------a7584d0e40b10c4a"</li> </ul> <p>In frame 2, everything is still fine, the va_list is constructed (it should point to the first of the two strings, but i have no clue how to debug that in gdb), and control is handed over to vsnprintf, which curl internally defines as curl_mvsnprintf.</p> <p>In frame 1, all the parameters still look good, the 4k Buffer has random data in it, but that should be ok, it will be overwritten, the maxlength of 4096 is correct, the format string still has our format. the nsprintf struct is created, and control is handed over to dprintf_formatf - let's print all the parameters that are passed to dprintf_formatf:</p> <pre><code>(gdb) print info $6 = {buffer = 0x73860540 "\b\025\206sa", length = 0, max = 4096} (gdb) print &amp;info $7 = (struct nsprintf *) 0x73860510 (gdb) print addbyter $8 = {int (int, FILE *)} 0x7356e580 &lt;addbyter&gt; (gdb) print format $9 = 0x737a1528 "%s; boundary=%s\r\n" (gdb) print ap_save $10 = {__ap = 0x73861554} </code></pre> <p>As you can see, the info struct is populated correctly, nothing to say about the function pointer to the addbyter function, and the va_args ap_save, but at least the format string is still ok.</p> <p>Now, when we look at frame 0 everything got corrupted:</p> <pre><code>#0 0x7356d700 in dprintf_formatf (data=0x7393ba34, stream=0x65, format=0x739458a4 "l&gt;\016", ap_save=...) at .../curl/./lib/mprintf.c:518 (gdb) print ap_save $11 = {__ap = 0x739fae60} </code></pre> <p>The info pointer changed from 0x73860510 to 0x7393ba34, the function pointer from 0x7356e580 to 0x65, the format string from 0x737a1528 to 0x739458a4 and the __ap inside the va_list from 0x73861554 to 0x739fae60.</p> <p>These (invalid) pointers seem to stay constant on every run of the program - i get exactly the same addresses for data, stream and format, and even the same contents of format ("l>\016") whenever i run the program.</p> <p>I have a few questions:</p> <ul> <li>when i fork(), the parent's memory is copied to the new child process, but after the fork the parent cannot modify the client's memory, right? I'm asking because my parent process is multi-threaded (yeah, i know, multi-threading and fork, not a good idea, but i'm only doing that when I'm already crashing anyway...)</li> <li>how can it happen that all the arguments to a function are lost and replaced by something invalid? I think the only answer here is that something corrupted the stack, right?</li> <li>what could possibly corrupt my stack in the child process (which should be a completely healthy process that just owns a lot of potentially damaged memory from the parent)?</li> <li>May i have done something wrong in compiling libCurl? (the whole upload works fine when invoked from anywhere (including forked child processes) <em>except</em> in this one case when the child process is created in the signal handler)</li> <li>Where are those invalid pointers pointing to, why do i always see the same string in format? I assume I'm seeing program code here?</li> </ul> <p>Thanks in advance for your help, I'm really out of ideas how to fix this :)</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload