fosstodon.org is one of the many independent Mastodon servers you can use to participate in the fediverse.
Fosstodon is an invite only Mastodon instance that is open to those who are interested in technology; particularly free & open source software. If you wish to join, contact us for an invite.

Administered by:

Server stats:

10K
active users

Kees Cook :tux:

I decided to actually go see how hard adding __builtin_is_lvalue() to Clang would be, and it only took an evening. With that available we can set the variables passed to kfree() to NULL automatically. This should kill a subset of "dangling pointer" Use-After-Free flaws with basically no overhead and almost no refactoring in the kernel.

lore.kernel.org/linux-hardenin

lore.kernel.org[RFC 0/5] slab: Set freed variables to NULL by default - Kees Cook

@kees but what if the calling code wants to use the pointer value they just freed for something else? Maybe they use it as a key in some other structure and they now need to go remove that entry. By setting their passed lvalue to null won’t you break their code? Obviously an edge case, but just pointing out this trick isn’t universally safe. Obviously very useful most of the time however.

@pauldoo @kees yeah that was my thought as well. Shouldn't the compiler or static checkers be able to do more here? Check that it's unused after kfree() or not dereferenced after kfree() etc.

Also after the Linus reply on kmalloc_obj() seems he's very much against hidden side effects so maybe should have been cc'd here too :/

@vbabka @pauldoo That's a fair point -- it's another hidden assignment...

Perhaps make kfree() return NULL and mark it __must_check, and tree wide replacement:

ptr = kfree(ptr);

? Leave __kfree as void?

It's much more painful though, since there are so so many non-lvalue kfree uses.

@kees @vbabka @pauldoo you could do a treewide replacement of kfree() with something called KFREE() or such, and then at least the uppercasing will hint to everyone that this is a macro doing magic macro things?

@pauldoo @kees i dunno if kfree() is declared in a way that makes a compiler think it’s equivalent to standard free(), but standard C says the value of a pointer becomes indeterminate after the memory it points to is freed. yes this is weird, how can free() have side effects on its arguments?! but what worries me is if the compiler marks the variable dead when it is passed to free() so if it is used after that point the compiler could treat it as uninitialized

@fanf @pauldoo Is there anything in GCC or Clang that does this? I didn't find a function attribute that would have that effect. It'd be a nice diagnostic. The "malloc" attribute has a "deallocator" argument, but it doesn't seem to imply variable uninitialized-ness. :(

@kees @pauldoo i don’t think any compilers currently do so, but there is some very risky stuff going on around realloc and allocation size tracking, so i expect future compiler releases to do more and more exciting things with undefined behaviour and (de)allocation functions … it worries me, so i wanted to warn against using pointers after free() - and it’s another reason that it’s a good idea to nullify them

@fanf @kees @pauldoo for extra irony, I try to be sure and nullify pointers for more or less these reasons, and what I've learned is that cov-scan hates it.

Because it's a dead store if you get it right, and it flags it as a maintenance issue. fml.

@kees @fanf @pauldoo @pinskia GCC tracks liveness with the malloc attribute, it doesn't do any magic based on free-like functions other than diagnostics AFAIK if the deallocator argument is also passed. But if you're not giving the deallocator argument, I don't think you'd have anything to worry about there even in terms of futureproofing.

Also, kfree isn't a reserved name, so we can't make that assumption.

@thesamesam @kees @fanf @pauldoo @pinskia there's a tangentially related case where programs would assume that if realloc returned the same pointer value, they could continue using the old pointer variable without refreshing it (thus violating the invalidated pointer limitation in the standard), which stumbled on _FORTIFY_SOURCE because the compiler couldn't see the new size.

I would say it's safest to always assume that a freed pointer is unusable the moment it is freed.

@thesamesam @kees @fanf @pauldoo @pinskia to Kees' question, the compiler does have some diagnostics (use-after-free and some analyzer heuristics IIRC) that use the deallocator pairing to emit warnings, but it doesn't flag the freed pointers as "uninitialised".