|
|
Subscribe / Log in / New account

Checking the name

Checking the name

Posted Jun 19, 2022 21:45 UTC (Sun) by corbet (editor, #1)
In reply to: A new LLVM CFI implementation by mss
Parent article: A new LLVM CFI implementation

I don't quite understand what you are asking for here. The name of the called function isn't known at compile time, that's why it's an indirect call. So what name would you check against?


to post comments

Checking the name

Posted Jun 19, 2022 21:58 UTC (Sun) by mss (subscriber, #138799) [Link] (5 responses)

> The name of the called function isn't known at compile time, that's why it's an indirect call

I think that the set of functions implementing particular callback in the kernel should be known at compile time, either via manual annotations (as willy has suggested above) or maybe even automatically by a sufficiently smart compiler.

This probably would be incompatible with out-of-tree kernel modules, however.

Checking the name

Posted Jun 19, 2022 22:40 UTC (Sun) by NYKevin (subscriber, #129325) [Link] (3 responses)

You can do that now. Just declare your functions as taking an extra (unused) argument of type struct { char[0]; char[0]; ...} with a different number of empty arrays for each possible callback. They have zero size and even at O0, no code should be emitted for them, but they still change the signature of the function and (should!) therefore change the C++ name mangling. The problem is, you also need to actually pass an argument, and unlike C++, C doesn't let you get away with just writing "{}" for that, so you probably need some sort of macro. It's a shame the standard doesn't let you write something like "void" for a zero-size argument.

Checking the name

Posted Jun 20, 2022 13:51 UTC (Mon) by khim (subscriber, #9252) [Link] (2 responses)

> It's a shame the standard doesn't let you write something like "void" for a zero-size argument.

Well… zero-sized arguments don't exist in standard C, they are GNU extension which means you can try to supply the patch which will support what you want to Clang and GCC.

Once you left the standard it's kind of hard to expect to see such non-standard constructs supported in said standard, don't you think?

Checking the name

Posted Jun 20, 2022 17:39 UTC (Mon) by nybble41 (subscriber, #55106) [Link] (1 responses)

I think the point was that the standard should have allowed zero-sized (void type) arguments, variables, and fields from the beginning, for symmetry with expressions and function return types, so it wouldn't require a GNU extension. Likewise for empty structures and unions & zero-length arrays (including array variables, not just fields).

A keyword for the void constructor might be nice, but "(void)0" would serve well enough. This could be made into a standard VOID macro, like NULL for "(void*)0".

Checking the name

Posted Jun 20, 2022 20:56 UTC (Mon) by wahern (subscriber, #37304) [Link]

The standard does have empty struct members using 0-length bit fields which have been in the standard from the beginning.[1] They're not quite empty as they're intended to serve as markers instructing the compiler to shift subsequent bit fields to a new word. 0-length arrays actually work similarly--fundamentally they're a mechanism for controlling alignment and can also introduce padding where there wouldn't have been any in their absence. (In practice, though, they can only introduce tail padding--at the tail end of a preceding bit field, if any, for the former, or tail end of the struct for the latter.) Empty bit fields seem a little more useful, though, as aside from being standard they can be (must be since C11) unnamed: `struct { int a:3; int:0; int b:1; };` is a valid definition. You can use them along with the GNU empty struct extension to get an empty type without any names: both `sizeof (struct { int:0; })` and `sizeof (struct { int:0; int:0; })` are valid and evaluate to 0 (tested clang 3.8 and GCC 9.4).

Also, at least based on a straight-forwarding reading of the standard, sequentially declared 0-length bit fields should collapse (i.e. not unspecified or undefined behavior), so that they introduce only one word of padding at most, if any; and this is indeed the behavior I see from clang and GCC. And while maybe more susceptible to disagreement, the language of the standard does seem to specify that a 0-length bit field not succeeding another bit field should not introduce any padding. I see the same behaviors for 0-length arrays, but the GCC documentation seemed much more ambiguous on both points.[2]

I am curious why I haven't seen void (the true "nothing") type semantics extended elsewhere in the grammar. Maybe 0-length bit and array fields were sufficient, if not ideal, for the most pressing scenarios. But perhaps the language (inclusive of extensions) is finally moving in a direction where the old hacks are insufficient, and void might see some more attention.

[1] See $ 3.5.2.1 at http://port70.net/~nsz/c/c89/c89-draft.txt

[2] Putting it all together after having double checked my assertions with the standard, it does seem that the only use for 0-length arrays has been almost entirely subsumed by flexible array members, except that the former make indexing notation easier (no offsetof verbiage). For anything else (mostly in relation to extensions, like 0-length structures), 0-length bit field notation seems sufficient. Maybe the situation is different with C++.

Checking the name

Posted Jun 19, 2022 23:29 UTC (Sun) by corbet (editor, #1) [Link]

That is essentially what the existing implementation does - that's what the jump tables contain. It requires link-time optimization to work, though, and I'm not sure what it buys over verification of the prototype.

Checking the name

Posted Jun 20, 2022 2:38 UTC (Mon) by comex (subscriber, #71521) [Link]

Maybe they are thinking of the function pointers in C++ vtables, where you know not just the expected signature, but the name of the virtual method that is being overridden. If you include that in the hash, you can prevent the attacker from replacing it with an unrelated function or method that happens to have the same signature.

Of course, that doesn't apply to C. But it may be possible to get a similar effect with manual annotations of some sort...


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds