diff options
-rw-r--r-- | genkey | 6 | ||||
-rw-r--r-- | kernel.spec | 29 | ||||
-rw-r--r-- | modsign-20120510.patch (renamed from modsign-20111207.patch) | 4606 |
3 files changed, 2665 insertions, 1976 deletions
@@ -1,5 +1,7 @@ -%pubring kernel.pub -%secring kernel.sec +%pubring modsign.pub +%secring modsign.sec +%no-protection: yes +%transient-key: yes Key-Type: RSA Key-Length: 2048 Name-Real: Fedora Project diff --git a/kernel.spec b/kernel.spec index 204372f7b..a2831a5bf 100644 --- a/kernel.spec +++ b/kernel.spec @@ -675,7 +675,7 @@ Patch700: linux-2.6-e1000-ich9-montevina.patch Patch800: linux-2.6-crash-driver.patch # crypto/ -Patch900: modsign-20111207.patch +Patch900: modsign-20120510.patch # virt + ksm patches Patch1555: fix_xen_guest_on_old_EC2.patch @@ -1382,7 +1382,7 @@ ApplyPatch linux-2.6-crash-driver.patch ApplyPatch linux-2.6-e1000-ich9-montevina.patch # crypto/ -ApplyPatch modsign-20111207.patch +ApplyPatch modsign-20120510.patch # Assorted Virt Fixes ApplyPatch fix_xen_guest_on_old_EC2.patch @@ -1495,27 +1495,7 @@ find . \( -name "*.orig" -o -name "*~" \) -exec rm -f {} \; >/dev/null find . -name .gitignore -exec rm -f {} \; >/dev/null %if %{signmodules} -cat <<EOF -### -### Now generating a PGP key pair to be used for signing modules. -### -### If this takes a long time, you might wish to run rngd in the background to -### keep the supply of entropy topped up. It needs to be run as root, and -### should use a hardware random number generator if one is available, eg: -### -### rngd -r /dev/hwrandom -### -### If one isn't available, the pseudo-random number generator can be used: -### -### rngd -r /dev/urandom -### -EOF -gpg --homedir . --batch --gen-key %{SOURCE11} -cat <<EOF -### -### Key pair generated. -### -EOF +cp %{SOURCE11} . %endif cd .. @@ -2317,6 +2297,9 @@ fi # ||----w | # || || %changelog +* Mon May 21 2012 Josh Boyer <jwboyer@redhat.com> +- Update the modsign patchset to the most recent version + * Mon May 21 2012 Josh Boyer <jwboyer@redhat.com> - 3.5.0-0.rc0.git1.2 - Linux v3.4-1622-g31a6710 diff --git a/modsign-20111207.patch b/modsign-20120510.patch index 5eee17a87..d9aabf83a 100644 --- a/modsign-20111207.patch +++ b/modsign-20120510.patch @@ -1,7 +1,7 @@ -From 5ba13e189c831b8ad2bfb14f4599b9b9d00cc5ae Mon Sep 17 00:00:00 2001 +From d093caa39460495390c94556f0680218223168c2 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:04 +0000 -Subject: MPILIB: Export some more symbols +Date: Fri, 4 May 2012 15:55:49 +0100 +Subject: [PATCH 01/36] MPILIB: Export some more symbols Export some more symbols for use by the DSA key subtype. @@ -12,7 +12,7 @@ Signed-off-by: David Howells <dhowells@redhat.com> lib/mpi/mpi-inv.c | 1 + lib/mpi/mpi-mpow.c | 1 + lib/mpi/mpi-mul.c | 1 + - 5 files changed, 6 insertions(+), 0 deletions(-) + 5 files changed, 6 insertions(+) diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c index 914bc42..1871e7b 100644 @@ -32,7 +32,7 @@ index 914bc42..1871e7b 100644 } +EXPORT_SYMBOL_GPL(mpi_cmp); diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c -index c3087d1..3da9402 100644 +index f68cbbb..fed3405 100644 --- a/lib/mpi/mpi-div.c +++ b/lib/mpi/mpi-div.c @@ -59,6 +59,7 @@ nomem: @@ -53,11 +53,11 @@ index 0951f98..bfc5ca1 100644 } +EXPORT_SYMBOL_GPL(mpi_invm); diff --git a/lib/mpi/mpi-mpow.c b/lib/mpi/mpi-mpow.c -index 4cc7593..5752194 100644 +index 7328d0d..b8b22e5 100644 --- a/lib/mpi/mpi-mpow.c +++ b/lib/mpi/mpi-mpow.c -@@ -131,3 +131,4 @@ nomem: - kfree(G); +@@ -132,3 +132,4 @@ nomem: + err_out: return rc; } +EXPORT_SYMBOL_GPL(mpi_mulpowm); @@ -71,26 +71,26 @@ index 1f3219e..3d514b9 100644 } +EXPORT_SYMBOL_GPL(mpi_mulm); -- -1.7.9.1 +1.7.10.2 -From 7a5782bc39eba97f3499e3d2686fe48d26f261b0 Mon Sep 17 00:00:00 2001 +From 335abcad2d9fa26198c8e99bae2bb9b3185dce22 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:06 +0000 -Subject: KEYS: Move the key config into security/keys/Kconfig +Date: Fri, 4 May 2012 15:55:50 +0100 +Subject: [PATCH 02/36] KEYS: Move the key config into security/keys/Kconfig Move the key config into security/keys/Kconfig as there are going to be a lot of key-related options. Signed-off-by: David Howells <dhowells@redhat.com> --- - security/Kconfig | 68 +---------------------------------------------- + security/Kconfig | 68 +--------------------------------------------- security/keys/Kconfig | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 67 deletions(-) create mode 100644 security/keys/Kconfig diff --git a/security/Kconfig b/security/Kconfig -index 51bd5a0..1c5a7a4 100644 +index ccc61f8..e9c6ac7 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -4,73 +4,7 @@ @@ -246,13 +246,13 @@ index 0000000..a90d6d3 + + If you are unsure as to whether this is required, answer N. -- -1.7.9.1 +1.7.10.2 -From f8b45d1f0f1bdd4c29733f462f6f43518ea625d3 Mon Sep 17 00:00:00 2001 +From 6569015cb5801f36324c76dee156a3e880fcf9be Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:07 +0000 -Subject: KEYS: Announce key type (un)registration +Date: Fri, 4 May 2012 15:55:50 +0100 +Subject: [PATCH 03/36] KEYS: Announce key type (un)registration Announce the (un)registration of a key type in the core key code rather than in the callers. @@ -264,7 +264,7 @@ Signed-off-by: David Howells <dhowells@redhat.com> 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c -index fa000d2..689d7c8 100644 +index c73bba3..14b2c3d 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -249,9 +249,6 @@ static int __init init_dns_resolver(void) @@ -277,7 +277,7 @@ index fa000d2..689d7c8 100644 /* create an override credential set with a special thread keyring in * which DNS requests are cached * -@@ -300,8 +297,6 @@ static void __exit exit_dns_resolver(void) +@@ -301,8 +298,6 @@ static void __exit exit_dns_resolver(void) key_revoke(dns_resolver_cache->thread_keyring); unregister_key_type(&key_type_dns_resolver); put_cred(dns_resolver_cache); @@ -287,10 +287,10 @@ index fa000d2..689d7c8 100644 module_init(init_dns_resolver) diff --git a/security/keys/key.c b/security/keys/key.c -index 4414abd..a8086a1 100644 +index 06783cf..dc62894 100644 --- a/security/keys/key.c +++ b/security/keys/key.c -@@ -957,6 +957,8 @@ int register_key_type(struct key_type *ktype) +@@ -980,6 +980,8 @@ int register_key_type(struct key_type *ktype) /* store the type */ list_add(&ktype->link, &key_types_list); @@ -299,7 +299,7 @@ index 4414abd..a8086a1 100644 ret = 0; out: -@@ -979,6 +981,7 @@ void unregister_key_type(struct key_type *ktype) +@@ -1002,6 +1004,7 @@ void unregister_key_type(struct key_type *ktype) list_del_init(&ktype->link); downgrade_write(&key_types_sem); key_gc_keytype(ktype); @@ -308,13 +308,13 @@ index 4414abd..a8086a1 100644 } EXPORT_SYMBOL(unregister_key_type); -- -1.7.9.1 +1.7.10.2 -From bc9e72fd7ba0f06b89c2887a2e2eefef0441d92d Mon Sep 17 00:00:00 2001 +From 13628af46a92a030fdb7dc33976b46cfcc4b3f31 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:08 +0000 -Subject: KEYS: Reorganise keys Makefile +Date: Fri, 4 May 2012 15:55:51 +0100 +Subject: [PATCH 04/36] KEYS: Reorganise keys Makefile Reorganise the keys directory Makefile to put all the core bits together and the type-specific bits after. @@ -322,7 +322,7 @@ the type-specific bits after. Signed-off-by: David Howells <dhowells@redhat.com> --- security/keys/Makefile | 12 +++++++++--- - 1 files changed, 9 insertions(+), 3 deletions(-) + 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/security/keys/Makefile b/security/keys/Makefile index a56f1ff..504aaa0 100644 @@ -355,14 +355,14 @@ index a56f1ff..504aaa0 100644 +obj-$(CONFIG_TRUSTED_KEYS) += trusted.o +obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ -- -1.7.9.1 +1.7.10.2 -From b78b34f3950b08d1def84449e10e4560d7cee280 Mon Sep 17 00:00:00 2001 +From 8c5366bc5c1c9ecaa1104d769f60c7b83ed342a9 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:08 +0000 -Subject: KEYS: Create a key type that can be used for general cryptographic - operations +Date: Fri, 4 May 2012 16:15:09 +0100 +Subject: [PATCH 05/36] KEYS: Create a key type that can be used for general + cryptographic operations Create a key type that can be used for general cryptographic operations, such as encryption, decryption, signature generation and signature verification. @@ -375,16 +375,20 @@ Signed-off-by: David Howells <dhowells@redhat.com> Documentation/security/keys-crypto.txt | 181 +++++++++++++++++++++++++ include/keys/crypto-subtype.h | 56 ++++++++ include/keys/crypto-type.h | 25 ++++ - security/keys/Kconfig | 8 + - security/keys/Makefile | 3 + - security/keys/crypto_keys.h | 28 ++++ - security/keys/crypto_type.c | 228 ++++++++++++++++++++++++++++++++ - 7 files changed, 529 insertions(+), 0 deletions(-) + security/keys/Kconfig | 2 + + security/keys/Makefile | 1 + + security/keys/crypto/Kconfig | 7 + + security/keys/crypto/Makefile | 7 + + security/keys/crypto/crypto_keys.h | 28 ++++ + security/keys/crypto/crypto_type.c | 228 ++++++++++++++++++++++++++++++++ + 9 files changed, 535 insertions(+) create mode 100644 Documentation/security/keys-crypto.txt create mode 100644 include/keys/crypto-subtype.h create mode 100644 include/keys/crypto-type.h - create mode 100644 security/keys/crypto_keys.h - create mode 100644 security/keys/crypto_type.c + create mode 100644 security/keys/crypto/Kconfig + create mode 100644 security/keys/crypto/Makefile + create mode 100644 security/keys/crypto/crypto_keys.h + create mode 100644 security/keys/crypto/crypto_type.c diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt new file mode 100644 @@ -667,14 +671,30 @@ index 0000000..47c00c7 + +#endif /* _KEYS_CRYPTO_TYPE_H */ diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index a90d6d3..290c9d3 100644 +index a90d6d3..992fe52 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig -@@ -69,3 +69,11 @@ config KEYS_DEBUG_PROC_KEYS +@@ -69,3 +69,5 @@ config KEYS_DEBUG_PROC_KEYS the resulting table. If you are unsure as to whether this is required, answer N. + ++source security/keys/crypto/Kconfig +diff --git a/security/keys/Makefile b/security/keys/Makefile +index 504aaa0..67dae73 100644 +--- a/security/keys/Makefile ++++ b/security/keys/Makefile +@@ -24,3 +24,4 @@ obj-$(CONFIG_SYSCTL) += sysctl.o + # + obj-$(CONFIG_TRUSTED_KEYS) += trusted.o + obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ ++obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto/ +diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig +new file mode 100644 +index 0000000..3d15710 +--- /dev/null ++++ b/security/keys/crypto/Kconfig +@@ -0,0 +1,7 @@ +config CRYPTO_KEY_TYPE + tristate "Cryptographic key type" + depends on KEYS @@ -682,22 +702,24 @@ index a90d6d3..290c9d3 100644 + This option provides support for a type of key that holds the keys + required for cryptographic operations such as encryption, decryption, + signature generation and signature verification. -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 504aaa0..67fceaa 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -24,3 +24,6 @@ obj-$(CONFIG_SYSCTL) += sysctl.o - # - obj-$(CONFIG_TRUSTED_KEYS) += trusted.o - obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +new file mode 100644 +index 0000000..36db1d5 +--- /dev/null ++++ b/security/keys/crypto/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for cryptographic keys ++# ++ +obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + +crypto_keys-y := crypto_type.o -diff --git a/security/keys/crypto_keys.h b/security/keys/crypto_keys.h +diff --git a/security/keys/crypto/crypto_keys.h b/security/keys/crypto/crypto_keys.h new file mode 100644 index 0000000..a339ce0 --- /dev/null -+++ b/security/keys/crypto_keys.h ++++ b/security/keys/crypto/crypto_keys.h @@ -0,0 +1,28 @@ +/* Internal crypto type stuff + * @@ -727,11 +749,11 @@ index 0000000..a339ce0 + */ +extern struct list_head crypto_key_parsers; +extern struct rw_semaphore crypto_key_parsers_sem; -diff --git a/security/keys/crypto_type.c b/security/keys/crypto_type.c +diff --git a/security/keys/crypto/crypto_type.c b/security/keys/crypto/crypto_type.c new file mode 100644 index 0000000..33d279b --- /dev/null -+++ b/security/keys/crypto_type.c ++++ b/security/keys/crypto/crypto_type.c @@ -0,0 +1,228 @@ +/* Cryptographic key type + * @@ -962,13 +984,13 @@ index 0000000..33d279b +module_init(crypto_key_init); +module_exit(crypto_key_cleanup); -- -1.7.9.1 +1.7.10.2 -From 9d66ee5300d0d1391367dd002eba6663aaf33760 Mon Sep 17 00:00:00 2001 +From e8d4b12988cd23815f1a5f4654d819f5a0a2194b Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:09 +0000 -Subject: KEYS: Add signature verification facility +Date: Fri, 4 May 2012 16:15:57 +0100 +Subject: [PATCH 06/36] KEYS: Add signature verification facility Add a facility whereby a key subtype may be asked to verify a signature against the data it is purported to have signed. @@ -1003,10 +1025,10 @@ Signed-off-by: David Howells <dhowells@redhat.com> Documentation/security/keys-crypto.txt | 101 +++++++++++++++++++++++++++++ include/keys/crypto-subtype.h | 21 ++++++ include/keys/crypto-type.h | 9 +++ - security/keys/Makefile | 2 +- - security/keys/crypto_verify.c | 111 ++++++++++++++++++++++++++++++++ - 5 files changed, 243 insertions(+), 1 deletions(-) - create mode 100644 security/keys/crypto_verify.c + security/keys/crypto/Makefile | 2 +- + security/keys/crypto/crypto_verify.c | 111 ++++++++++++++++++++++++++++++++ + 5 files changed, 243 insertions(+), 1 deletion(-) + create mode 100644 security/keys/crypto/crypto_verify.c diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt index 97dee80..a964717 100644 @@ -1207,21 +1229,21 @@ index 47c00c7..6b93366 100644 /* * The payload is at the discretion of the subtype. */ -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 67fceaa..8462904 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -26,4 +26,4 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o - obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 36db1d5..67001bc 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -4,4 +4,4 @@ + obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o -crypto_keys-y := crypto_type.o +crypto_keys-y := crypto_type.o crypto_verify.o -diff --git a/security/keys/crypto_verify.c b/security/keys/crypto_verify.c +diff --git a/security/keys/crypto/crypto_verify.c b/security/keys/crypto/crypto_verify.c new file mode 100644 index 0000000..65f734c --- /dev/null -+++ b/security/keys/crypto_verify.c ++++ b/security/keys/crypto/crypto_verify.c @@ -0,0 +1,111 @@ +/* Signature verification with a crypto key + * @@ -1335,32 +1357,33 @@ index 0000000..65f734c +} +EXPORT_SYMBOL_GPL(verify_sig_cancel); -- -1.7.9.1 +1.7.10.2 -From 8842a89fac8ac5a9691fb8ff381cdf98e23e8029 Mon Sep 17 00:00:00 2001 +From db170ec4f4df7d8f188134c9c9a3e2736ec0dbff Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:10 +0000 -Subject: KEYS: Asymmetric public-key algorithm crypto key subtype +Date: Fri, 4 May 2012 16:16:46 +0100 +Subject: [PATCH 07/36] KEYS: Asymmetric public-key algorithm crypto key + subtype Add a subtype for supporting asymmetric public-key encryption algorithms such as DSA (FIPS-186) and RSA (PKCS#1 / RFC1337). Signed-off-by: David Howells <dhowells@redhat.com> --- - security/keys/Kconfig | 9 ++++ - security/keys/Makefile | 1 + - security/keys/public_key.c | 55 +++++++++++++++++++++++ - security/keys/public_key.h | 106 ++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 171 insertions(+), 0 deletions(-) - create mode 100644 security/keys/public_key.c - create mode 100644 security/keys/public_key.h - -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index 290c9d3..07c7f3b 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -77,3 +77,12 @@ config CRYPTO_KEY_TYPE + security/keys/crypto/Kconfig | 10 ++++ + security/keys/crypto/Makefile | 3 +- + security/keys/crypto/public_key.c | 55 +++++++++++++++++++ + security/keys/crypto/public_key.h | 106 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 173 insertions(+), 1 deletion(-) + create mode 100644 security/keys/crypto/public_key.c + create mode 100644 security/keys/crypto/public_key.h + +diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig +index 3d15710..5f2b8ac 100644 +--- a/security/keys/crypto/Kconfig ++++ b/security/keys/crypto/Kconfig +@@ -5,3 +5,13 @@ config CRYPTO_KEY_TYPE This option provides support for a type of key that holds the keys required for cryptographic operations such as encryption, decryption, signature generation and signature verification. @@ -1368,27 +1391,29 @@ index 290c9d3..07c7f3b 100644 +config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE + tristate "Asymmetric public-key crypto algorithm subtype" + depends on CRYPTO_KEY_TYPE ++ 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. -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 8462904..dc3281f 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -25,5 +25,6 @@ obj-$(CONFIG_SYSCTL) += sysctl.o - obj-$(CONFIG_TRUSTED_KEYS) += trusted.o - obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ - obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o -+obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 67001bc..6384306 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -3,5 +3,6 @@ + # + obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o +- crypto_keys-y := crypto_type.o crypto_verify.o -diff --git a/security/keys/public_key.c b/security/keys/public_key.c ++ ++obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o +diff --git a/security/keys/crypto/public_key.c b/security/keys/crypto/public_key.c new file mode 100644 index 0000000..c00ddac --- /dev/null -+++ b/security/keys/public_key.c ++++ b/security/keys/crypto/public_key.c @@ -0,0 +1,55 @@ +/* Asymmetric public key crypto subtype + * @@ -1445,11 +1470,11 @@ index 0000000..c00ddac + .destroy = public_key_destroy, +}; +EXPORT_SYMBOL_GPL(public_key_crypto_key_subtype); -diff --git a/security/keys/public_key.h b/security/keys/public_key.h +diff --git a/security/keys/crypto/public_key.h b/security/keys/crypto/public_key.h new file mode 100644 index 0000000..81ed603 --- /dev/null -+++ b/security/keys/public_key.h ++++ b/security/keys/crypto/public_key.h @@ -0,0 +1,106 @@ +/* Asymmetric public-key algorithm definitions + * @@ -1558,13 +1583,13 @@ index 0000000..81ed603 + +#endif /* _LINUX_PUBLIC_KEY_H */ -- -1.7.9.1 +1.7.10.2 -From 6fc88dcf4610907920e8ec8fc9d11610a23b12ae Mon Sep 17 00:00:00 2001 +From 07f1001d10c926d28b92f0a32dbb57131a0f0942 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:11 +0000 -Subject: KEYS: RSA signature verification algorithm +Date: Fri, 4 May 2012 16:30:18 +0100 +Subject: [PATCH 08/36] KEYS: RSA signature verification algorithm Implement the RSA algorithm (PKCS#1 / RFC3447). At this time, only signature verification is supported. This uses the asymmetric public key subtype to hold @@ -1572,18 +1597,18 @@ its key data. Signed-off-by: David Howells <dhowells@redhat.com> --- - security/keys/Kconfig | 6 + - security/keys/Makefile | 1 + - security/keys/crypto_rsa.c | 282 ++++++++++++++++++++++++++++++++++++++++++++ - security/keys/public_key.h | 2 + - 4 files changed, 291 insertions(+), 0 deletions(-) - create mode 100644 security/keys/crypto_rsa.c - -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index 07c7f3b..65d640b 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -86,3 +86,9 @@ config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE + security/keys/crypto/Kconfig | 7 + + security/keys/crypto/Makefile | 1 + + security/keys/crypto/crypto_rsa.c | 282 +++++++++++++++++++++++++++++++++++++ + security/keys/crypto/public_key.h | 2 + + 4 files changed, 292 insertions(+) + create mode 100644 security/keys/crypto/crypto_rsa.c + +diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig +index 5f2b8ac..4e3777e 100644 +--- a/security/keys/crypto/Kconfig ++++ b/security/keys/crypto/Kconfig +@@ -15,3 +15,10 @@ config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE 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. @@ -1591,24 +1616,23 @@ index 07c7f3b..65d640b 100644 +config CRYPTO_KEY_PKEY_ALGO_RSA + tristate "RSA public-key algorithm" + depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE ++ select MPILIB_EXTRA + help + This option enables support for the RSA algorithm (PKCS#1, RFC3447). -diff --git a/security/keys/Makefile b/security/keys/Makefile -index dc3281f..59e7180 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -26,5 +26,6 @@ obj-$(CONFIG_TRUSTED_KEYS) += trusted.o - obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ - obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 6384306..b6b1a5a 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -6,3 +6,4 @@ obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o + crypto_keys-y := crypto_type.o crypto_verify.o + obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o +obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o - - crypto_keys-y := crypto_type.o crypto_verify.o -diff --git a/security/keys/crypto_rsa.c b/security/keys/crypto_rsa.c +diff --git a/security/keys/crypto/crypto_rsa.c b/security/keys/crypto/crypto_rsa.c new file mode 100644 index 0000000..beb5181 --- /dev/null -+++ b/security/keys/crypto_rsa.c ++++ b/security/keys/crypto/crypto_rsa.c @@ -0,0 +1,282 @@ +/* RSA asymmetric public-key algorithm [RFC3447] + * @@ -1892,10 +1916,10 @@ index 0000000..beb5181 + .verify = RSA_verify_signature, +}; +EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); -diff --git a/security/keys/public_key.h b/security/keys/public_key.h +diff --git a/security/keys/crypto/public_key.h b/security/keys/crypto/public_key.h index 81ed603..7913615 100644 ---- a/security/keys/public_key.h -+++ b/security/keys/public_key.h +--- a/security/keys/crypto/public_key.h ++++ b/security/keys/crypto/public_key.h @@ -42,6 +42,8 @@ struct public_key_algorithm { const struct public_key_signature *sig); }; @@ -1906,13 +1930,68 @@ index 81ed603..7913615 100644 * Asymmetric public key data */ -- -1.7.9.1 +1.7.10.2 + + +From a1ac402f327ab537a629c4d365b3f5461eaecb82 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 4 May 2012 16:30:20 +0100 +Subject: [PATCH 09/36] Fix signature verification for shorter signatures + +gpg can produce a signature file where length of signature is less than the +modulus size because the amount of space an MPI takes up is kept as low as +possible by discarding leading zeros. This regularly happens for several +modules during the build. + +Fix it by relaxing check in RSA verification code. + +Thanks to Tomas Mraz and Miloslav Trmac for help. + +Signed-off-by: Milan Broz <mbroz@redhat.com> +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/crypto/crypto_rsa.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/security/keys/crypto/crypto_rsa.c b/security/keys/crypto/crypto_rsa.c +index beb5181..cc5cd95 100644 +--- a/security/keys/crypto/crypto_rsa.c ++++ b/security/keys/crypto/crypto_rsa.c +@@ -219,15 +219,23 @@ static int RSA_verify_signature(const struct public_key *key, + kenter(""); + + /* (1) Check the signature size against the public key modulus size */ +- k = (mpi_get_nbits(key->rsa.n) + 7) / 8; ++ k = mpi_get_nbits(key->rsa.n); ++ tsize = mpi_get_nbits(sig->rsa.s); + +- tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; ++ /* 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 (tsize != k) { ++ 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) +-- +1.7.10.2 -From 82b8d487e66a5218ca9f91ca406db97b2113da60 Mon Sep 17 00:00:00 2001 +From d682ea629a2494aab705468d1479058a03fd7879 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:11 +0000 -Subject: PGPLIB: PGP definitions (RFC 4880) +Date: Fri, 4 May 2012 16:30:23 +0100 +Subject: [PATCH 10/36] PGPLIB: PGP definitions (RFC 4880) Provide some useful PGP definitions from RFC 4880. These describe details of public key crypto as used by crypto keys for things like signature @@ -1921,7 +2000,7 @@ verification. Signed-off-by: David Howells <dhowells@redhat.com> --- include/linux/pgp.h | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 files changed, 206 insertions(+), 0 deletions(-) + 1 file changed, 206 insertions(+) create mode 100644 include/linux/pgp.h diff --git a/include/linux/pgp.h b/include/linux/pgp.h @@ -2137,13 +2216,13 @@ index 0000000..1359f64 + +#endif /* _LINUX_PGP_H */ -- -1.7.9.1 +1.7.10.2 -From 570b106e22577e362c2772bdbfa1049c894b5cfb Mon Sep 17 00:00:00 2001 +From 651d6e549374b13b2d0473db17df90ab66abf855 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:12 +0000 -Subject: PGPLIB: Basic packet parser +Date: Fri, 4 May 2012 16:33:28 +0100 +Subject: [PATCH 11/36] PGPLIB: Basic packet parser Provide a simple parser that extracts the packets from a PGP packet blob and passes the desirous ones to the given processor function: @@ -2164,12 +2243,12 @@ This is configured on with CONFIG_PGP_LIBRARY. Signed-off-by: David Howells <dhowells@redhat.com> --- - include/linux/pgp.h | 25 ++++ - security/keys/Kconfig | 6 + - security/keys/Makefile | 1 + - security/keys/pgp_library.c | 254 +++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 286 insertions(+), 0 deletions(-) - create mode 100644 security/keys/pgp_library.c + include/linux/pgp.h | 25 ++++ + security/keys/crypto/Kconfig | 6 + + security/keys/crypto/Makefile | 1 + + security/keys/crypto/pgp_library.c | 254 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 286 insertions(+) + create mode 100644 security/keys/crypto/pgp_library.c diff --git a/include/linux/pgp.h b/include/linux/pgp.h index 1359f64..235270a 100644 @@ -2205,12 +2284,12 @@ index 1359f64..235270a 100644 + struct pgp_parse_pubkey *pk); + #endif /* _LINUX_PGP_H */ -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index 65d640b..aa3954c 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -92,3 +92,9 @@ config CRYPTO_KEY_PKEY_ALGO_RSA - depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE +diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig +index 4e3777e..88ce0e2 100644 +--- a/security/keys/crypto/Kconfig ++++ b/security/keys/crypto/Kconfig +@@ -22,3 +22,9 @@ config CRYPTO_KEY_PKEY_ALGO_RSA + select MPILIB_EXTRA help This option enables support for the RSA algorithm (PKCS#1, RFC3447). + @@ -2219,22 +2298,20 @@ index 65d640b..aa3954c 100644 + help + This option enables a library that provides a number of simple + utility functions for parsing PGP (RFC 4880) packet-based messages. -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 59e7180..2dbbe6c 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -27,5 +27,6 @@ obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ - obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index b6b1a5a..5fbe54e 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -7,3 +7,4 @@ crypto_keys-y := crypto_type.o crypto_verify.o + obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o +obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o - - crypto_keys-y := crypto_type.o crypto_verify.o -diff --git a/security/keys/pgp_library.c b/security/keys/pgp_library.c +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c new file mode 100644 index 0000000..685660f --- /dev/null -+++ b/security/keys/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c @@ -0,0 +1,254 @@ +/* PGP packet parser (RFC 4880) + * @@ -2491,13 +2568,13 @@ index 0000000..685660f +} +EXPORT_SYMBOL_GPL(pgp_parse_public_key); -- -1.7.9.1 +1.7.10.2 -From 194b547524cc4abf00e357948d949871d42bed84 Mon Sep 17 00:00:00 2001 +From 1123a360effa696546dbce1273c680b45c5cf946 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:13 +0000 -Subject: PGPLIB: Signature parser +Date: Fri, 4 May 2012 16:33:30 +0100 +Subject: [PATCH 12/36] PGPLIB: Signature parser Provide some PGP signature parsing helpers: @@ -2515,9 +2592,9 @@ Provide some PGP signature parsing helpers: Signed-off-by: David Howells <dhowells@redhat.com> --- - include/linux/pgp.h | 24 ++++ - security/keys/pgp_library.c | 277 +++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 301 insertions(+), 0 deletions(-) + include/linux/pgp.h | 24 ++++ + security/keys/crypto/pgp_library.c | 277 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 301 insertions(+) diff --git a/include/linux/pgp.h b/include/linux/pgp.h index 235270a..ab1a8fa 100644 @@ -2552,10 +2629,10 @@ index 235270a..ab1a8fa 100644 + struct pgp_sig_parameters *p); + #endif /* _LINUX_PGP_H */ -diff --git a/security/keys/pgp_library.c b/security/keys/pgp_library.c +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c index 685660f..f6b831f 100644 ---- a/security/keys/pgp_library.c -+++ b/security/keys/pgp_library.c +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c @@ -252,3 +252,280 @@ int pgp_parse_public_key(const u8 **_data, size_t *_datalen, return 0; } @@ -2838,13 +2915,13 @@ index 685660f..f6b831f 100644 +} +EXPORT_SYMBOL_GPL(pgp_parse_sig_params); -- -1.7.9.1 +1.7.10.2 -From ee32f2d2d24a635e7bb46cbd37a0622850f4c66e Mon Sep 17 00:00:00 2001 +From 53f01a04d44b822af15cd31bb451ca13695bdf1c Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:13 +0000 -Subject: KEYS: PGP data parser +Date: Fri, 4 May 2012 16:36:35 +0100 +Subject: [PATCH 13/36] KEYS: PGP data parser Implement a PGP data parser for the crypto key type to use when instantiating a key. @@ -2858,19 +2935,19 @@ appropriate handler routines (DSA or RSA) and attach it to the key. Signed-off-by: David Howells <dhowells@redhat.com> --- - security/keys/Kconfig | 12 ++ - security/keys/Makefile | 4 + - security/keys/pgp_key_parser.c | 343 ++++++++++++++++++++++++++++++++++++++++ - security/keys/pgp_parser.h | 23 +++ - 4 files changed, 382 insertions(+), 0 deletions(-) - create mode 100644 security/keys/pgp_key_parser.c - create mode 100644 security/keys/pgp_parser.h - -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index aa3954c..fd53028 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -98,3 +98,15 @@ config PGP_LIBRARY + security/keys/crypto/Kconfig | 12 ++ + security/keys/crypto/Makefile | 4 + + security/keys/crypto/pgp_key_parser.c | 343 +++++++++++++++++++++++++++++++++ + security/keys/crypto/pgp_parser.h | 23 +++ + 4 files changed, 382 insertions(+) + create mode 100644 security/keys/crypto/pgp_key_parser.c + create mode 100644 security/keys/crypto/pgp_parser.h + +diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig +index 88ce0e2..1c2ae55 100644 +--- a/security/keys/crypto/Kconfig ++++ b/security/keys/crypto/Kconfig +@@ -28,3 +28,15 @@ config PGP_LIBRARY help This option enables a library that provides a number of simple utility functions for parsing PGP (RFC 4880) packet-based messages. @@ -2886,25 +2963,23 @@ index aa3954c..fd53028 100644 + This option provides support for parsing PGP (RFC 4880) format blobs + for key data and provides the ability to instantiate a crypto key + from a public key packet found inside the blob. -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 2dbbe6c..416670c 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -28,5 +28,9 @@ obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 5fbe54e..3bb2e61 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -8,3 +8,7 @@ crypto_keys-y := crypto_type.o crypto_verify.o obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o -+obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o - - crypto_keys-y := crypto_type.o crypto_verify.o + ++obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o +pgp_parser-y := \ + pgp_key_parser.o -diff --git a/security/keys/pgp_key_parser.c b/security/keys/pgp_key_parser.c +diff --git a/security/keys/crypto/pgp_key_parser.c b/security/keys/crypto/pgp_key_parser.c new file mode 100644 index 0000000..4efc4de --- /dev/null -+++ b/security/keys/pgp_key_parser.c ++++ b/security/keys/crypto/pgp_key_parser.c @@ -0,0 +1,343 @@ +/* Parser for PGP format key data [RFC 4880] + * @@ -3249,11 +3324,11 @@ index 0000000..4efc4de + +module_init(pgp_key_init); +module_exit(pgp_key_exit); -diff --git a/security/keys/pgp_parser.h b/security/keys/pgp_parser.h +diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h new file mode 100644 index 0000000..1cda231 --- /dev/null -+++ b/security/keys/pgp_parser.h ++++ b/security/keys/crypto/pgp_parser.h @@ -0,0 +1,23 @@ +/* PGP crypto data parser internal definitions + * @@ -3279,13 +3354,13 @@ index 0000000..1cda231 +extern const +struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; -- -1.7.9.1 +1.7.10.2 -From 0e862034535288f2ee5653563178f6a6b99f8c47 Mon Sep 17 00:00:00 2001 +From 3e401cdc0ae1768ecbc301a631a2a34f56834313 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:14 +0000 -Subject: KEYS: PGP-based public key signature verification +Date: Fri, 4 May 2012 16:40:17 +0100 +Subject: [PATCH 14/36] KEYS: PGP-based public key signature verification Provide handlers for PGP-based public-key algorithm signature verification. This does most of the work involved in signature verification as most of it is @@ -3297,27 +3372,27 @@ patch provides. Signed-off-by: David Howells <dhowells@redhat.com> --- - security/keys/Makefile | 3 +- - security/keys/pgp_parser.h | 6 + - security/keys/pgp_pubkey_sig.c | 323 ++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 331 insertions(+), 1 deletions(-) - create mode 100644 security/keys/pgp_pubkey_sig.c - -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 416670c..24e83a2 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -33,4 +33,5 @@ obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o - crypto_keys-y := crypto_type.o crypto_verify.o + security/keys/crypto/Makefile | 3 +- + security/keys/crypto/pgp_parser.h | 6 + + security/keys/crypto/pgp_pubkey_sig.c | 323 +++++++++++++++++++++++++++++++++ + 3 files changed, 331 insertions(+), 1 deletion(-) + create mode 100644 security/keys/crypto/pgp_pubkey_sig.c + +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 3bb2e61..d4ac8ac 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -11,4 +11,5 @@ obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o + obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o pgp_parser-y := \ - pgp_key_parser.o + pgp_key_parser.o \ + pgp_pubkey_sig.o -diff --git a/security/keys/pgp_parser.h b/security/keys/pgp_parser.h +diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h index 1cda231..a6192ce 100644 ---- a/security/keys/pgp_parser.h -+++ b/security/keys/pgp_parser.h +--- a/security/keys/crypto/pgp_parser.h ++++ b/security/keys/crypto/pgp_parser.h @@ -21,3 +21,9 @@ */ extern const @@ -3328,11 +3403,11 @@ index 1cda231..a6192ce 100644 + */ +extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( + struct key *crypto_key, const u8 *sigdata, size_t siglen); -diff --git a/security/keys/pgp_pubkey_sig.c b/security/keys/pgp_pubkey_sig.c +diff --git a/security/keys/crypto/pgp_pubkey_sig.c b/security/keys/crypto/pgp_pubkey_sig.c new file mode 100644 index 0000000..b4b7cb0 --- /dev/null -+++ b/security/keys/pgp_pubkey_sig.c ++++ b/security/keys/crypto/pgp_pubkey_sig.c @@ -0,0 +1,323 @@ +/* Handling for PGP public key signature data [RFC 4880] + * @@ -3658,13 +3733,13 @@ index 0000000..b4b7cb0 + kleave(""); +} -- -1.7.9.1 +1.7.10.2 -From b8d572f41734596c3abbd15b1d2e30f5fa603c01 Mon Sep 17 00:00:00 2001 +From 55e67eca050ff43915912e50dda49ecafdc816aa Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:15 +0000 -Subject: KEYS: PGP format signature parser +Date: Fri, 4 May 2012 16:40:39 +0100 +Subject: [PATCH 15/36] KEYS: PGP format signature parser Implement a signature parser that will attempt to parse a signature blob as a PGP packet format message. If it can, it will find an appropriate crypto key @@ -3672,27 +3747,27 @@ and set the public-key algorithm according to the data in the signature. Signed-off-by: David Howells <dhowells@redhat.com> --- - security/keys/Makefile | 1 + - security/keys/pgp_key_parser.c | 1 + - security/keys/pgp_parser.h | 6 ++ - security/keys/pgp_sig_parser.c | 104 ++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 112 insertions(+), 0 deletions(-) - create mode 100644 security/keys/pgp_sig_parser.c - -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 24e83a2..9aa48fe 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -34,4 +34,5 @@ crypto_keys-y := crypto_type.o crypto_verify.o - + security/keys/crypto/Makefile | 1 + + security/keys/crypto/pgp_key_parser.c | 1 + + security/keys/crypto/pgp_parser.h | 6 ++ + security/keys/crypto/pgp_sig_parser.c | 104 +++++++++++++++++++++++++++++++++ + 4 files changed, 112 insertions(+) + create mode 100644 security/keys/crypto/pgp_sig_parser.c + +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index d4ac8ac..fa7746d 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -12,4 +12,5 @@ obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o + obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o pgp_parser-y := \ pgp_key_parser.o \ + pgp_sig_parser.o \ pgp_pubkey_sig.o -diff --git a/security/keys/pgp_key_parser.c b/security/keys/pgp_key_parser.c +diff --git a/security/keys/crypto/pgp_key_parser.c b/security/keys/crypto/pgp_key_parser.c index 4efc4de..1407e2e 100644 ---- a/security/keys/pgp_key_parser.c -+++ b/security/keys/pgp_key_parser.c +--- a/security/keys/crypto/pgp_key_parser.c ++++ b/security/keys/crypto/pgp_key_parser.c @@ -324,6 +324,7 @@ static struct crypto_key_parser pgp_key_parser = { .owner = THIS_MODULE, .name = "pgp", @@ -3701,10 +3776,10 @@ index 4efc4de..1407e2e 100644 }; /* -diff --git a/security/keys/pgp_parser.h b/security/keys/pgp_parser.h +diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h index a6192ce..73c900e 100644 ---- a/security/keys/pgp_parser.h -+++ b/security/keys/pgp_parser.h +--- a/security/keys/crypto/pgp_parser.h ++++ b/security/keys/crypto/pgp_parser.h @@ -23,6 +23,12 @@ extern const struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; @@ -3718,11 +3793,11 @@ index a6192ce..73c900e 100644 * pgp_pubkey_sig.c */ extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( -diff --git a/security/keys/pgp_sig_parser.c b/security/keys/pgp_sig_parser.c +diff --git a/security/keys/crypto/pgp_sig_parser.c b/security/keys/crypto/pgp_sig_parser.c new file mode 100644 index 0000000..b72c505 --- /dev/null -+++ b/security/keys/pgp_sig_parser.c ++++ b/security/keys/crypto/pgp_sig_parser.c @@ -0,0 +1,104 @@ +/* Handling for PGP public key signature data [RFC 4880] + * @@ -3829,13 +3904,14 @@ index 0000000..b72c505 + return ctx; +} -- -1.7.9.1 +1.7.10.2 -From e25da6c545204746a8011dc27ce179816f715449 Mon Sep 17 00:00:00 2001 +From 0760cf6519e184298944df0d9f6fe5a097fb16ff Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:16 +0000 -Subject: KEYS: Provide a function to load keys from a PGP keyring blob +Date: Fri, 4 May 2012 16:41:12 +0100 +Subject: [PATCH 16/36] KEYS: Provide a function to load keys from a PGP + keyring blob Provide a function to load keys from a PGP keyring blob for use in initialising the module signing key keyring: @@ -3857,12 +3933,12 @@ Looking as root in /proc/keys after the module signing keyring has been loaded: Signed-off-by: David Howells <dhowells@redhat.com> --- Documentation/security/keys-crypto.txt | 20 +++++++ - include/keys/crypto-type.h | 3 + - security/keys/Kconfig | 9 +++ - security/keys/Makefile | 1 + - security/keys/pgp_preload.c | 90 ++++++++++++++++++++++++++++++++ - 5 files changed, 123 insertions(+), 0 deletions(-) - create mode 100644 security/keys/pgp_preload.c + include/keys/crypto-type.h | 3 ++ + security/keys/crypto/Kconfig | 9 ++++ + security/keys/crypto/Makefile | 1 + + security/keys/crypto/pgp_preload.c | 90 ++++++++++++++++++++++++++++++++ + 5 files changed, 123 insertions(+) + create mode 100644 security/keys/crypto/pgp_preload.c diff --git a/Documentation/security/keys-crypto.txt b/Documentation/security/keys-crypto.txt index a964717..ba2ab55 100644 @@ -3911,11 +3987,11 @@ index 6b93366..710e77f 100644 + struct key *keyring, const char *descprefix); + #endif /* _KEYS_CRYPTO_TYPE_H */ -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index fd53028..5e77c2a 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -110,3 +110,12 @@ config CRYPTO_KEY_PGP_PARSER +diff --git a/security/keys/crypto/Kconfig b/security/keys/crypto/Kconfig +index 1c2ae55..8af0155 100644 +--- a/security/keys/crypto/Kconfig ++++ b/security/keys/crypto/Kconfig +@@ -40,3 +40,12 @@ config CRYPTO_KEY_PGP_PARSER This option provides support for parsing PGP (RFC 4880) format blobs for key data and provides the ability to instantiate a crypto key from a public key packet found inside the blob. @@ -3928,23 +4004,23 @@ index fd53028..5e77c2a 100644 + This option provides a facility for the kernel to preload PGP-wrapped + bundles of keys during boot. It is used by module signing to load + the module signing keys for example. -diff --git a/security/keys/Makefile b/security/keys/Makefile -index 9aa48fe..5a43bdb 100644 ---- a/security/keys/Makefile -+++ b/security/keys/Makefile -@@ -28,6 +28,7 @@ obj-$(CONFIG_CRYPTO_KEY_TYPE) += crypto_keys.o +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index fa7746d..4162ecb 100644 +--- a/security/keys/crypto/Makefile ++++ b/security/keys/crypto/Makefile +@@ -8,6 +8,7 @@ crypto_keys-y := crypto_type.o crypto_verify.o obj-$(CONFIG_CRYPTO_KEY_PUBLIC_KEY_SUBTYPE) += public_key.o obj-$(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) += crypto_rsa.o obj-$(CONFIG_PGP_LIBRARY) += pgp_library.o +obj-$(CONFIG_PGP_PRELOAD) += pgp_preload.o - obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o - crypto_keys-y := crypto_type.o crypto_verify.o -diff --git a/security/keys/pgp_preload.c b/security/keys/pgp_preload.c + obj-$(CONFIG_CRYPTO_KEY_PGP_PARSER) += pgp_parser.o + pgp_parser-y := \ +diff --git a/security/keys/crypto/pgp_preload.c b/security/keys/crypto/pgp_preload.c new file mode 100644 index 0000000..25154e3 --- /dev/null -+++ b/security/keys/pgp_preload.c ++++ b/security/keys/crypto/pgp_preload.c @@ -0,0 +1,90 @@ +/* Cryptographic key request handling + * @@ -4037,13 +4113,87 @@ index 0000000..25154e3 + return pgp_parse_packets(pgpdata, pgpdatalen, &ctx.pgp); +} -- -1.7.9.1 +1.7.10.2 + + +From 8f7d6b082b6b7357e44f9345c8c040f53aa60a7f Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:46:56 +0100 +Subject: [PATCH 17/36] Provide macros for forming the name of an ELF note and + its section + +Provide macros for stringifying the name of an ELF note and its section +appropriately so that the macro can be used in both C and assembly. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + include/linux/elfnote.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h +index 278e3ef..949d494 100644 +--- a/include/linux/elfnote.h ++++ b/include/linux/elfnote.h +@@ -58,6 +58,7 @@ + ELFNOTE_END + + #else /* !__ASSEMBLER__ */ ++#include <linux/stringify.h> + #include <linux/elf.h> + /* + * Use an anonymous structure which matches the shape of +@@ -93,6 +94,9 @@ + + #define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc) + #define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc) ++ ++#define ELFNOTE_NAME(name) __stringify(name) ++#define ELFNOTE_SECTION(name) ".note."ELFNOTE_NAME(name) + #endif /* __ASSEMBLER__ */ + + #endif /* _LINUX_ELFNOTE_H */ +-- +1.7.10.2 -From dad531381fad892fda776ddb354e1eb936b46b62 Mon Sep 17 00:00:00 2001 +From b37a512b3d6593d541e05550316bd407515c1ec2 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:16 +0000 -Subject: MODSIGN: Add indications of module ELF types +Date: Thu, 10 May 2012 23:49:44 +0100 +Subject: [PATCH 18/36] Guard check in module loader against integer overflow + +The check: + + if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) + +may not work if there's an overflow in the right-hand side of the condition. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/module.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/module.c b/kernel/module.c +index 78ac6ec..377cb06 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2429,7 +2429,8 @@ static int copy_and_check(struct load_info *info, + goto free_hdr; + } + +- if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { ++ if (hdr->e_shoff >= len || ++ hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) { + err = -ENOEXEC; + goto free_hdr; + } +-- +1.7.10.2 + + +From a7f2ec2a77490ed84bf8020cd5b41d7c7ea3f3cb Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:52 +0100 +Subject: [PATCH 19/36] MODSIGN: Add indications of module ELF types Add per-arch indications of module ELF types and relocation table entry types. @@ -4060,8 +4210,9 @@ Signed-Off-By: David Howells <dhowells@redhat.com> arch/parisc/include/asm/module.h | 8 ++++++++ arch/powerpc/include/asm/module.h | 10 ++++++++++ arch/s390/include/asm/module.h | 3 +++ + arch/x86/include/asm/module.h | 6 ++++++ include/asm-generic/module.h | 10 ++++++++++ - 12 files changed, 74 insertions(+), 2 deletions(-) + 13 files changed, 80 insertions(+), 2 deletions(-) diff --git a/arch/alpha/include/asm/module.h b/arch/alpha/include/asm/module.h index 7b63743..3d5a3ea 100644 @@ -4194,7 +4345,7 @@ index edffe66..9e2cd74 100644 #endif /* _ASM_M68K_MODULE_H */ diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h -index bc01a02..73c71a2 100644 +index 7467d1d..4404cca 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -33,11 +33,15 @@ typedef struct { @@ -4314,6 +4465,21 @@ index 1cc1c5a..b64dab0 100644 #define Elf_Rela ElfW(Rela) #define Elf_Shdr ElfW(Shdr) #define Elf_Sym ElfW(Sym) +diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h +index 9eae775..724f173 100644 +--- a/arch/x86/include/asm/module.h ++++ b/arch/x86/include/asm/module.h +@@ -63,4 +63,10 @@ + # define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY + #endif + ++#ifdef CONFIG_X86_32 ++#define MODULE_HAS_ELF_REL_ONLY ++#else ++#define MODULE_HAS_ELF_RELA_ONLY ++#endif ++ + #endif /* _ASM_X86_MODULE_H */ diff --git a/include/asm-generic/module.h b/include/asm-generic/module.h index ed5b44d..e053617b 100644 --- a/include/asm-generic/module.h @@ -4343,818 +4509,129 @@ index ed5b44d..e053617b 100644 #endif /* __ASM_GENERIC_MODULE_H */ -- -1.7.9.1 +1.7.10.2 - -From a66294fc859a6a9374a6d873d8a6ca3ec683538f Mon Sep 17 00:00:00 2001 +From b31d1ea8afb0b63e872a1bed3a3c88d7696bf2e7 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:17 +0000 -Subject: MODSIGN: Module ELF verifier - -Do preliminary verification of the ELF structure of a module. This is used to -make sure that the ELF structure can then be used to check the module signature -and access the module data without breaking the module loader. +Date: Thu, 10 May 2012 23:49:53 +0100 +Subject: [PATCH 20/36] MODSIGN: Provide gitignore and make clean rules for + extra files -If the module's ELF metadata is determined to be bad, then ELIBBAD will be -returned and a message will be logged to the kernel log. +Provide gitignore and make clean rules for extra files to hide and clean up the +extra files produced by module signing stuff once it is added. Also add a +clean up rule for the module content extractor program used to extract the data +to be signed. -Signed-Off-By: David Howells <dhowells@redhat.com> - -Rebased-to-3.3-rc6: Josh Boyer <jwboyer@redhat.com> +Signed-off-by: David Howells <dhowells@redhat.com> --- - init/Kconfig | 11 ++ - kernel/Makefile | 2 + - kernel/module-verify-elf.c | 344 ++++++++++++++++++++++++++++++++++++++++++++ - kernel/module-verify.c | 41 ++++++ - kernel/module-verify.h | 53 +++++++ - kernel/module.c | 6 + - 6 files changed, 457 insertions(+), 0 deletions(-) - create mode 100644 kernel/module-verify-elf.c - create mode 100644 kernel/module-verify.c - create mode 100644 kernel/module-verify.h + .gitignore | 12 ++++++++++++ + Makefile | 1 + + scripts/mod/.gitignore | 1 + + 3 files changed, 14 insertions(+) -diff --git a/init/Kconfig b/init/Kconfig -index 3f42cd6..61b5f03 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1418,6 +1418,17 @@ 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_VERIFY_ELF -+ bool "Module ELF structure verification" -+ depends on MODULES -+ help -+ Check ELF structure of modules upon load -+ -+config MODULE_VERIFY -+ bool -+ depends on MODULES -+ default y if MODULE_VERIFY_ELF -+ - endif # MODULES - - config INIT_ALL_POSSIBLE -diff --git a/kernel/Makefile b/kernel/Makefile -index 2d9de86..77b7a39 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -52,6 +52,8 @@ 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_VERIFY) += module-verify.o -+obj-$(CONFIG_MODULE_VERIFY_ELF) += module-verify-elf.o - obj-$(CONFIG_KALLSYMS) += kallsyms.o - obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o - obj-$(CONFIG_KEXEC) += kexec.o -diff --git a/kernel/module-verify-elf.c b/kernel/module-verify-elf.c -new file mode 100644 -index 0000000..4dea8d0 ---- /dev/null -+++ b/kernel/module-verify-elf.c -@@ -0,0 +1,344 @@ -+/* module-verify-elf.c: module ELF verifier -+ * -+ * 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 License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/elf.h> -+#include <linux/ctype.h> -+#include "module-verify.h" -+ -+#if 0 -+#define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__) -+#else -+#define _debug(FMT, ...) do {} while (0) -+#endif -+ -+/* -+ * verify the ELF structure of a module -+ */ -+int module_verify_elf(struct module_verify_data *mvdata) -+{ -+ const struct elf_note *note; -+ const Elf_Ehdr *hdr = mvdata->hdr; -+ const Elf_Shdr *section, *section2, *secstop; -+ const Elf_Rela *relas, *rela, *relastop; -+ const Elf_Rel *rels, *rel, *relstop; -+ const Elf_Sym *symbol, *symstop; -+ const void *start, *p, *stop; -+ const char *q, *qs; -+ size_t size, sssize, *secsize, tmp, tmp2; -+ long last; -+ int line; -+ -+ size = mvdata->size; -+ mvdata->nsects = hdr->e_shnum; -+ -+#define elfcheck(X) \ -+do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while(0) -+ -+#define seccheck(X) \ -+do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while(0) -+ -+#define symcheck(X) \ -+do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0) -+ -+#define relcheck(X) \ -+do { if (unlikely(!(X))) { line = __LINE__; goto relcheck_error; } } while(0) -+ -+#define relacheck(X) \ -+do { if (unlikely(!(X))) { line = __LINE__; goto relacheck_error; } } while(0) -+ -+#define notecheck(X) \ -+do { if (unlikely(!(X))) { line = __LINE__; goto notecheck_error; } } while(0) -+ -+ /* validate the ELF header */ -+ elfcheck(hdr->e_ehsize < size); -+ /*elfcheck(hdr->e_entry == 0);*/ -+ elfcheck(hdr->e_phoff == 0); -+ elfcheck(hdr->e_phnum == 0); -+ -+ elfcheck(hdr->e_shnum < SHN_LORESERVE); -+ elfcheck(hdr->e_shoff < size); -+ elfcheck(hdr->e_shoff >= hdr->e_ehsize); -+ elfcheck((hdr->e_shoff & (sizeof(long) - 1)) == 0); -+ elfcheck(hdr->e_shstrndx > 0); -+ elfcheck(hdr->e_shstrndx < hdr->e_shnum); -+ elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr)); -+ -+ tmp = (size_t) hdr->e_shentsize * (size_t) hdr->e_shnum; -+ elfcheck(tmp <= size - hdr->e_shoff); -+ -+ /* allocate a table to hold in-file section sizes */ -+ mvdata->secsizes = kcalloc(hdr->e_shnum, sizeof(size_t), GFP_KERNEL); -+ if (!mvdata->secsizes) -+ return -ENOMEM; -+ -+ /* validate the ELF section headers */ -+ mvdata->sections = mvdata->buffer + hdr->e_shoff; -+ secstop = mvdata->sections + mvdata->nsects; -+ -+ sssize = mvdata->sections[hdr->e_shstrndx].sh_size; -+ elfcheck(sssize > 0); -+ -+ section = mvdata->sections; -+ seccheck(section->sh_type == SHT_NULL); -+ seccheck(section->sh_size == 0); -+ seccheck(section->sh_offset == 0); -+ -+ secsize = mvdata->secsizes + 1; -+ for (section++; section < secstop; secsize++, section++) { -+ seccheck(section->sh_name < sssize); -+ seccheck(section->sh_link < hdr->e_shnum); -+ -+ if (section->sh_entsize > 0) -+ seccheck(section->sh_size % section->sh_entsize == 0); -+ -+ seccheck(section->sh_offset >= hdr->e_ehsize); -+ seccheck(section->sh_offset < size); -+ -+ /* determine the section's in-file size */ -+ tmp = size - section->sh_offset; -+ if (section->sh_offset < hdr->e_shoff) -+ tmp = hdr->e_shoff - section->sh_offset; -+ -+ for (section2 = mvdata->sections + 1; -+ section2 < secstop; -+ section2++) { -+ if (section->sh_offset < section2->sh_offset) { -+ tmp2 = section2->sh_offset - -+ section->sh_offset; -+ if (tmp2 < tmp) -+ tmp = tmp2; -+ } -+ } -+ *secsize = tmp; -+ -+ _debug("Section %ld: %zx bytes at %lx\n", -+ section - mvdata->sections, -+ *secsize, -+ (unsigned long) section->sh_offset); -+ -+ /* perform section type specific checks */ -+ switch (section->sh_type) { -+ case SHT_NOBITS: -+ break; -+ -+ case SHT_REL: -+ seccheck(section->sh_entsize == sizeof(Elf_Rel)); -+ goto more_rel_checks; -+ -+ case SHT_RELA: -+ seccheck(section->sh_entsize == sizeof(Elf_Rela)); -+ more_rel_checks: -+ seccheck(section->sh_info > 0); -+ seccheck(section->sh_info < hdr->e_shnum); -+ goto more_sec_checks; -+ -+ case SHT_SYMTAB: -+ seccheck(section->sh_entsize == sizeof(Elf_Sym)); -+ goto more_sec_checks; -+ -+ default: -+ more_sec_checks: -+ /* most types of section must be contained entirely -+ * within the file */ -+ seccheck(section->sh_size <= *secsize); -+ break; -+ } -+ } -+ -+ /* validate the ELF section names */ -+ section = &mvdata->sections[hdr->e_shstrndx]; -+ -+ seccheck(section->sh_offset != hdr->e_shoff); -+ -+ mvdata->secstrings = mvdata->buffer + section->sh_offset; -+ -+ last = -1; -+ for (section = mvdata->sections + 1; section < secstop; section++) { -+ const char *secname; -+ tmp = sssize - section->sh_name; -+ secname = mvdata->secstrings + section->sh_name; -+ seccheck(secname[0] != 0); -+ if (section->sh_name > last) -+ last = section->sh_name; -+ } -+ -+ if (last > -1) { -+ tmp = sssize - last; -+ elfcheck(memchr(mvdata->secstrings + last, 0, tmp) != NULL); -+ } -+ -+ /* look for various sections in the module */ -+ for (section = mvdata->sections + 1; section < secstop; section++) { -+ switch (section->sh_type) { -+ case SHT_SYMTAB: -+ if (strcmp(mvdata->secstrings + section->sh_name, -+ ".symtab") == 0 -+ ) { -+ seccheck(mvdata->symbols == NULL); -+ mvdata->symbols = -+ mvdata->buffer + section->sh_offset; -+ mvdata->nsyms = -+ section->sh_size / sizeof(Elf_Sym); -+ seccheck(section->sh_size > 0); -+ } -+ break; -+ -+ case SHT_STRTAB: -+ if (strcmp(mvdata->secstrings + section->sh_name, -+ ".strtab") == 0 -+ ) { -+ seccheck(mvdata->strings == NULL); -+ mvdata->strings = -+ mvdata->buffer + section->sh_offset; -+ sssize = mvdata->nstrings = section->sh_size; -+ seccheck(section->sh_size > 0); -+ } -+ break; -+ } -+ } -+ -+ if (!mvdata->symbols) { -+ printk("Couldn't locate module symbol table\n"); -+ goto format_error; -+ } -+ -+ if (!mvdata->strings) { -+ printk("Couldn't locate module strings table\n"); -+ goto format_error; -+ } -+ -+ /* validate the symbol table */ -+ symstop = mvdata->symbols + mvdata->nsyms; -+ -+ symbol = mvdata->symbols; -+ symcheck(ELF_ST_TYPE(symbol[0].st_info) == STT_NOTYPE); -+ symcheck(symbol[0].st_shndx == SHN_UNDEF); -+ symcheck(symbol[0].st_value == 0); -+ symcheck(symbol[0].st_size == 0); -+ -+ last = -1; -+ for (symbol++; symbol < symstop; symbol++) { -+ symcheck(symbol->st_name < sssize); -+ if (symbol->st_name > last) -+ last = symbol->st_name; -+ symcheck(symbol->st_shndx < mvdata->nsects || -+ symbol->st_shndx >= SHN_LORESERVE); -+ } -+ -+ if (last > -1) { -+ tmp = sssize - last; -+ elfcheck(memchr(mvdata->strings + last, 0, tmp) != NULL); -+ } -+ -+ /* validate each relocation table and note list as best we can */ -+ for (section = mvdata->sections + 1; section < secstop; section++) { -+ section2 = mvdata->sections + section->sh_info; -+ start = mvdata->buffer + section->sh_offset; -+ stop = start + section->sh_size; -+ -+ switch (section->sh_type) { -+ case SHT_REL: -+ rels = start; -+ relstop = stop; -+ -+ for (rel = rels; rel < relstop; rel++) { -+ relcheck(rel->r_offset < section2->sh_size); -+ relcheck(ELF_R_SYM(rel->r_info) < -+ mvdata->nsyms); -+ } -+ -+ break; -+ -+ case SHT_RELA: -+ relas = start; -+ relastop = stop; -+ -+ for (rela = relas; rela < relastop; rela++) { -+ relacheck(rela->r_offset < section2->sh_size); -+ relacheck(ELF_R_SYM(rela->r_info) < -+ mvdata->nsyms); -+ } -+ -+ break; -+ -+ case SHT_NOTE: -+ p = start; -+ while (p < stop) { -+ note = p; -+ notecheck(stop - p >= sizeof(*note)); -+ p += sizeof(*note); -+ tmp = note->n_namesz; -+ if (tmp > 0) { -+ notecheck(stop - p >= tmp); -+ qs = p + tmp - 1; -+ notecheck(*qs == '\0'); -+ for (q = p; q < qs; q++) -+ notecheck(*q != '\0'); -+ tmp = roundup(tmp, 4); -+ notecheck(stop - p >= tmp); -+ p += tmp; -+ } -+ tmp = note->n_descsz; -+ if (tmp > 0) { -+ notecheck(stop - p >= tmp); -+ tmp = roundup(tmp, 4); -+ notecheck(stop - p >= tmp); -+ p += tmp; -+ } -+ } -+ seccheck(p == stop); -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ _debug("ELF okay\n"); -+ return 0; -+ -+elfcheck_error: -+ printk("Verify ELF error (assertion %d)\n", line); -+ goto format_error; -+ -+seccheck_error: -+ printk("Verify ELF error [sec %ld] (assertion %d)\n", -+ (long)(section - mvdata->sections), line); -+ goto format_error; -+ -+symcheck_error: -+ printk("Verify ELF error [sym %ld] (assertion %d)\n", -+ (long)(symbol - mvdata->symbols), line); -+ goto format_error; -+ -+relcheck_error: -+ printk("Verify ELF error [sec %ld rel %ld] (assertion %d)\n", -+ (long)(section - mvdata->sections), -+ (long)(rel - rels), line); -+ goto format_error; -+ -+relacheck_error: -+ printk("Verify ELF error [sec %ld rela %ld] (assertion %d)\n", -+ (long)(section - mvdata->sections), -+ (long)(rela - relas), line); -+ goto format_error; -+ -+notecheck_error: -+ printk("Verify ELF error [sec %ld note %ld] (assertion %d)\n", -+ (long)(section - mvdata->sections), -+ (long)(p - start), line); -+ goto format_error; -+ -+format_error: -+ return -ELIBBAD; -+} -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -new file mode 100644 -index 0000000..875279f ---- /dev/null -+++ b/kernel/module-verify.c -@@ -0,0 +1,41 @@ -+/* module-verify.c: module verifier -+ * -+ * 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 License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include "module-verify.h" -+ -+/* -+ * verify a module's integrity -+ * - check the ELF is viable -+ */ -+int module_verify(const Elf_Ehdr *hdr, size_t size) -+{ -+ struct module_verify_data mvdata; -+ int ret; -+ -+ memset(&mvdata, 0, sizeof(mvdata)); -+ mvdata.buffer = hdr; -+ mvdata.hdr = hdr; -+ mvdata.size = size; -+ -+ ret = module_verify_elf(&mvdata); -+ if (ret < 0) { -+ if (ret == -ELIBBAD) -+ printk("Module failed ELF checks\n"); -+ goto error; -+ } -+ -+error: -+ kfree(mvdata.secsizes); -+ kfree(mvdata.canonlist); -+ return ret; -+} -diff --git a/kernel/module-verify.h b/kernel/module-verify.h -new file mode 100644 -index 0000000..20884fc ---- /dev/null -+++ b/kernel/module-verify.h -@@ -0,0 +1,53 @@ -+/* module-verify.h: module verification definitions -+ * -+ * Copyright (C) 2004 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 License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include <linux/types.h> -+#include <asm/module.h> -+ -+#ifdef CONFIG_MODULE_VERIFY -+struct module_verify_data { -+ const void *buffer; /* module buffer */ -+ const Elf_Ehdr *hdr; /* ELF header */ -+ const Elf_Shdr *sections; /* ELF section table */ -+ const Elf_Sym *symbols; /* ELF symbol table */ -+ const char *secstrings; /* ELF section string table */ -+ const char *strings; /* ELF string table */ -+ size_t *secsizes; /* section size list */ -+ size_t size; /* module object size */ -+ size_t nsects; /* number of sections */ -+ size_t nsyms; /* number of symbols */ -+ size_t nstrings; /* size of strings section */ -+ size_t signed_size; /* count of bytes contributed to digest */ -+ int *canonlist; /* list of canonicalised sections */ -+ int *canonmap; /* section canonicalisation map */ -+ int ncanon; /* number of canonicalised sections */ -+ int sig_index; /* module signature section index */ -+ uint8_t xcsum; /* checksum of bytes contributed to digest */ -+ uint8_t csum; /* checksum of bytes representing a section */ -+}; -+ -+/* -+ * module-verify.c -+ */ -+extern int module_verify(const Elf_Ehdr *hdr, size_t size); -+ -+/* -+ * module-verify-elf.c -+ */ -+#ifdef CONFIG_MODULE_VERIFY_ELF -+extern int module_verify_elf(struct module_verify_data *mvdata); -+#else -+#define module_verify_elf(m) (0) -+#endif +diff --git a/.gitignore b/.gitignore +index 57af07c..7948eeb 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -14,6 +14,9 @@ + *.o.* + *.a + *.s ++*.ko.unsigned ++*.ko.digest ++*.ko.digest.sig + *.ko + *.so + *.so.dbg +@@ -84,3 +87,12 @@ GTAGS + *.orig + *~ + \#*# + -+#else -+#define module_verify(h, s) (0) -+#endif -diff --git a/kernel/module.c b/kernel/module.c -index 2c93276..54d6910 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -58,6 +58,7 @@ - #include <linux/jump_label.h> - #include <linux/pfn.h> - #include <linux/bsearch.h> -+#include "module-verify.h" - - #define CREATE_TRACE_POINTS - #include <trace/events/module.h> -@@ -2404,6 +2405,11 @@ static int copy_and_check(struct load_info *info, - goto free_hdr; - } ++# ++# GPG leavings from module signing ++# ++genkey ++modsign.pub ++modsign.sec ++random_seed ++trustdb.gpg +diff --git a/Makefile b/Makefile +index a06ee9f..1df8b14 100644 +--- a/Makefile ++++ b/Makefile +@@ -1407,6 +1407,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.*' \ +diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore +index e9b7abe..223dfd6 100644 +--- a/scripts/mod/.gitignore ++++ b/scripts/mod/.gitignore +@@ -1,4 +1,5 @@ + elfconfig.h + mk_elfconfig + modpost ++mod-extract -+ /* Verify the module's contents */ -+ err = module_verify(hdr, len); -+ if (err < 0) -+ goto free_hdr; -+ - info->hdr = hdr; - info->len = len; - return 0; -- -1.7.9.1 +1.7.10.2 -From 1ecd333ad910d539e75f8f85d1fb1e3d87547c4e Mon Sep 17 00:00:00 2001 +From dce3a6eca8dda09a28cb2f45b87e70e1c2d52139 Mon Sep 17 00:00:00 2001 From: David Howells <dhowells@redhat.com> -Date: Wed, 7 Dec 2011 14:07:18 +0000 -Subject: MODSIGN: Apply signature checking to modules on module load - -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. +Date: Thu, 10 May 2012 23:49:53 +0100 +Subject: [PATCH 21/36] MODSIGN: Provide Documentation and Kconfig options -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; +Provide documentation and kernel configuration options for module signing. - (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. - -These patches have two main appeals: (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: +The documentation can be found 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. +The following configuration options are added: -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. + (1) CONFIG_MODULE_SIG -===================== -SUPPLYING PUBLIC KEYS -===================== + Enable module signing. This will both cause the build process to sign + modules and the kernel to check modules when they're loaded. -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 - -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). + (2) CONFIG_MODULE_SIG_SHA1 + CONFIG_MODULE_SIG_SHA224 + CONFIG_MODULE_SIG_SHA256 + CONFIG_MODULE_SIG_SHA384 + CONFIG_MODULE_SIG_SHA512 -This table indicates the behaviours of the various situations: + Select the cryptographic hash used to digest the data prior to signing. + Additionally, the crypto module selected will be built into the kernel as + it won't be possible to load it as a module without incurring a circular + dependency when the kernel tries to check its signature. - 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 - Corrupt ELF ELIBBAD ELIBBAD + (3) CONFIG_MODULE_SIG_FORCE -Signed-Off-By: David Howells <dhowells@redhat.com> + Require that any module loaded must be signed with a key compiled into + the kernel. All other modules are rejected with EKEYREJECTED. -Rebased-to-3.3-rc6-by: Josh Boyer <jwboyer@redhat.com> +Signed-off-by: David Howells <dhowells@redhat.com> --- - .gitignore | 15 + - Documentation/module-signing.txt | 186 ++++++++ - Makefile | 1 + - include/linux/elfnote.h | 4 + - include/linux/modsign.h | 27 ++ - include/linux/module.h | 3 + - init/Kconfig | 56 +++- - kernel/Makefile | 2 + - kernel/modsign-pubkey.c | 44 ++ - kernel/module-verify-sig.c | 526 ++++++++++++++++++++++ - kernel/module-verify.c | 5 +- - kernel/module-verify.h | 19 +- - kernel/module.c | 21 +- - scripts/Makefile.modpost | 85 ++++- - scripts/mod/.gitignore | 1 + - scripts/mod/Makefile | 2 +- - scripts/mod/mod-extract.c | 913 ++++++++++++++++++++++++++++++++++++++ - scripts/mod/modsign-note.sh | 16 + - 18 files changed, 1914 insertions(+), 12 deletions(-) + Documentation/module-signing.txt | 194 ++++++++++++++++++++++++++++++++++++++ + include/linux/modsign.h | 27 ++++++ + init/Kconfig | 53 +++++++++++ + 3 files changed, 274 insertions(+) create mode 100644 Documentation/module-signing.txt create mode 100644 include/linux/modsign.h - create mode 100644 kernel/modsign-pubkey.c - create mode 100644 kernel/module-verify-sig.c - create mode 100644 scripts/mod/mod-extract.c - create mode 100644 scripts/mod/modsign-note.sh -diff --git a/.gitignore b/.gitignore -index 57af07c..841a17ee 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -14,6 +14,9 @@ - *.o.* - *.a - *.s -+*.ko.unsigned -+*.ko.digest -+*.ko.digest.sig - *.ko - *.so - *.so.dbg -@@ -84,3 +87,15 @@ GTAGS - *.orig - *~ - \#*# -+ -+# -+# GPG leavings from module signing -+# -+trustdb.gpg -+random_seed -+kernel.pub -+kernel.sec -+extract.pub -+secring.gpg -+pubring.gpg -+crypto/signature/key.h diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt new file mode 100644 -index 0000000..300b91a +index 0000000..d75d473 --- /dev/null +++ b/Documentation/module-signing.txt -@@ -0,0 +1,186 @@ +@@ -0,0 +1,194 @@ + ============================== + KERNEL MODULE SIGNING FACILITY + ============================== @@ -5185,16 +4662,16 @@ index 0000000..300b91a + +A set of public keys must be supplied at kernel image build time. This is done +by taking a GPG public key file and placing it in the base of the kernel -+directory in a file called kernel.pub. ++directory in a file called modsign.pub. + +For example, a throwaway key could be generated automatically by something like +the following: + + cat >genkey <<EOF -+ %pubring kernel.pub -+ %secring kernel.sec -+ Key-Type: DSA -+ Key-Length: 512 ++ %pubring modsign.pub ++ %secring modsign.sec ++ Key-Type: RSA ++ Key-Length: 4096 + Name-Real: A. N. Other + Name-Comment: Kernel Module GPG key + %commit @@ -5202,15 +4679,12 @@ index 0000000..300b91a + gpg --homedir . --batch --gen-key genkey + +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. ++in /dev/random, more can be provided using the rngd program if there's a ++hardware random number generator available. + +Note that no GPG password is used in the above scriptlet. + -+The kernel.pub file is compiled into the kernel directly by the assembler by ++The modsign.pub file is compiled into the kernel directly by the assembler by +means of an ".incbin" directive in kernel/modsign-pubkey.c. + +Once the kernel is running, the keys are visible to root as kernel crypto keys @@ -5255,12 +4729,12 @@ index 0000000..300b91a + (*) 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". ++ the secret key to be used. The default is "./modsign.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". ++ the public key to be used. The default is "./modsign.pub". + + (*) MODKEYNAME=<key-name> + @@ -5296,10 +4770,16 @@ index 0000000..300b91a +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. ++Signed modules may be safely stripped with any of the following: ++ ++ strip -x ++ strip -g ++ eu-strip ++ ++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 @@ -5309,14 +4789,19 @@ index 0000000..300b91a +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. + ++Note that "strip" and "strip -s" may not be used on a module, signed or ++otherwise, as they remove the symbol table and render the relocation tables ++unusable. ++ + +====================== +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 detect it and apply signature checking. ++is inserted into the module object file during the build process as an ELF note ++called "module.sig" in an ELF section called ".note.module.sig". The signature ++checker will detect it and apply signature checking. + + +========================================= @@ -5341,40 +4826,6 @@ index 0000000..300b91a + Signed, hash algorithm unavailable ENOPKG ENOPKG + Corrupt signature EBADMSG EBADMSG + Corrupt ELF ELIBBAD ELIBBAD -diff --git a/Makefile b/Makefile -index 66d13c9..8ba824f 100644 ---- a/Makefile -+++ b/Makefile -@@ -1407,6 +1407,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.*' \ -diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h -index 278e3ef..949d494 100644 ---- a/include/linux/elfnote.h -+++ b/include/linux/elfnote.h -@@ -58,6 +58,7 @@ - ELFNOTE_END - - #else /* !__ASSEMBLER__ */ -+#include <linux/stringify.h> - #include <linux/elf.h> - /* - * Use an anonymous structure which matches the shape of -@@ -93,6 +94,9 @@ - - #define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc) - #define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc) -+ -+#define ELFNOTE_NAME(name) __stringify(name) -+#define ELFNOTE_SECTION(name) ".note."ELFNOTE_NAME(name) - #endif /* __ASSEMBLER__ */ - - #endif /* _LINUX_ELFNOTE_H */ diff --git a/include/linux/modsign.h b/include/linux/modsign.h new file mode 100644 index 0000000..c5ac87a @@ -5408,37 +4859,22 @@ index 0000000..c5ac87a +#endif + +#endif /* _LINUX_MODSIGN_H */ -diff --git a/include/linux/module.h b/include/linux/module.h -index 4598bf0..2bd03f1 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -294,6 +294,9 @@ struct module - - unsigned int taints; /* same bits as kernel:tainted */ - -+ /* Is this module GPG signed */ -+ int gpgsig_ok; -+ - #ifdef CONFIG_GENERIC_BUG - /* Support for BUG */ - unsigned num_bugs; diff --git a/init/Kconfig b/init/Kconfig -index 61b5f03..b21dcae 100644 +index 6cfd71d..7cda3e6 100644 --- a/init/Kconfig +++ b/init/Kconfig -@@ -1424,10 +1424,64 @@ config MODULE_VERIFY_ELF - help - Check ELF structure of modules upon load +@@ -1409,6 +1409,59 @@ 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 (EXPERIMENTAL)" -+ depends on MODULES && EXPERIMENTAL ++ bool "Module signature verification" ++ depends on MODULES + select CRYPTO_KEY_TYPE + select CRYPTO_KEY_PKEY_ALGO_DSA + select CRYPTO_KEY_PKEY_ALGO_RSA + select PGP_PARSER + select PGP_PRELOAD -+ select MODULE_VERIFY_ELF + help + Check modules for valid signatures upon load. For more information + see: @@ -5484,759 +4920,65 @@ index 61b5f03..b21dcae 100644 + Reject unsigned modules or signed modules for which we don't have a + key. + - config MODULE_VERIFY - bool - depends on MODULES -- default y if MODULE_VERIFY_ELF -+ default y if MODULE_VERIFY_ELF || MODULE_SIG - endif # MODULES -diff --git a/kernel/Makefile b/kernel/Makefile -index 77b7a39..9732e11 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -54,6 +54,8 @@ obj-$(CONFIG_UID16) += uid16.o - obj-$(CONFIG_MODULES) += module.o - obj-$(CONFIG_MODULE_VERIFY) += module-verify.o - obj-$(CONFIG_MODULE_VERIFY_ELF) += module-verify-elf.o -+obj-$(CONFIG_MODULE_SIG) += module-verify-sig.o modsign-pubkey.o -+kernel/modsign-pubkey.o: kernel.pub - obj-$(CONFIG_KALLSYMS) += kallsyms.o - obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o - obj-$(CONFIG_KEXEC) += kexec.o -diff --git a/kernel/modsign-pubkey.c b/kernel/modsign-pubkey.c -new file mode 100644 -index 0000000..df55565 ---- /dev/null -+++ b/kernel/modsign-pubkey.c -@@ -0,0 +1,44 @@ -+/* Public keys for module signature verification -+ * -+ * Copyright (C) 2011 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 <keys/crypto-type.h> -+#include "module-verify.h" -+ -+extern __initdata const u8 modsign_public_keys[]; -+extern __initdata const u8 modsign_public_keys_end[]; -+asm(".section .init.data,\"aw\"\n" -+ "modsign_public_keys:\n" -+ ".incbin \"kernel.pub\"\n" -+ "modsign_public_keys_end:" -+ ); -+ -+/* -+ * We need to make sure ccache doesn't cache the .o file as it doesn't notice -+ * if kernel.pub changes. -+ */ -+static __initdata const char annoy_ccache[] = __TIME__ "foo"; -+ -+/* -+ * Load the compiled-in keys -+ */ -+static __init int modsign_pubkey_init(void) -+{ -+ pr_notice("Load module verification keys\n"); -+ -+ if (preload_pgp_keys(modsign_public_keys, -+ modsign_public_keys_end - modsign_public_keys, -+ modsign_keyring, "modsign.") < 0) -+ panic("Can't load module signing keys\n"); -+ -+ return 0; -+} -+late_initcall(modsign_pubkey_init); -diff --git a/kernel/module-verify-sig.c b/kernel/module-verify-sig.c -new file mode 100644 -index 0000000..ced5681 ---- /dev/null -+++ b/kernel/module-verify-sig.c -@@ -0,0 +1,526 @@ -+/* Module signature checker -+ * -+ * Copyright (C) 2004,2011 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * - Derived from GregKH's RSA module signer -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/elf.h> -+#include <linux/sched.h> -+#include <linux/cred.h> -+#include <linux/modsign.h> -+#include <keys/keyring-type.h> -+#include "module-verify.h" -+ -+#undef MODSIGN_DEBUG -+ -+struct key *modsign_keyring; -+ -+int modsign_debug; -+core_param(modsign_debug, modsign_debug, bool, 0644); -+ -+#define _debug(FMT, ...) \ -+ do { \ -+ if (unlikely(modsign_debug)) \ -+ pr_debug(FMT, ##__VA_ARGS__); \ -+ } while(0) -+ -+#ifdef MODSIGN_DEBUG -+#define count_and_csum(C, __p, __n) \ -+do { \ -+ int __loop; \ -+ for (__loop = 0; __loop < __n; __loop++) { \ -+ (C)->csum += __p[__loop]; \ -+ (C)->xcsum += __p[__loop]; \ -+ } \ -+ (C)->signed_size += __n; \ -+} while (0) -+#else -+#define count_and_csum(C, __p, __n) \ -+do { \ -+ (C)->signed_size += __n; \ -+} while (0) -+#endif -+ -+#define crypto_digest_update_data(C, PTR, N) \ -+do { \ -+ uint8_t *__p = (uint8_t *)(PTR); \ -+ size_t __n = (N); \ -+ count_and_csum((C), __p, __n); \ -+ verify_sig_add_data((C)->mod_sig, __p, __n); \ -+} while (0) -+ -+#define crypto_digest_update_val(C, VAL) \ -+do { \ -+ uint8_t *__p = (uint8_t *)&(VAL); \ -+ size_t __n = sizeof(VAL); \ -+ count_and_csum((C), __p, __n); \ -+ verify_sig_add_data((C)->mod_sig, __p, __n); \ -+} while (0) -+ -+static int module_verify_canonicalise(struct module_verify_data *mvdata); -+ -+static int extract_elf_rela(struct module_verify_data *mvdata, -+ int secix, -+ const Elf_Rela *relatab, size_t nrels, -+ const char *sh_name); -+ -+static int extract_elf_rel(struct module_verify_data *mvdata, -+ int secix, -+ const Elf_Rel *reltab, size_t nrels, -+ const char *sh_name); -+ -+#ifdef CONFIG_MODULE_SIG_FORCE -+static int signedonly = 1; -+#else -+static int signedonly; -+#endif -+ -+static int __init sign_setup(char *str) -+{ -+ signedonly = 1; -+ return 0; -+} -+__setup("enforcemodulesig", sign_setup); -+ -+static const char modsign_note_name[] = ELFNOTE_NAME(MODSIGN_NOTE_NAME); -+static const char modsign_note_section[] = ELFNOTE_SECTION(MODSIGN_NOTE_NAME); -+ -+/* -+ * verify a module's signature -+ */ -+int module_verify_signature(struct module_verify_data *mvdata, -+ int *_gpgsig_ok) -+{ -+ struct crypto_key_verify_context *mod_sig; -+ const struct elf_note *note; -+ const Elf_Shdr *sechdrs = mvdata->sections; -+ const char *secstrings = mvdata->secstrings; -+ const char *sig; -+ unsigned note_size, sig_size, note_namesz; -+ int loop, ret; -+ -+ _debug("looking for sig section '%s'\n", modsign_note_section); -+ -+ for (loop = 1; loop < mvdata->nsects; loop++) { -+ switch (sechdrs[loop].sh_type) { -+ case SHT_NOTE: -+ if (strcmp(mvdata->secstrings + sechdrs[loop].sh_name, -+ modsign_note_section) == 0) -+ mvdata->sig_index = loop; -+ break; -+ } -+ } -+ -+ if (mvdata->sig_index <= 0) -+ goto no_signature; -+ -+ note = mvdata->buffer + sechdrs[mvdata->sig_index].sh_offset; -+ note_size = sechdrs[mvdata->sig_index].sh_size; -+ -+ /* there should be one note of the appropriate type */ -+ if (note_size < sizeof(*note) + 2 * 4) -+ goto format_error_no_free; -+ note_namesz = note->n_namesz; -+ sig_size = note->n_descsz; -+ if (note_namesz != sizeof(modsign_note_name)) -+ goto format_error_no_free; -+ if (note->n_type != MODSIGN_NOTE_TYPE) -+ goto format_error_no_free; -+ if (memcmp(note + 1, modsign_note_name, note_namesz) != 0) -+ goto format_error_no_free; -+ sig = (void *)(note + 1) + roundup(note_namesz, 4); -+ -+ _debug("sig in section %d (size %d)\n", -+ mvdata->sig_index, sig_size); -+ _debug("%02x%02x%02x%02x%02x%02x%02x%02x\n", -+ sig[0], sig[1], sig[2], sig[3], -+ sig[4], sig[5], sig[6], sig[7]); -+ -+ /* produce a canonicalisation map for the sections */ -+ ret = module_verify_canonicalise(mvdata); -+ if (ret < 0) -+ return ret; -+ -+ /* Find the crypto key for the module signature -+ * - !!! if this tries to load the required hash algorithm module, -+ * we will deadlock!!! -+ */ -+ mod_sig = verify_sig_begin(modsign_keyring, sig, sig_size); -+ if (IS_ERR(mod_sig)) { -+ pr_err("Couldn't initiate module signature verification: %ld\n", -+ PTR_ERR(mod_sig)); -+ return PTR_ERR(mod_sig); -+ } -+ -+ mvdata->mod_sig = mod_sig; -+ -+#ifdef MODSIGN_DEBUG -+ mvdata->xcsum = 0; -+#endif -+ -+ /* load data from each relevant section into the digest */ -+ for (loop = 0; loop < mvdata->ncanon; loop++) { -+ int sect = mvdata->canonlist[loop]; -+ unsigned long sh_type = sechdrs[sect].sh_type; -+ unsigned long sh_info = sechdrs[sect].sh_info; -+ unsigned long sh_size = sechdrs[sect].sh_size; -+ unsigned long sh_flags = sechdrs[sect].sh_flags; -+ const char *sh_name = secstrings + sechdrs[sect].sh_name; -+ const void *data = mvdata->buffer + sechdrs[sect].sh_offset; -+ -+#ifdef MODSIGN_DEBUG -+ mvdata->csum = 0; -+#endif -+ -+ /* it would be nice to include relocation sections, but the act -+ * of adding a signature to the module seems changes their -+ * contents, because the symtab gets changed when sections are -+ * added or removed */ -+ if (sh_type == SHT_REL || sh_type == SHT_RELA) { -+ uint32_t xsh_info = mvdata->canonmap[sh_info]; -+ -+ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); -+ crypto_digest_update_val(mvdata, xsh_info); -+ -+ if (sh_type == SHT_RELA) -+ ret = extract_elf_rela( -+ mvdata, sect, -+ data, -+ sh_size / sizeof(Elf_Rela), -+ sh_name); -+ else -+ ret = extract_elf_rel( -+ mvdata, sect, -+ data, -+ sh_size / sizeof(Elf_Rel), -+ sh_name); -+ -+ if (ret < 0) -+ goto format_error; -+ continue; -+ } -+ -+ /* include the headers of BSS sections */ -+ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { -+ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); -+ goto digested; -+ } -+ -+ /* include allocatable loadable sections */ -+ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) -+ goto include_section; -+ -+ continue; -+ -+ include_section: -+ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); -+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); -+ -+ crypto_digest_update_data(mvdata, data, sh_size); -+ -+ digested: -+ _debug("%08zx %02x digested the %s section, size %ld\n", -+ mvdata->signed_size, mvdata->csum, sh_name, sh_size); -+ } -+ -+ _debug("Contributed %zu bytes to the digest (csum 0x%02x)\n", -+ mvdata->signed_size, mvdata->xcsum); -+ -+ /* do the actual signature verification */ -+ ret = verify_sig_end(mvdata->mod_sig, sig, sig_size); -+ mvdata->mod_sig = NULL; -+ -+ _debug("verify-sig : %d\n", ret); -+ -+ switch (ret) { -+ case 0: /* good signature */ -+ *_gpgsig_ok = 1; -+ break; -+ case -EKEYREJECTED: /* signature mismatch or number format error */ -+ pr_err("Module signature verification failed\n"); -+ break; -+ case -ENOKEY: /* signed, but we don't have the public key */ -+ pr_err("Module signed with unknown public key\n"); -+ break; -+ default: /* other error (probably ENOMEM) */ -+ break; -+ } -+ -+ return ret; -+ -+format_error: -+ verify_sig_cancel(mvdata->mod_sig); -+ mvdata->mod_sig = NULL; -+format_error_no_free: -+ pr_err("Module format error encountered\n"); -+ return -ELIBBAD; -+ -+ /* deal with the case of an unsigned module */ -+no_signature: -+ _debug("no signature found\n"); -+ if (!signedonly) -+ return 0; -+ pr_err("An attempt to load unsigned module was rejected\n"); -+ return -EKEYREJECTED; -+} -+ -+/* -+ * canonicalise the section table index numbers -+ */ -+static int module_verify_canonicalise(struct module_verify_data *mvdata) -+{ -+ int canon, loop, changed, tmp; -+ -+ /* produce a list of index numbers of sections that contribute -+ * to the kernel's module image -+ */ -+ mvdata->canonlist = -+ kmalloc(sizeof(int) * mvdata->nsects * 2, GFP_KERNEL); -+ if (!mvdata->canonlist) -+ return -ENOMEM; -+ -+ mvdata->canonmap = mvdata->canonlist + mvdata->nsects; -+ canon = 0; -+ -+ for (loop = 1; loop < mvdata->nsects; loop++) { -+ const Elf_Shdr *section = mvdata->sections + loop; -+ -+ if (loop == mvdata->sig_index) -+ continue; -+ -+ /* we only need to canonicalise allocatable sections */ -+ if (section->sh_flags & SHF_ALLOC) -+ mvdata->canonlist[canon++] = loop; -+ else if ((section->sh_type == SHT_REL || -+ section->sh_type == SHT_RELA) && -+ mvdata->sections[section->sh_info].sh_flags & SHF_ALLOC) -+ mvdata->canonlist[canon++] = loop; -+ } -+ -+ /* canonicalise the index numbers of the contributing section */ -+ do { -+ changed = 0; -+ -+ for (loop = 0; loop < canon - 1; loop++) { -+ const char *x, *y; -+ -+ x = mvdata->secstrings + -+ mvdata->sections[mvdata->canonlist[loop + 0]].sh_name; -+ y = mvdata->secstrings + -+ mvdata->sections[mvdata->canonlist[loop + 1]].sh_name; -+ -+ if (strcmp(x, y) > 0) { -+ tmp = mvdata->canonlist[loop + 0]; -+ mvdata->canonlist[loop + 0] = -+ mvdata->canonlist[loop + 1]; -+ mvdata->canonlist[loop + 1] = tmp; -+ changed = 1; -+ } -+ } -+ -+ } while (changed); -+ -+ for (loop = 0; loop < canon; loop++) -+ mvdata->canonmap[mvdata->canonlist[loop]] = loop + 1; -+ mvdata->ncanon = canon; -+ return 0; -+} -+ -+/* -+ * extract an ELF RELA table -+ * - need to canonicalise the entries in case section addition/removal has -+ * rearranged the symbol table and the section table -+ */ -+static int extract_elf_rela(struct module_verify_data *mvdata, -+ int secix, -+ const Elf_Rela *relatab, size_t nrels, -+ const char *sh_name) -+{ -+ struct { -+#if defined(MODULES_ARE_ELF32) -+ uint32_t r_offset; -+ uint32_t r_addend; -+ uint32_t st_value; -+ uint32_t st_size; -+ uint16_t st_shndx; -+ uint8_t r_type; -+ uint8_t st_info; -+ uint8_t st_other; -+#elif defined(MODULES_ARE_ELF64) -+ uint64_t r_offset; -+ uint64_t r_addend; -+ uint64_t st_value; -+ uint64_t st_size; -+ uint32_t r_type; -+ uint16_t st_shndx; -+ uint8_t st_info; -+ uint8_t st_other; -+#else -+#error unsupported module type -+#endif -+ } __attribute__((packed)) relocation; -+ -+ const Elf_Rela *reloc; -+ const Elf_Sym *symbol; -+ size_t loop; -+ -+ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ -+ for (loop = 0; loop < nrels; loop++) { -+ int st_shndx; -+ -+ reloc = &relatab[loop]; -+ -+ /* decode the relocation */ -+ relocation.r_offset = reloc->r_offset; -+ relocation.r_addend = reloc->r_addend; -+ relocation.r_type = ELF_R_TYPE(reloc->r_info); -+ -+ /* decode the symbol referenced by the relocation */ -+ symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)]; -+ relocation.st_info = symbol->st_info; -+ relocation.st_other = symbol->st_other; -+ relocation.st_value = symbol->st_value; -+ relocation.st_size = symbol->st_size; -+ relocation.st_shndx = symbol->st_shndx; -+ st_shndx = symbol->st_shndx; -+ -+ /* canonicalise the section used by the symbol */ -+ if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects) -+ relocation.st_shndx = mvdata->canonmap[st_shndx]; -+ -+ crypto_digest_update_val(mvdata, relocation); -+ -+ /* undefined symbols must be named if referenced */ -+ if (st_shndx == SHN_UNDEF) { -+ const char *name = mvdata->strings + symbol->st_name; -+ crypto_digest_update_data(mvdata, -+ name, strlen(name) + 1); -+ } -+ } -+ -+ _debug("%08zx %02x digested the %s section, nrels %zu\n", -+ mvdata->signed_size, mvdata->csum, sh_name, nrels); -+ -+ return 0; -+} -+ -+/* -+ * extract an ELF REL table -+ * - need to canonicalise the entries in case section addition/removal has -+ * rearranged the symbol table and the section table -+ */ -+static int extract_elf_rel(struct module_verify_data *mvdata, -+ int secix, -+ const Elf_Rel *reltab, size_t nrels, -+ const char *sh_name) -+{ -+ struct { -+#if defined(MODULES_ARE_ELF32) -+ uint32_t r_offset; -+ uint32_t st_value; -+ uint32_t st_size; -+ uint16_t st_shndx; -+ uint8_t r_type; -+ uint8_t st_info; -+ uint8_t st_other; -+#elif defined(MODULES_ARE_ELF64) -+ uint64_t r_offset; -+ uint64_t st_value; -+ uint64_t st_size; -+ uint32_t r_type; -+ uint16_t st_shndx; -+ uint8_t st_info; -+ uint8_t st_other; -+#else -+#error unsupported module type -+#endif -+ } __attribute__((packed)) relocation; -+ -+ const Elf_Rel *reloc; -+ const Elf_Sym *symbol; -+ size_t loop; -+ -+ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ -+ for (loop = 0; loop < nrels; loop++) { -+ int st_shndx; -+ -+ reloc = &reltab[loop]; -+ -+ /* decode the relocation */ -+ relocation.r_offset = reloc->r_offset; -+ relocation.r_type = ELF_R_TYPE(reloc->r_info); -+ -+ /* decode the symbol referenced by the relocation */ -+ symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)]; -+ relocation.st_info = symbol->st_info; -+ relocation.st_other = symbol->st_other; -+ relocation.st_value = symbol->st_value; -+ relocation.st_size = symbol->st_size; -+ relocation.st_shndx = symbol->st_shndx; -+ st_shndx = symbol->st_shndx; -+ -+ /* canonicalise the section used by the symbol */ -+ if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects) -+ relocation.st_shndx = mvdata->canonmap[st_shndx]; -+ -+ crypto_digest_update_val(mvdata, relocation); -+ -+ /* undefined symbols must be named if referenced */ -+ if (st_shndx == SHN_UNDEF) { -+ const char *name = mvdata->strings + symbol->st_name; -+ crypto_digest_update_data(mvdata, -+ name, strlen(name) + 1); -+ } -+ } -+ -+ _debug("%08zx %02x digested the %s section, nrels %zu\n", -+ mvdata->signed_size, mvdata->csum, sh_name, nrels); -+ -+ return 0; -+} -+ -+/* -+ * 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", -+ 0, 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); -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index 875279f..64c5813 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -16,8 +16,9 @@ - /* - * verify a module's integrity - * - check the ELF is viable -+ * - check the module's signature - */ --int module_verify(const Elf_Ehdr *hdr, size_t size) -+int module_verify(const Elf_Ehdr *hdr, size_t size, int *_gpgsig_ok) - { - struct module_verify_data mvdata; - int ret; -@@ -34,6 +35,8 @@ int module_verify(const Elf_Ehdr *hdr, size_t size) - goto error; - } - -+ ret = module_verify_signature(&mvdata, _gpgsig_ok); -+ - error: - kfree(mvdata.secsizes); - kfree(mvdata.canonlist); -diff --git a/kernel/module-verify.h b/kernel/module-verify.h -index 20884fc..0ccdb71 100644 ---- a/kernel/module-verify.h -+++ b/kernel/module-verify.h -@@ -10,10 +10,13 @@ - */ - - #include <linux/types.h> -+#include <linux/elf.h> -+#include <keys/crypto-type.h> - #include <asm/module.h> - - #ifdef CONFIG_MODULE_VERIFY - struct module_verify_data { -+ struct crypto_key_verify_context *mod_sig; /* Module signing context */ - const void *buffer; /* module buffer */ - const Elf_Ehdr *hdr; /* ELF header */ - const Elf_Shdr *sections; /* ELF section table */ -@@ -37,7 +40,7 @@ struct module_verify_data { - /* - * module-verify.c - */ --extern int module_verify(const Elf_Ehdr *hdr, size_t size); -+extern int module_verify(const Elf_Ehdr *hdr, size_t size, int *_gpgsig_ok); - - /* - * module-verify-elf.c -@@ -48,6 +51,18 @@ extern int module_verify_elf(struct module_verify_data *mvdata); - #define module_verify_elf(m) (0) - #endif - -+/* -+ * module-verify-sig.c -+ */ -+#ifdef CONFIG_MODULE_SIG -+extern struct key *modsign_keyring; -+ -+extern int module_verify_signature(struct module_verify_data *mvdata, -+ int *_gpgsig_ok); -+#else -+#define module_verify_signature(m, g) (0) -+#endif -+ - #else --#define module_verify(h, s) (0) -+#define module_verify(h, s, g) (0) - #endif -diff --git a/kernel/module.c b/kernel/module.c -index 54d6910..bb38584 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -2372,7 +2372,8 @@ static inline void kmemleak_load_module(const struct module *mod, - /* Sets info->hdr and info->len. */ - static int copy_and_check(struct load_info *info, - const void __user *umod, unsigned long len, -- const char __user *uargs) -+ const char __user *uargs, -+ int *_gpgsig_ok) - { - int err; - Elf_Ehdr *hdr; -@@ -2406,7 +2407,7 @@ static int copy_and_check(struct load_info *info, - } - - /* Verify the module's contents */ -- err = module_verify(hdr, len); -+ err = module_verify(hdr, len, _gpgsig_ok); - if (err < 0) - goto free_hdr; - -@@ -2752,7 +2753,8 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr, - return 0; - } - --static struct module *layout_and_allocate(struct load_info *info) -+static struct module *layout_and_allocate(struct load_info *info, -+ int gpgsig_ok) - { - /* Module within temporary copy. */ - struct module *mod; -@@ -2762,6 +2764,7 @@ static struct module *layout_and_allocate(struct load_info *info) - mod = setup_load_info(info); - if (IS_ERR(mod)) - return mod; -+ mod->gpgsig_ok = gpgsig_ok; - - err = check_modinfo(mod, info); - if (err) -@@ -2845,17 +2848,18 @@ static struct module *load_module(void __user *umod, - struct load_info info = { NULL, }; - struct module *mod; - long err; -+ int gpgsig_ok; - - pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", - umod, len, uargs); - - /* Copy in the blobs from userspace, check they are vaguely sane. */ -- err = copy_and_check(&info, umod, len, uargs); -+ err = copy_and_check(&info, umod, len, uargs, &gpgsig_ok); - if (err) - return ERR_PTR(err); - - /* Figure out module layout, and allocate all the memory. */ -- mod = layout_and_allocate(&info); -+ mod = layout_and_allocate(&info, gpgsig_ok); - if (IS_ERR(mod)) { - err = PTR_ERR(mod); - goto free_copy; -@@ -3491,8 +3495,13 @@ void print_modules(void) - printk(KERN_DEFAULT "Modules linked in:"); - /* Most callers should already have preempt disabled, but make sure */ - preempt_disable(); -- list_for_each_entry_rcu(mod, &modules, list) -+ list_for_each_entry_rcu(mod, &modules, list) { - printk(" %s%s", mod->name, module_flags(mod, buf)); -+#ifdef CONFIG_MODULE_SIG -+ if (!mod->gpgsig_ok) -+ printk("(U)"); -+#endif -+ } - preempt_enable(); - if (last_unloaded_module[0]) - printk(" [last unloaded: %s]", last_unloaded_module); + config INIT_ALL_POSSIBLE +-- +1.7.10.2 + + +From f9980a27c5d2d02af2feb578957145a206088fff Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:54 +0100 +Subject: [PATCH 22/36] MODSIGN: Sign modules during the build process + +If CONFIG_MODULE_SIG is set, then this patch will cause the module to get a +signature installed. The following steps will occur: + + (1) The module will be linked to foo.ko.unsigned instead of foo.ko + + (2) The module's signable content will be extracted to foo.ko.digest by the + mod-extract program. + + (3) The signature will be generated on foo.ko.digest by gpg and placed in + foo.ko.digest.sig + + (4) The signature will be encapsulated into an ELF note and placed into a file + called foo.ko.note.o using the output from modsign-note.sh piped into the + assembler. + + (5) The unsigned module from (1) and the signature ELF note from (4) will be + linked together to produce foo.ko + +Step (3) requires private and public keys to be available. By default these +are expected to be found in PGP keyring files called modsign.sec (the secret +key) and modsign.pub (the public key) in the build root. + +If the secret key is not found then signing will be skipped and the unsigned +module from (1) will just be copied to foo.ko. + +If signing occurs, lines like the following will be seen: + + LD [M] fs/foo/foo.ko.unsigned + SIGN [M] fs/foo/foo.ko + +will appear in the build log. If it is skipped, the following will be seen: + + LD [M] fs/foo/foo.ko.unsigned + NO SIGN [M] fs/foo/foo.ko + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + scripts/Makefile.modpost | 87 ++++- + scripts/mod/Makefile | 2 +- + scripts/mod/mod-extract.c | 913 +++++++++++++++++++++++++++++++++++++++++++ + scripts/mod/modsign-note.sh | 16 + + 4 files changed, 1016 insertions(+), 2 deletions(-) + create mode 100644 scripts/mod/mod-extract.c + create mode 100644 scripts/mod/modsign-note.sh + diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost -index 08dce14..b436b04 100644 +index 08dce14..17465d8 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -14,7 +14,8 @@ @@ -6266,7 +5008,7 @@ index 08dce14..b436b04 100644 quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -@@ -125,7 +129,86 @@ $(modules): %.ko :%.o %.mod.o FORCE +@@ -125,7 +129,88 @@ $(modules): %.ko :%.o %.mod.o FORCE $(call if_changed,ld_ko_o) targets += $(modules) @@ -6284,8 +5026,8 @@ index 08dce14..b436b04 100644 +targets += $(modules:.ko=.ko.unsigned) + +# Step 7), sign the modules -+MODSECKEY = ./kernel.sec -+MODPUBKEY = ./kernel.pub ++MODSECKEY = ./modsign.sec ++MODPUBKEY = ./modsign.pub +KEYFLAGS = --no-default-keyring --secret-keyring $(MODSECKEY) --keyring $(MODPUBKEY) --no-default-keyring --homedir . --no-options --no-auto-check-trustdb --no-permission-warning + +ifdef CONFIG_MODULE_SIG_SHA1 @@ -6331,6 +5073,7 @@ index 08dce14..b436b04 100644 +endif + +ifeq ($(SIGN_MODULES),1) ++KEYRING_DEP := modsign.sec modsign.pub +quiet_cmd_sign_ko_ko_unsigned = SIGN [M] $@ + cmd_sign_ko_ko_unsigned = \ + scripts/mod/mod-extract $< $@.digest && \ @@ -6340,12 +5083,13 @@ index 08dce14..b436b04 100644 + $(CC) -x assembler-with-cpp $(c_flags) $(CFLAGS_MODULE) -c -o $@.note.o - && \ + $(LD) -r $(LDFLAGS) -o $@ $< $@.note.o +else ++KEYRING_DEP := +quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@ + cmd_sign_ko_ko_unsigned = \ + cp $< $@ +endif + -+$(modules): %.ko :%.ko.unsigned FORCE ++$(modules): %.ko :%.ko.unsigned $(KEYRING_DEP) FORCE + $(call if_changed,sign_ko_ko_unsigned) + +targets += $(modules) @@ -6353,16 +5097,6 @@ index 08dce14..b436b04 100644 # Add FORCE to the prequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- -diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore -index e9b7abe..223dfd6 100644 ---- a/scripts/mod/.gitignore -+++ b/scripts/mod/.gitignore -@@ -1,4 +1,5 @@ - elfconfig.h - mk_elfconfig - modpost -+mod-extract - diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index ff954f8..4654e3b 100644 --- a/scripts/mod/Makefile @@ -7315,78 +6049,2048 @@ index 0000000..bca67c0 + +exit 0 -- -1.7.9.1 +1.7.10.2 + + +From 38ddca03060502e8134320b732758fd6b6a98247 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:55 +0100 +Subject: [PATCH 23/36] MODSIGN: Module signature verification stub + +Create a stub for the module signature verifier and link it into module.c so +that it gets called. A field is added to struct module to record whether or +not a valid module signature was detected. + +The stub also implements the policy for handling unsigned modules and the +printing of error messages to indicate various problems with the module. -From 31e77b71e584a702c8e44b83f6af03bb8511cf8d Mon Sep 17 00:00:00 2001 -From: Josh Boyer <jwboyer@redhat.com> -Date: Tue, 6 Mar 2012 12:56:49 -0500 -Subject: [PATCH] Make sure MPILIB is selected for stuff that uses it... +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. -security/built-in.o: In function `public_key_destroy': -/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/public_key.c:41: undefined reference to `mpi_free' -security/built-in.o: In function `RSA_verify_signature': -/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:222: undefined reference to `mpi_get_nbits' -/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:224: undefined reference to `mpi_get_nbits' +This table indicates the behaviours in the various situations: -security/built-in.o: In function `RSAVP1': -/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:93: undefined reference to `mpi_cmp_ui' -/home/jwboyer/kernel/kernel-3.2.fc17/linux-3.3.0-0.rc6.git0.3.fc17.x86_64/security/keys/crypto_rsa.c:97: undefined reference to `mpi_cmp' + 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 + Signed, hash algorithm unavailable ENOPKG ENOPKG + Corrupt signature EBADMSG EBADMSG + Corrupt ELF ELIBBAD ELIBBAD -Signed-off-by: Josh Boyer <jwboyer@redhat.com> +Signed-off-by: David Howells <dhowells@redhat.com> --- - security/keys/Kconfig | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + include/linux/module.h | 3 ++ + kernel/Makefile | 1 + + kernel/module-verify-defs.h | 77 ++++++++++++++++++++++++++++++ + kernel/module-verify.c | 109 +++++++++++++++++++++++++++++++++++++++++++ + kernel/module-verify.h | 19 ++++++++ + kernel/module.c | 26 +++++++++-- + 6 files changed, 230 insertions(+), 5 deletions(-) + create mode 100644 kernel/module-verify-defs.h + create mode 100644 kernel/module-verify.c + create mode 100644 kernel/module-verify.h -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index 5e77c2a..e40f9b68 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -89,12 +89,14 @@ config CRYPTO_KEY_PUBLIC_KEY_SUBTYPE +diff --git a/include/linux/module.h b/include/linux/module.h +index fbcafe2..7391833 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -227,6 +227,9 @@ struct module + /* Unique handle for this module */ + char name[MODULE_NAME_LEN]; - config CRYPTO_KEY_PKEY_ALGO_RSA - tristate "RSA public-key algorithm" -+ select MPILIB_EXTRA - depends on CRYPTO_KEY_PUBLIC_KEY_SUBTYPE - help - This option enables support for the RSA algorithm (PKCS#1, RFC3447). ++ /* Is this module GPG signed */ ++ bool gpgsig_ok; ++ + /* Sysfs stuff. */ + struct module_kobject mkobj; + struct module_attribute *modinfo_attrs; +diff --git a/kernel/Makefile b/kernel/Makefile +index cb41b95..7608053 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -51,6 +51,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-verify.o + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +diff --git a/kernel/module-verify-defs.h b/kernel/module-verify-defs.h +new file mode 100644 +index 0000000..292d2ba +--- /dev/null ++++ b/kernel/module-verify-defs.h +@@ -0,0 +1,77 @@ ++/* Module verification 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. ++ */ ++ ++#ifdef CONFIG_MODULE_SIG ++ ++/* ++ * Internal state ++ */ ++struct module_verify_data { ++ struct crypto_key_verify_context *mod_sig; /* Module signing context */ ++ union { ++ const void *buffer; /* module buffer */ ++ const Elf_Ehdr *hdr; /* ELF header */ ++ }; ++ const Elf_Shdr *sections; /* ELF section table */ ++ const char *secstrings; /* ELF section string table */ ++ const void *sig; /* Signature note content */ ++ size_t size; /* module object size */ ++ size_t nsects; /* number of sections */ ++ size_t sig_size; /* Size of signature */ ++ size_t signed_size; /* count of bytes contributed to digest */ ++ unsigned *canonlist; /* list of canonicalised sections */ ++ unsigned *canonmap; /* section canonicalisation map */ ++ unsigned ncanon; /* number of canonicalised sections */ ++ unsigned sig_index; /* module signature section index */ ++ uint8_t xcsum; /* checksum of bytes contributed to digest */ ++ uint8_t csum; /* checksum of bytes representing a section */ ++}; ++ ++/* ++ * Whether or not we support various types of ELF relocation record ++ */ ++#if defined(MODULE_HAS_ELF_REL_ONLY) ++#define is_elf_rel(sh_type) ((sh_type) == SHT_REL) ++#define is_elf_rela(sh_type) (0) ++#elif defined(MODULE_HAS_ELF_RELA_ONLY) ++#define is_elf_rel(sh_type) (0) ++#define is_elf_rela(sh_type) ((sh_type) == SHT_RELA) ++#else ++#define is_elf_rel(sh_type) ((sh_type) == SHT_REL) ++#define is_elf_rela(sh_type) ((sh_type) == SHT_RELA) ++#endif ++ ++/* ++ * Debugging. Define DEBUG to enable. ++ */ ++#define _debug(FMT, ...) \ ++ do { \ ++ if (unlikely(modsign_debug)) \ ++ pr_debug(FMT, ##__VA_ARGS__); \ ++ } while(0) ++ ++#ifdef DEBUG ++#define count_and_csum(C, __p, __n) \ ++do { \ ++ int __loop; \ ++ for (__loop = 0; __loop < __n; __loop++) { \ ++ (C)->csum += __p[__loop]; \ ++ (C)->xcsum += __p[__loop]; \ ++ } \ ++ (C)->signed_size += __n; \ ++} while (0) ++#else ++#define count_and_csum(C, __p, __n) \ ++do { \ ++} while (0) ++#endif ++ ++#endif /* CONFIG_MODULE_SIG */ +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +new file mode 100644 +index 0000000..0a3eb4b +--- /dev/null ++++ b/kernel/module-verify.c +@@ -0,0 +1,109 @@ ++/* Module signature verification ++ * ++ * The code in this file examines a signed kernel module and attempts to ++ * determine if the PGP signature inside the module matches a digest of the ++ * allocatable sections and the canonicalised relocation tables for those ++ * allocatable sections. ++ * ++ * The module signature is included in an ELF note within the ELF structure of ++ * the module blob. This, combined with the minimal canonicalisation performed ++ * here, permits the module to pass through "strip -x", "strip -g" and ++ * "eu-strip" without becoming corrupt. "strip" and "strip -s" will render a ++ * module unusable by removing the symbol table. ++ * ++ * Copyright (C) 2004, 2011, 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * - Derived from GregKH's RSA module signer ++ * ++ * 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. ++ */ ++ ++#undef DEBUG ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/elf.h> ++#include <linux/elfnote.h> ++#include <linux/sched.h> ++#include <linux/cred.h> ++#include <linux/modsign.h> ++#include <linux/moduleparam.h> ++#include <keys/crypto-type.h> ++#include "module-verify.h" ++#include "module-verify-defs.h" ++ ++#ifdef DEBUG ++static int modsign_debug; ++core_param(modsign_debug, modsign_debug, int, 0644); ++#else ++#define modsign_debug false ++#endif ++ ++#ifdef CONFIG_MODULE_SIG_FORCE ++#define modsign_signedonly true ++#else ++static bool modsign_signedonly; ++#endif ++ ++static const char modsign_note_name[] = ELFNOTE_NAME(MODSIGN_NOTE_NAME); ++static const char modsign_note_section[] = ELFNOTE_SECTION(MODSIGN_NOTE_NAME); ++ ++/* ++ * Verify a module's integrity ++ */ ++int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) ++{ ++ struct module_verify_data mvdata; ++ int ret; ++ ++ memset(&mvdata, 0, sizeof(mvdata)); ++ mvdata.buffer = hdr; ++ mvdata.size = size; ++ ++ if (mvdata.sig_index <= 0) { ++ /* Deal with an unsigned module */ ++ if (modsign_signedonly) { ++ pr_err("An attempt to load unsigned module was rejected\n"); ++ return -EKEYREJECTED; ++ } else { ++ return 0; ++ } ++ goto out; ++ } ++ ++ ret = 0; ++ ++out: ++ switch (ret) { ++ case 0: /* Good signature */ ++ *_gpgsig_ok = true; ++ break; ++ case -ELIBBAD: ++ pr_err("Module format error encountered\n"); ++ break; ++ case -EBADMSG: ++ pr_err("Module signature error encountered\n"); ++ break; ++ case -EKEYREJECTED: /* Signature mismatch or number format error */ ++ pr_err("Module signature verification failed\n"); ++ break; ++ case -ENOKEY: /* Signed, but we don't have the public key */ ++ pr_err("Module signed with unknown public key\n"); ++ break; ++ default: /* Other error (probably ENOMEM) */ ++ break; ++ } ++ return ret; ++} ++ ++static int __init sign_setup(char *str) ++{ ++#ifndef CONFIG_MODULE_SIG_FORCE ++ modsign_signedonly = true; ++#endif ++ return 0; ++} ++__setup("enforcemodulesig", sign_setup); +diff --git a/kernel/module-verify.h b/kernel/module-verify.h +new file mode 100644 +index 0000000..6bb6b56 +--- /dev/null ++++ b/kernel/module-verify.h +@@ -0,0 +1,19 @@ ++/* Module verification definitions ++ * ++ * Copyright (C) 2004, 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 License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#ifdef CONFIG_MODULE_SIG ++extern int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok); ++#else ++static inline int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) ++{ ++ return 0; ++} ++#endif +diff --git a/kernel/module.c b/kernel/module.c +index 377cb06..c3797f7 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -58,6 +58,7 @@ + #include <linux/jump_label.h> + #include <linux/pfn.h> + #include <linux/bsearch.h> ++#include "module-verify.h" - config PGP_LIBRARY - tristate "PGP parsing library" -+ select MPILIB - help - This option enables a library that provides a number of simple - utility functions for parsing PGP (RFC 4880) packet-based messages. + #define CREATE_TRACE_POINTS + #include <trace/events/module.h> +@@ -2402,7 +2403,8 @@ static inline void kmemleak_load_module(const struct module *mod, + /* Sets info->hdr and info->len. */ + static int copy_and_check(struct load_info *info, + const void __user *umod, unsigned long len, +- const char __user *uargs) ++ const char __user *uargs, ++ bool *_gpgsig_ok) + { + int err; + Elf_Ehdr *hdr; +@@ -2435,6 +2437,12 @@ static int copy_and_check(struct load_info *info, + goto free_hdr; + } + ++ /* Verify the module's contents */ ++ *_gpgsig_ok = false; ++ err = module_verify(hdr, len, _gpgsig_ok); ++ if (err < 0) ++ goto free_hdr; ++ + info->hdr = hdr; + info->len = len; + return 0; +@@ -2777,7 +2785,8 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr, + return 0; + } + +-static struct module *layout_and_allocate(struct load_info *info) ++static struct module *layout_and_allocate(struct load_info *info, ++ bool gpgsig_ok) + { + /* Module within temporary copy. */ + struct module *mod; +@@ -2787,6 +2796,7 @@ static struct module *layout_and_allocate(struct load_info *info) + mod = setup_load_info(info); + if (IS_ERR(mod)) + return mod; ++ mod->gpgsig_ok = gpgsig_ok; + + err = check_modinfo(mod, info); + if (err) +@@ -2870,17 +2880,18 @@ static struct module *load_module(void __user *umod, + struct load_info info = { NULL, }; + struct module *mod; + long err; ++ bool gpgsig_ok; + + pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", + umod, len, uargs); + + /* Copy in the blobs from userspace, check they are vaguely sane. */ +- err = copy_and_check(&info, umod, len, uargs); ++ err = copy_and_check(&info, umod, len, uargs, &gpgsig_ok); + if (err) + return ERR_PTR(err); + + /* Figure out module layout, and allocate all the memory. */ +- mod = layout_and_allocate(&info); ++ mod = layout_and_allocate(&info, gpgsig_ok); + if (IS_ERR(mod)) { + err = PTR_ERR(mod); + goto free_copy; +@@ -3517,8 +3528,13 @@ void print_modules(void) + printk(KERN_DEFAULT "Modules linked in:"); + /* Most callers should already have preempt disabled, but make sure */ + preempt_disable(); +- list_for_each_entry_rcu(mod, &modules, list) ++ list_for_each_entry_rcu(mod, &modules, list) { + printk(" %s%s", mod->name, module_flags(mod, buf)); ++#ifdef CONFIG_MODULE_SIG ++ if (!mod->gpgsig_ok) ++ printk("(U)"); ++#endif ++ } + preempt_enable(); + if (last_unloaded_module[0]) + printk(" [last unloaded: %s]", last_unloaded_module); -- -1.7.9.1 +1.7.10.2 -diff --git a/security/keys/crypto_rsa.c b/security/keys/crypto_rsa.c ---- a/security/keys/crypto_rsa.c ---- b/security/keys/crypto_rsa.c -@@ -219,15 +219,24 @@ - kenter(""); + +From 6f5323e52cdc37969939ef82036783da67afe69f Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:55 +0100 +Subject: [PATCH 24/36] MODSIGN: Provide module signing public keys to the + kernel + +Include a PGP keyring containing the public keys required to perform module +verification in the kernel image during build and create a special keyring +during boot which is then populated with keys of crypto type holding the public +keys found in the PGP keyring. + +These can be seen by root: + +[root@andromeda ~]# cat /proc/keys +07ad4ee0 I----- 1 perm 3f010000 0 0 crypto modsign.0: RSA 87b9b3bd [] +15c7f8c3 I----- 1 perm 1f030000 0 0 keyring .module_sign: 1/4 +... + +It is probably worth permitting root to invalidate these keys, resulting in +their removal and preventing further modules from being loaded with that key. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/Makefile | 3 +- + kernel/modsign-pubkey.c | 74 +++++++++++++++++++++++++++++++++++++++++++ + kernel/module-verify-defs.h | 4 +++ + kernel/module-verify.c | 2 -- + 4 files changed, 80 insertions(+), 3 deletions(-) + create mode 100644 kernel/modsign-pubkey.c + +diff --git a/kernel/Makefile b/kernel/Makefile +index 7608053..986ed7f 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -51,7 +51,8 @@ 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-verify.o ++obj-$(CONFIG_MODULE_SIG) += module-verify.o modsign-pubkey.o ++kernel/modsign-pubkey.o: modsign.pub + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +diff --git a/kernel/modsign-pubkey.c b/kernel/modsign-pubkey.c +new file mode 100644 +index 0000000..2ada460 +--- /dev/null ++++ b/kernel/modsign-pubkey.c +@@ -0,0 +1,74 @@ ++/* Public keys for module signature verification ++ * ++ * Copyright (C) 2011 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 <keys/crypto-type.h> ++#include "module-verify-defs.h" ++ ++struct key *modsign_keyring; ++ ++extern __initdata const u8 modsign_public_keys[]; ++extern __initdata const u8 modsign_public_keys_end[]; ++asm(".section .init.data,\"aw\"\n" ++ "modsign_public_keys:\n" ++ ".incbin \"modsign.pub\"\n" ++ "modsign_public_keys_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", ++ 0, 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 modsign_pubkey_init(void) ++{ ++ pr_notice("Load module verification keys\n"); ++ ++ if (preload_pgp_keys(modsign_public_keys, ++ modsign_public_keys_end - modsign_public_keys, ++ modsign_keyring, "modsign.") < 0) ++ panic("Can't load module signing keys\n"); ++ ++ return 0; ++} ++late_initcall(modsign_pubkey_init); +diff --git a/kernel/module-verify-defs.h b/kernel/module-verify-defs.h +index 292d2ba..45bea45 100644 +--- a/kernel/module-verify-defs.h ++++ b/kernel/module-verify-defs.h +@@ -11,6 +11,10 @@ - /* (1) Check the signature size against the public key modulus size */ -- k = (mpi_get_nbits(key->rsa.n) + 7) / 8; -+ k = mpi_get_nbits(key->rsa.n); -+ tsize = mpi_get_nbits(sig->rsa.s); + #ifdef CONFIG_MODULE_SIG -- tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; -+ /* 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. -+ * Fail here only if signature length is longer than modulus size. ++#include <linux/module.h> ++ ++extern struct key *modsign_keyring; ++ + /* + * Internal state + */ +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 0a3eb4b..b1c1d4c 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -27,8 +27,6 @@ + #include <linux/slab.h> + #include <linux/elf.h> + #include <linux/elfnote.h> +-#include <linux/sched.h> +-#include <linux/cred.h> + #include <linux/modsign.h> + #include <linux/moduleparam.h> + #include <keys/crypto-type.h> +-- +1.7.10.2 + + +From 5727333d123ef9d7fa2666069306bf3ec2d7f110 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:56 +0100 +Subject: [PATCH 25/36] MODSIGN: Check the ELF container + +Check the ELF container of the kernel module to prevent the kernel from +crashing or getting corrupted whilst trying to use it and locate the module +signature note if present. + +We try to check as little as possible. We check the metadata that the +signature checker actually has to use, and leave anything that it doesn't +actually need to the signature to catch. + +The stuff we need to check is: + + (1) The locations and offsets in the ELF header of important parts like the + section table. + + (2) The section table. Note that we only check sh_info for section types that + we're actually interested in (string, symbol and relocation tables). We + also check that alignments are what we expect for those tables. + + (3) That non-empty string tables have the required NUL at the end so that we + can be sure that all strings therein are NUL-terminated. We don't bother + checking for the required NUL at the beginning as it shouldn't cause a + problem to us. + + (4) The name offset and section index in each symbol. We could defer this to + when we deal with the relocation tables so that we only check symbols that + are used by relocations - but we would then end up checking some symbols + multiple times. + + (5) The module signature note section and the first note in it if present. + + (6) That relocations applied to an allocatable section only refer to + symbols in allocatable sections and absolute symbols (done in the module + signing code rather than here). + +Note that these checks survive "strip -x", "strip -g" and "eu-strip" being +applied to a module and detect if the module was given to "strip" or "strip -s" +and report an error. + +We can skip some direct checks that turn out unnecessary or redundant: + + (1) That sh_link has a greater than 0 value for symbol tables and relocation + tables. These require the index of a string table and a symbol table + respectively - and since we have already checked section 0 is of SHT_NULL + type, checking the symbol type renders the sh_link > 0 check redundant. + + (2) That a non-empty string table begins with a NUL. Since we check the + string table ends with a NUL, any string in there will be NUL-terminated + and shouldn't cause us to transgress beyond the bounds of the string table + when using strlen(). + + (3) That strings in a string table actually make sense. We don't care, so + long as it is NUL terminated. Any string that refers to an undefined + symbol is added to the crypto digest and will be checked that way. + Strings that we directly look for (such as ".modinfo") will be validated + by that. + + (4) That sections don't overlap. We don't actually care if sections overlap + in the file, provided we don't see bad metadata. If the sections holding + the allocatable content overlap, then the signature check is likely to + fail. + + (5) That symbol values and relocation offsets and addends make sense. We just + add this data to the digest if it pertains to an allocatable section. + + (6) That allocatable note sections, other than the signature note, make sense. + The contents of these get added to the digest in their entirety, so we + don't need to check them manually. + +If bad ELF is detected, ELIBBAD is indicated. + +Note! The "noinline" attribute on the module_verify_elf() function results in +somewhat smaller code. Similarly, having separate loops to check basic section +parameters and to check type-specific features of sections results in smaller +code, presumably because some local variables can be discarded. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/module-verify.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 226 insertions(+) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index b1c1d4c..5711aeb 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -50,6 +50,224 @@ static const char modsign_note_name[] = ELFNOTE_NAME(MODSIGN_NOTE_NAME); + static const char modsign_note_section[] = ELFNOTE_SECTION(MODSIGN_NOTE_NAME); + + /* ++ * Verify the minimum amount of ELF structure of a module needed to check the ++ * module's signature without bad ELF crashing the kernel. ++ */ ++static noinline int module_verify_elf(struct module_verify_data *mvdata) ++{ ++ const struct elf_note *note; ++ const Elf_Ehdr *hdr = mvdata->hdr; ++ const Elf_Shdr *section, *secstop; ++ const Elf_Sym *symbols, *symbol, *symstop; ++ const char *strtab; ++ size_t size, secsize, secstrsize, strsize, notesize, notemetasize; ++ unsigned line; ++ ++ size = mvdata->size; ++ ++#define elfcheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while(0) ++ ++#define seccheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while(0) ++ ++#define symcheck(X) \ ++do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0) ++ ++ /* Validate the ELF header */ ++ elfcheck(size > sizeof(Elf_Ehdr)); ++ elfcheck(hdr->e_ehsize < size); ++ ++ elfcheck(hdr->e_shnum < SHN_LORESERVE); ++ elfcheck(hdr->e_shstrndx < hdr->e_shnum); ++ elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr)); ++ elfcheck(hdr->e_shoff < size); ++ elfcheck(hdr->e_shoff >= hdr->e_ehsize); ++ elfcheck(hdr->e_shoff % sizeof(long) == 0); ++ elfcheck(hdr->e_shnum * sizeof(Elf_Shdr) <= size - hdr->e_shoff); ++ ++ /* Validate the section table contents */ ++ mvdata->nsects = hdr->e_shnum; ++ mvdata->sections = mvdata->buffer + hdr->e_shoff; ++ secstop = mvdata->sections + mvdata->nsects; ++ ++ /* Section 0 is special, usually indicating an undefined symbol */ ++ seccheck(mvdata->sections[SHN_UNDEF].sh_type == SHT_NULL); ++ ++ /* We also want access to the section name table */ ++ seccheck(mvdata->sections[hdr->e_shstrndx].sh_type == SHT_STRTAB); ++ secstrsize = mvdata->sections[hdr->e_shstrndx].sh_size; ++ ++ for (section = mvdata->sections + 1; section < secstop; section++) { ++ seccheck(section->sh_name < secstrsize); ++ seccheck(section->sh_link < hdr->e_shnum); ++ ++ /* Section file offsets must reside within the file, though ++ * they don't have to actually consume file space (.bss for ++ * example). ++ */ ++ seccheck(section->sh_offset >= hdr->e_ehsize); ++ seccheck((section->sh_offset & (section->sh_addralign - 1)) == 0); ++ seccheck(section->sh_offset <= size); ++ if (section->sh_type != SHT_NOBITS) ++ seccheck(section->sh_size <= size - section->sh_offset); ++ ++ /* Some types of section should contain arrays of fixed-length ++ * records of a predetermined size and mustn't contain partial ++ * records. Also, records we're going to access directly must ++ * have appropriate alignment that we don't get a misalignment ++ * exception. ++ */ ++ if (section->sh_entsize > 1) ++ seccheck(section->sh_size % section->sh_entsize == 0); ++ ++ switch (section->sh_type) { ++ case SHT_SYMTAB: ++ seccheck(section->sh_entsize == sizeof(Elf_Sym)); ++ seccheck(section->sh_addralign % sizeof(long) == 0); ++ break; ++ case SHT_REL: ++#ifndef MODULE_HAS_ELF_RELA_ONLY ++ seccheck(section->sh_entsize == sizeof(Elf_Rel)); ++ seccheck(section->sh_addralign % sizeof(long) == 0); ++ break; ++#else ++ seccheck(false); ++ break; ++#endif ++ case SHT_RELA: ++#ifndef MODULE_HAS_ELF_REL_ONLY ++ seccheck(section->sh_entsize == sizeof(Elf_Rela)); ++ seccheck(section->sh_addralign % sizeof(long) == 0); ++ break; ++#else ++ seccheck(false); ++ break; ++#endif ++ case SHT_NOTE: ++ seccheck(section->sh_addralign % 4 == 0); ++ break; ++ case SHT_STRTAB: ++ /* We require all string tables to be non-empty. If ++ * not empty, a string table must end in a NUL (it ++ * should also begin with a NUL, but it's not a problem ++ * for us if it doesn't). ++ */ ++ seccheck(section->sh_size >= 2); ++ strtab = mvdata->buffer + section->sh_offset; ++ seccheck(strtab[section->sh_size - 1] == '\0'); ++ break; ++ } ++ } ++ ++ /* Check features specific to the type of each section. ++ * ++ * Note that having a separate loop here allows the compiler to discard ++ * some local variables used in the above loop thus making the code ++ * smaller. + */ - pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); -- if (tsize != k) { -+ if (k < tsize) { - ret = -EBADMSG; - goto error; ++ for (section = mvdata->sections + 1; section < secstop; section++) { ++ switch (section->sh_type) { ++ case SHT_SYMTAB: ++ /* Symbol tables nominate a string table. */ ++ seccheck(mvdata->sections[section->sh_link].sh_type == ++ SHT_STRTAB); ++ ++ /* Validate the symbols in the table. The first symbol ++ * (STN_UNDEF) is special. ++ */ ++ symbol = symbols = mvdata->buffer + section->sh_offset; ++ symstop = mvdata->buffer + ++ (section->sh_offset + section->sh_size); ++ ++ symcheck(ELF_ST_TYPE(symbols[0].st_info) == STT_NOTYPE); ++ symcheck(symbol[0].st_shndx == SHN_UNDEF); ++ ++ strsize = mvdata->sections[section->sh_link].sh_size; ++ for (symbol++; symbol < symstop; symbol++) { ++ symcheck(symbol->st_name < strsize); ++ symcheck(symbol->st_shndx < hdr->e_shnum || ++ symbol->st_shndx >= SHN_LORESERVE); ++ } ++ break; ++ ++#ifndef MODULE_HAS_ELF_RELA_ONLY ++ case SHT_REL: ++#endif ++#ifndef MODULE_HAS_ELF_REL_ONLY ++ case SHT_RELA: ++#endif ++ /* Relocation tables nominate a symbol table and a ++ * target section to which the relocations will be ++ * applied. ++ */ ++ seccheck(mvdata->sections[section->sh_link].sh_type == ++ SHT_SYMTAB); ++ seccheck(section->sh_info > 0); ++ seccheck(section->sh_info < hdr->e_shnum); ++ break; ++ } ++ } ++ ++ /* We can now use section name string table section as we checked its ++ * bounds in the loop above. ++ * ++ * Each name is NUL-terminated, and the table as a whole should have a ++ * NUL at either end as there to be at least one named section for the ++ * module information. ++ */ ++ section = &mvdata->sections[hdr->e_shstrndx]; ++ mvdata->secstrings = mvdata->buffer + section->sh_offset; ++ ++ for (section = mvdata->sections + 1; section < secstop; section++) { ++ const char *name = mvdata->secstrings + section->sh_name; ++ ++ switch (section->sh_type) { ++ case SHT_NOTE: ++ if (strcmp(name, modsign_note_section) != 0) ++ continue; ++ ++ /* We've found a note purporting to contain a signature ++ * so we should check the structure of that. ++ */ ++ notemetasize = sizeof(struct elf_note) + ++ roundup(sizeof(modsign_note_name), 4); ++ ++ seccheck(mvdata->sig_index == 0); ++ seccheck(section->sh_size > notemetasize); ++ note = mvdata->buffer + section->sh_offset; ++ seccheck(note->n_type == MODSIGN_NOTE_TYPE); ++ seccheck(note->n_namesz == sizeof(modsign_note_name)); ++ ++ notesize = section->sh_size - notemetasize; ++ seccheck(note->n_descsz <= notesize); ++ ++ seccheck(memcmp(note + 1, modsign_note_name, ++ note->n_namesz) == 0); ++ ++ mvdata->sig_size = note->n_descsz; ++ mvdata->sig = (void *)note + notemetasize; ++ mvdata->sig_index = section - mvdata->sections; ++ break; ++ } ++ } ++ ++ return 0; ++ ++elfcheck_error: ++ _debug("Verify ELF error (check %u)\n", line); ++ return -ELIBBAD; ++seccheck_error: ++ _debug("Verify ELF error [sec %ld] (check %u)\n", ++ (long)(section - mvdata->sections), line); ++ return -ELIBBAD; ++symcheck_error: ++ _debug("Verify ELF error [sym %ld] (check %u)\n", ++ (long)(symbol - symbols), line); ++ return -ELIBBAD; ++} ++ ++/* + * Verify a module's integrity + */ + int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) +@@ -61,6 +279,14 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) + mvdata.buffer = hdr; + mvdata.size = size; + ++ /* Minimally check the ELF to make sure building the signature digest ++ * won't crash the kernel. ++ */ ++ ret = module_verify_elf(&mvdata); ++ if (ret < 0) ++ goto out; ++ ++ /* The ELF checker found the sig for us if it exists */ + if (mvdata.sig_index <= 0) { + /* Deal with an unsigned module */ + if (modsign_signedonly) { +-- +1.7.10.2 + + +From 21a28e681f53685960f2780b7884e8b391122259 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:56 +0100 +Subject: [PATCH 26/36] MODSIGN: Produce a filtered and canonicalised section + list + +Build a list of the sections in which we're interested and canonicalise the +section indices to avoid the problems of the section table being altered by ld +when the signature is linked into the binary and by strip. + +The only sections in which we're actually interested are those that are marked +allocatable (which will be kept in memory) and relocation tables that are +applicable to those sections. + +Canonicalisation is done by sorting the filtered list in order of section name. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/module-verify.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 5711aeb..13c60c2 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -268,6 +268,80 @@ symcheck_error: + } + + /* ++ * Canonicalise the section table index numbers. ++ * ++ * We build a list of the sections we want to add to the digest and sort it by ++ * name. We're only interested in adding two types of section: ++ * ++ * (1) Allocatable sections. These should have no references to other ++ * sections. ++ * ++ * (2) Relocation tables for allocatable sections. The section table entry ++ * has a reference to the target section to which the relocations will be ++ * applied. The relocation entries have references to symbols in ++ * non-allocatable sections. Symbols can be replaced by their contents, ++ * but do include a further reference to a section - which must be ++ * canonicalised. ++ * ++ * We also build a map of raw section index to canonical section index. ++ */ ++static int module_verify_canonicalise(struct module_verify_data *mvdata) ++{ ++ const Elf_Shdr *sechdrs = mvdata->sections; ++ unsigned *canonlist, canon, loop, tmp; ++ bool changed; ++ ++ canonlist = kmalloc(sizeof(unsigned) * mvdata->nsects * 2, GFP_KERNEL); ++ if (!canonlist) ++ return -ENOMEM; ++ ++ mvdata->canonlist = canonlist; ++ mvdata->canonmap = canonlist + mvdata->nsects; ++ canon = 0; ++ ++ for (loop = 1; loop < mvdata->nsects; loop++) { ++ const Elf_Shdr *section = mvdata->sections + loop; ++ ++ if (loop == mvdata->sig_index) ++ continue; ++ ++ /* We only want allocatable sections and relocation tables */ ++ if (section->sh_flags & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ else if ((is_elf_rel(section->sh_type) || ++ is_elf_rela(section->sh_type)) && ++ mvdata->sections[section->sh_info].sh_flags & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ } ++ ++ /* Sort the canonicalisation list */ ++ do { ++ changed = false; ++ ++ for (loop = 0; loop < canon - 1; loop++) { ++ const char *x, *y; ++ ++ x = mvdata->secstrings + sechdrs[canonlist[loop + 0]].sh_name; ++ y = mvdata->secstrings + sechdrs[canonlist[loop + 1]].sh_name; ++ ++ if (strcmp(x, y) > 0) { ++ tmp = canonlist[loop + 0]; ++ canonlist[loop + 0] = canonlist[loop + 1]; ++ canonlist[loop + 1] = tmp; ++ changed = true; ++ } ++ } ++ } while (changed); ++ ++ /* What we really want is a raw-to-canon lookup table */ ++ memset(mvdata->canonmap, 0xff, mvdata->nsects * sizeof(unsigned)); ++ for (loop = 0; loop < canon; loop++) ++ mvdata->canonmap[mvdata->canonlist[loop]] = loop + 1; ++ mvdata->ncanon = canon; ++ return 0; ++} ++ ++/* + * Verify a module's integrity + */ + int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) +@@ -298,7 +372,13 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) + goto out; } -+ /* Round up to octets */ -+ k = (k + 7) / 8; ++ /* Produce a canonicalisation map for the sections */ ++ ret = module_verify_canonicalise(&mvdata); ++ if (ret < 0) ++ goto out; + - /* (2b) Apply the RSAVP1 verification primitive to the public key */ - ret = RSAVP1(key, sig->rsa.s, &m); + ret = 0; ++ kfree(mvdata.canonlist); + + out: + switch (ret) { +-- +1.7.10.2 + + +From 92fb97859c50a0dd63886baf057477a7a336b2a1 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:56 +0100 +Subject: [PATCH 27/36] MODSIGN: Create digest of module content and check + signature + +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. + +There are several reasons why these patches are useful, amongst which are: + + (1) to prevent accidentally corrupted modules from causing damage; + + (2) to prevent maliciously modified modules from 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. + +These patches have two main appeals: (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. + +Note that 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. To protect the kernel image +would be the responsibility of the boot loader or the system BIOS. + +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! The "noinline" attribute on module_verify_signature() results in +somewhat smaller code. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/module-verify.c | 321 +++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 320 insertions(+), 1 deletion(-) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 13c60c2..a31b39c 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -49,6 +49,22 @@ static bool modsign_signedonly; + static const char modsign_note_name[] = ELFNOTE_NAME(MODSIGN_NOTE_NAME); + static const char modsign_note_section[] = ELFNOTE_SECTION(MODSIGN_NOTE_NAME); + ++#define crypto_digest_update_data(C, PTR, N) \ ++do { \ ++ uint8_t *__p = (uint8_t *)(PTR); \ ++ size_t __n = (N); \ ++ count_and_csum((C), __p, __n); \ ++ verify_sig_add_data((C)->mod_sig, __p, __n); \ ++} while (0) ++ ++#define crypto_digest_update_val(C, VAL) \ ++do { \ ++ uint8_t *__p = (uint8_t *)&(VAL); \ ++ size_t __n = sizeof(VAL); \ ++ count_and_csum((C), __p, __n); \ ++ verify_sig_add_data((C)->mod_sig, __p, __n); \ ++} while (0) ++ + /* + * Verify the minimum amount of ELF structure of a module needed to check the + * module's signature without bad ELF crashing the kernel. +@@ -342,6 +358,309 @@ static int module_verify_canonicalise(struct module_verify_data *mvdata) + } + + /* ++ * Extract an ELF REL table ++ * ++ * We need to canonicalise the entries in case section/symbol addition/removal ++ * has rearranged the symbol table and the section table. ++ */ ++static int extract_elf_rel(struct module_verify_data *mvdata, ++ unsigned secix, ++ const Elf_Rel *reltab, size_t nrels, ++ const char *sh_name) ++{ ++ struct { ++#if defined(MODULES_ARE_ELF32) ++ uint32_t r_offset; ++ uint32_t st_value; ++ uint32_t st_size; ++ uint16_t st_shndx; ++ uint8_t r_type; ++ uint8_t st_info; ++ uint8_t st_other; ++#elif defined(MODULES_ARE_ELF64) ++ uint64_t r_offset; ++ uint64_t st_value; ++ uint64_t st_size; ++ uint32_t r_type; ++ uint16_t st_shndx; ++ uint8_t st_info; ++ uint8_t st_other; ++#else ++#error unsupported module type ++#endif ++ } __attribute__((packed)) relocation; ++ ++ const Elf_Rel *reloc; ++ const Elf_Sym *symbols, *symbol; ++ const char *strings; ++ unsigned long r_sym; ++ size_t nsyms, loop; ++ ++ nsyms = mvdata->sections[secix].sh_size / sizeof(Elf_Sym); ++ symbols = mvdata->buffer + mvdata->sections[secix].sh_offset; ++ strings = mvdata->buffer + ++ mvdata->sections[mvdata->sections[secix].sh_link].sh_offset; ++ ++ /* Contribute the relevant bits from a join of { REL, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ unsigned st_shndx; ++ ++ reloc = &reltab[loop]; ++ ++ /* Decode the relocation */ ++ relocation.r_offset = reloc->r_offset; ++ relocation.r_type = ELF_R_TYPE(reloc->r_info); ++ ++ /* Decode the symbol referenced by the relocation */ ++ r_sym = ELF_R_SYM(reloc->r_info); ++ if (r_sym >= nsyms) ++ return -ELIBBAD; ++ symbol = &symbols[r_sym]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = symbol->st_shndx; ++ st_shndx = symbol->st_shndx; ++ ++ /* Canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects) { ++ if (!(mvdata->sections[st_shndx].sh_flags & SHF_ALLOC)) ++ return -ELIBBAD; ++ relocation.st_shndx = mvdata->canonmap[st_shndx]; ++ } ++ ++ crypto_digest_update_val(mvdata, relocation); ++ ++ /* Undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + symbol->st_name; ++ crypto_digest_update_data(mvdata, ++ name, strlen(name) + 1); ++ } ++ } ++ ++ _debug("%08zx %02x digested the %s section, nrels %zu\n", ++ mvdata->signed_size, mvdata->csum, sh_name, nrels); ++ ++ return 0; ++} ++ ++/* ++ * Extract an ELF RELA table ++ * ++ * We need to canonicalise the entries in case section/symbol addition/removal ++ * has rearranged the symbol table and the section table. ++ */ ++static int extract_elf_rela(struct module_verify_data *mvdata, ++ unsigned secix, ++ const Elf_Rela *relatab, size_t nrels, ++ const char *sh_name) ++{ ++ struct { ++#if defined(MODULES_ARE_ELF32) ++ uint32_t r_offset; ++ uint32_t r_addend; ++ uint32_t st_value; ++ uint32_t st_size; ++ uint16_t st_shndx; ++ uint8_t r_type; ++ uint8_t st_info; ++ uint8_t st_other; ++#elif defined(MODULES_ARE_ELF64) ++ uint64_t r_offset; ++ uint64_t r_addend; ++ uint64_t st_value; ++ uint64_t st_size; ++ uint32_t r_type; ++ uint16_t st_shndx; ++ uint8_t st_info; ++ uint8_t st_other; ++#else ++#error unsupported module type ++#endif ++ } __attribute__((packed)) relocation; ++ ++ const Elf_Shdr *relsec, *symsec, *strsec; ++ const Elf_Rela *reloc; ++ const Elf_Sym *symbols, *symbol; ++ unsigned long r_sym; ++ const char *strings; ++ size_t nsyms, loop; ++ ++ relsec = &mvdata->sections[secix]; ++ symsec = &mvdata->sections[relsec->sh_link]; ++ strsec = &mvdata->sections[symsec->sh_link]; ++ nsyms = symsec->sh_size / sizeof(Elf_Sym); ++ symbols = mvdata->buffer + symsec->sh_offset; ++ strings = mvdata->buffer + strsec->sh_offset; ++ ++ /* Contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ unsigned st_shndx; ++ ++ reloc = &relatab[loop]; ++ ++ /* Decode the relocation */ ++ relocation.r_offset = reloc->r_offset; ++ relocation.r_addend = reloc->r_addend; ++ relocation.r_type = ELF_R_TYPE(reloc->r_info); ++ ++ /* Decode the symbol referenced by the relocation */ ++ r_sym = ELF_R_SYM(reloc->r_info); ++ if (r_sym >= nsyms) ++ return -ELIBBAD; ++ symbol = &symbols[r_sym]; ++ relocation.st_info = symbol->st_info; ++ relocation.st_other = symbol->st_other; ++ relocation.st_value = symbol->st_value; ++ relocation.st_size = symbol->st_size; ++ relocation.st_shndx = 0; ++ st_shndx = symbol->st_shndx; ++ ++ /* Canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects) { ++ if (!(mvdata->sections[st_shndx].sh_flags & SHF_ALLOC)) ++ return -ELIBBAD; ++ relocation.st_shndx = mvdata->canonmap[st_shndx]; ++ } ++ ++ crypto_digest_update_val(mvdata, relocation); ++ ++ /* Undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + symbol->st_name; ++ crypto_digest_update_data(mvdata, ++ name, strlen(name) + 1); ++ } ++ } ++ ++ _debug("%08zx %02x digested the %s section, nrels %zu\n", ++ mvdata->signed_size, mvdata->csum, sh_name, nrels); ++ ++ return 0; ++} ++ ++/* ++ * Verify a module's signature ++ */ ++static noinline int module_verify_signature(struct module_verify_data *mvdata) ++{ ++ struct crypto_key_verify_context *mod_sig; ++ const Elf_Shdr *sechdrs = mvdata->sections; ++ const char *secstrings = mvdata->secstrings; ++ const u8 *sig = mvdata->sig; ++ size_t sig_size = mvdata->sig_size; ++ int loop, ret; ++ ++ _debug("sig in section %u (size %zu)\n", ++ mvdata->sig_index, mvdata->sig_size); ++ _debug("%02x%02x%02x%02x%02x%02x%02x%02x\n", ++ sig[0], sig[1], sig[2], sig[3], ++ sig[4], sig[5], sig[6], sig[7]); ++ ++ /* Find the crypto key for the module signature ++ * - !!! if this tries to load the required hash algorithm module, ++ * we will deadlock!!! ++ */ ++ mod_sig = verify_sig_begin(modsign_keyring, sig, sig_size); ++ if (IS_ERR(mod_sig)) { ++ pr_err("Couldn't initiate module signature verification: %ld\n", ++ PTR_ERR(mod_sig)); ++ return PTR_ERR(mod_sig); ++ } ++ ++ mvdata->mod_sig = mod_sig; ++#ifdef DEBUG ++ mvdata->xcsum = 0; ++#endif ++ ++ /* Load data from each relevant section into the digest. Note that ++ * canonlist[] is a filtered list and only contains the sections we ++ * actually want. ++ */ ++ for (loop = 0; loop < mvdata->ncanon; loop++) { ++ int sect = mvdata->canonlist[loop]; ++ unsigned long sh_type = sechdrs[sect].sh_type; ++ unsigned long sh_info = sechdrs[sect].sh_info; ++ unsigned long sh_size = sechdrs[sect].sh_size; ++ const char *sh_name = secstrings + sechdrs[sect].sh_name; ++ const void *data = mvdata->buffer + sechdrs[sect].sh_offset; ++ ++#ifdef DEBUG ++ mvdata->csum = 0; ++#endif ++ ++ /* Digest the headers of any section we include. */ ++ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name)); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size); ++ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign); ++ ++ /* Relocation record sections refer to the section to be ++ * relocated, but this needs to be canonicalised to survive ++ * stripping. ++ */ ++ if (is_elf_rel(sh_type) || is_elf_rela(sh_type)) ++ crypto_digest_update_val(mvdata, ++ mvdata->canonmap[sh_info]); ++ ++ /* Since relocation records give details of how we have to ++ * alter the allocatable sections, we need to digest these too. ++ * ++ * These, however, refer to metadata (symbols and sections) ++ * that may have been altered by the process of adding the ++ * signature section or the process of being stripped. ++ * ++ * To deal with this, we substitute the referenced metadata for ++ * the references to that metadata. So, for instance, the ++ * symbol ref from the relocation record is replaced with the ++ * contents of the symbol to which it refers, and the symbol's ++ * section ref is replaced with a canonicalised section number. ++ */ ++ if (is_elf_rel(sh_type)) { ++ ret = extract_elf_rel(mvdata, sect, ++ data, ++ sh_size / sizeof(Elf_Rel), ++ sh_name); ++ if (ret < 0) ++ goto format_error; ++ continue; ++ } ++ ++ if (is_elf_rela(sh_type)) { ++ ret = extract_elf_rela(mvdata, sect, ++ data, ++ sh_size / sizeof(Elf_Rela), ++ sh_name); ++ if (ret < 0) ++ goto format_error; ++ continue; ++ } ++ ++ /* Include allocatable loadable sections */ ++ if (sh_type != SHT_NOBITS) ++ crypto_digest_update_data(mvdata, data, sh_size); ++ ++ _debug("%08zx %02x digested the %s section, size %ld\n", ++ mvdata->signed_size, mvdata->csum, sh_name, sh_size); ++ } ++ ++ _debug("Contributed %zu bytes to the digest (csum 0x%02x)\n", ++ mvdata->signed_size, mvdata->xcsum); ++ ++ /* Do the actual signature verification */ ++ ret = verify_sig_end(mvdata->mod_sig, sig, sig_size); ++ _debug("verify-sig : %d\n", ret); ++ return ret; ++ ++format_error: ++ verify_sig_cancel(mvdata->mod_sig); ++ return -ELIBBAD; ++} ++ ++/* + * Verify a module's integrity + */ + int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) +@@ -377,7 +696,7 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) if (ret < 0) + goto out; + +- ret = 0; ++ ret = module_verify_signature(&mvdata); + kfree(mvdata.canonlist); + + out: +-- +1.7.10.2 + + +From 2e9f557c1235027c0c7223a8a072333758905066 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:49:57 +0100 +Subject: [PATCH 28/36] MODSIGN: Automatically generate module signing keys if + missing + +Automatically generate keys for module signing if they're absent so that +allyesconfig doesn't break. The builder should consider generating their own +keyrings, however, so that the keys are appropriately named and any extra keys +required get imported. + +Also change the names of the keyring files to modsign.pub and modsign.sec so +that they are then a more obvious what they're about and add a dependency for +the signing rules on the keyring files so that the signatures get regenerated +if the keyrings change. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/Makefile | 42 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +diff --git a/kernel/Makefile b/kernel/Makefile +index 986ed7f..d8139bb 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -52,7 +52,6 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += module.o + obj-$(CONFIG_MODULE_SIG) += module-verify.o modsign-pubkey.o +-kernel/modsign-pubkey.o: modsign.pub + obj-$(CONFIG_KALLSYMS) += kallsyms.o + obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o + obj-$(CONFIG_KEXEC) += kexec.o +@@ -129,3 +128,44 @@ quiet_cmd_timeconst = TIMEC $@ + targets += timeconst.h + $(obj)/timeconst.h: $(src)/timeconst.pl FORCE + $(call if_changed,timeconst) ++ ++############################################################################### ++# ++# 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. ++# ++############################################################################### ++ifeq ($(CONFIG_MODULE_SIG),y) ++kernel/modsign-pubkey.o: modsign.pub ++ ++modsign.pub modsign.sec: genkey ++ @echo "###" ++ @echo "### Now generating a PGP 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 "###" ++ gpg --homedir . --batch --gen-key genkey ++ @echo "###" ++ @echo "### Key pair generated." ++ @echo "###" ++ rm -f pubring.gpg secring.gpg trustdb.gpg ++ ++genkey: ++ echo "%pubring modsign.pub" >genkey ++ echo "%secring modsign.sec" >>genkey ++ echo "%no-protection: yes" >> genkey ++ echo "%transient-key: yes" >>genkey ++ echo "Key-Type: RSA" >>genkey ++ echo "Key-Length: 4096" >>genkey ++ echo "Name-Real: Sample kernel key" >>genkey ++ echo "Name-Comment: Sample kernel module signing key" >>genkey ++ echo "%commit" >>genkey ++ ++endif ++CLEAN_FILES += modsign.pub modsign.sec genkey random_seed +-- +1.7.10.2 + + +From 958049a9def253735019a5acf19b4c2aeec9f01c Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 10 May 2012 23:55:35 +0100 +Subject: [PATCH 29/36] MODSIGN: Suppress some redundant ELF checks + +Suppress some redundant ELF checks in module_verify_elf() that are also done +by copy_and_check() in the core module loader code prior to calling +module_verify(). + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/module-verify.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index a31b39c..e1bfd28 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -76,7 +76,7 @@ static noinline int module_verify_elf(struct module_verify_data *mvdata) + const Elf_Shdr *section, *secstop; + const Elf_Sym *symbols, *symbol, *symstop; + const char *strtab; +- size_t size, secsize, secstrsize, strsize, notesize, notemetasize; ++ size_t size, secstrsize, strsize, notesize, notemetasize; + unsigned line; + + size = mvdata->size; +@@ -96,11 +96,11 @@ do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0) + + elfcheck(hdr->e_shnum < SHN_LORESERVE); + elfcheck(hdr->e_shstrndx < hdr->e_shnum); +- elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr)); +- elfcheck(hdr->e_shoff < size); ++ /* elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr)); */ ++ /* elfcheck(hdr->e_shoff < size); */ + elfcheck(hdr->e_shoff >= hdr->e_ehsize); + elfcheck(hdr->e_shoff % sizeof(long) == 0); +- elfcheck(hdr->e_shnum * sizeof(Elf_Shdr) <= size - hdr->e_shoff); ++ /* elfcheck(hdr->e_shnum * sizeof(Elf_Shdr) <= size - hdr->e_shoff); */ + + /* Validate the section table contents */ + mvdata->nsects = hdr->e_shnum; +-- +1.7.10.2 + + +From b5df4e7900852395a1ccb70190827cccc0c0de2d Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 11 May 2012 16:56:05 +0100 +Subject: [PATCH 30/36] MODSIGN: Fix some checkpatch noise + +Fix some warnings and errors produced by checkpatch. + +Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> +Signed-off-by: David Howells <dhowells@redhat.com> +--- + kernel/module-verify-defs.h | 24 ++++++++++++------------ + kernel/module-verify.c | 18 +++++++++++------- + kernel/module-verify.h | 3 ++- + security/keys/crypto/pgp_key_parser.c | 2 +- + 4 files changed, 26 insertions(+), 21 deletions(-) + +diff --git a/kernel/module-verify-defs.h b/kernel/module-verify-defs.h +index 45bea45..2fe31e1 100644 +--- a/kernel/module-verify-defs.h ++++ b/kernel/module-verify-defs.h +@@ -60,22 +60,22 @@ struct module_verify_data { + do { \ + if (unlikely(modsign_debug)) \ + pr_debug(FMT, ##__VA_ARGS__); \ +- } while(0) ++ } while (0) + + #ifdef DEBUG +-#define count_and_csum(C, __p, __n) \ +-do { \ +- int __loop; \ +- for (__loop = 0; __loop < __n; __loop++) { \ +- (C)->csum += __p[__loop]; \ +- (C)->xcsum += __p[__loop]; \ +- } \ +- (C)->signed_size += __n; \ +-} while (0) ++#define count_and_csum(C, __p, __n) \ ++ do { \ ++ int __loop; \ ++ for (__loop = 0; __loop < __n; __loop++) { \ ++ (C)->csum += __p[__loop]; \ ++ (C)->xcsum += __p[__loop]; \ ++ } \ ++ (C)->signed_size += __n; \ ++ } while (0) + #else + #define count_and_csum(C, __p, __n) \ +-do { \ +-} while (0) ++ do { \ ++ } while (0) + #endif + + #endif /* CONFIG_MODULE_SIG */ +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index e1bfd28..161cf3e 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -82,13 +82,13 @@ static noinline int module_verify_elf(struct module_verify_data *mvdata) + size = mvdata->size; + + #define elfcheck(X) \ +-do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while(0) ++do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while (0) + + #define seccheck(X) \ +-do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while(0) ++do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while (0) + + #define symcheck(X) \ +-do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0) ++do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while (0) + + /* Validate the ELF header */ + elfcheck(size > sizeof(Elf_Ehdr)); +@@ -388,7 +388,7 @@ static int extract_elf_rel(struct module_verify_data *mvdata, + #else + #error unsupported module type + #endif +- } __attribute__((packed)) relocation; ++ } __packed relocation; + + const Elf_Rel *reloc; + const Elf_Sym *symbols, *symbol; +@@ -401,7 +401,9 @@ static int extract_elf_rel(struct module_verify_data *mvdata, + strings = mvdata->buffer + + mvdata->sections[mvdata->sections[secix].sh_link].sh_offset; + +- /* Contribute the relevant bits from a join of { REL, SYMBOL, SECTION } */ ++ /* Contribute the relevant bits from a join of ++ * { REL, SYMBOL, SECTION } ++ */ + for (loop = 0; loop < nrels; loop++) { + unsigned st_shndx; + +@@ -479,7 +481,7 @@ static int extract_elf_rela(struct module_verify_data *mvdata, + #else + #error unsupported module type + #endif +- } __attribute__((packed)) relocation; ++ } __packed relocation; + + const Elf_Shdr *relsec, *symsec, *strsec; + const Elf_Rela *reloc; +@@ -495,7 +497,9 @@ static int extract_elf_rela(struct module_verify_data *mvdata, + symbols = mvdata->buffer + symsec->sh_offset; + strings = mvdata->buffer + strsec->sh_offset; + +- /* Contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ /* Contribute the relevant bits from a join of ++ * { RELA, SYMBOL, SECTION } ++ */ + for (loop = 0; loop < nrels; loop++) { + unsigned st_shndx; + +diff --git a/kernel/module-verify.h b/kernel/module-verify.h +index 6bb6b56..c640634 100644 +--- a/kernel/module-verify.h ++++ b/kernel/module-verify.h +@@ -12,7 +12,8 @@ + #ifdef CONFIG_MODULE_SIG + extern int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok); + #else +-static inline int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) ++static inline int module_verify(const Elf_Ehdr *hdr, size_t size, ++ bool *_gpgsig_ok) + { + return 0; + } +diff --git a/security/keys/crypto/pgp_key_parser.c b/security/keys/crypto/pgp_key_parser.c +index 1407e2e..d913538 100644 +--- a/security/keys/crypto/pgp_key_parser.c ++++ b/security/keys/crypto/pgp_key_parser.c +@@ -94,7 +94,7 @@ static int pgp_calc_pkey_keyid(struct shash_desc *digest, + if (pgp->version < PGP_KEY_VERSION_4) { + u16 a16; + +- if( pgp->expires_at) ++ if (pgp->expires_at) + a16 = (pgp->expires_at - pgp->creation_time) / 86400UL; + else + a16 = 0; +-- +1.7.10.2 + + +From 27ecab7d7ee104299133c9ffd51d00ea378ed56b Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 16 May 2012 15:13:41 +0100 +Subject: [PATCH 31/36] PGPLIB: Preclear array on stack + +Preclear an array on the stack so that the error handling that frees what the +array might point to won't crash. + +Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/crypto/pgp_key_parser.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/security/keys/crypto/pgp_key_parser.c b/security/keys/crypto/pgp_key_parser.c +index d913538..84ce457 100644 +--- a/security/keys/crypto/pgp_key_parser.c ++++ b/security/keys/crypto/pgp_key_parser.c +@@ -71,6 +71,9 @@ static int pgp_calc_pkey_keyid(struct shash_desc *digest, + + kenter(""); + ++ for (i = 0; i < ARRAY_SIZE(pp); i++) ++ pp[i] = NULL; ++ + n = (pgp->version < PGP_KEY_VERSION_4) ? 8 : 6; + for (i = 0; i < npkey; i++) { + nb[i] = mpi_get_nbits(key->mpi[i]); +-- +1.7.10.2 + + +From a382a46fe70ee35cfb6fe97faa8abffd82368cbe Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Wed, 16 May 2012 15:19:24 +0100 +Subject: [PATCH 32/36] PGPLIB: Check the length in a packet or subpacket + +Check the length in a packet or subpacket to make sure there isn't an overflow +should the length not fit into the lower 31 bits of an integer. + +It is possible that both pgp_parse_packet_header() and +pgp_parse_sig_subpkt_header() could see packets that purport to be >2G in size. +Normally this will not be a problem because EBADMSG is indicated if the size +indicated is greater than the remnant size of the data - but just in case we do +end up parsing a >2G blob, a couple of simple checks can prevent an overflow +from occurring. + +Reported-by: Stephan Mueller <stephan.mueller@atsec.com> +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/crypto/pgp_library.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +index f6b831f..a9462f5 100644 +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c +@@ -137,6 +137,8 @@ ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, + pr_devel("datalen=%zu size=%zu", datalen, size); + if (datalen < size) + goto short_packet; ++ if ((int)size < 0) ++ goto too_big; + + *_data = data; + *_datalen = datalen; +@@ -147,6 +149,9 @@ ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, + short_packet: + pr_debug("Attempt to parse short packet\n"); + return -EBADMSG; ++too_big: ++ pr_debug("Signature subpacket size >2G\n"); ++ return -EMSGSIZE; + } + + /** +@@ -312,6 +317,8 @@ ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, + pr_debug("Signature subpacket size can't be zero\n"); + return -EBADMSG; + } ++ if ((int)size < 0) ++ goto too_big; + + type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; + datalen--; +@@ -330,6 +337,9 @@ ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, + short_subpacket: + pr_debug("Attempt to parse short signature subpacket\n"); + return -EBADMSG; ++too_big: ++ pr_debug("Signature subpacket size >2G\n"); ++ return -EMSGSIZE; + } + + /** +-- +1.7.10.2 + + +From a577fc904c197d97b028863989d9a891c3e1ea17 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 17 May 2012 17:41:36 +0100 +Subject: [PATCH 33/36] PGPLIB: Remnant length should be decreased in + pgp_parse_sig_params() + +The remnant length of the signature packet should be decreased rather than +being increased as we parse in pgp_parse_sig_params(). + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/crypto/pgp_library.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +index a9462f5..1ff3628 100644 +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c +@@ -503,7 +503,7 @@ int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, + if (ret < 0) + return ret; + data += subdatalen; +- datalen += subdatalen; ++ datalen -= subdatalen; + } + + subdatalen = *data++ << 8; +@@ -521,7 +521,7 @@ int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, + if (ret < 0) + return ret; + data += subdatalen; +- datalen += subdatalen; ++ datalen -= subdatalen; + } + + if (!ctx.got_the_issuer) { +-- +1.7.10.2 + + +From ab7204f60a1cedecb24bb2888db5d03bdcf20488 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 17 May 2012 17:41:36 +0100 +Subject: [PATCH 34/36] PGPLIB: Parse 5-octet length new-format packet headers + +Parse 5-octet length new-format packet headers to extract the 32-bit length +encoded therein [RFC4880 4.2.2.3]. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/crypto/pgp_library.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +index 1ff3628..310ee2f 100644 +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c +@@ -86,8 +86,17 @@ ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, + *_headerlen = 3; + break; + case 0xff: +- pr_debug("Five-byte packet length not supported\n"); +- return -EBADMSG; ++ /* Five-byte length */ ++ if (datalen < 5) ++ goto short_packet; ++ size = data[1] << 24; ++ size |= data[2] << 16; ++ size |= data[3] << 8; ++ size |= data[4]; ++ data += 5; ++ datalen -= 5; ++ *_headerlen = 6; ++ break; + default: + pr_debug("Error parsing packet length\n"); + return -EBADMSG; +-- +1.7.10.2 + + +From df233b65b833e085f39d80dc6f77c383b32786ce Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 17 May 2012 17:41:36 +0100 +Subject: [PATCH 35/36] PGPLIB: Change the debug message for Partial Body + Length specifier + +Change the debug message displayed if we encounter a Partial Body Length +specifier whilst parsing a PGP stream [RFC4880 4.2.2.4]. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + security/keys/crypto/pgp_library.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +index 310ee2f..111cbd7 100644 +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c +@@ -98,7 +98,7 @@ ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, + *_headerlen = 6; + break; + default: +- pr_debug("Error parsing packet length\n"); ++ pr_debug("Partial body length packet not supported\n"); + return -EBADMSG; + } + } else { +-- +1.7.10.2 + + +From 3ac676c62cceabdbf814bbc3495f36abd1848a97 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 18 May 2012 16:44:14 +0100 +Subject: [PATCH 36/36] PGPLIB: Adjust error handling + +Adjust the error handling in the following ways: + + (1) When parsing signature subpacket header, do the size checks before + accessing the subpacket type (which is in the subpacket payload governed + by the size). + + (2) Indicate ENOPKG when we are asked to use a public key algorithm we don't + support rather than returning ENOKEY. + + (3) Indicate EKEYREJECTED if the key that matches the signature demands a + different key algorithm to the signature. + + (4) Indicate ENOMSG if the signature blob does not contain a signature + packet. Possibly this should be EBADMSG - though that causes the next + packet parser to be tried if available. + + (5) Give a better debug message in the case of an unsupported hash. + + (6) Don't return keyring-related errors when searching for a key containing + the public key (EACCES, ENOTDIR, EAGAIN), but rather map them to ENOKEY. + Possibly EACCES should be passed through as you also get that if there + *is* a matching key, but it cannot be accessed. + +Signed-off-by: David Howells <dhowells@redhat.com> +--- + Documentation/module-signing.txt | 2 ++ + security/keys/crypto/pgp_library.c | 16 ++++++++-------- + security/keys/crypto/pgp_pubkey_sig.c | 9 +++++---- + security/keys/crypto/pgp_sig_parser.c | 15 ++++++++++++--- + 4 files changed, 27 insertions(+), 15 deletions(-) + +diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt +index d75d473..d3beb1e 100644 +--- a/Documentation/module-signing.txt ++++ b/Documentation/module-signing.txt +@@ -185,10 +185,12 @@ This table indicates the behaviours of the various situations: + MODULE STATE PERMISSIVE MODE ENFORCING MODE + ======================================= =============== =============== + Unsigned Ok EKEYREJECTED ++ No signature packet in the signature ENOMSG ENOMSG + Signed, no public key ENOKEY ENOKEY + Validly signed, public key Ok Ok + Invalidly signed, public key EKEYREJECTED EKEYREJECTED + Validly signed, expired key EKEYEXPIRED EKEYEXPIRED ++ Signed, pubkey algorithm unavailable ENOPKG ENOPKG + Signed, hash algorithm unavailable ENOPKG ENOPKG + Corrupt signature EBADMSG EBADMSG + Corrupt ELF ELIBBAD ELIBBAD +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +index 111cbd7..ee08b86 100644 +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c +@@ -322,10 +322,11 @@ ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, + } + + /* The type octet is included in the size */ +- if (size == 0) { +- pr_debug("Signature subpacket size can't be zero\n"); +- return -EBADMSG; +- } ++ pr_devel("datalen=%zu size=%zu", datalen, size); ++ if (datalen < size) ++ goto short_subpacket; ++ if (size == 0) ++ goto very_short_subpacket; + if ((int)size < 0) + goto too_big; + +@@ -333,16 +334,15 @@ ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, + datalen--; + size--; + +- pr_devel("datalen=%zu size=%zu", datalen, size); +- if (datalen < size) +- goto short_subpacket; +- + *_data = data; + *_datalen = datalen; + *_type = type; + pr_devel("Found subpkt type=%u size=%zd\n", type, size); + return size; + ++very_short_subpacket: ++ pr_debug("Signature subpacket size can't be zero\n"); ++ return -EBADMSG; + short_subpacket: + pr_debug("Attempt to parse short signature subpacket\n"); + return -EBADMSG; +diff --git a/security/keys/crypto/pgp_pubkey_sig.c b/security/keys/crypto/pgp_pubkey_sig.c +index b4b7cb0..bc02dfa 100644 +--- a/security/keys/crypto/pgp_pubkey_sig.c ++++ b/security/keys/crypto/pgp_pubkey_sig.c +@@ -86,12 +86,12 @@ struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( + !pgp_public_key_algorithms[p.params.pubkey_algo]) { + pr_debug("Unsupported public key algorithm %u\n", + p.params.pubkey_algo); +- return ERR_PTR(-ENOKEY); ++ return ERR_PTR(-ENOPKG); + } + + if (pgp_public_key_algorithms[p.params.pubkey_algo] != key->algo) { +- kleave(" = -ENOKEY [wrong pk algo]"); +- return ERR_PTR(-ENOKEY); ++ kleave(" = -EKEYREJECTED [wrong pk algo]"); ++ return ERR_PTR(-EKEYREJECTED); + } + + if (!(key->capabilities & PKEY_CAN_VERIFY)) { +@@ -101,7 +101,8 @@ struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( + + if (p.params.hash_algo >= PGP_HASH__LAST || + !pgp_hash_algorithms[p.params.hash_algo]) { +- kleave(" = -ENOPKG [hash]"); ++ pr_debug("Unsupported hash algorithm %u\n", ++ p.params.hash_algo); + return ERR_PTR(-ENOPKG); + } + +diff --git a/security/keys/crypto/pgp_sig_parser.c b/security/keys/crypto/pgp_sig_parser.c +index b72c505..3dd223f 100644 +--- a/security/keys/crypto/pgp_sig_parser.c ++++ b/security/keys/crypto/pgp_sig_parser.c +@@ -66,7 +66,7 @@ static struct key *find_key_for_pgp_sig(struct key *keyring, + return ERR_PTR(ret); + + if (!p.found_sig) +- return ERR_PTR(-EINVAL); ++ return ERR_PTR(-ENOMSG); + + sprintf(criterion, "id:%08x%08x", + be32_to_cpu(p.params.issuer32[0]), +@@ -76,8 +76,17 @@ static struct key *find_key_for_pgp_sig(struct key *keyring, + + key = keyring_search(make_key_ref(keyring, 1), + &key_type_crypto, criterion); +- if (IS_ERR(key)) +- return ERR_CAST(key); ++ 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_debug("Found key %x\n", key_serial(key_ref_to_ptr(key))); + return key_ref_to_ptr(key); +-- +1.7.10.2 + |