Skip to content

Commit 444d13f

Browse files
Jessica Yurustyrussell
authored andcommitted
modules: add ro_after_init support
Add ro_after_init support for modules by adding a new page-aligned section in the module layout (after rodata) for ro_after_init data and enabling RO protection for that section after module init runs. Signed-off-by: Jessica Yu <[email protected]> Acked-by: Kees Cook <[email protected]> Signed-off-by: Rusty Russell <[email protected]>
1 parent bdc9f37 commit 444d13f

File tree

4 files changed

+60
-15
lines changed

4 files changed

+60
-15
lines changed

include/linux/module.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ struct module_layout {
298298
unsigned int text_size;
299299
/* Size of RO section of the module (text+rodata) */
300300
unsigned int ro_size;
301+
/* Size of RO after init section */
302+
unsigned int ro_after_init_size;
301303

302304
#ifdef CONFIG_MODULES_TREE_LOOKUP
303305
struct mod_tree_node mtn;
@@ -765,12 +767,12 @@ extern int module_sysfs_initialized;
765767
#ifdef CONFIG_DEBUG_SET_MODULE_RONX
766768
extern void set_all_modules_text_rw(void);
767769
extern void set_all_modules_text_ro(void);
768-
extern void module_enable_ro(const struct module *mod);
770+
extern void module_enable_ro(const struct module *mod, bool after_init);
769771
extern void module_disable_ro(const struct module *mod);
770772
#else
771773
static inline void set_all_modules_text_rw(void) { }
772774
static inline void set_all_modules_text_ro(void) { }
773-
static inline void module_enable_ro(const struct module *mod) { }
775+
static inline void module_enable_ro(const struct module *mod, bool after_init) { }
774776
static inline void module_disable_ro(const struct module *mod) { }
775777
#endif
776778

include/uapi/linux/elf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ typedef struct elf64_phdr {
286286
#define SHF_ALLOC 0x2
287287
#define SHF_EXECINSTR 0x4
288288
#define SHF_RELA_LIVEPATCH 0x00100000
289+
#define SHF_RO_AFTER_INIT 0x00200000
289290
#define SHF_MASKPROC 0xf0000000
290291

291292
/* special section indexes */

kernel/livepatch/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod,
309309
break;
310310
}
311311

312-
module_enable_ro(pmod);
312+
module_enable_ro(pmod, true);
313313
return ret;
314314
}
315315

kernel/module.c

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,10 +1857,11 @@ static void mod_sysfs_teardown(struct module *mod)
18571857
* from modification and any data from execution.
18581858
*
18591859
* General layout of module is:
1860-
* [text] [read-only-data] [writable data]
1861-
* text_size -----^ ^ ^
1862-
* ro_size ------------------------| |
1863-
* size -------------------------------------------|
1860+
* [text] [read-only-data] [ro-after-init] [writable data]
1861+
* text_size -----^ ^ ^ ^
1862+
* ro_size ------------------------| | |
1863+
* ro_after_init_size -----------------------------| |
1864+
* size -----------------------------------------------------------|
18641865
*
18651866
* These values are always page-aligned (as is base)
18661867
*/
@@ -1883,36 +1884,51 @@ static void frob_rodata(const struct module_layout *layout,
18831884
(layout->ro_size - layout->text_size) >> PAGE_SHIFT);
18841885
}
18851886

1887+
static void frob_ro_after_init(const struct module_layout *layout,
1888+
int (*set_memory)(unsigned long start, int num_pages))
1889+
{
1890+
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
1891+
BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
1892+
BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
1893+
set_memory((unsigned long)layout->base + layout->ro_size,
1894+
(layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
1895+
}
1896+
18861897
static void frob_writable_data(const struct module_layout *layout,
18871898
int (*set_memory)(unsigned long start, int num_pages))
18881899
{
18891900
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
1890-
BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
1901+
BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
18911902
BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
1892-
set_memory((unsigned long)layout->base + layout->ro_size,
1893-
(layout->size - layout->ro_size) >> PAGE_SHIFT);
1903+
set_memory((unsigned long)layout->base + layout->ro_after_init_size,
1904+
(layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
18941905
}
18951906

18961907
/* livepatching wants to disable read-only so it can frob module. */
18971908
void module_disable_ro(const struct module *mod)
18981909
{
18991910
frob_text(&mod->core_layout, set_memory_rw);
19001911
frob_rodata(&mod->core_layout, set_memory_rw);
1912+
frob_ro_after_init(&mod->core_layout, set_memory_rw);
19011913
frob_text(&mod->init_layout, set_memory_rw);
19021914
frob_rodata(&mod->init_layout, set_memory_rw);
19031915
}
19041916

1905-
void module_enable_ro(const struct module *mod)
1917+
void module_enable_ro(const struct module *mod, bool after_init)
19061918
{
19071919
frob_text(&mod->core_layout, set_memory_ro);
19081920
frob_rodata(&mod->core_layout, set_memory_ro);
19091921
frob_text(&mod->init_layout, set_memory_ro);
19101922
frob_rodata(&mod->init_layout, set_memory_ro);
1923+
1924+
if (after_init)
1925+
frob_ro_after_init(&mod->core_layout, set_memory_ro);
19111926
}
19121927

19131928
static void module_enable_nx(const struct module *mod)
19141929
{
19151930
frob_rodata(&mod->core_layout, set_memory_nx);
1931+
frob_ro_after_init(&mod->core_layout, set_memory_nx);
19161932
frob_writable_data(&mod->core_layout, set_memory_nx);
19171933
frob_rodata(&mod->init_layout, set_memory_nx);
19181934
frob_writable_data(&mod->init_layout, set_memory_nx);
@@ -1921,6 +1937,7 @@ static void module_enable_nx(const struct module *mod)
19211937
static void module_disable_nx(const struct module *mod)
19221938
{
19231939
frob_rodata(&mod->core_layout, set_memory_x);
1940+
frob_ro_after_init(&mod->core_layout, set_memory_x);
19241941
frob_writable_data(&mod->core_layout, set_memory_x);
19251942
frob_rodata(&mod->init_layout, set_memory_x);
19261943
frob_writable_data(&mod->init_layout, set_memory_x);
@@ -1963,6 +1980,8 @@ static void disable_ro_nx(const struct module_layout *layout)
19631980
frob_text(layout, set_memory_rw);
19641981
frob_rodata(layout, set_memory_rw);
19651982
frob_rodata(layout, set_memory_x);
1983+
frob_ro_after_init(layout, set_memory_rw);
1984+
frob_ro_after_init(layout, set_memory_x);
19661985
frob_writable_data(layout, set_memory_x);
19671986
}
19681987

@@ -2305,6 +2324,7 @@ static void layout_sections(struct module *mod, struct load_info *info)
23052324
* finder in the two loops below */
23062325
{ SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
23072326
{ SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
2327+
{ SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL },
23082328
{ SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
23092329
{ ARCH_SHF_SMALL | SHF_ALLOC, 0 }
23102330
};
@@ -2336,7 +2356,11 @@ static void layout_sections(struct module *mod, struct load_info *info)
23362356
mod->core_layout.size = debug_align(mod->core_layout.size);
23372357
mod->core_layout.ro_size = mod->core_layout.size;
23382358
break;
2339-
case 3: /* whole core */
2359+
case 2: /* RO after init */
2360+
mod->core_layout.size = debug_align(mod->core_layout.size);
2361+
mod->core_layout.ro_after_init_size = mod->core_layout.size;
2362+
break;
2363+
case 4: /* whole core */
23402364
mod->core_layout.size = debug_align(mod->core_layout.size);
23412365
break;
23422366
}
@@ -2366,7 +2390,14 @@ static void layout_sections(struct module *mod, struct load_info *info)
23662390
mod->init_layout.size = debug_align(mod->init_layout.size);
23672391
mod->init_layout.ro_size = mod->init_layout.size;
23682392
break;
2369-
case 3: /* whole init */
2393+
case 2:
2394+
/*
2395+
* RO after init doesn't apply to init_layout (only
2396+
* core_layout), so it just takes the value of ro_size.
2397+
*/
2398+
mod->init_layout.ro_after_init_size = mod->init_layout.ro_size;
2399+
break;
2400+
case 4: /* whole init */
23702401
mod->init_layout.size = debug_align(mod->init_layout.size);
23712402
break;
23722403
}
@@ -3193,6 +3224,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
31933224
{
31943225
/* Module within temporary copy. */
31953226
struct module *mod;
3227+
unsigned int ndx;
31963228
int err;
31973229

31983230
mod = setup_load_info(info, flags);
@@ -3215,6 +3247,15 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
32153247
/* We will do a special allocation for per-cpu sections later. */
32163248
info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
32173249

3250+
/*
3251+
* Mark ro_after_init section with SHF_RO_AFTER_INIT so that
3252+
* layout_sections() can put it in the right place.
3253+
* Note: ro_after_init sections also have SHF_{WRITE,ALLOC} set.
3254+
*/
3255+
ndx = find_sec(info, ".data..ro_after_init");
3256+
if (ndx)
3257+
info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT;
3258+
32183259
/* Determine total sizes, and put offsets in sh_entsize. For now
32193260
this is done generically; there doesn't appear to be any
32203261
special cases for the architectures. */
@@ -3381,12 +3422,14 @@ static noinline int do_init_module(struct module *mod)
33813422
/* Switch to core kallsyms now init is done: kallsyms may be walking! */
33823423
rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
33833424
#endif
3425+
module_enable_ro(mod, true);
33843426
mod_tree_remove_init(mod);
33853427
disable_ro_nx(&mod->init_layout);
33863428
module_arch_freeing_init(mod);
33873429
mod->init_layout.base = NULL;
33883430
mod->init_layout.size = 0;
33893431
mod->init_layout.ro_size = 0;
3432+
mod->init_layout.ro_after_init_size = 0;
33903433
mod->init_layout.text_size = 0;
33913434
/*
33923435
* We want to free module_init, but be aware that kallsyms may be
@@ -3478,8 +3521,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
34783521
/* This relies on module_mutex for list integrity. */
34793522
module_bug_finalize(info->hdr, info->sechdrs, mod);
34803523

3481-
/* Set RO and NX regions */
3482-
module_enable_ro(mod);
3524+
module_enable_ro(mod, false);
34833525
module_enable_nx(mod);
34843526

34853527
/* Mark state as coming so strong_try_module_get() ignores us,

0 commit comments

Comments
 (0)