mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge tag 'modules-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/modules/linux
Pull module updates from Sami Tolvanen:
"Kernel symbol flags:
- Replace the separate *_gpl symbol sections (__ksymtab_gpl and
__kcrctab_gpl) with a unified symbol table and a new __kflagstab
section.
This section stores symbol flags, such as the GPL-only flag, as an
8-bit bitset for each exported symbol. This is a cleanup that
simplifies symbol lookup in the module loader by avoiding table
fragmentation and will allow a cleaner way to add more flags later
if needed.
Module signature UAPI:
- Move struct module_signature to the UAPI headers to allow reuse by
tools outside the kernel proper, such as kmod and
scripts/sign-file.
This also renames a few constants for clarity and drops unused
signature types as preparation for hash-based module integrity
checking work that's in progress.
Sysfs:
- Add a /sys/module/<module>/import_ns sysfs attribute to show the
symbol namespaces imported by loaded modules.
This makes it easier to verify driver API access at runtime on
systems that care about such things (e.g. Android).
Cleanups and fixes:
- Force sh_addr to 0 for all sections in module.lds. This prevents
non-zero section addresses when linking modules with 'ld.bfd -r',
which confused elfutils.
- Fix a memory leak of charp module parameters on module unload when
the kernel is configured with CONFIG_SYSFS=n.
- Override the -EEXIST error code returned by module_init() to
userspace. This prevents confusion with the errno reserved by the
module loader to indicate that a module is already loaded.
- Simplify the warning message and drop the stack dump on positive
returns from module_init().
- Drop unnecessary extern keywords from function declarations and
synchronize parse_args() arguments with their implementation"
* tag 'modules-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/modules/linux: (23 commits)
module: Simplify warning on positive returns from module_init()
module: Override -EEXIST module return
documentation: remove references to *_gpl sections
module: remove *_gpl sections from vmlinux and modules
module: deprecate usage of *_gpl sections in module loader
module: use kflagstab instead of *_gpl sections
module: populate kflagstab in modpost
module: add kflagstab section to vmlinux and modules
module: define ksym_flags enumeration to represent kernel symbol flags
selftests/bpf: verify_pkcs7_sig: Use 'struct module_signature' from the UAPI headers
sign-file: use 'struct module_signature' from the UAPI headers
tools uapi headers: add linux/module_signature.h
module: Move 'struct module_signature' to UAPI
module: Give MODULE_SIG_STRING a more descriptive name
module: Give 'enum pkey_id_type' a more specific name
module: Drop unused signature types
extract-cert: drop unused definition of PKEY_ID_PKCS7
docs: symbol-namespaces: mention sysfs attribute
module: expose imported namespaces via sysfs
module: Remove extern keyword from param prototypes
...
This commit is contained in:
@@ -48,6 +48,15 @@ Contact: Kay Sievers <kay.sievers@vrfy.org>
|
||||
Description: Show the initialization state(live, coming, going) of
|
||||
the module.
|
||||
|
||||
What: /sys/module/*/import_ns
|
||||
Date: January 2026
|
||||
KernelVersion: 7.1
|
||||
Contact: linux-modules@vger.kernel.org
|
||||
Description: List of symbol namespaces imported by this module via
|
||||
MODULE_IMPORT_NS(). Each namespace appears on a separate line.
|
||||
This file only exists for modules that import at least one
|
||||
namespace.
|
||||
|
||||
What: /sys/module/*/taint
|
||||
Date: Jan 2012
|
||||
KernelVersion: 3.3
|
||||
|
||||
@@ -114,6 +114,11 @@ inspected with modinfo::
|
||||
import_ns: USB_STORAGE
|
||||
[...]
|
||||
|
||||
For modules that are currently loaded, imported namespaces are also available
|
||||
via sysfs::
|
||||
|
||||
$ cat /sys/module/ums_karma/import_ns
|
||||
USB_STORAGE
|
||||
|
||||
It is advisable to add the MODULE_IMPORT_NS() statement close to other module
|
||||
metadata definitions like MODULE_AUTHOR() or MODULE_LICENSE().
|
||||
|
||||
@@ -426,11 +426,12 @@ Symbols From the Kernel (vmlinux + modules)
|
||||
Version Information Formats
|
||||
---------------------------
|
||||
|
||||
Exported symbols have information stored in __ksymtab or __ksymtab_gpl
|
||||
sections. Symbol names and namespaces are stored in __ksymtab_strings,
|
||||
using a format similar to the string table used for ELF. If
|
||||
CONFIG_MODVERSIONS is enabled, the CRCs corresponding to exported
|
||||
symbols will be added to the __kcrctab or __kcrctab_gpl.
|
||||
Exported symbols have information stored in the __ksymtab and
|
||||
__kflagstab sections. Symbol names and namespaces are stored in
|
||||
__ksymtab_strings section, using a format similar to the string
|
||||
table used for ELF. If CONFIG_MODVERSIONS is enabled, the CRCs
|
||||
corresponding to exported symbols will be added to the
|
||||
__kcrctab section.
|
||||
|
||||
If CONFIG_BASIC_MODVERSIONS is enabled (default with
|
||||
CONFIG_MODVERSIONS), imported symbols will have their symbol name and
|
||||
|
||||
@@ -28,7 +28,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = {
|
||||
#ifdef CONFIG_KEXEC_SIG
|
||||
int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||
{
|
||||
const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
|
||||
const unsigned long marker_len = sizeof(MODULE_SIGNATURE_MARKER) - 1;
|
||||
struct module_signature *ms;
|
||||
unsigned long sig_len;
|
||||
int ret;
|
||||
@@ -40,7 +40,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||
if (marker_len > kernel_len)
|
||||
return -EKEYREJECTED;
|
||||
|
||||
if (memcmp(kernel + kernel_len - marker_len, MODULE_SIG_STRING,
|
||||
if (memcmp(kernel + kernel_len - marker_len, MODULE_SIGNATURE_MARKER,
|
||||
marker_len))
|
||||
return -EKEYREJECTED;
|
||||
kernel_len -= marker_len;
|
||||
@@ -53,7 +53,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||
return -EKEYREJECTED;
|
||||
kernel_len -= sig_len;
|
||||
|
||||
if (ms->id_type != PKEY_ID_PKCS7)
|
||||
if (ms->id_type != MODULE_SIGNATURE_TYPE_PKCS7)
|
||||
return -EKEYREJECTED;
|
||||
|
||||
if (ms->algo != 0 ||
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
#endif
|
||||
#include "ssl-common.h"
|
||||
|
||||
#define PKEY_ID_PKCS7 2
|
||||
|
||||
static __attribute__((noreturn))
|
||||
void format(void)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
IF_MEM_ALLOC_PROFILING(SECTION_WITH_BOUNDARIES(alloc_tags))
|
||||
|
||||
#define MOD_SEPARATE_CODETAG_SECTION(_name) \
|
||||
.codetag.##_name : { \
|
||||
.codetag.##_name 0 : { \
|
||||
SECTION_WITH_BOUNDARIES(_name) \
|
||||
}
|
||||
|
||||
|
||||
@@ -508,32 +508,25 @@
|
||||
\
|
||||
PRINTK_INDEX \
|
||||
\
|
||||
/* Kernel symbol table: Normal symbols */ \
|
||||
/* Kernel symbol table */ \
|
||||
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
|
||||
__start___ksymtab = .; \
|
||||
KEEP(*(SORT(___ksymtab+*))) \
|
||||
__stop___ksymtab = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only symbols */ \
|
||||
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
|
||||
__start___ksymtab_gpl = .; \
|
||||
KEEP(*(SORT(___ksymtab_gpl+*))) \
|
||||
__stop___ksymtab_gpl = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: Normal symbols */ \
|
||||
/* Kernel symbol CRC table */ \
|
||||
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
|
||||
__start___kcrctab = .; \
|
||||
KEEP(*(SORT(___kcrctab+*))) \
|
||||
__stop___kcrctab = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only symbols */ \
|
||||
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
|
||||
__start___kcrctab_gpl = .; \
|
||||
KEEP(*(SORT(___kcrctab_gpl+*))) \
|
||||
__stop___kcrctab_gpl = .; \
|
||||
/* Kernel symbol flags table */ \
|
||||
__kflagstab : AT(ADDR(__kflagstab) - LOAD_OFFSET) { \
|
||||
__start___kflagstab = .; \
|
||||
KEEP(*(SORT(___kflagstab+*))) \
|
||||
__stop___kflagstab = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: strings */ \
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
* section flag requires it. Use '%progbits' instead of '@progbits' since the
|
||||
* former apparently works on all arches according to the binutils source.
|
||||
*/
|
||||
#define __KSYMTAB(name, sym, sec, ns) \
|
||||
#define __KSYMTAB(name, sym, ns) \
|
||||
asm(" .section \"__ksymtab_strings\",\"aMS\",%progbits,1" "\n" \
|
||||
"__kstrtab_" #name ":" "\n" \
|
||||
" .asciz \"" #name "\"" "\n" \
|
||||
"__kstrtabns_" #name ":" "\n" \
|
||||
" .asciz \"" ns "\"" "\n" \
|
||||
" .previous" "\n" \
|
||||
" .section \"___ksymtab" sec "+" #name "\", \"a\"" "\n" \
|
||||
" .section \"___ksymtab+" #name "\", \"a\"" "\n" \
|
||||
__KSYM_ALIGN "\n" \
|
||||
"__ksymtab_" #name ":" "\n" \
|
||||
__KSYM_REF(sym) "\n" \
|
||||
@@ -59,14 +59,22 @@
|
||||
#define KSYM_FUNC(name) name
|
||||
#endif
|
||||
|
||||
#define KSYMTAB_FUNC(name, sec, ns) __KSYMTAB(name, KSYM_FUNC(name), sec, ns)
|
||||
#define KSYMTAB_DATA(name, sec, ns) __KSYMTAB(name, name, sec, ns)
|
||||
#define KSYMTAB_FUNC(name, ns) __KSYMTAB(name, KSYM_FUNC(name), ns)
|
||||
#define KSYMTAB_DATA(name, ns) __KSYMTAB(name, name, ns)
|
||||
|
||||
#define SYMBOL_CRC(sym, crc, sec) \
|
||||
asm(".section \"___kcrctab" sec "+" #sym "\",\"a\"" "\n" \
|
||||
".balign 4" "\n" \
|
||||
"__crc_" #sym ":" "\n" \
|
||||
".long " #crc "\n" \
|
||||
".previous" "\n")
|
||||
#define SYMBOL_CRC(sym, crc) \
|
||||
asm(" .section \"___kcrctab+" #sym "\",\"a\"" "\n" \
|
||||
" .balign 4" "\n" \
|
||||
"__crc_" #sym ":" "\n" \
|
||||
" .long " #crc "\n" \
|
||||
" .previous" "\n" \
|
||||
)
|
||||
|
||||
#define SYMBOL_FLAGS(sym, flags) \
|
||||
asm(" .section \"___kflagstab+" #sym "\",\"a\"" "\n" \
|
||||
"__flags_" #sym ":" "\n" \
|
||||
" .byte " #flags "\n" \
|
||||
" .previous" "\n" \
|
||||
)
|
||||
|
||||
#endif /* __LINUX_EXPORT_INTERNAL_H__ */
|
||||
|
||||
@@ -413,11 +413,13 @@ struct module {
|
||||
struct module_attribute *modinfo_attrs;
|
||||
const char *version;
|
||||
const char *srcversion;
|
||||
const char *imported_namespaces;
|
||||
struct kobject *holders_dir;
|
||||
|
||||
/* Exported symbols */
|
||||
const struct kernel_symbol *syms;
|
||||
const u32 *crcs;
|
||||
const u8 *flagstab;
|
||||
unsigned int num_syms;
|
||||
|
||||
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
|
||||
@@ -433,9 +435,6 @@ struct module {
|
||||
unsigned int num_kp;
|
||||
|
||||
/* GPL-only exported symbols. */
|
||||
unsigned int num_gpl_syms;
|
||||
const struct kernel_symbol *gpl_syms;
|
||||
const u32 *gpl_crcs;
|
||||
bool using_gplonly_symbols;
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
|
||||
@@ -10,35 +10,7 @@
|
||||
#define _LINUX_MODULE_SIGNATURE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
|
||||
#define MODULE_SIG_STRING "~Module signature appended~\n"
|
||||
|
||||
enum pkey_id_type {
|
||||
PKEY_ID_PGP, /* OpenPGP generated key ID */
|
||||
PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
|
||||
PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
|
||||
};
|
||||
|
||||
/*
|
||||
* Module signature information block.
|
||||
*
|
||||
* The constituents of the signature section are, in order:
|
||||
*
|
||||
* - Signer's name
|
||||
* - Key identifier
|
||||
* - Signature data
|
||||
* - Information block
|
||||
*/
|
||||
struct module_signature {
|
||||
u8 algo; /* Public-key crypto algorithm [0] */
|
||||
u8 hash; /* Digest algorithm [0] */
|
||||
u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
||||
u8 signer_len; /* Length of signer's name [0] */
|
||||
u8 key_id_len; /* Length of key identifier [0] */
|
||||
u8 __pad[3];
|
||||
__be32 sig_len; /* Length of signature data */
|
||||
};
|
||||
#include <uapi/linux/module_signature.h>
|
||||
|
||||
int mod_check_sig(const struct module_signature *ms, size_t file_len,
|
||||
const char *name);
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
#ifndef _LINUX_MODULE_SYMBOL_H
|
||||
#define _LINUX_MODULE_SYMBOL_H
|
||||
|
||||
/* Kernel symbol flags bitset. */
|
||||
enum ksym_flags {
|
||||
KSYM_FLAG_GPL_ONLY = 1 << 0,
|
||||
};
|
||||
|
||||
/* This ignores the intensely annoying "mapping symbols" found in ELF files. */
|
||||
static inline bool is_mapping_symbol(const char *str)
|
||||
{
|
||||
|
||||
@@ -317,8 +317,8 @@ struct kparam_array
|
||||
name, &__param_ops_##name, arg, perm, -1, 0)
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
extern void kernel_param_lock(struct module *mod);
|
||||
extern void kernel_param_unlock(struct module *mod);
|
||||
void kernel_param_lock(struct module *mod);
|
||||
void kernel_param_unlock(struct module *mod);
|
||||
#else
|
||||
static inline void kernel_param_lock(struct module *mod)
|
||||
{
|
||||
@@ -398,7 +398,7 @@ static inline void kernel_param_unlock(struct module *mod)
|
||||
* Returns: true if the two parameter names are equal.
|
||||
* Dashes (-) are considered equal to underscores (_).
|
||||
*/
|
||||
extern bool parameq(const char *name1, const char *name2);
|
||||
bool parameq(const char *name1, const char *name2);
|
||||
|
||||
/**
|
||||
* parameqn - checks if two parameter names match
|
||||
@@ -412,28 +412,23 @@ extern bool parameq(const char *name1, const char *name2);
|
||||
* are equal.
|
||||
* Dashes (-) are considered equal to underscores (_).
|
||||
*/
|
||||
extern bool parameqn(const char *name1, const char *name2, size_t n);
|
||||
bool parameqn(const char *name1, const char *name2, size_t n);
|
||||
|
||||
typedef int (*parse_unknown_fn)(char *param, char *val, const char *doing, void *arg);
|
||||
|
||||
/* Called on module insert or kernel boot */
|
||||
extern char *parse_args(const char *name,
|
||||
char *args,
|
||||
const struct kernel_param *params,
|
||||
unsigned num,
|
||||
s16 level_min,
|
||||
s16 level_max,
|
||||
void *arg, parse_unknown_fn unknown);
|
||||
char *parse_args(const char *doing,
|
||||
char *args,
|
||||
const struct kernel_param *params,
|
||||
unsigned int num,
|
||||
s16 min_level,
|
||||
s16 max_level,
|
||||
void *arg, parse_unknown_fn unknown);
|
||||
|
||||
/* Called by module remove. */
|
||||
#ifdef CONFIG_SYSFS
|
||||
extern void destroy_params(const struct kernel_param *params, unsigned num);
|
||||
#else
|
||||
static inline void destroy_params(const struct kernel_param *params,
|
||||
unsigned num)
|
||||
{
|
||||
}
|
||||
#endif /* !CONFIG_SYSFS */
|
||||
#ifdef CONFIG_MODULES
|
||||
void module_destroy_params(const struct kernel_param *params, unsigned int num);
|
||||
#endif
|
||||
|
||||
/* All the helper functions */
|
||||
/* The macros to do compile-time type checking stolen from Jakub
|
||||
@@ -442,78 +437,77 @@ static inline void destroy_params(const struct kernel_param *params,
|
||||
static inline type __always_unused *__check_##name(void) { return(p); }
|
||||
|
||||
extern const struct kernel_param_ops param_ops_byte;
|
||||
extern int param_set_byte(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_byte(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_byte(const char *val, const struct kernel_param *kp);
|
||||
int param_get_byte(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_byte(name, p) __param_check(name, p, unsigned char)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_short;
|
||||
extern int param_set_short(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_short(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_short(const char *val, const struct kernel_param *kp);
|
||||
int param_get_short(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_short(name, p) __param_check(name, p, short)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_ushort;
|
||||
extern int param_set_ushort(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_ushort(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_ushort(const char *val, const struct kernel_param *kp);
|
||||
int param_get_ushort(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_ushort(name, p) __param_check(name, p, unsigned short)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_int;
|
||||
extern int param_set_int(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_int(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_int(const char *val, const struct kernel_param *kp);
|
||||
int param_get_int(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_int(name, p) __param_check(name, p, int)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_uint;
|
||||
extern int param_set_uint(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_uint(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_uint(const char *val, const struct kernel_param *kp);
|
||||
int param_get_uint(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_uint_minmax(const char *val, const struct kernel_param *kp,
|
||||
unsigned int min, unsigned int max);
|
||||
#define param_check_uint(name, p) __param_check(name, p, unsigned int)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_long;
|
||||
extern int param_set_long(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_long(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_long(const char *val, const struct kernel_param *kp);
|
||||
int param_get_long(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_long(name, p) __param_check(name, p, long)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_ulong;
|
||||
extern int param_set_ulong(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_ulong(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_ulong(const char *val, const struct kernel_param *kp);
|
||||
int param_get_ulong(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_ulong(name, p) __param_check(name, p, unsigned long)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_ullong;
|
||||
extern int param_set_ullong(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_ullong(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_ullong(const char *val, const struct kernel_param *kp);
|
||||
int param_get_ullong(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_ullong(name, p) __param_check(name, p, unsigned long long)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_hexint;
|
||||
extern int param_set_hexint(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_hexint(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_hexint(const char *val, const struct kernel_param *kp);
|
||||
int param_get_hexint(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_hexint(name, p) param_check_uint(name, p)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_charp;
|
||||
extern int param_set_charp(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_charp(char *buffer, const struct kernel_param *kp);
|
||||
extern void param_free_charp(void *arg);
|
||||
int param_set_charp(const char *val, const struct kernel_param *kp);
|
||||
int param_get_charp(char *buffer, const struct kernel_param *kp);
|
||||
void param_free_charp(void *arg);
|
||||
#define param_check_charp(name, p) __param_check(name, p, char *)
|
||||
|
||||
/* We used to allow int as well as bool. We're taking that away! */
|
||||
extern const struct kernel_param_ops param_ops_bool;
|
||||
extern int param_set_bool(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_bool(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_bool(const char *val, const struct kernel_param *kp);
|
||||
int param_get_bool(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_bool(name, p) __param_check(name, p, bool)
|
||||
|
||||
extern const struct kernel_param_ops param_ops_bool_enable_only;
|
||||
extern int param_set_bool_enable_only(const char *val,
|
||||
const struct kernel_param *kp);
|
||||
int param_set_bool_enable_only(const char *val, const struct kernel_param *kp);
|
||||
/* getter is the same as for the regular bool */
|
||||
#define param_check_bool_enable_only param_check_bool
|
||||
|
||||
extern const struct kernel_param_ops param_ops_invbool;
|
||||
extern int param_set_invbool(const char *val, const struct kernel_param *kp);
|
||||
extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_invbool(const char *val, const struct kernel_param *kp);
|
||||
int param_get_invbool(char *buffer, const struct kernel_param *kp);
|
||||
#define param_check_invbool(name, p) __param_check(name, p, bool)
|
||||
|
||||
/* An int, which can only be set like a bool (though it shows as an int). */
|
||||
extern const struct kernel_param_ops param_ops_bint;
|
||||
extern int param_set_bint(const char *val, const struct kernel_param *kp);
|
||||
int param_set_bint(const char *val, const struct kernel_param *kp);
|
||||
#define param_get_bint param_get_int
|
||||
#define param_check_bint param_check_int
|
||||
|
||||
@@ -620,19 +614,19 @@ enum hwparam_type {
|
||||
extern const struct kernel_param_ops param_array_ops;
|
||||
|
||||
extern const struct kernel_param_ops param_ops_string;
|
||||
extern int param_set_copystring(const char *val, const struct kernel_param *);
|
||||
extern int param_get_string(char *buffer, const struct kernel_param *kp);
|
||||
int param_set_copystring(const char *val, const struct kernel_param *kp);
|
||||
int param_get_string(char *buffer, const struct kernel_param *kp);
|
||||
|
||||
/* for exporting parameters in /sys/module/.../parameters */
|
||||
|
||||
struct module;
|
||||
|
||||
#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES)
|
||||
extern int module_param_sysfs_setup(struct module *mod,
|
||||
const struct kernel_param *kparam,
|
||||
unsigned int num_params);
|
||||
int module_param_sysfs_setup(struct module *mod,
|
||||
const struct kernel_param *kparam,
|
||||
unsigned int num_params);
|
||||
|
||||
extern void module_param_sysfs_remove(struct module *mod);
|
||||
void module_param_sysfs_remove(struct module *mod);
|
||||
#else
|
||||
static inline int module_param_sysfs_setup(struct module *mod,
|
||||
const struct kernel_param *kparam,
|
||||
|
||||
41
include/uapi/linux/module_signature.h
Normal file
41
include/uapi/linux/module_signature.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* Module signature handling.
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_MODULE_SIGNATURE_H
|
||||
#define _UAPI_LINUX_MODULE_SIGNATURE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
|
||||
#define MODULE_SIGNATURE_MARKER "~Module signature appended~\n"
|
||||
|
||||
enum module_signature_type {
|
||||
MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */
|
||||
};
|
||||
|
||||
/*
|
||||
* Module signature information block.
|
||||
*
|
||||
* The constituents of the signature section are, in order:
|
||||
*
|
||||
* - Signer's name
|
||||
* - Key identifier
|
||||
* - Signature data
|
||||
* - Information block
|
||||
*/
|
||||
struct module_signature {
|
||||
__u8 algo; /* Public-key crypto algorithm [0] */
|
||||
__u8 hash; /* Digest algorithm [0] */
|
||||
__u8 id_type; /* Key identifier type [enum module_signature_type] */
|
||||
__u8 signer_len; /* Length of signer's name [0] */
|
||||
__u8 key_id_len; /* Length of key identifier [0] */
|
||||
__u8 __pad[3];
|
||||
__be32 sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_MODULE_SIGNATURE_H */
|
||||
@@ -53,10 +53,8 @@ extern const size_t modinfo_attrs_count;
|
||||
/* Provided by the linker */
|
||||
extern const struct kernel_symbol __start___ksymtab[];
|
||||
extern const struct kernel_symbol __stop___ksymtab[];
|
||||
extern const struct kernel_symbol __start___ksymtab_gpl[];
|
||||
extern const struct kernel_symbol __stop___ksymtab_gpl[];
|
||||
extern const u32 __start___kcrctab[];
|
||||
extern const u32 __start___kcrctab_gpl[];
|
||||
extern const u8 __start___kflagstab[];
|
||||
|
||||
#define KMOD_PATH_LEN 256
|
||||
extern char modprobe_path[];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/extable.h>
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/module_signature.h>
|
||||
#include <linux/module_symbol.h>
|
||||
#include <linux/trace_events.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kallsyms.h>
|
||||
@@ -87,7 +88,7 @@ struct mod_tree_root mod_tree __cacheline_aligned = {
|
||||
struct symsearch {
|
||||
const struct kernel_symbol *start, *stop;
|
||||
const u32 *crcs;
|
||||
enum mod_license license;
|
||||
const u8 *flagstab;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -364,19 +365,21 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
|
||||
struct find_symbol_arg *fsa)
|
||||
{
|
||||
struct kernel_symbol *sym;
|
||||
|
||||
if (!fsa->gplok && syms->license == GPL_ONLY)
|
||||
return false;
|
||||
u8 sym_flags;
|
||||
|
||||
sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
|
||||
sizeof(struct kernel_symbol), cmp_name);
|
||||
if (!sym)
|
||||
return false;
|
||||
|
||||
sym_flags = *(syms->flagstab + (sym - syms->start));
|
||||
if (!fsa->gplok && (sym_flags & KSYM_FLAG_GPL_ONLY))
|
||||
return false;
|
||||
|
||||
fsa->owner = owner;
|
||||
fsa->crc = symversion(syms->crcs, sym - syms->start);
|
||||
fsa->sym = sym;
|
||||
fsa->license = syms->license;
|
||||
fsa->license = (sym_flags & KSYM_FLAG_GPL_ONLY) ? GPL_ONLY : NOT_GPL_ONLY;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -387,36 +390,31 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
|
||||
*/
|
||||
bool find_symbol(struct find_symbol_arg *fsa)
|
||||
{
|
||||
static const struct symsearch arr[] = {
|
||||
{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
|
||||
NOT_GPL_ONLY },
|
||||
{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
|
||||
__start___kcrctab_gpl,
|
||||
GPL_ONLY },
|
||||
const struct symsearch syms = {
|
||||
.start = __start___ksymtab,
|
||||
.stop = __stop___ksymtab,
|
||||
.crcs = __start___kcrctab,
|
||||
.flagstab = __start___kflagstab,
|
||||
};
|
||||
struct module *mod;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arr); i++)
|
||||
if (find_exported_symbol_in_section(&arr[i], NULL, fsa))
|
||||
return true;
|
||||
if (find_exported_symbol_in_section(&syms, NULL, fsa))
|
||||
return true;
|
||||
|
||||
list_for_each_entry_rcu(mod, &modules, list,
|
||||
lockdep_is_held(&module_mutex)) {
|
||||
struct symsearch arr[] = {
|
||||
{ mod->syms, mod->syms + mod->num_syms, mod->crcs,
|
||||
NOT_GPL_ONLY },
|
||||
{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
|
||||
mod->gpl_crcs,
|
||||
GPL_ONLY },
|
||||
const struct symsearch syms = {
|
||||
.start = mod->syms,
|
||||
.stop = mod->syms + mod->num_syms,
|
||||
.crcs = mod->crcs,
|
||||
.flagstab = mod->flagstab,
|
||||
};
|
||||
|
||||
if (mod->state == MODULE_STATE_UNFORMED)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arr); i++)
|
||||
if (find_exported_symbol_in_section(&arr[i], mod, fsa))
|
||||
return true;
|
||||
if (find_exported_symbol_in_section(&syms, mod, fsa))
|
||||
return true;
|
||||
}
|
||||
|
||||
pr_debug("Failed to find symbol %s\n", fsa->name);
|
||||
@@ -607,6 +605,36 @@ static const struct module_attribute modinfo_##field = { \
|
||||
MODINFO_ATTR(version);
|
||||
MODINFO_ATTR(srcversion);
|
||||
|
||||
static void setup_modinfo_import_ns(struct module *mod, const char *s)
|
||||
{
|
||||
mod->imported_namespaces = NULL;
|
||||
}
|
||||
|
||||
static ssize_t show_modinfo_import_ns(const struct module_attribute *mattr,
|
||||
struct module_kobject *mk, char *buffer)
|
||||
{
|
||||
return sysfs_emit(buffer, "%s\n", mk->mod->imported_namespaces);
|
||||
}
|
||||
|
||||
static int modinfo_import_ns_exists(struct module *mod)
|
||||
{
|
||||
return mod->imported_namespaces != NULL;
|
||||
}
|
||||
|
||||
static void free_modinfo_import_ns(struct module *mod)
|
||||
{
|
||||
kfree(mod->imported_namespaces);
|
||||
mod->imported_namespaces = NULL;
|
||||
}
|
||||
|
||||
static const struct module_attribute modinfo_import_ns = {
|
||||
.attr = { .name = "import_ns", .mode = 0444 },
|
||||
.show = show_modinfo_import_ns,
|
||||
.setup = setup_modinfo_import_ns,
|
||||
.test = modinfo_import_ns_exists,
|
||||
.free = free_modinfo_import_ns,
|
||||
};
|
||||
|
||||
static struct {
|
||||
char name[MODULE_NAME_LEN];
|
||||
char taints[MODULE_FLAGS_BUF_SIZE];
|
||||
@@ -1058,6 +1086,7 @@ const struct module_attribute *const modinfo_attrs[] = {
|
||||
&module_uevent,
|
||||
&modinfo_version,
|
||||
&modinfo_srcversion,
|
||||
&modinfo_import_ns,
|
||||
&modinfo_initstate,
|
||||
&modinfo_coresize,
|
||||
#ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC
|
||||
@@ -1408,7 +1437,7 @@ static void free_module(struct module *mod)
|
||||
module_unload_free(mod);
|
||||
|
||||
/* Free any allocated parameters. */
|
||||
destroy_params(mod->kp, mod->num_kp);
|
||||
module_destroy_params(mod->kp, mod->num_kp);
|
||||
|
||||
if (is_livepatch_module(mod))
|
||||
free_module_elf(mod);
|
||||
@@ -1466,29 +1495,17 @@ EXPORT_SYMBOL_GPL(__symbol_get);
|
||||
*/
|
||||
static int verify_exported_symbols(struct module *mod)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct kernel_symbol *s;
|
||||
struct {
|
||||
const struct kernel_symbol *sym;
|
||||
unsigned int num;
|
||||
} arr[] = {
|
||||
{ mod->syms, mod->num_syms },
|
||||
{ mod->gpl_syms, mod->num_gpl_syms },
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(arr); i++) {
|
||||
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
|
||||
struct find_symbol_arg fsa = {
|
||||
.name = kernel_symbol_name(s),
|
||||
.gplok = true,
|
||||
};
|
||||
if (find_symbol(&fsa)) {
|
||||
pr_err("%s: exports duplicate symbol %s"
|
||||
" (owned by %s)\n",
|
||||
mod->name, kernel_symbol_name(s),
|
||||
module_name(fsa.owner));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
for (s = mod->syms; s < mod->syms + mod->num_syms; s++) {
|
||||
struct find_symbol_arg fsa = {
|
||||
.name = kernel_symbol_name(s),
|
||||
.gplok = true,
|
||||
};
|
||||
if (find_symbol(&fsa)) {
|
||||
pr_err("%s: exports duplicate symbol %s (owned by %s)\n",
|
||||
mod->name, kernel_symbol_name(s),
|
||||
module_name(fsa.owner));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1760,11 +1777,43 @@ static void module_license_taint_check(struct module *mod, const char *license)
|
||||
}
|
||||
}
|
||||
|
||||
static int copy_modinfo_import_ns(struct module *mod, struct load_info *info)
|
||||
{
|
||||
char *ns;
|
||||
size_t len, total_len = 0;
|
||||
char *buf, *p;
|
||||
|
||||
for_each_modinfo_entry(ns, info, "import_ns")
|
||||
total_len += strlen(ns) + 1;
|
||||
|
||||
if (!total_len) {
|
||||
mod->imported_namespaces = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = kmalloc(total_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
p = buf;
|
||||
for_each_modinfo_entry(ns, info, "import_ns") {
|
||||
len = strlen(ns);
|
||||
memcpy(p, ns, len);
|
||||
p += len;
|
||||
*p++ = '\n';
|
||||
}
|
||||
/* Replace trailing newline with null terminator. */
|
||||
*(p - 1) = '\0';
|
||||
|
||||
mod->imported_namespaces = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_modinfo(struct module *mod, struct load_info *info)
|
||||
{
|
||||
const struct module_attribute *attr;
|
||||
char *imported_namespace;
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; (attr = modinfo_attrs[i]); i++) {
|
||||
if (attr->setup)
|
||||
@@ -1783,6 +1832,10 @@ static int setup_modinfo(struct module *mod, struct load_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
err = copy_modinfo_import_ns(mod, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2610,10 +2663,14 @@ static int find_module_sections(struct module *mod, struct load_info *info)
|
||||
mod->syms = section_objs(info, "__ksymtab",
|
||||
sizeof(*mod->syms), &mod->num_syms);
|
||||
mod->crcs = section_addr(info, "__kcrctab");
|
||||
mod->gpl_syms = section_objs(info, "__ksymtab_gpl",
|
||||
sizeof(*mod->gpl_syms),
|
||||
&mod->num_gpl_syms);
|
||||
mod->gpl_crcs = section_addr(info, "__kcrctab_gpl");
|
||||
mod->flagstab = section_addr(info, "__kflagstab");
|
||||
|
||||
if (section_addr(info, "__ksymtab_gpl"))
|
||||
pr_warn("%s: ignoring obsolete section __ksymtab_gpl\n",
|
||||
mod->name);
|
||||
if (section_addr(info, "__kcrctab_gpl"))
|
||||
pr_warn("%s: ignoring obsolete section __kcrctab_gpl\n",
|
||||
mod->name);
|
||||
|
||||
#ifdef CONFIG_CONSTRUCTORS
|
||||
mod->ctors = section_objs(info, ".ctors",
|
||||
@@ -2817,11 +2874,14 @@ out_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_export_symbol_versions(struct module *mod)
|
||||
static int check_export_symbol_sections(struct module *mod)
|
||||
{
|
||||
if (mod->num_syms && !mod->flagstab) {
|
||||
pr_err("%s: no flags for exported symbols\n", mod->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
if ((mod->num_syms && !mod->crcs) ||
|
||||
(mod->num_gpl_syms && !mod->gpl_crcs)) {
|
||||
if (mod->num_syms && !mod->crcs) {
|
||||
return try_to_force_load(mod,
|
||||
"no versions for exported symbols");
|
||||
}
|
||||
@@ -3045,15 +3105,19 @@ static noinline int do_init_module(struct module *mod)
|
||||
if (mod->init != NULL)
|
||||
ret = do_one_initcall(mod->init);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* -EEXIST is reserved by [f]init_module() to signal to userspace that
|
||||
* a module with this name is already loaded. Use something else if the
|
||||
* module itself is returning that.
|
||||
*/
|
||||
if (ret == -EEXIST)
|
||||
ret = -EBUSY;
|
||||
|
||||
goto fail_free_freeinit;
|
||||
}
|
||||
if (ret > 0) {
|
||||
pr_warn("%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();
|
||||
}
|
||||
if (ret > 0)
|
||||
pr_warn("%s: init suspiciously returned %d, it should follow 0/-E convention\n",
|
||||
mod->name, ret);
|
||||
|
||||
/* Now it's a first class citizen! */
|
||||
mod->state = MODULE_STATE_LIVE;
|
||||
@@ -3434,7 +3498,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||
if (err)
|
||||
goto free_unload;
|
||||
|
||||
err = check_export_symbol_versions(mod);
|
||||
err = check_export_symbol_sections(mod);
|
||||
if (err)
|
||||
goto free_unload;
|
||||
|
||||
@@ -3519,7 +3583,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
|
||||
mod_sysfs_teardown(mod);
|
||||
coming_cleanup:
|
||||
mod->state = MODULE_STATE_GOING;
|
||||
destroy_params(mod->kp, mod->num_kp);
|
||||
module_destroy_params(mod->kp, mod->num_kp);
|
||||
blocking_notifier_call_chain(&module_notify_list,
|
||||
MODULE_STATE_GOING, mod);
|
||||
klp_module_going(mod);
|
||||
|
||||
@@ -70,7 +70,7 @@ int mod_verify_sig(const void *mod, struct load_info *info)
|
||||
int module_sig_check(struct load_info *info, int flags)
|
||||
{
|
||||
int err = -ENODATA;
|
||||
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
|
||||
const unsigned long markerlen = sizeof(MODULE_SIGNATURE_MARKER) - 1;
|
||||
const char *reason;
|
||||
const void *mod = info->hdr;
|
||||
bool mangled_module = flags & (MODULE_INIT_IGNORE_MODVERSIONS |
|
||||
@@ -81,7 +81,7 @@ int module_sig_check(struct load_info *info, int flags)
|
||||
*/
|
||||
if (!mangled_module &&
|
||||
info->len > markerlen &&
|
||||
memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
|
||||
memcmp(mod + info->len - markerlen, MODULE_SIGNATURE_MARKER, markerlen) == 0) {
|
||||
/* We truncate the module to discard the signature */
|
||||
info->len -= markerlen;
|
||||
err = mod_verify_sig(mod, info);
|
||||
|
||||
@@ -24,7 +24,7 @@ int mod_check_sig(const struct module_signature *ms, size_t file_len,
|
||||
if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms))
|
||||
return -EBADMSG;
|
||||
|
||||
if (ms->id_type != PKEY_ID_PKCS7) {
|
||||
if (ms->id_type != MODULE_SIGNATURE_TYPE_PKCS7) {
|
||||
pr_err("%s: not signed with expected PKCS#7 message\n",
|
||||
name);
|
||||
return -ENOPKG;
|
||||
|
||||
@@ -161,7 +161,7 @@ static int parse_one(char *param,
|
||||
char *parse_args(const char *doing,
|
||||
char *args,
|
||||
const struct kernel_param *params,
|
||||
unsigned num,
|
||||
unsigned int num,
|
||||
s16 min_level,
|
||||
s16 max_level,
|
||||
void *arg, parse_unknown_fn unknown)
|
||||
@@ -745,15 +745,6 @@ void module_param_sysfs_remove(struct module *mod)
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy_params(const struct kernel_param *params, unsigned num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
if (params[i].ops->free)
|
||||
params[i].ops->free(params[i].arg);
|
||||
}
|
||||
|
||||
struct module_kobject * __init_or_module
|
||||
lookup_or_create_module_kobject(const char *name)
|
||||
{
|
||||
@@ -985,3 +976,21 @@ static int __init param_sysfs_builtin_init(void)
|
||||
late_initcall(param_sysfs_builtin_init);
|
||||
|
||||
#endif /* CONFIG_SYSFS */
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
/*
|
||||
* module_destroy_params - free all parameters for one module
|
||||
* @params: module parameters (array)
|
||||
* @num: number of module parameters
|
||||
*/
|
||||
void module_destroy_params(const struct kernel_param *params, unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
if (params[i].ops->free)
|
||||
params[i].ops->free(params[i].arg);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
@@ -35,6 +35,7 @@ HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
|
||||
HOSTLDLIBS_sorttable = -lpthread
|
||||
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
|
||||
HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null)
|
||||
HOSTCFLAGS_sign-file.o += -I$(srctree)/tools/include/uapi/
|
||||
HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto)
|
||||
|
||||
ifdef CONFIG_UNWINDER_ORC
|
||||
|
||||
@@ -244,6 +244,11 @@ static struct symbol *alloc_symbol(const char *name)
|
||||
return s;
|
||||
}
|
||||
|
||||
static uint8_t get_symbol_flags(const struct symbol *sym)
|
||||
{
|
||||
return sym->is_gpl_only ? KSYM_FLAG_GPL_ONLY : 0;
|
||||
}
|
||||
|
||||
/* For the hash of exported symbols */
|
||||
static void hash_add_symbol(struct symbol *sym)
|
||||
{
|
||||
@@ -1871,9 +1876,12 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
|
||||
if (trim_unused_exports && !sym->used)
|
||||
continue;
|
||||
|
||||
buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n",
|
||||
buf_printf(buf, "KSYMTAB_%s(%s, \"%s\");\n",
|
||||
sym->is_func ? "FUNC" : "DATA", sym->name,
|
||||
sym->is_gpl_only ? "_gpl" : "", sym->namespace);
|
||||
sym->namespace);
|
||||
|
||||
buf_printf(buf, "SYMBOL_FLAGS(%s, 0x%02x);\n",
|
||||
sym->name, get_symbol_flags(sym));
|
||||
}
|
||||
|
||||
if (!modversions)
|
||||
@@ -1891,8 +1899,8 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
|
||||
sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
|
||||
sym->name);
|
||||
|
||||
buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
|
||||
sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
|
||||
buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x);\n",
|
||||
sym->name, sym->crc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ SECTIONS {
|
||||
}
|
||||
|
||||
__ksymtab 0 : ALIGN(8) { *(SORT(___ksymtab+*)) }
|
||||
__ksymtab_gpl 0 : ALIGN(8) { *(SORT(___ksymtab_gpl+*)) }
|
||||
__kcrctab 0 : ALIGN(4) { *(SORT(___kcrctab+*)) }
|
||||
__kcrctab_gpl 0 : ALIGN(4) { *(SORT(___kcrctab_gpl+*)) }
|
||||
__kflagstab 0 : ALIGN(1) { *(SORT(___kflagstab+*)) }
|
||||
|
||||
.ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
|
||||
.init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
|
||||
@@ -32,30 +31,30 @@ SECTIONS {
|
||||
__jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) }
|
||||
__ex_table 0 : ALIGN(4) { KEEP(*(__ex_table)) }
|
||||
|
||||
__patchable_function_entries : { *(__patchable_function_entries) }
|
||||
__patchable_function_entries 0 : { *(__patchable_function_entries) }
|
||||
|
||||
.init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
|
||||
.init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
|
||||
|
||||
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
|
||||
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
|
||||
__kcfi_traps 0 : { KEEP(*(.kcfi_traps)) }
|
||||
#endif
|
||||
|
||||
.text : {
|
||||
.text 0 : {
|
||||
*(.text .text.[0-9a-zA-Z_]*)
|
||||
}
|
||||
|
||||
.bss : {
|
||||
.bss 0 : {
|
||||
*(.bss .bss.[0-9a-zA-Z_]*)
|
||||
*(.bss..L*)
|
||||
}
|
||||
|
||||
.data : {
|
||||
.data 0 : {
|
||||
*(.data .data.[0-9a-zA-Z_]*)
|
||||
*(.data..L*)
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
.rodata 0 : {
|
||||
*(.rodata .rodata.[0-9a-zA-Z_]*)
|
||||
*(.rodata..L*)
|
||||
}
|
||||
|
||||
@@ -40,19 +40,7 @@
|
||||
#endif
|
||||
#include "ssl-common.h"
|
||||
|
||||
struct module_signature {
|
||||
uint8_t algo; /* Public-key crypto algorithm [0] */
|
||||
uint8_t hash; /* Digest algorithm [0] */
|
||||
uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
||||
uint8_t signer_len; /* Length of signer's name [0] */
|
||||
uint8_t key_id_len; /* Length of key identifier [0] */
|
||||
uint8_t __pad[3];
|
||||
uint32_t sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
#define PKEY_ID_PKCS7 2
|
||||
|
||||
static char magic_number[] = "~Module signature appended~\n";
|
||||
#include <linux/module_signature.h>
|
||||
|
||||
static __attribute__((noreturn))
|
||||
void format(void)
|
||||
@@ -197,7 +185,7 @@ static X509 *read_x509(const char *x509_name)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
|
||||
struct module_signature sig_info = { .id_type = MODULE_SIGNATURE_TYPE_PKCS7 };
|
||||
char *hash_algo = NULL;
|
||||
char *private_key_name = NULL, *raw_sig_name = NULL;
|
||||
char *x509_name, *module_name, *dest_name;
|
||||
@@ -357,7 +345,8 @@ int main(int argc, char **argv)
|
||||
sig_size = BIO_number_written(bd) - module_size;
|
||||
sig_info.sig_len = htonl(sig_size);
|
||||
ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);
|
||||
ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name);
|
||||
ERR(BIO_write(bd, MODULE_SIGNATURE_MARKER, sizeof(MODULE_SIGNATURE_MARKER) - 1) < 0,
|
||||
"%s", dest_name);
|
||||
|
||||
ERR(BIO_free(bd) != 1, "%s", dest_name);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ struct modsig {
|
||||
int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
struct modsig **modsig)
|
||||
{
|
||||
const size_t marker_len = strlen(MODULE_SIG_STRING);
|
||||
const size_t marker_len = strlen(MODULE_SIGNATURE_MARKER);
|
||||
const struct module_signature *sig;
|
||||
struct modsig *hdr;
|
||||
size_t sig_len;
|
||||
@@ -51,7 +51,7 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
return -ENOENT;
|
||||
|
||||
p = buf + buf_len - marker_len;
|
||||
if (memcmp(p, MODULE_SIG_STRING, marker_len))
|
||||
if (memcmp(p, MODULE_SIGNATURE_MARKER, marker_len))
|
||||
return -ENOENT;
|
||||
|
||||
buf_len -= marker_len;
|
||||
@@ -105,7 +105,7 @@ void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
|
||||
* Provide the file contents (minus the appended sig) so that the PKCS7
|
||||
* code can calculate the file hash.
|
||||
*/
|
||||
size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
|
||||
size -= modsig->raw_pkcs7_len + strlen(MODULE_SIGNATURE_MARKER) +
|
||||
sizeof(struct module_signature);
|
||||
rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
|
||||
if (rc)
|
||||
|
||||
41
tools/include/uapi/linux/module_signature.h
Normal file
41
tools/include/uapi/linux/module_signature.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* Module signature handling.
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_MODULE_SIGNATURE_H
|
||||
#define _UAPI_LINUX_MODULE_SIGNATURE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
|
||||
#define MODULE_SIGNATURE_MARKER "~Module signature appended~\n"
|
||||
|
||||
enum module_signature_type {
|
||||
MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */
|
||||
};
|
||||
|
||||
/*
|
||||
* Module signature information block.
|
||||
*
|
||||
* The constituents of the signature section are, in order:
|
||||
*
|
||||
* - Signer's name
|
||||
* - Key identifier
|
||||
* - Signature data
|
||||
* - Information block
|
||||
*/
|
||||
struct module_signature {
|
||||
__u8 algo; /* Public-key crypto algorithm [0] */
|
||||
__u8 hash; /* Digest algorithm [0] */
|
||||
__u8 id_type; /* Key identifier type [enum module_signature_type] */
|
||||
__u8 signer_len; /* Length of signer's name [0] */
|
||||
__u8 key_id_len; /* Length of key identifier [0] */
|
||||
__u8 __pad[3];
|
||||
__be32 sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_MODULE_SIGNATURE_H */
|
||||
@@ -274,6 +274,7 @@ $(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_r
|
||||
$(OUTPUT)/sign-file: ../../../../scripts/sign-file.c
|
||||
$(call msg,SIGN-FILE,,$@)
|
||||
$(Q)$(CC) $(shell $(PKG_CONFIG) --cflags libcrypto 2> /dev/null) \
|
||||
-I$(srctree)/tools/include/uapi/ \
|
||||
$< -o $@ \
|
||||
$(shell $(PKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/keyctl.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <linux/fsverity.h>
|
||||
#include <linux/module_signature.h>
|
||||
#include <test_progs.h>
|
||||
|
||||
#include "test_verify_pkcs7_sig.skel.h"
|
||||
@@ -33,29 +34,6 @@
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#endif
|
||||
|
||||
/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
|
||||
#define MODULE_SIG_STRING "~Module signature appended~\n"
|
||||
|
||||
/*
|
||||
* Module signature information block.
|
||||
*
|
||||
* The constituents of the signature section are, in order:
|
||||
*
|
||||
* - Signer's name
|
||||
* - Key identifier
|
||||
* - Signature data
|
||||
* - Information block
|
||||
*/
|
||||
struct module_signature {
|
||||
__u8 algo; /* Public-key crypto algorithm [0] */
|
||||
__u8 hash; /* Digest algorithm [0] */
|
||||
__u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
|
||||
__u8 signer_len; /* Length of signer's name [0] */
|
||||
__u8 key_id_len; /* Length of key identifier [0] */
|
||||
__u8 __pad[3];
|
||||
__be32 sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
struct data {
|
||||
__u8 data[MAX_DATA_SIZE];
|
||||
__u32 data_len;
|
||||
@@ -215,7 +193,7 @@ static int populate_data_item_mod(struct data *data_item)
|
||||
return 0;
|
||||
|
||||
modlen = st.st_size;
|
||||
marker_len = sizeof(MODULE_SIG_STRING) - 1;
|
||||
marker_len = sizeof(MODULE_SIGNATURE_MARKER) - 1;
|
||||
|
||||
fd = open(mod_path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
@@ -228,7 +206,7 @@ static int populate_data_item_mod(struct data *data_item)
|
||||
if (mod == MAP_FAILED)
|
||||
return -errno;
|
||||
|
||||
if (strncmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len)) {
|
||||
if (strncmp(mod + modlen - marker_len, MODULE_SIGNATURE_MARKER, marker_len)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user