Discussion:
[PATCH 0/6] MODSIGN: Kernel module signing
David Howells
2007-02-14 19:09:38 UTC
Permalink
These patches provide a GPG-based kernel module signing facility. Their use is
not fully automated within the confines of the kernel build process because it
needs provision of keys from outside of the kernel before the kernel can be
compiled.

The patches are:

(1) A cut-down MPI library derived from GPG with error handling added.

(2) Permit hash algorithms to hash kernel data defined by a virtual address
and a length rather than trying to use scattergather lists (which require
struct page pointers to be determined).

(3) Add extra information to the per-arch ELF headers to more fully describe
the format of the ELF metadata.

(4) Add module verification capabilities, including ELF metadata verification.

(5) Add a generic DSA signature checker. Given a SHA1 hash of the data to be
verified and a binary blob holding a GPG signature stream, this verifies
the signature using a built-in ring of public keys.

(6) Add a module signature checker that applies signature checking to modules
on module load, checking the signature against the ring of public keys
compiled into the kernel.


These patches have been in use by RHEL and Fedora kernels for years, and so
have been thoroughly tested. The signed modules survive both the debuginfo
separation performed by rpmbuild and the strip performed when modules are being
reduced as much as possible before being included in an initial ramdisk
composition. Signed modules have been tested to work with LE and BE, 32- and
64-bit arch kernels, including i386, x86_64, ppc64, ia64, s390 and s390x.

There are several reasons why these patches are useful, amongst which are:

(1) to protect against accidentally-corrupted modules causing damage;

(2) to protect against maliciously modified modules causing damage;

(3) to allow a sysadmin (or more likely an IT department) to enforce a policy
that only known and approved modules shall be loaded onto machines which
they're expected to support;

(4) to allow other support providers to do likewise, or at least to _detect_
the fact that unsupported modules are loaded;

(5) to allow the detection of modules replaced by a second-order distro or a
preloaded Linux purveyor.

Basically, these patches have two main appeals to me: (a) preventing malicious
modules from being loaded, and (b) reducing support workload by pointing out
modules on a crashing box that aren't what they're expected to be.


Now, this is not a complete solution by any means: the core kernel is not
protected, and nor are /dev/mem or /dev/kmem, but it denies (or at least
controls) one relatively simple attack vector.

This facility is optional: the builder of a kernel is by no means under any
requirement to actually enable it, let alone force the set of loadable modules
to be restricted to just those that the builder provides (there are degrees of
restriction available).


Note to Andrew and Linus: Herbert Xu and the crypto guys need to check the
crypto bits before this should be accepted. Possibly these patches should go
via the crypto tree.

David
David Howells
2007-02-14 19:09:49 UTC
Permalink
Two extensions are added:

(1) Support for SHA1 digestion of in-kernel buffers directly without the use
of scatter-gather lists.

(2) Allocation of crypto algorithm instances without resort to fallback module
loading.

SHA1 is used by module signature checking, and so must not itself require
loading as a module when the module signature checking is enabled.

Signed-Off-By: David Howells <***@redhat.com>
---

crypto/api.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
crypto/digest.c | 9 +++++++++
include/linux/crypto.h | 11 +++++++++++
3 files changed, 65 insertions(+), 1 deletions(-)

diff --git a/crypto/api.c b/crypto/api.c
index 55af8bb..3138d7c 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -341,6 +341,45 @@ out:
EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);

/*
+ * crypto_alloc_tfm2 - Find or load crypto module
+ * @name: Name of algorithm
+ * @flags: Flags to control algorithm instance
+ * @nomodload: True to suppress resort to module loading
+ *
+ * Attempt to find or load a crypto algorithm module and create an
+ * instance of it.
+ */
+struct crypto_tfm *crypto_alloc_tfm2(const char *name, u32 flags,
+ int nomodload)
+{
+ struct crypto_tfm *tfm = NULL;
+ int err;
+
+ do {
+ struct crypto_alg *alg;
+
+ if (!nomodload)
+ alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC);
+ else
+ alg = crypto_alg_lookup(name, 0, CRYPTO_ALG_ASYNC);
+
+ err = PTR_ERR(alg);
+ if (IS_ERR(alg))
+ continue;
+
+ tfm = __crypto_alloc_tfm(alg, flags, 0);
+ err = 0;
+ if (IS_ERR(tfm)) {
+ crypto_mod_put(alg);
+ err = PTR_ERR(tfm);
+ tfm = NULL;
+ }
+ } while (err == -EAGAIN && !signal_pending(current));
+
+ return tfm;
+}
+
+/*
* crypto_alloc_base - Locate algorithm and allocate transform
* @alg_name: Name of algorithm
* @type: Type of algorithm
@@ -392,7 +431,12 @@ err:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(crypto_alloc_base);
-
+
+struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
+{
+ return crypto_alloc_tfm2(name, flags, 0);
+}
+
/*
* crypto_free_tfm - Free crypto transform
* @tfm: Transform to free
diff --git a/crypto/digest.c b/crypto/digest.c
index 1bf7414..d03a4e1 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -91,6 +91,14 @@ static int update(struct hash_desc *desc,
return update2(desc, sg, nbytes);
}

+static void update_kernel(struct hash_desc *desc,
+ const void *data, size_t count)
+{
+ struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
+ tfm->__crt_alg->cra_digest.dia_update(tfm, data, count);
+ crypto_yield(desc->flags);
+}
+
static int final(struct hash_desc *desc, u8 *out)
{
struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
@@ -146,6 +154,7 @@ int crypto_init_digest_ops(struct crypto_tfm *tfm)

ops->init = init;
ops->update = update;
+ ops->update_kernel = update_kernel;
ops->final = final;
ops->digest = digest;
ops->setkey = dalg->dia_setkey ? setkey : nosetkey;
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 779aa78..d960ec1 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -273,6 +273,8 @@ struct hash_tfm {
int (*init)(struct hash_desc *desc);
int (*update)(struct hash_desc *desc,
struct scatterlist *sg, unsigned int nsg);
+ void (*update_kernel)(struct hash_desc *desc,
+ const void *data, size_t count);
int (*final)(struct hash_desc *desc, u8 *out);
int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
unsigned int nsg, u8 *out);
@@ -341,6 +343,8 @@ struct crypto_attr_alg {
*/

struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
+struct crypto_tfm *crypto_alloc_tfm2(const char *alg_name, u32 tfm_flags,
+ int nomodload);
struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask);
void crypto_free_tfm(struct crypto_tfm *tfm);

@@ -739,6 +743,13 @@ static inline int crypto_hash_update(struct hash_desc *desc,
return crypto_hash_crt(desc->tfm)->update(desc, sg, nbytes);
}

+static inline void crypto_hash_update_kernel(struct hash_desc *desc,
+ const void *data,
+ size_t count)
+{
+ return crypto_hash_crt(desc->tfm)->update_kernel(desc, data, count);
+}
+
static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
{
return crypto_hash_crt(desc->tfm)->final(desc, out);
David Howells
2007-02-14 19:09:54 UTC
Permalink
Add per-arch indications of module ELF types and relocation table entry types.

Signed-Off-By: David Howells <***@redhat.com>
---

include/asm-alpha/module.h | 3 +++
include/asm-arm/module.h | 5 +++++
include/asm-cris/module.h | 5 +++++
include/asm-h8300/module.h | 5 +++++
include/asm-i386/module.h | 5 +++++
include/asm-ia64/module.h | 5 +++++
include/asm-m32r/module.h | 5 +++++
include/asm-m68k/module.h | 5 +++++
include/asm-mips/module.h | 12 ++++++++++--
include/asm-parisc/module.h | 8 ++++++++
include/asm-powerpc/module.h | 10 ++++++++++
include/asm-s390/module.h | 3 +++
include/asm-sh/module.h | 5 +++++
include/asm-sparc/module.h | 5 +++++
include/asm-sparc64/module.h | 5 +++++
include/asm-um/module-i386.h | 4 ++++
include/asm-v850/module.h | 5 +++++
include/asm-x86_64/module.h | 5 +++++
18 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/include/asm-alpha/module.h b/include/asm-alpha/module.h
index 7b63743..3d5a3ea 100644
--- a/include/asm-alpha/module.h
+++ b/include/asm-alpha/module.h
@@ -6,6 +6,7 @@ struct mod_arch_specific
unsigned int gotsecindex;
};

+#define MODULES_ARE_ELF64
#define Elf_Sym Elf64_Sym
#define Elf_Shdr Elf64_Shdr
#define Elf_Ehdr Elf64_Ehdr
@@ -13,6 +14,8 @@ struct mod_arch_specific
#define Elf_Dyn Elf64_Dyn
#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 ARCH_SHF_SMALL SHF_ALPHA_GPREL

diff --git a/include/asm-arm/module.h b/include/asm-arm/module.h
index 24b168d..f1558f3 100644
--- a/include/asm-arm/module.h
+++ b/include/asm-arm/module.h
@@ -6,9 +6,14 @@ struct mod_arch_specific
int foo;
};

+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)

/*
* Include the ARM architecture version.
diff --git a/include/asm-cris/module.h b/include/asm-cris/module.h
index 7ee7231..03f7b2e 100644
--- a/include/asm-cris/module.h
+++ b/include/asm-cris/module.h
@@ -3,7 +3,12 @@
/* cris is simple */
struct mod_arch_specific { };

+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)
#endif /* _ASM_CRIS_MODULE_H */
diff --git a/include/asm-h8300/module.h b/include/asm-h8300/module.h
index de23231..b1c08e2 100644
--- a/include/asm-h8300/module.h
+++ b/include/asm-h8300/module.h
@@ -4,9 +4,14 @@
* This file contains the H8/300 architecture specific module code.
*/
struct mod_arch_specific { };
+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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 MODULE_SYMBOL_PREFIX "_"

diff --git a/include/asm-i386/module.h b/include/asm-i386/module.h
index 02f8f54..42ab093 100644
--- a/include/asm-i386/module.h
+++ b/include/asm-i386/module.h
@@ -6,9 +6,14 @@ struct mod_arch_specific
{
};

+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)

#ifdef CONFIG_M386
#define MODULE_PROC_FAMILY "386 "
diff --git a/include/asm-ia64/module.h b/include/asm-ia64/module.h
index d2da61e..191355a 100644
--- a/include/asm-ia64/module.h
+++ b/include/asm-ia64/module.h
@@ -23,9 +23,14 @@ struct mod_arch_specific {
unsigned int next_got_entry; /* index of next available got entry */
};

+#define MODULES_ARE_ELF64
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
+#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 MODULE_PROC_FAMILY "ia64"
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \
diff --git a/include/asm-m32r/module.h b/include/asm-m32r/module.h
index eb73ee0..7146455 100644
--- a/include/asm-m32r/module.h
+++ b/include/asm-m32r/module.h
@@ -3,8 +3,13 @@

struct mod_arch_specific { };

+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)

#endif /* _ASM_M32R_MODULE_H */
diff --git a/include/asm-m68k/module.h b/include/asm-m68k/module.h
index c6d75af..ee98908 100644
--- a/include/asm-m68k/module.h
+++ b/include/asm-m68k/module.h
@@ -1,7 +1,12 @@
#ifndef _ASM_M68K_MODULE_H
#define _ASM_M68K_MODULE_H
struct mod_arch_specific { };
+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)
#endif /* _ASM_M68K_MODULE_H */
diff --git a/include/asm-mips/module.h b/include/asm-mips/module.h
index 399d03f..694f979 100644
--- a/include/asm-mips/module.h
+++ b/include/asm-mips/module.h
@@ -33,11 +33,15 @@ typedef struct {
} Elf64_Mips_Rela;

#ifdef CONFIG_32BIT
-
+#define MODULES_ARE_ELF32
#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
@@ -48,11 +52,15 @@ typedef struct {
#endif

#ifdef CONFIG_64BIT
-
+#define MODULES_ARE_ELF64
#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
diff --git a/include/asm-parisc/module.h b/include/asm-parisc/module.h
index 00f0688..ebd9a5e 100644
--- a/include/asm-parisc/module.h
+++ b/include/asm-parisc/module.h
@@ -4,17 +4,25 @@
* This file contains the parisc architecture specific module code.
*/
#ifdef __LP64__
+#define MODULES_ARE_ELF64
#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)
#else
+#define MODULES_ARE_ELF32
#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)
#endif

struct unwind_table;
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
index e5f14b1..f9baae1 100644
--- a/include/asm-powerpc/module.h
+++ b/include/asm-powerpc/module.h
@@ -52,16 +52,26 @@ struct mod_arch_specific {
*/

#ifdef __powerpc64__
+# define MODULES_ARE_ELF64
# define Elf_Shdr Elf64_Shdr
# define Elf_Sym Elf64_Sym
# define Elf_Ehdr Elf64_Ehdr
+# 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)
# ifdef MODULE
asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
# endif
#else
+# define MODULES_ARE_ELF32
# define Elf_Shdr Elf32_Shdr
# define Elf_Sym Elf32_Sym
# define Elf_Ehdr Elf32_Ehdr
+# 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)
# ifdef MODULE
asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
diff --git a/include/asm-s390/module.h b/include/asm-s390/module.h
index 1cc1c5a..b64dab0 100644
--- a/include/asm-s390/module.h
+++ b/include/asm-s390/module.h
@@ -29,14 +29,17 @@ struct mod_arch_specific
};

#ifdef __s390x__
+#define MODULES_ARE_ELF64
#define ElfW(x) Elf64_ ## x
#define ELFW(x) ELF64_ ## x
#else
+#define MODULES_ARE_ELF32
#define ElfW(x) Elf32_ ## x
#define ELFW(x) ELF32_ ## x
#endif

#define Elf_Addr ElfW(Addr)
+#define Elf_Rel ElfW(Rel)
#define Elf_Rela ElfW(Rela)
#define Elf_Shdr ElfW(Shdr)
#define Elf_Sym ElfW(Sym)
diff --git a/include/asm-sh/module.h b/include/asm-sh/module.h
index 118d5a2..c3cf495 100644
--- a/include/asm-sh/module.h
+++ b/include/asm-sh/module.h
@@ -9,9 +9,14 @@ struct mod_arch_specific {
/* Nothing to see here .. */
};

+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)

#ifdef CONFIG_CPU_LITTLE_ENDIAN
# ifdef CONFIG_CPU_SH2
diff --git a/include/asm-sparc/module.h b/include/asm-sparc/module.h
index cbd9e67..e2921e2 100644
--- a/include/asm-sparc/module.h
+++ b/include/asm-sparc/module.h
@@ -1,7 +1,12 @@
#ifndef _ASM_SPARC_MODULE_H
#define _ASM_SPARC_MODULE_H
struct mod_arch_specific { };
+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)
#endif /* _ASM_SPARC_MODULE_H */
diff --git a/include/asm-sparc64/module.h b/include/asm-sparc64/module.h
index 3d77ba4..2e7ca17 100644
--- a/include/asm-sparc64/module.h
+++ b/include/asm-sparc64/module.h
@@ -1,7 +1,12 @@
#ifndef _ASM_SPARC64_MODULE_H
#define _ASM_SPARC64_MODULE_H
struct mod_arch_specific { };
+#define MODULES_ARE_ELF64
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
+#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)
#endif /* _ASM_SPARC64_MODULE_H */
diff --git a/include/asm-um/module-i386.h b/include/asm-um/module-i386.h
index 5ead4a0..b441057 100644
--- a/include/asm-um/module-i386.h
+++ b/include/asm-um/module-i386.h
@@ -9,5 +9,9 @@ struct mod_arch_specific
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)

#endif
diff --git a/include/asm-v850/module.h b/include/asm-v850/module.h
index 2c2f494..48752f3 100644
--- a/include/asm-v850/module.h
+++ b/include/asm-v850/module.h
@@ -31,9 +31,14 @@ struct mod_arch_specific
unsigned int core_plt_section, init_plt_section;
};

+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#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)

/* Make empty sections for module_frob_arch_sections to expand. */
#ifdef MODULE
diff --git a/include/asm-x86_64/module.h b/include/asm-x86_64/module.h
index 67f8f69..3a7373a 100644
--- a/include/asm-x86_64/module.h
+++ b/include/asm-x86_64/module.h
@@ -3,8 +3,13 @@

struct mod_arch_specific {};

+#define MODULES_ARE_ELF64
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
+#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)

#endif
David Howells
2007-02-14 19:10:09 UTC
Permalink
Apply signature checking to modules on module load, checking the signature
against the ring of public keys compiled into the kernel (if enabled by
CONFIG_MODULE_SIG). Turning on signature checking will also force the module's
ELF metadata to be verified first.

These patches have been in use by RHEL and Fedora kernels for years, and so
have been thoroughly tested. The signed modules survive both the debuginfo
separation performed by rpmbuild and the strip performed when modules are being
reduced as much as possible before being included in an initial ramdisk
composition. Signed modules have been tested to work with LE and BE, 32- and
64-bit arch kernels, including i386, x86_64, ppc64, ia64, s390 and s390x.

There are several reasons why these patches are useful, amongst which are:

(1) to protect against accidentally-corrupted modules causing damage;

(2) to protect against maliciously modified modules causing damage;

(3) to allow a sysadmin (or more likely an IT department) to enforce a policy
that only known and approved modules shall be loaded onto machines which
they're expected to support;

(4) to allow other support providers to do likewise, or at least to _detect_
the fact that unsupported modules are loaded;

(5) to allow the detection of modules replaced by a second-order distro or a
preloaded Linux purveyor.

Basically, these patches have two main appeals to me: (a) preventing malicious
modules from being loaded, and (b) reducing support workload by pointing out
modules on a crashing box that aren't what they're expected to be.

Now, this is not a complete solution by any means: the core kernel is not
protected, and nor are /dev/mem or /dev/kmem, but it denies (or at least
controls) one relatively simple attack vector.

This facility is optional: the builder of a kernel is by no means under any
requirement to actually enable it, let alone force the set of loadable modules
to be restricted to just those that the builder provides (there are degrees of
restriction available).


Use of the module signing facility is documentated in:

Documentation/module-signing.txt

which I've included here for reference:

==============================
KERNEL MODULE SIGNING FACILITY
==============================

The module signing facilitiy applies cryptographic signature checking to
modules on module load, checking the signature against a ring of public keys
compiled into the kernel. GPG is used to do the cryptographic work and
determines the format of the signature and key data. The facility uses GPG's
MPI library to handle the huge numbers involved.

This facility is enabled through CONFIG_MODULE_SIG. Turning on signature
checking will also force the module's ELF metadata to be verified before the
signature is checked.


=====================
SUPPLYING PUBLIC KEYS
=====================

A set of public keys must be supplied at main kernel compile time. This is
done by taking a GPG public key file, running it through the kernel's bin2c
program and writing the result over crypto/signature/key.h. To automate this
process, something like this could be done:

cat >genkey <<EOF
%pubring kernel.pub
%secring kernel.sec
Key-Type: DSA
Key-Length: 512
Name-Real: A. N. Other
Name-Comment: Kernel Module GPG key
%commit
EOF
make scripts/bin2c
gpg --homedir . --batch --gen-key genkey
gpg --homedir . --export --keyring kernel.pub keyname |
scripts/bin2c ksign_def_public_key __initdata >crypto/signature/key.h

The above generates fresh keys using /dev/random. If there's insufficient data
in /dev/random, more can be provided more by running:

rngd -r /dev/urandom

in the background.

Note:

(1) That "keyname" is the name of the key in the keyring. This differentiates
it from any other keys that may be added to the keyring.

(2) That no GPG password is used in the above scriptlet.

(3) It may be desirable to shred and delete the private key file after signing
the modules.


==============
MODULE SIGNING
==============

Modules will then be signed automatically. The kernel make command line can
include the following options:

(*) MODSECKEY=<secret-key-ring-path>

This indicates the whereabouts of the GPG keyring that is the source of
the secret key to be used. The default is "./kernel.sec".

(*) MODPUBKEY=<public-key-ring-path>

This indicates the whereabouts of the GPG keyring that is the source of
the public key to be used. The default is "./kernel.pub".

(*) MODKEYNAME=<key-name>

The name of the key pair to be used from the aforementioned keyrings.
This defaults to being unset, thus leaving the choice of default key to
gpg.

(*) KEYFLAGS="gpg-options"

Override the complete gpg command line, including the preceding three
options. The default options supplied to gpg are:

--no-default-keyring
--secret-keyring $(MODSECKEY)
--keyring $(MODPUBKEY)
--no-default-keyring
--homedir .
--no-options
--no-auto-check-trustdb
--no-permission-warning

with:

--default-key $(MODKEYNAME)

being added if requested.

The resulting module.ko file will be the signed module.


========================
STRIPPING SIGNED MODULES
========================

Signed modules may be safely stripped as the signature only covers those parts
of the module the kernel actually uses and any ELF metadata required to deal
with them. Any necessary ELF metadata that is affected by stripping is
canonicalised by the sig generator and the sig checker to hide strip effects.

This permits the debuginfo to be detached from the module and placed in another
spot so that gdb can find it when referring to that module without the need for
multiple signed versions of the module. Such is done by rpmbuild when
producing RPMs.

It also permits the module to be stripped as far as possible for when modules
are being reduced prior to being included in an initial ramdisk composition.


======================
LOADING SIGNED MODULES
======================

Modules are loaded with insmod, exactly as for unsigned modules. The signature
is inserted into the module object file as an ELF section called ".module_sig".
The signature checker will spot it and apply signature checking.


=========================================
NON-VALID SIGNATURES AND UNSIGNED MODULES
=========================================

If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on
the kernel command line, the kernel will _only_ load validly signed modules
for which it has a public key. Otherwise, it will also load modules that are
unsigned. Any module for which the kernel has a key, but which proves to have
a signature mismatch will not be permitted to load (returning EKEYREJECTED).

This table indicates the behaviours of the various situations:

MODULE STATE PERMISSIVE MODE ENFORCING MODE
=============================== =============== ===============
Unsigned Ok EKEYREJECTED
Signed, no public key ENOKEY ENOKEY
Validly signed, public key Ok Ok
Invalidly signed, public key EKEYREJECTED EKEYREJECTED
Validly signed, expired key EKEYEXPIRED EKEYEXPIRED
Corrupt signature ELIBBAD ELIBBAD