[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [libmicrohttpd] [PATCH] MHD_add_response_header: Check on passed nul

From: Alexander Dahl
Subject: Re: [libmicrohttpd] [PATCH] MHD_add_response_header: Check on passed nullptr
Date: Fri, 28 Jan 2022 11:08:00 +0100

Hello Evgeny,

thanks for your detailed answer.  I read that basically as "I can not assume 
libmicrohttpd checks user input" in general, but I have some remarks below.

Am Freitag, 28. Januar 2022, 10:31:26 CET schrieb Evgeny Grin:
> Hello Alexander,
> On 27.01.2022 21:12, Alexander Dahl wrote:
> >> However this is not a such case. MHD never have guaranteed tolerating of
> >> NULL in this function. The data must be a valid C string. The NULL
> >> pointer
> >> is definitely not a valid C string.
> > 
> > 
> > Well, I could not tell based on the API documentation, what's intended
> > behaviour here.
> Pointer to char is always C sting in C, unless another type is 
> explicitly documented (like pointer to a single char).
> NULL is not a valid C string.

While that's certainly true, I did not talk about 'char *' or 'const char *' 
but about 'struct MHD_Response *response' which is a different type.  Maybe 
the same argumentation applies, though.

> Even if something is unclear from documentation, it is called "undefined 
> behaviour". Undefined behaviour should be avoided as it may work on one 
> platform or version and may not work on another platform or version.
> >> MHD would (silently) ignore bad parameters with your patch. This may
> >> mask
> >> some bug in code that use MHD_add_response_header() function so while
> >> this
> >> patch may look useful for production code, actually it makes situation
> >> even
 worse as it may give false feeling of correct functioning instead
> >> of revealing bug as soon as possible.
> > 
> > 
> > Well, my patch just restores the behaviour of libmicrohttpd from
> > before 185f740e0684, where MHD_add_response_header() returned what
> > add_response_entry() returns.  That function add_response_entry()
> > checks for (response == NULL) and silently returns MHD_NO in that
> > case.
> > 
> > Intended or not, changeset 185f740e0684 broke that behaviour, and it
> > did not mention in commit message nor in code itself.
> If behaviour is undefined, it cannot be broken.
> You should not expect that NULL will be processed as a valid C string. 

I did not expect that.

> On the other hand, it was not guaranteed that MHD would segfault on NULL.

Nor was guaranteed MHD would check parameters.  But it actually did check 
before 185f740e0684 and crashed after.  ¯\_(ツ)_/¯

> >> Hypothetical situation:
> >> ===============================
> >> MHD_add_response_header (r, "System-Command", "sudo rm -rf /
> >> --no-preserve-root");
> >> char *behaviour = strdup ("no-execute, check-syntax-only");
> >> MHD_add_response_header (r, "Modify-Behavior", behaviour);
> >> free (behaviour);
> >> MHD_queue_response (c, MHD_HTTP_OK, r);
> >> ==============================
> >> Very typical mistake: no checks for returned values. The code may work
> >> fine,
 but at some moment, due to some leak in another place, strdup()
> >> fail. With your patch second header would not be added, but response
> >> would be sent. I think it's better to crash earlier in such situation
> >> than trying to fix automatically wrong parameters.
> > 
> > 
> > You're absolutely right. Users of your library must check return
> > values, no doubt about that.
> Also users of the library should provide correct data.


> >>  From the description of the issue in your library, it's clear than you
> >>  was
> >> 
> >> able to find another error (return 200 instead of 404) with wrong
> >> filename
> >> only when MHD stopped tolerating NULL. If MHD would not tolerate NULL
> >> initially (which was not intentional behaviour), you would be able to
> >> find
> >> and fix this bug earlier.
> > 
> > 
> > It's not my library, I'm just a user.  And I'm sorry, I'm confused
> > now.  What is the intentional behaviour of libmicrohttpd?
> Intentional behaviour is correct processing of correct data. So tricky 
> and/or complicated combination of strings are detected on run-time, but 
> fundamental types expected to be correct, like strings are 
> zero-terminated and in valid readable memory area.
> > I mean, libmicrohttpd detecting NULL and returning MHD_NO tells me
> > something went wrong at runtime, if I check for return value, which I
> > should do.
> Yes, you should check the return value as well as you should provide 
> valid C strings.

I actually provided valid C strings for both 'header' and 'content'.  It was 
'struct MHD_Response *response' which was NULL.

> When application pass NULL as a C string, it's clear indication that 
> something goes terribly wrong in the application, right?
> The best thing that you can do in such situation is to abort the broken 
> application, before it overwrites some valid data with some invalid data 
> or does other horrible unexpected things.
> > Checking for return value is pointless, however, if libmicrohttpd
> > crashes before returning anything.
> That's correct. But if application supplies such obvious invalid input, 
> there is a high chance that return value is not checked as well, just 
> because most probably the invalid input was the return value from 
> another function that was not checked before.
> Crash/segfault is your friend when something is badly broken. Masking 
> obvious problems does not help debugging and testing and makes things 
> worse in production.

I think this tends to be a question of design philosophy.  Some developers 
expect libraries to never segfault.

> On the other hand "libmicrohttpd" is still "micro". The library core 
> without optional parts still could be very small. So library expects 
> that parameters have valid types. Otherwise we should bloat up the code 
> with checks for every single parameter validity, including readability 
> of pointed memory region.

Well, then you could drop some checks from 'add_response_entry()' in source 
file "src/microhttpd/response.c", right?  Especially the first three of them?

    static enum MHD_Result
    add_response_entry (struct MHD_Response *response,
                        enum MHD_ValueKind kind,
                        const char *header,
                        const char *content)
      struct MHD_HTTP_Header *hdr;
      if ( (NULL == response) ||
           (NULL == header) ||
           (NULL == content) ||


Don't take all this as pro argumentation for my patch.  I'm perfectly fine 
with dropping it, if it does not comply with the design philosophy of 


reply via email to

[Prev in Thread] Current Thread [Next in Thread]