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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJQ0VKlAAoJENkgDmzRrbjxjuEQALVHpD1cSmryOzVwkNn7rVGP PV3KVbUs+qzUCm2c3AafIIlSBm2LOUl+cR3uNC7di8aHarRF3VHkK2OQ4Fx97ECd KKBqAyY3R0q1mAKujb/MWwiK0YgosEDIOzGGn2yQhNFsxKqnMB02P4j82IO7+g+w Cc3XuDyWHoH2I+ySgz0Q8NHAqufD/DMZUKud7jw2Lsv6PuICJ1Oqgl/Gd/muxort 4a5tV3tjhRGywHS/8b2fbDUXkybC5NKK0FN+gyoaROmJ/THeHEQDGXZT9bc2vmVx HvRy/5k8dzQ6LAJ2mLnPvy0pmv0u7NYMvjxTxxUlUkFMkYuVticikQfwSYDbDPt4 mbsLxchpgi8z4x8HltEERffCX5tldo/5hz1uemqhqIsMRIrRFnlHkSIgkGjVHf2u LXQBLT8uTm6C0VyNQPrI/hUZzIax7WtKbPSoK9lmExNbKqloEFh/mVXvfQxei2kp wnUZcnmPIqSvw7b4CWu7HibMYu2VvGBgm3YIfJRi4AQme1mzFYLpZoxF5Pj+Ykbt T//Hb1EsNQTTFCg7MZhnJSAw/EVUvNDUoullORClyqw6+xxjVKqWpPJgYDRfWOlJ Xa+s7DNrL+Oo1WWR8l5ruoQszbR8szIyeyPKKxRUcQj2zsqghoWuzKAx2saSEw3W pNkoJU+dGC7kG/yVAS8N =uoJj -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7a684c452e
36 changed files with 497 additions and 273 deletions
|
@ -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:
|
||||||
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,
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -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 @@
|
||||||
#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 @@
|
||||||
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 @@
|
||||||
#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)
|
||||||
|
|
||||||
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)
|
||||||
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 @@
|
||||||
#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 @@
|
||||||
#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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
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 @@
|
||||||
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 @@
|
||||||
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 {
|
||||||
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 @@
|
||||||
|
|
||||||
#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 *);
|
||||||
# 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);
|
||||||
(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);
|
||||||
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)
|
||||||
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 @@
|
||||||
/* 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)
|
||||||
* 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 {
|
||||||
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);
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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, \
|
||||||
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,
|
||||||
|
|
8
include/uapi/linux/module.h
Normal file
8
include/uapi/linux/module.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#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
|
||||||
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)
|
||||||
#
|
#
|
||||||
# Pull the signing certificate and any extra certificates into the kernel
|
# Pull the signing certificate and any extra certificates into the kernel
|
||||||
#
|
#
|
||||||
extra_certificates:
|
|
||||||
touch $@
|
|
||||||
|
|
||||||
kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
|
quiet_cmd_touch = TOUCH $@
|
||||||
|
cmd_touch = touch $@
|
||||||
|
|
||||||
|
extra_certificates:
|
||||||
|
$(call cmd,touch)
|
||||||
|
|
||||||
|
kernel/modsign_certificate.o: signing_key.x509 extra_certificates
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
#
|
#
|
||||||
|
|
19
kernel/modsign_certificate.S
Normal file
19
kernel/modsign_certificate.S
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
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
|
||||||
|
|
565
kernel/module.c
565
kernel/module.c
|
@ -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 @@
|
||||||
#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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
#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,
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int err;
|
if (info->len < sizeof(*(info->hdr)))
|
||||||
Elf_Ehdr *hdr;
|
|
||||||
|
|
||||||
if (len < sizeof(*hdr))
|
|
||||||
return -ENOEXEC;
|
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;
|
||||||
|
|
||||||
|
info->len = len;
|
||||||
|
if (info->len < sizeof(*(info->hdr)))
|
||||||
|
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);
|
|
||||||
if (err)
|
|
||||||
goto free_hdr;
|
|
||||||
|
|
||||||
/* Sanity checks against insmoding binaries or wrong arch,
|
|
||||||
weird elf version */
|
|
||||||
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
|
|
||||||
|| 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 ||
|
|
||||||
hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) {
|
|
||||||
err = -ENOEXEC;
|
|
||||||
goto free_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
info->hdr = hdr;
|
|
||||||
info->len = len;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
free_hdr:
|
/* Sets info->hdr and info->len. */
|
||||||
vfree(hdr);
|
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)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (stat.size > INT_MAX) {
|
||||||
|
err = -EFBIG;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
info->hdr = vmalloc(stat.size);
|
||||||
|
if (!info->hdr) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while (pos < stat.size) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
out:
|
||||||
|
fput(file);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,7 +2586,10 @@ 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. */
|
||||||
info->index.vers = find_sec(info, "__versions");
|
if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
|
||||||
|
info->index.vers = 0; /* Pretend no __versions section! */
|
||||||
|
else
|
||||||
|
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;
|
||||||
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
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,20 +2790,23 @@ 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;
|
||||||
|
|
||||||
ptr = module_alloc_update_bounds(mod->init_size);
|
if (mod->init_size) {
|
||||||
/*
|
ptr = module_alloc_update_bounds(mod->init_size);
|
||||||
* The pointer to this block is stored in the module structure
|
/*
|
||||||
* which is inside the block. This block doesn't need to be
|
* The pointer to this block is stored in the module structure
|
||||||
* scanned as it contains data and code that will be freed
|
* which is inside the block. This block doesn't need to be
|
||||||
* after the module is initialized.
|
* scanned as it contains data and code that will be freed
|
||||||
*/
|
* after the module is initialized.
|
||||||
kmemleak_ignore(ptr);
|
*/
|
||||||
if (!ptr && mod->init_size) {
|
kmemleak_ignore(ptr);
|
||||||
module_free(mod, mod->module_core);
|
if (!ptr) {
|
||||||
return -ENOMEM;
|
module_free(mod, mod->module_core);
|
||||||
}
|
return -ENOMEM;
|
||||||
memset(ptr, 0, mod->init_size);
|
}
|
||||||
mod->module_init = ptr;
|
memset(ptr, 0, mod->init_size);
|
||||||
|
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,
|
||||||
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,156 +2997,6 @@ static bool finished_loading(const char *name)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and load the module: note that size of section 0 is always
|
|
||||||
zero, and we rely on this for optional sections. */
|
|
||||||
static struct module *load_module(void __user *umod,
|
|
||||||
unsigned long len,
|
|
||||||
const char __user *uargs)
|
|
||||||
{
|
|
||||||
struct load_info info = { NULL, };
|
|
||||||
struct module *mod, *old;
|
|
||||||
long err;
|
|
||||||
|
|
||||||
pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
|
|
||||||
umod, len, uargs);
|
|
||||||
|
|
||||||
/* Copy in the blobs from userspace, check they are vaguely sane. */
|
|
||||||
err = copy_and_check(&info, umod, len, uargs);
|
|
||||||
if (err)
|
|
||||||
return ERR_PTR(err);
|
|
||||||
|
|
||||||
/* Figure out module layout, and allocate all the memory. */
|
|
||||||
mod = layout_and_allocate(&info);
|
|
||||||
if (IS_ERR(mod)) {
|
|
||||||
err = PTR_ERR(mod);
|
|
||||||
goto free_copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_MODULE_SIG
|
|
||||||
mod->sig_ok = info.sig_ok;
|
|
||||||
if (!mod->sig_ok)
|
|
||||||
add_taint_module(mod, TAINT_FORCED_MODULE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Now module is in final location, initialize linked lists, etc. */
|
|
||||||
err = module_unload_init(mod);
|
|
||||||
if (err)
|
|
||||||
goto free_module;
|
|
||||||
|
|
||||||
/* Now we've got everything in the final locations, we can
|
|
||||||
* find optional sections. */
|
|
||||||
find_module_sections(mod, &info);
|
|
||||||
|
|
||||||
err = check_module_license_and_versions(mod);
|
|
||||||
if (err)
|
|
||||||
goto free_unload;
|
|
||||||
|
|
||||||
/* Set up MODINFO_ATTR fields */
|
|
||||||
setup_modinfo(mod, &info);
|
|
||||||
|
|
||||||
/* Fix up syms, so that st_value is a pointer to location. */
|
|
||||||
err = simplify_symbols(mod, &info);
|
|
||||||
if (err < 0)
|
|
||||||
goto free_modinfo;
|
|
||||||
|
|
||||||
err = apply_relocations(mod, &info);
|
|
||||||
if (err < 0)
|
|
||||||
goto free_modinfo;
|
|
||||||
|
|
||||||
err = post_relocation(mod, &info);
|
|
||||||
if (err < 0)
|
|
||||||
goto free_modinfo;
|
|
||||||
|
|
||||||
flush_module_icache(mod);
|
|
||||||
|
|
||||||
/* Now copy in args */
|
|
||||||
mod->args = strndup_user(uargs, ~0UL >> 1);
|
|
||||||
if (IS_ERR(mod->args)) {
|
|
||||||
err = PTR_ERR(mod->args);
|
|
||||||
goto free_arch_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark state as coming so strong_try_module_get() ignores us. */
|
|
||||||
mod->state = MODULE_STATE_COMING;
|
|
||||||
|
|
||||||
/* Now sew it into the lists so we can get lockdep and oops
|
|
||||||
* info during argument parsing. No one should access us, since
|
|
||||||
* strong_try_module_get() will fail.
|
|
||||||
* lockdep/oops can run asynchronous, so use the RCU list insertion
|
|
||||||
* function to insert in a way safe to concurrent readers.
|
|
||||||
* The mutex protects against concurrent writers.
|
|
||||||
*/
|
|
||||||
again:
|
|
||||||
mutex_lock(&module_mutex);
|
|
||||||
if ((old = find_module(mod->name)) != NULL) {
|
|
||||||
if (old->state == MODULE_STATE_COMING) {
|
|
||||||
/* Wait in case it fails to load. */
|
|
||||||
mutex_unlock(&module_mutex);
|
|
||||||
err = wait_event_interruptible(module_wq,
|
|
||||||
finished_loading(mod->name));
|
|
||||||
if (err)
|
|
||||||
goto free_arch_cleanup;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
err = -EEXIST;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This has to be done once we're sure module name is unique. */
|
|
||||||
dynamic_debug_setup(info.debug, info.num_debug);
|
|
||||||
|
|
||||||
/* Find duplicate symbols */
|
|
||||||
err = verify_export_symbols(mod);
|
|
||||||
if (err < 0)
|
|
||||||
goto ddebug;
|
|
||||||
|
|
||||||
module_bug_finalize(info.hdr, info.sechdrs, mod);
|
|
||||||
list_add_rcu(&mod->list, &modules);
|
|
||||||
mutex_unlock(&module_mutex);
|
|
||||||
|
|
||||||
/* Module is ready to execute: parsing args may do that. */
|
|
||||||
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
|
|
||||||
-32768, 32767, &ddebug_dyndbg_module_param_cb);
|
|
||||||
if (err < 0)
|
|
||||||
goto unlink;
|
|
||||||
|
|
||||||
/* Link in to syfs. */
|
|
||||||
err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
|
|
||||||
if (err < 0)
|
|
||||||
goto unlink;
|
|
||||||
|
|
||||||
/* Get rid of temporary copy. */
|
|
||||||
free_copy(&info);
|
|
||||||
|
|
||||||
/* Done! */
|
|
||||||
trace_module_load(mod);
|
|
||||||
return mod;
|
|
||||||
|
|
||||||
unlink:
|
|
||||||
mutex_lock(&module_mutex);
|
|
||||||
/* Unlink carefully: kallsyms could be walking list. */
|
|
||||||
list_del_rcu(&mod->list);
|
|
||||||
module_bug_cleanup(mod);
|
|
||||||
wake_up_all(&module_wq);
|
|
||||||
ddebug:
|
|
||||||
dynamic_debug_remove(info.debug);
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&module_mutex);
|
|
||||||
synchronize_sched();
|
|
||||||
kfree(mod->args);
|
|
||||||
free_arch_cleanup:
|
|
||||||
module_arch_cleanup(mod);
|
|
||||||
free_modinfo:
|
|
||||||
free_modinfo(mod);
|
|
||||||
free_unload:
|
|
||||||
module_unload_free(mod);
|
|
||||||
free_module:
|
|
||||||
module_deallocate(mod, &info);
|
|
||||||
free_copy:
|
|
||||||
free_copy(&info);
|
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call module constructors. */
|
/* Call module constructors. */
|
||||||
static void do_mod_ctors(struct module *mod)
|
static void do_mod_ctors(struct module *mod)
|
||||||
{
|
{
|
||||||
|
@ -3104,21 +3009,10 @@ static void do_mod_ctors(struct module *mod)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is where the real work happens */
|
/* This is where the real work happens */
|
||||||
SYSCALL_DEFINE3(init_module, void __user *, umod,
|
static int do_init_module(struct module *mod)
|
||||||
unsigned long, len, const char __user *, uargs)
|
|
||||||
{
|
{
|
||||||
struct module *mod;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Must have permission */
|
|
||||||
if (!capable(CAP_SYS_MODULE) || modules_disabled)
|
|
||||||
return -EPERM;
|
|
||||||
|
|
||||||
/* Do all the hard work */
|
|
||||||
mod = load_module(umod, len, uargs);
|
|
||||||
if (IS_ERR(mod))
|
|
||||||
return PTR_ERR(mod);
|
|
||||||
|
|
||||||
blocking_notifier_call_chain(&module_notify_list,
|
blocking_notifier_call_chain(&module_notify_list,
|
||||||
MODULE_STATE_COMING, mod);
|
MODULE_STATE_COMING, mod);
|
||||||
|
|
||||||
|
@ -3188,6 +3082,205 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||||
return 0;
|
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
|
||||||
|
zero, and we rely on this for optional sections. */
|
||||||
|
static int load_module(struct load_info *info, const char __user *uargs,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
struct module *mod, *old;
|
||||||
|
long err;
|
||||||
|
|
||||||
|
err = module_sig_check(info);
|
||||||
|
if (err)
|
||||||
|
goto free_copy;
|
||||||
|
|
||||||
|
err = elf_header_check(info);
|
||||||
|
if (err)
|
||||||
|
goto free_copy;
|
||||||
|
|
||||||
|
/* Figure out module layout, and allocate all the memory. */
|
||||||
|
mod = layout_and_allocate(info, flags);
|
||||||
|
if (IS_ERR(mod)) {
|
||||||
|
err = PTR_ERR(mod);
|
||||||
|
goto free_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MODULE_SIG
|
||||||
|
mod->sig_ok = info->sig_ok;
|
||||||
|
if (!mod->sig_ok)
|
||||||
|
add_taint_module(mod, TAINT_FORCED_MODULE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Now module is in final location, initialize linked lists, etc. */
|
||||||
|
err = module_unload_init(mod);
|
||||||
|
if (err)
|
||||||
|
goto free_module;
|
||||||
|
|
||||||
|
/* Now we've got everything in the final locations, we can
|
||||||
|
* find optional sections. */
|
||||||
|
find_module_sections(mod, info);
|
||||||
|
|
||||||
|
err = check_module_license_and_versions(mod);
|
||||||
|
if (err)
|
||||||
|
goto free_unload;
|
||||||
|
|
||||||
|
/* Set up MODINFO_ATTR fields */
|
||||||
|
setup_modinfo(mod, info);
|
||||||
|
|
||||||
|
/* Fix up syms, so that st_value is a pointer to location. */
|
||||||
|
err = simplify_symbols(mod, info);
|
||||||
|
if (err < 0)
|
||||||
|
goto free_modinfo;
|
||||||
|
|
||||||
|
err = apply_relocations(mod, info);
|
||||||
|
if (err < 0)
|
||||||
|
goto free_modinfo;
|
||||||
|
|
||||||
|
err = post_relocation(mod, info);
|
||||||
|
if (err < 0)
|
||||||
|
goto free_modinfo;
|
||||||
|
|
||||||
|
flush_module_icache(mod);
|
||||||
|
|
||||||
|
/* Now copy in args */
|
||||||
|
mod->args = strndup_user(uargs, ~0UL >> 1);
|
||||||
|
if (IS_ERR(mod->args)) {
|
||||||
|
err = PTR_ERR(mod->args);
|
||||||
|
goto free_arch_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark state as coming so strong_try_module_get() ignores us. */
|
||||||
|
mod->state = MODULE_STATE_COMING;
|
||||||
|
|
||||||
|
/* Now sew it into the lists so we can get lockdep and oops
|
||||||
|
* info during argument parsing. No one should access us, since
|
||||||
|
* strong_try_module_get() will fail.
|
||||||
|
* lockdep/oops can run asynchronous, so use the RCU list insertion
|
||||||
|
* function to insert in a way safe to concurrent readers.
|
||||||
|
* The mutex protects against concurrent writers.
|
||||||
|
*/
|
||||||
|
again:
|
||||||
|
mutex_lock(&module_mutex);
|
||||||
|
if ((old = find_module(mod->name)) != NULL) {
|
||||||
|
if (old->state == MODULE_STATE_COMING) {
|
||||||
|
/* Wait in case it fails to load. */
|
||||||
|
mutex_unlock(&module_mutex);
|
||||||
|
err = wait_event_interruptible(module_wq,
|
||||||
|
finished_loading(mod->name));
|
||||||
|
if (err)
|
||||||
|
goto free_arch_cleanup;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
err = -EEXIST;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This has to be done once we're sure module name is unique. */
|
||||||
|
dynamic_debug_setup(info->debug, info->num_debug);
|
||||||
|
|
||||||
|
/* Find duplicate symbols */
|
||||||
|
err = verify_export_symbols(mod);
|
||||||
|
if (err < 0)
|
||||||
|
goto ddebug;
|
||||||
|
|
||||||
|
module_bug_finalize(info->hdr, info->sechdrs, mod);
|
||||||
|
list_add_rcu(&mod->list, &modules);
|
||||||
|
mutex_unlock(&module_mutex);
|
||||||
|
|
||||||
|
/* Module is ready to execute: parsing args may do that. */
|
||||||
|
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
|
||||||
|
-32768, 32767, &ddebug_dyndbg_module_param_cb);
|
||||||
|
if (err < 0)
|
||||||
|
goto unlink;
|
||||||
|
|
||||||
|
/* Link in to syfs. */
|
||||||
|
err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
|
||||||
|
if (err < 0)
|
||||||
|
goto unlink;
|
||||||
|
|
||||||
|
/* Get rid of temporary copy. */
|
||||||
|
free_copy(info);
|
||||||
|
|
||||||
|
/* Done! */
|
||||||
|
trace_module_load(mod);
|
||||||
|
|
||||||
|
return do_init_module(mod);
|
||||||
|
|
||||||
|
unlink:
|
||||||
|
mutex_lock(&module_mutex);
|
||||||
|
/* Unlink carefully: kallsyms could be walking list. */
|
||||||
|
list_del_rcu(&mod->list);
|
||||||
|
module_bug_cleanup(mod);
|
||||||
|
wake_up_all(&module_wq);
|
||||||
|
ddebug:
|
||||||
|
dynamic_debug_remove(info->debug);
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&module_mutex);
|
||||||
|
synchronize_sched();
|
||||||
|
kfree(mod->args);
|
||||||
|
free_arch_cleanup:
|
||||||
|
module_arch_cleanup(mod);
|
||||||
|
free_modinfo:
|
||||||
|
free_modinfo(mod);
|
||||||
|
free_unload:
|
||||||
|
module_unload_free(mod);
|
||||||
|
free_module:
|
||||||
|
module_deallocate(mod, info);
|
||||||
|
free_copy:
|
||||||
|
free_copy(info);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCALL_DEFINE3(init_module, void __user *, umod,
|
||||||
|
unsigned long, len, const char __user *, uargs)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct load_info info = { };
|
||||||
|
|
||||||
|
err = may_init_module();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
|
||||||
|
umod, len, uargs);
|
||||||
|
|
||||||
|
err = copy_module_from_user(umod, len, &info);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return load_module(&info, uargs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct load_info info = { };
|
||||||
|
|
||||||
|
err = may_init_module();
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
|
||||||
|
|
||||||
|
if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
|
||||||
|
|MODULE_INIT_IGNORE_VERMAGIC))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = copy_module_from_fd(fd, &info);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
return ((void *)addr >= start && (void *)addr < start + size);
|
return ((void *)addr >= start && (void *)addr < start + size);
|
||||||
|
|
|
@ -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 @@ next_tag:
|
||||||
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 @@ next_tag:
|
||||||
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 @@ next_op:
|
||||||
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 @@ next_op:
|
||||||
|
|
||||||
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;
|
||||||
|
|
32
scripts/Makefile.modsign
Normal file
32
scripts/Makefile.modsign
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# ==========================================================================
|
||||||
|
# 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)
|
||||||
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)
|
||||||
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);
|
||||||
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 @@ err_out:
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
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[] = {
|
||||||
.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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue