[HN Gopher] Control-flow integrity in Linux 5.13
___________________________________________________________________
Control-flow integrity in Linux 5.13
Author : chmaynard
Score : 123 points
Date : 2021-05-27 04:26 UTC (1 days ago)
(HTM) web link (lwn.net)
(TXT) w3m dump (lwn.net)
| yosefk wrote:
| This CFI implementation makes &func be different values in 2
| different loadable kernel modules. C says they should be the same
| value. What do the language lawyers among the compiler writers,
| who explain why the execution of an entire program is rendered
| meaningless by undefined behavior, tell us about this? What is
| the definition of the language compiled with CFI enabled (it's
| not C but some close relative)?
| Joker_vD wrote:
| Could you elaborate the scenario a bit? Two different loadable
| kernel modules would define two different (even if named the
| same) functions "func" so "&func" has to be two different
| pointers... or do you mean that if that "func" was defined in
| the kernel, and both of those modules are linked against the
| kernel dynamically, then "&func" should yield the same value?
| But even now they don't even without CFI: when "func" is
| defined in the dinamically-loaded library, the "&func" value is
| the pointer into the (calling object file's) PLT.
| bcoates wrote:
| Loadable modules aren't part of the C spec. Whatever the
| meaning of &func in 2 different modules potentially compiled by
| 2 different compilers is is specified by the ABI.
|
| CFI is a breaking change to the contract the Linux kernel makes
| with kernel modules, but it doesn't have anything in particular
| to do with C the language.
| derefr wrote:
| > What is the definition of the language compiled with CFI
| enabled (it's not C but some close relative)?
|
| I think I saw mentioned, in the comments of a recent HN post
| about undefined behavior in C, that OS kernels aren't using
| "standard C", as they use a bunch of compiler flags to
| constrain what the compiler does in the face of UB, contrary to
| what the standard says the compiler is allowed to do. As such,
| OS kernels have always kind of been using a "close relative of
| C." (Same syntax, slightly different semantics.)
| KMag wrote:
| I'm not a language lawyer, but I'm pretty sure with x86 and
| x86_64 ELF dynamic symbols, &func is the address of the program
| linkage table (PLT) entry for the dynamic symbol, in the
| current ELF executable/library.
|
| The executable has its own PLT. Each library has its own PLT.
| The executable has its own global offset table (GOT). Each
| library has its own GOT. A given dynamically linked function
| will have one PLT entry and one GOT entry in each library that
| calls it. After the function's actual global entry point has
| been resolved, its address will be in the GOT entry. However,
| symbol resolution can be done lazily, and we don't want taking
| the address of a function to potentially perform the lookup, so
| I think the function address is just the start of the PLT
| entry.
|
| For instance, if the executable and several libraries it loads
| all call printf, they'll each have their own tiny machine code
| stub (PLT entry) that (after dynamic symbol resolution) just
| jumps to the actual printf implementation. The executable will
| use the start of its PLT entry for printf as its address for
| printf. Each library will use the start of its PLT entry for
| printf as its address for printf.
|
| The PLT entry is a tiny machine code stub within the same
| library or executable that does an indirect jump to the address
| held in a global offset table (GOT) entry. For lazily resolved
| symbols, the GOT is initialized to the address of a stub that
| does the dynamic symbol resolution and overwrites the GOT entry
| with the correct address (and then jumps to that address). Any
| later function call will still hit the PLT and jump to the
| address in the GOT, but the GOT will now point to the actual
| start of the function.
| pritambaral wrote:
| So if I take the address of printf in one library, and ask
| another library to compare it with their address of printf,
| will they not be equal?
| bombela wrote:
| Correct. They won't be equal. Since each library has its
| own table.
| ufo wrote:
| Does anyone know which tools the kernel developers used to
| identify all the places in the kernel that use function pointer
| equality?
|
| Changing how all the function pointers behave is a spooky change
| to make so they must have had some tools to help them find all
| the tricky places, right?
| DSingularity wrote:
| I am wary of any claim to CFI without secure tracking of the
| call-stack to verify the return destination. You need to compare
| return destinations against a shadow call-stack. If you dont
| protect this call stack then attackers will just evolve slightly.
| You can encrypt/decrypt the return address grsecurity style but
| we know that this can still be bypassed.
| agumonkey wrote:
| do you know who works on such topics ?
| DSingularity wrote:
| I'm not sure what you mean. I've read a variety of papers and
| articles on this topic. Are you referring to the user that
| replied to me?
| jnwatson wrote:
| It looks like backwards-edge protection is in a different
| patch. Backwards-edge is a bit easier to implement.
| DSingularity wrote:
| Well I am not sure I agree. It seems to me that there are
| significant security complications due to the need of making
| a runtime comparison to determine the integrity of the return
| destination. How are we to be convinced that the value at the
| top of the shadow-stack is not attacker-controlled?
| ndesaulniers wrote:
| An attacker could modify the shadow stack, it's just rather
| difficult to find where it's randomly placed and would
| require arbitrary read/write capabilities. The kernel zeros
| out the register used to write to the shadow stack as soon
| as possible after use. It's not impossible to defeat, but
| does raise the bar significantly.
|
| I encourage you to read the commit message of shadow call
| stack kernel patches, which as another commenter notes is
| only backwards edge protection; CFI is forwards edge
| protection.
___________________________________________________________________
(page generated 2021-05-28 23:01 UTC)