[go: up one dir, main page]

|
|
Log in / Subscribe / Register

A canary for timer-expiration functions

A canary for timer-expiration functions

Posted Aug 20, 2017 9:26 UTC (Sun) by jzbiciak (guest, #5246)
In reply to: A canary for timer-expiration functions by Sesse
Parent article: A canary for timer-expiration functions

You could, in principle, allow modules to register their entry points as well. Perhaps structure it as a tuple, with <module,entry> pairs, with only the module part being determined dynamically at module-load time.

Indeed, we implemented something like this in a small secure-kernel + secure-module API that I helped develop for an embedded processor. Each module defined its set of entry points, and received a load-time assigned module ID. The module ID did require an extra level of indirection to find the entry point table for the module, so that was one downside.


to post comments

A canary for timer-expiration functions

Posted Aug 20, 2017 9:35 UTC (Sun) by Sesse (subscriber, #53779) [Link] (3 responses)

At this point, you need a runtime table of function pointers, as opposed to fixed and locked-down switch/case code… what did you gain?

A canary for timer-expiration functions

Posted Aug 20, 2017 9:47 UTC (Sun) by jzbiciak (guest, #5246) [Link] (2 responses)

It's still fixed tables of addresses, converted to small, easily-validated numbers. I can validate that the module ID and index are both in-range with a single comparison each. The tables themselves can live in read-only memory as well.

This limits the attacker to only being able to select among the fixed list of entry points determined at compile time, while still permitting loadable modules.

Now, if someone could modprobe evil.ko, then yeah, they can subvert this. But if they can do that, there are much shorter, more obvious paths to running their code.

A canary for timer-expiration functions

Posted Aug 20, 2017 9:53 UTC (Sun) by Sesse (subscriber, #53779) [Link] (1 responses)

No, my question is; how can you make sure a good out-of-tree module can register a timer in such a scheme? That won't work if the tables are locked and live in read-only memory.

A canary for timer-expiration functions

Posted Aug 20, 2017 10:16 UTC (Sun) by jzbiciak (guest, #5246) [Link]

I'm saying that each module provides its own table in an rodata type of section that can be mapped read-only. The only dynamic run-time bit, then, is a module ID, which indexes a writable table of pointers to read-only tables of function pointers. All of the tables of function pointers at least are read-only.

Something like this very rough sketch:

/* This part lives in the kernel */
void *const kernel_fxn_ptrs[] = { ... };  /* this is read-only */
void *const *module_fxn_table_ptrs[MAX_MODULES];  /* this is read-write */

/* This part lives in each module */
void *const module_fxn_ptrs[] = { ... }; /* this is read-only */

Now, since module_fxn_table_ptrs only needs modification at module load time, you could imagine spending the cost of establishing a writeable mapping to it during module load, and then discarding that writeable mapping once the module's table is registered. That means you'd only have read-only tables for these function pointers under normal circumstances, with a small window during module load where a writeable mapping exists.

Of course, that idea assumes we don't have a full MMU to work with (as was the case on that embedded processor). We do have a full MMU at our disposal.

So here's an even better idea that keeps every table read-only the entire time. Put the function pointer tables in their own dedicated multiple-of-the-page sized section. Let's call it .rodata.fxn_ptr. The kernel maps its own .rodata.fxn_ptr read-only at some virtual address determined at runtime (ASLR). As modules get loaded, map their .rodata.fxn_ptr pages directly after the kernel's, also read-only. The module ID now just becomes "how many pages to skip to get to the start of my module's table." That also removes the indirection. When a module gets unloaded, unmap its table.

Now, you do have a new resource to manage. But, if you force everyone into no more than, say, 8K, that still gives you 1024 entry points on a 64-bit machine.


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