Commit 2f3238aebedb243804f58d62d57244edec4149b2

Authored by Rusty Russell
1 parent 34e1169d99

module: add flags arg to sys_finit_module()

Thanks to Michael Kerrisk for keeping us honest.  These flags are actually
useful for eliminating the only case where kmod has to mangle a module's
internals: for overriding module versioning.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Lucas De Marchi <lucas.demarchi@profusion.mobi>
Acked-by: Kees Cook <keescook@chromium.org>

Showing 3 changed files with 35 additions and 15 deletions Side-by-side Diff

include/linux/syscalls.h
... ... @@ -868,6 +868,6 @@
868 868  
869 869 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
870 870 unsigned long idx1, unsigned long idx2);
871   -asmlinkage long sys_finit_module(int fd, const char __user *uargs);
  871 +asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
872 872 #endif
include/uapi/linux/module.h
  1 +#ifndef _UAPI_LINUX_MODULE_H
  2 +#define _UAPI_LINUX_MODULE_H
  3 +
  4 +/* Flags for sys_finit_module: */
  5 +#define MODULE_INIT_IGNORE_MODVERSIONS 1
  6 +#define MODULE_INIT_IGNORE_VERMAGIC 2
  7 +
  8 +#endif /* _UAPI_LINUX_MODULE_H */
... ... @@ -60,6 +60,7 @@
60 60 #include <linux/pfn.h>
61 61 #include <linux/bsearch.h>
62 62 #include <linux/fips.h>
  63 +#include <uapi/linux/module.h>
63 64 #include "module-internal.h"
64 65  
65 66 #define CREATE_TRACE_POINTS
... ... @@ -2553,7 +2554,7 @@
2553 2554 vfree(info->hdr);
2554 2555 }
2555 2556  
2556   -static int rewrite_section_headers(struct load_info *info)
  2557 +static int rewrite_section_headers(struct load_info *info, int flags)
2557 2558 {
2558 2559 unsigned int i;
2559 2560  
... ... @@ -2581,7 +2582,10 @@
2581 2582 }
2582 2583  
2583 2584 /* Track but don't keep modinfo and version sections. */
2584   - info->index.vers = find_sec(info, "__versions");
  2585 + if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
  2586 + info->index.vers = 0; /* Pretend no __versions section! */
  2587 + else
  2588 + info->index.vers = find_sec(info, "__versions");
2585 2589 info->index.info = find_sec(info, ".modinfo");
2586 2590 info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
2587 2591 info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
... ... @@ -2596,7 +2600,7 @@
2596 2600 * Return the temporary module pointer (we'll replace it with the final
2597 2601 * one when we move the module sections around).
2598 2602 */
2599   -static struct module *setup_load_info(struct load_info *info)
  2603 +static struct module *setup_load_info(struct load_info *info, int flags)
2600 2604 {
2601 2605 unsigned int i;
2602 2606 int err;
... ... @@ -2607,7 +2611,7 @@
2607 2611 info->secstrings = (void *)info->hdr
2608 2612 + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
2609 2613  
2610   - err = rewrite_section_headers(info);
  2614 + err = rewrite_section_headers(info, flags);
2611 2615 if (err)
2612 2616 return ERR_PTR(err);
2613 2617  
2614 2618  
... ... @@ -2645,11 +2649,14 @@
2645 2649 return mod;
2646 2650 }
2647 2651  
2648   -static int check_modinfo(struct module *mod, struct load_info *info)
  2652 +static int check_modinfo(struct module *mod, struct load_info *info, int flags)
2649 2653 {
2650 2654 const char *modmagic = get_modinfo(info, "vermagic");
2651 2655 int err;
2652 2656  
  2657 + if (flags & MODULE_INIT_IGNORE_VERMAGIC)
  2658 + modmagic = NULL;
  2659 +
2653 2660 /* This is allowed: modprobe --force will invalidate it. */
2654 2661 if (!modmagic) {
2655 2662 err = try_to_force_load(mod, "bad vermagic");
2656 2663  
2657 2664  
... ... @@ -2885,18 +2892,18 @@
2885 2892 return 0;
2886 2893 }
2887 2894  
2888   -static struct module *layout_and_allocate(struct load_info *info)
  2895 +static struct module *layout_and_allocate(struct load_info *info, int flags)
2889 2896 {
2890 2897 /* Module within temporary copy. */
2891 2898 struct module *mod;
2892 2899 Elf_Shdr *pcpusec;
2893 2900 int err;
2894 2901  
2895   - mod = setup_load_info(info);
  2902 + mod = setup_load_info(info, flags);
2896 2903 if (IS_ERR(mod))
2897 2904 return mod;
2898 2905  
2899   - err = check_modinfo(mod, info);
  2906 + err = check_modinfo(mod, info, flags);
2900 2907 if (err)
2901 2908 return ERR_PTR(err);
2902 2909  
... ... @@ -3078,7 +3085,8 @@
3078 3085  
3079 3086 /* Allocate and load the module: note that size of section 0 is always
3080 3087 zero, and we rely on this for optional sections. */
3081   -static int load_module(struct load_info *info, const char __user *uargs)
  3088 +static int load_module(struct load_info *info, const char __user *uargs,
  3089 + int flags)
3082 3090 {
3083 3091 struct module *mod, *old;
3084 3092 long err;
... ... @@ -3092,7 +3100,7 @@
3092 3100 goto free_copy;
3093 3101  
3094 3102 /* Figure out module layout, and allocate all the memory. */
3095   - mod = layout_and_allocate(info);
  3103 + mod = layout_and_allocate(info, flags);
3096 3104 if (IS_ERR(mod)) {
3097 3105 err = PTR_ERR(mod);
3098 3106 goto free_copy;
3099 3107  
... ... @@ -3241,10 +3249,10 @@
3241 3249 if (err)
3242 3250 return err;
3243 3251  
3244   - return load_module(&info, uargs);
  3252 + return load_module(&info, uargs, 0);
3245 3253 }
3246 3254  
3247   -SYSCALL_DEFINE2(finit_module, int, fd, const char __user *, uargs)
  3255 +SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
3248 3256 {
3249 3257 int err;
3250 3258 struct load_info info = { };
3251 3259  
3252 3260  
... ... @@ -3253,13 +3261,17 @@
3253 3261 if (err)
3254 3262 return err;
3255 3263  
3256   - pr_debug("finit_module: fd=%d, uargs=%p\n", fd, uargs);
  3264 + pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
3257 3265  
  3266 + if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
  3267 + |MODULE_INIT_IGNORE_VERMAGIC))
  3268 + return -EINVAL;
  3269 +
3258 3270 err = copy_module_from_fd(fd, &info);
3259 3271 if (err)
3260 3272 return err;
3261 3273  
3262   - return load_module(&info, uargs);
  3274 + return load_module(&info, uargs, flags);
3263 3275 }
3264 3276  
3265 3277 static inline int within(unsigned long addr, void *start, unsigned long size)