Commit d25282d1 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull module signing support from Rusty Russell:
 "module signing is the highlight, but it's an all-over David Howells frenzy..."

Hmm "Magrathea: Glacier signing key". Somebody has been reading too much HHGTTG.

* 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (37 commits)
  X.509: Fix indefinite length element skip error handling
  X.509: Convert some printk calls to pr_devel
  asymmetric keys: fix printk format warning
  MODSIGN: Fix 32-bit overflow in X.509 certificate validity date checking
  MODSIGN: Make mrproper should remove generated files.
  MODSIGN: Use utf8 strings in signer's name in autogenerated X.509 certs
  MODSIGN: Use the same digest for the autogen key sig as for the module sig
  MODSIGN: Sign modules during the build process
  MODSIGN: Provide a script for generating a key ID from an X.509 cert
  MODSIGN: Implement module signature checking
  MODSIGN: Provide module signing public keys to the kernel
  MODSIGN: Automatically generate module signing keys if missing
  MODSIGN: Provide Kconfig options
  MODSIGN: Provide gitignore and make clean rules for extra files
  MODSIGN: Add FIPS policy
  module: signature checking hook
  X.509: Add a crypto key parser for binary (DER) X.509 certificates
  MPILIB: Provide a function to read raw data into an MPI
  X.509: Add an ASN.1 decoder
  X.509: Add simple ASN.1 grammar compiler
  ...
parents b6eea87f dbadc176
......@@ -14,6 +14,10 @@
*.o.*
*.a
*.s
*.ko.unsigned
*.ko.stripped
*.ko.stripped.dig
*.ko.stripped.sig
*.ko
*.so
*.so.dbg
......@@ -84,3 +88,13 @@ GTAGS
*.orig
*~
\#*#
#
# Leavings from module signing
#
extra_certificates
signing_key.priv
signing_key.x509
signing_key.x509.keyid
signing_key.x509.signer
x509.genkey
This diff is collapsed.
......@@ -1593,6 +1593,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
log everything. Information is printed at KERN_DEBUG
so loglevel=8 may also need to be specified.
module.sig_enforce
[KNL] When CONFIG_MODULE_SIG is set, this means that
modules without (valid) signatures will fail to load.
Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
is always true, so this option does nothing.
mousedev.tap_time=
[MOUSE] Maximum time between finger touching and
leaving touchpad surface for touch to be considered
......
......@@ -412,6 +412,10 @@ The main syscalls are:
to the keyring. In this case, an error will be generated if the process
does not have permission to write to the keyring.
If the key type supports it, if the description is NULL or an empty
string, the key type will try and generate a description from the content
of the payload.
The payload is optional, and the pointer can be NULL if not required by
the type. The payload is plen in size, and plen can be zero for an empty
payload.
......@@ -1114,12 +1118,53 @@ The structure has a number of fields, some of which are mandatory:
it should return 0.
(*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
(*) int (*preparse)(struct key_preparsed_payload *prep);
This optional method permits the key type to attempt to parse payload
before a key is created (add key) or the key semaphore is taken (update or
instantiate key). The structure pointed to by prep looks like:
struct key_preparsed_payload {
char *description;
void *type_data[2];
void *payload;
const void *data;
size_t datalen;
size_t quotalen;
};
Before calling the method, the caller will fill in data and datalen with
the payload blob parameters; quotalen will be filled in with the default
quota size from the key type and the rest will be cleared.
If a description can be proposed from the payload contents, that should be
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to type_data[] and payload. These
are merely passed along to the instantiate() or update() operations.
The method should return 0 if success ful or a negative error code
otherwise.
(*) void (*free_preparse)(struct key_preparsed_payload *prep);
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the
description, type_data and payload fields of the key_preparsed_payload
struct as filled in by the preparse() method.
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
This method is called to attach a payload to a key during construction.
The payload attached need not bear any relation to the data passed to this
function.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
If the amount of data attached to the key differs from the size in
keytype->def_datalen, then key_payload_reserve() should be called.
......@@ -1135,6 +1180,9 @@ The structure has a number of fields, some of which are mandatory:
If this type of key can be updated, then this method should be provided.
It is called to update a key's payload from the blob of data provided.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
key_payload_reserve() should be called if the data length might change
before any changes are actually made. Note that if this succeeds, the type
is committed to changing the key because it's already been altered, so all
......
......@@ -997,7 +997,10 @@ CLEAN_DIRS += $(MODVERDIR)
MRPROPER_DIRS += include/config usr/include include/generated \
arch/*/include/generated
MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
signing_key.priv signing_key.x509 x509.genkey \
extra_certificates signing_key.x509.keyid \
signing_key.x509.signer
# clean - Delete most, but leave enough to build external modules
#
......@@ -1241,6 +1244,7 @@ clean: $(clean-dirs)
$(call cmd,rmfiles)
@find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '*.ko.*' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.symtypes' -o -name 'modules.order' \
-o -name modules.builtin -o -name '.tmp_*.o.*' \
......
......@@ -322,4 +322,23 @@ config HAVE_IRQ_TIME_ACCOUNTING
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
bool
config HAVE_MOD_ARCH_SPECIFIC
bool
help
The arch uses struct mod_arch_specific to store data. Many arches
just need a simple module loader without arch specific data - those
should not enable this.
config MODULES_USE_ELF_RELA
bool
help
Modules only use ELF RELA relocations. Modules with ELF REL
relocations will give an error.
config MODULES_USE_ELF_REL
bool
help
Modules only use ELF REL relocations. Modules with ELF RELA
relocations will give an error.
source "kernel/gcov/Kconfig"
......@@ -22,6 +22,8 @@ config ALPHA
select GENERIC_STRNLEN_USER
select GENERIC_KERNEL_THREAD
select GENERIC_KERNEL_EXECVE
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
......
#ifndef _ALPHA_MODULE_H
#define _ALPHA_MODULE_H
#include <asm-generic/module.h>
struct mod_arch_specific
{
unsigned int gotsecindex;
};
#define Elf_Sym Elf64_Sym
#define Elf_Shdr Elf64_Shdr
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Dyn Elf64_Dyn
#define Elf_Rel Elf64_Rel
#define Elf_Rela Elf64_Rela
#define ARCH_SHF_SMALL SHF_ALPHA_GPREL
#ifdef MODULE
......
......@@ -53,6 +53,8 @@ config ARM
select PERF_USE_VMALLOC
select RTC_LIB
select SYS_SUPPORTS_APM_EMULATION
select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
select MODULES_USE_ELF_REL
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
......
#ifndef _ASM_ARM_MODULE_H
#define _ASM_ARM_MODULE_H
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#include <asm-generic/module.h>
struct unwind_table;
......@@ -16,13 +14,11 @@ enum {
ARM_SEC_DEVEXIT,
ARM_SEC_MAX,
};
#endif
struct mod_arch_specific {
#ifdef CONFIG_ARM_UNWIND
struct unwind_table *unwind[ARM_SEC_MAX];
#endif
};
#endif
/*
* Add the ARM architecture version to the version magic string
......
......@@ -15,6 +15,8 @@ config AVR32
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CLOCKEVENTS
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
help
AVR32 is a high-performance 32-bit RISC microprocessor core,
designed for cost-sensitive embedded applications, with particular
......
#ifndef __ASM_AVR32_MODULE_H
#define __ASM_AVR32_MODULE_H
#include <asm-generic/module.h>
struct mod_arch_syminfo {
unsigned long got_offset;
int got_initialized;
......@@ -17,10 +19,6 @@ struct mod_arch_specific {
struct mod_arch_syminfo *syminfo;
};
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define MODULE_PROC_FAMILY "AVR32v1"
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
......
......@@ -43,6 +43,8 @@ config BLACKFIN
select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
select GENERIC_SMP_IDLE_THREAD
select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
config GENERIC_CSUM
def_bool y
......
......@@ -7,9 +7,7 @@
#ifndef _ASM_BFIN_MODULE_H
#define _ASM_BFIN_MODULE_H
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#include <asm-generic/module.h>
struct mod_arch_specific {
Elf_Shdr *text_l1;
......
......@@ -18,6 +18,7 @@ config C6X
select OF_EARLY_FLATTREE
select GENERIC_CLOCKEVENTS
select GENERIC_KERNEL_THREAD
select MODULES_USE_ELF_RELA
config MMU
def_bool n
......
......@@ -13,17 +13,7 @@
#ifndef _ASM_C6X_MODULE_H
#define _ASM_C6X_MODULE_H
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
#define Elf_Word Elf32_Word
/*
* This file contains the C6x architecture specific module code.
*/
struct mod_arch_specific {
};
#include <asm-generic/module.h>
struct loaded_sections {
unsigned int new_vaddr;
......
......@@ -48,6 +48,7 @@ config CRIS
select GENERIC_IOMAP
select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
select GENERIC_CMOS_UPDATE
select MODULES_USE_ELF_RELA
config HZ
int
......
......@@ -10,3 +10,4 @@ header-y += sync_serial.h
generic-y += clkdev.h
generic-y += exec.h
generic-y += module.h
#ifndef _ASM_CRIS_MODULE_H
#define _ASM_CRIS_MODULE_H
/* cris is simple */
struct mod_arch_specific { };
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#endif /* _ASM_CRIS_MODULE_H */
......@@ -11,13 +11,7 @@
#ifndef _ASM_MODULE_H
#define _ASM_MODULE_H
struct mod_arch_specific
{
};
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#include <asm-generic/module.h>
/*
* Include the architecture version.
......
......@@ -7,6 +7,7 @@ config H8300
select ARCH_WANT_IPC_PARSE_VERSION
select GENERIC_IRQ_SHOW
select GENERIC_CPU_DEVICES
select MODULES_USE_ELF_RELA
config SYMBOL_PREFIX
string
......
......@@ -2,3 +2,4 @@ include include/asm-generic/Kbuild.asm
generic-y += clkdev.h
generic-y += exec.h
generic-y += module.h
#ifndef _ASM_H8300_MODULE_H
#define _ASM_H8300_MODULE_H
/*
* This file contains the H8/300 architecture specific module code.
*/
struct mod_arch_specific { };
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#endif /* _ASM_H8/300_MODULE_H */
......@@ -30,6 +30,7 @@ config HEXAGON
select KTIME_SCALAR
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST
select MODULES_USE_ELF_RELA
---help---
Qualcomm Hexagon is a processor architecture designed for high
performance and low power across a wide variety of applications.
......
......@@ -40,6 +40,8 @@ config IA64
select ARCH_THREAD_INFO_ALLOCATOR
select ARCH_CLOCKSOURCE_DATA
select GENERIC_TIME_VSYSCALL_OLD
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
......
#ifndef _ASM_IA64_MODULE_H
#define _ASM_IA64_MODULE_H
#include <asm-generic/module.h>
/*
* IA-64-specific support for kernel module loader.
*
......@@ -29,10 +31,6 @@ struct mod_arch_specific {
unsigned int next_got_entry; /* index of next available got entry */
};
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
#define MODULE_PROC_FAMILY "ia64"
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \
"gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
......
......@@ -14,6 +14,7 @@ config M32R
select GENERIC_IRQ_SHOW
select GENERIC_ATOMIC64
select ARCH_USES_GETTIMEOFFSET
select MODULES_USE_ELF_RELA
config SBUS
bool
......
......@@ -2,3 +2,4 @@ include include/asm-generic/Kbuild.asm
generic-y += clkdev.h
generic-y += exec.h
generic-y += module.h
#ifndef _ASM_M32R_MODULE_H
#define _ASM_M32R_MODULE_H
struct mod_arch_specific { };
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#endif /* _ASM_M32R_MODULE_H */
......@@ -201,18 +201,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
}
return 0;
}
int apply_relocate(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
#if 0
printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
me->name);
return -ENOEXEC;
#endif
return 0;
}
......@@ -16,6 +16,9 @@ config M68K
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
select GENERIC_KERNEL_THREAD
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA
config RWSEM_GENERIC_SPINLOCK
bool
......
#ifndef _ASM_M68K_MODULE_H
#define _ASM_M68K_MODULE_H
#include <asm-generic/module.h>
enum m68k_fixup_type {
m68k_fixup_memoffset,
m68k_fixup_vnode_shift,
......@@ -36,8 +38,4 @@ struct module;
extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
struct m68k_fixup_info *end);
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#endif /* _ASM_M68K_MODULE_H */
......@@ -25,6 +25,7 @@ config MICROBLAZE
select GENERIC_CPU_DEVICES
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA
config SWAP
def_bool n
......
......@@ -37,6 +37,9 @@ config MIPS
select BUILDTIME_EXTABLE_SORT
select GENERIC_CLOCKEVENTS
select GENERIC_CMOS_UPDATE
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA if 64BIT
menu "Machine selection"
......
......@@ -35,11 +35,14 @@ typedef struct {
} Elf64_Mips_Rela;
#ifdef CONFIG_32BIT
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
#define Elf_Rel Elf32_Rel
#define Elf_Rela Elf32_Rela
#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
#define ELF_R_SYM(X) ELF32_R_SYM(X)
#define Elf_Mips_Rel Elf32_Rel
#define Elf_Mips_Rela Elf32_Rela
......@@ -50,11 +53,14 @@ typedef struct {
#endif
#ifdef CONFIG_64BIT
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Addr Elf64_Addr
#define Elf_Rel Elf64_Rel
#define Elf_Rela Elf64_Rela
#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
#define ELF_R_SYM(X) ELF64_R_SYM(X)
#define Elf_Mips_Rel Elf64_Mips_Rel
#define Elf_Mips_Rela Elf64_Mips_Rela
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
......
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (C) 2001 Rusty Russell.
* Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2005 Thiemo Seufer
*/
#include <linux/elf.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/moduleloader.h>
extern int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v);
static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
{
*location = v;
return 0;
}
static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
{
if (v % 4) {
pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
me->name);
return -ENOEXEC;
}
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
printk(KERN_ERR
"module %s: relocation overflow\n",
me->name);
return -ENOEXEC;
}
*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
return 0;
}
static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
{
*location = (*location & 0xffff0000) |
((((long long) v + 0x8000LL) >> 16) & 0xffff);
return 0;
}
static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
{
*location = (*location & 0xffff0000) | (v & 0xffff);
return 0;
}
static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
{
*(Elf_Addr *)location = v;
return 0;
}
static int apply_r_mips_higher_rela(struct module *me, u32 *location,
Elf_Addr v)
{
*location = (*location & 0xffff0000) |
((((long long) v + 0x80008000LL) >> 32) & 0xffff);
return 0;
}
static int apply_r_mips_highest_rela(struct module *me, u32 *location,
Elf_Addr v)
{
*location = (*location & 0xffff0000) |
((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
return 0;
}
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
Elf_Addr v) = {
[R_MIPS_NONE] = apply_r_mips_none,
[R_MIPS_32] = apply_r_mips_32_rela,
[R_MIPS_26] = apply_r_mips_26_rela,
[R_MIPS_HI16] = apply_r_mips_hi16_rela,
[R_MIPS_LO16] = apply_r_mips_lo16_rela,
[R_MIPS_64] = apply_r_mips_64_rela,
[R_MIPS_HIGHER] = apply_r_mips_higher_rela,
[R_MIPS_HIGHEST] = apply_r_mips_highest_rela
};
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec,
struct module *me)
{
Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
Elf_Sym *sym;
u32 *location;
unsigned int i;
Elf_Addr v;
int res;
pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset;
/* This is the symbol it is referring to */
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ ELF_MIPS_R_SYM(rel[i]);
if (IS_ERR_VALUE(sym->st_value)) {
/* Ignore unresolved weak symbol */
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
continue;
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
v = sym->st_value + rel[i].r_addend;
res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
if (res)
return res;
}
return 0;
}
......@@ -51,7 +51,7 @@ void *module_alloc(unsigned long size)
}
#endif
static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
{
return 0;
}
......@@ -63,13 +63,6 @@ static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v)
return 0;
}
static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
{
*location = v;
return 0;
}
static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
{
if (v % 4) {
......@@ -91,26 +84,6 @@ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
return 0;
}
static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
{
if (v % 4) {
pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
me->name);
return -ENOEXEC;
}
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
printk(KERN_ERR
"module %s: relocation overflow\n",
me->name);
return -ENOEXEC;
}
*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
return 0;
}
static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
{
struct mips_hi16 *n;
......@@ -132,14 +105,6 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
return 0;
}
static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
{
*location = (*location & 0xffff0000) |
((((long long) v + 0x8000LL) >> 16) & 0xffff);
return 0;
}
static void free_relocation_chain(struct mips_hi16 *l)
{
struct mips_hi16 *next;
......@@ -217,38 +182,6 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
return -ENOEXEC;
}
static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
{
*location = (*location & 0xffff0000) | (v & 0xffff);
return 0;
}
static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
{
*(Elf_Addr *)location = v;
return 0;
}
static int apply_r_mips_higher_rela(struct module *me, u32 *location,
Elf_Addr v)
{
*location = (*location & 0xffff0000) |
((((long long) v + 0x80008000LL) >> 32) & 0xffff);
return 0;
}
static int apply_r_mips_highest_rela(struct module *me, u32 *location,
Elf_Addr v)
{
*location = (*location & 0xffff0000) |
((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
return 0;
}
static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
Elf_Addr v) = {
[R_MIPS_NONE] = apply_r_mips_none,
......@@ -258,18 +191,6 @@ static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
[R_MIPS_LO16] = apply_r_mips_lo16_rel
};
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
Elf_Addr v) = {
[R_MIPS_NONE] = apply_r_mips_none,
[R_MIPS_32] = apply_r_mips_32_rela,
[R_MIPS_26] = apply_r_mips_26_rela,
[R_MIPS_HI16] = apply_r_mips_hi16_rela,
[R_MIPS_LO16] = apply_r_mips_lo16_rela,
[R_MIPS_64] = apply_r_mips_64_rela,
[R_MIPS_HIGHER] = apply_r_mips_higher_rela,
[R_MIPS_HIGHEST] = apply_r_mips_highest_rela
};
int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec,
struct module *me)
......@@ -324,46 +245,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
return 0;
}
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec,
struct module *me)
{
Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
Elf_Sym *sym;
u32 *location;
unsigned int i;
Elf_Addr v;
int res;
pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset;
/* This is the symbol it is referring to */
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ ELF_MIPS_R_SYM(rel[i]);
if (IS_ERR_VALUE(sym->st_value)) {
/* Ignore unresolved weak symbol */
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
continue;
printk(KERN_WARNING "%s: Unknown symbol %s\n",
me->name, strtab + sym->st_name);
return -ENOENT;
}
v = sym->st_value + rel[i].r_addend;
res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
if (res)
return res;
}
return 0;
}
/* Given an address, look for it in the module exception tables. */
const struct exception_table_entry *search_module_dbetables(unsigned long addr)
{
......
......@@ -9,6 +9,7 @@ config MN10300
select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
select GENERIC_CLOCKEVENTS
select GENERIC_KERNEL_THREAD
select MODULES_USE_ELF_RELA
config AM33_2
def_bool n
......
......@@ -12,12 +12,7 @@
#ifndef _ASM_MODULE_H
#define _ASM_MODULE_H
struct mod_arch_specific {
};
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#include <asm-generic/module.h>
/*
* Include the MN10300 architecture version.
......
......@@ -21,6 +21,7 @@ config OPENRISC
select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA
config MMU
def_bool y
......
......@@ -20,6 +20,8 @@ config PARISC
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
......
#ifndef _ASM_PARISC_MODULE_H
#define _ASM_PARISC_MODULE_H
#include <asm-generic/module.h>
/*
* This file contains the parisc architecture specific module code.
*/
#ifdef CONFIG_64BIT
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Addr Elf64_Addr
#define Elf_Rela Elf64_Rela
#else
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
#define Elf_Rela Elf32_Rela
#endif
struct unwind_table;
......
......@@ -142,6 +142,8 @@ config PPC
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select GENERIC_KERNEL_THREAD
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
config EARLY_PRINTK
bool
......
......@@ -11,6 +11,7 @@
#include <linux/list.h>
#include <asm/bug.h>
#include <asm-generic/module.h>
#ifndef __powerpc64__
......@@ -60,16 +61,10 @@ struct mod_arch_specific {
*/
#ifdef __powerpc64__
# define Elf_Shdr Elf64_Shdr
# define Elf_Sym Elf64_Sym
# define Elf_Ehdr Elf64_Ehdr
# ifdef MODULE
asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
# endif
#else
# define Elf_Shdr Elf32_Shdr
# define Elf_Sym Elf32_Sym
# define Elf_Ehdr Elf32_Ehdr
# ifdef MODULE
asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
......
......@@ -136,6 +136,8 @@ config S390
select KTIME_SCALAR if 32BIT
select HAVE_ARCH_SECCOMP_FILTER
select GENERIC_KERNEL_THREAD
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
config SCHED_OMIT_FRAME_POINTER
def_bool y
......
#ifndef _ASM_S390_MODULE_H
#define _ASM_S390_MODULE_H
#include <asm-generic/module.h>
/*
* This file contains the s390 architecture specific module code.
*/
......@@ -28,19 +31,4 @@ struct mod_arch_specific
struct mod_arch_syminfo *syminfo;
};
#ifdef CONFIG_64BIT
#define ElfW(x) Elf64_ ## x
#define ELFW(x) ELF64_ ## x
#else
#define ElfW(x) Elf32_ ## x
#define ELFW(x) ELF32_ ## x
#endif
#define Elf_Addr ElfW(Addr)
#define Elf_Rela ElfW(Rela)
#define Elf_Shdr ElfW(Shdr)
#define Elf_Sym ElfW(Sym)
#define Elf_Ehdr ElfW(Ehdr)
#define ELF_R_SYM ELFW(R_SYM)
#define ELF_R_TYPE ELFW(R_TYPE)
#endif /* _ASM_S390_MODULE_H */
......@@ -11,6 +11,8 @@ config SCORE
select ARCH_DISCARD_MEMBLOCK
select GENERIC_CPU_DEVICES
select GENERIC_CLOCKEVENTS
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
choice
prompt "System type"
......
......@@ -3,6 +3,7 @@
#include <linux/list.h>
#include <asm/uaccess.h>
#include <asm-generic/module.h>
struct mod_arch_specific {
/* Data Bus Error exception tables */
......@@ -13,11 +14,6 @@ struct mod_arch_specific {
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
/* Given an address, look for it in the exception tables. */
#ifdef CONFIG_MODULES
const struct exception_table_entry *search_module_dbetables(unsigned long addr);
......
......@@ -125,16 +125,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
return 0;
}
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
unsigned int symindex, unsigned int relsec,
struct module *me)
{
/* Non-standard return value... most other arch's return -ENOEXEC
* for an unsupported relocation variant
*/
return 0;
}
/* Given an address, look for it in the module exception tables. */
const struct exception_table_entry *search_module_dbetables(unsigned long addr)
{
......
......@@ -38,6 +38,8 @@ config SUPERH
select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
select MODULES_USE_ELF_RELA
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
......
#ifndef _ASM_SH_MODULE_H
#define _ASM_SH_MODULE_H
struct mod_arch_specific {
#include <asm-generic/module.h>
#ifdef CONFIG_DWARF_UNWINDER
struct mod_arch_specific {
struct list_head fde_list;
struct list_head cie_list;
#endif
};
#ifdef CONFIG_64BIT
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
#else
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#endif
#ifdef CONFIG_CPU_LITTLE_ENDIAN
......
......@@ -39,6 +39,7 @@ config SPARC
select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA
config SPARC32
def_bool !64BIT
......
......@@ -7,4 +7,5 @@ generic-y += exec.h
generic-y += local64.h
generic-y += irq_regs.h
generic-y += local.h
generic-y += module.h
generic-y += word-at-a-time.h
#ifndef __SPARC_MODULE_H
#define __SPARC_MODULE_H
struct mod_arch_specific { };
/*
* Use some preprocessor magic to define the correct symbol
* for sparc32 and sparc64.
* Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64
*/
#define ___ELF(a, b, c) a##b##c
#define __ELF(a, b, c) ___ELF(a, b, c)
#define _Elf(t) __ELF(Elf, CONFIG_BITS, t)
#define _ELF(t) __ELF(ELF, CONFIG_BITS, t)
#define Elf_Shdr _Elf(_Shdr)
#define Elf_Sym _Elf(_Sym)
#define Elf_Ehdr _Elf(_Ehdr)
#define Elf_Rela _Elf(_Rela)
#define Elf_Addr _Elf(_Addr)
#define ELF_R_SYM _ELF(_R_SYM)
#define ELF_R_TYPE _ELF(_R_TYPE)
#endif /* __SPARC_MODULE_H */
......@@ -20,6 +20,7 @@ config TILE
select SYS_HYPERVISOR
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
......
......@@ -15,6 +15,7 @@ config UNICORE32
select GENERIC_IRQ_SHOW
select ARCH_WANT_FRAME_POINTERS
select GENERIC_IOMAP
select MODULES_USE_ELF_REL
help
UniCore-32 is 32-bit Instruction Set Architecture,
including a series of low-power-consumption RISC chip
......
......@@ -110,6 +110,8 @@ config X86
select HAVE_IRQ_TIME_ACCOUNTING
select GENERIC_KERNEL_THREAD
select GENERIC_KERNEL_EXECVE
select MODULES_USE_ELF_REL if X86_32
select MODULES_USE_ELF_RELA if X86_64
config INSTRUCTION_DECODER
def_bool y
......
......@@ -24,9 +24,11 @@ config X86_32
def_bool !64BIT
select HAVE_AOUT
select ARCH_WANT_IPC_PARSE_VERSION
select MODULES_USE_ELF_REL
config X86_64
def_bool 64BIT
select MODULES_USE_ELF_RELA
config RWSEM_XCHGADD_ALGORITHM
def_bool X86_XADD && 64BIT
......
......@@ -13,15 +13,8 @@
#ifndef _XTENSA_MODULE_H
#define _XTENSA_MODULE_H
struct mod_arch_specific
{
/* No special elements, yet. */
};
#define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " "
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#include <asm-generic/module.h>
#endif /* _XTENSA_MODULE_H */
......@@ -1216,5 +1216,6 @@ config CRYPTO_USER_API_SKCIPHER
key cipher algorithms.
source "drivers/crypto/Kconfig"
source crypto/asymmetric_keys/Kconfig
endif # if CRYPTO
......@@ -97,3 +97,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
#
obj-$(CONFIG_XOR_BLOCKS) += xor.o
obj-$(CONFIG_ASYNC_CORE) += async_tx/
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
menuconfig ASYMMETRIC_KEY_TYPE
tristate "Asymmetric (public-key cryptographic) key type"
depends on KEYS
help
This option provides support for a key type that holds the data for
the asymmetric keys used for public key cryptographic operations such
as encryption, decryption, signature generation and signature
verification.
if ASYMMETRIC_KEY_TYPE
config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
tristate "Asymmetric public-key crypto algorithm subtype"
select MPILIB
help
This option provides support for asymmetric public key type handling.
If signature generation and/or verification are to be used,
appropriate hash algorithms (such as SHA-1) must be available.
ENOPKG will be reported if the requisite algorithm is unavailable.
config PUBLIC_KEY_ALGO_RSA
tristate "RSA public-key algorithm"
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select MPILIB_EXTRA
help
This option enables support for the RSA algorithm (PKCS#1, RFC3447).
config X509_CERTIFICATE_PARSER
tristate "X.509 certificate parser"
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select ASN1
select OID_REGISTRY
help
This option procides support for parsing X.509 format blobs for key
data and provides the ability to instantiate a crypto key from a
public key packet found inside the certificate.
endif # ASYMMETRIC_KEY_TYPE
#
# Makefile for asymmetric cryptographic keys
#
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
asymmetric_keys-y := asymmetric_type.o signature.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
#
# X.509 Certificate handling
#
obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
x509_key_parser-y := \
x509-asn1.o \
x509_rsakey-asn1.o \
x509_cert_parser.o \
x509_public_key.o
$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h
$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
clean-files += x509-asn1.c x509-asn1.h
clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
/* Internal definitions for asymmetric key type
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
static inline const char *asymmetric_key_id(const struct key *key)
{
return key->type_data.p[1];
}
/* Asymmetric public-key cryptography key type
*
* See Documentation/security/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "asymmetric_keys.h"
MODULE_LICENSE("GPL");
static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem);
/*
* Match asymmetric keys on (part of) their name
* We have some shorthand methods for matching keys. We allow:
*
* "<desc>" - request a key by description
* "id:<id>" - request a key matching the ID
* "<subtype>:<id>" - request a key of a subtype
*/
static int asymmetric_key_match(const struct key *key, const void *description)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *spec = description;
const char *id, *kid;
ptrdiff_t speclen;
size_t idlen, kidlen;
if (!subtype || !spec || !*spec)
return 0;
/* See if the full key description matches as is */
if (key->description && strcmp(key->description, description) == 0)
return 1;
/* All tests from here on break the criterion description into a
* specifier, a colon and then an identifier.
*/
id = strchr(spec, ':');
if (!id)
return 0;
speclen = id - spec;
id++;
/* Anything after here requires a partial match on the ID string */
kid = asymmetric_key_id(key);
if (!kid)
return 0;
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
if (speclen == 2 &&
memcmp(spec, "id", 2) == 0)
return 1;
if (speclen == subtype->name_len &&
memcmp(spec, subtype->name, speclen) == 0)
return 1;
return 0;
}
/*
* Describe the asymmetric key
*/
static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *kid = asymmetric_key_id(key);
size_t n;
seq_puts(m, key->description);
if (subtype) {
seq_puts(m, ": ");
subtype->describe(key, m);
if (kid) {
seq_putc(m, ' ');
n = strlen(kid);
if (n <= 8)
seq_puts(m, kid);
else
seq_puts(m, kid + n - 8);
}
seq_puts(m, " [");
/* put something here to indicate the key's capabilities */
seq_putc(m, ']');
}
}
/*
* Preparse a asymmetric payload to get format the contents appropriately for the
* internal payload to cut down on the number of scans of the data performed.
*
* We also generate a proposed description from the contents of the key that
* can be used to name the key if the user doesn't want to provide one.
*/
static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
{
struct asymmetric_key_parser *parser;
int ret;
pr_devel("==>%s()\n", __func__);
if (prep->datalen == 0)
return -EINVAL;
down_read(&asymmetric_key_parsers_sem);
ret = -EBADMSG;
list_for_each_entry(parser, &asymmetric_key_parsers, link) {
pr_debug("Trying parser '%s'\n", parser->name);
ret = parser->parse(prep);
if (ret != -EBADMSG) {
pr_debug("Parser recognised the format (ret %d)\n",
ret);
break;
}
}
up_read(&asymmetric_key_parsers_sem);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* Clean up the preparse data
*/
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
{
struct asymmetric_key_subtype *subtype = prep->type_data[0];
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload);
module_put(subtype->owner);
}
kfree(prep->type_data[1]);
kfree(prep->description);
}
/*
* Instantiate a asymmetric_key defined key. The key was preparsed, so we just
* have to transfer the data here.
*/
static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
int ret;
pr_devel("==>%s()\n", __func__);
ret = key_payload_reserve(key, prep->quotalen);
if (ret == 0) {
key->type_data.p[0] = prep->type_data[0];
key->type_data.p[1] = prep->type_data[1];
key->payload.data = prep->payload;
prep->type_data[0] = NULL;
prep->type_data[1] = NULL;
prep->payload = NULL;
}
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* dispose of the data dangling from the corpse of a asymmetric key
*/
static void asymmetric_key_destroy(struct key *key)
{
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
if (subtype) {
subtype->destroy(key->payload.data);
module_put(subtype->owner);
key->type_data.p[0] = NULL;
}
kfree(key->type_data.p[1]);
key->type_data.p[1] = NULL;
}
struct key_type key_type_asymmetric = {
.name = "asymmetric",
.preparse = asymmetric_key_preparse,
.free_preparse = asymmetric_key_free_preparse,
.instantiate = asymmetric_key_instantiate,
.match = asymmetric_key_match,
.destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe,
};
EXPORT_SYMBOL_GPL(key_type_asymmetric);
/**
* register_asymmetric_key_parser - Register a asymmetric key blob parser
* @parser: The parser to register
*/
int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
{
struct asymmetric_key_parser *cursor;
int ret;
down_write(&asymmetric_key_parsers_sem);
list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
if (strcmp(cursor->name, parser->name) == 0) {
pr_err("Asymmetric key parser '%s' already registered\n",
parser->name);
ret = -EEXIST;
goto out;
}
}
list_add_tail(&parser->link, &asymmetric_key_parsers);
pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
ret = 0;
out:
up_write(&asymmetric_key_parsers_sem);
return ret;
}
EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
/**
* unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
* @parser: The parser to unregister
*/
void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
{
down_write(&asymmetric_key_parsers_sem);
list_del(&parser->link);
up_write(&asymmetric_key_parsers_sem);
pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
}
EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
/*
* Module stuff
*/
static int __init asymmetric_key_init(void)
{
return register_key_type(&key_type_asymmetric);
}
static void __exit asymmetric_key_cleanup(void)
{
unregister_key_type(&key_type_asymmetric);
}
module_init(asymmetric_key_init);
module_exit(asymmetric_key_cleanup);
/* In-software asymmetric public-key crypto subtype
*
* See Documentation/crypto/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PKEY: "fmt
#include <linux/module.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <keys/asymmetric-subtype.h>
#include "public_key.h"
MODULE_LICENSE("GPL");
const char *const pkey_algo[PKEY_ALGO__LAST] = {
[PKEY_ALGO_DSA] = "DSA",
[PKEY_ALGO_RSA] = "RSA",
};
EXPORT_SYMBOL_GPL(pkey_algo);
const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
[PKEY_HASH_MD4] = "md4",
[PKEY_HASH_MD5] = "md5",
[PKEY_HASH_SHA1] = "sha1",
[PKEY_HASH_RIPE_MD_160] = "rmd160",
[PKEY_HASH_SHA256] = "sha256",
[PKEY_HASH_SHA384] = "sha384",
[PKEY_HASH_SHA512] = "sha512",
[PKEY_HASH_SHA224] = "sha224",
};
EXPORT_SYMBOL_GPL(pkey_hash_algo);
const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
[PKEY_ID_PGP] = "PGP",
[PKEY_ID_X509] = "X509",
};
EXPORT_SYMBOL_GPL(pkey_id_type);
/*
* Provide a part of a description of the key for /proc/keys.
*/
static void public_key_describe(const struct key *asymmetric_key,
struct seq_file *m)
{
struct public_key *key = asymmetric_key->payload.data;
if (key)
seq_printf(m, "%s.%s",
pkey_id_type[key->id_type], key->algo->name);
}
/*
* Destroy a public key algorithm key.
*/
void public_key_destroy(void *payload)
{
struct public_key *key = payload;
int i;
if (key) {
for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
mpi_free(key->mpi[i]);
kfree(key);
}
}
EXPORT_SYMBOL_GPL(public_key_destroy);
/*
* Verify a signature using a public key.
*/
static int public_key_verify_signature(const struct key *key,
const struct public_key_signature *sig)
{
const struct public_key *pk = key->payload.data;
if (!pk->algo->verify_signature)
return -ENOTSUPP;
if (sig->nr_mpi != pk->algo->n_sig_mpi) {
pr_debug("Signature has %u MPI not %u\n",
sig->nr_mpi, pk->algo->n_sig_mpi);
return -EINVAL;
}
return pk->algo->verify_signature(pk, sig);
}
/*
* Public key algorithm asymmetric key subtype
*/
struct asymmetric_key_subtype public_key_subtype = {
.owner = THIS_MODULE,
.name = "public_key",
.describe = public_key_describe,
.destroy = public_key_destroy,
.verify_signature = public_key_verify_signature,
};
EXPORT_SYMBOL_GPL(public_key_subtype);
/* Public key algorithm internals
*
* See Documentation/crypto/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <crypto/public_key.h>
extern struct asymmetric_key_subtype public_key_subtype;
/*
* Public key algorithm definition.
*/
struct public_key_algorithm {
const char *name;
u8 n_pub_mpi; /* Number of MPIs in public key */
u8 n_sec_mpi; /* Number of MPIs in secret key */
u8 n_sig_mpi; /* Number of MPIs in a signature */
int (*verify_signature)(const struct public_key *key,
const struct public_key_signature *sig);
};
extern const struct public_key_algorithm RSA_public_key_algorithm;
/* RSA asymmetric public-key algorithm [RFC3447]
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "RSA: "fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "public_key.h"
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RSA Public Key Algorithm");
#define kenter(FMT, ...) \
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
/*
* Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
*/
static const u8 RSA_digest_info_MD5[] = {
0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
0x05, 0x00, 0x04, 0x10
};
static const u8 RSA_digest_info_SHA1[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
0x2B, 0x0E, 0x03, 0x02, 0x1A,
0x05, 0x00, 0x04, 0x14
};
static const u8 RSA_digest_info_RIPE_MD_160[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
0x2B, 0x24, 0x03, 0x02, 0x01,
0x05, 0x00, 0x04, 0x14
};
static const u8 RSA_digest_info_SHA224[] = {
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
0x05, 0x00, 0x04, 0x1C
};
static const u8 RSA_digest_info_SHA256[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
0x05, 0x00, 0x04, 0x20
};
static const u8 RSA_digest_info_SHA384[] = {
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
0x05, 0x00, 0x04, 0x30
};
static const u8 RSA_digest_info_SHA512[] = {
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
0x05, 0x00, 0x04, 0x40
};
static const struct {
const u8 *data;
size_t size;
} RSA_ASN1_templates[PKEY_HASH__LAST] = {
#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
[PKEY_HASH_MD5] = _(MD5),
[PKEY_HASH_SHA1] = _(SHA1),
[PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160),
[PKEY_HASH_SHA256] = _(SHA256),
[PKEY_HASH_SHA384] = _(SHA384),
[PKEY_HASH_SHA512] = _(SHA512),
[PKEY_HASH_SHA224] = _(SHA224),
#undef _
};
/*
* RSAVP1() function [RFC3447 sec 5.2.2]
*/
static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
{
MPI m;
int ret;
/* (1) Validate 0 <= s < n */
if (mpi_cmp_ui(s, 0) < 0) {
kleave(" = -EBADMSG [s < 0]");
return -EBADMSG;
}
if (mpi_cmp(s, key->rsa.n) >= 0) {
kleave(" = -EBADMSG [s >= n]");
return -EBADMSG;
}
m = mpi_alloc(0);
if (!m)
return -ENOMEM;
/* (2) m = s^e mod n */
ret = mpi_powm(m, s, key->rsa.e, key->rsa.n);
if (ret < 0) {
mpi_free(m);
return ret;
}
*_m = m;
return 0;
}
/*
* Integer to Octet String conversion [RFC3447 sec 4.1]
*/
static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
{
unsigned X_size, x_size;
int X_sign;
u8 *X;
/* Make sure the string is the right length. The number should begin
* with { 0x00, 0x01, ... } so we have to account for 15 leading zero
* bits not being reported by MPI.
*/
x_size = mpi_get_nbits(x);
pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8);
if (x_size != xLen * 8 - 15)
return -ERANGE;
X = mpi_get_buffer(x, &X_size, &X_sign);
if (!X)
return -ENOMEM;
if (X_sign < 0) {
kfree(X);
return -EBADMSG;
}
if (X_size != xLen - 1) {
kfree(X);
return -EBADMSG;
}
*_X = X;
return 0;
}
/*
* Perform the RSA signature verification.
* @H: Value of hash of data and metadata
* @EM: The computed signature value
* @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
* @hash_size: The size of H
* @asn1_template: The DigestInfo ASN.1 template
* @asn1_size: Size of asm1_template[]
*/
static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
const u8 *asn1_template, size_t asn1_size)
{
unsigned PS_end, T_offset, i;
kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
if (k < 2 + 1 + asn1_size + hash_size)
return -EBADMSG;
/* Decode the EMSA-PKCS1-v1_5 */
if (EM[1] != 0x01) {
kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]);
return -EBADMSG;
}
T_offset = k - (asn1_size + hash_size);
PS_end = T_offset - 1;
if (EM[PS_end] != 0x00) {
kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
return -EBADMSG;
}
for (i = 2; i < PS_end; i++) {
if (EM[i] != 0xff) {
kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
return -EBADMSG;
}
}
if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) {
kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
return -EBADMSG;
}
if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) {
kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
return -EKEYREJECTED;
}
kleave(" = 0");
return 0;
}
/*
* Perform the verification step [RFC3447 sec 8.2.2].
*/
static int RSA_verify_signature(const struct public_key *key,
const struct public_key_signature *sig)
{
size_t tsize;
int ret;
/* Variables as per RFC3447 sec 8.2.2 */
const u8 *H = sig->digest;
u8 *EM = NULL;
MPI m = NULL;
size_t k;
kenter("");
if (!RSA_ASN1_templates[sig->pkey_hash_algo].data)
return -ENOTSUPP;
/* (1) Check the signature size against the public key modulus size */
k = mpi_get_nbits(key->rsa.n);
tsize = mpi_get_nbits(sig->rsa.s);
/* According to RFC 4880 sec 3.2, length of MPI is computed starting
* from most significant bit. So the RFC 3447 sec 8.2.2 size check
* must be relaxed to conform with shorter signatures - so we fail here
* only if signature length is longer than modulus size.
*/
pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
if (k < tsize) {
ret = -EBADMSG;
goto error;
}
/* Round up and convert to octets */
k = (k + 7) / 8;
/* (2b) Apply the RSAVP1 verification primitive to the public key */
ret = RSAVP1(key, sig->rsa.s, &m);
if (ret < 0)
goto error;
/* (2c) Convert the message representative (m) to an encoded message
* (EM) of length k octets.
*
* NOTE! The leading zero byte is suppressed by MPI, so we pass a
* pointer to the _preceding_ byte to RSA_verify()!
*/
ret = RSA_I2OSP(m, k, &EM);
if (ret < 0)
goto error;
ret = RSA_verify(H, EM - 1, k, sig->digest_size,
RSA_ASN1_templates[sig->pkey_hash_algo].data,
RSA_ASN1_templates[sig->pkey_hash_algo].size);
error:
kfree(EM);
mpi_free(m);
kleave(" = %d", ret);
return ret;
}
const struct public_key_algorithm RSA_public_key_algorithm = {
.name = "RSA",
.n_pub_mpi = 2,
.n_sec_mpi = 3,
.n_sig_mpi = 1,
.verify_signature = RSA_verify_signature,
};
EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
/* Signature verification with an asymmetric key
*
* See Documentation/security/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <keys/asymmetric-subtype.h>
#include <linux/module.h>
#include <linux/err.h>
#include <crypto/public_key.h>
#include "asymmetric_keys.h"
/**
* verify_signature - Initiate the use of an asymmetric key to verify a signature
* @key: The asymmetric key to verify against
* @sig: The signature to check
*
* Returns 0 if successful or else an error.
*/
int verify_signature(const struct key *key,
const struct public_key_signature *sig)
{
const struct asymmetric_key_subtype *subtype;
int ret;
pr_devel("==>%s()\n", __func__);
if (key->type != &key_type_asymmetric)
return -EINVAL;
subtype = asymmetric_key_subtype(key);
if (!subtype ||
!key->payload.data)
return -EINVAL;
if (!subtype->verify_signature)
return -ENOTSUPP;
ret = subtype->verify_signature(key, sig);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL_GPL(verify_signature);
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }),
signatureAlgorithm AlgorithmIdentifier,
signature BIT STRING ({ x509_note_signature })
}
TBSCertificate ::= SEQUENCE {
version [ 0 ] Version DEFAULT,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
issuer Name ({ x509_note_issuer }),
validity Validity,
subject Name ({ x509_note_subject }),
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
extensions [ 3 ] Extensions OPTIONAL
}
Version ::= INTEGER
CertificateSerialNumber ::= INTEGER
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
parameters ANY OPTIONAL
}
Name ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
AttributeValueAssertion ::= SEQUENCE {
attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
attributeValue ANY ({ x509_extract_name_segment })
}
Validity ::= SEQUENCE {
notBefore Time ({ x509_note_not_before }),
notAfter Time ({ x509_note_not_after })
}
Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime
}
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING ({ x509_extract_key_data })
}
UniqueIdentifier ::= BIT STRING
Extensions ::= SEQUENCE OF Extension
Extension ::= SEQUENCE {
extnid OBJECT IDENTIFIER ({ x509_note_OID }),
critical BOOLEAN DEFAULT,
extnValue OCTET STRING ({ x509_process_extension })
}
This diff is collapsed.
/* X.509 certificate parser internal definitions
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <crypto/public_key.h>
struct x509_certificate {
struct x509_certificate *next;
struct public_key *pub; /* Public key details */
char *issuer; /* Name of certificate issuer */
char *subject; /* Name of certificate subject */
char *fingerprint; /* Key fingerprint as hex */
char *authority; /* Authority key fingerprint as hex */
struct tm valid_from;
struct tm valid_to;
enum pkey_algo pkey_algo : 8; /* Public key algorithm */
enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
const void *tbs; /* Signed data */
size_t tbs_size; /* Size of signed data */
const void *sig; /* Signature data */
size_t sig_size; /* Size of sigature */
};
/*
* x509_cert_parser.c
*/
extern void x509_free_certificate(struct x509_certificate *cert);
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
/* Instantiate a public key crypto key from an X.509 Certificate
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "X.509: "fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/mpi.h>
#include <linux/asn1_decoder.h>
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <crypto/hash.h>
#include "asymmetric_keys.h"
#include "public_key.h"
#include "x509_parser.h"
static const
struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = {
[PKEY_ALGO_DSA] = NULL,
#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
[PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
#endif
};
/*
* Check the signature on a certificate using the provided public key
*/
static int x509_check_signature(const struct public_key *pub,
const struct x509_certificate *cert)
{
struct public_key_signature *sig;
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
int ret;
pr_devel("==>%s()\n", __func__);
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm);
/* We allocate the hash operational data storage on the end of our
* context data.
*/
ret = -ENOMEM;
sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
if (!sig)
goto error_no_sig;
sig->pkey_hash_algo = cert->sig_hash_algo;
sig->digest = (u8 *)sig + sizeof(*sig) + desc_size;
sig->digest_size = digest_size;
desc = (void *)sig + sizeof(*sig);
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
ret = -ENOMEM;
sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
if (!sig->rsa.s)
goto error;
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
if (ret < 0)
goto error_mpi;
ret = pub->algo->verify_signature(pub, sig);
pr_debug("Cert Verification: %d\n", ret);
error_mpi:
mpi_free(sig->rsa.s);
error:
kfree(sig);
error_no_sig:
crypto_free_shash(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* Attempt to parse a data blob for a key as an X509 certificate.
*/
static int x509_key_preparse(struct key_preparsed_payload *prep)
{
struct x509_certificate *cert;
struct tm now;
size_t srlen, sulen;
char *desc = NULL;
int ret;
cert = x509_cert_parse(prep->data, prep->datalen);
if (IS_ERR(cert))
return PTR_ERR(cert);
pr_devel("Cert Issuer: %s\n", cert->issuer);
pr_devel("Cert Subject: %s\n", cert->subject);
pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
cert->valid_from.tm_mday, cert->valid_from.tm_hour,
cert->valid_from.tm_min, cert->valid_from.tm_sec);
pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
cert->valid_to.tm_mday, cert->valid_to.tm_hour,
cert->valid_to.tm_min, cert->valid_to.tm_sec);
pr_devel("Cert Signature: %s + %s\n",
pkey_algo[cert->sig_pkey_algo],
pkey_hash_algo[cert->sig_hash_algo]);
if (!cert->fingerprint || !cert->authority) {
pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
cert->subject);
ret = -EKEYREJECTED;
goto error_free_cert;
}
time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
now.tm_hour, now.tm_min, now.tm_sec);
if (now.tm_year < cert->valid_from.tm_year ||
(now.tm_year == cert->valid_from.tm_year &&
(now.tm_mon < cert->valid_from.tm_mon ||
(now.tm_mon == cert->valid_from.tm_mon &&
(now.tm_mday < cert->valid_from.tm_mday ||
(now.tm_mday == cert->valid_from.tm_mday &&
(now.tm_hour < cert->valid_from.tm_hour ||
(now.tm_hour == cert->valid_from.tm_hour &&
(now.tm_min < cert->valid_from.tm_min ||
(now.tm_min == cert->valid_from.tm_min &&
(now.tm_sec < cert->valid_from.tm_sec
))))))))))) {
pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
ret = -EKEYREJECTED;
goto error_free_cert;
}
if (now.tm_year > cert->valid_to.tm_year ||
(now.tm_year == cert->valid_to.tm_year &&
(now.tm_mon > cert->valid_to.tm_mon ||
(now.tm_mon == cert->valid_to.tm_mon &&
(now.tm_mday > cert->valid_to.tm_mday ||
(now.tm_mday == cert->valid_to.tm_mday &&
(now.tm_hour > cert->valid_to.tm_hour ||
(now.tm_hour == cert->valid_to.tm_hour &&
(now.tm_min > cert->valid_to.tm_min ||
(now.tm_min == cert->valid_to.tm_min &&
(now.tm_sec > cert->valid_to.tm_sec
))))))))))) {
pr_warn("Cert %s has expired\n", cert->fingerprint);
ret = -EKEYEXPIRED;
goto error_free_cert;
}
cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
cert->pub->id_type = PKEY_ID_X509;
/* Check the signature on the key */
if (strcmp(cert->fingerprint, cert->authority) == 0) {
ret = x509_check_signature(cert->pub, cert);
if (ret < 0)
goto error_free_cert;
}
/* Propose a description */
sulen = strlen(cert->subject);
srlen = strlen(cert->fingerprint);
ret = -ENOMEM;
desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
if (!desc)
goto error_free_cert;
memcpy(desc, cert->subject, sulen);
desc[sulen] = ':';
desc[sulen + 1] = ' ';
memcpy(desc + sulen + 2, cert->fingerprint, srlen);
desc[sulen + 2 + srlen] = 0;
/* We're pinning the module by being linked against it */
__module_get(public_key_subtype.owner);
prep->type_data[0] = &public_key_subtype;
prep->type_data[1] = cert->fingerprint;
prep->payload = cert->pub;
prep->description = desc;
prep->quotalen = 100;
/* We've finished with the certificate */
cert->pub = NULL;
cert->fingerprint = NULL;
desc = NULL;
ret = 0;
error_free_cert:
x509_free_certificate(cert);
return ret;
}
static struct asymmetric_key_parser x509_key_parser = {
.owner = THIS_MODULE,
.name = "x509",
.parse = x509_key_preparse,
};
/*
* Module stuff
*/
static int __init x509_key_init(void)
{
return register_asymmetric_key_parser(&x509_key_parser);
}
static void __exit x509_key_exit(void)
{
unregister_asymmetric_key_parser(&x509_key_parser);
}
module_init(x509_key_init);
module_exit(x509_key_exit);
RSAPublicKey ::= SEQUENCE {
modulus INTEGER ({ rsa_extract_mpi }), -- n
publicExponent INTEGER ({ rsa_extract_mpi }) -- e
}
......@@ -31,18 +31,18 @@
/* create a new cifs key */
static int
cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
char *payload;
int ret;
ret = -ENOMEM;
payload = kmalloc(datalen, GFP_KERNEL);
payload = kmalloc(prep->datalen, GFP_KERNEL);
if (!payload)
goto error;
/* attach the data */
memcpy(payload, data, datalen);
memcpy(payload, prep->data, prep->datalen);
key->payload.data = payload;
ret = 0;
......
......@@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {
};
static int
cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
char *payload;
payload = kmalloc(datalen, GFP_KERNEL);
payload = kmalloc(prep->datalen, GFP_KERNEL);
if (!payload)
return -ENOMEM;
memcpy(payload, data, datalen);
memcpy(payload, prep->data, prep->datalen);
key->payload.data = payload;
key->datalen = datalen;
key->datalen = prep->datalen;
return 0;
}
......
/* Count leading and trailing zeros functions
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
#include <asm/bitops.h>
/**
* count_leading_zeros - Count the number of zeros from the MSB back
* @x: The value
*
* Count the number of leading zeros from the MSB going towards the LSB in @x.
*
* If the MSB of @x is set, the result is 0.
* If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
* If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
*/
static inline int count_leading_zeros(unsigned long x)
{
if (sizeof(x) == 4)
return BITS_PER_LONG - fls(x);
else
return BITS_PER_LONG - fls64(x);
}
#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
/**
* count_trailing_zeros - Count the number of zeros from the LSB forwards
* @x: The value
*
* Count the number of trailing zeros from the LSB going towards the MSB in @x.
*
* If the LSB of @x is set, the result is 0.
* If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
* If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
*/
static inline int count_trailing_zeros(unsigned long x)
{
#define COUNT_TRAILING_ZEROS_0 (-1)
if (sizeof(x) == 4)
return ffs(x);
else
return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
}
#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */
......@@ -5,18 +5,44 @@
* Many architectures just need a simple module
* loader without arch specific data.
*/
#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC
struct mod_arch_specific
{
};
#endif
#ifdef CONFIG_64BIT
#define Elf_Shdr Elf64_Shdr
#define Elf_Phdr Elf64_Phdr
#define Elf_Sym Elf64_Sym
#define Elf_Dyn Elf64_Dyn
#define Elf_Ehdr Elf64_Ehdr
#else
#define Elf_Addr Elf64_Addr
#ifdef CONFIG_MODULES_USE_ELF_REL
#define Elf_Rel Elf64_Rel
#endif
#ifdef CONFIG_MODULES_USE_ELF_RELA
#define Elf_Rela Elf64_Rela
#endif
#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
#define ELF_R_SYM(X) ELF64_R_SYM(X)
#else /* CONFIG_64BIT */
#define Elf_Shdr Elf32_Shdr
#define Elf_Phdr Elf32_Phdr
#define Elf_Sym Elf32_Sym
#define Elf_Dyn Elf32_Dyn
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
#ifdef CONFIG_MODULES_USE_ELF_REL
#define Elf_Rel Elf32_Rel
#endif
#ifdef CONFIG_MODULES_USE_ELF_RELA
#define Elf_Rela Elf32_Rela
#endif
#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
#define ELF_R_SYM(X) ELF32_R_SYM(X)
#endif
#endif /* __ASM_GENERIC_MODULE_H */
/* Asymmetric public-key algorithm definitions
*
* See Documentation/crypto/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_PUBLIC_KEY_H
#define _LINUX_PUBLIC_KEY_H
#include <linux/mpi.h>
enum pkey_algo {
PKEY_ALGO_DSA,
PKEY_ALGO_RSA,
PKEY_ALGO__LAST
};
extern const char *const pkey_algo[PKEY_ALGO__LAST];
enum pkey_hash_algo {
PKEY_HASH_MD4,
PKEY_HASH_MD5,
PKEY_HASH_SHA1,
PKEY_HASH_RIPE_MD_160,
PKEY_HASH_SHA256,
PKEY_HASH_SHA384,
PKEY_HASH_SHA512,
PKEY_HASH_SHA224,
PKEY_HASH__LAST
};
extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
enum pkey_id_type {
PKEY_ID_PGP, /* OpenPGP generated key ID */
PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
PKEY_ID_TYPE__LAST
};
extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST];
/*
* Cryptographic data for the public-key subtype of the asymmetric key type.
*
* Note that this may include private part of the key as well as the public
* part.
*/
struct public_key {
const struct public_key_algorithm *algo;
u8 capabilities;
#define PKEY_CAN_ENCRYPT 0x01
#define PKEY_CAN_DECRYPT 0x02
#define PKEY_CAN_SIGN 0x04
#define PKEY_CAN_VERIFY 0x08
enum pkey_id_type id_type : 8;
union {
MPI mpi[5];
struct {
MPI p; /* DSA prime */
MPI q; /* DSA group order */
MPI g; /* DSA group generator */
MPI y; /* DSA public-key value = g^x mod p */
MPI x; /* DSA secret exponent (if present) */
} dsa;
struct {
MPI n; /* RSA public modulus */
MPI e; /* RSA public encryption exponent */
MPI d; /* RSA secret encryption exponent (if present) */
MPI p; /* RSA secret prime (if present) */
MPI q; /* RSA secret prime (if present) */
} rsa;
};
};
extern void public_key_destroy(void *payload);
/*
* Public key cryptography signature data
*/
struct public_key_signature {
u8 *digest;
u8 digest_size; /* Number of bytes in digest */
u8 nr_mpi; /* Occupancy of mpi[] */
enum pkey_hash_algo pkey_hash_algo : 8;
union {
MPI mpi[2];
struct {
MPI s; /* m^d mod n */
} rsa;
struct {
MPI r;
MPI s;
} dsa;
};
};
struct key;
extern int verify_signature(const struct key *key,
const struct public_key_signature *sig);
#endif /* _LINUX_PUBLIC_KEY_H */
/* Asymmetric public-key cryptography data parser
*
* See Documentation/crypto/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _KEYS_ASYMMETRIC_PARSER_H
#define _KEYS_ASYMMETRIC_PARSER_H
/*
* Key data parser. Called during key instantiation.
*/
struct asymmetric_key_parser {
struct list_head link;
struct module *owner;
const char *name;
/* Attempt to parse a key from the data blob passed to add_key() or
* keyctl_instantiate(). Should also generate a proposed description
* that the caller can optionally use for the key.
*
* Return EBADMSG if not recognised.
*/
int (*parse)(struct key_preparsed_payload *prep);
};
extern int register_asymmetric_key_parser(struct asymmetric_key_parser *);
extern void unregister_asymmetric_key_parser(struct asymmetric_key_parser *);
#endif /* _KEYS_ASYMMETRIC_PARSER_H */
/* Asymmetric public-key cryptography key subtype
*
* See Documentation/security/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _KEYS_ASYMMETRIC_SUBTYPE_H
#define _KEYS_ASYMMETRIC_SUBTYPE_H
#include <linux/seq_file.h>
#include <keys/asymmetric-type.h>
struct public_key_signature;
/*
* Keys of this type declare a subtype that indicates the handlers and
* capabilities.
*/
struct asymmetric_key_subtype {
struct module *owner;
const char *name;
unsigned short name_len; /* length of name */
/* Describe a key of this subtype for /proc/keys */
void (*describe)(const struct key *key, struct seq_file *m);
/* Destroy a key of this subtype */
void (*destroy)(void *payload);
/* Verify the signature on a key of this subtype (optional) */
int (*verify_signature)(const struct key *key,
const struct public_key_signature *sig);
};
/**
* asymmetric_key_subtype - Get the subtype from an asymmetric key
* @key: The key of interest.
*
* Retrieves and returns the subtype pointer of the asymmetric key from the
* type-specific data attached to the key.
*/
static inline
struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key)
{
return key->type_data.p[0];
}
#endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */
/* Asymmetric Public-key cryptography key type interface
*
* See Documentation/security/asymmetric-keys.txt
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _KEYS_ASYMMETRIC_TYPE_H
#define _KEYS_ASYMMETRIC_TYPE_H
#include <linux/key-type.h>
extern struct key_type key_type_asymmetric;
/*
* The payload is at the discretion of the subtype.
*/
#endif /* _KEYS_ASYMMETRIC_TYPE_H */
......@@ -35,8 +35,10 @@ struct user_key_payload {
extern struct key_type key_type_user;
extern struct key_type key_type_logon;
extern int user_instantiate(struct key *key, const void *data, size_t datalen);
extern int user_update(struct key *key, const void *data, size_t datalen);
struct key_preparsed_payload;
extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep);
extern int user_update(struct key *key, struct key_preparsed_payload *prep);
extern int user_match(const struct key *key, const void *criterion);
extern void user_revoke(struct key *key);
extern void user_destroy(struct key *key);
......
/* ASN.1 BER/DER/CER encoding definitions
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_ASN1_H
#define _LINUX_ASN1_H
/* Class */
enum asn1_class {
ASN1_UNIV = 0, /* Universal */
ASN1_APPL = 1, /* Application */
ASN1_CONT = 2, /* Context */
ASN1_PRIV = 3 /* Private */
};
#define ASN1_CLASS_BITS 0xc0
enum asn1_method {
ASN1_PRIM = 0, /* Primitive */
ASN1_CONS = 1 /* Constructed */
};
#define ASN1_CONS_BIT 0x20
/* Tag */
enum asn1_tag {
ASN1_EOC = 0, /* End Of Contents or N/A */
ASN1_BOOL = 1, /* Boolean */
ASN1_INT = 2, /* Integer */
ASN1_BTS = 3, /* Bit String */
ASN1_OTS = 4, /* Octet String */
ASN1_NULL = 5, /* Null */
ASN1_OID = 6, /* Object Identifier */
ASN1_ODE = 7, /* Object Description */
ASN1_EXT = 8, /* External */
ASN1_REAL = 9, /* Real float */
ASN1_ENUM = 10, /* Enumerated */
ASN1_EPDV = 11, /* Embedded PDV */
ASN1_UTF8STR = 12, /* UTF8 String */
ASN1_RELOID = 13, /* Relative OID */
/* 14 - Reserved */
/* 15 - Reserved */
ASN1_SEQ = 16, /* Sequence and Sequence of */
ASN1_SET = 17, /* Set and Set of */
ASN1_NUMSTR = 18, /* Numerical String */
ASN1_PRNSTR = 19, /* Printable String */
ASN1_TEXSTR = 20, /* T61 String / Teletext String */
ASN1_VIDSTR = 21, /* Videotex String */
ASN1_IA5STR = 22, /* IA5 String */
ASN1_UNITIM = 23, /* Universal Time */
ASN1_GENTIM = 24, /* General Time */
ASN1_GRASTR = 25, /* Graphic String */
ASN1_VISSTR = 26, /* Visible String */
ASN1_GENSTR = 27, /* General String */
ASN1_UNISTR = 28, /* Universal String */
ASN1_CHRSTR = 29, /* Character String */
ASN1_BMPSTR = 30, /* BMP String */
ASN1_LONG_TAG = 31 /* Long form tag */
};
#endif /* _LINUX_ASN1_H */
/* ASN.1 BER/DER/CER parsing state machine internal definitions
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_ASN1_BER_BYTECODE_H
#define _LINUX_ASN1_BER_BYTECODE_H
#ifdef __KERNEL__
#include <linux/types.h>
#endif
#include <linux/asn1.h>
typedef int (*asn1_action_t)(void *context,
size_t hdrlen, /* In case of ANY type */
unsigned char tag, /* In case of ANY type */
const void *value, size_t vlen);
struct asn1_decoder {
const unsigned char *machine;
size_t machlen;
const asn1_action_t *actions;
};
enum asn1_opcode {
/* The tag-matching ops come first and the odd-numbered slots
* are for OR_SKIP ops.
*/
#define ASN1_OP_MATCH__SKIP 0x01
#define ASN1_OP_MATCH__ACT 0x02
#define ASN1_OP_MATCH__JUMP 0x04
#define ASN1_OP_MATCH__ANY 0x08
#define ASN1_OP_MATCH__COND 0x10
ASN1_OP_MATCH = 0x00,
ASN1_OP_MATCH_OR_SKIP = 0x01,
ASN1_OP_MATCH_ACT = 0x02,
ASN1_OP_MATCH_ACT_OR_SKIP = 0x03,
ASN1_OP_MATCH_JUMP = 0x04,
ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
ASN1_OP_MATCH_ANY = 0x08,
ASN1_OP_MATCH_ANY_ACT = 0x0a,
/* Everything before here matches unconditionally */
ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
ASN1_OP_COND_MATCH_ANY = 0x18,
ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
/* Everything before here will want a tag from the data */
#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT
/* These are here to help fill up space */
ASN1_OP_COND_FAIL = 0x1b,
ASN1_OP_COMPLETE = 0x1c,
ASN1_OP_ACT = 0x1d,
ASN1_OP_RETURN = 0x1e,
/* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
ASN1_OP_END_SEQ = 0x20,
ASN1_OP_END_SET = 0x21,
ASN1_OP_END_SEQ_OF = 0x22,
ASN1_OP_END_SET_OF = 0x23,
ASN1_OP_END_SEQ_ACT = 0x24,
ASN1_OP_END_SET_ACT = 0x25,
ASN1_OP_END_SEQ_OF_ACT = 0x26,
ASN1_OP_END_SET_OF_ACT = 0x27,
#define ASN1_OP_END__SET 0x01
#define ASN1_OP_END__OF 0x02
#define ASN1_OP_END__ACT 0x04
ASN1_OP__NR
};
#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG)
#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG)
#define _jump_target(N) (N)
#define _action(N) (N)
#endif /* _LINUX_ASN1_BER_BYTECODE_H */
/* ASN.1 decoder
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_ASN1_DECODER_H
#define _LINUX_ASN1_DECODER_H
#include <linux/asn1.h>
struct asn1_decoder;
extern int asn1_ber_decoder(const struct asn1_decoder *decoder,
void *context,
const unsigned char *data,
size_t datalen);
#endif /* _LINUX_ASN1_DECODER_H */
......@@ -26,6 +26,27 @@ struct key_construction {
struct key *authkey;/* authorisation for key being constructed */
};
/*
* Pre-parsed payload, used by key add, update and instantiate.
*
* This struct will be cleared and data and datalen will be set with the data
* and length parameters from the caller and quotalen will be set from
* def_datalen from the key type. Then if the preparse() op is provided by the
* key type, that will be called. Then the struct will be passed to the
* instantiate() or the update() op.
*
* If the preparse() op is given, the free_preparse() op will be called to
* clear the contents.
*/
struct key_preparsed_payload {
char *description; /* Proposed key description (or NULL) */
void *type_data[2]; /* Private key-type data */
void *payload; /* Proposed payload */
const void *data; /* Raw data */
size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */
};
typedef int (*request_key_actor_t)(struct key_construction *key,
const char *op, void *aux);
......@@ -45,18 +66,28 @@ struct key_type {
/* vet a description */
int (*vet_description)(const char *description);
/* Preparse the data blob from userspace that is to be the payload,
* generating a proposed description and payload that will be handed to
* the instantiate() and update() ops.
*/
int (*preparse)(struct key_preparsed_payload *prep);
/* Free a preparse data structure.
*/
void (*free_preparse)(struct key_preparsed_payload *prep);
/* instantiate a key of this type
* - this method should call key_payload_reserve() to determine if the
* user's quota will hold the payload
*/
int (*instantiate)(struct key *key, const void *data, size_t datalen);
int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
/* update a key of this type (optional)
* - this method should call key_payload_reserve() to recalculate the
* quota consumption
* - the key must be locked against read when modifying
*/
int (*update)(struct key *key, const void *data, size_t datalen);
int (*update)(struct key *key, struct key_preparsed_payload *prep);
/* match a key against a description */
int (*match)(const struct key *key, const void *desc);
......
......@@ -21,6 +21,9 @@
#include <linux/percpu.h>
#include <asm/module.h>
/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
#define MODULE_SIG_STRING "~Module signature appended~\n"
/* Not Yet Implemented */
#define MODULE_SUPPORTED_DEVICE(name)
......@@ -260,6 +263,11 @@ struct module
const unsigned long *unused_gpl_crcs;
#endif
#ifdef CONFIG_MODULE_SIG
/* Signature was verified. */
bool sig_ok;
#endif
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
const unsigned long *gpl_future_crcs;
......
......@@ -28,21 +28,49 @@ void *module_alloc(unsigned long size);
/* Free memory returned from module_alloc. */
void module_free(struct module *mod, void *module_region);
/* Apply the given relocation to the (simplified) ELF. Return -error
or 0. */
/*
* Apply the given relocation to the (simplified) ELF. Return -error
* or 0.
*/
#ifdef CONFIG_MODULES_USE_ELF_REL
int apply_relocate(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *mod);
#else
static inline int apply_relocate(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
return -ENOEXEC;
}
#endif
/* Apply the given add relocation to the (simplified) ELF. Return
-error or 0 */
/*
* Apply the given add relocation to the (simplified) ELF. Return
* -error or 0
*/
#ifdef CONFIG_MODULES_USE_ELF_RELA
int apply_relocate_add(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *mod);
#else
static inline int apply_relocate_add(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
return -ENOEXEC;
}
#endif
/* Any final processing of module before access. Return -error or 0. */
int module_finalize(const Elf_Ehdr *hdr,
......
......@@ -76,6 +76,7 @@ void mpi_swap(MPI a, MPI b);
/*-- mpicoder.c --*/
MPI do_encode_md(const void *sha_buffer, unsigned nbits);
MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes);
MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
int mpi_fromstr(MPI val, const char *str);
u32 mpi_get_keyid(MPI a, u32 *keyid);
......
/* ASN.1 Object identifier (OID) registry
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_OID_REGISTRY_H
#define _LINUX_OID_REGISTRY_H
#include <linux/types.h>
/*
* OIDs are turned into these values if possible, or OID__NR if not held here.
*
* NOTE! Do not mess with the format of each line as this is read by
* build_OID_registry.pl to generate the data for look_up_OID().
*/
enum OID {
OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */
OID_id_dsa, /* 1.2.840.10040.4.1 */
OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */
OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */
/* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */
OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */
OID_md2WithRSAEncryption, /* 1.2.840.113549.1.1.2 */
OID_md3WithRSAEncryption, /* 1.2.840.113549.1.1.3 */
OID_md4WithRSAEncryption, /* 1.2.840.113549.1.1.4 */
OID_sha1WithRSAEncryption, /* 1.2.840.113549.1.1.5 */
OID_sha256WithRSAEncryption, /* 1.2.840.113549.1.1.11 */
OID_sha384WithRSAEncryption, /* 1.2.840.113549.1.1.12 */
OID_sha512WithRSAEncryption, /* 1.2.840.113549.1.1.13 */
OID_sha224WithRSAEncryption, /* 1.2.840.113549.1.1.14 */
/* PKCS#7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)} */
OID_data, /* 1.2.840.113549.1.7.1 */
OID_signed_data, /* 1.2.840.113549.1.7.2 */
/* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
OID_email_address, /* 1.2.840.113549.1.9.1 */
OID_content_type, /* 1.2.840.113549.1.9.3 */
OID_messageDigest, /* 1.2.840.113549.1.9.4 */
OID_signingTime, /* 1.2.840.113549.1.9.5 */
OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
OID_smimeAuthenticatedAttrs, /* 1.2.840.113549.1.9.16.2.11 */
/* {iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2)} */
OID_md2, /* 1.2.840.113549.2.2 */
OID_md4, /* 1.2.840.113549.2.4 */
OID_md5, /* 1.2.840.113549.2.5 */
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
OID_sha1, /* 1.3.14.3.2.26 */
/* Distinguished Name attribute IDs [RFC 2256] */
OID_commonName, /* 2.5.4.3 */
OID_surname, /* 2.5.4.4 */
OID_countryName, /* 2.5.4.6 */
OID_locality, /* 2.5.4.7 */
OID_stateOrProvinceName, /* 2.5.4.8 */
OID_organizationName, /* 2.5.4.10 */
OID_organizationUnitName, /* 2.5.4.11 */
OID_title, /* 2.5.4.12 */
OID_description, /* 2.5.4.13 */
OID_name, /* 2.5.4.41 */
OID_givenName, /* 2.5.4.42 */
OID_initials, /* 2.5.4.43 */
OID_generationalQualifier, /* 2.5.4.44 */
/* Certificate extension IDs */
OID_subjectKeyIdentifier, /* 2.5.29.14 */
OID_keyUsage, /* 2.5.29.15 */
OID_subjectAltName, /* 2.5.29.17 */
OID_issuerAltName, /* 2.5.29.18 */
OID_basicConstraints, /* 2.5.29.19 */
OID_crlDistributionPoints, /* 2.5.29.31 */
OID_certPolicies, /* 2.5.29.32 */
OID_authorityKeyIdentifier, /* 2.5.29.35 */
OID_extKeyUsage, /* 2.5.29.37 */
OID__NR
};
extern enum OID look_up_OID(const void *data, size_t datasize);
extern int sprint_oid(const void *, size_t, char *, size_t);
extern int sprint_OID(enum OID, char *, size_t);
#endif /* _LINUX_OID_REGISTRY_H */
......@@ -1574,6 +1574,66 @@ config MODULE_SRCVERSION_ALL
the version). With this option, such a "srcversion" field
will be created for all modules. If unsure, say N.
config MODULE_SIG
bool "Module signature verification"
depends on MODULES
select KEYS
select CRYPTO
select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select PUBLIC_KEY_ALGO_RSA
select ASN1
select OID_REGISTRY
select X509_CERTIFICATE_PARSER
help
Check modules for valid signatures upon load: the signature
is simply appended to the module. For more information see
Documentation/module-signing.txt.
!!!WARNING!!! If you enable this option, you MUST make sure that the
module DOES NOT get stripped after being signed. This includes the
debuginfo strip done by some packagers (such as rpmbuild) and
inclusion into an initramfs that wants the module size reduced.
config MODULE_SIG_FORCE
bool "Require modules to be validly signed"
depends on MODULE_SIG
help
Reject unsigned modules or signed modules for which we don't have a
key. Without this, such modules will simply taint the kernel.
choice
prompt "Which hash algorithm should modules be signed with?"
depends on MODULE_SIG
help
This determines which sort of hashing algorithm will be used during
signature generation. This algorithm _must_ be built into the kernel
directly so that signature verification can take place. It is not
possible to load a signed module containing the algorithm to check
the signature on that module.
config MODULE_SIG_SHA1
bool "Sign modules with SHA-1"
select CRYPTO_SHA1
config MODULE_SIG_SHA224
bool "Sign modules with SHA-224"
select CRYPTO_SHA256
config MODULE_SIG_SHA256
bool "Sign modules with SHA-256"
select CRYPTO_SHA256
config MODULE_SIG_SHA384
bool "Sign modules with SHA-384"
select CRYPTO_SHA512
config MODULE_SIG_SHA512
bool "Sign modules with SHA-512"
select CRYPTO_SHA512
endchoice
endif # MODULES
config INIT_ALL_POSSIBLE
......@@ -1607,4 +1667,12 @@ config PADATA
config BROKEN_RODATA
bool
config ASN1
tristate
help
Build a simple ASN.1 grammar compiler that produces a bytecode output
that can be interpreted by the ASN.1 stream decoder and used to
inform it as to what tags are to be expected in a stream and what
functions to call on what tags.
source "kernel/Kconfig.locks"
......@@ -54,6 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
obj-$(CONFIG_KEXEC) += kexec.o
......@@ -130,3 +131,79 @@ quiet_cmd_timeconst = TIMEC $@
targets += timeconst.h
$(obj)/timeconst.h: $(src)/timeconst.pl FORCE
$(call if_changed,timeconst)
ifeq ($(CONFIG_MODULE_SIG),y)
#
# Pull the signing certificate and any extra certificates into the kernel
#
extra_certificates:
touch $@
kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
###############################################################################
#
# If module signing is requested, say by allyesconfig, but a key has not been
# supplied, then one will need to be generated to make sure the build does not
# fail and that the kernel may be used afterwards.
#
###############################################################################
sign_key_with_hash :=
ifeq ($(CONFIG_MODULE_SIG_SHA1),y)
sign_key_with_hash := -sha1
endif
ifeq ($(CONFIG_MODULE_SIG_SHA224),y)
sign_key_with_hash := -sha224
endif
ifeq ($(CONFIG_MODULE_SIG_SHA256),y)
sign_key_with_hash := -sha256
endif
ifeq ($(CONFIG_MODULE_SIG_SHA384),y)
sign_key_with_hash := -sha384
endif
ifeq ($(CONFIG_MODULE_SIG_SHA512),y)
sign_key_with_hash := -sha512
endif
ifeq ($(sign_key_with_hash),)
$(error Could not determine digest type to use from kernel config)
endif
signing_key.priv signing_key.x509: x509.genkey
@echo "###"
@echo "### Now generating an X.509 key pair to be used for signing modules."
@echo "###"
@echo "### If this takes a long time, you might wish to run rngd in the"
@echo "### background to keep the supply of entropy topped up. It"
@echo "### needs to be run as root, and should use a hardware random"
@echo "### number generator if one is available, eg:"
@echo "###"
@echo "### rngd -r /dev/hwrandom"
@echo "###"
openssl req -new -nodes -utf8 $(sign_key_with_hash) -days 36500 -batch \
-x509 -config x509.genkey \
-outform DER -out signing_key.x509 \
-keyout signing_key.priv
@echo "###"
@echo "### Key pair generated."
@echo "###"
x509.genkey:
@echo Generating X.509 key generation config
@echo >x509.genkey "[ req ]"
@echo >>x509.genkey "default_bits = 4096"
@echo >>x509.genkey "distinguished_name = req_distinguished_name"
@echo >>x509.genkey "prompt = no"
@echo >>x509.genkey "string_mask = utf8only"
@echo >>x509.genkey "x509_extensions = myexts"
@echo >>x509.genkey
@echo >>x509.genkey "[ req_distinguished_name ]"
@echo >>x509.genkey "O = Magrathea"
@echo >>x509.genkey "CN = Glacier signing key"
@echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2"
@echo >>x509.genkey
@echo >>x509.genkey "[ myexts ]"
@echo >>x509.genkey "basicConstraints=critical,CA:FALSE"
@echo >>x509.genkey "keyUsage=digitalSignature"
@echo >>x509.genkey "subjectKeyIdentifier=hash"
@echo >>x509.genkey "authorityKeyIdentifier=keyid"
endif
/* Public keys for module signature verification
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/err.h>
#include <keys/asymmetric-type.h>
#include "module-internal.h"
struct key *modsign_keyring;
extern __initdata const u8 modsign_certificate_list[];
extern __initdata const u8 modsign_certificate_list_end[];
asm(".section .init.data,\"aw\"\n"
"modsign_certificate_list:\n"
".incbin \"signing_key.x509\"\n"
".incbin \"extra_certificates\"\n"
"modsign_certificate_list_end:"
);
/*
* We need to make sure ccache doesn't cache the .o file as it doesn't notice
* if modsign.pub changes.
*/
static __initdata const char annoy_ccache[] = __TIME__ "foo";
/*
* Load the compiled-in keys
*/
static __init int module_verify_init(void)
{
pr_notice("Initialise module verification\n");
modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
KUIDT_INIT(0), KGIDT_INIT(0),
current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(modsign_keyring))
panic("Can't allocate module signing keyring\n");
if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
panic("Can't instantiate module signing keyring\n");
return 0;
}
/*
* Must be initialised before we try and load the keys into the keyring.
*/
device_initcall(module_verify_init);
/*
* Load the compiled-in keys
*/
static __init int load_module_signing_keys(void)
{
key_ref_t key;
const u8 *p, *end;
size_t plen;
pr_notice("Loading module verification certificates\n");
end = modsign_certificate_list_end;
p = modsign_certificate_list;
while (p < end) {
/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
* than 256 bytes in size.
*/
if (end - p < 4)
goto dodgy_cert;
if (p[0] != 0x30 &&
p[1] != 0x82)
goto dodgy_cert;
plen = (p[2] << 8) | p[3];
plen += 4;
if (plen > end - p)
goto dodgy_cert;
key = key_create_or_update(make_key_ref(modsign_keyring, 1),
"asymmetric",
NULL,
p,
plen,
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key))
pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
else
pr_notice("MODSIGN: Loaded cert '%s'\n",
key_ref_to_ptr(key)->description);
p += plen;
}
return 0;
dodgy_cert:
pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
return 0;
}
late_initcall(load_module_signing_keys);
/* Module internals
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
extern struct key *modsign_keyring;
extern int mod_verify_sig(const void *mod, unsigned long modlen,
const void *sig, unsigned long siglen);
......@@ -58,6 +58,8 @@
#include <linux/jump_label.h>
#include <linux/pfn.h>
#include <linux/bsearch.h>
#include <linux/fips.h>
#include "module-internal.h"
#define CREATE_TRACE_POINTS
#include <trace/events/module.h>
......@@ -102,6 +104,43 @@ static LIST_HEAD(modules);
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
#endif /* CONFIG_KGDB_KDB */
#ifdef CONFIG_MODULE_SIG
#ifdef CONFIG_MODULE_SIG_FORCE
static bool sig_enforce = true;
#else
static bool sig_enforce = false;
static int param_set_bool_enable_only(const char *val,
const struct kernel_param *kp)
{
int err;
bool test;
struct kernel_param dummy_kp = *kp;
dummy_kp.arg = &test;
err = param_set_bool(val, &dummy_kp);
if (err)
return err;
/* Don't let them unset it once it's set! */
if (!test && sig_enforce)
return -EROFS;
if (test)
sig_enforce = true;
return 0;
}
static const struct kernel_param_ops param_ops_bool_enable_only = {
.set = param_set_bool_enable_only,
.get = param_get_bool,
};
#define param_check_bool_enable_only param_check_bool
module_param(sig_enforce, bool_enable_only, 0644);
#endif /* !CONFIG_MODULE_SIG_FORCE */
#endif /* CONFIG_MODULE_SIG */
/* Block module loading/unloading? */
int modules_disabled = 0;
......@@ -136,6 +175,7 @@ struct load_info {
unsigned long symoffs, stroffs;
struct _ddebug *debug;
unsigned int num_debug;
bool sig_ok;
struct {
unsigned int sym, str, mod, vers, info, pcpu;
} index;
......@@ -1949,26 +1989,6 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
return ret;
}
int __weak apply_relocate(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
pr_err("module %s: REL relocation unsupported\n", me->name);
return -ENOEXEC;
}
int __weak apply_relocate_add(Elf_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
pr_err("module %s: RELA relocation unsupported\n", me->name);
return -ENOEXEC;
}
static int apply_relocations(struct module *mod, const struct load_info *info)
{
unsigned int i;
......@@ -2399,7 +2419,52 @@ static inline void kmemleak_load_module(const struct module *mod,
}
#endif
/* Sets info->hdr and info->len. */
#ifdef CONFIG_MODULE_SIG
static int module_sig_check(struct load_info *info,
const void *mod, unsigned long *len)
{
int err = -ENOKEY;
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
const void *p = mod, *end = mod + *len;
/* Poor man's memmem. */
while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
if (p + markerlen > end)
break;
if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
const void *sig = p + markerlen;
/* Truncate module up to signature. */
*len = p - mod;
err = mod_verify_sig(mod, *len, sig, end - sig);
break;
}
p++;
}
if (!err) {
info->sig_ok = true;
return 0;
}
/* Not having a signature is only an error if we're strict. */
if (err < 0 && fips_enabled)
panic("Module verification failed with error %d in FIPS mode\n",
err);
if (err == -ENOKEY && !sig_enforce)
err = 0;
return err;
}
#else /* !CONFIG_MODULE_SIG */
static int module_sig_check(struct load_info *info,
void *mod, unsigned long *len)
{
return 0;
}
#endif /* !CONFIG_MODULE_SIG */
/* Sets info->hdr, info->len and info->sig_ok. */
static int copy_and_check(struct load_info *info,
const void __user *umod, unsigned long len,
const char __user *uargs)
......@@ -2419,6 +2484,10 @@ static int copy_and_check(struct load_info *info,
goto free_hdr;
}
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
......@@ -2730,6 +2799,10 @@ static int check_module_license_and_versions(struct module *mod)
if (strcmp(mod->name, "driverloader") == 0)
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
/* lve claims to be GPL but upstream won't provide source */
if (strcmp(mod->name, "lve") == 0)
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !mod->crcs)
|| (mod->num_gpl_syms && !mod->gpl_crcs)
......@@ -2861,6 +2934,20 @@ static int post_relocation(struct module *mod, const struct load_info *info)
return module_finalize(info->hdr, info->sechdrs, mod);
}
/* Is this module of this name done loading? No locks held. */
static bool finished_loading(const char *name)
{
struct module *mod;
bool ret;
mutex_lock(&module_mutex);
mod = find_module(name);
ret = !mod || mod->state != MODULE_STATE_COMING;
mutex_unlock(&module_mutex);
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,
......@@ -2868,7 +2955,7 @@ static struct module *load_module(void __user *umod,
const char __user *uargs)
{
struct load_info info = { NULL, };
struct module *mod;
struct module *mod, *old;
long err;
pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
......@@ -2886,6 +2973,12 @@ static struct module *load_module(void __user *umod,
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)
......@@ -2934,8 +3027,18 @@ static struct module *load_module(void __user *umod,
* function to insert in a way safe to concurrent readers.
* The mutex protects against concurrent writers.
*/
again:
mutex_lock(&module_mutex);
if (find_module(mod->name)) {
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;
}
......@@ -2975,7 +3078,7 @@ static struct module *load_module(void __user *umod,
/* 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:
......@@ -3050,7 +3153,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
free_module(mod);
wake_up(&module_wq);
wake_up_all(&module_wq);
return ret;
}
if (ret > 0) {
......@@ -3062,9 +3165,8 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
dump_stack();
}
/* Now it's a first class citizen! Wake up anyone waiting for it. */
/* Now it's a first class citizen! */
mod->state = MODULE_STATE_LIVE;
wake_up(&module_wq);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_LIVE, mod);
......@@ -3087,6 +3189,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
mod->init_ro_size = 0;
mod->init_text_size = 0;
mutex_unlock(&module_mutex);
wake_up_all(&module_wq);
return 0;
}
......
/* Module signature checker
*
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <crypto/public_key.h>
#include <crypto/hash.h>
#include <keys/asymmetric-type.h>
#include "module-internal.h"
/*
* 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 {
enum pkey_algo algo : 8; /* Public-key crypto algorithm */
enum pkey_hash_algo hash : 8; /* Digest algorithm */
enum pkey_id_type id_type : 8; /* Key identifier type */
u8 signer_len; /* Length of signer's name */
u8 key_id_len; /* Length of key identifier */
u8 __pad[3];
__be32 sig_len; /* Length of signature data */
};
/*
* Digest the module contents.
*/
static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
const void *mod,
unsigned long modlen)
{
struct public_key_signature *pks;
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
int ret;
pr_devel("==>%s()\n", __func__);
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm);
/* We allocate the hash operational data storage on the end of our
* context data and the digest output buffer on the end of that.
*/
ret = -ENOMEM;
pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
if (!pks)
goto error_no_pks;
pks->pkey_hash_algo = hash;
pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
pks->digest_size = digest_size;
desc = (void *)pks + sizeof(*pks);
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, mod, modlen, pks->digest);
if (ret < 0)
goto error;
crypto_free_shash(tfm);
pr_devel("<==%s() = ok\n", __func__);
return pks;
error:
kfree(pks);
error_no_pks:
crypto_free_shash(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ERR_PTR(ret);
}
/*
* Extract an MPI array from the signature data. This represents the actual
* signature. Each raw MPI is prefaced by a BE 2-byte value indicating the
* size of the MPI in bytes.
*
* RSA signatures only have one MPI, so currently we only read one.
*/
static int mod_extract_mpi_array(struct public_key_signature *pks,
const void *data, size_t len)
{
size_t nbytes;
MPI mpi;
if (len < 3)
return -EBADMSG;
nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1];
data += 2;
len -= 2;
if (len != nbytes)
return -EBADMSG;
mpi = mpi_read_raw_data(data, nbytes);
if (!mpi)
return -ENOMEM;
pks->mpi[0] = mpi;
pks->nr_mpi = 1;
return 0;
}
/*
* Request an asymmetric key.
*/
static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
const u8 *key_id, size_t key_id_len)
{
key_ref_t key;
size_t i;
char *id, *q;
pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len);
/* Construct an identifier. */
id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL);
if (!id)
return ERR_PTR(-ENOKEY);
memcpy(id, signer, signer_len);
q = id + signer_len;
*q++ = ':';
*q++ = ' ';
for (i = 0; i < key_id_len; i++) {
*q++ = hex_asc[*key_id >> 4];
*q++ = hex_asc[*key_id++ & 0x0f];
}
*q = 0;
pr_debug("Look up: \"%s\"\n", id);
key = keyring_search(make_key_ref(modsign_keyring, 1),
&key_type_asymmetric, id);
if (IS_ERR(key))
pr_warn("Request for unknown module key '%s' err %ld\n",
id, PTR_ERR(key));
kfree(id);
if (IS_ERR(key)) {
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
return ERR_CAST(key);
}
}
pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
return key_ref_to_ptr(key);
}
/*
* Verify the signature on a module.
*/
int mod_verify_sig(const void *mod, unsigned long modlen,
const void *sig, unsigned long siglen)
{
struct public_key_signature *pks;
struct module_signature ms;
struct key *key;
size_t sig_len;
int ret;
pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen);
if (siglen <= sizeof(ms))
return -EBADMSG;
memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms));
siglen -= sizeof(ms);
sig_len = be32_to_cpu(ms.sig_len);
if (sig_len >= siglen ||
siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len)
return -EBADMSG;
/* For the moment, only support RSA and X.509 identifiers */
if (ms.algo != PKEY_ALGO_RSA ||
ms.id_type != PKEY_ID_X509)
return -ENOPKG;
if (ms.hash >= PKEY_HASH__LAST ||
!pkey_hash_algo[ms.hash])
return -ENOPKG;
key = request_asymmetric_key(sig, ms.signer_len,
sig + ms.signer_len, ms.key_id_len);
if (IS_ERR(key))
return PTR_ERR(key);
pks = mod_make_digest(ms.hash, mod, modlen);
if (IS_ERR(pks)) {
ret = PTR_ERR(pks);
goto error_put_key;
}
ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len,
sig_len);
if (ret < 0)
goto error_free_pks;
ret = verify_signature(key, pks);
pr_devel("verify_signature() = %d\n", ret);
error_free_pks:
mpi_free(pks->rsa.s);
kfree(pks);
error_put_key:
key_put(key);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
......@@ -3,4 +3,4 @@
#
gen_crc32table
crc32table.h
oid_registry_data.c
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment