aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/syscalls/syscall_32.tbl1
-rw-r--r--arch/x86/syscalls/syscall_64.tbl1
-rw-r--r--include/linux/syscalls.h1
-rw-r--r--kernel/module.c367
-rw-r--r--kernel/sys_ni.c1
5 files changed, 223 insertions, 148 deletions
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index a47103fbc692..83b3838417ed 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -356,3 +356,4 @@
356347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv 356347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv
357348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev 357348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev
358349 i386 kcmp sys_kcmp 358349 i386 kcmp sys_kcmp
359350 i386 finit_module sys_finit_module
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index a582bfed95bb..7c58c84b7bc8 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -319,6 +319,7 @@
319310 64 process_vm_readv sys_process_vm_readv 319310 64 process_vm_readv sys_process_vm_readv
320311 64 process_vm_writev sys_process_vm_writev 320311 64 process_vm_writev sys_process_vm_writev
321312 common kcmp sys_kcmp 321312 common kcmp sys_kcmp
322313 common finit_module sys_finit_module
322 323
323# 324#
324# x32-specific system call numbers start at 512 to avoid cache impact 325# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 727f0cd73921..32bc035bcd68 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -868,4 +868,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
868 868
869asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, 869asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
870 unsigned long idx1, unsigned long idx2); 870 unsigned long idx1, unsigned long idx2);
871asmlinkage long sys_finit_module(int fd, const char __user *uargs);
871#endif 872#endif
diff --git a/kernel/module.c b/kernel/module.c
index 6e48c3a43599..6d2c4e4ca1f5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -21,6 +21,7 @@
21#include <linux/ftrace_event.h> 21#include <linux/ftrace_event.h>
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/kallsyms.h> 23#include <linux/kallsyms.h>
24#include <linux/file.h>
24#include <linux/fs.h> 25#include <linux/fs.h>
25#include <linux/sysfs.h> 26#include <linux/sysfs.h>
26#include <linux/kernel.h> 27#include <linux/kernel.h>
@@ -2425,18 +2426,17 @@ static inline void kmemleak_load_module(const struct module *mod,
2425#endif 2426#endif
2426 2427
2427#ifdef CONFIG_MODULE_SIG 2428#ifdef CONFIG_MODULE_SIG
2428static int module_sig_check(struct load_info *info, 2429static int module_sig_check(struct load_info *info)
2429 const void *mod, unsigned long *_len)
2430{ 2430{
2431 int err = -ENOKEY; 2431 int err = -ENOKEY;
2432 unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; 2432 const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
2433 unsigned long len = *_len; 2433 const void *mod = info->hdr;
2434 2434
2435 if (len > markerlen && 2435 if (info->len > markerlen &&
2436 memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { 2436 memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
2437 /* We truncate the module to discard the signature */ 2437 /* We truncate the module to discard the signature */
2438 *_len -= markerlen; 2438 info->len -= markerlen;
2439 err = mod_verify_sig(mod, _len); 2439 err = mod_verify_sig(mod, &info->len);
2440 } 2440 }
2441 2441
2442 if (!err) { 2442 if (!err) {
@@ -2454,59 +2454,97 @@ static int module_sig_check(struct load_info *info,
2454 return err; 2454 return err;
2455} 2455}
2456#else /* !CONFIG_MODULE_SIG */ 2456#else /* !CONFIG_MODULE_SIG */
2457static int module_sig_check(struct load_info *info, 2457static int module_sig_check(struct load_info *info)
2458 void *mod, unsigned long *len)
2459{ 2458{
2460 return 0; 2459 return 0;
2461} 2460}
2462#endif /* !CONFIG_MODULE_SIG */ 2461#endif /* !CONFIG_MODULE_SIG */
2463 2462
2464/* Sets info->hdr, info->len and info->sig_ok. */ 2463/* Sanity checks against invalid binaries, wrong arch, weird elf version. */
2465static int copy_and_check(struct load_info *info, 2464static int elf_header_check(struct load_info *info)
2466 const void __user *umod, unsigned long len,
2467 const char __user *uargs)
2468{ 2465{
2469 int err; 2466 if (info->len < sizeof(*(info->hdr)))
2470 Elf_Ehdr *hdr; 2467 return -ENOEXEC;
2468
2469 if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
2470 || info->hdr->e_type != ET_REL
2471 || !elf_check_arch(info->hdr)
2472 || info->hdr->e_shentsize != sizeof(Elf_Shdr))
2473 return -ENOEXEC;
2474
2475 if (info->hdr->e_shoff >= info->len
2476 || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
2477 info->len - info->hdr->e_shoff))
2478 return -ENOEXEC;
2471 2479
2472 if (len < sizeof(*hdr)) 2480 return 0;
2481}
2482
2483/* Sets info->hdr and info->len. */
2484static int copy_module_from_user(const void __user *umod, unsigned long len,
2485 struct load_info *info)
2486{
2487 info->len = len;
2488 if (info->len < sizeof(*(info->hdr)))
2473 return -ENOEXEC; 2489 return -ENOEXEC;
2474 2490
2475 /* Suck in entire file: we'll want most of it. */ 2491 /* Suck in entire file: we'll want most of it. */
2476 if ((hdr = vmalloc(len)) == NULL) 2492 info->hdr = vmalloc(info->len);
2493 if (!info->hdr)
2477 return -ENOMEM; 2494 return -ENOMEM;
2478 2495
2479 if (copy_from_user(hdr, umod, len) != 0) { 2496 if (copy_from_user(info->hdr, umod, info->len) != 0) {
2480 err = -EFAULT; 2497 vfree(info->hdr);
2481 goto free_hdr; 2498 return -EFAULT;
2482 } 2499 }
2483 2500
2484 err = module_sig_check(info, hdr, &len); 2501 return 0;
2502}
2503
2504/* Sets info->hdr and info->len. */
2505static int copy_module_from_fd(int fd, struct load_info *info)
2506{
2507 struct file *file;
2508 int err;
2509 struct kstat stat;
2510 loff_t pos;
2511 ssize_t bytes = 0;
2512
2513 file = fget(fd);
2514 if (!file)
2515 return -ENOEXEC;
2516
2517 err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
2485 if (err) 2518 if (err)
2486 goto free_hdr; 2519 goto out;
2487 2520
2488 /* Sanity checks against insmoding binaries or wrong arch, 2521 if (stat.size > INT_MAX) {
2489 weird elf version */ 2522 err = -EFBIG;
2490 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 2523 goto out;
2491 || hdr->e_type != ET_REL
2492 || !elf_check_arch(hdr)
2493 || hdr->e_shentsize != sizeof(Elf_Shdr)) {
2494 err = -ENOEXEC;
2495 goto free_hdr;
2496 } 2524 }
2497 2525 info->hdr = vmalloc(stat.size);
2498 if (hdr->e_shoff >= len || 2526 if (!info->hdr) {
2499 hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) { 2527 err = -ENOMEM;
2500 err = -ENOEXEC; 2528 goto out;
2501 goto free_hdr;
2502 } 2529 }
2503 2530
2504 info->hdr = hdr; 2531 pos = 0;
2505 info->len = len; 2532 while (pos < stat.size) {
2506 return 0; 2533 bytes = kernel_read(file, pos, (char *)(info->hdr) + pos,
2534 stat.size - pos);
2535 if (bytes < 0) {
2536 vfree(info->hdr);
2537 err = bytes;
2538 goto out;
2539 }
2540 if (bytes == 0)
2541 break;
2542 pos += bytes;
2543 }
2544 info->len = pos;
2507 2545
2508free_hdr: