diff options
author | Jessica Yu <jeyu@redhat.com> | 2016-07-26 22:36:21 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2016-08-03 20:46:55 -0400 |
commit | 444d13ff10fb13bc3e64859c3cf9ce43dcfeb075 (patch) | |
tree | ab35e195fe3daeae0bd87f6f5bd7cc1cf07fd86a | |
parent | bdc9f373551dd3f1e6fae1618f2394ee9bc7db2e (diff) |
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 <jeyu@redhat.com>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | include/linux/module.h | 6 | ||||
-rw-r--r-- | include/uapi/linux/elf.h | 1 | ||||
-rw-r--r-- | kernel/livepatch/core.c | 2 | ||||
-rw-r--r-- | kernel/module.c | 66 |
4 files changed, 60 insertions, 15 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index f95ed243a4de..0c3207d26ac0 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -298,6 +298,8 @@ struct module_layout { | |||
298 | unsigned int text_size; | 298 | unsigned int text_size; |
299 | /* Size of RO section of the module (text+rodata) */ | 299 | /* Size of RO section of the module (text+rodata) */ |
300 | unsigned int ro_size; | 300 | unsigned int ro_size; |
301 | /* Size of RO after init section */ | ||
302 | unsigned int ro_after_init_size; | ||
301 | 303 | ||
302 | #ifdef CONFIG_MODULES_TREE_LOOKUP | 304 | #ifdef CONFIG_MODULES_TREE_LOOKUP |
303 | struct mod_tree_node mtn; | 305 | struct mod_tree_node mtn; |
@@ -765,12 +767,12 @@ extern int module_sysfs_initialized; | |||
765 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | 767 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX |
766 | extern void set_all_modules_text_rw(void); | 768 | extern void set_all_modules_text_rw(void); |
767 | extern void set_all_modules_text_ro(void); | 769 | 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); |
769 | extern void module_disable_ro(const struct module *mod); | 771 | extern void module_disable_ro(const struct module *mod); |
770 | #else | 772 | #else |
771 | static inline void set_all_modules_text_rw(void) { } | 773 | static inline void set_all_modules_text_rw(void) { } |
772 | static inline void set_all_modules_text_ro(void) { } | 774 | 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) { } |
774 | static inline void module_disable_ro(const struct module *mod) { } | 776 | static inline void module_disable_ro(const struct module *mod) { } |
775 | #endif | 777 | #endif |
776 | 778 | ||
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index cb4a72f888d5..70b172ba41ce 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h | |||
@@ -286,6 +286,7 @@ typedef struct elf64_phdr { | |||
286 | #define SHF_ALLOC 0x2 | 286 | #define SHF_ALLOC 0x2 |
287 | #define SHF_EXECINSTR 0x4 | 287 | #define SHF_EXECINSTR 0x4 |
288 | #define SHF_RELA_LIVEPATCH 0x00100000 | 288 | #define SHF_RELA_LIVEPATCH 0x00100000 |
289 | #define SHF_RO_AFTER_INIT 0x00200000 | ||
289 | #define SHF_MASKPROC 0xf0000000 | 290 | #define SHF_MASKPROC 0xf0000000 |
290 | 291 | ||
291 | /* special section indexes */ | 292 | /* special section indexes */ |
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 5c2bc1052691..8bbe50704621 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
@@ -309,7 +309,7 @@ static int klp_write_object_relocations(struct module *pmod, | |||
309 | break; | 309 | break; |
310 | } | 310 | } |
311 | 311 | ||
312 | module_enable_ro(pmod); | 312 | module_enable_ro(pmod, true); |
313 | return ret; | 313 | return ret; |
314 | } | 314 | } |
315 | 315 | ||
diff --git a/kernel/module.c b/kernel/module.c index c91c2fdca2e6..205a71a97852 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1857,10 +1857,11 @@ static void mod_sysfs_teardown(struct module *mod) | |||
1857 | * from modification and any data from execution. | 1857 | * from modification and any data from execution. |
1858 | * | 1858 | * |
1859 | * General layout of module is: | 1859 | * General layout of module is: |
1860 | * [text] [read-only-data] [writable data] | 1860 | * [text] [read-only-data] [ro-after-init] [writable data] |
1861 | * text_size -----^ ^ ^ | 1861 | * text_size -----^ ^ ^ ^ |
1862 | * ro_size ------------------------| | | 1862 | * ro_size ------------------------| | | |
1863 | * size -------------------------------------------| | 1863 | * ro_after_init_size -----------------------------| | |
1864 | * size -----------------------------------------------------------| | ||
1864 | * | 1865 | * |
1865 | * These values are always page-aligned (as is base) | 1866 | * These values are always page-aligned (as is base) |
1866 | */ | 1867 | */ |
@@ -1883,14 +1884,24 @@ static void frob_rodata(const struct module_layout *layout, | |||
1883 | (layout->ro_size - layout->text_size) >> PAGE_SHIFT); | 1884 | (layout->ro_size - layout->text_size) >> PAGE_SHIFT); |
1884 | } | 1885 | } |
1885 | 1886 | ||
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 | |||
1886 | static void frob_writable_data(const struct module_layout *layout, | 1897 | static void frob_writable_data(const struct module_layout *layout, |
1887 | int (*set_memory)(unsigned long start, int num_pages)) | 1898 | int (*set_memory)(unsigned long start, int num_pages)) |
1888 | { | 1899 | { |
1889 | BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1)); | 1900 | 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)); |
1891 | BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1)); | 1902 | BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1)); |
1892 | set_memory((unsigned long)layout->base + layout->ro_size, | 1903 | set_memory((unsigned long)layout->base + layout->ro_after_init_size, |
1893 | (layout->size - layout->ro_size) >> PAGE_SHIFT); | 1904 | (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT); |
1894 | } | 1905 | } |
1895 | 1906 | ||
1896 | /* livepatching wants to disable read-only so it can frob module. */ | 1907 | /* livepatching wants to disable read-only so it can frob module. */ |
@@ -1898,21 +1909,26 @@ void module_disable_ro(const struct module *mod) | |||
1898 | { | 1909 | { |
1899 | frob_text(&mod->core_layout, set_memory_rw); | 1910 | frob_text(&mod->core_layout, set_memory_rw); |
1900 | frob_rodata(&mod->core_layout, set_memory_rw); | 1911 | frob_rodata(&mod->core_layout, set_memory_rw); |
1912 | frob_ro_after_init(&mod->core_layout, set_memory_rw); | ||
1901 | frob_text(&mod->init_layout, set_memory_rw); | 1913 | frob_text(&mod->init_layout, set_memory_rw); |
1902 | frob_rodata(&mod->init_layout, set_memory_rw); | 1914 | frob_rodata(&mod->init_layout, set_memory_rw); |
1903 | } | 1915 | } |
1904 | 1916 | ||
1905 | void module_enable_ro(const struct module *mod) | 1917 | void module_enable_ro(const struct module *mod, bool after_init) |
1906 | { | 1918 | { |
1907 | frob_text(&mod->core_layout, set_memory_ro); | 1919 | frob_text(&mod->core_layout, set_memory_ro); |
1908 | frob_rodata(&mod->core_layout, set_memory_ro); | 1920 | frob_rodata(&mod->core_layout, set_memory_ro); |
1909 | frob_text(&mod->init_layout, set_memory_ro); | 1921 | frob_text(&mod->init_layout, set_memory_ro); |
1910 | frob_rodata(&mod->init_layout, set_memory_ro); | 1922 | frob_rodata(&mod->init_layout, set_memory_ro); |
1923 | |||
1924 | if (after_init) | ||
1925 | frob_ro_after_init(&mod->core_layout, set_memory_ro); | ||
1911 | } | 1926 | } |
1912 | 1927 | ||
1913 | static void module_enable_nx(const struct module *mod) | 1928 | static void module_enable_nx(const struct module *mod) |
1914 | { | 1929 | { |
1915 | frob_rodata(&mod->core_layout, set_memory_nx); | 1930 | frob_rodata(&mod->core_layout, set_memory_nx); |
1931 | frob_ro_after_init(&mod->core_layout, set_memory_nx); | ||
1916 | frob_writable_data(&mod->core_layout, set_memory_nx); | 1932 | frob_writable_data(&mod->core_layout, set_memory_nx); |
1917 | frob_rodata(&mod->init_layout, set_memory_nx); | 1933 | frob_rodata(&mod->init_layout, set_memory_nx); |
1918 | frob_writable_data(&mod->init_layout, set_memory_nx); | 1934 | frob_writable_data(&mod->init_layout, set_memory_nx); |
@@ -1921,6 +1937,7 @@ static void module_enable_nx(const struct module *mod) | |||
1921 | static void module_disable_nx(const struct module *mod) | 1937 | static void module_disable_nx(const struct module *mod) |
1922 | { | 1938 | { |
1923 | frob_rodata(&mod->core_layout, set_memory_x); | 1939 | frob_rodata(&mod->core_layout, set_memory_x); |
1940 | frob_ro_after_init(&mod->core_layout, set_memory_x); | ||
1924 | frob_writable_data(&mod->core_layout, set_memory_x); | 1941 | frob_writable_data(&mod->core_layout, set_memory_x); |
1925 | frob_rodata(&mod->init_layout, set_memory_x); | 1942 | frob_rodata(&mod->init_layout, set_memory_x); |
1926 | frob_writable_data(&mod->init_layout, set_memory_x); | 1943 | frob_writable_data(&mod->init_layout, set_memory_x); |
@@ -1963,6 +1980,8 @@ static void disable_ro_nx(const struct module_layout *layout) | |||
1963 | frob_text(layout, set_memory_rw); | 1980 | frob_text(layout, set_memory_rw); |
1964 | frob_rodata(layout, set_memory_rw); | 1981 | frob_rodata(layout, set_memory_rw); |
1965 | frob_rodata(layout, set_memory_x); | 1982 | frob_rodata(layout, set_memory_x); |
1983 | frob_ro_after_init(layout, set_memory_rw); | ||
1984 | frob_ro_after_init(layout, set_memory_x); | ||
1966 | frob_writable_data(layout, set_memory_x); | 1985 | frob_writable_data(layout, set_memory_x); |
1967 | } | 1986 | } |
1968 | 1987 | ||
@@ -2305,6 +2324,7 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
2305 | * finder in the two loops below */ | 2324 | * finder in the two loops below */ |
2306 | { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, | 2325 | { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, |
2307 | { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, | 2326 | { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, |
2327 | { SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL }, | ||
2308 | { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, | 2328 | { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, |
2309 | { ARCH_SHF_SMALL | SHF_ALLOC, 0 } | 2329 | { ARCH_SHF_SMALL | SHF_ALLOC, 0 } |
2310 | }; | 2330 | }; |
@@ -2336,7 +2356,11 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
2336 | mod->core_layout.size = debug_align(mod->core_layout.size); | 2356 | mod->core_layout.size = debug_align(mod->core_layout.size); |
2337 | mod->core_layout.ro_size = mod->core_layout.size; | 2357 | mod->core_layout.ro_size = mod->core_layout.size; |
2338 | break; | 2358 | 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 */ | ||
2340 | mod->core_layout.size = debug_align(mod->core_layout.size); | 2364 | mod->core_layout.size = debug_align(mod->core_layout.size); |
2341 | break; | 2365 | break; |
2342 | } | 2366 | } |
@@ -2366,7 +2390,14 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
2366 | mod->init_layout.size = debug_align(mod->init_layout.size); | 2390 | mod->init_layout.size = debug_align(mod->init_layout.size); |
2367 | mod->init_layout.ro_size = mod->init_layout.size; | 2391 | mod->init_layout.ro_size = mod->init_layout.size; |
2368 | break; | 2392 | 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 */ | ||
2370 | mod->init_layout.size = debug_align(mod->init_layout.size); | 2401 | mod->init_layout.size = debug_align(mod->init_layout.size); |
2371 | break; | 2402 | break; |
2372 | } | 2403 | } |
@@ -3193,6 +3224,7 @@ static struct module *layout_and_allocate(struct load_info *info, int flags) | |||
3193 | { | 3224 | { |
3194 | /* Module within temporary copy. */ | 3225 | /* Module within temporary copy. */ |
3195 | struct module *mod; | 3226 | struct module *mod; |
3227 | unsigned int ndx; | ||
3196 | int err; | 3228 | int err; |
3197 | 3229 | ||
3198 | mod = setup_load_info(info, flags); | 3230 | mod = setup_load_info(info, flags); |
@@ -3215,6 +3247,15 @@ static struct module *layout_and_allocate(struct load_info *info, int flags) | |||
3215 | /* We will do a special allocation for per-cpu sections later. */ | 3247 | /* We will do a special allocation for per-cpu sections later. */ |
3216 | info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC; | 3248 | info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC; |
3217 | 3249 | ||
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 | |||
3218 | /* Determine total sizes, and put offsets in sh_entsize. For now | 3259 | /* Determine total sizes, and put offsets in sh_entsize. For now |
3219 | this is done generically; there doesn't appear to be any | 3260 | this is done generically; there doesn't appear to be any |
3220 | special cases for the architectures. */ | 3261 | special cases for the architectures. */ |
@@ -3381,12 +3422,14 @@ static noinline int do_init_module(struct module *mod) | |||
3381 | /* Switch to core kallsyms now init is done: kallsyms may be walking! */ | 3422 | /* Switch to core kallsyms now init is done: kallsyms may be walking! */ |
3382 | rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); | 3423 | rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); |
3383 | #endif | 3424 | #endif |
3425 | module_enable_ro(mod, true); | ||
3384 | mod_tree_remove_init(mod); | 3426 | mod_tree_remove_init(mod); |
3385 | disable_ro_nx(&mod->init_layout); | 3427 | disable_ro_nx(&mod->init_layout); |
3386 | module_arch_freeing_init(mod); | 3428 | module_arch_freeing_init(mod); |
3387 | mod->init_layout.base = NULL; | 3429 | mod->init_layout.base = NULL; |
3388 | mod->init_layout.size = 0; | 3430 | mod->init_layout.size = 0; |
3389 | mod->init_layout.ro_size = 0; | 3431 | mod->init_layout.ro_size = 0; |
3432 | mod->init_layout.ro_after_init_size = 0; | ||
3390 | mod->init_layout.text_size = 0; | 3433 | mod->init_layout.text_size = 0; |
3391 | /* | 3434 | /* |
3392 | * We want to free module_init, but be aware that kallsyms may be | 3435 | * 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) | |||
3478 | /* This relies on module_mutex for list integrity. */ | 3521 | /* This relies on module_mutex for list integrity. */ |
3479 | module_bug_finalize(info->hdr, info->sechdrs, mod); | 3522 | module_bug_finalize(info->hdr, info->sechdrs, mod); |
3480 | 3523 | ||
3481 | /* Set RO and NX regions */ | 3524 | module_enable_ro(mod, false); |
3482 | module_enable_ro(mod); | ||
3483 | module_enable_nx(mod); | 3525 | module_enable_nx(mod); |
3484 | 3526 | ||
3485 | /* Mark state as coming so strong_try_module_get() ignores us, | 3527 | /* Mark state as coming so strong_try_module_get() ignores us, |