Commit 7a684c45 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux

Pull module update from Rusty Russell:
 "Nothing all that exciting; a new module-from-fd syscall for those who
  want to verify the source of the module (ChromeOS) and/or use standard
  IMA on it or other security hooks."

* tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux:
  MODSIGN: Fix kbuild output when using default extra_certificates
  MODSIGN: Avoid using .incbin in C source
  modules: don't hand 0 to vmalloc.
  module: Remove a extra null character at the top of module->strtab.
  ASN.1: Use the ASN1_LONG_TAG and ASN1_INDEFINITE_LENGTH constants
  ASN.1: Define indefinite length marker constant
  moduleparam: use __UNIQUE_ID()
  __UNIQUE_ID()
  MODSIGN: Add modules_sign make target
  powerpc: add finit_module syscall.
  ima: support new kernel module syscall
  add finit_module syscall to asm-generic
  ARM: add finit_module syscall to ARM
  security: introduce kernel_module_from_file hook
  module: add flags arg to sys_finit_module()
  module: add syscall to load module from fd
parents 7f2de817 e10e1774
...@@ -23,7 +23,7 @@ Description: ...@@ -23,7 +23,7 @@ Description:
lsm: [[subj_user=] [subj_role=] [subj_type=] lsm: [[subj_user=] [subj_role=] [subj_type=]
[obj_user=] [obj_role=] [obj_type=]] [obj_user=] [obj_role=] [obj_type=]]
base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK] base: func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK][MODULE_CHECK]
mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
fsmagic:= hex value fsmagic:= hex value
uid:= decimal value uid:= decimal value
...@@ -53,6 +53,7 @@ Description: ...@@ -53,6 +53,7 @@ Description:
measure func=BPRM_CHECK measure func=BPRM_CHECK
measure func=FILE_MMAP mask=MAY_EXEC measure func=FILE_MMAP mask=MAY_EXEC
measure func=FILE_CHECK mask=MAY_READ uid=0 measure func=FILE_CHECK mask=MAY_READ uid=0
measure func=MODULE_CHECK uid=0
appraise fowner=0 appraise fowner=0
The default policy measures all executables in bprm_check, The default policy measures all executables in bprm_check,
......
...@@ -981,6 +981,12 @@ _modinst_post: _modinst_ ...@@ -981,6 +981,12 @@ _modinst_post: _modinst_
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst
$(call cmd,depmod) $(call cmd,depmod)
ifeq ($(CONFIG_MODULE_SIG), y)
PHONY += modules_sign
modules_sign:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modsign
endif
else # CONFIG_MODULES else # CONFIG_MODULES
# Modules not configured # Modules not configured
......
...@@ -405,6 +405,7 @@ ...@@ -405,6 +405,7 @@
#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376) #define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)
#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) #define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
/* 378 for kcmp */ /* 378 for kcmp */
#define __NR_finit_module (__NR_SYSCALL_BASE+379)
/* /*
* This may need to be greater than __NR_last_syscall+1 in order to * This may need to be greater than __NR_last_syscall+1 in order to
......
...@@ -388,6 +388,7 @@ ...@@ -388,6 +388,7 @@
CALL(sys_process_vm_readv) CALL(sys_process_vm_readv)
CALL(sys_process_vm_writev) CALL(sys_process_vm_writev)
CALL(sys_ni_syscall) /* reserved for sys_kcmp */ CALL(sys_ni_syscall) /* reserved for sys_kcmp */
CALL(sys_finit_module)
#ifndef syscalls_counted #ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted #define syscalls_counted
......
...@@ -32,8 +32,6 @@ ...@@ -32,8 +32,6 @@
#ifdef CONFIG_ETRAX_KMALLOCED_MODULES #ifdef CONFIG_ETRAX_KMALLOCED_MODULES
void *module_alloc(unsigned long size) void *module_alloc(unsigned long size)
{ {
if (size == 0)
return NULL;
return kmalloc(size, GFP_KERNEL); return kmalloc(size, GFP_KERNEL);
} }
......
...@@ -214,8 +214,6 @@ static inline int reassemble_22(int as22) ...@@ -214,8 +214,6 @@ static inline int reassemble_22(int as22)
void *module_alloc(unsigned long size) void *module_alloc(unsigned long size)
{ {
if (size == 0)
return NULL;
/* using RWX means less protection for modules, but it's /* using RWX means less protection for modules, but it's
* easier than trying to map the text, data, init_text and * easier than trying to map the text, data, init_text and
* init_data correctly */ * init_data correctly */
......
...@@ -356,3 +356,4 @@ COMPAT_SYS_SPU(sendmmsg) ...@@ -356,3 +356,4 @@ COMPAT_SYS_SPU(sendmmsg)
SYSCALL_SPU(setns) SYSCALL_SPU(setns)
COMPAT_SYS(process_vm_readv) COMPAT_SYS(process_vm_readv)
COMPAT_SYS(process_vm_writev) COMPAT_SYS(process_vm_writev)
SYSCALL(finit_module)
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <uapi/asm/unistd.h> #include <uapi/asm/unistd.h>
#define __NR_syscalls 353 #define __NR_syscalls 354
#define __NR__exit __NR_exit #define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls #define NR_syscalls __NR_syscalls
......
...@@ -375,6 +375,7 @@ ...@@ -375,6 +375,7 @@
#define __NR_setns 350 #define __NR_setns 350
#define __NR_process_vm_readv 351 #define __NR_process_vm_readv 351
#define __NR_process_vm_writev 352 #define __NR_process_vm_writev 352
#define __NR_finit_module 353
#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
...@@ -43,10 +43,6 @@ void *module_alloc(unsigned long size) ...@@ -43,10 +43,6 @@ void *module_alloc(unsigned long size)
{ {
void *ret; void *ret;
/* We handle the zero case fine, unlike vmalloc */
if (size == 0)
return NULL;
ret = module_map(size); ret = module_map(size);
if (ret) if (ret)
memset(ret, 0, size); memset(ret, 0, size);
......
...@@ -42,8 +42,6 @@ void *module_alloc(unsigned long size) ...@@ -42,8 +42,6 @@ void *module_alloc(unsigned long size)
int i = 0; int i = 0;
int npages; int npages;
if (size == 0)
return NULL;
npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL); pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
if (pages == NULL) if (pages == NULL)
......
...@@ -27,9 +27,6 @@ void *module_alloc(unsigned long size) ...@@ -27,9 +27,6 @@ void *module_alloc(unsigned long size)
struct vm_struct *area; struct vm_struct *area;
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
if (!size)
return NULL;
area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END); area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
if (!area) if (!area)
return NULL; return NULL;
......
...@@ -356,3 +356,4 @@ ...@@ -356,3 +356,4 @@
347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv 347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv
348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev 348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev
349 i386 kcmp sys_kcmp 349 i386 kcmp sys_kcmp
350 i386 finit_module sys_finit_module
...@@ -319,6 +319,7 @@ ...@@ -319,6 +319,7 @@
310 64 process_vm_readv sys_process_vm_readv 310 64 process_vm_readv sys_process_vm_readv
311 64 process_vm_writev sys_process_vm_writev 311 64 process_vm_writev sys_process_vm_writev
312 common kcmp sys_kcmp 312 common kcmp sys_kcmp
313 common finit_module sys_finit_module
# #
# x32-specific system call numbers start at 512 to avoid cache impact # x32-specific system call numbers start at 512 to avoid cache impact
......
...@@ -64,4 +64,6 @@ enum asn1_tag { ...@@ -64,4 +64,6 @@ enum asn1_tag {
ASN1_LONG_TAG = 31 /* Long form tag */ ASN1_LONG_TAG = 31 /* Long form tag */
}; };
#define ASN1_INDEFINITE_LENGTH 0x80
#endif /* _LINUX_ASN1_H */ #endif /* _LINUX_ASN1_H */
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#define __linktime_error(message) __attribute__((__error__(message))) #define __linktime_error(message) __attribute__((__error__(message)))
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
#if __GNUC_MINOR__ >= 5 #if __GNUC_MINOR__ >= 5
/* /*
* Mark a position in code as unreachable. This can be used to * Mark a position in code as unreachable. This can be used to
......
...@@ -44,6 +44,10 @@ extern void __chk_io_ptr(const volatile void __iomem *); ...@@ -44,6 +44,10 @@ extern void __chk_io_ptr(const volatile void __iomem *);
# define __rcu # define __rcu
#endif #endif
/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
#ifdef __KERNEL__ #ifdef __KERNEL__
#ifdef __GNUC__ #ifdef __GNUC__
...@@ -166,6 +170,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); ...@@ -166,6 +170,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
(typeof(ptr)) (__ptr + (off)); }) (typeof(ptr)) (__ptr + (off)); })
#endif #endif
/* Not-quite-unique ID. */
#ifndef __UNIQUE_ID
# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
......
...@@ -18,6 +18,7 @@ extern int ima_bprm_check(struct linux_binprm *bprm); ...@@ -18,6 +18,7 @@ extern int ima_bprm_check(struct linux_binprm *bprm);
extern int ima_file_check(struct file *file, int mask); extern int ima_file_check(struct file *file, int mask);
extern void ima_file_free(struct file *file); extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot); extern int ima_file_mmap(struct file *file, unsigned long prot);
extern int ima_module_check(struct file *file);
#else #else
static inline int ima_bprm_check(struct linux_binprm *bprm) static inline int ima_bprm_check(struct linux_binprm *bprm)
...@@ -40,6 +41,11 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot) ...@@ -40,6 +41,11 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
return 0; return 0;
} }
static inline int ima_module_check(struct file *file)
{
return 0;
}
#endif /* CONFIG_IMA_H */ #endif /* CONFIG_IMA_H */
#ifdef CONFIG_IMA_APPRAISE #ifdef CONFIG_IMA_APPRAISE
......
...@@ -16,17 +16,15 @@ ...@@ -16,17 +16,15 @@
/* Chosen so that structs with an unsigned long line up. */ /* Chosen so that structs with an unsigned long line up. */
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
#define ___module_cat(a,b) __mod_ ## a ## b
#define __module_cat(a,b) ___module_cat(a,b)
#ifdef MODULE #ifdef MODULE
#define __MODULE_INFO(tag, name, info) \ #define __MODULE_INFO(tag, name, info) \
static const char __module_cat(name,__LINE__)[] \ static const char __UNIQUE_ID(name)[] \
__used __attribute__((section(".modinfo"), unused, aligned(1))) \ __used __attribute__((section(".modinfo"), unused, aligned(1))) \
= __stringify(tag) "=" info = __stringify(tag) "=" info
#else /* !MODULE */ #else /* !MODULE */
/* This struct is here for syntactic coherency, it is not used */ /* This struct is here for syntactic coherency, it is not used */
#define __MODULE_INFO(tag, name, info) \ #define __MODULE_INFO(tag, name, info) \
struct __module_cat(name,__LINE__) {} struct __UNIQUE_ID(name) {}
#endif #endif
#define __MODULE_PARM_TYPE(name, _type) \ #define __MODULE_PARM_TYPE(name, _type) \
__MODULE_INFO(parmtype, name##type, #name ":" _type) __MODULE_INFO(parmtype, name##type, #name ":" _type)
......
...@@ -694,6 +694,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -694,6 +694,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* userspace to load a kernel module with the given name. * userspace to load a kernel module with the given name.
* @kmod_name name of the module requested by the kernel * @kmod_name name of the module requested by the kernel
* Return 0 if successful. * Return 0 if successful.
* @kernel_module_from_file:
* Load a kernel module from userspace.
* @file contains the file structure pointing to the file containing
* the kernel module to load. If the module is being loaded from a blob,
* this argument will be NULL.
* Return 0 if permission is granted.
* @task_fix_setuid: * @task_fix_setuid:
* Update the module's state after setting one or more of the user * Update the module's state after setting one or more of the user
* identity attributes of the current process. The @flags parameter * identity attributes of the current process. The @flags parameter
...@@ -1508,6 +1514,7 @@ struct security_operations { ...@@ -1508,6 +1514,7 @@ struct security_operations {
int (*kernel_act_as)(struct cred *new, u32 secid); int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode); int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_module_request)(char *kmod_name); int (*kernel_module_request)(char *kmod_name);
int (*kernel_module_from_file)(struct file *file);
int (*task_fix_setuid) (struct cred *new, const struct cred *old, int (*task_fix_setuid) (struct cred *new, const struct cred *old,
int flags); int flags);
int (*task_setpgid) (struct task_struct *p, pid_t pgid); int (*task_setpgid) (struct task_struct *p, pid_t pgid);
...@@ -1765,6 +1772,7 @@ void security_transfer_creds(struct cred *new, const struct cred *old); ...@@ -1765,6 +1772,7 @@ void security_transfer_creds(struct cred *new, const struct cred *old);
int security_kernel_act_as(struct cred *new, u32 secid); int security_kernel_act_as(struct cred *new, u32 secid);
int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_kernel_module_request(char *kmod_name); int security_kernel_module_request(char *kmod_name);
int security_kernel_module_from_file(struct file *file);
int security_task_fix_setuid(struct cred *new, const struct cred *old, int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags); int flags);
int security_task_setpgid(struct task_struct *p, pid_t pgid); int security_task_setpgid(struct task_struct *p, pid_t pgid);
...@@ -2278,6 +2286,11 @@ static inline int security_kernel_module_request(char *kmod_name) ...@@ -2278,6 +2286,11 @@ static inline int security_kernel_module_request(char *kmod_name)
return 0; return 0;
} }
static inline int security_kernel_module_from_file(struct file *file)
{
return 0;
}
static inline int security_task_fix_setuid(struct cred *new, static inline int security_task_fix_setuid(struct cred *new,
const struct cred *old, const struct cred *old,
int flags) int flags)
......
...@@ -880,4 +880,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid, ...@@ -880,4 +880,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2); unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
#endif #endif
...@@ -690,9 +690,11 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \ ...@@ -690,9 +690,11 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
compat_sys_process_vm_writev) compat_sys_process_vm_writev)
#define __NR_kcmp 272 #define __NR_kcmp 272
__SYSCALL(__NR_kcmp, sys_kcmp) __SYSCALL(__NR_kcmp, sys_kcmp)
#define __NR_finit_module 273
__SYSCALL(__NR_finit_module, sys_finit_module)
#undef __NR_syscalls #undef __NR_syscalls
#define __NR_syscalls 273 #define __NR_syscalls 274
/* /*
* All syscalls below here should go away really, * All syscalls below here should go away really,
......
#ifndef _UAPI_LINUX_MODULE_H
#define _UAPI_LINUX_MODULE_H
/* Flags for sys_finit_module: */
#define MODULE_INIT_IGNORE_MODVERSIONS 1
#define MODULE_INIT_IGNORE_VERMAGIC 2
#endif /* _UAPI_LINUX_MODULE_H */
...@@ -54,7 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o ...@@ -54,7 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
obj-$(CONFIG_PROVE_LOCKING) += spinlock.o obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_KEXEC) += kexec.o
...@@ -137,10 +137,14 @@ ifeq ($(CONFIG_MODULE_SIG),y) ...@@ -137,10 +137,14 @@ ifeq ($(CONFIG_MODULE_SIG),y)
# #
# Pull the signing certificate and any extra certificates into the kernel # Pull the signing certificate and any extra certificates into the kernel
# #
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
extra_certificates: extra_certificates:
touch $@ $(call cmd,touch)
kernel/modsign_pubkey.o: signing_key.x509 extra_certificates kernel/modsign_certificate.o: signing_key.x509 extra_certificates
############################################################################### ###############################################################################
# #
......
/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */
#ifndef SYMBOL_PREFIX
#define ASM_SYMBOL(sym) sym
#else
#define PASTE2(x,y) x##y
#define PASTE(x,y) PASTE2(x,y)
#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
#endif
#define GLOBAL(name) \
.globl ASM_SYMBOL(name); \
ASM_SYMBOL(name):
.section ".init.data","aw"
GLOBAL(modsign_certificate_list)
.incbin "signing_key.x509"
.incbin "extra_certificates"
GLOBAL(modsign_certificate_list_end)
...@@ -20,12 +20,6 @@ struct key *modsign_keyring; ...@@ -20,12 +20,6 @@ struct key *modsign_keyring;
extern __initdata const u8 modsign_certificate_list[]; extern __initdata const u8 modsign_certificate_list[];
extern __initdata const u8 modsign_certificate_list_end[]; extern __initdata const u8 modsign_certificate_list_end[];
asm(".section .init.data,\"aw\"\n"
SYMBOL_PREFIX "modsign_certificate_list:\n"
".incbin \"signing_key.x509\"\n"
".incbin \"extra_certificates\"\n"
SYMBOL_PREFIX "modsign_certificate_list_end:"
);
/* /*
* We need to make sure ccache doesn't cache the .o file as it doesn't notice * We need to make sure ccache doesn't cache the .o file as it doesn't notice
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/ftrace_event.h> #include <linux/ftrace_event.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/file.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/security.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
...@@ -59,6 +61,7 @@ ...@@ -59,6 +61,7 @@
#include <linux/pfn.h> #include <linux/pfn.h>
#include <linux/bsearch.h> #include <linux/bsearch.h>
#include <linux/fips.h> #include <linux/fips.h>
#include <uapi/linux/module.h>
#include "module-internal.h" #include "module-internal.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
...@@ -2279,7 +2282,7 @@ static void layout_symtab(struct module *mod, struct load_info *info) ...@@ -2279,7 +2282,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
Elf_Shdr *symsect = info->sechdrs + info->index.sym; Elf_Shdr *symsect = info->sechdrs + info->index.sym;
Elf_Shdr *strsect = info->sechdrs + info->index.str; Elf_Shdr *strsect = info->sechdrs + info->index.str;
const Elf_Sym *src; const Elf_Sym *src;
unsigned int i, nsrc, ndst, strtab_size; unsigned int i, nsrc, ndst, strtab_size = 0;
/* Put symbol section at end of init part of module. */ /* Put symbol section at end of init part of module. */
symsect->sh_flags |= SHF_ALLOC; symsect->sh_flags |= SHF_ALLOC;
...@@ -2290,9 +2293,6 @@ static void layout_symtab(struct module *mod, struct load_info *info) ...@@ -2290,9 +2293,6 @@ static void layout_symtab(struct module *mod, struct load_info *info)
src = (void *)info->hdr + symsect->sh_offset; src = (void *)info->hdr + symsect->sh_offset;
nsrc = symsect->sh_size / sizeof(*src); nsrc = symsect->sh_size / sizeof(*src);
/* strtab always starts with a nul, so offset 0 is the empty string. */
strtab_size = 1;
/* Compute total space required for the core symbols' strtab. */ /* Compute total space required for the core symbols' strtab. */
for (ndst = i = 0; i < nsrc; i++) { for (ndst = i = 0; i < nsrc; i++) {
if (i == 0 || if (i == 0 ||
...@@ -2334,7 +2334,6 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) ...@@ -2334,7 +2334,6 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
mod->core_symtab = dst = mod->module_core + info->symoffs; mod->core_symtab = dst = mod->module_core + info->symoffs;
mod->core_strtab = s = mod->module_core + info->stroffs; mod->core_strtab = s = mod->module_core + info->stroffs;
src = mod->symtab; src = mod->symtab;
*s++ = 0;
for (ndst = i = 0; i < mod->num_symtab; i++) { for (ndst = i = 0; i < mod->num_symtab; i++) {
if (i == 0 || if (i == 0 ||
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) { is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
...@@ -2375,7 +2374,7 @@ static void dynamic_debug_remove(struct _ddebug *debug) ...@@ -2375,7 +2374,7 @@ static void dynamic_debug_remove(struct _ddebug *debug)
void * __weak module_alloc(unsigned long size) void * __weak module_alloc(unsigned long size)
{ {
return size == 0 ? NULL : vmalloc_exec(size); return vmalloc_exec(size);
} }
static void *module_alloc_update_bounds(unsigned long size) static void *module_alloc_update_bounds(unsigned long size)
...@@ -2422,18 +2421,17 @@ static inline void kmemleak_load_module(const struct module *mod, ...@@ -2422,18 +2421,17 @@ static inline void kmemleak_load_module(const struct module *mod,
#endif #endif
#ifdef CONFIG_MODULE_SIG #ifdef CONFIG_MODULE_SIG
static int module_sig_check(struct load_info *info, static int module_sig_check(struct load_info *info)
const void *mod, unsigned long *_len)
{ {
int err = -ENOKEY; int err = -ENOKEY;
unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
unsigned long len = *_len; const void *mod = info->hdr;
if (len > markerlen && if (info->len > markerlen &&
memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
/* We truncate the module to discard the signature */ /* We truncate the module to discard the signature */
*_len -= markerlen; info->len -= markerlen;
err = mod_verify_sig(mod, _len); err = mod_verify_sig(mod, &info->len);
} }
if (!err) { if (!err) {
...@@ -2451,59 +2449,107 @@ static int module_sig_check(struct load_info *info, ...@@ -2451,59 +2449,107 @@ static int module_sig_check(struct load_info *info,
return err; return err;
} }
#else /* !CONFIG_MODULE_SIG */ #else /* !CONFIG_MODULE_SIG */
static int module_sig_check(struct load_info *info, static int module_sig_check(struct load_info *info)
void *mod, unsigned long *len)
{ {
return 0; return 0;
} }
#endif /* !CONFIG_MODULE_SIG */ #endif /* !CONFIG_MODULE_SIG */
/* Sets info->hdr, info->len and info->sig_ok. */ /* Sanity checks against invalid binaries, wrong arch, weird elf version. */
static int copy_and_check(struct load_info *info, static int elf_header_check(struct load_info *info)
const void __user *umod, unsigned long len, {
const char __user *uargs) if (info->len < sizeof(*(info->hdr)))
return -ENOEXEC;
if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
|| info->hdr->e_type != ET_REL
|| !elf_check_arch(info->hdr)
|| info->hdr->e_shentsize != sizeof(Elf_Shdr))
return -ENOEXEC;
if (info->hdr->e_shoff >= info->len
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >
info->len - info->hdr->e_shoff))
return -ENOEXEC;
return 0;
}
/* Sets info->hdr and info->len. */
static int copy_module_from_user(const void __user *umod, unsigned long len,
struct load_info *info)
{ {
int err; int err;
Elf_Ehdr *hdr;
if (len < sizeof(*hdr)) info->len = len;
if (info->len < sizeof(*(info->hdr)))
return -ENOEXEC; return -ENOEXEC;
err = security_kernel_module_from_file(NULL);
if (err)
return err;
/* Suck in entire file: we'll want most of it. */ /* Suck in entire file: we'll want most of it. */
if ((hdr = vmalloc(len)) == NULL) info->hdr = vmalloc(info->len);
if (!info->hdr)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(hdr, umod, len) != 0) { if (copy_from_user(info->hdr, umod, info->len) != 0) {
err = -EFAULT; vfree(info->hdr);
goto free_hdr; return -EFAULT;
} }
err = module_sig_check(info, hdr, &len); return 0;
}
/* Sets info->hdr and info->len. */
static int copy_module_from_fd(int fd, struct load_info *info)
{
struct file *file;
int err;
struct kstat stat;
loff_t pos;
ssize_t bytes = 0;
file = fget(fd);
if (!file)
return -ENOEXEC;
err = security_kernel_module_from_file(file);
if (err) if (err)
goto free_hdr; goto out;
/* Sanity checks against insmoding binaries or wrong arch, err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
weird elf version */ if (err)
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 goto out;
|| hdr->e_type != ET_REL
|| !elf_check_arch(hdr)
|| hdr->e_shentsize != sizeof(Elf_Shdr)) {
err = -ENOEXEC;
goto free_hdr;
}
if (hdr->e_shoff >= len || if (stat.size > INT_MAX) {
hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) { err = -EFBIG;
err = -ENOEXEC; goto out;
goto free_hdr; }
info->hdr = vmalloc(stat.size);
if (!info->hdr) {
err = -ENOMEM;
goto out;
} }
info->hdr = hdr; pos = 0;
info->len = len; while (pos < stat.size) {
return 0; bytes = kernel_read(file, pos, (char *)(info->hdr) + pos,
stat.size - pos);
if (bytes < 0) {
vfree(info->hdr);
err = bytes;
goto out;
}
if (bytes == 0)
break;
pos += bytes;
}
info->len = pos;
free_hdr: out:
vfree(hdr); fput(file);
return err; return err;
} }
...@@ -2512,7 +2558,7 @@ static void free_copy(struct load_info *info) ...@@ -2512,7 +2558,7 @@ static void free_copy(struct load_info *info)
vfree(info->hdr); vfree(info->hdr);
} }
static int rewrite_section_headers(struct load_info *info) static int rewrite_section_headers(struct load_info *info, int flags)
{ {
unsigned int i; unsigned int i;
...@@ -2540,6 +2586,9 @@ static int rewrite_section_headers(struct load_info *info) ...@@ -2540,6 +2586,9 @@ static int rewrite_section_headers(struct load_info *info)
} }
/* Track but don't keep modinfo and version sections. */ /* Track but don't keep modinfo and version sections. */
if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
info->index.vers = 0; /* Pretend no __versions section! */
else
info->index.vers = find_sec(info, "__versions"); info->index.vers = find_sec(info, "__versions");
info->index.info = find_sec(info, ".modinfo"); info->index.info = find_sec(info, ".modinfo");
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC; info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
...@@ -2555,7 +2604,7 @@ static int rewrite_section_headers(struct load_info *info) ...@@ -2555,7 +2604,7 @@ static int rewrite_section_headers(struct load_info *info)
* Return the temporary module pointer (we'll replace it with the final * Return the temporary module pointer (we'll replace it with the final
* one when we move the module sections around). * one when we move the module sections around).
*/ */
static struct module *setup_load_info(struct load_info *info) static struct module *setup_load_info(struct load_info *info, int flags)
{ {
unsigned int i; unsigned int i;
int err; int err;
...@@ -2566,7 +2615,7 @@ static struct module *setup_load_info(struct load_info *info) ...@@ -2566,7 +2615,7 @@ static struct module *setup_load_info(struct load_info *info)
info->secstrings = (void *)info->hdr info->secstrings = (void *)info->hdr
+ info->sechdrs[info->hdr->e_shstrndx].sh_offset; + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
err = rewrite_section_headers(info); err = rewrite_section_headers(info, flags);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
...@@ -2604,11 +2653,14 @@ static struct module *setup_load_info(struct load_info *info) ...@@ -2604,11 +2653,14 @@ static struct module *setup_load_info(struct load_info *info)
return mod; return mod;
} }
static int check_modinfo(struct module *mod, struct load_info *info) static int check_modinfo(struct module *mod, struct load_info *info, int flags)
{ {
const char *modmagic = get_modinfo(info, "vermagic"); const char *modmagic = get_modinfo(info, "vermagic");
int err; int err;
if (flags & MODULE_INIT_IGNORE_VERMAGIC)
modmagic = NULL;
/* This is allowed: modprobe --force will invalidate it. */ /* This is allowed: modprobe --force will invalidate it. */
if (!modmagic) { if (!modmagic) {
err = try_to_force_load(mod, "bad vermagic"); err = try_to_force_load(mod, "bad vermagic");
...@@ -2738,6 +2790,7 @@ static int move_module(struct module *mod, struct load_info *info) ...@@ -2738,6 +2790,7 @@ static int move_module(struct module *mod, struct load_info *info)
memset(ptr, 0, mod->core_size); memset(ptr, 0, mod->core_size);
mod->module_core = ptr; mod->module_core = ptr;
if (mod->init_size) {
ptr = module_alloc_update_bounds(mod->init_size); ptr = module_alloc_update_bounds(mod->init_size);
/* /*
* The pointer to this block is stored in the module structure * The pointer to this block is stored in the module structure
...@@ -2746,12 +2799,14 @@ static int move_module(struct module *mod, struct load_info *info) ...@@ -2746,12 +2799,14 @@ static int move_module(struct module *mod, struct load_info *info)
* after the module is initialized. * after the module is initialized.
*/ */
kmemleak_ignore(ptr); kmemleak_ignore(ptr);
if (!ptr && mod->init_size) { if (!ptr) {
module_free(mod, mod->module_core); module_free(mod, mod->module_core);
return -ENOMEM; return -ENOMEM;
} }
memset(ptr, 0, mod->init_size); memset(ptr, 0, mod->init_size);
mod->module_init = ptr; mod->module_init = ptr;
} else
mod->module_init = NULL;
/* Transfer each section which specifies SHF_ALLOC */ /* Transfer each section which specifies SHF_ALLOC */
pr_debug("final section addresses:\n"); pr_debug("final section addresses:\n");
...@@ -2844,18 +2899,18 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr, ...@@ -2844,18 +2899,18 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
return 0; return 0;
} }
static struct module *layout_and_allocate(struct load_info *info) static struct module *layout_and_allocate(struct load_info *info, int flags)
{ {
/* Module within temporary copy. */ /* Module within temporary copy. */
struct module *mod; struct module *mod;
Elf_Shdr *pcpusec; Elf_Shdr *pcpusec;
int err; int err;
mod = setup_load_info(info); mod = setup_load_info(info, flags);
if (IS_ERR(mod)) if (IS_ERR(mod))
return mod; return mod;
err = check_modinfo(mod, info); err = check_modinfo(mod, info, flags);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
...@@ -2942,33 +2997,124 @@ static bool finished_loading(const char *name) ...@@ -2942,33 +2997,124 @@ static bool finished_loading(const char *name)
return ret; return ret;
} }
/* Call module constructors. */
static void do_mod_ctors(struct module *mod)
{
#ifdef CONFIG_CONSTRUCTORS
unsigned long i;
for (i = 0; i < mod->num_ctors; i++)
mod->ctors[i]();
#endif
}
/* This is where the real work happens */
static int do_init_module(struct module *mod)
{
int ret = 0;
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_COMING, mod);
/* Set RO and NX regions for core */
set_section_ro_nx(mod->module_core,
mod->core_text_size,
mod->core_ro_size,
mod->core_size);
/* Set RO and NX regions for init */
set_section_ro_nx(mod->module_init,
mod->init_text_size,
mod->init_ro_size,
mod->init_size);
do_mod_ctors(mod);
/* Start the module */
if (mod->init != NULL)
ret = do_one_initcall(mod->init);
if (ret < 0) {
/* Init routine failed: abort. Try to protect us from
buggy refcounters. */
mod->state = MODULE_STATE_GOING;
synchronize_sched();
module_put(mod);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
free_module(mod);
wake_up_all(&module_wq);
return ret;
}
if (ret > 0) {
printk(KERN_WARNING
"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
"%s: loading module anyway...\n",
__func__, mod->name, ret,
__func__);
dump_stack();
}
/* Now it's a first class citizen! */
mod->state = MODULE_STATE_LIVE;
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_LIVE, mod);
/* We need to finish all async code before the module init sequence is done */
async_synchronize_full();
mutex_lock(&module_mutex);
/* Drop initial reference. */
module_put(mod);
trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
mod->num_symtab = mod->core_num_syms;
mod->symtab = mod->core_symtab;
mod->strtab = mod->core_strtab;
#endif
unset_module_init_ro_nx(mod);
module_free(mod, mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
mod->init_ro_size = 0;
mod->init_text_size = 0;
mutex_unlock(&module_mutex);
wake_up_all(&module_wq);
return 0;
}
static int may_init_module(void)
{
if (!capable(CAP_SYS_MODULE) || modules_disabled)
return -EPERM;
return 0;
}
/* Allocate and load the module: note that size of section 0 is always /* Allocate and load the module: note that size of section 0 is always
zero, and we rely on this for optional sections. */ zero, and we rely on this for optional sections. */
static struct module *load_module(void __user *umod, static int load_module(struct load_info *info, const char __user *uargs,
unsigned long len, int flags)
const char __user *uargs)
{ {
struct load_info info = { NULL, };
struct module *mod, *old; struct module *mod, *old;
long err; long err;
pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", err = module_sig_check(info);
umod, len, uargs); if (err)
goto free_copy;
/* Copy in the blobs from userspace, check they are vaguely sane. */ err = elf_header_check(info);
err = copy_and_check(&info, umod, len, uargs);
if (err) if (err)
return ERR_PTR(err); goto free_copy;
/* Figure out module layout, and allocate all the memory. */ /* Figure out module layout, and allocate all the memory. */
mod = layout_and_allocate(&info); mod = layout_and_allocate(info, flags);
if (IS_ERR(mod)) { if (IS_ERR(mod)) {
err = PTR_ERR(mod); err = PTR_ERR(mod);
goto free_copy; goto free_copy;
} }
#ifdef CONFIG_MODULE_SIG #ifdef CONFIG_MODULE_SIG
mod->sig_ok = info.sig_ok; mod->sig_ok = info->sig_ok;
if (!mod->sig_ok) if (!mod->sig_ok)
add_taint_module(mod, TAINT_FORCED_MODULE); add_taint_module(mod, TAINT_FORCED_MODULE);
#endif #endif
...@@ -2980,25 +3126,25 @@ static struct module *load_module(void __user *umod, ...@@ -2980,25 +3126,25 @@ static struct module *load_module(void __user *umod,
/* Now we've got everything in the final locations, we can /* Now we've got everything in the final locations, we can
* find optional sections. */ * find optional sections. */
find_module_sections(mod, &info); find_module_sections(mod, info);
err = check_module_license_and_versions(mod); err = check_module_license_and_versions(mod);
if (err) if (err)
goto free_unload; goto free_unload;
/* Set up MODINFO_ATTR fields */ /* Set up MODINFO_ATTR fields */
setup_modinfo(mod, &info); setup_modinfo(mod, info);
/* Fix up syms, so that st_value is a pointer to location. */ /* Fix up syms, so that st_value is a pointer to location. */
err = simplify_symbols(mod, &info); err = simplify_symbols(mod, info);
if (err < 0) if (err < 0)
goto free_modinfo; goto free_modinfo;
err = apply_relocations(mod, &info); err = apply_relocations(mod, info);
if (err < 0) if (err < 0)
goto free_modinfo; goto free_modinfo;
err = post_relocation(mod, &info); err = post_relocation(mod, info);
if (err < 0) if (err < 0)
goto free_modinfo; goto free_modinfo;
...@@ -3038,14 +3184,14 @@ static struct module *load_module(void __user *umod, ...@@ -3038,14 +3184,14 @@ static struct module *load_module(void __user *umod,
} }
/* This has to be done once we're sure module name is unique. */ /* This has to be done once we're sure module name is unique. */
dynamic_debug_setup(info.debug, info.num_debug); dynamic_debug_setup(info->debug, info->num_debug);
/* Find duplicate symbols */ /* Find duplicate symbols */
err = verify_export_symbols(mod); err = verify_export_symbols(mod);
if (err < 0) if (err < 0)
goto ddebug; goto ddebug;
module_bug_finalize(info.hdr, info.sechdrs, mod); module_bug_finalize(info->hdr, info->sechdrs, mod);
list_add_rcu(&mod->list, &modules); list_add_rcu(&mod->list, &modules);
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
...@@ -3056,16 +3202,17 @@ static struct module *load_module(void __user *umod, ...@@ -3056,16 +3202,17 @@ static struct module *load_module(void __user *umod,
goto unlink; goto unlink;
/* Link in to syfs. */ /* Link in to syfs. */
err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp); err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
if (err < 0) if (err < 0)
goto unlink; goto unlink;
/* Get rid of temporary copy. */ /* Get rid of temporary copy. */
free_copy(&info); free_copy(info);
/* Done! */ /* Done! */
trace_module_load(mod); trace_module_load(mod);
return mod;
return do_init_module(mod);
unlink: unlink:
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
...@@ -3074,7 +3221,7 @@ static struct module *load_module(void __user *umod, ...@@ -3074,7 +3221,7 @@ static struct module *load_module(void __user *umod,
module_bug_cleanup(mod); module_bug_cleanup(mod);
wake_up_all(&module_wq); wake_up_all(&module_wq);
ddebug: ddebug:
dynamic_debug_remove(info.debug); dynamic_debug_remove(info->debug);
unlock: unlock:
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
synchronize_sched(); synchronize_sched();
...@@ -3086,106 +3233,52 @@ static struct module *load_module(void __user *umod, ...@@ -3086,106 +3233,52 @@ static struct module *load_module(void __user *umod,
free_unload: free_unload:
module_unload_free(mod); module_unload_free(mod);
free_module: free_module:
module_deallocate(mod, &info); module_deallocate(mod, info);
free_copy: free_copy:
free_copy(&info); free_copy(info);
return ERR_PTR(err); return err;
}
/* Call module constructors. */
static void do_mod_ctors(struct module *mod)
{
#ifdef CONFIG_CONSTRUCTORS
unsigned long i;
for (i = 0; i < mod->num_ctors; i++)
mod->ctors[i]();
#endif
} }
/* This is where the real work happens */
SYSCALL_DEFINE3(init_module, void __user *, umod, SYSCALL_DEFINE3(init_module, void __user *, umod,
unsigned long, len, const char __user *, uargs) unsigned long, len, const char __user *, uargs)
{ {
struct module *mod; int err;
int ret = 0; struct load_info info = { };
/* Must have permission */ err = may_init_module();
if (!capable(CAP_SYS_MODULE) || modules_disabled) if (err)
return -EPERM; return err;
/* Do all the hard work */ pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
mod = load_module(umod, len, uargs); umod, len, uargs);
if (IS_ERR(mod))
return PTR_ERR(mod);
blocking_notifier_call_chain(&module_notify_list, err = copy_module_from_user(umod, len, &info);
MODULE_STATE_COMING, mod); if (err)
return err;
/* Set RO and NX regions for core */ return load_module(&info, uargs, 0);
set_section_ro_nx(mod->module_core, }
mod->core_text_size,
mod->core_ro_size,
mod->core_size);
/* Set RO and NX regions for init */ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
set_section_ro_nx(mod->module_init, {
mod->init_text_size, int err;
mod->init_ro_size, struct load_info info = { };
mod->init_size);
do_mod_ctors(mod); err = may_init_module();
/* Start the module */ if (err)
if (mod->init != NULL) return err;
ret = do_one_initcall(mod->init);
if (ret < 0) {
/* Init routine failed: abort. Try to protect us from
buggy refcounters. */
mod->state = MODULE_STATE_GOING;
synchronize_sched();
module_put(mod);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
free_module(mod);
wake_up_all(&module_wq);
return ret;
}
if (ret > 0) {
printk(KERN_WARNING
"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
"%s: loading module anyway...\n",
__func__, mod->name, ret,
__func__);
dump_stack();
}
/* Now it's a first class citizen! */ pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
mod->state = MODULE_STATE_LIVE;
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_LIVE, mod);
/* We need to finish all async code before the module init sequence is done */ if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
async_synchronize_full(); |MODULE_INIT_IGNORE_VERMAGIC))
return -EINVAL;
mutex_lock(&module_mutex); err = copy_module_from_fd(fd, &info);
/* Drop initial reference. */ if (err)
module_put(mod); return err;
trim_init_extable(mod);
#ifdef CONFIG_KALLSYMS
mod->num_symtab = mod->core_num_syms;
mod->symtab = mod->core_symtab;
mod->strtab = mod->core_strtab;
#endif
unset_module_init_ro_nx(mod);
module_free(mod, mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
mod->init_ro_size = 0;
mod->init_text_size = 0;
mutex_unlock(&module_mutex);
wake_up_all(&module_wq);
return 0; return load_module(&info, uargs, flags);
} }
static inline int within(unsigned long addr, void *start, unsigned long size) static inline int within(unsigned long addr, void *start, unsigned long size)
......
...@@ -25,6 +25,7 @@ cond_syscall(sys_swapoff); ...@@ -25,6 +25,7 @@ cond_syscall(sys_swapoff);
cond_syscall(sys_kexec_load); cond_syscall(sys_kexec_load);
cond_syscall(compat_sys_kexec_load); cond_syscall(compat_sys_kexec_load);
cond_syscall(sys_init_module); cond_syscall(sys_init_module);
cond_syscall(sys_finit_module);
cond_syscall(sys_delete_module); cond_syscall(sys_delete_module);
cond_syscall(sys_socketpair); cond_syscall(sys_socketpair);
cond_syscall(sys_bind); cond_syscall(sys_bind);
......
...@@ -81,7 +81,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen ...@@ -81,7 +81,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
goto next_tag; goto next_tag;
} }
if (unlikely((tag & 0x1f) == 0x1f)) { if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) {
do { do {
if (unlikely(datalen - dp < 2)) if (unlikely(datalen - dp < 2))
goto data_overrun_error; goto data_overrun_error;
...@@ -96,7 +96,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen ...@@ -96,7 +96,7 @@ static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen
goto next_tag; goto next_tag;
} }
if (unlikely(len == 0x80)) { if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
/* Indefinite length */ /* Indefinite length */
if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5)) if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5))
goto indefinite_len_primitive; goto indefinite_len_primitive;
...@@ -222,7 +222,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -222,7 +222,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
if (unlikely(dp >= datalen - 1)) if (unlikely(dp >= datalen - 1))
goto data_overrun_error; goto data_overrun_error;
tag = data[dp++]; tag = data[dp++];
if (unlikely((tag & 0x1f) == 0x1f)) if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
goto long_tag_not_supported; goto long_tag_not_supported;
if (op & ASN1_OP_MATCH__ANY) { if (op & ASN1_OP_MATCH__ANY) {
...@@ -254,7 +254,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, ...@@ -254,7 +254,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder,
len = data[dp++]; len = data[dp++];
if (len > 0x7f) { if (len > 0x7f) {
if (unlikely(len == 0x80)) { if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
/* Indefinite length */ /* Indefinite length */
if (unlikely(!(tag & ASN1_CONS_BIT))) if (unlikely(!(tag & ASN1_CONS_BIT)))
goto indefinite_len_primitive; goto indefinite_len_primitive;
......
# ==========================================================================
# Signing modules
# ==========================================================================
PHONY := __modsign
__modsign:
include scripts/Kbuild.include
__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
PHONY += $(modules)
__modsign: $(modules)
@:
quiet_cmd_sign_ko = SIGN [M] $(2)/$(notdir $@)
cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@)
# Modules built outside the kernel source tree go into extra by default
INSTALL_MOD_DIR ?= extra
ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
$(modules):
$(call cmd,sign_ko,$(MODLIB)/$(modinst_dir))
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable se we can use it in if_changed and friends.
.PHONY: $(PHONY)
...@@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name) ...@@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name)
return 0; return 0;
} }
static int cap_kernel_module_from_file(struct file *file)
{
return 0;
}
static int cap_task_setpgid(struct task_struct *p, pid_t pgid) static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
{ {
return 0; return 0;
...@@ -967,6 +972,7 @@ void __init security_fixup_ops(struct security_operations *ops) ...@@ -967,6 +972,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, kernel_act_as); set_to_cap_if_null(ops, kernel_act_as);
set_to_cap_if_null(ops, kernel_create_files_as); set_to_cap_if_null(ops, kernel_create_files_as);
set_to_cap_if_null(ops, kernel_module_request); set_to_cap_if_null(ops, kernel_module_request);
set_to_cap_if_null(ops, kernel_module_from_file);
set_to_cap_if_null(ops, task_fix_setuid); set_to_cap_if_null(ops, task_fix_setuid);
set_to_cap_if_null(ops, task_setpgid); set_to_cap_if_null(ops, task_setpgid);
set_to_cap_if_null(ops, task_getpgid); set_to_cap_if_null(ops, task_getpgid);
......
...@@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); ...@@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode); struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
/* IMA policy related functions */ /* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR }; enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags); int flags);
......
...@@ -100,12 +100,12 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename, ...@@ -100,12 +100,12 @@ void ima_add_violation(struct inode *inode, const unsigned char *filename,
* ima_get_action - appraise & measure decision based on policy. * ima_get_action - appraise & measure decision based on policy.
* @inode: pointer to inode to measure * @inode: pointer to inode to measure
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE) * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
* @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP) * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP, MODULE_CHECK)
* *
* The policy is defined in terms of keypairs: * The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic= * subj=, obj=, type=, func=, mask=, fsmagic=
* subj,obj, and type: are LSM specific. * subj,obj, and type: are LSM specific.
* func: FILE_CHECK | BPRM_CHECK | FILE_MMAP * func: FILE_CHECK | BPRM_CHECK | FILE_MMAP | MODULE_CHECK
* mask: contains the permission mask * mask: contains the permission mask
* fsmagic: hex value * fsmagic: hex value
* *
......
...@@ -280,6 +280,27 @@ int ima_file_check(struct file *file, int mask) ...@@ -280,6 +280,27 @@ int ima_file_check(struct file *file, int mask)
} }
EXPORT_SYMBOL_GPL(ima_file_check); EXPORT_SYMBOL_GPL(ima_file_check);
/**
* ima_module_check - based on policy, collect/store/appraise measurement.
* @file: pointer to the file to be measured/appraised
*
* Measure/appraise kernel modules based on policy.
*
* Always return 0 and audit dentry_open failures.
* Return code is based upon measurement appraisal.
*/
int ima_module_check(struct file *file)
{
int rc;
if (!file)
rc = INTEGRITY_UNKNOWN;
else
rc = process_measurement(file, file->f_dentry->d_name.name,
MAY_EXEC, MODULE_CHECK);
return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
}
static int __init init_ima(void) static int __init init_ima(void)
{ {
int error; int error;
......
...@@ -80,6 +80,7 @@ static struct ima_rule_entry default_rules[] = { ...@@ -80,6 +80,7 @@ static struct ima_rule_entry default_rules[] = {
.flags = IMA_FUNC | IMA_MASK}, .flags = IMA_FUNC | IMA_MASK},
{.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID, {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID,
.flags = IMA_FUNC | IMA_MASK | IMA_UID}, .flags = IMA_FUNC | IMA_MASK | IMA_UID},
{.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC},
}; };
static struct ima_rule_entry default_appraise_rules[] = { static struct ima_rule_entry default_appraise_rules[] = {
...@@ -401,6 +402,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) ...@@ -401,6 +402,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
/* PATH_CHECK is for backwards compat */ /* PATH_CHECK is for backwards compat */
else if (strcmp(args[0].from, "PATH_CHECK") == 0) else if (strcmp(args[0].from, "PATH_CHECK") == 0)
entry->func = FILE_CHECK; entry->func = FILE_CHECK;
else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
entry->func = MODULE_CHECK;
else if (strcmp(args[0].from, "FILE_MMAP") == 0) else if (strcmp(args[0].from, "FILE_MMAP") == 0)
entry->func = FILE_MMAP; entry->func = FILE_MMAP;
else if (strcmp(args[0].from, "BPRM_CHECK") == 0) else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
......
...@@ -820,6 +820,16 @@ int security_kernel_module_request(char *kmod_name) ...@@ -820,6 +820,16 @@ int security_kernel_module_request(char *kmod_name)
return security_ops->kernel_module_request(kmod_name); return security_ops->kernel_module_request(kmod_name);
} }
int security_kernel_module_from_file(struct file *file)
{
int ret;
ret = security_ops->kernel_module_from_file(file);
if (ret)
return ret;
return ima_module_check(file);
}
int security_task_fix_setuid(struct cred *new, const struct cred *old, int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags) int flags)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment