History

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.

Jessica Yu committed 10 years ago

Commit 444d13f1 parent bdc9f374 files · +60 −15Browse files

Unified · Split

4 files
  1. include/linux/module.h +4 −2
  2. include/uapi/linux/elf.h +1 −0
  3. kernel/livepatch/core.c +1 −1
  4. kernel/module.c +54 −12
include/linux/module.h+4−2
@@ -298,6 +298,8 @@ struct module_layout { · 297 unmodified lines
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; · 461 unmodified lines
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+1−0
@@ -286,6 +286,7 @@ typedef struct elf64_phdr { · 285 unmodified lines
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+1−1
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod, · 308 unmodified lines
309309 break;
310310 }
311311
312− module_enable_ro(pmod);
312+ module_enable_ro(pmod, true);
313313 return ret;
314314 }
315315
kernel/module.c+54−12
@@ -1857,10 +1857,11 @@ static void mod_sysfs_teardown(struct module *mod) · 1856 unmodified lines
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,14 +1884,24 @@ static void frob_rodata(const struct module_layout *layout, · 16 unmodified lines
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. */
@@ -1898,21 +1909,26 @@ void module_disable_ro(const struct module *mod) · 1 unmodified line
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) · 2 unmodified lines
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) · 36 unmodified lines
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) · 336 unmodified lines
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) · 25 unmodified lines
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) · 23 unmodified lines
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) · 820 unmodified lines
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) · 16 unmodified lines
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) · 160 unmodified lines
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) · 85 unmodified lines
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,