From 306dfccc03842b8b0238c2c4ec13198f8b8ea2a3 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Jul 24 2012 15:22:38 +0000 Subject: Update modsign and include secure boot - Update modsign patch to latest upstream - Add initial UEFI Secure Boot patchset. Work in progress. --- diff --git a/kernel.spec b/kernel.spec index fe8ba5e..6f3a9c6 100644 --- a/kernel.spec +++ b/kernel.spec @@ -62,7 +62,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 1 +%global baserelease 2 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -672,7 +672,10 @@ Patch700: linux-2.6-e1000-ich9-montevina.patch Patch800: linux-2.6-crash-driver.patch # crypto/ -Patch900: modsign-20120718.patch +Patch900: modsign-20120724.patch + +# secure boot +Patch1000: secure-boot-20120724.patch # virt + ksm patches Patch1555: fix_xen_guest_on_old_EC2.patch @@ -1374,7 +1377,10 @@ ApplyPatch linux-2.6-crash-driver.patch ApplyPatch linux-2.6-e1000-ich9-montevina.patch # crypto/ -ApplyPatch modsign-20120718.patch +ApplyPatch modsign-20120724.patch + +# secure boot +ApplyPatch secure-boot-20120724.patch # Assorted Virt Fixes ApplyPatch fix_xen_guest_on_old_EC2.patch @@ -2295,6 +2301,10 @@ fi # ||----w | # || || %changelog +* Tue Jul 24 2012 Josh Boyer +- Update modsign patch to latest upstream +- Add initial UEFI Secure Boot patchset. Work in progress. + * Tue Jul 24 2012 Justin M. Forbes - 3.6.0-0.rc0.git1.1 - Linux v3.5-1643-gf0a08fc diff --git a/modsign-20120718.patch b/modsign-20120718.patch deleted file mode 100644 index 0630014..0000000 --- a/modsign-20120718.patch +++ /dev/null @@ -1,8664 +0,0 @@ -From d1ff3781d12ad616073b4f1f3b04cef22d8c7c21 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 13:12:20 +0100 -Subject: [PATCH 01/27] MPILIB: Provide count_leading/trailing_zeros() based - on arch functions - -Provide count_leading/trailing_zeros() macros based on extant arch bit scanning -functions rather than reimplementing from scratch in MPILIB. - -Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x). - -Also move the definition to asm-generic as other people may be interested in -using it. - -Signed-off-by: David Howells -Cc: David S. Miller -Cc: Dmitry Kasatkin -Cc: Arnd Bergmann ---- - include/asm-generic/bitops/count_zeros.h | 57 ++++++++++++ - lib/mpi/longlong.h | 138 +----------------------------- - lib/mpi/mpi-bit.c | 2 +- - lib/mpi/mpi-div.c | 2 +- - lib/mpi/mpi-pow.c | 4 +- - lib/mpi/mpi-scan.c | 2 +- - lib/mpi/mpih-div.c | 8 +- - 7 files changed, 68 insertions(+), 145 deletions(-) - create mode 100644 include/asm-generic/bitops/count_zeros.h - -diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h -new file mode 100644 -index 0000000..97520d2 ---- /dev/null -+++ b/include/asm-generic/bitops/count_zeros.h -@@ -0,0 +1,57 @@ -+/* Count leading and trailing zeros functions -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ -+#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ -+ -+#include -+ -+/** -+ * count_leading_zeros - Count the number of zeros from the MSB back -+ * @x: The value -+ * -+ * Count the number of leading zeros from the MSB going towards the LSB in @x. -+ * -+ * If the MSB of @x is set, the result is 0. -+ * If only the LSB of @x is set, then the result is BITS_PER_LONG-1. -+ * If @x is 0 then the result is COUNT_LEADING_ZEROS_0. -+ */ -+static inline int count_leading_zeros(unsigned long x) -+{ -+ if (sizeof(x) == 4) -+ return BITS_PER_LONG - fls(x); -+ else -+ return BITS_PER_LONG - fls64(x); -+} -+ -+#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG -+ -+/** -+ * count_trailing_zeros - Count the number of zeros from the LSB forwards -+ * @x: The value -+ * -+ * Count the number of trailing zeros from the LSB going towards the MSB in @x. -+ * -+ * If the LSB of @x is set, the result is 0. -+ * If only the MSB of @x is set, then the result is BITS_PER_LONG-1. -+ * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0. -+ */ -+static inline int count_trailing_zeros(unsigned long x) -+{ -+#define COUNT_TRAILING_ZEROS_0 (-1) -+ -+ if (sizeof(x) == 4) -+ return ffs(x); -+ else -+ return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0; -+} -+ -+#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */ -diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h -index 29f9862..678ce4f 100644 ---- a/lib/mpi/longlong.h -+++ b/lib/mpi/longlong.h -@@ -19,6 +19,8 @@ - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. */ - -+#include -+ - /* You have to define the following before including this file: - * - * UWtype -- An unsigned type, default type for operations (typically a "word") -@@ -146,12 +148,6 @@ do { \ - : "1" ((USItype)(n1)), \ - "r" ((USItype)(n0)), \ - "r" ((USItype)(d))) -- --#define count_leading_zeros(count, x) \ -- __asm__ ("clz %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x))) --#define COUNT_LEADING_ZEROS_0 32 - #endif /* __a29k__ */ - - #if defined(__alpha) && W_TYPE_SIZE == 64 -@@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd(); - : "1" ((USItype)(nh)), \ - "0" ((USItype)(nl)), \ - "g" ((USItype)(d))) --#define count_leading_zeros(count, x) \ -- __asm__ ("bsch/1 %1,%0" \ -- : "=g" (count) \ -- : "g" ((USItype)(x)), \ -- "0" ((USItype)0)) - #endif - - /*************************************** -@@ -354,27 +345,6 @@ do { USItype __r; \ - } while (0) - extern USItype __udiv_qrnnd(); - #endif /* LONGLONG_STANDALONE */ --#define count_leading_zeros(count, x) \ --do { \ -- USItype __tmp; \ -- __asm__ ( \ -- "ldi 1,%0\n" \ -- "extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ -- "extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n" \ -- "ldo 16(%0),%0 ; Yes. Perform add.\n" \ -- "extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ -- "extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n" \ -- "ldo 8(%0),%0 ; Yes. Perform add.\n" \ -- "extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ -- "extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n" \ -- "ldo 4(%0),%0 ; Yes. Perform add.\n" \ -- "extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ -- "extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n" \ -- "ldo 2(%0),%0 ; Yes. Perform add.\n" \ -- "extru %1,30,1,%1 ; Extract bit 1.\n" \ -- "sub %0,%1,%0 ; Subtract it. " \ -- : "=r" (count), "=r" (__tmp) : "1" (x)); \ --} while (0) - #endif /* hppa */ - - /*************************************** -@@ -457,15 +427,6 @@ do { \ - : "0" ((USItype)(n0)), \ - "1" ((USItype)(n1)), \ - "rm" ((USItype)(d))) --#define count_leading_zeros(count, x) \ --do { \ -- USItype __cbtmp; \ -- __asm__ ("bsrl %1,%0" \ -- : "=r" (__cbtmp) : "rm" ((USItype)(x))); \ -- (count) = __cbtmp ^ 31; \ --} while (0) --#define count_trailing_zeros(count, x) \ -- __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) - #ifndef UMUL_TIME - #define UMUL_TIME 40 - #endif -@@ -536,15 +497,6 @@ do { \ - "dI" ((USItype)(d))); \ - (r) = __rq.__i.__l; (q) = __rq.__i.__h; \ - } while (0) --#define count_leading_zeros(count, x) \ --do { \ -- USItype __cbtmp; \ -- __asm__ ("scanbit %1,%0" \ -- : "=r" (__cbtmp) \ -- : "r" ((USItype)(x))); \ -- (count) = __cbtmp ^ 31; \ --} while (0) --#define COUNT_LEADING_ZEROS_0 (-32) /* sic */ - #if defined(__i960mx) /* what is the proper symbol to test??? */ - #define rshift_rhlc(r, h, l, c) \ - do { \ -@@ -603,11 +555,6 @@ do { \ - : "0" ((USItype)(n0)), \ - "1" ((USItype)(n1)), \ - "dmi" ((USItype)(d))) --#define count_leading_zeros(count, x) \ -- __asm__ ("bfffo %1{%b2:%b2},%0" \ -- : "=d" ((USItype)(count)) \ -- : "od" ((USItype)(x)), "n" (0)) --#define COUNT_LEADING_ZEROS_0 32 - #else /* not mc68020 */ - #define umul_ppmm(xh, xl, a, b) \ - do { USItype __umul_tmp1, __umul_tmp2; \ -@@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \ - "rJ" ((USItype)(bh)), \ - "rJ" ((USItype)(al)), \ - "rJ" ((USItype)(bl))) --#define count_leading_zeros(count, x) \ --do { \ -- USItype __cbtmp; \ -- __asm__ ("ff1 %0,%1" \ -- : "=r" (__cbtmp) \ -- : "r" ((USItype)(x))); \ -- (count) = __cbtmp ^ 31; \ --} while (0) --#define COUNT_LEADING_ZEROS_0 63 /* sic */ - #if defined(__m88110__) - #define umul_ppmm(wh, wl, u, v) \ - do { \ -@@ -779,12 +717,6 @@ do { \ - : "0" (__xx.__ll), \ - "g" ((USItype)(d))); \ - (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) --#define count_trailing_zeros(count, x) \ --do { \ -- __asm__("ffsd %2,%0" \ -- : "=r"((USItype) (count)) \ -- : "0"((USItype) 0), "r"((USItype) (x))); \ -- } while (0) - #endif /* __ns32000__ */ - - /*************************************** -@@ -855,11 +787,6 @@ do { \ - "rI" ((USItype)(al)), \ - "r" ((USItype)(bl))); \ - } while (0) --#define count_leading_zeros(count, x) \ -- __asm__ ("{cntlz|cntlzw} %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x))) --#define COUNT_LEADING_ZEROS_0 32 - #if defined(_ARCH_PPC) - #define umul_ppmm(ph, pl, m0, m1) \ - do { \ -@@ -1001,19 +928,6 @@ do { \ - } while (0) - #define UMUL_TIME 20 - #define UDIV_TIME 200 --#define count_leading_zeros(count, x) \ --do { \ -- if ((x) >= 0x10000) \ -- __asm__ ("clz %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x) >> 16)); \ -- else { \ -- __asm__ ("clz %0,%1" \ -- : "=r" ((USItype)(count)) \ -- : "r" ((USItype)(x))); \ -- (count) += 16; \ -- } \ --} while (0) - #endif /* RT/ROMP */ - - /*************************************** -@@ -1142,13 +1056,6 @@ do { \ - "rI" ((USItype)(d)) \ - : "%g1" __AND_CLOBBER_CC) - #define UDIV_TIME 37 --#define count_leading_zeros(count, x) \ -- __asm__ ("scan %1,0,%0" \ -- : "=r" ((USItype)(x)) \ -- : "r" ((USItype)(count))) --/* Early sparclites return 63 for an argument of 0, but they warn that future -- implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 -- undefined. */ - #endif /* __sparclite__ */ - #endif /* __sparc_v8__ */ - /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */ -@@ -1454,47 +1361,6 @@ do { \ - #define udiv_qrnnd __udiv_qrnnd_c - #endif - --#undef count_leading_zeros --#if !defined(count_leading_zeros) -- extern --#ifdef __STDC__ -- const --#endif -- unsigned char __clz_tab[]; --#define count_leading_zeros(count, x) \ --do { \ -- UWtype __xr = (x); \ -- UWtype __a; \ -- \ -- if (W_TYPE_SIZE <= 32) { \ -- __a = __xr < ((UWtype) 1 << 2*__BITS4) \ -- ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \ -- : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ -- } \ -- else { \ -- for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ -- if (((__xr >> __a) & 0xff) != 0) \ -- break; \ -- } \ -- \ -- (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ --} while (0) -- /* This version gives a well-defined value for zero. */ --#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE --#endif -- --#if !defined(count_trailing_zeros) --/* Define count_trailing_zeros using count_leading_zeros. The latter might be -- defined in asm, but if it is not, the C version above is good enough. */ --#define count_trailing_zeros(count, x) \ --do { \ -- UWtype __ctz_x = (x); \ -- UWtype __ctz_c; \ -- count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \ -- (count) = W_TYPE_SIZE - 1 - __ctz_c; \ --} while (0) --#endif -- - #ifndef UDIV_NEEDS_NORMALIZATION - #define UDIV_NEEDS_NORMALIZATION 0 - #endif -diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c -index 0c50536..3fc00bf 100644 ---- a/lib/mpi/mpi-bit.c -+++ b/lib/mpi/mpi-bit.c -@@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a) - if (a->nlimbs) { - mpi_limb_t alimb = a->d[a->nlimbs - 1]; - if (alimb) -- count_leading_zeros(n, alimb); -+ n = count_leading_zeros(alimb); - else - n = BITS_PER_MPI_LIMB; - n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB; -diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c -index f68cbbb..51f105c 100644 ---- a/lib/mpi/mpi-div.c -+++ b/lib/mpi/mpi-div.c -@@ -217,7 +217,7 @@ int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den) - } else /* Put quotient at top of remainder. */ - qp = rp + dsize; - -- count_leading_zeros(normalization_steps, dp[dsize - 1]); -+ normalization_steps = count_leading_zeros(dp[dsize - 1]); - - /* Normalize the denominator, i.e. make its most significant bit set by - * shifting it NORMALIZATION_STEPS bits to the left. Also shift the -diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c -index 67f3e79..5464c87 100644 ---- a/lib/mpi/mpi-pow.c -+++ b/lib/mpi/mpi-pow.c -@@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) - mp = mp_marker = mpi_alloc_limb_space(msize); - if (!mp) - goto enomem; -- count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); -+ mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]); - if (mod_shift_cnt) - mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); - else -@@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) - - i = esize - 1; - e = ep[i]; -- count_leading_zeros(c, e); -+ c = count_leading_zeros(e); - e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ - c = BITS_PER_MPI_LIMB - 1 - c; - -diff --git a/lib/mpi/mpi-scan.c b/lib/mpi/mpi-scan.c -index b2da5ad..58556b5 100644 ---- a/lib/mpi/mpi-scan.c -+++ b/lib/mpi/mpi-scan.c -@@ -125,7 +125,7 @@ unsigned mpi_trailing_zeros(const MPI a) - unsigned nn; - mpi_limb_t alimb = a->d[n]; - -- count_trailing_zeros(nn, alimb); -+ nn = count_trailing_zeros(alimb); - count += nn; - break; - } -diff --git a/lib/mpi/mpih-div.c b/lib/mpi/mpih-div.c -index cde1aae..d6483792 100644 ---- a/lib/mpi/mpih-div.c -+++ b/lib/mpi/mpih-div.c -@@ -65,7 +65,7 @@ mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, - && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { - int normalization_steps; - -- count_leading_zeros(normalization_steps, divisor_limb); -+ normalization_steps = count_leading_zeros(divisor_limb); - if (normalization_steps) { - mpi_limb_t divisor_limb_inverted; - -@@ -142,7 +142,7 @@ mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, - if (UDIV_NEEDS_NORMALIZATION) { - int normalization_steps; - -- count_leading_zeros(normalization_steps, divisor_limb); -+ normalization_steps = count_leading_zeros(divisor_limb); - if (normalization_steps) { - divisor_limb <<= normalization_steps; - -@@ -421,7 +421,7 @@ mpihelp_divmod_1(mpi_ptr_t quot_ptr, - && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { - int normalization_steps; - -- count_leading_zeros(normalization_steps, divisor_limb); -+ normalization_steps = count_leading_zeros(divisor_limb); - if (normalization_steps) { - mpi_limb_t divisor_limb_inverted; - -@@ -496,7 +496,7 @@ mpihelp_divmod_1(mpi_ptr_t quot_ptr, - if (UDIV_NEEDS_NORMALIZATION) { - int normalization_steps; - -- count_leading_zeros(normalization_steps, divisor_limb); -+ normalization_steps = count_leading_zeros(divisor_limb); - if (normalization_steps) { - divisor_limb <<= normalization_steps; - --- -1.7.10.4 - - -From 7611bb8e543cb2255c69bfb5edd85ed0d2cdb9e9 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 13:12:20 +0100 -Subject: [PATCH 02/27] 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. - -The key type is "crypto" and can provide access to a variety of cryptographic -algorithms. - -Signed-off-by: David Howells ---- - Documentation/security/keys-crypto.txt | 181 +++++++++++++++++++++++++ - include/keys/crypto-subtype.h | 56 ++++++++ - include/keys/crypto-type.h | 25 ++++ - 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/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 -index 0000000..97dee80 ---- /dev/null -+++ b/Documentation/security/keys-crypto.txt -@@ -0,0 +1,181 @@ -+ ====================== -+ CRYPTOGRAPHIC KEY TYPE -+ ====================== -+ -+Contents: -+ -+ - Overview. -+ - Key identification. -+ - Accessing crypto keys. -+ - Implementing crypto parsers. -+ - Implementing crypto subtypes. -+ -+ -+======== -+OVERVIEW -+======== -+ -+The "crypto" key type is designed to be a container for cryptographic keys, -+without imposing any particular restrictions on the form of the cryptography or -+the key. -+ -+The crypto key is given a subtype that defines what sort of data is associated -+with the key and provides operations to describe and destroy it. However, no -+requirement is made that the key data actually be loaded into the key. -+ -+The crypto key also has a number of data parsers registered with it. The data -+parsers are responsible for extracing information the blobs of data passed to -+the instantiator function. The first data parser that recognises the blob gets -+to set the subtype of the key and define the operations that can be done on -+that key. -+ -+Completely in-kernel key retention and operation subtypes and parsers can be -+defined, but it would also be possible to provide access to cryptographic -+hardware (such as a TPM) that might be used to both retain the relevant key and -+perform operations using that key. In such a case, the crypto key would then -+merely be an interface to the TPM driver. -+ -+ -+================== -+KEY IDENTIFICATION -+================== -+ -+Because the identity of a key is not necessarily known and may not be easily -+calculated when a crypto key is allocated, it may not be a simple matter to set -+a key description to something that's useful for determining whether this is -+the key you're looking for. Furthermore, it may be necessary to perform a -+partial match upon the key identity. -+ -+To help with this, when a key is loaded, the parser calculates the key -+fingerprint and stores a copy in the key structure. -+ -+The crypto key type's key matching function then performs more checks than just -+the straightforward comparison of the description with the criterion string: -+ -+ (1) If the criterion string is of the form "id:" then the match -+ function will examine a key's fingerprint to see if the hex digits given -+ after the "id:" match the tail. For instance: -+ -+ keyctl search @s crypto id:5acc2142 -+ -+ will match a key with fingerprint: -+ -+ 1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142 -+ -+ (2) If the criterion string is of the form ":" then the -+ match will match the ID as in (1), but with the added restriction that -+ only keys of the specified subtype (e.g. dsa or rsa) will be matched. For -+ instance: -+ -+ keyctl search @s crypto dsa:5acc2142 -+ -+Looking in /proc/keys, the last 8 hex digits of the key fingerprint are -+displayed, along with the subtype: -+ -+ 1a39e171 I----- 1 perm 3f010000 0 0 crypto modsign.0: DSA 5acc2142 [] -+ -+ -+===================== -+ACCESSING CRYPTO KEYS -+===================== -+ -+To access crypto keys from within the kernel, the following inclusion is -+required: -+ -+ #include -+ -+This gives access to the key type: -+ -+ struct key_type key_type_crypto; -+ -+ -+=========================== -+IMPLEMENTING CRYPTO PARSERS -+=========================== -+ -+The crypto key type keeps a list of registered data parsers. An example of -+such a parser is one that parses OpenPGP packet formatted data [RFC 4880]. -+ -+During key instantiation each parser in the list is tried until one doesn't -+return -EBADMSG. -+ -+The parser definition structure looks like the following: -+ -+ struct crypto_key_parser { -+ struct module *owner; -+ const char *name; -+ -+ int (*instantiate)(struct key *key, -+ const void *data, size_t datalen); -+ }; -+ -+The owner and name fields should be set to the owning module and the name of -+the parser. -+ -+There are a number of operations defined by the parser. They are all optional, -+but it is expected that at least one will be defined. -+ -+ (1) instantiate(). -+ -+ The arguments are the same as for the instantiate function in the key -+ type. 'key' is the crypto key being instantiated; data and datalen are -+ the instantiation data, presumably containing cryptographic key data, and -+ the length of that data. -+ -+ If the data format is not recognised, -EBADMSG should be returned. If it -+ is recognised, but the key cannot for some reason be set up, some other -+ negative error code should be returned. -+ -+ If the key can be successfully set up, then key->payload should be set to -+ point to the retained data, key->type_data.p[0] should be set to point to -+ the subtype chosen and key->type_data.p[1] should be set to point to a -+ copy of the key's identity string and 0 should be returned. -+ -+ The key's identity string may be partially matched upon. For a public-key -+ algorithm such as RSA and DSA this will likely be a printable hex version -+ of the key's fingerprint. -+ -+Functions are provided to register and unregister parsers: -+ -+ int register_crypto_key_parser(struct crypto_key_parser *parser); -+ void unregister_crypto_key_parser(struct crypto_key_parser *subtype); -+ -+Parsers may not have the same name. The names are only used for displaying in -+debugging messages. -+ -+ -+============================ -+IMPLEMENTING CRYPTO SUBTYPES -+============================ -+ -+The parser selects the appropriate subtype directly and sets it on the key; the -+crypto key then retains a reference on the subtype module (which means the -+parser can be removed thereafter). -+ -+The subtype definition structure looks like the following: -+ -+ struct crypto_key_subtype { -+ struct module *owner; -+ const char *name; -+ -+ void (*describe)(const struct key *key, struct seq_file *m); -+ void (*destroy)(void *payload); -+ }; -+ -+The owner and name fields should be set to the owning module and the name of -+the subtype. -+ -+There are a number of operations defined by the subtype: -+ -+ (1) describe(). -+ -+ Mandatory. This allows the subtype to display something in /proc/keys -+ against the key. For instance the name of the public key algorithm type -+ could be displayed. The key type will display the tail of the key -+ identity string after this. -+ -+ (2) destroy(). -+ -+ Mandatory. This should free the memory associated with the key. The -+ crypto key will look after freeing the fingerprint and releasing the -+ reference on the subtype module. -diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h -new file mode 100644 -index 0000000..fa87555 ---- /dev/null -+++ b/include/keys/crypto-subtype.h -@@ -0,0 +1,56 @@ -+/* Cryptographic key subtype -+ * -+ * 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. -+ * -+ * See Documentation/security/keys-crypto.txt -+ */ -+ -+#ifndef _KEYS_CRYPTO_SUBTYPE_H -+#define _KEYS_CRYPTO_SUBTYPE_H -+ -+#include -+#include -+ -+extern struct key_type key_type_crypto; -+ -+/* -+ * Keys of this type declare a subtype that indicates the handlers and -+ * capabilities. -+ */ -+struct crypto_key_subtype { -+ struct module *owner; -+ const char *name; -+ unsigned short name_len; /* length of name */ -+ -+ void (*describe)(const struct key *key, struct seq_file *m); -+ -+ void (*destroy)(void *payload); -+}; -+ -+/* -+ * Data parser. Called during instantiation and signature verification -+ * initiation. -+ */ -+struct crypto_key_parser { -+ struct list_head link; -+ struct module *owner; -+ const char *name; -+ -+ /* Attempt to instantiate a key from the data blob passed to add_key() -+ * or keyctl_instantiate(). -+ * -+ * Return EBADMSG if not recognised. -+ */ -+ int (*instantiate)(struct key *key, const void *data, size_t datalen); -+}; -+ -+extern int register_crypto_key_parser(struct crypto_key_parser *); -+extern void unregister_crypto_key_parser(struct crypto_key_parser *); -+ -+#endif /* _KEYS_CRYPTO_SUBTYPE_H */ -diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h -new file mode 100644 -index 0000000..47c00c7 ---- /dev/null -+++ b/include/keys/crypto-type.h -@@ -0,0 +1,25 @@ -+/* Cryptographic key type interface -+ * -+ * 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. -+ * -+ * See Documentation/security/keys-crypto.txt -+ */ -+ -+#ifndef _KEYS_CRYPTO_TYPE_H -+#define _KEYS_CRYPTO_TYPE_H -+ -+#include -+ -+extern struct key_type key_type_crypto; -+ -+/* -+ * The payload is at the discretion of the subtype. -+ */ -+ -+#endif /* _KEYS_CRYPTO_TYPE_H */ -diff --git a/security/keys/Kconfig b/security/keys/Kconfig -index a90d6d3..992fe52 100644 ---- a/security/keys/Kconfig -+++ b/security/keys/Kconfig -@@ -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 -+ help -+ 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/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/crypto_keys.h b/security/keys/crypto/crypto_keys.h -new file mode 100644 -index 0000000..a339ce0 ---- /dev/null -+++ b/security/keys/crypto/crypto_keys.h -@@ -0,0 +1,28 @@ -+/* Internal crypto type stuff -+ * -+ * 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. -+ */ -+ -+static inline -+struct crypto_key_subtype *crypto_key_subtype(const struct key *key) -+{ -+ return key->type_data.p[0]; -+} -+ -+static inline char *crypto_key_id(const struct key *key) -+{ -+ return key->type_data.p[1]; -+} -+ -+ -+/* -+ * crypto_type.c -+ */ -+extern struct list_head crypto_key_parsers; -+extern struct rw_semaphore crypto_key_parsers_sem; -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/crypto_type.c -@@ -0,0 +1,228 @@ -+/* Cryptographic key type -+ * -+ * 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. -+ * -+ * See Documentation/security/keys-crypto.txt -+ */ -+#include -+#include -+#include -+#include -+#include "crypto_keys.h" -+ -+MODULE_LICENSE("GPL"); -+ -+LIST_HEAD(crypto_key_parsers); -+DECLARE_RWSEM(crypto_key_parsers_sem); -+ -+/* -+ * Match crypto_keys on (part of) their name -+ * We have some shorthand methods for matching keys. We allow: -+ * -+ * "" - request a key by description -+ * "id:" - request a key matching the ID -+ * ":" - request a key of a subtype -+ */ -+static int crypto_key_match(const struct key *key, const void *description) -+{ -+ const struct crypto_key_subtype *subtype = crypto_key_subtype(key); -+ const char *spec = description; -+ const char *id, *kid; -+ ptrdiff_t speclen; -+ size_t idlen, kidlen; -+ -+ if (!subtype || !spec || !*spec) -+ return 0; -+ -+ /* See if the full key description matches as is */ -+ if (key->description && strcmp(key->description, description) == 0) -+ return 1; -+ -+ /* All tests from here on break the criterion description into a -+ * specifier, a colon and then an identifier. -+ */ -+ id = strchr(spec, ':'); -+ if (!id) -+ return 0; -+ -+ speclen = id - spec; -+ id++; -+ -+ /* Anything after here requires a partial match on the ID string */ -+ kid = crypto_key_id(key); -+ if (!kid) -+ return 0; -+ -+ idlen = strlen(id); -+ kidlen = strlen(kid); -+ if (idlen > kidlen) -+ return 0; -+ -+ kid += kidlen - idlen; -+ if (strcasecmp(id, kid) != 0) -+ return 0; -+ -+ if (speclen == 2 && -+ memcmp(spec, "id", 2) == 0) -+ return 1; -+ -+ if (speclen == subtype->name_len && -+ memcmp(spec, subtype->name, speclen) == 0) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * Describe the crypto key -+ */ -+static void crypto_key_describe(const struct key *key, struct seq_file *m) -+{ -+ const struct crypto_key_subtype *subtype = crypto_key_subtype(key); -+ const char *kid = crypto_key_id(key); -+ size_t n; -+ -+ seq_puts(m, key->description); -+ -+ if (subtype) { -+ seq_puts(m, ": "); -+ subtype->describe(key, m); -+ -+ if (kid) { -+ seq_putc(m, ' '); -+ n = strlen(kid); -+ if (n <= 8) -+ seq_puts(m, kid); -+ else -+ seq_puts(m, kid + n - 8); -+ } -+ -+ seq_puts(m, " ["); -+ /* put something here to indicate the key's capabilities */ -+ seq_putc(m, ']'); -+ } -+} -+ -+/* -+ * Instantiate a crypto_key defined key -+ */ -+static int crypto_key_instantiate(struct key *key, -+ const void *data, size_t datalen) -+{ -+ struct crypto_key_parser *parser; -+ int ret; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ if (datalen == 0) -+ return -EINVAL; -+ -+ down_read(&crypto_key_parsers_sem); -+ -+ ret = -EBADMSG; -+ list_for_each_entry(parser, &crypto_key_parsers, link) { -+ pr_debug("Trying parser '%s'\n", parser->name); -+ -+ ret = parser->instantiate(key, data, datalen); -+ if (ret != -EBADMSG) { -+ pr_debug("Parser recognised the format (ret %d)\n", -+ ret); -+ break; -+ } -+ } -+ -+ up_read(&crypto_key_parsers_sem); -+ pr_devel("<==%s() = %d\n", __func__, ret); -+ return ret; -+} -+ -+/* -+ * dispose of the data dangling from the corpse of a crypto key -+ */ -+static void crypto_key_destroy(struct key *key) -+{ -+ struct crypto_key_subtype *subtype = crypto_key_subtype(key); -+ if (subtype) { -+ subtype->destroy(key->payload.data); -+ module_put(subtype->owner); -+ key->type_data.p[0] = NULL; -+ } -+ kfree(key->type_data.p[1]); -+ key->type_data.p[1] = NULL; -+} -+ -+struct key_type key_type_crypto = { -+ .name = "crypto", -+ .instantiate = crypto_key_instantiate, -+ .match = crypto_key_match, -+ .destroy = crypto_key_destroy, -+ .describe = crypto_key_describe, -+}; -+EXPORT_SYMBOL_GPL(key_type_crypto); -+ -+/** -+ * register_crypto_key_parser - Register a crypto key blob parser -+ * @parser: The parser to register -+ */ -+int register_crypto_key_parser(struct crypto_key_parser *parser) -+{ -+ struct crypto_key_parser *cursor; -+ int ret; -+ -+ down_write(&crypto_key_parsers_sem); -+ -+ list_for_each_entry(cursor, &crypto_key_parsers, link) { -+ if (strcmp(cursor->name, parser->name) == 0) { -+ pr_err("Crypto key parser '%s' already registered\n", -+ parser->name); -+ ret = -EEXIST; -+ goto out; -+ } -+ } -+ -+ list_add_tail(&parser->link, &crypto_key_parsers); -+ -+ pr_notice("Crypto key parser '%s' registered\n", parser->name); -+ ret = 0; -+ -+out: -+ up_write(&crypto_key_parsers_sem); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(register_crypto_key_parser); -+ -+/** -+ * unregister_crypto_key_parser - Unregister a crypto key blob parser -+ * @parser: The parser to unregister -+ */ -+void unregister_crypto_key_parser(struct crypto_key_parser *parser) -+{ -+ down_write(&crypto_key_parsers_sem); -+ list_del(&parser->link); -+ up_write(&crypto_key_parsers_sem); -+ -+ pr_notice("Crypto key parser '%s' unregistered\n", parser->name); -+} -+EXPORT_SYMBOL_GPL(unregister_crypto_key_parser); -+ -+/* -+ * Module stuff -+ */ -+static int __init crypto_key_init(void) -+{ -+ return register_key_type(&key_type_crypto); -+} -+ -+static void __exit crypto_key_cleanup(void) -+{ -+ unregister_key_type(&key_type_crypto); -+} -+ -+module_init(crypto_key_init); -+module_exit(crypto_key_cleanup); --- -1.7.10.4 - - -From 23d7c6d8927420846af94823a90de1c24120bfea Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 13:12:20 +0100 -Subject: [PATCH 03/27] 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. - -This adds four routines: - - (1) struct crypto_key_verify_context * - verify_sig_begin(struct key *keyring, const void *sig, size_t siglen); - - This sets up a verification context for the given signature using - information in that signature to select a key from the specified keyring - and to request a hash algorithm from the crypto layer. - - (2) int verify_sig_add_data(struct crypto_key_verify_context *ctx, - const void *data, size_t datalen); - - Incrementally supply data to be signed. May be called multiple times. - - (3) int verify_sig_end(struct crypto_key_verify_context *ctx, - const void *sig, size_t siglen); - - Complete the verification process and return the result. -EKEYREJECTED - will indicate that the verification failed and 0 will indicate success. - Other errors are also possible. - - (4) void verify_sig_cancel(struct crypto_key_verify_context *ctx); - - Cancel the verification process. - -Signed-off-by: David Howells ---- - Documentation/security/keys-crypto.txt | 101 ++++++++++++++++++++++++++++ - include/keys/crypto-subtype.h | 21 ++++++ - include/keys/crypto-type.h | 9 +++ - security/keys/crypto/Makefile | 2 +- - security/keys/crypto/crypto_verify.c | 112 ++++++++++++++++++++++++++++++++ - 5 files changed, 244 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 ---- a/Documentation/security/keys-crypto.txt -+++ b/Documentation/security/keys-crypto.txt -@@ -7,6 +7,7 @@ Contents: - - Overview. - - Key identification. - - Accessing crypto keys. -+ - Signature verification. - - Implementing crypto parsers. - - Implementing crypto subtypes. - -@@ -89,6 +90,65 @@ This gives access to the key type: - struct key_type key_type_crypto; - - -+SIGNATURE VERIFICATION -+---------------------- -+ -+The four operations that can perform cryptographic signature verification, -+using one of a set of keys to provide the public key: -+ -+ (1) Begin verification procedure. -+ -+ struct crypto_key_verify_context * -+ verify_sig_begin(struct key *keyring, const void *sig, size_t siglen); -+ -+ This function sets up a verification context from the information in the -+ signature and looks for a suitable key in the keyring. The signature blob -+ must be presented again at the end of the procedure. The keys will be -+ checked against parameters in the signature, and if the matching one is -+ not found then -ENOKEY will be returned. -+ -+ The hashing algorithm, if such a thing applies, will be determined from -+ information in the signature and the appropriate crypto module will be -+ used. -ENOPKG will be returned if the hash algorithm is unavailable. -+ -+ The return value is an opaque pointer to be passed to the other functions, -+ or a negative error code. -+ -+ (2) Indicate data to be verified. -+ -+ int verify_sig_add_data(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen); -+ -+ This function is used to shovel data to the verification procedure so that -+ it can load it into the hash, pass it to hardware or whatever is -+ appropriate for the algorithm being employed. -+ -+ The data is not canonicalised for the document type specified in the -+ signature. The caller must do that. -+ -+ It will return 0 if successful and a negative error code if not. -+ -+ (3) Complete the verification process. -+ -+ int verify_sig_end(struct crypto_key_verify_context *ctx, -+ const void *sig, size_t siglen); -+ -+ This function performs the actual signature verification step and cleans -+ up the resources allocated at the beginning. The signature must be -+ presented again as some of the data therein may need to be added to the -+ internal hash. -+ -+ It will return -EKEYREJECTED if the signature didn't match, 0 if -+ successful and may return other errors as appropriate. -+ -+ (4) Cancel the verification process. -+ -+ void verify_sig_cancel(struct crypto_key_verify_context *ctx); -+ -+ This function cleans up the resources allocated at the beginning. This is -+ not necessary if verify_sig_end() was called. -+ -+ - =========================== - IMPLEMENTING CRYPTO PARSERS - =========================== -@@ -96,6 +156,7 @@ IMPLEMENTING CRYPTO PARSERS - The crypto key type keeps a list of registered data parsers. An example of - such a parser is one that parses OpenPGP packet formatted data [RFC 4880]. - -+ - During key instantiation each parser in the list is tried until one doesn't - return -EBADMSG. - -@@ -107,6 +168,8 @@ The parser definition structure looks like the following: - - int (*instantiate)(struct key *key, - const void *data, size_t datalen); -+ struct crypto_key_verify_context *(*verify_sig_begin)( -+ struct key *keyring, const u8 *sig, size_t siglen); - }; - - The owner and name fields should be set to the owning module and the name of -@@ -135,6 +198,44 @@ but it is expected that at least one will be defined. - algorithm such as RSA and DSA this will likely be a printable hex version - of the key's fingerprint. - -+ (2) verify_sig_begin(). -+ -+ This is similar in concept to the instantiate() function, except that it -+ is given a signature blob to parse rather than a key data blob. -+ -+ If the data format is not recognised, -EBADMSG should be returned. If it -+ is recognised, but the signature verification process cannot for some -+ reason be set up, some other negative error code should be returned. -+ -ENOKEY should be used to indicate that no matching key is available and -+ -ENOPKG should be returned if the hash algorithm or the verification -+ algorithm are unavailable. -+ -+ If successful, the parser should allocate a verification context and embed -+ the following struct in it: -+ -+ struct crypto_key_verify_context { -+ struct key *key; -+ int (*add_data)(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen); -+ int (*end)(struct crypto_key_verify_context *ctx, -+ const u8 *sig, size_t siglen); -+ void (*cancel)(struct crypto_key_verify_context *ctx); -+ }; -+ -+ and return a pointer to this to the caller, who will then pass it to the -+ verification operation wrappers described in the "Signature Verification" -+ section. The three operation pointers here correspond exactly to those -+ wrappers and are all mandatory. container_of() should be used to retrieve -+ the actual context. -+ -+ Note that the crypto key type retains a reference on the parser module for -+ the lifetime of this context, though the operation pointers need not point -+ into this module. -+ -+ The parser should also record a pointer to the key selected and take a -+ reference on that key with key_get(). -+ -+ - Functions are provided to register and unregister parsers: - - int register_crypto_key_parser(struct crypto_key_parser *parser); -diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h -index fa87555..f2b927a 100644 ---- a/include/keys/crypto-subtype.h -+++ b/include/keys/crypto-subtype.h -@@ -20,6 +20,20 @@ - extern struct key_type key_type_crypto; - - /* -+ * Context base for signature verification methods. Allocated by the subtype -+ * and presumably embedded in something appropriate. -+ */ -+struct crypto_key_verify_context { -+ struct key *key; -+ struct crypto_key_parser *parser; -+ int (*add_data)(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen); -+ int (*end)(struct crypto_key_verify_context *ctx, -+ const u8 *sig, size_t siglen); -+ void (*cancel)(struct crypto_key_verify_context *ctx); -+}; -+ -+/* - * Keys of this type declare a subtype that indicates the handlers and - * capabilities. - */ -@@ -48,6 +62,13 @@ struct crypto_key_parser { - * Return EBADMSG if not recognised. - */ - int (*instantiate)(struct key *key, const void *data, size_t datalen); -+ -+ /* Attempt to recognise a signature blob and find a matching key. -+ * -+ * Return EBADMSG if not recognised. -+ */ -+ struct crypto_key_verify_context *(*verify_sig_begin)( -+ struct key *keyring, const u8 *sig, size_t siglen); - }; - - extern int register_crypto_key_parser(struct crypto_key_parser *); -diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h -index 47c00c7..6b93366 100644 ---- a/include/keys/crypto-type.h -+++ b/include/keys/crypto-type.h -@@ -18,6 +18,15 @@ - - extern struct key_type key_type_crypto; - -+struct crypto_key_verify_context; -+extern struct crypto_key_verify_context *verify_sig_begin( -+ struct key *key, const void *sig, size_t siglen); -+extern int verify_sig_add_data(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen); -+extern int verify_sig_end(struct crypto_key_verify_context *ctx, -+ const void *sig, size_t siglen); -+extern void verify_sig_cancel(struct crypto_key_verify_context *ctx); -+ - /* - * The payload is at the discretion of the subtype. - */ -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/crypto_verify.c b/security/keys/crypto/crypto_verify.c -new file mode 100644 -index 0000000..3f2964b ---- /dev/null -+++ b/security/keys/crypto/crypto_verify.c -@@ -0,0 +1,112 @@ -+/* Signature verification with a crypto key -+ * -+ * 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. -+ * -+ * See Documentation/security/keys-crypto.txt -+ */ -+ -+#include -+#include -+#include -+#include "crypto_keys.h" -+ -+/** -+ * verify_sig_begin - Initiate the use of a crypto key to verify a signature -+ * @keyring: The public keys to verify against -+ * @sig: The signature data -+ * @siglen: The signature length -+ * -+ * Returns a context or an error. -+ */ -+struct crypto_key_verify_context *verify_sig_begin( -+ struct key *keyring, const void *sig, size_t siglen) -+{ -+ struct crypto_key_verify_context *ret; -+ struct crypto_key_parser *parser; -+ -+ pr_devel("==>%s()\n", __func__); -+ -+ if (siglen == 0 || !sig) -+ return ERR_PTR(-EINVAL); -+ -+ down_read(&crypto_key_parsers_sem); -+ -+ ret = ERR_PTR(-EBADMSG); -+ list_for_each_entry(parser, &crypto_key_parsers, link) { -+ if (parser->verify_sig_begin) { -+ if (!try_module_get(parser->owner)) -+ continue; -+ -+ pr_debug("Trying parser '%s'\n", parser->name); -+ -+ ret = parser->verify_sig_begin(keyring, sig, siglen); -+ if (IS_ERR(ret)) -+ module_put(parser->owner); -+ else -+ ret->parser = parser; -+ if (ret != ERR_PTR(-EBADMSG)) { -+ pr_debug("Parser recognised the format" -+ " (ret %ld)\n", -+ PTR_ERR(ret)); -+ break; -+ } -+ } -+ } -+ -+ up_read(&crypto_key_parsers_sem); -+ pr_devel("<==%s() = %p\n", __func__, ret); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(verify_sig_begin); -+ -+/** -+ * verify_sig_add_data - Incrementally provide data to be verified -+ * @ctx: The context from verify_sig_begin() -+ * @data: Data -+ * @datalen: The amount of @data -+ * -+ * This may be called multiple times. -+ */ -+int verify_sig_add_data(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen) -+{ -+ return ctx->add_data(ctx, data, datalen); -+} -+EXPORT_SYMBOL_GPL(verify_sig_add_data); -+ -+/** -+ * verify_sig_end - Finalise signature verification and return result -+ * @ctx: The context from verify_sig_begin() -+ * @sig: The signature data -+ * @siglen: The signature length -+ */ -+int verify_sig_end(struct crypto_key_verify_context *ctx, -+ const void *sig, size_t siglen) -+{ -+ struct crypto_key_parser *parser = ctx->parser; -+ int ret; -+ -+ ret = ctx->end(ctx, sig, siglen); -+ module_put(parser->owner); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(verify_sig_end); -+ -+/** -+ * verify_sig_end - Cancel signature verification -+ * @ctx: The context from verify_sig_begin() -+ */ -+void verify_sig_cancel(struct crypto_key_verify_context *ctx) -+{ -+ struct crypto_key_parser *parser = ctx->parser; -+ -+ ctx->cancel(ctx); -+ module_put(parser->owner); -+} -+EXPORT_SYMBOL_GPL(verify_sig_cancel); --- -1.7.10.4 - - -From 2fd136dec4682c1fa2609a7a94cf0353c334615c Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 13:12:20 +0100 -Subject: [PATCH 04/27] 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 ---- - 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. -+ -+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/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 -+ -+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/crypto/public_key.c -@@ -0,0 +1,55 @@ -+/* Asymmetric public key crypto subtype -+ * -+ * 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. -+ */ -+ -+#define pr_fmt(fmt) "PKEY: "fmt -+#include -+#include -+#include "public_key.h" -+ -+MODULE_LICENSE("GPL"); -+ -+/* -+ * Provide a part of a description of the key for /proc/keys. -+ */ -+static void public_key_describe(const struct key *crypto_key, -+ struct seq_file *m) -+{ -+ struct public_key *key = crypto_key->payload.data; -+ -+ if (key) -+ seq_puts(m, key->algo->name); -+} -+ -+/* -+ * Destroy a public key algorithm key -+ */ -+static void public_key_destroy(void *payload) -+{ -+ struct public_key *key = payload; -+ int i; -+ -+ if (key) { -+ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) -+ mpi_free(key->mpi[i]); -+ kfree(key); -+ } -+} -+ -+/* -+ * Public key algorithm crypto key subtype -+ */ -+struct crypto_key_subtype public_key_crypto_key_subtype = { -+ .owner = THIS_MODULE, -+ .name = "public_key", -+ .describe = public_key_describe, -+ .destroy = public_key_destroy, -+}; -+EXPORT_SYMBOL_GPL(public_key_crypto_key_subtype); -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/crypto/public_key.h -@@ -0,0 +1,106 @@ -+/* Asymmetric public-key algorithm definitions -+ * -+ * 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. -+ */ -+ -+#ifndef _LINUX_PUBLIC_KEY_H -+#define _LINUX_PUBLIC_KEY_H -+ -+#include -+#include -+#include -+ -+struct public_key; -+struct public_key_signature; -+ -+enum pkey_hash_algo { -+ PKEY_HASH_MD5, -+ PKEY_HASH_SHA1, -+ PKEY_HASH_RIPE_MD_160, -+ PKEY_HASH_SHA256, -+ PKEY_HASH_SHA384, -+ PKEY_HASH_SHA512, -+ PKEY_HASH_SHA224, -+ PKEY_HASH__LAST -+}; -+ -+/* -+ * Public key type definition -+ */ -+struct public_key_algorithm { -+ const char *name; -+ u8 n_pub_mpi; /* Number of MPIs in public key */ -+ u8 n_sec_mpi; /* Number of MPIs in secret key */ -+ u8 n_sig_mpi; /* Number of MPIs in a signature */ -+ int (*verify)(const struct public_key *key, -+ const struct public_key_signature *sig); -+}; -+ -+/* -+ * Asymmetric public key data -+ */ -+struct public_key { -+ const struct public_key_algorithm *algo; -+ u8 capabilities; -+#define PKEY_CAN_ENCRYPT 0x01 -+#define PKEY_CAN_DECRYPT 0x02 -+#define PKEY_CAN_ENCDEC (PKEY_CAN_ENCRYPT | PKEY_CAN_DECRYPT) -+#define PKEY_CAN_SIGN 0x04 -+#define PKEY_CAN_VERIFY 0x08 -+#define PKEY_CAN_SIGVER (PKEY_CAN_SIGN | PKEY_CAN_VERIFY) -+ union { -+ MPI mpi[5]; -+ struct { -+ MPI p; /* DSA prime */ -+ MPI q; /* DSA group order */ -+ MPI g; /* DSA group generator */ -+ MPI y; /* DSA public-key value = g^x mod p */ -+ MPI x; /* DSA secret exponent (if present) */ -+ } dsa; -+ struct { -+ MPI n; /* RSA public modulus */ -+ MPI e; /* RSA public encryption exponent */ -+ MPI d; /* RSA secret encryption exponent (if present) */ -+ MPI p; /* RSA secret prime (if present) */ -+ MPI q; /* RSA secret prime (if present) */ -+ } rsa; -+ }; -+ -+ u8 key_id[8]; /* ID of this key pair */ -+ u8 key_id_size; /* Number of bytes in key_id */ -+}; -+ -+/* -+ * Asymmetric public key algorithm signature data -+ */ -+struct public_key_signature { -+ struct crypto_key_verify_context base; -+ u8 *digest; -+ enum pkey_hash_algo pkey_hash_algo : 8; -+ u8 signed_hash_msw[2]; -+ u8 digest_size; /* Number of bytes in digest */ -+ union { -+ MPI mpi[2]; -+ struct { -+ MPI s; /* m^d mod n */ -+ } rsa; -+ struct { -+ MPI r; -+ MPI s; -+ } dsa; -+ }; -+ struct shash_desc hash; /* This must go last! */ -+}; -+ -+extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( -+ struct key *crypto_key, const u8 *sigdata, size_t siglen); -+ -+extern struct crypto_key_subtype public_key_crypto_key_subtype; -+ -+#endif /* _LINUX_PUBLIC_KEY_H */ --- -1.7.10.4 - - -From ba785b97c90fc4403b2124dc2cecc842ba49be54 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 13:12:21 +0100 -Subject: [PATCH 05/27] KEYS: RSA: Add exports from MPILIB - -Export mpi_cmp() and mpi_cmp_ui() from the MPI library for use by RSA. - -Signed-off-by: David Howells ---- - lib/mpi/mpi-cmp.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c -index 914bc42..1871e7b 100644 ---- a/lib/mpi/mpi-cmp.c -+++ b/lib/mpi/mpi-cmp.c -@@ -39,6 +39,7 @@ int mpi_cmp_ui(MPI u, unsigned long v) - else - return -1; - } -+EXPORT_SYMBOL_GPL(mpi_cmp_ui); - - int mpi_cmp(MPI u, MPI v) - { -@@ -66,3 +67,4 @@ int mpi_cmp(MPI u, MPI v) - return 1; - return -1; - } -+EXPORT_SYMBOL_GPL(mpi_cmp); --- -1.7.10.4 - - -From 650edd748b92eea0622ecb26a5ee81c7b582d04c Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:15:36 +0100 -Subject: [PATCH 06/27] KEYS: RSA: Implement signature verification algorithm - [PKCS#1 / RFC3447] - -Implement RSA public key cryptography [PKCS#1 / RFC3447]. At this time, only -the signature verification algorithm is supported. This uses the asymmetric -public key subtype to hold its key data. - -Signed-off-by: David Howells ---- - security/keys/crypto/Kconfig | 7 + - security/keys/crypto/Makefile | 1 + - security/keys/crypto/crypto_rsa.c | 264 +++++++++++++++++++++++++++++++++++++ - security/keys/crypto/public_key.h | 2 + - 4 files changed, 274 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. -+ -+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/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 -diff --git a/security/keys/crypto/crypto_rsa.c b/security/keys/crypto/crypto_rsa.c -new file mode 100644 -index 0000000..845285c ---- /dev/null -+++ b/security/keys/crypto/crypto_rsa.c -@@ -0,0 +1,264 @@ -+/* RSA asymmetric public-key algorithm [RFC3447] -+ * -+ * 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. -+ */ -+ -+#define pr_fmt(fmt) "RSA: "fmt -+#include -+#include -+#include "public_key.h" -+ -+MODULE_LICENSE("GPL"); -+ -+#define kenter(FMT, ...) \ -+ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) -+#define kleave(FMT, ...) \ -+ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) -+ -+/* -+ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. -+ */ -+static const u8 RSA_digest_info_MD5[] = { -+ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, -+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ -+ 0x05, 0x00, 0x04, 0x10 -+}; -+ -+static const u8 RSA_digest_info_SHA1[] = { -+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, -+ 0x2B, 0x0E, 0x03, 0x02, 0x1A, -+ 0x05, 0x00, 0x04, 0x14 -+}; -+ -+static const u8 RSA_digest_info_RIPE_MD_160[] = { -+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, -+ 0x2B, 0x24, 0x03, 0x02, 0x01, -+ 0x05, 0x00, 0x04, 0x14 -+}; -+ -+static const u8 RSA_digest_info_SHA224[] = { -+ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, -+ 0x05, 0x00, 0x04, 0x1C -+}; -+ -+static const u8 RSA_digest_info_SHA256[] = { -+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, -+ 0x05, 0x00, 0x04, 0x20 -+}; -+ -+static const u8 RSA_digest_info_SHA384[] = { -+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, -+ 0x05, 0x00, 0x04, 0x30 -+}; -+ -+static const u8 RSA_digest_info_SHA512[] = { -+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, -+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, -+ 0x05, 0x00, 0x04, 0x40 -+}; -+ -+static const struct { -+ const u8 *data; -+ size_t size; -+} RSA_ASN1_templates[PKEY_HASH__LAST] = { -+#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } -+ [PKEY_HASH_MD5] = _(MD5), -+ [PKEY_HASH_SHA1] = _(SHA1), -+ [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), -+ [PKEY_HASH_SHA256] = _(SHA256), -+ [PKEY_HASH_SHA384] = _(SHA384), -+ [PKEY_HASH_SHA512] = _(SHA512), -+ [PKEY_HASH_SHA224] = _(SHA224), -+#undef _ -+}; -+ -+/* -+ * RSAVP1() function [RFC3447 sec 5.2.2] -+ */ -+static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) -+{ -+ MPI m; -+ int ret; -+ -+ /* (1) Validate 0 <= s < n */ -+ if (mpi_cmp_ui(s, 0) < 0) { -+ kleave(" = -EBADMSG [s < 0]"); -+ return -EBADMSG; -+ } -+ if (mpi_cmp(s, key->rsa.n) >= 0) { -+ kleave(" = -EBADMSG [s >= n]"); -+ return -EBADMSG; -+ } -+ -+ m = mpi_alloc(0); -+ if (!m) -+ return -ENOMEM; -+ -+ /* (2) m = s^e mod n */ -+ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); -+ if (ret < 0) { -+ mpi_free(m); -+ return ret; -+ } -+ -+ *_m = m; -+ return 0; -+} -+ -+/* -+ * Integer to Octet String conversion [RFC3447 sec 4.1] -+ */ -+static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) -+{ -+ unsigned X_size, x_size; -+ int X_sign; -+ u8 *X; -+ -+ /* Make sure the string is the right length. The number should begin -+ * with { 0x00, 0x01, ... } so we have to account for 15 leading zero -+ * bits not being reported by MPI. -+ */ -+ x_size = mpi_get_nbits(x); -+ pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); -+ if (x_size != xLen * 8 - 15) -+ return -ERANGE; -+ -+ X = mpi_get_buffer(x, &X_size, &X_sign); -+ if (!X) -+ return -ENOMEM; -+ if (X_sign < 0) { -+ kfree(X); -+ return -EBADMSG; -+ } -+ if (X_size != xLen - 1) { -+ kfree(X); -+ return -EBADMSG; -+ } -+ -+ *_X = X; -+ return 0; -+} -+ -+/* -+ * Perform the RSA signature verification. -+ * @H: Value of hash of data and metadata -+ * @EM: The computed signature value -+ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) -+ * @hash_size: The size of H -+ * @asn1_template: The DigestInfo ASN.1 template -+ * @asn1_size: Size of asm1_template[] -+ */ -+static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, -+ const u8 *asn1_template, size_t asn1_size) -+{ -+ unsigned PS_end, T_offset, i; -+ -+ kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); -+ -+ if (k < 2 + 1 + asn1_size + hash_size) -+ return -EBADMSG; -+ -+ /* Decode the EMSA-PKCS1-v1_5 */ -+ if (EM[1] != 0x01) { -+ kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); -+ return -EBADMSG; -+ } -+ -+ T_offset = k - (asn1_size + hash_size); -+ PS_end = T_offset - 1; -+ if (EM[PS_end] != 0x00) { -+ kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); -+ return -EBADMSG; -+ } -+ -+ for (i = 2; i < PS_end; i++) { -+ if (EM[i] != 0xff) { -+ kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); -+ return -EBADMSG; -+ } -+ } -+ -+ if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { -+ kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); -+ return -EBADMSG; -+ } -+ -+ if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { -+ kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); -+ return -EKEYREJECTED; -+ } -+ -+ kleave(" = 0"); -+ return 0; -+} -+ -+/* -+ * Perform the verification step [RFC3447 sec 8.2.2]. -+ */ -+static int RSA_verify_signature(const struct public_key *key, -+ const struct public_key_signature *sig) -+{ -+ size_t tsize; -+ int ret; -+ -+ /* Variables as per RFC3447 sec 8.2.2 */ -+ const u8 *H = sig->digest; -+ u8 *EM = NULL; -+ MPI m = NULL; -+ size_t k; -+ -+ kenter(""); -+ -+ /* (1) Check the signature size against the public key modulus size */ -+ k = (mpi_get_nbits(key->rsa.n) + 7) / 8; -+ -+ tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; -+ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); -+ if (tsize != k) { -+ ret = -EBADMSG; -+ goto error; -+ } -+ -+ /* (2b) Apply the RSAVP1 verification primitive to the public key */ -+ ret = RSAVP1(key, sig->rsa.s, &m); -+ if (ret < 0) -+ goto error; -+ -+ /* (2c) Convert the message representative (m) to an encoded message -+ * (EM) of length k octets. -+ * -+ * NOTE! The leading zero byte is suppressed by MPI, so we pass a -+ * pointer to the _preceding_ byte to RSA_verify()! -+ */ -+ ret = RSA_I2OSP(m, k, &EM); -+ if (ret < 0) -+ goto error; -+ -+ ret = RSA_verify(H, EM - 1, k, sig->digest_size, -+ RSA_ASN1_templates[sig->pkey_hash_algo].data, -+ RSA_ASN1_templates[sig->pkey_hash_algo].size); -+ -+error: -+ kfree(EM); -+ mpi_free(m); -+ kleave(" = %d", ret); -+ return ret; -+} -+ -+const struct public_key_algorithm RSA_public_key_algorithm = { -+ .name = "RSA", -+ .n_pub_mpi = 2, -+ .n_sec_mpi = 3, -+ .n_sig_mpi = 1, -+ .verify = RSA_verify_signature, -+}; -+EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); -diff --git a/security/keys/crypto/public_key.h b/security/keys/crypto/public_key.h -index 81ed603..7913615 100644 ---- 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); - }; - -+extern const struct public_key_algorithm RSA_public_key_algorithm; -+ - /* - * Asymmetric public key data - */ --- -1.7.10.4 - - -From 7da10c257377762e1a6ac747b48791cf610ba4c5 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:15:39 +0100 -Subject: [PATCH 07/27] KEYS: RSA: 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 -Signed-off-by: David Howells ---- - 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 845285c..a4a63be 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.4 - - -From 4366c59a624398d1aba4d6651191ba880da9e694 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:15:52 +0100 -Subject: [PATCH 08/27] 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 -verification. - -Signed-off-by: David Howells ---- - include/linux/pgp.h | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 206 insertions(+) - create mode 100644 include/linux/pgp.h - -diff --git a/include/linux/pgp.h b/include/linux/pgp.h -new file mode 100644 -index 0000000..1359f64 ---- /dev/null -+++ b/include/linux/pgp.h -@@ -0,0 +1,206 @@ -+/* PGP definitions (RFC 4880) -+ * -+ * 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. -+ */ -+ -+#ifndef _LINUX_PGP_H -+#define _LINUX_PGP_H -+ -+#include -+ -+struct pgp_key_ID { -+ u8 id[8]; -+}; -+ -+struct pgp_time { -+ u8 time[4]; -+}; -+ -+/* -+ * PGP public-key algorithm identifiers [RFC4880: 9.1] -+ */ -+enum pgp_pubkey_algo { -+ PGP_PUBKEY_RSA_ENC_OR_SIG = 1, -+ PGP_PUBKEY_RSA_ENC_ONLY = 2, -+ PGP_PUBKEY_RSA_SIG_ONLY = 3, -+ PGP_PUBKEY_ELGAMAL = 16, -+ PGP_PUBKEY_DSA = 17, -+ PGP_PUBKEY__LAST -+}; -+ -+/* -+ * PGP symmetric-key algorithm identifiers [RFC4880: 9.2] -+ */ -+enum pgp_symkey_algo { -+ PGP_SYMKEY_PLAINTEXT = 0, -+ PGP_SYMKEY_IDEA = 1, -+ PGP_SYMKEY_3DES = 2, -+ PGP_SYMKEY_CAST5 = 3, -+ PGP_SYMKEY_BLOWFISH = 4, -+ PGP_SYMKEY_AES_128KEY = 7, -+ PGP_SYMKEY_AES_192KEY = 8, -+ PGP_SYMKEY_AES_256KEY = 9, -+ PGP_SYMKEY_TWOFISH_256KEY = 10, -+}; -+ -+/* -+ * PGP compression algorithm identifiers [RFC4880: 9.3] -+ */ -+enum pgp_compr_algo { -+ PGP_COMPR_UNCOMPRESSED = 0, -+ PGP_COMPR_ZIP = 1, -+ PGP_COMPR_ZLIB = 2, -+ PGP_COMPR_BZIP2 = 3, -+}; -+ -+/* -+ * PGP hash algorithm identifiers [RFC4880: 9.4] -+ */ -+enum pgp_hash_algo { -+ PGP_HASH_MD5 = 1, -+ PGP_HASH_SHA1 = 2, -+ PGP_HASH_RIPE_MD_160 = 3, -+ PGP_HASH_SHA256 = 8, -+ PGP_HASH_SHA384 = 9, -+ PGP_HASH_SHA512 = 10, -+ PGP_HASH_SHA224 = 11, -+ PGP_HASH__LAST -+}; -+ -+extern const char *const pgp_hash_algorithms[PGP_HASH__LAST]; -+ -+/* -+ * PGP packet type tags [RFC4880: 4.3]. -+ */ -+enum pgp_packet_tag { -+ PGP_PKT_RESERVED = 0, -+ PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, -+ PGP_PKT_SIGNATURE = 2, -+ PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, -+ PGP_PKT_ONEPASS_SIGNATURE = 4, -+ PGP_PKT_SECRET_KEY = 5, -+ PGP_PKT_PUBLIC_KEY = 6, -+ PGP_PKT_SECRET_SUBKEY = 7, -+ PGP_PKT_COMPRESSED_DATA = 8, -+ PGP_PKT_SYM_ENC_DATA = 9, -+ PGP_PKT_MARKER = 10, -+ PGP_PKT_LITERAL_DATA = 11, -+ PGP_PKT_TRUST = 12, -+ PGP_PKT_USER_ID = 13, -+ PGP_PKT_PUBLIC_SUBKEY = 14, -+ PGP_PKT_USER_ATTRIBUTE = 17, -+ PGP_PKT_SYM_ENC_AND_INTEG_DATA = 18, -+ PGP_PKT_MODIFY_DETECT_CODE = 19, -+ PGP_PKT_PRIVATE_0 = 60, -+ PGP_PKT_PRIVATE_3 = 63, -+ PGP_PKT__HIGHEST = 63 -+}; -+ -+/* -+ * Signature (tag 2) packet [RFC4880: 5.2]. -+ */ -+enum pgp_signature_version { -+ PGP_SIG_VERSION_3 = 3, -+ PGP_SIG_VERSION_4 = 4, -+}; -+ -+enum pgp_signature_type { -+ PGP_SIG_BINARY_DOCUMENT_SIG = 0x00, -+ PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG = 0x01, -+ PGP_SIG_STANDALONE_SIG = 0x02, -+ PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY = 0x10, -+ PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY = 0x11, -+ PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY = 0x12, -+ PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY = 0x13, -+ PGP_SIG_SUBKEY_BINDING_SIG = 0x18, -+ PGP_SIG_PRIMARY_KEY_BINDING_SIG = 0x19, -+ PGP_SIG_DIRECTLY_ON_KEY = 0x1F, -+ PGP_SIG_KEY_REVOCATION_SIG = 0x20, -+ PGP_SIG_SUBKEY_REVOCATION_SIG = 0x28, -+ PGP_SIG_CERT_REVOCATION_SIG = 0x30, -+ PGP_SIG_TIMESTAMP_SIG = 0x40, -+ PGP_SIG_THIRD_PARTY_CONFIRM_SIG = 0x50, -+}; -+ -+struct pgp_signature_v3_packet { -+ enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */ -+ u8 length_of_hashed; /* == 5 */ -+ struct { -+ enum pgp_signature_type signature_type : 8; -+ struct pgp_time creation_time; -+ } hashed; -+ struct pgp_key_ID issuer; -+ enum pgp_pubkey_algo pubkey_algo : 8; -+ enum pgp_hash_algo hash_algo : 8; -+} __packed; -+ -+struct pgp_signature_v4_packet { -+ enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_4 */ -+ enum pgp_signature_type signature_type : 8; -+ enum pgp_pubkey_algo pubkey_algo : 8; -+ enum pgp_hash_algo hash_algo : 8; -+} __packed; -+ -+/* -+ * V4 signature subpacket types [RFC4880: 5.2.3.1]. -+ */ -+enum pgp_sig_subpkt_type { -+ PGP_SIG_CREATION_TIME = 2, -+ PGP_SIG_EXPIRATION_TIME = 3, -+ PGP_SIG_EXPORTABLE_CERT = 4, -+ PGP_SIG_TRUST_SIG = 5, -+ PGP_SIG_REGEXP = 6, -+ PGP_SIG_REVOCABLE = 7, -+ PGP_SIG_KEY_EXPIRATION_TIME = 9, -+ PGP_SIG_PREF_SYM_ALGO = 11, -+ PGP_SIG_REVOCATION_KEY = 12, -+ PGP_SIG_ISSUER = 16, -+ PGP_SIG_NOTATION_DATA = 20, -+ PGP_SIG_PREF_HASH_ALGO = 21, -+ PGP_SIG_PREF_COMPR_ALGO = 22, -+ PGP_SIG_KEY_SERVER_PREFS = 23, -+ PGP_SIG_PREF_KEY_SERVER = 24, -+ PGP_SIG_PRIMARY_USER_ID = 25, -+ PGP_SIG_POLICY_URI = 26, -+ PGP_SIG_KEY_FLAGS = 27, -+ PGP_SIG_SIGNERS_USER_ID = 28, -+ PGP_SIG_REASON_FOR_REVOCATION = 29, -+ PGP_SIG_FEATURES = 30, -+ PGP_SIG_TARGET = 31, -+ PGP_SIG_EMBEDDED_SIG = 32, -+ PGP_SIG__LAST -+}; -+ -+#define PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK 0x80 -+ -+/* -+ * Key (tag 5, 6, 7 and 14) packet -+ */ -+enum pgp_key_version { -+ PGP_KEY_VERSION_2 = 2, -+ PGP_KEY_VERSION_3 = 3, -+ PGP_KEY_VERSION_4 = 4, -+}; -+ -+struct pgp_key_v3_packet { -+ enum pgp_key_version version : 8; -+ struct pgp_time creation_time; -+ u8 expiry[2]; /* 0 or time in days till expiry */ -+ enum pgp_pubkey_algo pubkey_algo : 8; -+ u8 key_material[0]; -+} __packed; -+ -+struct pgp_key_v4_packet { -+ enum pgp_key_version version : 8; -+ struct pgp_time creation_time; -+ enum pgp_pubkey_algo pubkey_algo : 8; -+ u8 key_material[0]; -+} __packed; -+ -+#endif /* _LINUX_PGP_H */ --- -1.7.10.4 - - -From 0409a338e01de5025cec2a1b291442651163aafd Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:17:46 +0100 -Subject: [PATCH 09/27] 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: - - struct pgp_parse_context { - u64 types_of_interest; - int (*process_packet)(struct pgp_parse_context *context, - enum pgp_packet_tag type, - u8 headerlen, - const u8 *data, - size_t datalen); - }; - - int pgp_parse_packets(const u8 *data, size_t datalen, - struct pgp_parse_context *ctx); - -This is configured on with CONFIG_PGP_LIBRARY. - -Signed-off-by: David Howells ---- - include/linux/pgplib.h | 47 +++++++ - security/keys/crypto/Kconfig | 6 + - security/keys/crypto/Makefile | 1 + - security/keys/crypto/pgp_library.c | 268 ++++++++++++++++++++++++++++++++++++ - 4 files changed, 322 insertions(+) - create mode 100644 include/linux/pgplib.h - create mode 100644 security/keys/crypto/pgp_library.c - -diff --git a/include/linux/pgplib.h b/include/linux/pgplib.h -new file mode 100644 -index 0000000..a045b3a ---- /dev/null -+++ b/include/linux/pgplib.h -@@ -0,0 +1,47 @@ -+/* PGP library definitions (RFC 4880) -+ * -+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#ifndef _LINUX_PGPLIB_H -+#define _LINUX_PGPLIB_H -+ -+#if defined(CONFIG_PGP_LIBRARY) || defined(CONFIG_PGP_LIBRARY_MODULE) -+ -+#include -+ -+/* -+ * PGP library packet parser -+ */ -+struct pgp_parse_context { -+ u64 types_of_interest; -+ int (*process_packet)(struct pgp_parse_context *context, -+ enum pgp_packet_tag type, -+ u8 headerlen, -+ const u8 *data, -+ size_t datalen); -+}; -+ -+extern int pgp_parse_packets(const u8 *data, size_t datalen, -+ struct pgp_parse_context *ctx); -+ -+struct pgp_parse_pubkey { -+ enum pgp_key_version version : 8; -+ enum pgp_pubkey_algo pubkey_algo : 8; -+ time_t creation_time; -+ time_t expires_at; -+}; -+ -+extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, -+ struct pgp_parse_pubkey *pk); -+ -+ -+#endif /* CONFIG_PGP_LIBRARY */ -+ -+#endif /* _LINUX_PGPLIB_H */ -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). -+ -+config PGP_LIBRARY -+ tristate "PGP parsing library" -+ 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/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 -diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c -new file mode 100644 -index 0000000..af396d6 ---- /dev/null -+++ b/security/keys/crypto/pgp_library.c -@@ -0,0 +1,268 @@ -+/* PGP packet parser (RFC 4880) -+ * -+ * 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. -+ */ -+#define pr_fmt(fmt) "PGP: "fmt -+#include -+#include -+#include -+#include -+ -+MODULE_LICENSE("GPL"); -+ -+const char *const pgp_hash_algorithms[PGP_HASH__LAST] = { -+ [PGP_HASH_MD5] = "md5", -+ [PGP_HASH_SHA1] = "sha1", -+ [PGP_HASH_RIPE_MD_160] = "rmd160", -+ [PGP_HASH_SHA256] = "sha256", -+ [PGP_HASH_SHA384] = "sha384", -+ [PGP_HASH_SHA512] = "sha512", -+ [PGP_HASH_SHA224] = "sha224", -+}; -+EXPORT_SYMBOL_GPL(pgp_hash_algorithms); -+ -+/** -+ * pgp_parse_packet_header - Parse a PGP packet header -+ * @_data: Start of the PGP packet (updated to PGP packet data) -+ * @_datalen: Amount of data remaining in buffer (decreased) -+ * @_type: Where the packet type will be returned -+ * @_headerlen: Where the header length will be returned -+ * -+ * Parse a set of PGP packet header [RFC 4880: 4.2]. -+ * -+ * Returns packet data size on success; non-zero on error. If successful, -+ * *_data and *_datalen will have been updated and *_headerlen will be set to -+ * hold the length of the packet header. -+ */ -+static ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, -+ enum pgp_packet_tag *_type, -+ u8 *_headerlen) -+{ -+ enum pgp_packet_tag type; -+ const u8 *data = *_data; -+ size_t size, datalen = *_datalen; -+ -+ pr_devel("-->pgp_parse_packet_header(,%zu,,)", datalen); -+ -+ if (datalen < 2) -+ goto short_packet; -+ -+ pr_devel("pkthdr %02x, %02x\n", data[0], data[1]); -+ -+ type = *data++; -+ datalen--; -+ if (!(type & 0x80)) { -+ pr_debug("Packet type does not have MSB set\n"); -+ return -EBADMSG; -+ } -+ type &= ~0x80; -+ -+ if (type & 0x40) { -+ /* New packet length format */ -+ type &= ~0x40; -+ pr_devel("new format: t=%u\n", type); -+ switch (data[0]) { -+ case 0x00 ... 0xbf: -+ /* One-byte length */ -+ size = data[0]; -+ data++; -+ datalen--; -+ *_headerlen = 2; -+ break; -+ case 0xc0 ... 0xdf: -+ /* Two-byte length */ -+ if (datalen < 2) -+ goto short_packet; -+ size = (data[0] - 192) * 256; -+ size += data[1] + 192; -+ data += 2; -+ datalen -= 2; -+ *_headerlen = 3; -+ break; -+ case 0xff: -+ /* 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("Partial body length packet not supported\n"); -+ return -EBADMSG; -+ } -+ } else { -+ /* Old packet length format */ -+ u8 length_type = type & 0x03; -+ type >>= 2; -+ pr_devel("old format: t=%u lt=%u\n", type, length_type); -+ -+ switch (length_type) { -+ case 0: -+ /* One-byte length */ -+ size = data[0]; -+ data++; -+ datalen--; -+ *_headerlen = 2; -+ break; -+ case 1: -+ /* Two-byte length */ -+ if (datalen < 2) -+ goto short_packet; -+ size = data[0] << 8; -+ size |= data[1]; -+ data += 2; -+ datalen -= 2; -+ *_headerlen = 3; -+ break; -+ case 2: -+ /* Four-byte length */ -+ if (datalen < 4) -+ goto short_packet; -+ size = data[0] << 24; -+ size |= data[1] << 16; -+ size |= data[2] << 8; -+ size |= data[3]; -+ data += 4; -+ datalen -= 4; -+ *_headerlen = 5; -+ break; -+ default: -+ pr_debug("Indefinite length packet not supported\n"); -+ return -EBADMSG; -+ } -+ } -+ -+ 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; -+ *_type = type; -+ pr_devel("Found packet type=%u size=%zd\n", type, size); -+ return size; -+ -+short_packet: -+ pr_debug("Attempt to parse short packet\n"); -+ return -EBADMSG; -+too_big: -+ pr_debug("Signature subpacket size >2G\n"); -+ return -EMSGSIZE; -+} -+ -+/** -+ * pgp_parse_packets - Parse a set of PGP packets -+ * @_data: Data to be parsed (updated) -+ * @_datalen: Amount of data (updated) -+ * @ctx: Parsing context -+ * -+ * Parse a set of PGP packets [RFC 4880: 4]. -+ */ -+int pgp_parse_packets(const u8 *data, size_t datalen, -+ struct pgp_parse_context *ctx) -+{ -+ enum pgp_packet_tag type; -+ ssize_t pktlen; -+ u8 headerlen; -+ int ret; -+ -+ while (datalen > 2) { -+ pktlen = pgp_parse_packet_header(&data, &datalen, &type, -+ &headerlen); -+ if (pktlen < 0) -+ return pktlen; -+ -+ if ((ctx->types_of_interest >> type) & 1) { -+ ret = ctx->process_packet(ctx, type, headerlen, -+ data, pktlen); -+ if (ret < 0) -+ return ret; -+ } -+ data += pktlen; -+ datalen -= pktlen; -+ } -+ -+ if (datalen != 0) { -+ pr_debug("Excess octets in packet stream\n"); -+ return -EBADMSG; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(pgp_parse_packets); -+ -+/** -+ * pgp_parse_public_key - Parse the common part of a PGP pubkey packet -+ * @_data: Content of packet (updated) -+ * @_datalen: Length of packet remaining (updated) -+ * @pk: Public key data -+ * -+ * Parse the common data struct for a PGP pubkey packet [RFC 4880: 5.5.2]. -+ */ -+int pgp_parse_public_key(const u8 **_data, size_t *_datalen, -+ struct pgp_parse_pubkey *pk) -+{ -+ const u8 *data = *_data; -+ size_t datalen = *_datalen; -+ __be32 tmp; -+ -+ if (datalen < 12) { -+ pr_debug("Public key packet too short\n"); -+ return -EBADMSG; -+ } -+ -+ pk->version = *data++; -+ switch (pk->version) { -+ case PGP_KEY_VERSION_2: -+ case PGP_KEY_VERSION_3: -+ case PGP_KEY_VERSION_4: -+ break; -+ default: -+ pr_debug("Public key packet with unhandled version %d\n", -+ pk->version); -+ return -EBADMSG; -+ } -+ -+ tmp = *data++ << 24; -+ tmp |= *data++ << 16; -+ tmp |= *data++ << 8; -+ tmp |= *data++; -+ pk->creation_time = tmp; -+ if (pk->version == PGP_KEY_VERSION_4) { -+ pk->expires_at = 0; /* Have to get it from the selfsignature */ -+ } else { -+ unsigned short ndays; -+ ndays = *data++ << 8; -+ ndays |= *data++; -+ if (ndays) -+ pk->expires_at = pk->creation_time + ndays * 86400UL; -+ else -+ pk->expires_at = 0; -+ datalen -= 2; -+ } -+ -+ pk->pubkey_algo = *data++; -+ datalen -= 6; -+ -+ pr_devel("%x,%x,%lx,%lx", -+ pk->version, pk->pubkey_algo, pk->creation_time, -+ pk->expires_at); -+ -+ *_data = data; -+ *_datalen = datalen; -+ return 0; -+} -+EXPORT_SYMBOL_GPL(pgp_parse_public_key); --- -1.7.10.4 - - -From 2a76433139dbdc6d57d38da6ceb79ce05ab603a4 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:21:24 +0100 -Subject: [PATCH 10/27] PGPLIB: Signature parser - -Provide some PGP signature parsing helpers: - - (1) A function to parse V4 signature subpackets and pass the desired ones to - a processor function: - - int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, - struct pgp_parse_sig_context *ctx); - - (2) A function to parse out basic signature parameters from any PGP signature - such that the algorithms and public key can be selected: - - int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, - struct pgp_sig_parameters *p); - -Signed-off-by: David Howells ---- - include/linux/pgplib.h | 25 ++++ - security/keys/crypto/pgp_library.c | 280 ++++++++++++++++++++++++++++++++++++ - 2 files changed, 305 insertions(+) - -diff --git a/include/linux/pgplib.h b/include/linux/pgplib.h -index a045b3a..34594a9 100644 ---- a/include/linux/pgplib.h -+++ b/include/linux/pgplib.h -@@ -41,6 +41,31 @@ struct pgp_parse_pubkey { - extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, - struct pgp_parse_pubkey *pk); - -+struct pgp_parse_sig_context { -+ unsigned long types_of_interest[128 / BITS_PER_LONG]; -+ int (*process_packet)(struct pgp_parse_sig_context *context, -+ enum pgp_sig_subpkt_type type, -+ const u8 *data, -+ size_t datalen); -+}; -+ -+extern int pgp_parse_sig_packets(const u8 *data, size_t datalen, -+ struct pgp_parse_sig_context *ctx); -+ -+struct pgp_sig_parameters { -+ enum pgp_signature_version version : 8; -+ enum pgp_signature_type signature_type : 8; -+ enum pgp_pubkey_algo pubkey_algo : 8; -+ enum pgp_hash_algo hash_algo : 8; -+ union { -+ struct pgp_key_ID issuer; -+ __be32 issuer32[2]; -+ }; -+}; -+ -+extern int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, -+ struct pgp_sig_parameters *p); -+ - - #endif /* CONFIG_PGP_LIBRARY */ - -diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c -index af396d6..c9218df 100644 ---- a/security/keys/crypto/pgp_library.c -+++ b/security/keys/crypto/pgp_library.c -@@ -266,3 +266,283 @@ int pgp_parse_public_key(const u8 **_data, size_t *_datalen, - return 0; - } - EXPORT_SYMBOL_GPL(pgp_parse_public_key); -+ -+/** -+ * pgp_parse_sig_subpkt_header - Parse a PGP V4 signature subpacket header -+ * @_data: Start of the subpacket (updated to subpacket data) -+ * @_datalen: Amount of data remaining in buffer (decreased) -+ * @_type: Where the subpacket type will be returned -+ * -+ * Parse a PGP V4 signature subpacket header [RFC 4880: 5.2.3.1]. -+ * -+ * Returns packet data size on success; non-zero on error. If successful, -+ * *_data and *_datalen will have been updated and *_headerlen will be set to -+ * hold the length of the packet header. -+ */ -+static ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, -+ enum pgp_sig_subpkt_type *_type) -+{ -+ enum pgp_sig_subpkt_type type; -+ const u8 *data = *_data; -+ size_t size, datalen = *_datalen; -+ -+ pr_devel("-->pgp_parse_sig_subpkt_header(,%zu,,)", datalen); -+ -+ if (datalen < 2) -+ goto short_subpacket; -+ -+ pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]); -+ -+ switch (data[0]) { -+ case 0x00 ... 0xbf: -+ /* One-byte length */ -+ size = data[0]; -+ data++; -+ datalen--; -+ break; -+ case 0xc0 ... 0xfe: -+ /* Two-byte length */ -+ if (datalen < 3) -+ goto short_subpacket; -+ size = (data[0] - 192) * 256; -+ size += data[1] + 192; -+ data += 2; -+ datalen -= 2; -+ break; -+ case 0xff: -+ if (datalen < 6) -+ goto short_subpacket; -+ size = data[1] << 24; -+ size |= data[2] << 16; -+ size |= data[3] << 8; -+ size |= data[4]; -+ data += 5; -+ datalen -= 5; -+ break; -+ } -+ -+ /* The type octet is included in the size */ -+ 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; -+ -+ type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; -+ datalen--; -+ size--; -+ -+ *_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; -+too_big: -+ pr_debug("Signature subpacket size >2G\n"); -+ return -EMSGSIZE; -+} -+ -+/** -+ * pgp_parse_sig_subpkts - Parse a set of PGP V4 signatute subpackets -+ * @_data: Data to be parsed (updated) -+ * @_datalen: Amount of data (updated) -+ * @ctx: Parsing context -+ * -+ * Parse a set of PGP signature subpackets [RFC 4880: 5.2.3]. -+ */ -+static int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, -+ struct pgp_parse_sig_context *ctx) -+{ -+ enum pgp_sig_subpkt_type type; -+ ssize_t pktlen; -+ int ret; -+ -+ pr_devel("-->pgp_parse_sig_subpkts(,%zu,,)", datalen); -+ -+ while (datalen > 2) { -+ pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type); -+ if (pktlen < 0) -+ return pktlen; -+ if (test_bit(type, ctx->types_of_interest)) { -+ ret = ctx->process_packet(ctx, type, data, pktlen); -+ if (ret < 0) -+ return ret; -+ } -+ data += pktlen; -+ datalen -= pktlen; -+ } -+ -+ if (datalen != 0) { -+ pr_debug("Excess octets in signature subpacket stream\n"); -+ return -EBADMSG; -+ } -+ -+ return 0; -+} -+ -+struct pgp_parse_sig_params_ctx { -+ struct pgp_parse_sig_context base; -+ struct pgp_sig_parameters *params; -+ bool got_the_issuer; -+}; -+ -+/* -+ * Process a V4 signature subpacket. -+ */ -+static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context, -+ enum pgp_sig_subpkt_type type, -+ const u8 *data, -+ size_t datalen) -+{ -+ struct pgp_parse_sig_params_ctx *ctx = -+ container_of(context, struct pgp_parse_sig_params_ctx, base); -+ -+ if (ctx->got_the_issuer) { -+ pr_debug("V4 signature packet has multiple issuers\n"); -+ return -EBADMSG; -+ } -+ -+ if (datalen != 8) { -+ pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n", -+ datalen); -+ return -EBADMSG; -+ } -+ -+ memcpy(&ctx->params->issuer, data, 8); -+ ctx->got_the_issuer = true; -+ return 0; -+} -+ -+/** -+ * pgp_parse_sig_params - Parse basic parameters from a PGP signature packet -+ * @_data: Content of packet (updated) -+ * @_datalen: Length of packet remaining (updated) -+ * @p: The basic parameters -+ * -+ * Parse the basic parameters from a PGP signature packet [RFC 4880: 5.2] that -+ * are needed to start off a signature verification operation. The only ones -+ * actually necessary are the signature type (which affects how the data is -+ * transformed) and the hash algorithm. -+ * -+ * We also extract the public key algorithm and the issuer's key ID as we'll -+ * need those to determine if we actually have the public key available. If -+ * not, then we can't verify the signature anyway. -+ * -+ * Returns 0 if successful or a negative error code. *_data and *_datalen are -+ * updated to point to the 16-bit subset of the hash value and the set of MPIs. -+ */ -+int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, -+ struct pgp_sig_parameters *p) -+{ -+ const u8 *data = *_data; -+ size_t datalen = *_datalen; -+ int ret; -+ -+ pr_devel("-->pgp_parse_sig_params(,%zu,,)", datalen); -+ -+ if (datalen < 1) -+ return -EBADMSG; -+ p->version = *data; -+ -+ if (p->version == PGP_SIG_VERSION_3) { -+ const struct pgp_signature_v3_packet *v3 = (const void *)data; -+ -+ if (datalen < sizeof(*v3)) { -+ pr_debug("Short V3 signature packet\n"); -+ return -EBADMSG; -+ } -+ datalen -= sizeof(*v3); -+ data += sizeof(*v3); -+ -+ /* V3 has everything we need in the header */ -+ p->signature_type = v3->hashed.signature_type; -+ p->issuer = v3->issuer; -+ p->pubkey_algo = v3->pubkey_algo; -+ p->hash_algo = v3->hash_algo; -+ -+ } else if (p->version == PGP_SIG_VERSION_4) { -+ const struct pgp_signature_v4_packet *v4 = (const void *)data; -+ struct pgp_parse_sig_params_ctx ctx = { -+ .base.process_packet = pgp_process_sig_params_subpkt, -+ .params = p, -+ .got_the_issuer = false, -+ }; -+ size_t subdatalen; -+ -+ if (datalen < sizeof(*v4) + 2 + 2 + 2) { -+ pr_debug("Short V4 signature packet\n"); -+ return -EBADMSG; -+ } -+ datalen -= sizeof(*v4); -+ data += sizeof(*v4); -+ -+ /* V4 has most things in the header... */ -+ p->signature_type = v4->signature_type; -+ p->pubkey_algo = v4->pubkey_algo; -+ p->hash_algo = v4->hash_algo; -+ -+ /* ... but we have to get the key ID from the subpackets, of -+ * which there are two sets. */ -+ __set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest); -+ -+ subdatalen = *data++ << 8; -+ subdatalen |= *data++; -+ datalen -= 2; -+ if (subdatalen) { -+ /* Hashed subpackets */ -+ pr_devel("hashed data: %zu (after %zu)\n", -+ subdatalen, sizeof(*v4)); -+ if (subdatalen > datalen + 2 + 2) { -+ pr_debug("Short V4 signature packet [hdata]\n"); -+ return -EBADMSG; -+ } -+ ret = pgp_parse_sig_subpkts(data, subdatalen, -+ &ctx.base); -+ if (ret < 0) -+ return ret; -+ data += subdatalen; -+ datalen -= subdatalen; -+ } -+ -+ subdatalen = *data++ << 8; -+ subdatalen |= *data++; -+ datalen -= 2; -+ if (subdatalen) { -+ /* Unhashed subpackets */ -+ pr_devel("unhashed data: %zu\n", subdatalen); -+ if (subdatalen > datalen + 2) { -+ pr_debug("Short V4 signature packet [udata]\n"); -+ return -EBADMSG; -+ } -+ ret = pgp_parse_sig_subpkts(data, subdatalen, -+ &ctx.base); -+ if (ret < 0) -+ return ret; -+ data += subdatalen; -+ datalen -= subdatalen; -+ } -+ -+ if (!ctx.got_the_issuer) { -+ pr_debug("V4 signature packet lacks issuer\n"); -+ return -EBADMSG; -+ } -+ } else { -+ pr_debug("Signature packet with unhandled version %d\n", -+ p->version); -+ return -EBADMSG; -+ } -+ -+ *_data = data; -+ *_datalen = datalen; -+ return 0; -+} -+EXPORT_SYMBOL_GPL(pgp_parse_sig_params); --- -1.7.10.4 - - -From 91a05bc308c1e177410882a119f388d3b6b53c22 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:21:26 +0100 -Subject: [PATCH 11/27] KEYS: PGP data parser - -Implement a PGP data parser for the crypto key type to use when instantiating a -key. - -This parser attempts to parse the instantiation data as a PGP packet sequence -(RFC 4880) and if it parses okay, attempts to extract a public-key algorithm -key or subkey from it. - -If it finds such a key, it will set up a public_key subtype payload with -appropriate handler routines (DSA or RSA) and attach it to the key. - -Thanks to Tetsuo Handa for pointing out -some errors. - -Signed-off-by: David Howells ---- - security/keys/crypto/Kconfig | 12 ++ - security/keys/crypto/Makefile | 4 + - security/keys/crypto/pgp_parser.h | 23 +++ - security/keys/crypto/pgp_public_key.c | 348 +++++++++++++++++++++++++++++++++ - 4 files changed, 387 insertions(+) - create mode 100644 security/keys/crypto/pgp_parser.h - create mode 100644 security/keys/crypto/pgp_public_key.c - -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. -+ -+config CRYPTO_KEY_PGP_PARSER -+ tristate "PGP key blob parser" -+ depends on CRYPTO_KEY_TYPE -+ select CRYPTO_KEY_PUBLIC_KEY_SUBTYPE -+ select PGP_LIBRARY -+ select MD5 # V3 fingerprint generation -+ select SHA1 # V4 fingerprint generation -+ help -+ 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/crypto/Makefile b/security/keys/crypto/Makefile -index 5fbe54e..35733fc 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_key_parser.o -+pgp_key_parser-y := \ -+ pgp_public_key.o -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/crypto/pgp_parser.h -@@ -0,0 +1,23 @@ -+/* PGP crypto data parser internal definitions -+ * -+ * 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 -+ -+#define kenter(FMT, ...) \ -+ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) -+#define kleave(FMT, ...) \ -+ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) -+ -+/* -+ * pgp_key_parser.c -+ */ -+extern const -+struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; -diff --git a/security/keys/crypto/pgp_public_key.c b/security/keys/crypto/pgp_public_key.c -new file mode 100644 -index 0000000..8a8b7c0 ---- /dev/null -+++ b/security/keys/crypto/pgp_public_key.c -@@ -0,0 +1,348 @@ -+/* Instantiate a public key crypto key from PGP format data [RFC 4880] -+ * -+ * 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. -+ */ -+ -+#define pr_fmt(fmt) "PGP: "fmt -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "public_key.h" -+#include "pgp_parser.h" -+ -+MODULE_LICENSE("GPL"); -+ -+const -+struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST] = { -+#if defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) || \ -+ defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA_MODULE) -+ [PGP_PUBKEY_RSA_ENC_OR_SIG] = &RSA_public_key_algorithm, -+ [PGP_PUBKEY_RSA_ENC_ONLY] = &RSA_public_key_algorithm, -+ [PGP_PUBKEY_RSA_SIG_ONLY] = &RSA_public_key_algorithm, -+#endif -+ [PGP_PUBKEY_ELGAMAL] = NULL, -+ [PGP_PUBKEY_DSA] = NULL, -+}; -+ -+static const u8 pgp_public_key_capabilities[PGP_PUBKEY__LAST] = { -+ [PGP_PUBKEY_RSA_ENC_OR_SIG] = PKEY_CAN_ENCDEC | PKEY_CAN_SIGVER, -+ [PGP_PUBKEY_RSA_ENC_ONLY] = PKEY_CAN_ENCDEC, -+ [PGP_PUBKEY_RSA_SIG_ONLY] = PKEY_CAN_SIGVER, -+ [PGP_PUBKEY_ELGAMAL] = 0, -+ [PGP_PUBKEY_DSA] = 0, -+}; -+ -+static inline void digest_putc(struct shash_desc *digest, uint8_t ch) -+{ -+ crypto_shash_update(digest, &ch, 1); -+} -+ -+struct pgp_key_data_parse_context { -+ struct pgp_parse_context pgp; -+ struct crypto_key_subtype *subtype; -+ char *fingerprint; -+ void *payload; -+}; -+ -+/* -+ * Calculate the public key ID (RFC4880 12.2) -+ */ -+static int pgp_calc_pkey_keyid(struct shash_desc *digest, -+ struct pgp_parse_pubkey *pgp, -+ struct public_key *key) -+{ -+ unsigned nb[ARRAY_SIZE(key->mpi)]; -+ unsigned nn[ARRAY_SIZE(key->mpi)]; -+ unsigned n; -+ u8 *pp[ARRAY_SIZE(key->mpi)]; -+ u32 a32; -+ int npkey = key->algo->n_pub_mpi; -+ int i, ret = -ENOMEM; -+ -+ 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]); -+ pp[i] = mpi_get_buffer(key->mpi[i], nn + i, NULL); -+ if (!pp[i]) -+ goto error; -+ n += 2 + nn[i]; -+ } -+ -+ digest_putc(digest, 0x99); /* ctb */ -+ digest_putc(digest, n >> 8); /* 16-bit header length */ -+ digest_putc(digest, n); -+ digest_putc(digest, pgp->version); -+ -+ a32 = pgp->creation_time; -+ digest_putc(digest, a32 >> 24); -+ digest_putc(digest, a32 >> 16); -+ digest_putc(digest, a32 >> 8); -+ digest_putc(digest, a32 >> 0); -+ -+ if (pgp->version < PGP_KEY_VERSION_4) { -+ u16 a16; -+ -+ if (pgp->expires_at) -+ a16 = (pgp->expires_at - pgp->creation_time) / 86400UL; -+ else -+ a16 = 0; -+ digest_putc(digest, a16 >> 8); -+ digest_putc(digest, a16 >> 0); -+ } -+ -+ digest_putc(digest, pgp->pubkey_algo); -+ -+ for (i = 0; i < npkey; i++) { -+ digest_putc(digest, nb[i] >> 8); -+ digest_putc(digest, nb[i]); -+ crypto_shash_update(digest, pp[i], nn[i]); -+ } -+ ret = 0; -+ -+error: -+ for (i = 0; i < npkey; i++) -+ kfree(pp[i]); -+ kleave(" = %d", ret); -+ return ret; -+} -+ -+/* -+ * Calculate the public key ID fingerprint -+ */ -+static int pgp_generate_fingerprint(struct pgp_key_data_parse_context *ctx, -+ struct pgp_parse_pubkey *pgp, -+ struct public_key *key) -+{ -+ struct crypto_shash *tfm; -+ struct shash_desc *digest; -+ char *fingerprint; -+ u8 *raw_fingerprint; -+ int digest_size, offset; -+ int ret, i; -+ -+ ret = -ENOMEM; -+ tfm = crypto_alloc_shash(pgp->version < PGP_KEY_VERSION_4 ? -+ "md5" : "sha1", 0, 0); -+ if (!tfm) -+ goto cleanup; -+ -+ digest = kmalloc(sizeof(*digest) + crypto_shash_descsize(tfm), -+ GFP_KERNEL); -+ if (!digest) -+ goto cleanup_tfm; -+ -+ digest->tfm = tfm; -+ digest->flags = CRYPTO_TFM_REQ_MAY_SLEEP; -+ ret = crypto_shash_init(digest); -+ if (ret < 0) -+ goto cleanup_hash; -+ -+ ret = pgp_calc_pkey_keyid(digest, pgp, key); -+ if (ret < 0) -+ goto cleanup_hash; -+ -+ digest_size = crypto_shash_digestsize(tfm); -+ -+ raw_fingerprint = kmalloc(digest_size, GFP_KERNEL); -+ if (!raw_fingerprint) -+ goto cleanup_hash; -+ -+ ret = crypto_shash_final(digest, raw_fingerprint); -+ if (ret < 0) -+ goto cleanup_raw_fingerprint; -+ -+ fingerprint = kmalloc(digest_size * 2 + 1, GFP_KERNEL); -+ if (!fingerprint) -+ goto cleanup_raw_fingerprint; -+ -+ offset = digest_size - 8; -+ pr_debug("offset %u/%u\n", offset, digest_size); -+ -+ for (i = 0; i < digest_size; i++) -+ sprintf(fingerprint + i * 2, "%02x", raw_fingerprint[i]); -+ pr_debug("fingerprint %s\n", fingerprint); -+ -+ memcpy(&key->key_id, raw_fingerprint + offset, 8); -+ key->key_id_size = 8; -+ -+ ctx->fingerprint = fingerprint; -+ ret = 0; -+cleanup_raw_fingerprint: -+ kfree(raw_fingerprint); -+cleanup_hash: -+ kfree(digest); -+cleanup_tfm: -+ crypto_free_shash(tfm); -+cleanup: -+ kleave(" = %d", ret); -+ return ret; -+} -+ -+/* -+ * Extract a public key or public subkey from the PGP stream. -+ */ -+static int pgp_process_public_key(struct pgp_parse_context *context, -+ enum pgp_packet_tag type, -+ u8 headerlen, -+ const u8 *data, -+ size_t datalen) -+{ -+ const struct public_key_algorithm *algo; -+ struct pgp_key_data_parse_context *ctx = -+ container_of(context, struct pgp_key_data_parse_context, pgp); -+ struct pgp_parse_pubkey pgp; -+ struct public_key *key; -+ int i, ret; -+ -+ kenter(",%u,%u,,%zu", type, headerlen, datalen); -+ -+ if (ctx->subtype) { -+ kleave(" = -ENOKEY [already]"); -+ return -EBADMSG; -+ } -+ -+ key = kzalloc(sizeof(struct public_key), GFP_KERNEL); -+ if (!key) -+ return -ENOMEM; -+ -+ ret = pgp_parse_public_key(&data, &datalen, &pgp); -+ if (ret < 0) -+ goto cleanup; -+ -+ if (pgp.pubkey_algo >= PGP_PUBKEY__LAST || -+ !pgp_public_key_algorithms[pgp.pubkey_algo]) { -+ pr_debug("Unsupported public key algorithm %u\n", -+ pgp.pubkey_algo); -+ ret = -ENOPKG; -+ goto cleanup; -+ } -+ -+ algo = key->algo = pgp_public_key_algorithms[pgp.pubkey_algo]; -+ -+ /* It's a public key, so that only gives us encrypt and verify -+ * capabilities. -+ */ -+ key->capabilities = pgp_public_key_capabilities[pgp.pubkey_algo] & -+ (PKEY_CAN_ENCRYPT | PKEY_CAN_VERIFY); -+ -+ for (i = 0; i < algo->n_pub_mpi; i++) { -+ unsigned int remaining = datalen; -+ if (remaining == 0) { -+ pr_debug("short %zu mpi %d\n", datalen, i); -+ goto cleanup_badmsg; -+ } -+ key->mpi[i] = mpi_read_from_buffer(data, &remaining); -+ if (!key->mpi[i]) -+ goto cleanup_nomem; -+ data += remaining; -+ datalen -= remaining; -+ } -+ -+ if (datalen != 0) { -+ pr_debug("excess %zu\n", datalen); -+ goto cleanup_badmsg; -+ } -+ -+ ret = pgp_generate_fingerprint(ctx, &pgp, key); -+ if (ret < 0) -+ goto cleanup; -+ -+ /* We're pinning the module by being linked against it */ -+ __module_get(public_key_crypto_key_subtype.owner); -+ ctx->subtype = &public_key_crypto_key_subtype; -+ ctx->payload = key; -+ kleave(" = 0 [use]"); -+ return 0; -+ -+cleanup_nomem: -+ ret = -ENOMEM; -+ goto cleanup; -+cleanup_badmsg: -+ ret = -EBADMSG; -+cleanup: -+ pr_devel("cleanup"); -+ if (key) { -+ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) -+ mpi_free(key->mpi[i]); -+ kfree(key); -+ } -+ kleave(" = %d", ret); -+ return ret; -+} -+ -+/* -+ * Attempt to parse the instantiation data blob for a key as a PGP packet -+ * message holding a key. -+ */ -+static int pgp_key_instantiate(struct key *key, -+ const void *data, size_t datalen) -+{ -+ struct pgp_key_data_parse_context ctx; -+ int ret; -+ -+ kenter(""); -+ -+ ret = key_payload_reserve(key, datalen); -+ if (ret < 0) -+ return ret; -+ -+ ctx.pgp.types_of_interest = -+ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY); -+ ctx.pgp.process_packet = pgp_process_public_key; -+ ctx.subtype = NULL; -+ ctx.fingerprint = NULL; -+ ctx.payload = NULL; -+ -+ ret = pgp_parse_packets(data, datalen, &ctx.pgp); -+ if (ret < 0) { -+ if (ctx.payload) -+ ctx.subtype->destroy(ctx.payload); -+ if (ctx.subtype) -+ module_put(ctx.subtype->owner); -+ kfree(ctx.fingerprint); -+ key_payload_reserve(key, 0); -+ return ret; -+ } -+ -+ key->type_data.p[0] = ctx.subtype; -+ key->type_data.p[1] = ctx.fingerprint; -+ key->payload.data = ctx.payload; -+ return 0; -+} -+ -+static struct crypto_key_parser pgp_key_parser = { -+ .owner = THIS_MODULE, -+ .name = "pgp", -+ .instantiate = pgp_key_instantiate, -+}; -+ -+/* -+ * Module stuff -+ */ -+static int __init pgp_key_init(void) -+{ -+ return register_crypto_key_parser(&pgp_key_parser); -+} -+ -+static void __exit pgp_key_exit(void) -+{ -+ unregister_crypto_key_parser(&pgp_key_parser); -+} -+ -+module_init(pgp_key_init); -+module_exit(pgp_key_exit); --- -1.7.10.4 - - -From 14191eaae2f9ccba2563a4bf9c30ffcbf153f521 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:22:19 +0100 -Subject: [PATCH 12/27] 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 -public-key algorithm agnostic. The public-key verification algorithm itself -is just the last little bit and is supplied the complete hash data to process. - -This requires glue logic putting on top to make use of it - something the next -patch provides. - -Signed-off-by: David Howells ---- - security/keys/crypto/Makefile | 3 +- - security/keys/crypto/pgp_parser.h | 6 + - security/keys/crypto/pgp_sig_verify.c | 325 +++++++++++++++++++++++++++++++++ - 3 files changed, 333 insertions(+), 1 deletion(-) - create mode 100644 security/keys/crypto/pgp_sig_verify.c - -diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile -index 35733fc..0c8b8a1 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_key_parser.o - pgp_key_parser-y := \ -- pgp_public_key.o -+ pgp_public_key.o \ -+ pgp_sig_verify.o -diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h -index 1cda231..a6192ce 100644 ---- a/security/keys/crypto/pgp_parser.h -+++ b/security/keys/crypto/pgp_parser.h -@@ -21,3 +21,9 @@ - */ - extern const - struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; -+ -+/* -+ * pgp_pubkey_sig.c -+ */ -+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/crypto/pgp_sig_verify.c b/security/keys/crypto/pgp_sig_verify.c -new file mode 100644 -index 0000000..82c89da ---- /dev/null -+++ b/security/keys/crypto/pgp_sig_verify.c -@@ -0,0 +1,325 @@ -+/* PGP public key signature verification [RFC 4880] -+ * -+ * 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. -+ */ -+ -+#define pr_fmt(fmt) "PGPSIG: "fmt -+#include -+#include -+#include -+#include -+#include -+#include "public_key.h" -+#include "pgp_parser.h" -+ -+static const struct { -+ enum pkey_hash_algo algo : 8; -+} pgp_pubkey_hash[PGP_HASH__LAST] = { -+ [PGP_HASH_MD5].algo = PKEY_HASH_MD5, -+ [PGP_HASH_SHA1].algo = PKEY_HASH_SHA1, -+ [PGP_HASH_RIPE_MD_160].algo = PKEY_HASH_RIPE_MD_160, -+ [PGP_HASH_SHA256].algo = PKEY_HASH_SHA256, -+ [PGP_HASH_SHA384].algo = PKEY_HASH_SHA384, -+ [PGP_HASH_SHA512].algo = PKEY_HASH_SHA512, -+ [PGP_HASH_SHA224].algo = PKEY_HASH_SHA224, -+}; -+ -+static int pgp_pkey_verify_sig_add_data(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen); -+static int pgp_pkey_verify_sig_end(struct crypto_key_verify_context *ctx, -+ const u8 *sig, size_t siglen); -+static void pgp_pkey_verify_sig_cancel(struct crypto_key_verify_context *ctx); -+ -+struct pgp_pkey_sig_parse_context { -+ struct pgp_parse_context pgp; -+ struct pgp_sig_parameters params; -+}; -+ -+static int pgp_pkey_parse_signature(struct pgp_parse_context *context, -+ enum pgp_packet_tag type, -+ u8 headerlen, -+ const u8 *data, -+ size_t datalen) -+{ -+ struct pgp_pkey_sig_parse_context *ctx = -+ container_of(context, struct pgp_pkey_sig_parse_context, pgp); -+ -+ return pgp_parse_sig_params(&data, &datalen, &ctx->params); -+} -+ -+/* -+ * Begin the process of verifying a DSA signature. -+ * -+ * This involves allocating the hash into which first the data and then the -+ * metadata will be put, and parsing the signature to check that it matches the -+ * key. -+ */ -+struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( -+ struct key *crypto_key, const u8 *sigdata, size_t siglen) -+{ -+ struct pgp_pkey_sig_parse_context p; -+ struct public_key_signature *sig; -+ struct crypto_shash *tfm; -+ const struct public_key *key = crypto_key->payload.data; -+ size_t digest_size, desc_size; -+ int ret; -+ -+ kenter("{%d},,%zu", key_serial(crypto_key), siglen); -+ -+ if (!key) { -+ kleave(" = -ENOKEY [no public key]"); -+ return ERR_PTR(-ENOKEY); -+ } -+ -+ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); -+ p.pgp.process_packet = pgp_pkey_parse_signature; -+ ret = pgp_parse_packets(sigdata, siglen, &p.pgp); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ if (p.params.pubkey_algo >= PGP_PUBKEY__LAST || -+ !pgp_public_key_algorithms[p.params.pubkey_algo]) { -+ pr_debug("Unsupported public key algorithm %u\n", -+ p.params.pubkey_algo); -+ return ERR_PTR(-ENOPKG); -+ } -+ -+ if (pgp_public_key_algorithms[p.params.pubkey_algo] != key->algo) { -+ kleave(" = -EKEYREJECTED [wrong pk algo]"); -+ return ERR_PTR(-EKEYREJECTED); -+ } -+ -+ if (!(key->capabilities & PKEY_CAN_VERIFY)) { -+ kleave(" = -EKEYREJECTED [key can't verify]"); -+ return ERR_PTR(-EKEYREJECTED); -+ } -+ -+ if (p.params.hash_algo >= PGP_HASH__LAST || -+ !pgp_hash_algorithms[p.params.hash_algo]) { -+ pr_debug("Unsupported hash algorithm %u\n", -+ p.params.hash_algo); -+ return ERR_PTR(-ENOPKG); -+ } -+ -+ pr_debug("Signature generated with %s hash\n", -+ pgp_hash_algorithms[p.params.hash_algo]); -+ -+ if (memcmp(&p.params.issuer, key->key_id, 8) != 0) { -+ kleave(" = -ENOKEY [wrong key ID]"); -+ return ERR_PTR(-ENOKEY); -+ } -+ -+ if (p.params.signature_type != PGP_SIG_BINARY_DOCUMENT_SIG && -+ p.params.signature_type != PGP_SIG_STANDALONE_SIG) { -+ /* We don't want to canonicalise */ -+ kleave(" = -EOPNOTSUPP [canon]"); -+ return ERR_PTR(-EOPNOTSUPP); -+ } -+ -+ /* Allocate the hashing algorithm we're going to need and find out how -+ * big the hash operational data will be. -+ */ -+ tfm = crypto_alloc_shash(pgp_hash_algorithms[p.params.hash_algo], 0, 0); -+ if (IS_ERR(tfm)) -+ return PTR_ERR(tfm) == -ENOENT ? -+ ERR_PTR(-ENOPKG) : ERR_CAST(tfm); -+ -+ desc_size = crypto_shash_descsize(tfm); -+ digest_size = crypto_shash_digestsize(tfm); -+ -+ /* We allocate the hash operational data storage on the end of our -+ * context data. -+ */ -+ sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); -+ if (!sig) { -+ crypto_free_shash(tfm); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ sig->base.key = crypto_key; -+ sig->base.add_data = pgp_pkey_verify_sig_add_data; -+ sig->base.end = pgp_pkey_verify_sig_end; -+ sig->base.cancel = pgp_pkey_verify_sig_cancel; -+ sig->pkey_hash_algo = pgp_pubkey_hash[p.params.hash_algo].algo; -+ sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; -+ sig->digest_size = digest_size; -+ sig->hash.tfm = tfm; -+ sig->hash.flags = CRYPTO_TFM_REQ_MAY_SLEEP; -+ -+ ret = crypto_shash_init(&sig->hash); -+ if (ret < 0) { -+ crypto_free_shash(sig->hash.tfm); -+ kfree(sig); -+ return ERR_PTR(ret); -+ } -+ -+ key_get(sig->base.key); -+ kleave(" = %p", sig); -+ return &sig->base; -+} -+ -+/* -+ * Load data into the hash -+ */ -+static int pgp_pkey_verify_sig_add_data(struct crypto_key_verify_context *ctx, -+ const void *data, size_t datalen) -+{ -+ struct public_key_signature *sig = -+ container_of(ctx, struct public_key_signature, base); -+ -+ return crypto_shash_update(&sig->hash, data, datalen); -+} -+ -+struct pgp_pkey_sig_digest_context { -+ struct pgp_parse_context pgp; -+ const struct public_key *key; -+ struct public_key_signature *sig; -+}; -+ -+/* -+ * Extract required metadata from the signature packet and add what we need to -+ * to the hash. -+ */ -+static int pgp_pkey_digest_signature(struct pgp_parse_context *context, -+ enum pgp_packet_tag type, -+ u8 headerlen, -+ const u8 *data, -+ size_t datalen) -+{ -+ struct pgp_pkey_sig_digest_context *ctx = -+ container_of(context, struct pgp_pkey_sig_digest_context, pgp); -+ enum pgp_signature_version version; -+ int i; -+ -+ kenter(",%u,%u,,%zu", type, headerlen, datalen); -+ -+ version = *data; -+ if (version == PGP_SIG_VERSION_3) { -+ /* We just include an excerpt of the metadata from a V3 -+ * signature. -+ */ -+ crypto_shash_update(&ctx->sig->hash, data + 1, 5); -+ data += sizeof(struct pgp_signature_v3_packet); -+ datalen -= sizeof(struct pgp_signature_v3_packet); -+ } else if (version == PGP_SIG_VERSION_4) { -+ /* We add the whole metadata header and some of the hashed data -+ * for a V4 signature, plus a trailer. -+ */ -+ size_t hashedsz, unhashedsz; -+ u8 trailer[6]; -+ -+ hashedsz = 4 + 2 + (data[4] << 8) + data[5]; -+ crypto_shash_update(&ctx->sig->hash, data, hashedsz); -+ -+ trailer[0] = version; -+ trailer[1] = 0xffU; -+ trailer[2] = hashedsz >> 24; -+ trailer[3] = hashedsz >> 16; -+ trailer[4] = hashedsz >> 8; -+ trailer[5] = hashedsz; -+ -+ crypto_shash_update(&ctx->sig->hash, trailer, 6); -+ data += hashedsz; -+ datalen -= hashedsz; -+ -+ unhashedsz = 2 + (data[0] << 8) + data[1]; -+ data += unhashedsz; -+ datalen -= unhashedsz; -+ } -+ -+ if (datalen <= 2) { -+ kleave(" = -EBADMSG"); -+ return -EBADMSG; -+ } -+ -+ /* There's a quick check on the hash available. */ -+ ctx->sig->signed_hash_msw[0] = *data++; -+ ctx->sig->signed_hash_msw[1] = *data++; -+ datalen -= 2; -+ -+ /* And then the cryptographic data, which we'll need for the -+ * algorithm. -+ */ -+ for (i = 0; i < ctx->key->algo->n_sig_mpi; i++) { -+ unsigned int remaining = datalen; -+ if (remaining == 0) { -+ pr_debug("short %zu mpi %d\n", datalen, i); -+ return -EBADMSG; -+ } -+ ctx->sig->mpi[i] = mpi_read_from_buffer(data, &remaining); -+ if (!ctx->sig->mpi[i]) -+ return -ENOMEM; -+ data += remaining; -+ datalen -= remaining; -+ } -+ -+ if (datalen != 0) { -+ kleave(" = -EBADMSG [trailer %zu]", datalen); -+ return -EBADMSG; -+ } -+ -+ kleave(" = 0"); -+ return 0; -+} -+ -+/* -+ * The data is now all loaded into the hash; load the metadata, finalise the -+ * hash and perform the verification step. -+ */ -+static int pgp_pkey_verify_sig_end(struct crypto_key_verify_context *ctx, -+ const u8 *sigdata, size_t siglen) -+{ -+ struct public_key_signature *sig = -+ container_of(ctx, struct public_key_signature, base); -+ const struct public_key *key = sig->base.key->payload.data; -+ struct pgp_pkey_sig_digest_context p; -+ int ret; -+ -+ kenter(""); -+ -+ /* Firstly we add metadata, starting with some of the data from the -+ * signature packet */ -+ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); -+ p.pgp.process_packet = pgp_pkey_digest_signature; -+ p.key = key; -+ p.sig = sig; -+ ret = pgp_parse_packets(sigdata, siglen, &p.pgp); -+ if (ret < 0) -+ goto error_free_ctx; -+ -+ crypto_shash_final(&sig->hash, sig->digest); -+ -+ ret = key->algo->verify(key, sig); -+ -+error_free_ctx: -+ pgp_pkey_verify_sig_cancel(ctx); -+ kleave(" = %d", ret); -+ return ret; -+} -+ -+/* -+ * Cancel an in-progress data loading -+ */ -+static void pgp_pkey_verify_sig_cancel(struct crypto_key_verify_context *ctx) -+{ -+ struct public_key_signature *sig = -+ container_of(ctx, struct public_key_signature, base); -+ int i; -+ -+ kenter(""); -+ -+ /* !!! Do we need to tell the crypto layer to cancel too? */ -+ crypto_free_shash(sig->hash.tfm); -+ key_put(sig->base.key); -+ for (i = 0; i < ARRAY_SIZE(sig->mpi); i++) -+ mpi_free(sig->mpi[i]); -+ kfree(sig); -+ -+ kleave(""); -+} --- -1.7.10.4 - - -From 3ca6d54c9bbd0633b7f8e1b033c7d8b2ebe85489 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:22:40 +0100 -Subject: [PATCH 13/27] 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 -and set the public-key algorithm according to the data in the signature. - -Signed-off-by: David Howells ---- - security/keys/crypto/Makefile | 1 + - security/keys/crypto/pgp_parser.h | 6 ++ - security/keys/crypto/pgp_public_key.c | 1 + - security/keys/crypto/pgp_sig_parser.c | 114 +++++++++++++++++++++++++++++++++ - 4 files changed, 122 insertions(+) - create mode 100644 security/keys/crypto/pgp_sig_parser.c - -diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile -index 0c8b8a1..a9a34c6 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_key_parser.o - pgp_key_parser-y := \ - pgp_public_key.o \ -+ pgp_sig_parser.o \ - pgp_sig_verify.o -diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h -index a6192ce..73c900e 100644 ---- 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]; - - /* -+ * pgp_sig_parser.c -+ */ -+extern struct crypto_key_verify_context *pgp_verify_sig_begin( -+ struct key *keyring, const u8 *sig, size_t siglen); -+ -+/* - * pgp_pubkey_sig.c - */ - extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( -diff --git a/security/keys/crypto/pgp_public_key.c b/security/keys/crypto/pgp_public_key.c -index 8a8b7c0..5ab926d 100644 ---- a/security/keys/crypto/pgp_public_key.c -+++ b/security/keys/crypto/pgp_public_key.c -@@ -329,6 +329,7 @@ static struct crypto_key_parser pgp_key_parser = { - .owner = THIS_MODULE, - .name = "pgp", - .instantiate = pgp_key_instantiate, -+ .verify_sig_begin = pgp_verify_sig_begin, - }; - - /* -diff --git a/security/keys/crypto/pgp_sig_parser.c b/security/keys/crypto/pgp_sig_parser.c -new file mode 100644 -index 0000000..f5feb2b ---- /dev/null -+++ b/security/keys/crypto/pgp_sig_parser.c -@@ -0,0 +1,114 @@ -+/* Handling for PGP public key signature data [RFC 4880] -+ * -+ * 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. -+ */ -+ -+#define pr_fmt(fmt) "PGPSIG: "fmt -+#include -+#include -+#include -+#include -+#include "public_key.h" -+#include "pgp_parser.h" -+ -+struct PGP_sig_parse_context { -+ struct pgp_parse_context pgp; -+ struct pgp_sig_parameters params; -+ bool found_sig; -+}; -+ -+/* -+ * Look inside signature sections for a key ID -+ */ -+static int pgp_process_signature(struct pgp_parse_context *context, -+ enum pgp_packet_tag type, -+ u8 headerlen, -+ const u8 *data, -+ size_t datalen) -+{ -+ struct PGP_sig_parse_context *ctx = -+ container_of(context, struct PGP_sig_parse_context, pgp); -+ -+ ctx->found_sig = true; -+ return pgp_parse_sig_params(&data, &datalen, &ctx->params); -+} -+ -+/* -+ * Attempt to find a key to use for PGP signature verification, starting off by -+ * looking in the supplied keyring. -+ * -+ * The function may also look for other key sources such as a TPM. If an -+ * alternative key is found it can be added to the keyring for future -+ * reference. -+ */ -+static struct key *find_key_for_pgp_sig(struct key *keyring, -+ const u8 *sig, size_t siglen) -+{ -+ struct PGP_sig_parse_context p; -+ key_ref_t key; -+ char criterion[3 + 8 * 2 + 1]; -+ int ret; -+ -+ if (!keyring) -+ return ERR_PTR(-ENOKEY); -+ -+ /* Need to find the key ID */ -+ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); -+ p.pgp.process_packet = pgp_process_signature; -+ p.found_sig = false; -+ ret = pgp_parse_packets(sig, siglen, &p.pgp); -+ if (ret < 0) -+ return ERR_PTR(ret); -+ -+ if (!p.found_sig) -+ return ERR_PTR(-ENOMSG); -+ -+ sprintf(criterion, "id:%08x%08x", -+ be32_to_cpu(p.params.issuer32[0]), -+ be32_to_cpu(p.params.issuer32[1])); -+ -+ pr_debug("Look up: %s\n", criterion); -+ -+ key = keyring_search(make_key_ref(keyring, 1), -+ &key_type_crypto, criterion); -+ 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); -+} -+ -+/* -+ * Attempt to parse a signature as a PGP packet format blob and find a -+ * matching key. -+ */ -+struct crypto_key_verify_context *pgp_verify_sig_begin( -+ struct key *keyring, const u8 *sig, size_t siglen) -+{ -+ struct crypto_key_verify_context *ctx; -+ struct key *key; -+ -+ key = find_key_for_pgp_sig(keyring, sig, siglen); -+ if (IS_ERR(key)) -+ return ERR_CAST(key); -+ -+ /* We only handle in-kernel public key signatures for the moment */ -+ ctx = pgp_pkey_verify_sig_begin(key, sig, siglen); -+ key_put(key); -+ return ctx; -+} --- -1.7.10.4 - - -From 30a028f485bd476ef3ad73fbb042a55b4851c966 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:22:59 +0100 -Subject: [PATCH 14/27] 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: - - int load_PGP_keys(const u8 *pgpdata, size_t pgpdatalen, - struct key *keyring, const char *descprefix); - -The keys are labelled with descprefix plus a number to uniquify them. The keys -will actually be identified by the ID calculated from the PGP data rather than -by the description, so this shouldn't be a problem. - -The keys are attached to the keyring supplied. - -Looking as root in /proc/keys after the module signing keyring has been loaded: - -24460d1c I----- 1 perm 3f010000 0 0 crypto modsign.0: dsa 5acc2142 [] -3ca85723 I----- 1 perm 1f010000 0 0 keyring .module_sign: 1/4 - -Thanks to Tetsuo Handa for some pointing -out some errors. - -Signed-off-by: David Howells ---- - Documentation/security/keys-crypto.txt | 20 +++++++ - include/keys/crypto-type.h | 3 + - security/keys/crypto/Kconfig | 9 +++ - security/keys/crypto/Makefile | 1 + - security/keys/crypto/pgp_preload.c | 96 ++++++++++++++++++++++++++++++++ - 5 files changed, 129 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 ---- a/Documentation/security/keys-crypto.txt -+++ b/Documentation/security/keys-crypto.txt -@@ -10,6 +10,7 @@ Contents: - - Signature verification. - - Implementing crypto parsers. - - Implementing crypto subtypes. -+ - Initial PGP key preloading. - - - ======== -@@ -280,3 +281,22 @@ There are a number of operations defined by the subtype: - Mandatory. This should free the memory associated with the key. The - crypto key will look after freeing the fingerprint and releasing the - reference on the subtype module. -+ -+ -+======================= -+INITIAL PGP KEY LOADING -+======================= -+ -+A function is provided to perform an initial load of a set of public keys bound -+into a PGP packet format blob: -+ -+ int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, -+ struct key *keyring, const char *descprefix); -+ -+This takes the blob of data defined by pgpdata and pgpdatalen, extracts keys -+from them and adds them to the specified keyring. The keys are labelled with -+descprefix plus a simple uniquifier - it is not expected that the description -+will be used to identify the key. The description is required to prevent all -+but the last key being discarded when the keys are linked into the keyring. -+ -+This function is only available during initial kernel set up. -diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h -index 6b93366..710e77f 100644 ---- a/include/keys/crypto-type.h -+++ b/include/keys/crypto-type.h -@@ -31,4 +31,7 @@ extern void verify_sig_cancel(struct crypto_key_verify_context *ctx); - * The payload is at the discretion of the subtype. - */ - -+extern __init int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, -+ struct key *keyring, const char *descprefix); -+ - #endif /* _KEYS_CRYPTO_TYPE_H */ -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. -+ -+config PGP_PRELOAD -+ bool "PGP public key preloading facility" -+ select PGP_LIBRARY -+ select CRYPTO_KEY_PGP_PARSER -+ help -+ 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/crypto/Makefile b/security/keys/crypto/Makefile -index a9a34c6..c873674 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_key_parser.o - pgp_key_parser-y := \ -diff --git a/security/keys/crypto/pgp_preload.c b/security/keys/crypto/pgp_preload.c -new file mode 100644 -index 0000000..9028788 ---- /dev/null -+++ b/security/keys/crypto/pgp_preload.c -@@ -0,0 +1,96 @@ -+/* Cryptographic key request handling -+ * -+ * 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. -+ * -+ * See Documentation/security/keys-crypto.txt -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "crypto_keys.h" -+ -+struct preload_pgp_keys_context { -+ struct pgp_parse_context pgp; -+ key_ref_t keyring; -+ char descbuf[20]; -+ u8 key_n; -+ u8 dsize; -+}; -+ -+/* -+ * Extract a public key or subkey from the PGP stream. -+ */ -+static int __init found_pgp_key(struct pgp_parse_context *context, -+ enum pgp_packet_tag type, u8 headerlen, -+ const u8 *data, size_t datalen) -+{ -+ struct preload_pgp_keys_context *ctx = -+ container_of(context, struct preload_pgp_keys_context, pgp); -+ key_ref_t key; -+ -+ if (ctx->key_n >= 255) -+ return 0; /* Don't overrun descbuf */ -+ -+ sprintf(ctx->descbuf + ctx->dsize, "%d", ctx->key_n++); -+ -+ key = key_create_or_update(ctx->keyring, "crypto", ctx->descbuf, -+ data - headerlen, datalen + headerlen, -+ KEY_POS_ALL | KEY_USR_VIEW, -+ KEY_ALLOC_NOT_IN_QUOTA); -+ -+ if (IS_ERR(key)) -+ return PTR_ERR(key); -+ -+ pr_notice("Loaded %s key: %s\n", -+ key_ref_to_ptr(key)->description, -+ crypto_key_id(key_ref_to_ptr(key))); -+ -+ key_ref_put(key); -+ return 0; -+} -+ -+/** -+ * preload_pgp_keys - Load keys from a PGP keyring blob -+ * @pgpdata: The PGP keyring blob containing the keys. -+ * @pgpdatalen: The size of the @pgpdata blob. -+ * @keyring: The keyring to add the new keys to. -+ * @descprefix: The key description prefix. -+ * -+ * Preload a pack of keys from a PGP keyring blob. -+ * -+ * The keys are given description of @descprefix + the number of the key in the -+ * list. Since keys can be matched on their key IDs independently of the key -+ * description, the description is mostly irrelevant apart from the fact that -+ * keys of the same description displace one another from a keyring. -+ * -+ * The caller should override the current creds if they want the keys to be -+ * owned by someone other than the current process's owner. Keys will not be -+ * accounted towards the owner's quota. -+ * -+ * This function may only be called whilst the kernel is booting. -+ */ -+int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, -+ struct key *keyring, const char *descprefix) -+{ -+ struct preload_pgp_keys_context ctx; -+ -+ ctx.pgp.types_of_interest = -+ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY); -+ ctx.pgp.process_packet = found_pgp_key; -+ ctx.keyring = make_key_ref(keyring, 1); -+ ctx.key_n = 0; -+ ctx.dsize = strlen(descprefix); -+ BUG_ON(ctx.dsize > sizeof(ctx.descbuf) - 4); -+ strcpy(ctx.descbuf, descprefix); -+ -+ return pgp_parse_packets(pgpdata, pgpdatalen, &ctx.pgp); -+} --- -1.7.10.4 - - -From 13b8bd0afb58d1000c74741f176862efb6d1bcc9 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:25:41 +0100 -Subject: [PATCH 15/27] Make most arch asm/module.h files use - asm-generic/module.h - -Use the mapping of Elf_[SPE]hdr, Elf_Addr, Elf_Sym, Elf_Dyn, Elf_Rel/Rela, -ELF_R_TYPE() and ELF_R_SYM() to either the 32-bit version or the 64-bit version -into asm-generic/module.h for all arches bar MIPS. - -Also, use the generic definition mod_arch_specific where possible. - -To this end, I've defined three new config bools: - - (*) HAVE_MOD_ARCH_SPECIFIC - - Arches define this if they don't want to use the empty generic - mod_arch_specific struct. - - (*) MODULES_USE_ELF_RELA - - Arches define this if their modules can contain RELA records. This causes - the Elf_Rela mapping to be emitted and allows apply_relocate_add() to be - defined by the arch rather than have the core emit an error message. - - (*) MODULES_USE_ELF_REL - - Arches define this if their modules can contain REL records. This causes - the Elf_Rel mapping to be emitted and allows apply_relocate() to be - defined by the arch rather than have the core emit an error message. - -Note that it is possible to allow both REL and RELA records: m68k and mips are -two arches that do this. - -With this, some arch asm/module.h files can be deleted entirely and replaced -with a generic-y marker in the arch Kbuild file. - -Additionally, I have removed the bits from m32r and score that handle the -unsupported type of relocation record as that's now handled centrally. - -Signed-off-by: David Howells ---- - arch/Kconfig | 19 +++++++++++++++++ - arch/alpha/Kconfig | 2 ++ - arch/alpha/include/asm/module.h | 10 ++------- - arch/arm/Kconfig | 2 ++ - arch/arm/include/asm/module.h | 8 ++------ - arch/avr32/Kconfig | 2 ++ - arch/avr32/include/asm/module.h | 6 ++---- - arch/blackfin/Kconfig | 2 ++ - arch/blackfin/include/asm/module.h | 4 +--- - arch/c6x/Kconfig | 1 + - arch/c6x/include/asm/module.h | 12 +---------- - arch/cris/Kconfig | 1 + - arch/cris/include/asm/Kbuild | 2 ++ - arch/cris/include/asm/module.h | 9 -------- - arch/frv/include/asm/module.h | 8 +------- - arch/h8300/Kconfig | 1 + - arch/h8300/include/asm/Kbuild | 2 ++ - arch/h8300/include/asm/module.h | 11 ---------- - arch/hexagon/Kconfig | 1 + - arch/ia64/Kconfig | 2 ++ - arch/ia64/include/asm/module.h | 6 ++---- - arch/m32r/Kconfig | 1 + - arch/m32r/include/asm/Kbuild | 2 ++ - arch/m32r/include/asm/module.h | 10 --------- - arch/m32r/kernel/module.c | 15 -------------- - arch/m68k/Kconfig | 3 +++ - arch/m68k/include/asm/module.h | 6 ++---- - arch/microblaze/Kconfig | 1 + - arch/mips/Kconfig | 3 +++ - arch/mips/include/asm/module.h | 10 +++++++-- - arch/mips/kernel/module.c | 2 ++ - arch/mn10300/Kconfig | 1 + - arch/mn10300/include/asm/module.h | 7 +------ - arch/openrisc/Kconfig | 1 + - arch/parisc/Kconfig | 2 ++ - arch/parisc/include/asm/module.h | 16 +++------------ - arch/powerpc/Kconfig | 2 ++ - arch/powerpc/include/asm/module.h | 7 +------ - arch/s390/Kconfig | 2 ++ - arch/s390/include/asm/module.h | 18 +++------------- - arch/score/Kconfig | 2 ++ - arch/score/include/asm/module.h | 6 +----- - arch/score/kernel/module.c | 10 --------- - arch/sh/Kconfig | 2 ++ - arch/sh/include/asm/module.h | 14 +++---------- - arch/sparc/Kconfig | 1 + - arch/sparc/include/asm/Kbuild | 1 + - arch/sparc/include/asm/module.h | 24 ---------------------- - arch/tile/Kconfig | 1 + - arch/unicore32/Kconfig | 1 + - arch/x86/Kconfig | 2 ++ - arch/xtensa/Kconfig | 1 + - arch/xtensa/include/asm/module.h | 9 +------- - include/asm-generic/module.h | 40 +++++++++++++++++++++++++++++------- - include/linux/moduleloader.h | 36 ++++++++++++++++++++++++++++---- - kernel/module.c | 20 ------------------ - 56 files changed, 167 insertions(+), 223 deletions(-) - delete mode 100644 arch/cris/include/asm/module.h - delete mode 100644 arch/h8300/include/asm/module.h - delete mode 100644 arch/m32r/include/asm/module.h - delete mode 100644 arch/sparc/include/asm/module.h - -diff --git a/arch/Kconfig b/arch/Kconfig -index 8c3d957..51acb02 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -274,4 +274,23 @@ config SECCOMP_FILTER - - See Documentation/prctl/seccomp_filter.txt for details. - -+config HAVE_MOD_ARCH_SPECIFIC -+ bool -+ help -+ The arch uses struct mod_arch_specific to store data. Many arches -+ just need a simple module loader without arch specific data - those -+ should not enable this. -+ -+config MODULES_USE_ELF_RELA -+ bool -+ help -+ Modules only use ELF RELA relocations. Modules with ELF REL -+ relocations will give an error. -+ -+config MODULES_USE_ELF_REL -+ bool -+ help -+ Modules only use ELF REL relocations. Modules with ELF RELA -+ relocations will give an error. -+ - source "kernel/gcov/Kconfig" -diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig -index 3de74c9..6f580de 100644 ---- a/arch/alpha/Kconfig -+++ b/arch/alpha/Kconfig -@@ -17,6 +17,8 @@ config ALPHA - select ARCH_HAVE_NMI_SAFE_CMPXCHG - select GENERIC_SMP_IDLE_THREAD - select GENERIC_CMOS_UPDATE -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - help - The Alpha is a 64-bit general-purpose processor designed and - marketed by the Digital Equipment Corporation of blessed memory, -diff --git a/arch/alpha/include/asm/module.h b/arch/alpha/include/asm/module.h -index 7b63743..9cd13b5 100644 ---- a/arch/alpha/include/asm/module.h -+++ b/arch/alpha/include/asm/module.h -@@ -1,19 +1,13 @@ - #ifndef _ALPHA_MODULE_H - #define _ALPHA_MODULE_H - -+#include -+ - struct mod_arch_specific - { - unsigned int gotsecindex; - }; - --#define Elf_Sym Elf64_Sym --#define Elf_Shdr Elf64_Shdr --#define Elf_Ehdr Elf64_Ehdr --#define Elf_Phdr Elf64_Phdr --#define Elf_Dyn Elf64_Dyn --#define Elf_Rel Elf64_Rel --#define Elf_Rela Elf64_Rela -- - #define ARCH_SHF_SMALL SHF_ALPHA_GPREL - - #ifdef MODULE -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index a91009c..af8bf36 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -45,6 +45,8 @@ config ARM - select GENERIC_SMP_IDLE_THREAD - select KTIME_SCALAR - select GENERIC_CLOCKEVENTS_BROADCAST if SMP -+ select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND -+ select MODULES_USE_ELF_REL - help - The ARM series is a line of low-power-consumption RISC chip designs - licensed by ARM Ltd and targeted at embedded applications and -diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h -index 6c6809f..0d3a28d 100644 ---- a/arch/arm/include/asm/module.h -+++ b/arch/arm/include/asm/module.h -@@ -1,9 +1,7 @@ - #ifndef _ASM_ARM_MODULE_H - #define _ASM_ARM_MODULE_H - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -+#include - - struct unwind_table; - -@@ -16,13 +14,11 @@ enum { - ARM_SEC_DEVEXIT, - ARM_SEC_MAX, - }; --#endif - - struct mod_arch_specific { --#ifdef CONFIG_ARM_UNWIND - struct unwind_table *unwind[ARM_SEC_MAX]; --#endif - }; -+#endif - - /* - * Add the ARM architecture version to the version magic string -diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig -index 71d38c7..2779913 100644 ---- a/arch/avr32/Kconfig -+++ b/arch/avr32/Kconfig -@@ -14,6 +14,8 @@ config AVR32 - select ARCH_HAVE_CUSTOM_GPIO_H - select ARCH_HAVE_NMI_SAFE_CMPXCHG - select GENERIC_CLOCKEVENTS -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - help - AVR32 is a high-performance 32-bit RISC microprocessor core, - designed for cost-sensitive embedded applications, with particular -diff --git a/arch/avr32/include/asm/module.h b/arch/avr32/include/asm/module.h -index 4514445..3f083d3 100644 ---- a/arch/avr32/include/asm/module.h -+++ b/arch/avr32/include/asm/module.h -@@ -1,6 +1,8 @@ - #ifndef __ASM_AVR32_MODULE_H - #define __ASM_AVR32_MODULE_H - -+#include -+ - struct mod_arch_syminfo { - unsigned long got_offset; - int got_initialized; -@@ -17,10 +19,6 @@ struct mod_arch_specific { - struct mod_arch_syminfo *syminfo; - }; - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -- - #define MODULE_PROC_FAMILY "AVR32v1" - - #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY -diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig -index fef96f4..b8a7bc9 100644 ---- a/arch/blackfin/Kconfig -+++ b/arch/blackfin/Kconfig -@@ -40,6 +40,8 @@ config BLACKFIN - select HAVE_NMI_WATCHDOG if NMI_WATCHDOG - select GENERIC_SMP_IDLE_THREAD - select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - - config GENERIC_CSUM - def_bool y -diff --git a/arch/blackfin/include/asm/module.h b/arch/blackfin/include/asm/module.h -index ed5689b..231a149 100644 ---- a/arch/blackfin/include/asm/module.h -+++ b/arch/blackfin/include/asm/module.h -@@ -7,9 +7,7 @@ - #ifndef _ASM_BFIN_MODULE_H - #define _ASM_BFIN_MODULE_H - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -+#include - - struct mod_arch_specific { - Elf_Shdr *text_l1; -diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig -index 052f81a..8f3a304 100644 ---- a/arch/c6x/Kconfig -+++ b/arch/c6x/Kconfig -@@ -16,6 +16,7 @@ config C6X - select OF - select OF_EARLY_FLATTREE - select GENERIC_CLOCKEVENTS -+ select MODULES_USE_ELF_RELA - - config MMU - def_bool n -diff --git a/arch/c6x/include/asm/module.h b/arch/c6x/include/asm/module.h -index a453f97..5c7269c 100644 ---- a/arch/c6x/include/asm/module.h -+++ b/arch/c6x/include/asm/module.h -@@ -13,17 +13,7 @@ - #ifndef _ASM_C6X_MODULE_H - #define _ASM_C6X_MODULE_H - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr --#define Elf_Addr Elf32_Addr --#define Elf_Word Elf32_Word -- --/* -- * This file contains the C6x architecture specific module code. -- */ --struct mod_arch_specific { --}; -+#include - - struct loaded_sections { - unsigned int new_vaddr; -diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig -index bb34465..45782c7 100644 ---- a/arch/cris/Kconfig -+++ b/arch/cris/Kconfig -@@ -46,6 +46,7 @@ config CRIS - select GENERIC_IOMAP - select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32 - select GENERIC_CMOS_UPDATE -+ select MODULES_USE_ELF_RELA - - config HZ - int -diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild -index 04d02a5..28b690d 100644 ---- a/arch/cris/include/asm/Kbuild -+++ b/arch/cris/include/asm/Kbuild -@@ -7,3 +7,5 @@ header-y += ethernet.h - header-y += etraxgpio.h - header-y += rs485.h - header-y += sync_serial.h -+ -+generic-y += module.h -diff --git a/arch/cris/include/asm/module.h b/arch/cris/include/asm/module.h -deleted file mode 100644 -index 7ee7231..0000000 ---- a/arch/cris/include/asm/module.h -+++ /dev/null -@@ -1,9 +0,0 @@ --#ifndef _ASM_CRIS_MODULE_H --#define _ASM_CRIS_MODULE_H --/* cris is simple */ --struct mod_arch_specific { }; -- --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr --#endif /* _ASM_CRIS_MODULE_H */ -diff --git a/arch/frv/include/asm/module.h b/arch/frv/include/asm/module.h -index 3d5c636..a8848f0 100644 ---- a/arch/frv/include/asm/module.h -+++ b/arch/frv/include/asm/module.h -@@ -11,13 +11,7 @@ - #ifndef _ASM_MODULE_H - #define _ASM_MODULE_H - --struct mod_arch_specific --{ --}; -- --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -+#include - - /* - * Include the architecture version. -diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig -index 56e890d..9eaefdd 100644 ---- a/arch/h8300/Kconfig -+++ b/arch/h8300/Kconfig -@@ -5,6 +5,7 @@ config H8300 - select HAVE_GENERIC_HARDIRQS - select GENERIC_IRQ_SHOW - select GENERIC_CPU_DEVICES -+ select MODULES_USE_ELF_RELA - - config SYMBOL_PREFIX - string -diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild -index c68e168..871382d 100644 ---- a/arch/h8300/include/asm/Kbuild -+++ b/arch/h8300/include/asm/Kbuild -@@ -1 +1,3 @@ - include include/asm-generic/Kbuild.asm -+ -+generic-y += module.h -diff --git a/arch/h8300/include/asm/module.h b/arch/h8300/include/asm/module.h -deleted file mode 100644 -index 8e46724..0000000 ---- a/arch/h8300/include/asm/module.h -+++ /dev/null -@@ -1,11 +0,0 @@ --#ifndef _ASM_H8300_MODULE_H --#define _ASM_H8300_MODULE_H --/* -- * This file contains the H8/300 architecture specific module code. -- */ --struct mod_arch_specific { }; --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -- --#endif /* _ASM_H8/300_MODULE_H */ -diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig -index b2fdfb7..0744f7d 100644 ---- a/arch/hexagon/Kconfig -+++ b/arch/hexagon/Kconfig -@@ -30,6 +30,7 @@ config HEXAGON - select KTIME_SCALAR - select GENERIC_CLOCKEVENTS - select GENERIC_CLOCKEVENTS_BROADCAST -+ select MODULES_USE_ELF_RELA - ---help--- - Qualcomm Hexagon is a processor architecture designed for high - performance and low power across a wide variety of applications. -diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig -index 8186ec5..6f1b7b1 100644 ---- a/arch/ia64/Kconfig -+++ b/arch/ia64/Kconfig -@@ -39,6 +39,8 @@ config IA64 - select ARCH_THREAD_INFO_ALLOCATOR - select ARCH_CLOCKSOURCE_DATA - select GENERIC_TIME_VSYSCALL -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - default y - help - The Itanium Processor Family is Intel's 64-bit successor to -diff --git a/arch/ia64/include/asm/module.h b/arch/ia64/include/asm/module.h -index 908eaef..dfba22a 100644 ---- a/arch/ia64/include/asm/module.h -+++ b/arch/ia64/include/asm/module.h -@@ -1,6 +1,8 @@ - #ifndef _ASM_IA64_MODULE_H - #define _ASM_IA64_MODULE_H - -+#include -+ - /* - * IA-64-specific support for kernel module loader. - * -@@ -29,10 +31,6 @@ struct mod_arch_specific { - unsigned int next_got_entry; /* index of next available got entry */ - }; - --#define Elf_Shdr Elf64_Shdr --#define Elf_Sym Elf64_Sym --#define Elf_Ehdr Elf64_Ehdr -- - #define MODULE_PROC_FAMILY "ia64" - #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \ - "gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__) -diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig -index b638d5b..a30478e 100644 ---- a/arch/m32r/Kconfig -+++ b/arch/m32r/Kconfig -@@ -12,6 +12,7 @@ config M32R - select GENERIC_IRQ_SHOW - select GENERIC_ATOMIC64 - select ARCH_USES_GETTIMEOFFSET -+ select MODULES_USE_ELF_RELA - - config SBUS - bool -diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild -index c68e168..871382d 100644 ---- a/arch/m32r/include/asm/Kbuild -+++ b/arch/m32r/include/asm/Kbuild -@@ -1 +1,3 @@ - include include/asm-generic/Kbuild.asm -+ -+generic-y += module.h -diff --git a/arch/m32r/include/asm/module.h b/arch/m32r/include/asm/module.h -deleted file mode 100644 -index eb73ee0..0000000 ---- a/arch/m32r/include/asm/module.h -+++ /dev/null -@@ -1,10 +0,0 @@ --#ifndef _ASM_M32R_MODULE_H --#define _ASM_M32R_MODULE_H -- --struct mod_arch_specific { }; -- --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -- --#endif /* _ASM_M32R_MODULE_H */ -diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c -index 3071fe8..38233b6 100644 ---- a/arch/m32r/kernel/module.c -+++ b/arch/m32r/kernel/module.c -@@ -201,18 +201,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, - } - return 0; - } -- --int apply_relocate(Elf32_Shdr *sechdrs, -- const char *strtab, -- unsigned int symindex, -- unsigned int relsec, -- struct module *me) --{ --#if 0 -- printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", -- me->name); -- return -ENOEXEC; --#endif -- return 0; -- --} -diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig -index 1471201..3694301 100644 ---- a/arch/m68k/Kconfig -+++ b/arch/m68k/Kconfig -@@ -11,6 +11,9 @@ config M68K - select GENERIC_STRNLEN_USER if MMU - select FPU if MMU - select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_REL -+ select MODULES_USE_ELF_RELA - - config RWSEM_GENERIC_SPINLOCK - bool -diff --git a/arch/m68k/include/asm/module.h b/arch/m68k/include/asm/module.h -index edffe66..8b58fce 100644 ---- a/arch/m68k/include/asm/module.h -+++ b/arch/m68k/include/asm/module.h -@@ -1,6 +1,8 @@ - #ifndef _ASM_M68K_MODULE_H - #define _ASM_M68K_MODULE_H - -+#include -+ - enum m68k_fixup_type { - m68k_fixup_memoffset, - m68k_fixup_vnode_shift, -@@ -36,8 +38,4 @@ struct module; - extern void module_fixup(struct module *mod, struct m68k_fixup_info *start, - struct m68k_fixup_info *end); - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -- - #endif /* _ASM_M68K_MODULE_H */ -diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig -index 0bf4423..ee395d3 100644 ---- a/arch/microblaze/Kconfig -+++ b/arch/microblaze/Kconfig -@@ -23,6 +23,7 @@ config MICROBLAZE - select GENERIC_CPU_DEVICES - select GENERIC_ATOMIC64 - select GENERIC_CLOCKEVENTS -+ select MODULES_USE_ELF_RELA - - config SWAP - def_bool n -diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig -index 09ab87e..2901b41 100644 ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -34,6 +34,9 @@ config MIPS - select BUILDTIME_EXTABLE_SORT - select GENERIC_CLOCKEVENTS - select GENERIC_CMOS_UPDATE -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_REL -+ select MODULES_USE_ELF_RELA if 64BIT - - menu "Machine selection" - -diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h -index 5300080..2c6a4f21 100644 ---- a/arch/mips/include/asm/module.h -+++ b/arch/mips/include/asm/module.h -@@ -34,11 +34,14 @@ typedef struct { - } Elf64_Mips_Rela; - - #ifdef CONFIG_32BIT -- - #define Elf_Shdr Elf32_Shdr - #define Elf_Sym Elf32_Sym - #define Elf_Ehdr Elf32_Ehdr - #define Elf_Addr Elf32_Addr -+#define Elf_Rel Elf32_Rel -+#define Elf_Rela Elf32_Rela -+#define ELF_R_TYPE(X) ELF32_R_TYPE(X) -+#define ELF_R_SYM(X) ELF32_R_SYM(X) - - #define Elf_Mips_Rel Elf32_Rel - #define Elf_Mips_Rela Elf32_Rela -@@ -49,11 +52,14 @@ typedef struct { - #endif - - #ifdef CONFIG_64BIT -- - #define Elf_Shdr Elf64_Shdr - #define Elf_Sym Elf64_Sym - #define Elf_Ehdr Elf64_Ehdr - #define Elf_Addr Elf64_Addr -+#define Elf_Rel Elf64_Rel -+#define Elf_Rela Elf64_Rela -+#define ELF_R_TYPE(X) ELF64_R_TYPE(X) -+#define ELF_R_SYM(X) ELF64_R_SYM(X) - - #define Elf_Mips_Rel Elf64_Mips_Rel - #define Elf_Mips_Rela Elf64_Mips_Rela -diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c -index a5066b1..1500c80 100644 ---- a/arch/mips/kernel/module.c -+++ b/arch/mips/kernel/module.c -@@ -299,6 +299,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, - return 0; - } - -+#ifdef CONFIG_MODULES_USE_ELF_RELA - int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, - unsigned int symindex, unsigned int relsec, - struct module *me) -@@ -338,6 +339,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, - - return 0; - } -+#endif - - /* Given an address, look for it in the module exception tables. */ - const struct exception_table_entry *search_module_dbetables(unsigned long addr) -diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig -index 687f9b4..f8fec1c 100644 ---- a/arch/mn10300/Kconfig -+++ b/arch/mn10300/Kconfig -@@ -7,6 +7,7 @@ config MN10300 - select HAVE_ARCH_KGDB - select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER - select GENERIC_CLOCKEVENTS -+ select MODULES_USE_ELF_RELA - - config AM33_2 - def_bool n -diff --git a/arch/mn10300/include/asm/module.h b/arch/mn10300/include/asm/module.h -index 5d7057d..6571103 100644 ---- a/arch/mn10300/include/asm/module.h -+++ b/arch/mn10300/include/asm/module.h -@@ -12,12 +12,7 @@ - #ifndef _ASM_MODULE_H - #define _ASM_MODULE_H - --struct mod_arch_specific { --}; -- --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -+#include - - /* - * Include the MN10300 architecture version. -diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig -index 49765b5..05f2ba4 100644 ---- a/arch/openrisc/Kconfig -+++ b/arch/openrisc/Kconfig -@@ -21,6 +21,7 @@ config OPENRISC - select GENERIC_CLOCKEVENTS - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER -+ select MODULES_USE_ELF_RELA - - config MMU - def_bool y -diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig -index 3ff21b5..166d991 100644 ---- a/arch/parisc/Kconfig -+++ b/arch/parisc/Kconfig -@@ -19,6 +19,8 @@ config PARISC - select ARCH_HAVE_NMI_SAFE_CMPXCHG - select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - - help - The PA-RISC microprocessor is designed by Hewlett-Packard and used -diff --git a/arch/parisc/include/asm/module.h b/arch/parisc/include/asm/module.h -index 1f41234..bab37e9 100644 ---- a/arch/parisc/include/asm/module.h -+++ b/arch/parisc/include/asm/module.h -@@ -1,21 +1,11 @@ - #ifndef _ASM_PARISC_MODULE_H - #define _ASM_PARISC_MODULE_H -+ -+#include -+ - /* - * This file contains the parisc architecture specific module code. - */ --#ifdef CONFIG_64BIT --#define Elf_Shdr Elf64_Shdr --#define Elf_Sym Elf64_Sym --#define Elf_Ehdr Elf64_Ehdr --#define Elf_Addr Elf64_Addr --#define Elf_Rela Elf64_Rela --#else --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr --#define Elf_Addr Elf32_Addr --#define Elf_Rela Elf32_Rela --#endif - - struct unwind_table; - -diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig -index 050cb37..17d3267 100644 ---- a/arch/powerpc/Kconfig -+++ b/arch/powerpc/Kconfig -@@ -137,6 +137,8 @@ config PPC - select GENERIC_CLOCKEVENTS - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - - config EARLY_PRINTK - bool -diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h -index 0192a4e..c1df590 100644 ---- a/arch/powerpc/include/asm/module.h -+++ b/arch/powerpc/include/asm/module.h -@@ -11,6 +11,7 @@ - - #include - #include -+#include - - - #ifndef __powerpc64__ -@@ -60,16 +61,10 @@ struct mod_arch_specific { - */ - - #ifdef __powerpc64__ --# define Elf_Shdr Elf64_Shdr --# define Elf_Sym Elf64_Sym --# define Elf_Ehdr Elf64_Ehdr - # ifdef MODULE - asm(".section .stubs,\"ax\",@nobits; .align 3; .previous"); - # endif - #else --# define Elf_Shdr Elf32_Shdr --# define Elf_Sym Elf32_Sym --# define Elf_Ehdr Elf32_Ehdr - # ifdef MODULE - asm(".section .plt,\"ax\",@nobits; .align 3; .previous"); - asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous"); -diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig -index a39b469..7c16d31 100644 ---- a/arch/s390/Kconfig -+++ b/arch/s390/Kconfig -@@ -121,6 +121,8 @@ config S390 - select GENERIC_TIME_VSYSCALL - select GENERIC_CLOCKEVENTS - select KTIME_SCALAR if 32BIT -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_RELA - - config SCHED_OMIT_FRAME_POINTER - def_bool y -diff --git a/arch/s390/include/asm/module.h b/arch/s390/include/asm/module.h -index f0b6b26..df1f861 100644 ---- a/arch/s390/include/asm/module.h -+++ b/arch/s390/include/asm/module.h -@@ -1,5 +1,8 @@ - #ifndef _ASM_S390_MODULE_H - #define _ASM_S390_MODULE_H -+ -+#include -+ - /* - * This file contains the s390 architecture specific module code. - */ -@@ -28,19 +31,4 @@ struct mod_arch_specific - struct mod_arch_syminfo *syminfo; - }; - --#ifdef CONFIG_64BIT --#define ElfW(x) Elf64_ ## x --#define ELFW(x) ELF64_ ## x --#else --#define ElfW(x) Elf32_ ## x --#define ELFW(x) ELF32_ ## x --#endif -- --#define Elf_Addr ElfW(Addr) --#define Elf_Rela ElfW(Rela) --#define Elf_Shdr ElfW(Shdr) --#define Elf_Sym ElfW(Sym) --#define Elf_Ehdr ElfW(Ehdr) --#define ELF_R_SYM ELFW(R_SYM) --#define ELF_R_TYPE ELFW(R_TYPE) - #endif /* _ASM_S390_MODULE_H */ -diff --git a/arch/score/Kconfig b/arch/score/Kconfig -index ba0f412..e2c8db4 100644 ---- a/arch/score/Kconfig -+++ b/arch/score/Kconfig -@@ -10,6 +10,8 @@ config SCORE - select ARCH_DISCARD_MEMBLOCK - select GENERIC_CPU_DEVICES - select GENERIC_CLOCKEVENTS -+ select HAVE_MOD_ARCH_SPECIFIC -+ select MODULES_USE_ELF_REL - - choice - prompt "System type" -diff --git a/arch/score/include/asm/module.h b/arch/score/include/asm/module.h -index f0b5dc0..abf395b 100644 ---- a/arch/score/include/asm/module.h -+++ b/arch/score/include/asm/module.h -@@ -3,6 +3,7 @@ - - #include - #include -+#include - - struct mod_arch_specific { - /* Data Bus Error exception tables */ -@@ -13,11 +14,6 @@ struct mod_arch_specific { - - typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr --#define Elf_Addr Elf32_Addr -- - /* Given an address, look for it in the exception tables. */ - #ifdef CONFIG_MODULES - const struct exception_table_entry *search_module_dbetables(unsigned long addr); -diff --git a/arch/score/kernel/module.c b/arch/score/kernel/module.c -index 469e3b6..1378d99 100644 ---- a/arch/score/kernel/module.c -+++ b/arch/score/kernel/module.c -@@ -125,16 +125,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, - return 0; - } - --int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, -- unsigned int symindex, unsigned int relsec, -- struct module *me) --{ -- /* Non-standard return value... most other arch's return -ENOEXEC -- * for an unsupported relocation variant -- */ -- return 0; --} -- - /* Given an address, look for it in the module exception tables. */ - const struct exception_table_entry *search_module_dbetables(unsigned long addr) - { -diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig -index 31d9db7..22c02bb 100644 ---- a/arch/sh/Kconfig -+++ b/arch/sh/Kconfig -@@ -34,6 +34,8 @@ config SUPERH - select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER -+ select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER -+ select MODULES_USE_ELF_RELA - help - The SuperH is a RISC processor targeted for use in embedded systems - and consumer electronics; it was also used in the Sega Dreamcast -diff --git a/arch/sh/include/asm/module.h b/arch/sh/include/asm/module.h -index b7927de..81300d8b 100644 ---- a/arch/sh/include/asm/module.h -+++ b/arch/sh/include/asm/module.h -@@ -1,21 +1,13 @@ - #ifndef _ASM_SH_MODULE_H - #define _ASM_SH_MODULE_H - --struct mod_arch_specific { -+#include -+ - #ifdef CONFIG_DWARF_UNWINDER -+struct mod_arch_specific { - struct list_head fde_list; - struct list_head cie_list; --#endif - }; -- --#ifdef CONFIG_64BIT --#define Elf_Shdr Elf64_Shdr --#define Elf_Sym Elf64_Sym --#define Elf_Ehdr Elf64_Ehdr --#else --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr - #endif - - #ifdef CONFIG_CPU_LITTLE_ENDIAN -diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig -index e74ff13..acf5577 100644 ---- a/arch/sparc/Kconfig -+++ b/arch/sparc/Kconfig -@@ -36,6 +36,7 @@ config SPARC - select GENERIC_CLOCKEVENTS - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER -+ select MODULES_USE_ELF_RELA - - config SPARC32 - def_bool !64BIT -diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild -index 67f83e0..fbe1cb5 100644 ---- a/arch/sparc/include/asm/Kbuild -+++ b/arch/sparc/include/asm/Kbuild -@@ -21,4 +21,5 @@ generic-y += div64.h - generic-y += local64.h - generic-y += irq_regs.h - generic-y += local.h -+generic-y += module.h - generic-y += word-at-a-time.h -diff --git a/arch/sparc/include/asm/module.h b/arch/sparc/include/asm/module.h -deleted file mode 100644 -index ff8e02d..0000000 ---- a/arch/sparc/include/asm/module.h -+++ /dev/null -@@ -1,24 +0,0 @@ --#ifndef __SPARC_MODULE_H --#define __SPARC_MODULE_H --struct mod_arch_specific { }; -- --/* -- * Use some preprocessor magic to define the correct symbol -- * for sparc32 and sparc64. -- * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64 -- */ --#define ___ELF(a, b, c) a##b##c --#define __ELF(a, b, c) ___ELF(a, b, c) --#define _Elf(t) __ELF(Elf, CONFIG_BITS, t) --#define _ELF(t) __ELF(ELF, CONFIG_BITS, t) -- --#define Elf_Shdr _Elf(_Shdr) --#define Elf_Sym _Elf(_Sym) --#define Elf_Ehdr _Elf(_Ehdr) --#define Elf_Rela _Elf(_Rela) --#define Elf_Addr _Elf(_Addr) -- --#define ELF_R_SYM _ELF(_R_SYM) --#define ELF_R_TYPE _ELF(_R_TYPE) -- --#endif /* __SPARC_MODULE_H */ -diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig -index fe12881..2d8bc27 100644 ---- a/arch/tile/Kconfig -+++ b/arch/tile/Kconfig -@@ -15,6 +15,7 @@ config TILE - select SYS_HYPERVISOR - select ARCH_HAVE_NMI_SAFE_CMPXCHG - select GENERIC_CLOCKEVENTS -+ select MODULES_USE_ELF_RELA - - # FIXME: investigate whether we need/want these options. - # select HAVE_IOREMAP_PROT -diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig -index 03c9ff8..942b553 100644 ---- a/arch/unicore32/Kconfig -+++ b/arch/unicore32/Kconfig -@@ -14,6 +14,7 @@ config UNICORE32 - select GENERIC_IRQ_SHOW - select ARCH_WANT_FRAME_POINTERS - select GENERIC_IOMAP -+ select MODULES_USE_ELF_REL - help - UniCore-32 is 32-bit Instruction Set Architecture, - including a series of low-power-consumption RISC chip -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index c70684f..c38a60e 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -95,6 +95,8 @@ config X86 - select KTIME_SCALAR if X86_32 - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER -+ select MODULES_USE_ELF_REL if X86_32 -+ select MODULES_USE_ELF_RELA if X86_64 - - config INSTRUCTION_DECODER - def_bool (KPROBES || PERF_EVENTS || UPROBES) -diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig -index 8a3f835..516210a 100644 ---- a/arch/xtensa/Kconfig -+++ b/arch/xtensa/Kconfig -@@ -10,6 +10,7 @@ config XTENSA - select HAVE_GENERIC_HARDIRQS - select GENERIC_IRQ_SHOW - select GENERIC_CPU_DEVICES -+ select MODULES_USE_ELF_RELA - help - Xtensa processors are 32-bit RISC machines designed by Tensilica - primarily for embedded systems. These processors are both -diff --git a/arch/xtensa/include/asm/module.h b/arch/xtensa/include/asm/module.h -index d9b34be..488b40c 100644 ---- a/arch/xtensa/include/asm/module.h -+++ b/arch/xtensa/include/asm/module.h -@@ -13,15 +13,8 @@ - #ifndef _XTENSA_MODULE_H - #define _XTENSA_MODULE_H - --struct mod_arch_specific --{ -- /* No special elements, yet. */ --}; -- - #define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " " - --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -+#include - - #endif /* _XTENSA_MODULE_H */ -diff --git a/include/asm-generic/module.h b/include/asm-generic/module.h -index ed5b44d..14dc41d 100644 ---- a/include/asm-generic/module.h -+++ b/include/asm-generic/module.h -@@ -5,18 +5,44 @@ - * Many architectures just need a simple module - * loader without arch specific data. - */ -+#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC - struct mod_arch_specific - { - }; -+#endif - - #ifdef CONFIG_64BIT --#define Elf_Shdr Elf64_Shdr --#define Elf_Sym Elf64_Sym --#define Elf_Ehdr Elf64_Ehdr --#else --#define Elf_Shdr Elf32_Shdr --#define Elf_Sym Elf32_Sym --#define Elf_Ehdr Elf32_Ehdr -+#define Elf_Shdr Elf64_Shdr -+#define Elf_Phdr Elf64_Phdr -+#define Elf_Sym Elf64_Sym -+#define Elf_Dyn Elf64_Dyn -+#define Elf_Ehdr Elf64_Ehdr -+#define Elf_Addr Elf64_Addr -+#ifdef CONFIG_MODULES_USE_ELF_REL -+#define Elf_Rel Elf64_Rel -+#endif -+#ifdef CONFIG_MODULES_USE_ELF_RELA -+#define Elf_Rela Elf64_Rela -+#endif -+#define ELF_R_TYPE(X) ELF64_R_TYPE(X) -+#define ELF_R_SYM(X) ELF64_R_SYM(X) -+ -+#else /* CONFIG_64BIT */ -+ -+#define Elf_Shdr Elf32_Shdr -+#define Elf_Phdr Elf32_Phdr -+#define Elf_Sym Elf32_Sym -+#define Elf_Dyn Elf32_Dyn -+#define Elf_Ehdr Elf32_Ehdr -+#define Elf_Addr Elf32_Addr -+#ifdef CONFIG_MODULES_USE_ELF_REL -+#define Elf_Rel Elf32_Rel -+#endif -+#ifdef CONFIG_MODULES_USE_ELF_RELA -+#define Elf_Rela Elf32_Rela -+#endif -+#define ELF_R_TYPE(X) ELF32_R_TYPE(X) -+#define ELF_R_SYM(X) ELF32_R_SYM(X) - #endif - - #endif /* __ASM_GENERIC_MODULE_H */ -diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h -index b2be02e..b85dda8 100644 ---- a/include/linux/moduleloader.h -+++ b/include/linux/moduleloader.h -@@ -28,21 +28,49 @@ void *module_alloc(unsigned long size); - /* Free memory returned from module_alloc. */ - void module_free(struct module *mod, void *module_region); - --/* Apply the given relocation to the (simplified) ELF. Return -error -- or 0. */ -+/* -+ * Apply the given relocation to the (simplified) ELF. Return -error -+ * or 0. -+ */ -+#ifdef CONFIG_MODULES_USE_ELF_REL - int apply_relocate(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *mod); -+#else -+static inline int apply_relocate(Elf_Shdr *sechdrs, -+ const char *strtab, -+ unsigned int symindex, -+ unsigned int relsec, -+ struct module *me) -+{ -+ pr_err("module %s: REL relocation unsupported\n", me->name); -+ return -ENOEXEC; -+} -+#endif - --/* Apply the given add relocation to the (simplified) ELF. Return -- -error or 0 */ -+/* -+ * Apply the given add relocation to the (simplified) ELF. Return -+ * -error or 0 -+ */ -+#ifdef CONFIG_MODULES_USE_ELF_RELA - int apply_relocate_add(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *mod); -+#else -+static inline int apply_relocate_add(Elf_Shdr *sechdrs, -+ const char *strtab, -+ unsigned int symindex, -+ unsigned int relsec, -+ struct module *me) -+{ -+ pr_err("module %s: RELA relocation unsupported\n", me->name); -+ return -ENOEXEC; -+} -+#endif - - /* Any final processing of module before access. Return -error or 0. */ - int module_finalize(const Elf_Ehdr *hdr, -diff --git a/kernel/module.c b/kernel/module.c -index 4edbd9c..087aeed 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -1949,26 +1949,6 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) - return ret; - } - --int __weak apply_relocate(Elf_Shdr *sechdrs, -- const char *strtab, -- unsigned int symindex, -- unsigned int relsec, -- struct module *me) --{ -- pr_err("module %s: REL relocation unsupported\n", me->name); -- return -ENOEXEC; --} -- --int __weak apply_relocate_add(Elf_Shdr *sechdrs, -- const char *strtab, -- unsigned int symindex, -- unsigned int relsec, -- struct module *me) --{ -- pr_err("module %s: RELA relocation unsupported\n", me->name); -- return -ENOEXEC; --} -- - static int apply_relocations(struct module *mod, const struct load_info *info) - { - unsigned int i; --- -1.7.10.4 - - -From 69bdeeb86f28489efa7d5f414867bd07b9516c10 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:26:33 +0100 -Subject: [PATCH 16/27] 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 ---- - 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 - #include - /* - * 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.4 - - -From 5191f0bcbe03426b90b0a53c9ea960fafba7c269 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:27:05 +0100 -Subject: [PATCH 17/27] MODSIGN: Provide gitignore and make clean rules for - extra files - -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 ---- - .gitignore | 12 ++++++++++++ - Makefile | 1 + - scripts/mod/.gitignore | 1 + - 3 files changed, 14 insertions(+) - -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 - *~ - \#*# -+ -+# -+# GPG leavings from module signing -+# -+genkey -+modsign.pub -+modsign.sec -+random_seed -+trustdb.gpg -diff --git a/Makefile b/Makefile -index aa8e315..4a4a11f 100644 ---- a/Makefile -+++ b/Makefile -@@ -1239,6 +1239,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 - --- -1.7.10.4 - - -From bf067003ae6304d90c278118b5d65d905be16e53 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:27:16 +0100 -Subject: [PATCH 18/27] MODSIGN: Provide Documentation and Kconfig options - -Provide documentation and kernel configuration options for module signing. - -The documentation can be found in: - - Documentation/module-signing.txt - -The following configuration options are added: - - (1) CONFIG_MODULE_SIG - - Enable module signing. This will both cause the build process to sign - modules and the kernel to check modules when they're loaded. - - (2) CONFIG_MODULE_SIG_SHA1 - CONFIG_MODULE_SIG_SHA224 - CONFIG_MODULE_SIG_SHA256 - CONFIG_MODULE_SIG_SHA384 - CONFIG_MODULE_SIG_SHA512 - - 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. - - (3) CONFIG_MODULE_SIG_FORCE - - Require that any module loaded must be signed with a key compiled into - the kernel. All other modules are rejected with EKEYREJECTED. - -Signed-off-by: David Howells ---- - Documentation/module-signing.txt | 194 ++++++++++++++++++++++++++++++++++++++ - include/linux/modsign.h | 27 ++++++ - init/Kconfig | 54 +++++++++++ - 3 files changed, 275 insertions(+) - create mode 100644 Documentation/module-signing.txt - create mode 100644 include/linux/modsign.h - -diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt -new file mode 100644 -index 0000000..d75d473 ---- /dev/null -+++ b/Documentation/module-signing.txt -@@ -0,0 +1,194 @@ -+ ============================== -+ KERNEL MODULE SIGNING FACILITY -+ ============================== -+ -+The module signing facility applies cryptographic signature checking to modules -+on module load, checking the signature against a ring of public keys compiled -+into the kernel. GPG is used to do the cryptographic work and determines the -+format of the signature and key data. The facility uses GPG's MPI library to -+handle the huge numbers involved. -+ -+This facility is enabled through CONFIG_MODULE_SIG. Turning on signature -+checking will also force the module's ELF metadata to be verified before the -+signature is checked. -+ -+The signature checker in the kernel is capable of handling multiple keys of -+either DSA or RSA type, and can support any of MD5, RIPE-MD-160, SHA-1, -+SHA-224, SHA-256, SHA-384 and SHA-512 hashes - PROVIDED(!) the requisite -+algorithms are compiled into the kernel. -+ -+(!) NOTE: Modules may only be verified initially with algorithms compiled into -+the kernel. Further algorithm modules may be loaded and used - but these must -+first pass a verification step using already loaded/compiled-in algorithms. -+ -+ -+===================== -+SUPPLYING PUBLIC KEYS -+===================== -+ -+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 modsign.pub. -+ -+For example, a throwaway key could be generated automatically by something like -+the following: -+ -+ cat >genkey < -+ -+ This indicates the whereabouts of the GPG keyring that is the source of -+ the public key to be used. The default is "./modsign.pub". -+ -+ (*) MODKEYNAME= -+ -+ 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 -+ --digest-algo= -+ -+ 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 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 -+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. -+ -+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 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. -+ -+ -+========================================= -+NON-VALID SIGNATURES AND UNSIGNED MODULES -+========================================= -+ -+If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on -+the kernel command line, the kernel will _only_ load validly signed modules -+for which it has a public key. Otherwise, it will also load modules that are -+unsigned. Any module for which the kernel has a key, but which proves to have -+a signature mismatch will not be permitted to load (returning EKEYREJECTED). -+ -+This table indicates the behaviours of the various situations: -+ -+ MODULE STATE PERMISSIVE MODE ENFORCING MODE -+ ======================================= =============== =============== -+ Unsigned Ok EKEYREJECTED -+ Signed, no public key ENOKEY ENOKEY -+ Validly signed, public key Ok Ok -+ Invalidly signed, public key EKEYREJECTED EKEYREJECTED -+ Validly signed, expired key EKEYEXPIRED EKEYEXPIRED -+ Signed, hash algorithm unavailable ENOPKG ENOPKG -+ Corrupt signature EBADMSG EBADMSG -+ Corrupt ELF ELIBBAD ELIBBAD -diff --git a/include/linux/modsign.h b/include/linux/modsign.h -new file mode 100644 -index 0000000..c5ac87a ---- /dev/null -+++ b/include/linux/modsign.h -@@ -0,0 +1,27 @@ -+/* Module signing definitions -+ * -+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. -+ * Written by David Howells (dhowells@redhat.com) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public Licence -+ * as published by the Free Software Foundation; either version -+ * 2 of the Licence, or (at your option) any later version. -+ */ -+ -+#ifndef _LINUX_MODSIGN_H -+#define _LINUX_MODSIGN_H -+ -+#ifdef CONFIG_MODULE_SIG -+ -+#include -+ -+/* -+ * The parameters of the ELF note used to carry the signature -+ */ -+#define MODSIGN_NOTE_NAME module.sig -+#define MODSIGN_NOTE_TYPE 100 -+ -+#endif -+ -+#endif /* _LINUX_MODSIGN_H */ -diff --git a/init/Kconfig b/init/Kconfig -index d07dcf9..1d1a056 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1570,6 +1570,60 @@ config MODULE_SRCVERSION_ALL - the version). With this option, such a "srcversion" field - will be created for all modules. If unsure, say N. - -+config MODULE_SIG -+ bool "Module signature verification" -+ depends on MODULES -+ select KEYS -+ select CRYPTO_KEY_TYPE -+ select CRYPTO_KEY_PKEY_ALGO_DSA -+ select CRYPTO_KEY_PKEY_ALGO_RSA -+ select PGP_PARSER -+ select PGP_PRELOAD -+ help -+ Check modules for valid signatures upon load. For more information -+ see: -+ -+ Documentation/module-signing.txt -+ -+choice -+ prompt "Which hash algorithm should modules be signed with?" -+ depends on MODULE_SIG -+ help -+ This determines which sort of hashing algorithm will be used during -+ signature generation. This algorithm _must_ be built into the kernel -+ directly so that signature verification can take place. It is not -+ possible to load a signed module containing the algorithm to check -+ the signature on that module. -+ -+config MODULE_SIG_SHA1 -+ bool "Sign modules with SHA-1" -+ select CRYPTO_SHA1 -+ -+config MODULE_SIG_SHA224 -+ bool "Sign modules with SHA-224" -+ select CRYPTO_SHA224 -+ -+config MODULE_SIG_SHA256 -+ bool "Sign modules with SHA-256" -+ select CRYPTO_SHA256 -+ -+config MODULE_SIG_SHA384 -+ bool "Sign modules with SHA-384" -+ select CRYPTO_SHA384 -+ -+config MODULE_SIG_SHA512 -+ bool "Sign modules with SHA-512" -+ select CRYPTO_SHA512 -+ -+endchoice -+ -+config MODULE_SIG_FORCE -+ bool "Required modules to be validly signed (EXPERIMENTAL)" -+ depends on MODULE_SIG -+ help -+ Reject unsigned modules or signed modules for which we don't have a -+ key. -+ - endif # MODULES - - config INIT_ALL_POSSIBLE --- -1.7.10.4 - - -From 19c2fd74747b84e445b0a4eb7f7308a238267aec Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:27:38 +0100 -Subject: [PATCH 19/27] 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 ---- - 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..17465d8 100644 ---- a/scripts/Makefile.modpost -+++ b/scripts/Makefile.modpost -@@ -14,7 +14,8 @@ - # 3) create one .mod.c file pr. module - # 4) create one Module.symvers file with CRC for all exported symbols - # 5) compile all .mod.c files --# 6) final link of the module to a file -+# 6) final link of the module to a (or ) file -+# 7) signs the modules to a file - - # Step 3 is used to place certain information in the module's ELF - # section, including information such as: -@@ -32,6 +33,8 @@ - # Step 4 is solely used to allow module versioning in external modules, - # where the CRC of each module is retrieved from the Module.symvers file. - -+# Step 7 is dependent on CONFIG_MODULE_SIG being enabled. -+ - # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined - # symbols in the final module linking stage - # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. -@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE - targets += $(modules:.ko=.mod.o) - - # Step 6), final link of the modules -+ifneq ($(CONFIG_MODULE_SIG),y) - quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -@@ -125,7 +129,88 @@ $(modules): %.ko :%.o %.mod.o FORCE - $(call if_changed,ld_ko_o) - - targets += $(modules) -+else -+quiet_cmd_ld_ko_unsigned_o = LD [M] $@ -+ cmd_ld_ko_unsigned_o = \ -+ $(LD) -r $(LDFLAGS) \ -+ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -+ -o $@ $(filter-out FORCE,$^) \ -+ $(if $(AFTER_LINK),; $(AFTER_LINK)) -+ -+$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE -+ $(call if_changed,ld_ko_unsigned_o) -+ -+targets += $(modules:.ko=.ko.unsigned) -+ -+# Step 7), sign the modules -+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 -+KEYFLAGS += --digest-algo=SHA1 -+else -+ifdef CONFIG_MODULE_SIG_SHA224 -+KEYFLAGS += --digest-algo=SHA224 -+else -+ifdef CONFIG_MODULE_SIG_SHA256 -+KEYFLAGS += --digest-algo=SHA256 -+else -+ifdef CONFIG_MODULE_SIG_SHA384 -+KEYFLAGS += --digest-algo=SHA384 -+else -+ifdef CONFIG_MODULE_SIG_SHA512 -+KEYFLAGS += --digest-algo=SHA512 -+else -+endif -+endif -+endif -+endif -+endif -+ -+ifdef MODKEYNAME -+KEYFLAGS += --default-key $(MODKEYNAME) -+endif - -+ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) -+ifeq ($(KBUILD_SRC),) -+ # no O= is being used -+ SCRIPTS_DIR := scripts -+else -+ SCRIPTS_DIR := $(KBUILD_SRC)/scripts -+endif -+SIGN_MODULES := 1 -+else -+SIGN_MODULES := 0 -+endif -+ -+# only sign if it's an in-tree module -+ifneq ($(KBUILD_EXTMOD),) -+SIGN_MODULES := 0 -+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 && \ -+ rm -f $@.digest.sig && \ -+ gpg --batch --no-greeting $(KEYFLAGS) -b $@.digest && \ -+ sh $(SCRIPTS_DIR)/mod/modsign-note.sh $@.digest.sig | \ -+ $(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 $(KEYRING_DEP) FORCE -+ $(call if_changed,sign_ko_ko_unsigned) -+ -+targets += $(modules) -+endif - - # Add FORCE to the prequisites of a target to force it to be always rebuilt. - # --------------------------------------------------------------------------- -diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile -index ff954f8..4654e3b 100644 ---- a/scripts/mod/Makefile -+++ b/scripts/mod/Makefile -@@ -1,4 +1,4 @@ --hostprogs-y := modpost mk_elfconfig -+hostprogs-y := modpost mk_elfconfig mod-extract - always := $(hostprogs-y) empty.o - - modpost-objs := modpost.o file2alias.o sumversion.o -diff --git a/scripts/mod/mod-extract.c b/scripts/mod/mod-extract.c -new file mode 100644 -index 0000000..0c0e3e3 ---- /dev/null -+++ b/scripts/mod/mod-extract.c -@@ -0,0 +1,913 @@ -+/* mod-extract.c: module extractor for signing -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void extract_elf64(void *buffer, size_t size, Elf64_Ehdr *hdr); -+static void extract_elf32(void *buffer, size_t size, Elf32_Ehdr *hdr); -+ -+struct byteorder { -+ uint16_t (*get16)(const uint16_t *); -+ uint32_t (*get32)(const uint32_t *); -+ uint64_t (*get64)(const uint64_t *); -+ void (*set16)(uint16_t *, uint16_t); -+ void (*set32)(uint32_t *, uint32_t); -+ void (*set64)(uint64_t *, uint64_t); -+}; -+ -+static uint16_t get16_le(const uint16_t *p) { return __le16_to_cpu(*p); } -+static uint32_t get32_le(const uint32_t *p) { return __le32_to_cpu(*p); } -+static uint64_t get64_le(const uint64_t *p) { return __le64_to_cpu(*p); } -+static uint16_t get16_be(const uint16_t *p) { return __be16_to_cpu(*p); } -+static uint32_t get32_be(const uint32_t *p) { return __be32_to_cpu(*p); } -+static uint64_t get64_be(const uint64_t *p) { return __be64_to_cpu(*p); } -+ -+static void set16_le(uint16_t *p, uint16_t n) { *p = __cpu_to_le16(n); } -+static void set32_le(uint32_t *p, uint32_t n) { *p = __cpu_to_le32(n); } -+static void set64_le(uint64_t *p, uint64_t n) { *p = __cpu_to_le64(n); } -+static void set16_be(uint16_t *p, uint16_t n) { *p = __cpu_to_be16(n); } -+static void set32_be(uint32_t *p, uint32_t n) { *p = __cpu_to_be32(n); } -+static void set64_be(uint64_t *p, uint64_t n) { *p = __cpu_to_be64(n); } -+ -+static const struct byteorder byteorder_le = { -+ get16_le, get32_le, get64_le, -+ set16_le, set32_le, set64_le -+}; -+static const struct byteorder byteorder_be = { -+ get16_be, get32_be, get64_be, -+ set16_be, set32_be, set64_be -+}; -+static const struct byteorder *order; -+ -+static inline uint16_t get16(const uint16_t *p) { return order->get16(p); } -+static inline uint32_t get32(const uint32_t *p) { return order->get32(p); } -+static inline uint64_t get64(const uint64_t *p) { return order->get64(p); } -+static inline void set16(uint16_t *p, uint16_t n) { order->set16(p, n); } -+static inline void set32(uint32_t *p, uint32_t n) { order->set32(p, n); } -+static inline void set64(uint64_t *p, uint64_t n) { order->set64(p, n); } -+ -+static FILE *outfd; -+static uint8_t csum, xcsum; -+ -+static void write_out(const void *data, size_t size) -+{ -+ const uint8_t *p = data; -+ size_t loop; -+ -+ for (loop = 0; loop < size; loop++) { -+ csum += p[loop]; -+ xcsum += p[loop]; -+ } -+ -+ if (fwrite(data, 1, size, outfd) != size) { -+ perror("write"); -+ exit(1); -+ } -+} -+ -+#define write_out_val(VAL) write_out(&(VAL), sizeof(VAL)) -+ -+static int is_verbose; -+ -+static __attribute__((format(printf, 1, 2))) -+void verbose(const char *fmt, ...) -+{ -+ va_list va; -+ -+ if (is_verbose) { -+ va_start(va, fmt); -+ vprintf(fmt, va); -+ va_end(va); -+ } -+} -+ -+static __attribute__((noreturn)) -+void usage(void) -+{ -+ fprintf(stderr, "Usage: mod-extract [-v] \n"); -+ exit(2); -+} -+ -+/* -+ * -+ */ -+int main(int argc, char **argv) -+{ -+ struct stat st; -+ Elf32_Ehdr *hdr32; -+ Elf64_Ehdr *hdr64; -+ size_t len; -+ void *buffer; -+ int fd, be, b64; -+ -+ while (argc > 1 && strcmp("-v", argv[1]) == 0) { -+ argv++; -+ argc--; -+ is_verbose++; -+ } -+ -+ if (argc != 3) -+ usage(); -+ -+ /* map the module into memory */ -+ fd = open(argv[1], O_RDONLY); -+ if (fd < 0) { -+ perror("open input"); -+ exit(1); -+ } -+ -+ if (fstat(fd, &st) < 0) { -+ perror("fstat"); -+ exit(1); -+ } -+ -+ len = st.st_size; -+ -+ buffer = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); -+ if (buffer == MAP_FAILED) { -+ perror("mmap"); -+ exit(1); -+ } -+ -+ if (close(fd) < 0) { -+ perror("close input"); -+ exit(1); -+ } -+ -+ /* check it's an ELF object */ -+ hdr32 = buffer; -+ hdr64 = buffer; -+ -+ if (hdr32->e_ident[EI_MAG0] != ELFMAG0 || -+ hdr32->e_ident[EI_MAG1] != ELFMAG1 || -+ hdr32->e_ident[EI_MAG2] != ELFMAG2 || -+ hdr32->e_ident[EI_MAG3] != ELFMAG3 -+ ) { -+ fprintf(stderr, "Module does not appear to be ELF\n"); -+ exit(3); -+ } -+ -+ /* determine endianness and word size */ -+ b64 = (hdr32->e_ident[EI_CLASS] == ELFCLASS64); -+ be = (hdr32->e_ident[EI_DATA] == ELFDATA2MSB); -+ order = be ? &byteorder_be : &byteorder_le; -+ -+ verbose("Module is %s-bit %s-endian\n", -+ b64 ? "64" : "32", -+ be ? "big" : "little"); -+ -+ /* open the output file */ -+ outfd = fopen(argv[2], "w"); -+ if (!outfd) { -+ perror("open output"); -+ exit(1); -+ } -+ -+ /* perform the extraction */ -+ if (b64) -+ extract_elf64(buffer, len, hdr64); -+ else -+ extract_elf32(buffer, len, hdr32); -+ -+ /* done */ -+ if (fclose(outfd) == EOF) { -+ perror("close output"); -+ exit(1); -+ } -+ -+ return 0; -+} -+ -+/* -+ * extract a RELA table -+ * - need to canonicalise the entries in case section addition/removal has -+ * rearranged the symbol table and the section table -+ */ -+static void extract_elf64_rela(const void *buffer, int secix, int targetix, -+ const Elf64_Rela *relatab, size_t nrels, -+ const Elf64_Sym *symbols, size_t nsyms, -+ const Elf64_Shdr *sections, size_t nsects, int *canonmap, -+ const char *strings, size_t nstrings, -+ const char *sh_name) -+{ -+ struct { -+ 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; -+ -+ } __attribute__((packed)) relocation; -+ -+ const Elf64_Sym *symbol; -+ size_t loop; -+ -+ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ -+ for (loop = 0; loop < nrels; loop++) { -+ Elf64_Section st_shndx; -+ Elf64_Xword r_info; -+ -+ /* decode the relocation */ -+ r_info = get64(&relatab[loop].r_info); -+ relocation.r_offset = relatab[loop].r_offset; -+ relocation.r_addend = relatab[loop].r_addend; -+ set32(&relocation.r_type, ELF64_R_TYPE(r_info)); -+ -+ if (ELF64_R_SYM(r_info) >= nsyms) { -+ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n", -+ (size_t)ELF64_R_SYM(r_info), loop); -+ exit(1); -+ } -+ -+ /* decode the symbol referenced by the relocation */ -+ symbol = &symbols[ELF64_R_SYM(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 = get16(&symbol->st_shndx); -+ -+ /* canonicalise the section used by the symbol */ -+ if (st_shndx > SHN_UNDEF && st_shndx < nsects) -+ set16(&relocation.st_shndx, canonmap[st_shndx]); -+ -+ write_out_val(relocation); -+ -+ /* undefined symbols must be named if referenced */ -+ if (st_shndx == SHN_UNDEF) { -+ const char *name = strings + get32(&symbol->st_name); -+ write_out(name, strlen(name) + 1); -+ } -+ } -+ -+ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); -+} -+ -+/* -+ * extract a REL table -+ * - need to canonicalise the entries in case section addition/removal has -+ * rearranged the symbol table and the section table -+ */ -+static void extract_elf64_rel(const void *buffer, int secix, int targetix, -+ const Elf64_Rel *relatab, size_t nrels, -+ const Elf64_Sym *symbols, size_t nsyms, -+ const Elf64_Shdr *sections, size_t nsects, int *canonmap, -+ const char *strings, size_t nstrings, -+ const char *sh_name) -+{ -+ struct { -+ 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; -+ -+ } __attribute__((packed)) relocation; -+ -+ const Elf64_Sym *symbol; -+ size_t loop; -+ -+ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ -+ for (loop = 0; loop < nrels; loop++) { -+ Elf64_Section st_shndx; -+ Elf64_Xword r_info; -+ -+ /* decode the relocation */ -+ r_info = get64(&relatab[loop].r_info); -+ relocation.r_offset = relatab[loop].r_offset; -+ set32(&relocation.r_type, ELF64_R_TYPE(r_info)); -+ -+ if (ELF64_R_SYM(r_info) >= nsyms) { -+ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n", -+ (size_t)ELF64_R_SYM(r_info), loop); -+ exit(1); -+ } -+ -+ /* decode the symbol referenced by the relocation */ -+ symbol = &symbols[ELF64_R_SYM(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 = get16(&symbol->st_shndx); -+ -+ /* canonicalise the section used by the symbol */ -+ if (st_shndx > SHN_UNDEF && st_shndx < nsects) -+ set16(&relocation.st_shndx, canonmap[st_shndx]); -+ -+ write_out_val(relocation); -+ -+ /* undefined symbols must be named if referenced */ -+ if (st_shndx == SHN_UNDEF) { -+ const char *name = strings + get32(&symbol->st_name); -+ write_out(name, strlen(name) + 1); -+ } -+ } -+ -+ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); -+} -+ -+/* -+ * extract the data from a 64-bit module -+ */ -+static void extract_elf64(void *buffer, size_t len, Elf64_Ehdr *hdr) -+{ -+ const Elf64_Sym *symbols; -+ Elf64_Shdr *sections; -+ const char *secstrings, *strings; -+ size_t nsyms, nstrings; -+ int loop, shnum, *canonlist, *canonmap, canon, changed, tmp; -+ -+ sections = buffer + get64(&hdr->e_shoff); -+ secstrings = buffer + get64(§ions[get16(&hdr->e_shstrndx)].sh_offset); -+ shnum = get16(&hdr->e_shnum); -+ -+ /* find the symbol table and the string table and produce a list of -+ * index numbers of sections that contribute to the kernel's module -+ * image -+ */ -+ canonlist = calloc(sizeof(int), shnum * 2); -+ if (!canonlist) { -+ perror("calloc"); -+ exit(1); -+ } -+ canonmap = canonlist + shnum; -+ canon = 0; -+ -+ symbols = NULL; -+ strings = NULL; -+ nstrings = 0; -+ nsyms = 0; -+ -+ for (loop = 1; loop < shnum; loop++) { -+ const char *sh_name = secstrings + get32(§ions[loop].sh_name); -+ Elf64_Word sh_type = get32(§ions[loop].sh_type); -+ Elf64_Xword sh_size = get64(§ions[loop].sh_size); -+ Elf64_Xword sh_flags = get64(§ions[loop].sh_flags); -+ Elf64_Word sh_info = get32(§ions[loop].sh_info); -+ Elf64_Off sh_offset = get64(§ions[loop].sh_offset); -+ void *data = buffer + sh_offset; -+ -+ /* quick sanity check */ -+ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { -+ fprintf(stderr, "Section goes beyond EOF\n"); -+ exit(3); -+ } -+ -+ /* we only need to canonicalise allocatable sections */ -+ if (sh_flags & SHF_ALLOC) -+ canonlist[canon++] = loop; -+ else if ((sh_type == SHT_REL || sh_type == SHT_RELA) && -+ get64(§ions[sh_info].sh_flags) & SHF_ALLOC) -+ canonlist[canon++] = loop; -+ -+ /* keep track of certain special sections */ -+ switch (sh_type) { -+ case SHT_SYMTAB: -+ if (strcmp(sh_name, ".symtab") == 0) { -+ symbols = data; -+ nsyms = sh_size / sizeof(Elf64_Sym); -+ } -+ break; -+ -+ case SHT_STRTAB: -+ if (strcmp(sh_name, ".strtab") == 0) { -+ strings = data; -+ nstrings = sh_size; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ if (!symbols) { -+ fprintf(stderr, "Couldn't locate symbol table\n"); -+ exit(3); -+ } -+ -+ if (!strings) { -+ fprintf(stderr, "Couldn't locate strings table\n"); -+ exit(3); -+ } -+ -+ /* canonicalise the index numbers of the contributing section */ -+ do { -+ changed = 0; -+ -+ for (loop = 0; loop < canon - 1; loop++) { -+ const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name); -+ const char *y = secstrings + get32(§ions[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 = 1; -+ } -+ } -+ -+ } while (changed); -+ -+ for (loop = 0; loop < canon; loop++) -+ canonmap[canonlist[loop]] = loop + 1; -+ -+ if (is_verbose > 1) { -+ printf("\nSection canonicalisation map:\n"); -+ for (loop = 1; loop < shnum; loop++) { -+ const char *x = secstrings + get32(§ions[loop].sh_name); -+ printf("%4d %s\n", canonmap[loop], x); -+ } -+ -+ printf("\nAllocated section list in canonical order:\n"); -+ for (loop = 0; loop < canon; loop++) { -+ const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name); -+ printf("%4d %s\n", canonlist[loop], x); -+ } -+ } -+ -+ /* iterate through the section table looking for sections we want to -+ * contribute to the signature */ -+ verbose("\n"); -+ verbose("CAN FILE POS CS SECT NAME\n"); -+ verbose("=== ======== == ==== ==============================\n"); -+ -+ for (loop = 0; loop < canon; loop++) { -+ int sect = canonlist[loop]; -+ const char *sh_name = secstrings + get32(§ions[sect].sh_name); -+ Elf64_Word sh_type = get32(§ions[sect].sh_type); -+ Elf64_Xword sh_size = get64(§ions[sect].sh_size); -+ Elf64_Xword sh_flags = get64(§ions[sect].sh_flags); -+ Elf64_Word sh_info = get32(§ions[sect].sh_info); -+ Elf64_Off sh_offset = get64(§ions[sect].sh_offset); -+ void *data = buffer + sh_offset; -+ -+ csum = 0; -+ -+ /* include canonicalised relocation sections */ -+ if (sh_type == SHT_REL || sh_type == SHT_RELA) { -+ Elf32_Word canon_sh_info; -+ -+ if (sh_info <= 0 && sh_info >= hdr->e_shnum) { -+ fprintf(stderr, -+ "Invalid ELF - REL/RELA sh_info does" -+ " not refer to a valid section\n"); -+ exit(3); -+ } -+ -+ verbose("%3u %08lx ", loop, ftell(outfd)); -+ -+ set32(&canon_sh_info, canonmap[sh_info]); -+ -+ /* write out selected portions of the section header */ -+ write_out(sh_name, strlen(sh_name)); -+ write_out_val(sections[sect].sh_type); -+ write_out_val(sections[sect].sh_flags); -+ write_out_val(sections[sect].sh_size); -+ write_out_val(sections[sect].sh_addralign); -+ write_out_val(canon_sh_info); -+ -+ if (sh_type == SHT_RELA) -+ extract_elf64_rela(buffer, sect, sh_info, -+ data, sh_size / sizeof(Elf64_Rela), -+ symbols, nsyms, -+ sections, shnum, canonmap, -+ strings, nstrings, -+ sh_name); -+ else -+ extract_elf64_rel(buffer, sect, sh_info, -+ data, sh_size / sizeof(Elf64_Rel), -+ symbols, nsyms, -+ sections, shnum, canonmap, -+ strings, nstrings, -+ sh_name); -+ continue; -+ } -+ -+ /* include the headers of BSS sections */ -+ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { -+ verbose("%3u %08lx ", loop, ftell(outfd)); -+ -+ /* write out selected portions of the section header */ -+ write_out(sh_name, strlen(sh_name)); -+ write_out_val(sections[sect].sh_type); -+ write_out_val(sections[sect].sh_flags); -+ write_out_val(sections[sect].sh_size); -+ write_out_val(sections[sect].sh_addralign); -+ -+ verbose("%02x %4d %s\n", csum, sect, sh_name); -+ } -+ -+ /* include allocatable loadable sections */ -+ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) -+ goto include_section; -+ -+ /* not this section */ -+ continue; -+ -+ include_section: -+ verbose("%3u %08lx ", loop, ftell(outfd)); -+ -+ /* write out selected portions of the section header */ -+ write_out(sh_name, strlen(sh_name)); -+ write_out_val(sections[sect].sh_type); -+ write_out_val(sections[sect].sh_flags); -+ write_out_val(sections[sect].sh_size); -+ write_out_val(sections[sect].sh_addralign); -+ -+ /* write out the section data */ -+ write_out(data, sh_size); -+ -+ verbose("%02x %4d %s\n", csum, sect, sh_name); -+ } -+ -+ verbose("%08lx (%lu bytes csum 0x%02x)\n", -+ ftell(outfd), ftell(outfd), xcsum); -+} -+ -+/* -+ * extract a RELA table -+ * - need to canonicalise the entries in case section addition/removal has -+ * rearranged the symbol table and the section table -+ */ -+static void extract_elf32_rela(const void *buffer, int secix, int targetix, -+ const Elf32_Rela *relatab, size_t nrels, -+ const Elf32_Sym *symbols, size_t nsyms, -+ const Elf32_Shdr *sections, size_t nsects, -+ int *canonmap, -+ const char *strings, size_t nstrings, -+ const char *sh_name) -+{ -+ struct { -+ 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; -+ -+ } __attribute__((packed)) relocation; -+ -+ const Elf32_Sym *symbol; -+ size_t loop; -+ -+ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ -+ for (loop = 0; loop < nrels; loop++) { -+ Elf32_Section st_shndx; -+ Elf32_Word r_info; -+ -+ /* decode the relocation */ -+ r_info = get32(&relatab[loop].r_info); -+ relocation.r_offset = relatab[loop].r_offset; -+ relocation.r_addend = relatab[loop].r_addend; -+ relocation.r_type = ELF32_R_TYPE(r_info); -+ -+ if (ELF32_R_SYM(r_info) >= nsyms) { -+ fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n", -+ ELF32_R_SYM(r_info), loop); -+ exit(1); -+ } -+ -+ /* decode the symbol referenced by the relocation */ -+ symbol = &symbols[ELF32_R_SYM(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 = get16(&symbol->st_shndx); -+ -+ /* canonicalise the section used by the symbol */ -+ if (st_shndx > SHN_UNDEF && st_shndx < nsects) -+ set16(&relocation.st_shndx, canonmap[st_shndx]); -+ -+ write_out_val(relocation); -+ -+ /* undefined symbols must be named if referenced */ -+ if (st_shndx == SHN_UNDEF) { -+ const char *name = strings + get32(&symbol->st_name); -+ write_out(name, strlen(name) + 1); -+ } -+ } -+ -+ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); -+} -+ -+/* -+ * extract a REL table -+ * - need to canonicalise the entries in case section addition/removal has -+ * rearranged the symbol table and the section table -+ */ -+static void extract_elf32_rel(const void *buffer, int secix, int targetix, -+ const Elf32_Rel *relatab, size_t nrels, -+ const Elf32_Sym *symbols, size_t nsyms, -+ const Elf32_Shdr *sections, size_t nsects, -+ int *canonmap, -+ const char *strings, size_t nstrings, -+ const char *sh_name) -+{ -+ struct { -+ 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; -+ -+ } __attribute__((packed)) relocation; -+ -+ const Elf32_Sym *symbol; -+ size_t loop; -+ -+ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ -+ for (loop = 0; loop < nrels; loop++) { -+ Elf32_Section st_shndx; -+ Elf32_Word r_info; -+ -+ /* decode the relocation */ -+ r_info = get32(&relatab[loop].r_info); -+ relocation.r_offset = relatab[loop].r_offset; -+ relocation.r_type = ELF32_R_TYPE(r_info); -+ -+ if (ELF32_R_SYM(r_info) >= nsyms) { -+ fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n", -+ ELF32_R_SYM(r_info), loop); -+ exit(1); -+ } -+ -+ /* decode the symbol referenced by the relocation */ -+ symbol = &symbols[ELF32_R_SYM(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 = get16(&symbol->st_shndx); -+ -+ /* canonicalise the section used by the symbol */ -+ if (st_shndx > SHN_UNDEF && st_shndx < nsects) -+ set16(&relocation.st_shndx, canonmap[st_shndx]); -+ -+ write_out_val(relocation); -+ -+ /* undefined symbols must be named if referenced */ -+ if (st_shndx == SHN_UNDEF) { -+ const char *name = strings + get32(&symbol->st_name); -+ write_out(name, strlen(name) + 1); -+ } -+ } -+ -+ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); -+} -+ -+/* -+ * extract the data from a 32-bit module -+ */ -+static void extract_elf32(void *buffer, size_t len, Elf32_Ehdr *hdr) -+{ -+ const Elf32_Sym *symbols; -+ Elf32_Shdr *sections; -+ const char *secstrings, *strings; -+ size_t nsyms, nstrings; -+ int loop, shnum, *canonlist, *canonmap, canon, changed, tmp; -+ -+ sections = buffer + get32(&hdr->e_shoff); -+ secstrings = buffer + get32(§ions[get16(&hdr->e_shstrndx)].sh_offset); -+ shnum = get16(&hdr->e_shnum); -+ -+ /* find the symbol table and the string table and produce a list of -+ * index numbers of sections that contribute to the kernel's module -+ * image -+ */ -+ canonlist = calloc(sizeof(int), shnum * 2); -+ if (!canonlist) { -+ perror("calloc"); -+ exit(1); -+ } -+ canonmap = canonlist + shnum; -+ canon = 0; -+ -+ symbols = NULL; -+ strings = NULL; -+ nstrings = 0; -+ nsyms = 0; -+ -+ for (loop = 1; loop < shnum; loop++) { -+ const char *sh_name = secstrings + get32(§ions[loop].sh_name); -+ Elf32_Word sh_type = get32(§ions[loop].sh_type); -+ Elf32_Xword sh_size = get32(§ions[loop].sh_size); -+ Elf32_Xword sh_flags = get32(§ions[loop].sh_flags); -+ Elf64_Word sh_info = get32(§ions[loop].sh_info); -+ Elf32_Off sh_offset = get32(§ions[loop].sh_offset); -+ void *data = buffer + sh_offset; -+ -+ /* quick sanity check */ -+ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { -+ fprintf(stderr, "Section goes beyond EOF\n"); -+ exit(3); -+ } -+ -+ /* we only need to canonicalise allocatable sections */ -+ if (sh_flags & SHF_ALLOC) -+ canonlist[canon++] = loop; -+ else if ((sh_type == SHT_REL || sh_type == SHT_RELA) && -+ get32(§ions[sh_info].sh_flags) & SHF_ALLOC) -+ canonlist[canon++] = loop; -+ -+ /* keep track of certain special sections */ -+ switch (sh_type) { -+ case SHT_SYMTAB: -+ if (strcmp(sh_name, ".symtab") == 0) { -+ symbols = data; -+ nsyms = sh_size / sizeof(Elf32_Sym); -+ } -+ break; -+ -+ case SHT_STRTAB: -+ if (strcmp(sh_name, ".strtab") == 0) { -+ strings = data; -+ nstrings = sh_size; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ } -+ -+ if (!symbols) { -+ fprintf(stderr, "Couldn't locate symbol table\n"); -+ exit(3); -+ } -+ -+ if (!strings) { -+ fprintf(stderr, "Couldn't locate strings table\n"); -+ exit(3); -+ } -+ -+ /* canonicalise the index numbers of the contributing section */ -+ do { -+ changed = 0; -+ -+ for (loop = 0; loop < canon - 1; loop++) { -+ const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name); -+ const char *y = secstrings + get32(§ions[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 = 1; -+ } -+ } -+ -+ } while (changed); -+ -+ for (loop = 0; loop < canon; loop++) -+ canonmap[canonlist[loop]] = loop + 1; -+ -+ if (is_verbose > 1) { -+ printf("\nSection canonicalisation map:\n"); -+ for (loop = 1; loop < shnum; loop++) { -+ const char *x = secstrings + get32(§ions[loop].sh_name); -+ printf("%4d %s\n", canonmap[loop], x); -+ } -+ -+ printf("\nAllocated section list in canonical order:\n"); -+ for (loop = 0; loop < canon; loop++) { -+ const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name); -+ printf("%4d %s\n", canonlist[loop], x); -+ } -+ } -+ -+ /* iterate through the section table looking for sections we want to -+ * contribute to the signature */ -+ verbose("\n"); -+ verbose("CAN FILE POS CS SECT NAME\n"); -+ verbose("=== ======== == ==== ==============================\n"); -+ -+ for (loop = 0; loop < canon; loop++) { -+ int sect = canonlist[loop]; -+ const char *sh_name = secstrings + get32(§ions[sect].sh_name); -+ Elf32_Word sh_type = get32(§ions[sect].sh_type); -+ Elf32_Xword sh_size = get32(§ions[sect].sh_size); -+ Elf32_Xword sh_flags = get32(§ions[sect].sh_flags); -+ Elf32_Word sh_info = get32(§ions[sect].sh_info); -+ Elf32_Off sh_offset = get32(§ions[sect].sh_offset); -+ void *data = buffer + sh_offset; -+ -+ csum = 0; -+ -+ /* quick sanity check */ -+ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { -+ fprintf(stderr, "section goes beyond EOF\n"); -+ exit(3); -+ } -+ -+ /* include canonicalised relocation sections */ -+ if (sh_type == SHT_REL || sh_type == SHT_RELA) { -+ Elf32_Word canon_sh_info; -+ -+ if (sh_info <= 0 && sh_info >= hdr->e_shnum) { -+ fprintf(stderr, -+ "Invalid ELF - REL/RELA sh_info does" -+ " not refer to a valid section\n"); -+ exit(3); -+ } -+ -+ verbose("%3u %08lx ", loop, ftell(outfd)); -+ -+ set32(&canon_sh_info, canonmap[sh_info]); -+ -+ /* write out selected portions of the section header */ -+ write_out(sh_name, strlen(sh_name)); -+ write_out_val(sections[sect].sh_type); -+ write_out_val(sections[sect].sh_flags); -+ write_out_val(sections[sect].sh_size); -+ write_out_val(sections[sect].sh_addralign); -+ write_out_val(canon_sh_info); -+ -+ if (sh_type == SHT_RELA) -+ extract_elf32_rela(buffer, sect, sh_info, -+ data, sh_size / sizeof(Elf32_Rela), -+ symbols, nsyms, -+ sections, shnum, canonmap, -+ strings, nstrings, -+ sh_name); -+ else -+ extract_elf32_rel(buffer, sect, sh_info, -+ data, sh_size / sizeof(Elf32_Rel), -+ symbols, nsyms, -+ sections, shnum, canonmap, -+ strings, nstrings, -+ sh_name); -+ continue; -+ } -+ -+ /* include the headers of BSS sections */ -+ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { -+ verbose("%3u %08lx ", loop, ftell(outfd)); -+ -+ /* write out selected portions of the section header */ -+ write_out(sh_name, strlen(sh_name)); -+ write_out_val(sections[sect].sh_type); -+ write_out_val(sections[sect].sh_flags); -+ write_out_val(sections[sect].sh_size); -+ write_out_val(sections[sect].sh_addralign); -+ -+ verbose("%02x %4d %s\n", csum, sect, sh_name); -+ } -+ -+ /* include allocatable loadable sections */ -+ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) -+ goto include_section; -+ -+ /* not this section */ -+ continue; -+ -+ include_section: -+ verbose("%3u %08lx ", loop, ftell(outfd)); -+ -+ /* write out selected portions of the section header */ -+ write_out(sh_name, strlen(sh_name)); -+ write_out_val(sections[sect].sh_type); -+ write_out_val(sections[sect].sh_flags); -+ write_out_val(sections[sect].sh_size); -+ write_out_val(sections[sect].sh_addralign); -+ -+ /* write out the section data */ -+ write_out(data, sh_size); -+ -+ verbose("%02x %4d %s\n", csum, sect, sh_name); -+ } -+ -+ verbose("%08lx (%lu bytes csum 0x%02x)\n", -+ ftell(outfd), ftell(outfd), xcsum); -+} -diff --git a/scripts/mod/modsign-note.sh b/scripts/mod/modsign-note.sh -new file mode 100644 -index 0000000..bca67c0 ---- /dev/null -+++ b/scripts/mod/modsign-note.sh -@@ -0,0 +1,16 @@ -+#!/bin/sh -+# -+# Generate a module signature note source file -+# -+# mod-sign.sh > -+# -+ -+SIG=$1 -+ -+cat < -+ -+ELFNOTE(MODSIGN_NOTE_NAME, MODSIGN_NOTE_TYPE, .incbin "$SIG") -+EOF -+ -+exit 0 --- -1.7.10.4 - - -From 05f68f1852611dd7f2f7d28c677b1205b66d4337 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:27:49 +0100 -Subject: [PATCH 20/27] 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. - -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. - -This table indicates the behaviours in the various situations: - - MODULE STATE PERMISSIVE MODE ENFORCING MODE - ======================================= =============== =============== - Unsigned Ok EKEYREJECTED - Signed, no public key ENOKEY ENOKEY - Validly signed, public key Ok Ok - Invalidly signed, public key EKEYREJECTED EKEYREJECTED - Validly signed, expired key EKEYEXPIRED EKEYEXPIRED - Signed, hash algorithm unavailable ENOPKG ENOPKG - Corrupt signature EBADMSG EBADMSG - Corrupt ELF ELIBBAD ELIBBAD - -Signed-off-by: David Howells ---- - include/linux/module.h | 3 ++ - kernel/Makefile | 1 + - kernel/module-verify-defs.h | 77 ++++++++++++++++++++++++++++++ - kernel/module-verify.c | 110 +++++++++++++++++++++++++++++++++++++++++++ - kernel/module-verify.h | 20 ++++++++ - kernel/module.c | 26 ++++++++-- - 6 files changed, 232 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/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]; - -+ /* 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 c0cc67a..cec222a 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -55,6 +55,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..141ddab ---- /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..4bf857e ---- /dev/null -+++ b/kernel/module-verify.c -@@ -0,0 +1,110 @@ -+/* 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#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..c640634 ---- /dev/null -+++ b/kernel/module-verify.h -@@ -0,0 +1,20 @@ -+/* 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 087aeed..a59a9da 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -58,6 +58,7 @@ - #include - #include - #include -+#include "module-verify.h" - - #define CREATE_TRACE_POINTS - #include -@@ -2382,7 +2383,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; -@@ -2415,6 +2417,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; -@@ -2757,7 +2765,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; -@@ -2767,6 +2776,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) -@@ -2850,17 +2860,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; -@@ -3497,8 +3508,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.10.4 - - -From a8622506bccd42aecd271d2735f6734e539125ac Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:28:33 +0100 -Subject: [PATCH 21/27] 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 ---- - kernel/Makefile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 49 insertions(+) - -diff --git a/kernel/Makefile b/kernel/Makefile -index cec222a..28cd248 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -132,3 +132,52 @@ 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) -+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 "###" >&2 -+ @echo "### Now generating a sample key generation script." >&2 -+ @echo "###" >&2 -+ @echo "### IT IS STRONGLY RECOMMENDED THAT YOU SUPPLY YOUR OWN" >&2 -+ @echo "### SCRIPT WITH APPROPRIATE NAME FIELDS FILLED IN." >&2 -+ @echo "###" >&2 -+ @echo "### If you have a hardware random number generator feeding" >&2 -+ @echo "### into /dev/random, you should drop the %no-protection" >&2 -+ @echo "### and %transient-key lines from the script." >&2 -+ @echo "###" >&2 -+ 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.4 - - -From 2bde4c453e0b5ec52fe95c3fb800af86fdc38546 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:28:41 +0100 -Subject: [PATCH 22/27] 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 ---- - kernel/Makefile | 25 ++++++++------- - kernel/modsign-pubkey.c | 75 +++++++++++++++++++++++++++++++++++++++++++ - kernel/module-verify-defs.h | 4 +++ - kernel/module-verify.c | 2 -- - 4 files changed, 93 insertions(+), 13 deletions(-) - create mode 100644 kernel/modsign-pubkey.c - -diff --git a/kernel/Makefile b/kernel/Makefile -index 28cd248..1d20704 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -55,7 +55,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 -@@ -159,16 +160,18 @@ modsign.pub modsign.sec: genkey - rm -f pubring.gpg secring.gpg trustdb.gpg - - genkey: -- @echo "###" >&2 -- @echo "### Now generating a sample key generation script." >&2 -- @echo "###" >&2 -- @echo "### IT IS STRONGLY RECOMMENDED THAT YOU SUPPLY YOUR OWN" >&2 -- @echo "### SCRIPT WITH APPROPRIATE NAME FIELDS FILLED IN." >&2 -- @echo "###" >&2 -- @echo "### If you have a hardware random number generator feeding" >&2 -- @echo "### into /dev/random, you should drop the %no-protection" >&2 -- @echo "### and %transient-key lines from the script." >&2 -- @echo "###" >&2 -+ @echo "kernel/Makefile:163: ###" >&2 -+ @echo "kernel/Makefile:163: ### CONFIG_MODULE_SIG is enabled so a public key is needed." >&2 -+ @echo "kernel/Makefile:163: ###" >&2 -+ @echo "kernel/Makefile:163: ### Now generating a sample key generation script." >&2 -+ @echo "kernel/Makefile:163: ###" >&2 -+ @echo "kernel/Makefile:163: ### IT IS STRONGLY RECOMMENDED THAT YOU SUPPLY YOUR OWN" >&2 -+ @echo "kernel/Makefile:163: ### SCRIPT WITH APPROPRIATE NAME FIELDS FILLED IN." >&2 -+ @echo "kernel/Makefile:163: ###" >&2 -+ @echo "kernel/Makefile:163: ### If you have a hardware random number generator feeding" >&2 -+ @echo "kernel/Makefile:163: ### into /dev/random, you should drop the %no-protection" >&2 -+ @echo "kernel/Makefile:163: ### and %transient-key lines from the script." >&2 -+ @echo "kernel/Makefile:163: ###" >&2 - echo "%pubring modsign.pub" >genkey - echo "%secring modsign.sec" >>genkey - echo "%no-protection: yes" >> genkey -diff --git a/kernel/modsign-pubkey.c b/kernel/modsign-pubkey.c -new file mode 100644 -index 0000000..17e02f5 ---- /dev/null -+++ b/kernel/modsign-pubkey.c -@@ -0,0 +1,75 @@ -+/* 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 -+#include -+#include -+#include -+#include -+#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 141ddab..2fe31e1 100644 ---- a/kernel/module-verify-defs.h -+++ b/kernel/module-verify-defs.h -@@ -11,6 +11,10 @@ - - #ifdef CONFIG_MODULE_SIG - -+#include -+ -+extern struct key *modsign_keyring; -+ - /* - * Internal state - */ -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index 4bf857e..05473e6 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -28,8 +28,6 @@ - #include - #include - #include --#include --#include - #include - #include - #include --- -1.7.10.4 - - -From 689ea2a8739a5d61b7c55cd9084dd3096585c6de Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:29:17 +0100 -Subject: [PATCH 23/27] 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 ---- - kernel/module-verify.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 230 insertions(+) - -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index 05473e6..2161d11 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -51,6 +51,228 @@ 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, 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 */ -+ section = &mvdata->sections[SHN_UNDEF]; -+ seccheck(section->sh_type == SHT_NULL); -+ -+ /* We also want access to the section name table */ -+ section = &mvdata->sections[hdr->e_shstrndx]; -+ seccheck(section->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); -+ if (section->sh_addralign > 1) -+ 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: -+#ifdef Elf_Rel -+ seccheck(section->sh_entsize == sizeof(Elf_Rel)); -+ seccheck(section->sh_addralign % sizeof(long) == 0); -+ break; -+#else -+ seccheck(false); -+ break; -+#endif -+ case SHT_RELA: -+#ifdef Elf_Rela -+ 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. -+ */ -+ 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; -+ -+#ifdef Elf_Rel -+ case SHT_REL: -+#endif -+#ifdef Elf_Rela -+ 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) -@@ -62,6 +284,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.4 - - -From 4e90f1f1f04b2efb070f15211e644a8a86a2142e Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:29:43 +0100 -Subject: [PATCH 24/27] 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 ---- - kernel/module-verify.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 80 insertions(+) - -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index 2161d11..646b104 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -273,6 +273,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) -@@ -303,7 +377,13 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) - goto out; - } - -+ /* Produce a canonicalisation map for the sections */ -+ ret = module_verify_canonicalise(&mvdata); -+ if (ret < 0) -+ goto out; -+ - ret = 0; -+ kfree(mvdata.canonlist); - - out: - switch (ret) { --- -1.7.10.4 - - -From 5f48916c06318abb0821b41bc06f457248ed87eb Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:30:02 +0100 -Subject: [PATCH 25/27] 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 ---- - kernel/module-verify-defs.h | 11 +- - kernel/module-verify.c | 332 ++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 337 insertions(+), 6 deletions(-) - -diff --git a/kernel/module-verify-defs.h b/kernel/module-verify-defs.h -index 2fe31e1..82952b0 100644 ---- a/kernel/module-verify-defs.h -+++ b/kernel/module-verify-defs.h -@@ -42,15 +42,16 @@ struct module_verify_data { - /* - * Whether or not we support various types of ELF relocation record - */ --#if defined(MODULE_HAS_ELF_REL_ONLY) -+#ifdef Elf_Rel - #define is_elf_rel(sh_type) ((sh_type) == SHT_REL) --#define is_elf_rela(sh_type) (0) --#elif defined(MODULE_HAS_ELF_RELA_ONLY) -+#else - #define is_elf_rel(sh_type) (0) -+#endif -+ -+#ifdef Elf_Rela - #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) -+#define is_elf_rela(sh_type) (0) - #endif - - /* -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index 646b104..e275759 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -50,6 +50,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. -@@ -346,6 +362,320 @@ static int module_verify_canonicalise(struct module_verify_data *mvdata) - return 0; - } - -+#ifdef Elf_Rel -+/* -+ * 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 { -+#ifdef CONFIG_64BIT -+ 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 -+ 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; -+#endif -+ } __packed relocation; -+ -+ const Elf_Shdr *relsec, *symsec, *strsec; -+ const Elf_Rel *reloc; -+ const Elf_Sym *symbols, *symbol; -+ const char *strings; -+ unsigned long r_sym; -+ 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 -+ * { 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; -+} -+#endif -+ -+#ifdef Elf_Rela -+/* -+ * 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 { -+#ifdef CONFIG_64BIT -+ 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 -+ 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; -+#endif -+ } __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; -+} -+#endif -+ -+/* -+ * 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. -+ */ -+#ifdef Elf_Rel -+ 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; -+ } -+#endif -+ -+#ifdef Elf_Rela -+ 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; -+ } -+#endif -+ -+ /* 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 - */ -@@ -382,7 +712,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.4 - - -From 25841b75e473511f1dbe84cfb333ef2b748d2ec6 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:30:22 +0100 -Subject: [PATCH 26/27] 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 ---- - kernel/module-verify.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index e275759..bfd1286 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -97,11 +97,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.4 - - -From 3ac2defabc1996584fac06b76070138fe56753e6 Mon Sep 17 00:00:00 2001 -From: David Howells -Date: Wed, 18 Jul 2012 16:30:40 +0100 -Subject: [PATCH 27/27] MODSIGN: Panic the kernel if FIPS is enabled upon - module signing failure - -If module signing fails when the kernel is running with FIPS enabled then the -kernel should panic lest the crypto layer be compromised. Possibly a panic -shouldn't happen on cases like ENOMEM. - -Reported-by: Stephan Mueller -Signed-off-by: David Howells ---- - kernel/module-verify.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/kernel/module-verify.c b/kernel/module-verify.c -index bfd1286..b9c3955 100644 ---- a/kernel/module-verify.c -+++ b/kernel/module-verify.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - #include - #include "module-verify.h" - #include "module-verify-defs.h" -@@ -716,6 +717,10 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) - kfree(mvdata.canonlist); - - out: -+ if (ret < 0 && fips_enabled) -+ panic("Module verification failed with error %d in FIPS mode\n", -+ ret); -+ - switch (ret) { - case 0: /* Good signature */ - *_gpgsig_ok = true; --- -1.7.10.4 - diff --git a/modsign-20120724.patch b/modsign-20120724.patch new file mode 100644 index 0000000..d37497d --- /dev/null +++ b/modsign-20120724.patch @@ -0,0 +1,8670 @@ +From d012ed16fd7eff5498ddd9be8ad9960a644db518 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 13:59:15 +0100 +Subject: [PATCH 01/27] MPILIB: Provide count_leading/trailing_zeros() based + on arch functions + +Provide count_leading/trailing_zeros() macros based on extant arch bit scanning +functions rather than reimplementing from scratch in MPILIB. + +Whilst we're at it, turn count_foo_zeros(n, x) into n = count_foo_zeros(x). + +Also move the definition to asm-generic as other people may be interested in +using it. + +Signed-off-by: David Howells +Cc: David S. Miller +Cc: Dmitry Kasatkin +Cc: Arnd Bergmann +--- + include/asm-generic/bitops/count_zeros.h | 57 +++++++++++++ + lib/mpi/longlong.h | 138 +------------------------------ + lib/mpi/mpi-bit.c | 2 +- + lib/mpi/mpi-pow.c | 4 +- + 4 files changed, 62 insertions(+), 139 deletions(-) + create mode 100644 include/asm-generic/bitops/count_zeros.h + +diff --git a/include/asm-generic/bitops/count_zeros.h b/include/asm-generic/bitops/count_zeros.h +new file mode 100644 +index 0000000..97520d2 +--- /dev/null ++++ b/include/asm-generic/bitops/count_zeros.h +@@ -0,0 +1,57 @@ ++/* Count leading and trailing zeros functions ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ ++#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ ++ ++#include ++ ++/** ++ * count_leading_zeros - Count the number of zeros from the MSB back ++ * @x: The value ++ * ++ * Count the number of leading zeros from the MSB going towards the LSB in @x. ++ * ++ * If the MSB of @x is set, the result is 0. ++ * If only the LSB of @x is set, then the result is BITS_PER_LONG-1. ++ * If @x is 0 then the result is COUNT_LEADING_ZEROS_0. ++ */ ++static inline int count_leading_zeros(unsigned long x) ++{ ++ if (sizeof(x) == 4) ++ return BITS_PER_LONG - fls(x); ++ else ++ return BITS_PER_LONG - fls64(x); ++} ++ ++#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG ++ ++/** ++ * count_trailing_zeros - Count the number of zeros from the LSB forwards ++ * @x: The value ++ * ++ * Count the number of trailing zeros from the LSB going towards the MSB in @x. ++ * ++ * If the LSB of @x is set, the result is 0. ++ * If only the MSB of @x is set, then the result is BITS_PER_LONG-1. ++ * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0. ++ */ ++static inline int count_trailing_zeros(unsigned long x) ++{ ++#define COUNT_TRAILING_ZEROS_0 (-1) ++ ++ if (sizeof(x) == 4) ++ return ffs(x); ++ else ++ return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0; ++} ++ ++#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */ +diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h +index 29f9862..678ce4f 100644 +--- a/lib/mpi/longlong.h ++++ b/lib/mpi/longlong.h +@@ -19,6 +19,8 @@ + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. */ + ++#include ++ + /* You have to define the following before including this file: + * + * UWtype -- An unsigned type, default type for operations (typically a "word") +@@ -146,12 +148,6 @@ do { \ + : "1" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "r" ((USItype)(d))) +- +-#define count_leading_zeros(count, x) \ +- __asm__ ("clz %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x))) +-#define COUNT_LEADING_ZEROS_0 32 + #endif /* __a29k__ */ + + #if defined(__alpha) && W_TYPE_SIZE == 64 +@@ -298,11 +294,6 @@ extern UDItype __udiv_qrnnd(); + : "1" ((USItype)(nh)), \ + "0" ((USItype)(nl)), \ + "g" ((USItype)(d))) +-#define count_leading_zeros(count, x) \ +- __asm__ ("bsch/1 %1,%0" \ +- : "=g" (count) \ +- : "g" ((USItype)(x)), \ +- "0" ((USItype)0)) + #endif + + /*************************************** +@@ -354,27 +345,6 @@ do { USItype __r; \ + } while (0) + extern USItype __udiv_qrnnd(); + #endif /* LONGLONG_STANDALONE */ +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __tmp; \ +- __asm__ ( \ +- "ldi 1,%0\n" \ +- "extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ +- "extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n" \ +- "ldo 16(%0),%0 ; Yes. Perform add.\n" \ +- "extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ +- "extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n" \ +- "ldo 8(%0),%0 ; Yes. Perform add.\n" \ +- "extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ +- "extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n" \ +- "ldo 4(%0),%0 ; Yes. Perform add.\n" \ +- "extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ +- "extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n" \ +- "ldo 2(%0),%0 ; Yes. Perform add.\n" \ +- "extru %1,30,1,%1 ; Extract bit 1.\n" \ +- "sub %0,%1,%0 ; Subtract it. " \ +- : "=r" (count), "=r" (__tmp) : "1" (x)); \ +-} while (0) + #endif /* hppa */ + + /*************************************** +@@ -457,15 +427,6 @@ do { \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "rm" ((USItype)(d))) +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __cbtmp; \ +- __asm__ ("bsrl %1,%0" \ +- : "=r" (__cbtmp) : "rm" ((USItype)(x))); \ +- (count) = __cbtmp ^ 31; \ +-} while (0) +-#define count_trailing_zeros(count, x) \ +- __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) + #ifndef UMUL_TIME + #define UMUL_TIME 40 + #endif +@@ -536,15 +497,6 @@ do { \ + "dI" ((USItype)(d))); \ + (r) = __rq.__i.__l; (q) = __rq.__i.__h; \ + } while (0) +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __cbtmp; \ +- __asm__ ("scanbit %1,%0" \ +- : "=r" (__cbtmp) \ +- : "r" ((USItype)(x))); \ +- (count) = __cbtmp ^ 31; \ +-} while (0) +-#define COUNT_LEADING_ZEROS_0 (-32) /* sic */ + #if defined(__i960mx) /* what is the proper symbol to test??? */ + #define rshift_rhlc(r, h, l, c) \ + do { \ +@@ -603,11 +555,6 @@ do { \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "dmi" ((USItype)(d))) +-#define count_leading_zeros(count, x) \ +- __asm__ ("bfffo %1{%b2:%b2},%0" \ +- : "=d" ((USItype)(count)) \ +- : "od" ((USItype)(x)), "n" (0)) +-#define COUNT_LEADING_ZEROS_0 32 + #else /* not mc68020 */ + #define umul_ppmm(xh, xl, a, b) \ + do { USItype __umul_tmp1, __umul_tmp2; \ +@@ -664,15 +611,6 @@ do { USItype __umul_tmp1, __umul_tmp2; \ + "rJ" ((USItype)(bh)), \ + "rJ" ((USItype)(al)), \ + "rJ" ((USItype)(bl))) +-#define count_leading_zeros(count, x) \ +-do { \ +- USItype __cbtmp; \ +- __asm__ ("ff1 %0,%1" \ +- : "=r" (__cbtmp) \ +- : "r" ((USItype)(x))); \ +- (count) = __cbtmp ^ 31; \ +-} while (0) +-#define COUNT_LEADING_ZEROS_0 63 /* sic */ + #if defined(__m88110__) + #define umul_ppmm(wh, wl, u, v) \ + do { \ +@@ -779,12 +717,6 @@ do { \ + : "0" (__xx.__ll), \ + "g" ((USItype)(d))); \ + (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) +-#define count_trailing_zeros(count, x) \ +-do { \ +- __asm__("ffsd %2,%0" \ +- : "=r"((USItype) (count)) \ +- : "0"((USItype) 0), "r"((USItype) (x))); \ +- } while (0) + #endif /* __ns32000__ */ + + /*************************************** +@@ -855,11 +787,6 @@ do { \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + } while (0) +-#define count_leading_zeros(count, x) \ +- __asm__ ("{cntlz|cntlzw} %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x))) +-#define COUNT_LEADING_ZEROS_0 32 + #if defined(_ARCH_PPC) + #define umul_ppmm(ph, pl, m0, m1) \ + do { \ +@@ -1001,19 +928,6 @@ do { \ + } while (0) + #define UMUL_TIME 20 + #define UDIV_TIME 200 +-#define count_leading_zeros(count, x) \ +-do { \ +- if ((x) >= 0x10000) \ +- __asm__ ("clz %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x) >> 16)); \ +- else { \ +- __asm__ ("clz %0,%1" \ +- : "=r" ((USItype)(count)) \ +- : "r" ((USItype)(x))); \ +- (count) += 16; \ +- } \ +-} while (0) + #endif /* RT/ROMP */ + + /*************************************** +@@ -1142,13 +1056,6 @@ do { \ + "rI" ((USItype)(d)) \ + : "%g1" __AND_CLOBBER_CC) + #define UDIV_TIME 37 +-#define count_leading_zeros(count, x) \ +- __asm__ ("scan %1,0,%0" \ +- : "=r" ((USItype)(x)) \ +- : "r" ((USItype)(count))) +-/* Early sparclites return 63 for an argument of 0, but they warn that future +- implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 +- undefined. */ + #endif /* __sparclite__ */ + #endif /* __sparc_v8__ */ + /* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd. */ +@@ -1454,47 +1361,6 @@ do { \ + #define udiv_qrnnd __udiv_qrnnd_c + #endif + +-#undef count_leading_zeros +-#if !defined(count_leading_zeros) +- extern +-#ifdef __STDC__ +- const +-#endif +- unsigned char __clz_tab[]; +-#define count_leading_zeros(count, x) \ +-do { \ +- UWtype __xr = (x); \ +- UWtype __a; \ +- \ +- if (W_TYPE_SIZE <= 32) { \ +- __a = __xr < ((UWtype) 1 << 2*__BITS4) \ +- ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \ +- : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ +- } \ +- else { \ +- for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ +- if (((__xr >> __a) & 0xff) != 0) \ +- break; \ +- } \ +- \ +- (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ +-} while (0) +- /* This version gives a well-defined value for zero. */ +-#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +-#endif +- +-#if !defined(count_trailing_zeros) +-/* Define count_trailing_zeros using count_leading_zeros. The latter might be +- defined in asm, but if it is not, the C version above is good enough. */ +-#define count_trailing_zeros(count, x) \ +-do { \ +- UWtype __ctz_x = (x); \ +- UWtype __ctz_c; \ +- count_leading_zeros(__ctz_c, __ctz_x & -__ctz_x); \ +- (count) = W_TYPE_SIZE - 1 - __ctz_c; \ +-} while (0) +-#endif +- + #ifndef UDIV_NEEDS_NORMALIZATION + #define UDIV_NEEDS_NORMALIZATION 0 + #endif +diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c +index 5687248..503537e 100644 +--- a/lib/mpi/mpi-bit.c ++++ b/lib/mpi/mpi-bit.c +@@ -45,7 +45,7 @@ unsigned mpi_get_nbits(MPI a) + if (a->nlimbs) { + mpi_limb_t alimb = a->d[a->nlimbs - 1]; + if (alimb) +- count_leading_zeros(n, alimb); ++ n = count_leading_zeros(alimb); + else + n = BITS_PER_MPI_LIMB; + n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB; +diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c +index 67f3e79..5464c87 100644 +--- a/lib/mpi/mpi-pow.c ++++ b/lib/mpi/mpi-pow.c +@@ -77,7 +77,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) + mp = mp_marker = mpi_alloc_limb_space(msize); + if (!mp) + goto enomem; +- count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); ++ mod_shift_cnt = count_leading_zeros(mod->d[msize - 1]); + if (mod_shift_cnt) + mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); + else +@@ -169,7 +169,7 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) + + i = esize - 1; + e = ep[i]; +- count_leading_zeros(c, e); ++ c = count_leading_zeros(e); + e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ + c = BITS_PER_MPI_LIMB - 1 - c; + +-- +1.7.11.2 + + +From e2faf6ee3cc2f8cfe1c18e8d31eaf01fa653fd79 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 13:59:51 +0100 +Subject: [PATCH 02/27] 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. + +The key type is "crypto" and can provide access to a variety of cryptographic +algorithms. + +Signed-off-by: David Howells +--- + Documentation/security/keys-crypto.txt | 181 ++++++++++++++++++++++++++ + include/keys/crypto-subtype.h | 56 ++++++++ + include/keys/crypto-type.h | 25 ++++ + 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/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 +index 0000000..97dee80 +--- /dev/null ++++ b/Documentation/security/keys-crypto.txt +@@ -0,0 +1,181 @@ ++ ====================== ++ CRYPTOGRAPHIC KEY TYPE ++ ====================== ++ ++Contents: ++ ++ - Overview. ++ - Key identification. ++ - Accessing crypto keys. ++ - Implementing crypto parsers. ++ - Implementing crypto subtypes. ++ ++ ++======== ++OVERVIEW ++======== ++ ++The "crypto" key type is designed to be a container for cryptographic keys, ++without imposing any particular restrictions on the form of the cryptography or ++the key. ++ ++The crypto key is given a subtype that defines what sort of data is associated ++with the key and provides operations to describe and destroy it. However, no ++requirement is made that the key data actually be loaded into the key. ++ ++The crypto key also has a number of data parsers registered with it. The data ++parsers are responsible for extracing information the blobs of data passed to ++the instantiator function. The first data parser that recognises the blob gets ++to set the subtype of the key and define the operations that can be done on ++that key. ++ ++Completely in-kernel key retention and operation subtypes and parsers can be ++defined, but it would also be possible to provide access to cryptographic ++hardware (such as a TPM) that might be used to both retain the relevant key and ++perform operations using that key. In such a case, the crypto key would then ++merely be an interface to the TPM driver. ++ ++ ++================== ++KEY IDENTIFICATION ++================== ++ ++Because the identity of a key is not necessarily known and may not be easily ++calculated when a crypto key is allocated, it may not be a simple matter to set ++a key description to something that's useful for determining whether this is ++the key you're looking for. Furthermore, it may be necessary to perform a ++partial match upon the key identity. ++ ++To help with this, when a key is loaded, the parser calculates the key ++fingerprint and stores a copy in the key structure. ++ ++The crypto key type's key matching function then performs more checks than just ++the straightforward comparison of the description with the criterion string: ++ ++ (1) If the criterion string is of the form "id:" then the match ++ function will examine a key's fingerprint to see if the hex digits given ++ after the "id:" match the tail. For instance: ++ ++ keyctl search @s crypto id:5acc2142 ++ ++ will match a key with fingerprint: ++ ++ 1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142 ++ ++ (2) If the criterion string is of the form ":" then the ++ match will match the ID as in (1), but with the added restriction that ++ only keys of the specified subtype (e.g. dsa or rsa) will be matched. For ++ instance: ++ ++ keyctl search @s crypto dsa:5acc2142 ++ ++Looking in /proc/keys, the last 8 hex digits of the key fingerprint are ++displayed, along with the subtype: ++ ++ 1a39e171 I----- 1 perm 3f010000 0 0 crypto modsign.0: DSA 5acc2142 [] ++ ++ ++===================== ++ACCESSING CRYPTO KEYS ++===================== ++ ++To access crypto keys from within the kernel, the following inclusion is ++required: ++ ++ #include ++ ++This gives access to the key type: ++ ++ struct key_type key_type_crypto; ++ ++ ++=========================== ++IMPLEMENTING CRYPTO PARSERS ++=========================== ++ ++The crypto key type keeps a list of registered data parsers. An example of ++such a parser is one that parses OpenPGP packet formatted data [RFC 4880]. ++ ++During key instantiation each parser in the list is tried until one doesn't ++return -EBADMSG. ++ ++The parser definition structure looks like the following: ++ ++ struct crypto_key_parser { ++ struct module *owner; ++ const char *name; ++ ++ int (*instantiate)(struct key *key, ++ const void *data, size_t datalen); ++ }; ++ ++The owner and name fields should be set to the owning module and the name of ++the parser. ++ ++There are a number of operations defined by the parser. They are all optional, ++but it is expected that at least one will be defined. ++ ++ (1) instantiate(). ++ ++ The arguments are the same as for the instantiate function in the key ++ type. 'key' is the crypto key being instantiated; data and datalen are ++ the instantiation data, presumably containing cryptographic key data, and ++ the length of that data. ++ ++ If the data format is not recognised, -EBADMSG should be returned. If it ++ is recognised, but the key cannot for some reason be set up, some other ++ negative error code should be returned. ++ ++ If the key can be successfully set up, then key->payload should be set to ++ point to the retained data, key->type_data.p[0] should be set to point to ++ the subtype chosen and key->type_data.p[1] should be set to point to a ++ copy of the key's identity string and 0 should be returned. ++ ++ The key's identity string may be partially matched upon. For a public-key ++ algorithm such as RSA and DSA this will likely be a printable hex version ++ of the key's fingerprint. ++ ++Functions are provided to register and unregister parsers: ++ ++ int register_crypto_key_parser(struct crypto_key_parser *parser); ++ void unregister_crypto_key_parser(struct crypto_key_parser *subtype); ++ ++Parsers may not have the same name. The names are only used for displaying in ++debugging messages. ++ ++ ++============================ ++IMPLEMENTING CRYPTO SUBTYPES ++============================ ++ ++The parser selects the appropriate subtype directly and sets it on the key; the ++crypto key then retains a reference on the subtype module (which means the ++parser can be removed thereafter). ++ ++The subtype definition structure looks like the following: ++ ++ struct crypto_key_subtype { ++ struct module *owner; ++ const char *name; ++ ++ void (*describe)(const struct key *key, struct seq_file *m); ++ void (*destroy)(void *payload); ++ }; ++ ++The owner and name fields should be set to the owning module and the name of ++the subtype. ++ ++There are a number of operations defined by the subtype: ++ ++ (1) describe(). ++ ++ Mandatory. This allows the subtype to display something in /proc/keys ++ against the key. For instance the name of the public key algorithm type ++ could be displayed. The key type will display the tail of the key ++ identity string after this. ++ ++ (2) destroy(). ++ ++ Mandatory. This should free the memory associated with the key. The ++ crypto key will look after freeing the fingerprint and releasing the ++ reference on the subtype module. +diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h +new file mode 100644 +index 0000000..fa87555 +--- /dev/null ++++ b/include/keys/crypto-subtype.h +@@ -0,0 +1,56 @@ ++/* Cryptographic key subtype ++ * ++ * 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. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#ifndef _KEYS_CRYPTO_SUBTYPE_H ++#define _KEYS_CRYPTO_SUBTYPE_H ++ ++#include ++#include ++ ++extern struct key_type key_type_crypto; ++ ++/* ++ * Keys of this type declare a subtype that indicates the handlers and ++ * capabilities. ++ */ ++struct crypto_key_subtype { ++ struct module *owner; ++ const char *name; ++ unsigned short name_len; /* length of name */ ++ ++ void (*describe)(const struct key *key, struct seq_file *m); ++ ++ void (*destroy)(void *payload); ++}; ++ ++/* ++ * Data parser. Called during instantiation and signature verification ++ * initiation. ++ */ ++struct crypto_key_parser { ++ struct list_head link; ++ struct module *owner; ++ const char *name; ++ ++ /* Attempt to instantiate a key from the data blob passed to add_key() ++ * or keyctl_instantiate(). ++ * ++ * Return EBADMSG if not recognised. ++ */ ++ int (*instantiate)(struct key *key, const void *data, size_t datalen); ++}; ++ ++extern int register_crypto_key_parser(struct crypto_key_parser *); ++extern void unregister_crypto_key_parser(struct crypto_key_parser *); ++ ++#endif /* _KEYS_CRYPTO_SUBTYPE_H */ +diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h +new file mode 100644 +index 0000000..47c00c7 +--- /dev/null ++++ b/include/keys/crypto-type.h +@@ -0,0 +1,25 @@ ++/* Cryptographic key type interface ++ * ++ * 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. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#ifndef _KEYS_CRYPTO_TYPE_H ++#define _KEYS_CRYPTO_TYPE_H ++ ++#include ++ ++extern struct key_type key_type_crypto; ++ ++/* ++ * The payload is at the discretion of the subtype. ++ */ ++ ++#endif /* _KEYS_CRYPTO_TYPE_H */ +diff --git a/security/keys/Kconfig b/security/keys/Kconfig +index a90d6d3..992fe52 100644 +--- a/security/keys/Kconfig ++++ b/security/keys/Kconfig +@@ -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 ++ help ++ 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/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/crypto_keys.h b/security/keys/crypto/crypto_keys.h +new file mode 100644 +index 0000000..a339ce0 +--- /dev/null ++++ b/security/keys/crypto/crypto_keys.h +@@ -0,0 +1,28 @@ ++/* Internal crypto type stuff ++ * ++ * 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. ++ */ ++ ++static inline ++struct crypto_key_subtype *crypto_key_subtype(const struct key *key) ++{ ++ return key->type_data.p[0]; ++} ++ ++static inline char *crypto_key_id(const struct key *key) ++{ ++ return key->type_data.p[1]; ++} ++ ++ ++/* ++ * crypto_type.c ++ */ ++extern struct list_head crypto_key_parsers; ++extern struct rw_semaphore crypto_key_parsers_sem; +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/crypto_type.c +@@ -0,0 +1,228 @@ ++/* Cryptographic key type ++ * ++ * 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. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++#include ++#include ++#include ++#include ++#include "crypto_keys.h" ++ ++MODULE_LICENSE("GPL"); ++ ++LIST_HEAD(crypto_key_parsers); ++DECLARE_RWSEM(crypto_key_parsers_sem); ++ ++/* ++ * Match crypto_keys on (part of) their name ++ * We have some shorthand methods for matching keys. We allow: ++ * ++ * "" - request a key by description ++ * "id:" - request a key matching the ID ++ * ":" - request a key of a subtype ++ */ ++static int crypto_key_match(const struct key *key, const void *description) ++{ ++ const struct crypto_key_subtype *subtype = crypto_key_subtype(key); ++ const char *spec = description; ++ const char *id, *kid; ++ ptrdiff_t speclen; ++ size_t idlen, kidlen; ++ ++ if (!subtype || !spec || !*spec) ++ return 0; ++ ++ /* See if the full key description matches as is */ ++ if (key->description && strcmp(key->description, description) == 0) ++ return 1; ++ ++ /* All tests from here on break the criterion description into a ++ * specifier, a colon and then an identifier. ++ */ ++ id = strchr(spec, ':'); ++ if (!id) ++ return 0; ++ ++ speclen = id - spec; ++ id++; ++ ++ /* Anything after here requires a partial match on the ID string */ ++ kid = crypto_key_id(key); ++ if (!kid) ++ return 0; ++ ++ idlen = strlen(id); ++ kidlen = strlen(kid); ++ if (idlen > kidlen) ++ return 0; ++ ++ kid += kidlen - idlen; ++ if (strcasecmp(id, kid) != 0) ++ return 0; ++ ++ if (speclen == 2 && ++ memcmp(spec, "id", 2) == 0) ++ return 1; ++ ++ if (speclen == subtype->name_len && ++ memcmp(spec, subtype->name, speclen) == 0) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * Describe the crypto key ++ */ ++static void crypto_key_describe(const struct key *key, struct seq_file *m) ++{ ++ const struct crypto_key_subtype *subtype = crypto_key_subtype(key); ++ const char *kid = crypto_key_id(key); ++ size_t n; ++ ++ seq_puts(m, key->description); ++ ++ if (subtype) { ++ seq_puts(m, ": "); ++ subtype->describe(key, m); ++ ++ if (kid) { ++ seq_putc(m, ' '); ++ n = strlen(kid); ++ if (n <= 8) ++ seq_puts(m, kid); ++ else ++ seq_puts(m, kid + n - 8); ++ } ++ ++ seq_puts(m, " ["); ++ /* put something here to indicate the key's capabilities */ ++ seq_putc(m, ']'); ++ } ++} ++ ++/* ++ * Instantiate a crypto_key defined key ++ */ ++static int crypto_key_instantiate(struct key *key, ++ const void *data, size_t datalen) ++{ ++ struct crypto_key_parser *parser; ++ int ret; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (datalen == 0) ++ return -EINVAL; ++ ++ down_read(&crypto_key_parsers_sem); ++ ++ ret = -EBADMSG; ++ list_for_each_entry(parser, &crypto_key_parsers, link) { ++ pr_debug("Trying parser '%s'\n", parser->name); ++ ++ ret = parser->instantiate(key, data, datalen); ++ if (ret != -EBADMSG) { ++ pr_debug("Parser recognised the format (ret %d)\n", ++ ret); ++ break; ++ } ++ } ++ ++ up_read(&crypto_key_parsers_sem); ++ pr_devel("<==%s() = %d\n", __func__, ret); ++ return ret; ++} ++ ++/* ++ * dispose of the data dangling from the corpse of a crypto key ++ */ ++static void crypto_key_destroy(struct key *key) ++{ ++ struct crypto_key_subtype *subtype = crypto_key_subtype(key); ++ if (subtype) { ++ subtype->destroy(key->payload.data); ++ module_put(subtype->owner); ++ key->type_data.p[0] = NULL; ++ } ++ kfree(key->type_data.p[1]); ++ key->type_data.p[1] = NULL; ++} ++ ++struct key_type key_type_crypto = { ++ .name = "crypto", ++ .instantiate = crypto_key_instantiate, ++ .match = crypto_key_match, ++ .destroy = crypto_key_destroy, ++ .describe = crypto_key_describe, ++}; ++EXPORT_SYMBOL_GPL(key_type_crypto); ++ ++/** ++ * register_crypto_key_parser - Register a crypto key blob parser ++ * @parser: The parser to register ++ */ ++int register_crypto_key_parser(struct crypto_key_parser *parser) ++{ ++ struct crypto_key_parser *cursor; ++ int ret; ++ ++ down_write(&crypto_key_parsers_sem); ++ ++ list_for_each_entry(cursor, &crypto_key_parsers, link) { ++ if (strcmp(cursor->name, parser->name) == 0) { ++ pr_err("Crypto key parser '%s' already registered\n", ++ parser->name); ++ ret = -EEXIST; ++ goto out; ++ } ++ } ++ ++ list_add_tail(&parser->link, &crypto_key_parsers); ++ ++ pr_notice("Crypto key parser '%s' registered\n", parser->name); ++ ret = 0; ++ ++out: ++ up_write(&crypto_key_parsers_sem); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(register_crypto_key_parser); ++ ++/** ++ * unregister_crypto_key_parser - Unregister a crypto key blob parser ++ * @parser: The parser to unregister ++ */ ++void unregister_crypto_key_parser(struct crypto_key_parser *parser) ++{ ++ down_write(&crypto_key_parsers_sem); ++ list_del(&parser->link); ++ up_write(&crypto_key_parsers_sem); ++ ++ pr_notice("Crypto key parser '%s' unregistered\n", parser->name); ++} ++EXPORT_SYMBOL_GPL(unregister_crypto_key_parser); ++ ++/* ++ * Module stuff ++ */ ++static int __init crypto_key_init(void) ++{ ++ return register_key_type(&key_type_crypto); ++} ++ ++static void __exit crypto_key_cleanup(void) ++{ ++ unregister_key_type(&key_type_crypto); ++} ++ ++module_init(crypto_key_init); ++module_exit(crypto_key_cleanup); +-- +1.7.11.2 + + +From f7b41b16f3c6d24b46100b259a83c50615be5a23 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 13:59:51 +0100 +Subject: [PATCH 03/27] 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. + +This adds four routines: + + (1) struct crypto_key_verify_context * + verify_sig_begin(struct key *keyring, const void *sig, size_t siglen); + + This sets up a verification context for the given signature using + information in that signature to select a key from the specified keyring + and to request a hash algorithm from the crypto layer. + + (2) int verify_sig_add_data(struct crypto_key_verify_context *ctx, + const void *data, size_t datalen); + + Incrementally supply data to be signed. May be called multiple times. + + (3) int verify_sig_end(struct crypto_key_verify_context *ctx, + const void *sig, size_t siglen); + + Complete the verification process and return the result. -EKEYREJECTED + will indicate that the verification failed and 0 will indicate success. + Other errors are also possible. + + (4) void verify_sig_cancel(struct crypto_key_verify_context *ctx); + + Cancel the verification process. + +Signed-off-by: David Howells +--- + Documentation/security/keys-crypto.txt | 101 +++++++++++++++++++++++++++++ + include/keys/crypto-subtype.h | 21 +++++++ + include/keys/crypto-type.h | 9 +++ + security/keys/crypto/Makefile | 2 +- + security/keys/crypto/crypto_verify.c | 112 +++++++++++++++++++++++++++++++++ + 5 files changed, 244 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 +--- a/Documentation/security/keys-crypto.txt ++++ b/Documentation/security/keys-crypto.txt +@@ -7,6 +7,7 @@ Contents: + - Overview. + - Key identification. + - Accessing crypto keys. ++ - Signature verification. + - Implementing crypto parsers. + - Implementing crypto subtypes. + +@@ -89,6 +90,65 @@ This gives access to the key type: + struct key_type key_type_crypto; + + ++SIGNATURE VERIFICATION ++---------------------- ++ ++The four operations that can perform cryptographic signature verification, ++using one of a set of keys to provide the public key: ++ ++ (1) Begin verification procedure. ++ ++ struct crypto_key_verify_context * ++ verify_sig_begin(struct key *keyring, const void *sig, size_t siglen); ++ ++ This function sets up a verification context from the information in the ++ signature and looks for a suitable key in the keyring. The signature blob ++ must be presented again at the end of the procedure. The keys will be ++ checked against parameters in the signature, and if the matching one is ++ not found then -ENOKEY will be returned. ++ ++ The hashing algorithm, if such a thing applies, will be determined from ++ information in the signature and the appropriate crypto module will be ++ used. -ENOPKG will be returned if the hash algorithm is unavailable. ++ ++ The return value is an opaque pointer to be passed to the other functions, ++ or a negative error code. ++ ++ (2) Indicate data to be verified. ++ ++ int verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++ ++ This function is used to shovel data to the verification procedure so that ++ it can load it into the hash, pass it to hardware or whatever is ++ appropriate for the algorithm being employed. ++ ++ The data is not canonicalised for the document type specified in the ++ signature. The caller must do that. ++ ++ It will return 0 if successful and a negative error code if not. ++ ++ (3) Complete the verification process. ++ ++ int verify_sig_end(struct crypto_key_verify_context *ctx, ++ const void *sig, size_t siglen); ++ ++ This function performs the actual signature verification step and cleans ++ up the resources allocated at the beginning. The signature must be ++ presented again as some of the data therein may need to be added to the ++ internal hash. ++ ++ It will return -EKEYREJECTED if the signature didn't match, 0 if ++ successful and may return other errors as appropriate. ++ ++ (4) Cancel the verification process. ++ ++ void verify_sig_cancel(struct crypto_key_verify_context *ctx); ++ ++ This function cleans up the resources allocated at the beginning. This is ++ not necessary if verify_sig_end() was called. ++ ++ + =========================== + IMPLEMENTING CRYPTO PARSERS + =========================== +@@ -96,6 +156,7 @@ IMPLEMENTING CRYPTO PARSERS + The crypto key type keeps a list of registered data parsers. An example of + such a parser is one that parses OpenPGP packet formatted data [RFC 4880]. + ++ + During key instantiation each parser in the list is tried until one doesn't + return -EBADMSG. + +@@ -107,6 +168,8 @@ The parser definition structure looks like the following: + + int (*instantiate)(struct key *key, + const void *data, size_t datalen); ++ struct crypto_key_verify_context *(*verify_sig_begin)( ++ struct key *keyring, const u8 *sig, size_t siglen); + }; + + The owner and name fields should be set to the owning module and the name of +@@ -135,6 +198,44 @@ but it is expected that at least one will be defined. + algorithm such as RSA and DSA this will likely be a printable hex version + of the key's fingerprint. + ++ (2) verify_sig_begin(). ++ ++ This is similar in concept to the instantiate() function, except that it ++ is given a signature blob to parse rather than a key data blob. ++ ++ If the data format is not recognised, -EBADMSG should be returned. If it ++ is recognised, but the signature verification process cannot for some ++ reason be set up, some other negative error code should be returned. ++ -ENOKEY should be used to indicate that no matching key is available and ++ -ENOPKG should be returned if the hash algorithm or the verification ++ algorithm are unavailable. ++ ++ If successful, the parser should allocate a verification context and embed ++ the following struct in it: ++ ++ struct crypto_key_verify_context { ++ struct key *key; ++ int (*add_data)(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++ int (*end)(struct crypto_key_verify_context *ctx, ++ const u8 *sig, size_t siglen); ++ void (*cancel)(struct crypto_key_verify_context *ctx); ++ }; ++ ++ and return a pointer to this to the caller, who will then pass it to the ++ verification operation wrappers described in the "Signature Verification" ++ section. The three operation pointers here correspond exactly to those ++ wrappers and are all mandatory. container_of() should be used to retrieve ++ the actual context. ++ ++ Note that the crypto key type retains a reference on the parser module for ++ the lifetime of this context, though the operation pointers need not point ++ into this module. ++ ++ The parser should also record a pointer to the key selected and take a ++ reference on that key with key_get(). ++ ++ + Functions are provided to register and unregister parsers: + + int register_crypto_key_parser(struct crypto_key_parser *parser); +diff --git a/include/keys/crypto-subtype.h b/include/keys/crypto-subtype.h +index fa87555..f2b927a 100644 +--- a/include/keys/crypto-subtype.h ++++ b/include/keys/crypto-subtype.h +@@ -20,6 +20,20 @@ + extern struct key_type key_type_crypto; + + /* ++ * Context base for signature verification methods. Allocated by the subtype ++ * and presumably embedded in something appropriate. ++ */ ++struct crypto_key_verify_context { ++ struct key *key; ++ struct crypto_key_parser *parser; ++ int (*add_data)(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++ int (*end)(struct crypto_key_verify_context *ctx, ++ const u8 *sig, size_t siglen); ++ void (*cancel)(struct crypto_key_verify_context *ctx); ++}; ++ ++/* + * Keys of this type declare a subtype that indicates the handlers and + * capabilities. + */ +@@ -48,6 +62,13 @@ struct crypto_key_parser { + * Return EBADMSG if not recognised. + */ + int (*instantiate)(struct key *key, const void *data, size_t datalen); ++ ++ /* Attempt to recognise a signature blob and find a matching key. ++ * ++ * Return EBADMSG if not recognised. ++ */ ++ struct crypto_key_verify_context *(*verify_sig_begin)( ++ struct key *keyring, const u8 *sig, size_t siglen); + }; + + extern int register_crypto_key_parser(struct crypto_key_parser *); +diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h +index 47c00c7..6b93366 100644 +--- a/include/keys/crypto-type.h ++++ b/include/keys/crypto-type.h +@@ -18,6 +18,15 @@ + + extern struct key_type key_type_crypto; + ++struct crypto_key_verify_context; ++extern struct crypto_key_verify_context *verify_sig_begin( ++ struct key *key, const void *sig, size_t siglen); ++extern int verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++extern int verify_sig_end(struct crypto_key_verify_context *ctx, ++ const void *sig, size_t siglen); ++extern void verify_sig_cancel(struct crypto_key_verify_context *ctx); ++ + /* + * The payload is at the discretion of the subtype. + */ +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/crypto_verify.c b/security/keys/crypto/crypto_verify.c +new file mode 100644 +index 0000000..3f2964b +--- /dev/null ++++ b/security/keys/crypto/crypto_verify.c +@@ -0,0 +1,112 @@ ++/* Signature verification with a crypto key ++ * ++ * 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. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#include ++#include ++#include ++#include "crypto_keys.h" ++ ++/** ++ * verify_sig_begin - Initiate the use of a crypto key to verify a signature ++ * @keyring: The public keys to verify against ++ * @sig: The signature data ++ * @siglen: The signature length ++ * ++ * Returns a context or an error. ++ */ ++struct crypto_key_verify_context *verify_sig_begin( ++ struct key *keyring, const void *sig, size_t siglen) ++{ ++ struct crypto_key_verify_context *ret; ++ struct crypto_key_parser *parser; ++ ++ pr_devel("==>%s()\n", __func__); ++ ++ if (siglen == 0 || !sig) ++ return ERR_PTR(-EINVAL); ++ ++ down_read(&crypto_key_parsers_sem); ++ ++ ret = ERR_PTR(-EBADMSG); ++ list_for_each_entry(parser, &crypto_key_parsers, link) { ++ if (parser->verify_sig_begin) { ++ if (!try_module_get(parser->owner)) ++ continue; ++ ++ pr_debug("Trying parser '%s'\n", parser->name); ++ ++ ret = parser->verify_sig_begin(keyring, sig, siglen); ++ if (IS_ERR(ret)) ++ module_put(parser->owner); ++ else ++ ret->parser = parser; ++ if (ret != ERR_PTR(-EBADMSG)) { ++ pr_debug("Parser recognised the format" ++ " (ret %ld)\n", ++ PTR_ERR(ret)); ++ break; ++ } ++ } ++ } ++ ++ up_read(&crypto_key_parsers_sem); ++ pr_devel("<==%s() = %p\n", __func__, ret); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(verify_sig_begin); ++ ++/** ++ * verify_sig_add_data - Incrementally provide data to be verified ++ * @ctx: The context from verify_sig_begin() ++ * @data: Data ++ * @datalen: The amount of @data ++ * ++ * This may be called multiple times. ++ */ ++int verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen) ++{ ++ return ctx->add_data(ctx, data, datalen); ++} ++EXPORT_SYMBOL_GPL(verify_sig_add_data); ++ ++/** ++ * verify_sig_end - Finalise signature verification and return result ++ * @ctx: The context from verify_sig_begin() ++ * @sig: The signature data ++ * @siglen: The signature length ++ */ ++int verify_sig_end(struct crypto_key_verify_context *ctx, ++ const void *sig, size_t siglen) ++{ ++ struct crypto_key_parser *parser = ctx->parser; ++ int ret; ++ ++ ret = ctx->end(ctx, sig, siglen); ++ module_put(parser->owner); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(verify_sig_end); ++ ++/** ++ * verify_sig_end - Cancel signature verification ++ * @ctx: The context from verify_sig_begin() ++ */ ++void verify_sig_cancel(struct crypto_key_verify_context *ctx) ++{ ++ struct crypto_key_parser *parser = ctx->parser; ++ ++ ctx->cancel(ctx); ++ module_put(parser->owner); ++} ++EXPORT_SYMBOL_GPL(verify_sig_cancel); +-- +1.7.11.2 + + +From dfa8292f4527f46cabbbd64bd89766ac1dbe6546 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 13:59:52 +0100 +Subject: [PATCH 04/27] 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 +--- + 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. ++ ++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/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 ++ ++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/crypto/public_key.c +@@ -0,0 +1,55 @@ ++/* Asymmetric public key crypto subtype ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) "PKEY: "fmt ++#include ++#include ++#include "public_key.h" ++ ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Provide a part of a description of the key for /proc/keys. ++ */ ++static void public_key_describe(const struct key *crypto_key, ++ struct seq_file *m) ++{ ++ struct public_key *key = crypto_key->payload.data; ++ ++ if (key) ++ seq_puts(m, key->algo->name); ++} ++ ++/* ++ * Destroy a public key algorithm key ++ */ ++static void public_key_destroy(void *payload) ++{ ++ struct public_key *key = payload; ++ int i; ++ ++ if (key) { ++ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) ++ mpi_free(key->mpi[i]); ++ kfree(key); ++ } ++} ++ ++/* ++ * Public key algorithm crypto key subtype ++ */ ++struct crypto_key_subtype public_key_crypto_key_subtype = { ++ .owner = THIS_MODULE, ++ .name = "public_key", ++ .describe = public_key_describe, ++ .destroy = public_key_destroy, ++}; ++EXPORT_SYMBOL_GPL(public_key_crypto_key_subtype); +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/crypto/public_key.h +@@ -0,0 +1,106 @@ ++/* Asymmetric public-key algorithm definitions ++ * ++ * 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. ++ */ ++ ++#ifndef _LINUX_PUBLIC_KEY_H ++#define _LINUX_PUBLIC_KEY_H ++ ++#include ++#include ++#include ++ ++struct public_key; ++struct public_key_signature; ++ ++enum pkey_hash_algo { ++ PKEY_HASH_MD5, ++ PKEY_HASH_SHA1, ++ PKEY_HASH_RIPE_MD_160, ++ PKEY_HASH_SHA256, ++ PKEY_HASH_SHA384, ++ PKEY_HASH_SHA512, ++ PKEY_HASH_SHA224, ++ PKEY_HASH__LAST ++}; ++ ++/* ++ * Public key type definition ++ */ ++struct public_key_algorithm { ++ const char *name; ++ u8 n_pub_mpi; /* Number of MPIs in public key */ ++ u8 n_sec_mpi; /* Number of MPIs in secret key */ ++ u8 n_sig_mpi; /* Number of MPIs in a signature */ ++ int (*verify)(const struct public_key *key, ++ const struct public_key_signature *sig); ++}; ++ ++/* ++ * Asymmetric public key data ++ */ ++struct public_key { ++ const struct public_key_algorithm *algo; ++ u8 capabilities; ++#define PKEY_CAN_ENCRYPT 0x01 ++#define PKEY_CAN_DECRYPT 0x02 ++#define PKEY_CAN_ENCDEC (PKEY_CAN_ENCRYPT | PKEY_CAN_DECRYPT) ++#define PKEY_CAN_SIGN 0x04 ++#define PKEY_CAN_VERIFY 0x08 ++#define PKEY_CAN_SIGVER (PKEY_CAN_SIGN | PKEY_CAN_VERIFY) ++ union { ++ MPI mpi[5]; ++ struct { ++ MPI p; /* DSA prime */ ++ MPI q; /* DSA group order */ ++ MPI g; /* DSA group generator */ ++ MPI y; /* DSA public-key value = g^x mod p */ ++ MPI x; /* DSA secret exponent (if present) */ ++ } dsa; ++ struct { ++ MPI n; /* RSA public modulus */ ++ MPI e; /* RSA public encryption exponent */ ++ MPI d; /* RSA secret encryption exponent (if present) */ ++ MPI p; /* RSA secret prime (if present) */ ++ MPI q; /* RSA secret prime (if present) */ ++ } rsa; ++ }; ++ ++ u8 key_id[8]; /* ID of this key pair */ ++ u8 key_id_size; /* Number of bytes in key_id */ ++}; ++ ++/* ++ * Asymmetric public key algorithm signature data ++ */ ++struct public_key_signature { ++ struct crypto_key_verify_context base; ++ u8 *digest; ++ enum pkey_hash_algo pkey_hash_algo : 8; ++ u8 signed_hash_msw[2]; ++ u8 digest_size; /* Number of bytes in digest */ ++ union { ++ MPI mpi[2]; ++ struct { ++ MPI s; /* m^d mod n */ ++ } rsa; ++ struct { ++ MPI r; ++ MPI s; ++ } dsa; ++ }; ++ struct shash_desc hash; /* This must go last! */ ++}; ++ ++extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( ++ struct key *crypto_key, const u8 *sigdata, size_t siglen); ++ ++extern struct crypto_key_subtype public_key_crypto_key_subtype; ++ ++#endif /* _LINUX_PUBLIC_KEY_H */ +-- +1.7.11.2 + + +From 0a8e7f4cc41d3cddf8a2367b1f0ed2bb1f6ccc91 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:10:37 +0100 +Subject: [PATCH 05/27] MPILIB: Reinstate mpi_cmp[_ui]() and export for RSA + signature verification + +Reinstate and export mpi_cmp() and mpi_cmp_ui() from the MPI library for use by +RSA signature verification as per RFC3447 section 5.2.2 step 1. + +Signed-off-by: David Howells +--- + lib/mpi/Makefile | 1 + + lib/mpi/mpi-cmp.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 71 insertions(+) + create mode 100644 lib/mpi/mpi-cmp.c + +diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile +index 45ca90a..019a68c 100644 +--- a/lib/mpi/Makefile ++++ b/lib/mpi/Makefile +@@ -14,6 +14,7 @@ mpi-y = \ + generic_mpih-add1.o \ + mpicoder.o \ + mpi-bit.o \ ++ mpi-cmp.o \ + mpih-cmp.o \ + mpih-div.o \ + mpih-mul.o \ +diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c +new file mode 100644 +index 0000000..1871e7b +--- /dev/null ++++ b/lib/mpi/mpi-cmp.c +@@ -0,0 +1,70 @@ ++/* mpi-cmp.c - MPI functions ++ * Copyright (C) 1998, 1999 Free Software Foundation, Inc. ++ * ++ * This file is part of GnuPG. ++ * ++ * GnuPG 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. ++ * ++ * GnuPG is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ++ */ ++ ++#include "mpi-internal.h" ++ ++int mpi_cmp_ui(MPI u, unsigned long v) ++{ ++ mpi_limb_t limb = v; ++ ++ mpi_normalize(u); ++ if (!u->nlimbs && !limb) ++ return 0; ++ if (u->sign) ++ return -1; ++ if (u->nlimbs > 1) ++ return 1; ++ ++ if (u->d[0] == limb) ++ return 0; ++ else if (u->d[0] > limb) ++ return 1; ++ else ++ return -1; ++} ++EXPORT_SYMBOL_GPL(mpi_cmp_ui); ++ ++int mpi_cmp(MPI u, MPI v) ++{ ++ mpi_size_t usize, vsize; ++ int cmp; ++ ++ mpi_normalize(u); ++ mpi_normalize(v); ++ usize = u->nlimbs; ++ vsize = v->nlimbs; ++ if (!u->sign && v->sign) ++ return 1; ++ if (u->sign && !v->sign) ++ return -1; ++ if (usize != vsize && !u->sign && !v->sign) ++ return usize - vsize; ++ if (usize != vsize && u->sign && v->sign) ++ return vsize + usize; ++ if (!usize) ++ return 0; ++ cmp = mpihelp_cmp(u->d, v->d, usize); ++ if (!cmp) ++ return 0; ++ if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0)) ++ return 1; ++ return -1; ++} ++EXPORT_SYMBOL_GPL(mpi_cmp); +-- +1.7.11.2 + + +From de86fda3085f6586bfd28517c07a2cd8cd4f9893 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:10:39 +0100 +Subject: [PATCH 06/27] KEYS: RSA: Implement signature verification algorithm + [PKCS#1 / RFC3447] + +Implement RSA public key cryptography [PKCS#1 / RFC3447]. At this time, only +the signature verification algorithm is supported. This uses the asymmetric +public key subtype to hold its key data. + +Signed-off-by: David Howells +--- + security/keys/crypto/Kconfig | 7 + + security/keys/crypto/Makefile | 1 + + security/keys/crypto/crypto_rsa.c | 264 ++++++++++++++++++++++++++++++++++++++ + security/keys/crypto/public_key.h | 2 + + 4 files changed, 274 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. ++ ++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/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 +diff --git a/security/keys/crypto/crypto_rsa.c b/security/keys/crypto/crypto_rsa.c +new file mode 100644 +index 0000000..845285c +--- /dev/null ++++ b/security/keys/crypto/crypto_rsa.c +@@ -0,0 +1,264 @@ ++/* RSA asymmetric public-key algorithm [RFC3447] ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) "RSA: "fmt ++#include ++#include ++#include "public_key.h" ++ ++MODULE_LICENSE("GPL"); ++ ++#define kenter(FMT, ...) \ ++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) ++#define kleave(FMT, ...) \ ++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) ++ ++/* ++ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. ++ */ ++static const u8 RSA_digest_info_MD5[] = { ++ 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, ++ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ ++ 0x05, 0x00, 0x04, 0x10 ++}; ++ ++static const u8 RSA_digest_info_SHA1[] = { ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x0E, 0x03, 0x02, 0x1A, ++ 0x05, 0x00, 0x04, 0x14 ++}; ++ ++static const u8 RSA_digest_info_RIPE_MD_160[] = { ++ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, ++ 0x2B, 0x24, 0x03, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x14 ++}; ++ ++static const u8 RSA_digest_info_SHA224[] = { ++ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, ++ 0x05, 0x00, 0x04, 0x1C ++}; ++ ++static const u8 RSA_digest_info_SHA256[] = { ++ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x05, 0x00, 0x04, 0x20 ++}; ++ ++static const u8 RSA_digest_info_SHA384[] = { ++ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, ++ 0x05, 0x00, 0x04, 0x30 ++}; ++ ++static const u8 RSA_digest_info_SHA512[] = { ++ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x05, 0x00, 0x04, 0x40 ++}; ++ ++static const struct { ++ const u8 *data; ++ size_t size; ++} RSA_ASN1_templates[PKEY_HASH__LAST] = { ++#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } ++ [PKEY_HASH_MD5] = _(MD5), ++ [PKEY_HASH_SHA1] = _(SHA1), ++ [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), ++ [PKEY_HASH_SHA256] = _(SHA256), ++ [PKEY_HASH_SHA384] = _(SHA384), ++ [PKEY_HASH_SHA512] = _(SHA512), ++ [PKEY_HASH_SHA224] = _(SHA224), ++#undef _ ++}; ++ ++/* ++ * RSAVP1() function [RFC3447 sec 5.2.2] ++ */ ++static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) ++{ ++ MPI m; ++ int ret; ++ ++ /* (1) Validate 0 <= s < n */ ++ if (mpi_cmp_ui(s, 0) < 0) { ++ kleave(" = -EBADMSG [s < 0]"); ++ return -EBADMSG; ++ } ++ if (mpi_cmp(s, key->rsa.n) >= 0) { ++ kleave(" = -EBADMSG [s >= n]"); ++ return -EBADMSG; ++ } ++ ++ m = mpi_alloc(0); ++ if (!m) ++ return -ENOMEM; ++ ++ /* (2) m = s^e mod n */ ++ ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); ++ if (ret < 0) { ++ mpi_free(m); ++ return ret; ++ } ++ ++ *_m = m; ++ return 0; ++} ++ ++/* ++ * Integer to Octet String conversion [RFC3447 sec 4.1] ++ */ ++static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) ++{ ++ unsigned X_size, x_size; ++ int X_sign; ++ u8 *X; ++ ++ /* Make sure the string is the right length. The number should begin ++ * with { 0x00, 0x01, ... } so we have to account for 15 leading zero ++ * bits not being reported by MPI. ++ */ ++ x_size = mpi_get_nbits(x); ++ pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); ++ if (x_size != xLen * 8 - 15) ++ return -ERANGE; ++ ++ X = mpi_get_buffer(x, &X_size, &X_sign); ++ if (!X) ++ return -ENOMEM; ++ if (X_sign < 0) { ++ kfree(X); ++ return -EBADMSG; ++ } ++ if (X_size != xLen - 1) { ++ kfree(X); ++ return -EBADMSG; ++ } ++ ++ *_X = X; ++ return 0; ++} ++ ++/* ++ * Perform the RSA signature verification. ++ * @H: Value of hash of data and metadata ++ * @EM: The computed signature value ++ * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) ++ * @hash_size: The size of H ++ * @asn1_template: The DigestInfo ASN.1 template ++ * @asn1_size: Size of asm1_template[] ++ */ ++static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, ++ const u8 *asn1_template, size_t asn1_size) ++{ ++ unsigned PS_end, T_offset, i; ++ ++ kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); ++ ++ if (k < 2 + 1 + asn1_size + hash_size) ++ return -EBADMSG; ++ ++ /* Decode the EMSA-PKCS1-v1_5 */ ++ if (EM[1] != 0x01) { ++ kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); ++ return -EBADMSG; ++ } ++ ++ T_offset = k - (asn1_size + hash_size); ++ PS_end = T_offset - 1; ++ if (EM[PS_end] != 0x00) { ++ kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); ++ return -EBADMSG; ++ } ++ ++ for (i = 2; i < PS_end; i++) { ++ if (EM[i] != 0xff) { ++ kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); ++ return -EBADMSG; ++ } ++ } ++ ++ if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { ++ kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); ++ return -EBADMSG; ++ } ++ ++ if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { ++ kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); ++ return -EKEYREJECTED; ++ } ++ ++ kleave(" = 0"); ++ return 0; ++} ++ ++/* ++ * Perform the verification step [RFC3447 sec 8.2.2]. ++ */ ++static int RSA_verify_signature(const struct public_key *key, ++ const struct public_key_signature *sig) ++{ ++ size_t tsize; ++ int ret; ++ ++ /* Variables as per RFC3447 sec 8.2.2 */ ++ const u8 *H = sig->digest; ++ u8 *EM = NULL; ++ MPI m = NULL; ++ size_t k; ++ ++ kenter(""); ++ ++ /* (1) Check the signature size against the public key modulus size */ ++ k = (mpi_get_nbits(key->rsa.n) + 7) / 8; ++ ++ tsize = (mpi_get_nbits(sig->rsa.s) + 7) / 8; ++ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); ++ if (tsize != k) { ++ ret = -EBADMSG; ++ goto error; ++ } ++ ++ /* (2b) Apply the RSAVP1 verification primitive to the public key */ ++ ret = RSAVP1(key, sig->rsa.s, &m); ++ if (ret < 0) ++ goto error; ++ ++ /* (2c) Convert the message representative (m) to an encoded message ++ * (EM) of length k octets. ++ * ++ * NOTE! The leading zero byte is suppressed by MPI, so we pass a ++ * pointer to the _preceding_ byte to RSA_verify()! ++ */ ++ ret = RSA_I2OSP(m, k, &EM); ++ if (ret < 0) ++ goto error; ++ ++ ret = RSA_verify(H, EM - 1, k, sig->digest_size, ++ RSA_ASN1_templates[sig->pkey_hash_algo].data, ++ RSA_ASN1_templates[sig->pkey_hash_algo].size); ++ ++error: ++ kfree(EM); ++ mpi_free(m); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++const struct public_key_algorithm RSA_public_key_algorithm = { ++ .name = "RSA", ++ .n_pub_mpi = 2, ++ .n_sec_mpi = 3, ++ .n_sig_mpi = 1, ++ .verify = RSA_verify_signature, ++}; ++EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); +diff --git a/security/keys/crypto/public_key.h b/security/keys/crypto/public_key.h +index 81ed603..7913615 100644 +--- 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); + }; + ++extern const struct public_key_algorithm RSA_public_key_algorithm; ++ + /* + * Asymmetric public key data + */ +-- +1.7.11.2 + + +From 2363851f3eeae9ec32ee6d5f868085eb11afa717 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:19 +0100 +Subject: [PATCH 07/27] KEYS: RSA: 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 +Signed-off-by: David Howells +--- + 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 845285c..a4a63be 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.11.2 + + +From edfd057d757164e207edfb3d3affa87cf0b126e6 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:19 +0100 +Subject: [PATCH 08/27] 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 +verification. + +Signed-off-by: David Howells +--- + include/linux/pgp.h | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 206 insertions(+) + create mode 100644 include/linux/pgp.h + +diff --git a/include/linux/pgp.h b/include/linux/pgp.h +new file mode 100644 +index 0000000..1359f64 +--- /dev/null ++++ b/include/linux/pgp.h +@@ -0,0 +1,206 @@ ++/* PGP definitions (RFC 4880) ++ * ++ * 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. ++ */ ++ ++#ifndef _LINUX_PGP_H ++#define _LINUX_PGP_H ++ ++#include ++ ++struct pgp_key_ID { ++ u8 id[8]; ++}; ++ ++struct pgp_time { ++ u8 time[4]; ++}; ++ ++/* ++ * PGP public-key algorithm identifiers [RFC4880: 9.1] ++ */ ++enum pgp_pubkey_algo { ++ PGP_PUBKEY_RSA_ENC_OR_SIG = 1, ++ PGP_PUBKEY_RSA_ENC_ONLY = 2, ++ PGP_PUBKEY_RSA_SIG_ONLY = 3, ++ PGP_PUBKEY_ELGAMAL = 16, ++ PGP_PUBKEY_DSA = 17, ++ PGP_PUBKEY__LAST ++}; ++ ++/* ++ * PGP symmetric-key algorithm identifiers [RFC4880: 9.2] ++ */ ++enum pgp_symkey_algo { ++ PGP_SYMKEY_PLAINTEXT = 0, ++ PGP_SYMKEY_IDEA = 1, ++ PGP_SYMKEY_3DES = 2, ++ PGP_SYMKEY_CAST5 = 3, ++ PGP_SYMKEY_BLOWFISH = 4, ++ PGP_SYMKEY_AES_128KEY = 7, ++ PGP_SYMKEY_AES_192KEY = 8, ++ PGP_SYMKEY_AES_256KEY = 9, ++ PGP_SYMKEY_TWOFISH_256KEY = 10, ++}; ++ ++/* ++ * PGP compression algorithm identifiers [RFC4880: 9.3] ++ */ ++enum pgp_compr_algo { ++ PGP_COMPR_UNCOMPRESSED = 0, ++ PGP_COMPR_ZIP = 1, ++ PGP_COMPR_ZLIB = 2, ++ PGP_COMPR_BZIP2 = 3, ++}; ++ ++/* ++ * PGP hash algorithm identifiers [RFC4880: 9.4] ++ */ ++enum pgp_hash_algo { ++ PGP_HASH_MD5 = 1, ++ PGP_HASH_SHA1 = 2, ++ PGP_HASH_RIPE_MD_160 = 3, ++ PGP_HASH_SHA256 = 8, ++ PGP_HASH_SHA384 = 9, ++ PGP_HASH_SHA512 = 10, ++ PGP_HASH_SHA224 = 11, ++ PGP_HASH__LAST ++}; ++ ++extern const char *const pgp_hash_algorithms[PGP_HASH__LAST]; ++ ++/* ++ * PGP packet type tags [RFC4880: 4.3]. ++ */ ++enum pgp_packet_tag { ++ PGP_PKT_RESERVED = 0, ++ PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, ++ PGP_PKT_SIGNATURE = 2, ++ PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, ++ PGP_PKT_ONEPASS_SIGNATURE = 4, ++ PGP_PKT_SECRET_KEY = 5, ++ PGP_PKT_PUBLIC_KEY = 6, ++ PGP_PKT_SECRET_SUBKEY = 7, ++ PGP_PKT_COMPRESSED_DATA = 8, ++ PGP_PKT_SYM_ENC_DATA = 9, ++ PGP_PKT_MARKER = 10, ++ PGP_PKT_LITERAL_DATA = 11, ++ PGP_PKT_TRUST = 12, ++ PGP_PKT_USER_ID = 13, ++ PGP_PKT_PUBLIC_SUBKEY = 14, ++ PGP_PKT_USER_ATTRIBUTE = 17, ++ PGP_PKT_SYM_ENC_AND_INTEG_DATA = 18, ++ PGP_PKT_MODIFY_DETECT_CODE = 19, ++ PGP_PKT_PRIVATE_0 = 60, ++ PGP_PKT_PRIVATE_3 = 63, ++ PGP_PKT__HIGHEST = 63 ++}; ++ ++/* ++ * Signature (tag 2) packet [RFC4880: 5.2]. ++ */ ++enum pgp_signature_version { ++ PGP_SIG_VERSION_3 = 3, ++ PGP_SIG_VERSION_4 = 4, ++}; ++ ++enum pgp_signature_type { ++ PGP_SIG_BINARY_DOCUMENT_SIG = 0x00, ++ PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG = 0x01, ++ PGP_SIG_STANDALONE_SIG = 0x02, ++ PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY = 0x10, ++ PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY = 0x11, ++ PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY = 0x12, ++ PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY = 0x13, ++ PGP_SIG_SUBKEY_BINDING_SIG = 0x18, ++ PGP_SIG_PRIMARY_KEY_BINDING_SIG = 0x19, ++ PGP_SIG_DIRECTLY_ON_KEY = 0x1F, ++ PGP_SIG_KEY_REVOCATION_SIG = 0x20, ++ PGP_SIG_SUBKEY_REVOCATION_SIG = 0x28, ++ PGP_SIG_CERT_REVOCATION_SIG = 0x30, ++ PGP_SIG_TIMESTAMP_SIG = 0x40, ++ PGP_SIG_THIRD_PARTY_CONFIRM_SIG = 0x50, ++}; ++ ++struct pgp_signature_v3_packet { ++ enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */ ++ u8 length_of_hashed; /* == 5 */ ++ struct { ++ enum pgp_signature_type signature_type : 8; ++ struct pgp_time creation_time; ++ } hashed; ++ struct pgp_key_ID issuer; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ enum pgp_hash_algo hash_algo : 8; ++} __packed; ++ ++struct pgp_signature_v4_packet { ++ enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_4 */ ++ enum pgp_signature_type signature_type : 8; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ enum pgp_hash_algo hash_algo : 8; ++} __packed; ++ ++/* ++ * V4 signature subpacket types [RFC4880: 5.2.3.1]. ++ */ ++enum pgp_sig_subpkt_type { ++ PGP_SIG_CREATION_TIME = 2, ++ PGP_SIG_EXPIRATION_TIME = 3, ++ PGP_SIG_EXPORTABLE_CERT = 4, ++ PGP_SIG_TRUST_SIG = 5, ++ PGP_SIG_REGEXP = 6, ++ PGP_SIG_REVOCABLE = 7, ++ PGP_SIG_KEY_EXPIRATION_TIME = 9, ++ PGP_SIG_PREF_SYM_ALGO = 11, ++ PGP_SIG_REVOCATION_KEY = 12, ++ PGP_SIG_ISSUER = 16, ++ PGP_SIG_NOTATION_DATA = 20, ++ PGP_SIG_PREF_HASH_ALGO = 21, ++ PGP_SIG_PREF_COMPR_ALGO = 22, ++ PGP_SIG_KEY_SERVER_PREFS = 23, ++ PGP_SIG_PREF_KEY_SERVER = 24, ++ PGP_SIG_PRIMARY_USER_ID = 25, ++ PGP_SIG_POLICY_URI = 26, ++ PGP_SIG_KEY_FLAGS = 27, ++ PGP_SIG_SIGNERS_USER_ID = 28, ++ PGP_SIG_REASON_FOR_REVOCATION = 29, ++ PGP_SIG_FEATURES = 30, ++ PGP_SIG_TARGET = 31, ++ PGP_SIG_EMBEDDED_SIG = 32, ++ PGP_SIG__LAST ++}; ++ ++#define PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK 0x80 ++ ++/* ++ * Key (tag 5, 6, 7 and 14) packet ++ */ ++enum pgp_key_version { ++ PGP_KEY_VERSION_2 = 2, ++ PGP_KEY_VERSION_3 = 3, ++ PGP_KEY_VERSION_4 = 4, ++}; ++ ++struct pgp_key_v3_packet { ++ enum pgp_key_version version : 8; ++ struct pgp_time creation_time; ++ u8 expiry[2]; /* 0 or time in days till expiry */ ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ u8 key_material[0]; ++} __packed; ++ ++struct pgp_key_v4_packet { ++ enum pgp_key_version version : 8; ++ struct pgp_time creation_time; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ u8 key_material[0]; ++} __packed; ++ ++#endif /* _LINUX_PGP_H */ +-- +1.7.11.2 + + +From 36f2b76a6ee5c6d86f6d7725ead9e5252b1d29a6 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:20 +0100 +Subject: [PATCH 09/27] 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: + + struct pgp_parse_context { + u64 types_of_interest; + int (*process_packet)(struct pgp_parse_context *context, + enum pgp_packet_tag type, + u8 headerlen, + const u8 *data, + size_t datalen); + }; + + int pgp_parse_packets(const u8 *data, size_t datalen, + struct pgp_parse_context *ctx); + +This is configured on with CONFIG_PGP_LIBRARY. + +Signed-off-by: David Howells +--- + include/linux/pgplib.h | 47 +++++++ + security/keys/crypto/Kconfig | 6 + + security/keys/crypto/Makefile | 1 + + security/keys/crypto/pgp_library.c | 268 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 322 insertions(+) + create mode 100644 include/linux/pgplib.h + create mode 100644 security/keys/crypto/pgp_library.c + +diff --git a/include/linux/pgplib.h b/include/linux/pgplib.h +new file mode 100644 +index 0000000..a045b3a +--- /dev/null ++++ b/include/linux/pgplib.h +@@ -0,0 +1,47 @@ ++/* PGP library definitions (RFC 4880) ++ * ++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_PGPLIB_H ++#define _LINUX_PGPLIB_H ++ ++#if defined(CONFIG_PGP_LIBRARY) || defined(CONFIG_PGP_LIBRARY_MODULE) ++ ++#include ++ ++/* ++ * PGP library packet parser ++ */ ++struct pgp_parse_context { ++ u64 types_of_interest; ++ int (*process_packet)(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen); ++}; ++ ++extern int pgp_parse_packets(const u8 *data, size_t datalen, ++ struct pgp_parse_context *ctx); ++ ++struct pgp_parse_pubkey { ++ enum pgp_key_version version : 8; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ time_t creation_time; ++ time_t expires_at; ++}; ++ ++extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, ++ struct pgp_parse_pubkey *pk); ++ ++ ++#endif /* CONFIG_PGP_LIBRARY */ ++ ++#endif /* _LINUX_PGPLIB_H */ +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). ++ ++config PGP_LIBRARY ++ tristate "PGP parsing library" ++ 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/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 +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +new file mode 100644 +index 0000000..af396d6 +--- /dev/null ++++ b/security/keys/crypto/pgp_library.c +@@ -0,0 +1,268 @@ ++/* PGP packet parser (RFC 4880) ++ * ++ * 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. ++ */ ++#define pr_fmt(fmt) "PGP: "fmt ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++ ++const char *const pgp_hash_algorithms[PGP_HASH__LAST] = { ++ [PGP_HASH_MD5] = "md5", ++ [PGP_HASH_SHA1] = "sha1", ++ [PGP_HASH_RIPE_MD_160] = "rmd160", ++ [PGP_HASH_SHA256] = "sha256", ++ [PGP_HASH_SHA384] = "sha384", ++ [PGP_HASH_SHA512] = "sha512", ++ [PGP_HASH_SHA224] = "sha224", ++}; ++EXPORT_SYMBOL_GPL(pgp_hash_algorithms); ++ ++/** ++ * pgp_parse_packet_header - Parse a PGP packet header ++ * @_data: Start of the PGP packet (updated to PGP packet data) ++ * @_datalen: Amount of data remaining in buffer (decreased) ++ * @_type: Where the packet type will be returned ++ * @_headerlen: Where the header length will be returned ++ * ++ * Parse a set of PGP packet header [RFC 4880: 4.2]. ++ * ++ * Returns packet data size on success; non-zero on error. If successful, ++ * *_data and *_datalen will have been updated and *_headerlen will be set to ++ * hold the length of the packet header. ++ */ ++static ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, ++ enum pgp_packet_tag *_type, ++ u8 *_headerlen) ++{ ++ enum pgp_packet_tag type; ++ const u8 *data = *_data; ++ size_t size, datalen = *_datalen; ++ ++ pr_devel("-->pgp_parse_packet_header(,%zu,,)", datalen); ++ ++ if (datalen < 2) ++ goto short_packet; ++ ++ pr_devel("pkthdr %02x, %02x\n", data[0], data[1]); ++ ++ type = *data++; ++ datalen--; ++ if (!(type & 0x80)) { ++ pr_debug("Packet type does not have MSB set\n"); ++ return -EBADMSG; ++ } ++ type &= ~0x80; ++ ++ if (type & 0x40) { ++ /* New packet length format */ ++ type &= ~0x40; ++ pr_devel("new format: t=%u\n", type); ++ switch (data[0]) { ++ case 0x00 ... 0xbf: ++ /* One-byte length */ ++ size = data[0]; ++ data++; ++ datalen--; ++ *_headerlen = 2; ++ break; ++ case 0xc0 ... 0xdf: ++ /* Two-byte length */ ++ if (datalen < 2) ++ goto short_packet; ++ size = (data[0] - 192) * 256; ++ size += data[1] + 192; ++ data += 2; ++ datalen -= 2; ++ *_headerlen = 3; ++ break; ++ case 0xff: ++ /* 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("Partial body length packet not supported\n"); ++ return -EBADMSG; ++ } ++ } else { ++ /* Old packet length format */ ++ u8 length_type = type & 0x03; ++ type >>= 2; ++ pr_devel("old format: t=%u lt=%u\n", type, length_type); ++ ++ switch (length_type) { ++ case 0: ++ /* One-byte length */ ++ size = data[0]; ++ data++; ++ datalen--; ++ *_headerlen = 2; ++ break; ++ case 1: ++ /* Two-byte length */ ++ if (datalen < 2) ++ goto short_packet; ++ size = data[0] << 8; ++ size |= data[1]; ++ data += 2; ++ datalen -= 2; ++ *_headerlen = 3; ++ break; ++ case 2: ++ /* Four-byte length */ ++ if (datalen < 4) ++ goto short_packet; ++ size = data[0] << 24; ++ size |= data[1] << 16; ++ size |= data[2] << 8; ++ size |= data[3]; ++ data += 4; ++ datalen -= 4; ++ *_headerlen = 5; ++ break; ++ default: ++ pr_debug("Indefinite length packet not supported\n"); ++ return -EBADMSG; ++ } ++ } ++ ++ 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; ++ *_type = type; ++ pr_devel("Found packet type=%u size=%zd\n", type, size); ++ return size; ++ ++short_packet: ++ pr_debug("Attempt to parse short packet\n"); ++ return -EBADMSG; ++too_big: ++ pr_debug("Signature subpacket size >2G\n"); ++ return -EMSGSIZE; ++} ++ ++/** ++ * pgp_parse_packets - Parse a set of PGP packets ++ * @_data: Data to be parsed (updated) ++ * @_datalen: Amount of data (updated) ++ * @ctx: Parsing context ++ * ++ * Parse a set of PGP packets [RFC 4880: 4]. ++ */ ++int pgp_parse_packets(const u8 *data, size_t datalen, ++ struct pgp_parse_context *ctx) ++{ ++ enum pgp_packet_tag type; ++ ssize_t pktlen; ++ u8 headerlen; ++ int ret; ++ ++ while (datalen > 2) { ++ pktlen = pgp_parse_packet_header(&data, &datalen, &type, ++ &headerlen); ++ if (pktlen < 0) ++ return pktlen; ++ ++ if ((ctx->types_of_interest >> type) & 1) { ++ ret = ctx->process_packet(ctx, type, headerlen, ++ data, pktlen); ++ if (ret < 0) ++ return ret; ++ } ++ data += pktlen; ++ datalen -= pktlen; ++ } ++ ++ if (datalen != 0) { ++ pr_debug("Excess octets in packet stream\n"); ++ return -EBADMSG; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_packets); ++ ++/** ++ * pgp_parse_public_key - Parse the common part of a PGP pubkey packet ++ * @_data: Content of packet (updated) ++ * @_datalen: Length of packet remaining (updated) ++ * @pk: Public key data ++ * ++ * Parse the common data struct for a PGP pubkey packet [RFC 4880: 5.5.2]. ++ */ ++int pgp_parse_public_key(const u8 **_data, size_t *_datalen, ++ struct pgp_parse_pubkey *pk) ++{ ++ const u8 *data = *_data; ++ size_t datalen = *_datalen; ++ __be32 tmp; ++ ++ if (datalen < 12) { ++ pr_debug("Public key packet too short\n"); ++ return -EBADMSG; ++ } ++ ++ pk->version = *data++; ++ switch (pk->version) { ++ case PGP_KEY_VERSION_2: ++ case PGP_KEY_VERSION_3: ++ case PGP_KEY_VERSION_4: ++ break; ++ default: ++ pr_debug("Public key packet with unhandled version %d\n", ++ pk->version); ++ return -EBADMSG; ++ } ++ ++ tmp = *data++ << 24; ++ tmp |= *data++ << 16; ++ tmp |= *data++ << 8; ++ tmp |= *data++; ++ pk->creation_time = tmp; ++ if (pk->version == PGP_KEY_VERSION_4) { ++ pk->expires_at = 0; /* Have to get it from the selfsignature */ ++ } else { ++ unsigned short ndays; ++ ndays = *data++ << 8; ++ ndays |= *data++; ++ if (ndays) ++ pk->expires_at = pk->creation_time + ndays * 86400UL; ++ else ++ pk->expires_at = 0; ++ datalen -= 2; ++ } ++ ++ pk->pubkey_algo = *data++; ++ datalen -= 6; ++ ++ pr_devel("%x,%x,%lx,%lx", ++ pk->version, pk->pubkey_algo, pk->creation_time, ++ pk->expires_at); ++ ++ *_data = data; ++ *_datalen = datalen; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_public_key); +-- +1.7.11.2 + + +From 6f830b85b1e32e44291c2bdff6b936025c48b40d Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:20 +0100 +Subject: [PATCH 10/27] PGPLIB: Signature parser + +Provide some PGP signature parsing helpers: + + (1) A function to parse V4 signature subpackets and pass the desired ones to + a processor function: + + int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, + struct pgp_parse_sig_context *ctx); + + (2) A function to parse out basic signature parameters from any PGP signature + such that the algorithms and public key can be selected: + + int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, + struct pgp_sig_parameters *p); + +Signed-off-by: David Howells +--- + include/linux/pgplib.h | 25 ++++ + security/keys/crypto/pgp_library.c | 280 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 305 insertions(+) + +diff --git a/include/linux/pgplib.h b/include/linux/pgplib.h +index a045b3a..34594a9 100644 +--- a/include/linux/pgplib.h ++++ b/include/linux/pgplib.h +@@ -41,6 +41,31 @@ struct pgp_parse_pubkey { + extern int pgp_parse_public_key(const u8 **_data, size_t *_datalen, + struct pgp_parse_pubkey *pk); + ++struct pgp_parse_sig_context { ++ unsigned long types_of_interest[128 / BITS_PER_LONG]; ++ int (*process_packet)(struct pgp_parse_sig_context *context, ++ enum pgp_sig_subpkt_type type, ++ const u8 *data, ++ size_t datalen); ++}; ++ ++extern int pgp_parse_sig_packets(const u8 *data, size_t datalen, ++ struct pgp_parse_sig_context *ctx); ++ ++struct pgp_sig_parameters { ++ enum pgp_signature_version version : 8; ++ enum pgp_signature_type signature_type : 8; ++ enum pgp_pubkey_algo pubkey_algo : 8; ++ enum pgp_hash_algo hash_algo : 8; ++ union { ++ struct pgp_key_ID issuer; ++ __be32 issuer32[2]; ++ }; ++}; ++ ++extern int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, ++ struct pgp_sig_parameters *p); ++ + + #endif /* CONFIG_PGP_LIBRARY */ + +diff --git a/security/keys/crypto/pgp_library.c b/security/keys/crypto/pgp_library.c +index af396d6..c9218df 100644 +--- a/security/keys/crypto/pgp_library.c ++++ b/security/keys/crypto/pgp_library.c +@@ -266,3 +266,283 @@ int pgp_parse_public_key(const u8 **_data, size_t *_datalen, + return 0; + } + EXPORT_SYMBOL_GPL(pgp_parse_public_key); ++ ++/** ++ * pgp_parse_sig_subpkt_header - Parse a PGP V4 signature subpacket header ++ * @_data: Start of the subpacket (updated to subpacket data) ++ * @_datalen: Amount of data remaining in buffer (decreased) ++ * @_type: Where the subpacket type will be returned ++ * ++ * Parse a PGP V4 signature subpacket header [RFC 4880: 5.2.3.1]. ++ * ++ * Returns packet data size on success; non-zero on error. If successful, ++ * *_data and *_datalen will have been updated and *_headerlen will be set to ++ * hold the length of the packet header. ++ */ ++static ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, ++ enum pgp_sig_subpkt_type *_type) ++{ ++ enum pgp_sig_subpkt_type type; ++ const u8 *data = *_data; ++ size_t size, datalen = *_datalen; ++ ++ pr_devel("-->pgp_parse_sig_subpkt_header(,%zu,,)", datalen); ++ ++ if (datalen < 2) ++ goto short_subpacket; ++ ++ pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]); ++ ++ switch (data[0]) { ++ case 0x00 ... 0xbf: ++ /* One-byte length */ ++ size = data[0]; ++ data++; ++ datalen--; ++ break; ++ case 0xc0 ... 0xfe: ++ /* Two-byte length */ ++ if (datalen < 3) ++ goto short_subpacket; ++ size = (data[0] - 192) * 256; ++ size += data[1] + 192; ++ data += 2; ++ datalen -= 2; ++ break; ++ case 0xff: ++ if (datalen < 6) ++ goto short_subpacket; ++ size = data[1] << 24; ++ size |= data[2] << 16; ++ size |= data[3] << 8; ++ size |= data[4]; ++ data += 5; ++ datalen -= 5; ++ break; ++ } ++ ++ /* The type octet is included in the size */ ++ 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; ++ ++ type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; ++ datalen--; ++ size--; ++ ++ *_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; ++too_big: ++ pr_debug("Signature subpacket size >2G\n"); ++ return -EMSGSIZE; ++} ++ ++/** ++ * pgp_parse_sig_subpkts - Parse a set of PGP V4 signatute subpackets ++ * @_data: Data to be parsed (updated) ++ * @_datalen: Amount of data (updated) ++ * @ctx: Parsing context ++ * ++ * Parse a set of PGP signature subpackets [RFC 4880: 5.2.3]. ++ */ ++static int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, ++ struct pgp_parse_sig_context *ctx) ++{ ++ enum pgp_sig_subpkt_type type; ++ ssize_t pktlen; ++ int ret; ++ ++ pr_devel("-->pgp_parse_sig_subpkts(,%zu,,)", datalen); ++ ++ while (datalen > 2) { ++ pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type); ++ if (pktlen < 0) ++ return pktlen; ++ if (test_bit(type, ctx->types_of_interest)) { ++ ret = ctx->process_packet(ctx, type, data, pktlen); ++ if (ret < 0) ++ return ret; ++ } ++ data += pktlen; ++ datalen -= pktlen; ++ } ++ ++ if (datalen != 0) { ++ pr_debug("Excess octets in signature subpacket stream\n"); ++ return -EBADMSG; ++ } ++ ++ return 0; ++} ++ ++struct pgp_parse_sig_params_ctx { ++ struct pgp_parse_sig_context base; ++ struct pgp_sig_parameters *params; ++ bool got_the_issuer; ++}; ++ ++/* ++ * Process a V4 signature subpacket. ++ */ ++static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context, ++ enum pgp_sig_subpkt_type type, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct pgp_parse_sig_params_ctx *ctx = ++ container_of(context, struct pgp_parse_sig_params_ctx, base); ++ ++ if (ctx->got_the_issuer) { ++ pr_debug("V4 signature packet has multiple issuers\n"); ++ return -EBADMSG; ++ } ++ ++ if (datalen != 8) { ++ pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n", ++ datalen); ++ return -EBADMSG; ++ } ++ ++ memcpy(&ctx->params->issuer, data, 8); ++ ctx->got_the_issuer = true; ++ return 0; ++} ++ ++/** ++ * pgp_parse_sig_params - Parse basic parameters from a PGP signature packet ++ * @_data: Content of packet (updated) ++ * @_datalen: Length of packet remaining (updated) ++ * @p: The basic parameters ++ * ++ * Parse the basic parameters from a PGP signature packet [RFC 4880: 5.2] that ++ * are needed to start off a signature verification operation. The only ones ++ * actually necessary are the signature type (which affects how the data is ++ * transformed) and the hash algorithm. ++ * ++ * We also extract the public key algorithm and the issuer's key ID as we'll ++ * need those to determine if we actually have the public key available. If ++ * not, then we can't verify the signature anyway. ++ * ++ * Returns 0 if successful or a negative error code. *_data and *_datalen are ++ * updated to point to the 16-bit subset of the hash value and the set of MPIs. ++ */ ++int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, ++ struct pgp_sig_parameters *p) ++{ ++ const u8 *data = *_data; ++ size_t datalen = *_datalen; ++ int ret; ++ ++ pr_devel("-->pgp_parse_sig_params(,%zu,,)", datalen); ++ ++ if (datalen < 1) ++ return -EBADMSG; ++ p->version = *data; ++ ++ if (p->version == PGP_SIG_VERSION_3) { ++ const struct pgp_signature_v3_packet *v3 = (const void *)data; ++ ++ if (datalen < sizeof(*v3)) { ++ pr_debug("Short V3 signature packet\n"); ++ return -EBADMSG; ++ } ++ datalen -= sizeof(*v3); ++ data += sizeof(*v3); ++ ++ /* V3 has everything we need in the header */ ++ p->signature_type = v3->hashed.signature_type; ++ p->issuer = v3->issuer; ++ p->pubkey_algo = v3->pubkey_algo; ++ p->hash_algo = v3->hash_algo; ++ ++ } else if (p->version == PGP_SIG_VERSION_4) { ++ const struct pgp_signature_v4_packet *v4 = (const void *)data; ++ struct pgp_parse_sig_params_ctx ctx = { ++ .base.process_packet = pgp_process_sig_params_subpkt, ++ .params = p, ++ .got_the_issuer = false, ++ }; ++ size_t subdatalen; ++ ++ if (datalen < sizeof(*v4) + 2 + 2 + 2) { ++ pr_debug("Short V4 signature packet\n"); ++ return -EBADMSG; ++ } ++ datalen -= sizeof(*v4); ++ data += sizeof(*v4); ++ ++ /* V4 has most things in the header... */ ++ p->signature_type = v4->signature_type; ++ p->pubkey_algo = v4->pubkey_algo; ++ p->hash_algo = v4->hash_algo; ++ ++ /* ... but we have to get the key ID from the subpackets, of ++ * which there are two sets. */ ++ __set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest); ++ ++ subdatalen = *data++ << 8; ++ subdatalen |= *data++; ++ datalen -= 2; ++ if (subdatalen) { ++ /* Hashed subpackets */ ++ pr_devel("hashed data: %zu (after %zu)\n", ++ subdatalen, sizeof(*v4)); ++ if (subdatalen > datalen + 2 + 2) { ++ pr_debug("Short V4 signature packet [hdata]\n"); ++ return -EBADMSG; ++ } ++ ret = pgp_parse_sig_subpkts(data, subdatalen, ++ &ctx.base); ++ if (ret < 0) ++ return ret; ++ data += subdatalen; ++ datalen -= subdatalen; ++ } ++ ++ subdatalen = *data++ << 8; ++ subdatalen |= *data++; ++ datalen -= 2; ++ if (subdatalen) { ++ /* Unhashed subpackets */ ++ pr_devel("unhashed data: %zu\n", subdatalen); ++ if (subdatalen > datalen + 2) { ++ pr_debug("Short V4 signature packet [udata]\n"); ++ return -EBADMSG; ++ } ++ ret = pgp_parse_sig_subpkts(data, subdatalen, ++ &ctx.base); ++ if (ret < 0) ++ return ret; ++ data += subdatalen; ++ datalen -= subdatalen; ++ } ++ ++ if (!ctx.got_the_issuer) { ++ pr_debug("V4 signature packet lacks issuer\n"); ++ return -EBADMSG; ++ } ++ } else { ++ pr_debug("Signature packet with unhandled version %d\n", ++ p->version); ++ return -EBADMSG; ++ } ++ ++ *_data = data; ++ *_datalen = datalen; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(pgp_parse_sig_params); +-- +1.7.11.2 + + +From c0e901a1ce72ddf259de219506327271cf3bb700 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:21 +0100 +Subject: [PATCH 11/27] KEYS: PGP data parser + +Implement a PGP data parser for the crypto key type to use when instantiating a +key. + +This parser attempts to parse the instantiation data as a PGP packet sequence +(RFC 4880) and if it parses okay, attempts to extract a public-key algorithm +key or subkey from it. + +If it finds such a key, it will set up a public_key subtype payload with +appropriate handler routines (DSA or RSA) and attach it to the key. + +Thanks to Tetsuo Handa for pointing out +some errors. + +Signed-off-by: David Howells +--- + security/keys/crypto/Kconfig | 12 ++ + security/keys/crypto/Makefile | 4 + + security/keys/crypto/pgp_parser.h | 23 +++ + security/keys/crypto/pgp_public_key.c | 348 ++++++++++++++++++++++++++++++++++ + 4 files changed, 387 insertions(+) + create mode 100644 security/keys/crypto/pgp_parser.h + create mode 100644 security/keys/crypto/pgp_public_key.c + +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. ++ ++config CRYPTO_KEY_PGP_PARSER ++ tristate "PGP key blob parser" ++ depends on CRYPTO_KEY_TYPE ++ select CRYPTO_KEY_PUBLIC_KEY_SUBTYPE ++ select PGP_LIBRARY ++ select MD5 # V3 fingerprint generation ++ select SHA1 # V4 fingerprint generation ++ help ++ 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/crypto/Makefile b/security/keys/crypto/Makefile +index 5fbe54e..35733fc 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_key_parser.o ++pgp_key_parser-y := \ ++ pgp_public_key.o +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/crypto/pgp_parser.h +@@ -0,0 +1,23 @@ ++/* PGP crypto data parser internal definitions ++ * ++ * 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 ++ ++#define kenter(FMT, ...) \ ++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) ++#define kleave(FMT, ...) \ ++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) ++ ++/* ++ * pgp_key_parser.c ++ */ ++extern const ++struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; +diff --git a/security/keys/crypto/pgp_public_key.c b/security/keys/crypto/pgp_public_key.c +new file mode 100644 +index 0000000..8a8b7c0 +--- /dev/null ++++ b/security/keys/crypto/pgp_public_key.c +@@ -0,0 +1,348 @@ ++/* Instantiate a public key crypto key from PGP format data [RFC 4880] ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) "PGP: "fmt ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "public_key.h" ++#include "pgp_parser.h" ++ ++MODULE_LICENSE("GPL"); ++ ++const ++struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST] = { ++#if defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA) || \ ++ defined(CONFIG_CRYPTO_KEY_PKEY_ALGO_RSA_MODULE) ++ [PGP_PUBKEY_RSA_ENC_OR_SIG] = &RSA_public_key_algorithm, ++ [PGP_PUBKEY_RSA_ENC_ONLY] = &RSA_public_key_algorithm, ++ [PGP_PUBKEY_RSA_SIG_ONLY] = &RSA_public_key_algorithm, ++#endif ++ [PGP_PUBKEY_ELGAMAL] = NULL, ++ [PGP_PUBKEY_DSA] = NULL, ++}; ++ ++static const u8 pgp_public_key_capabilities[PGP_PUBKEY__LAST] = { ++ [PGP_PUBKEY_RSA_ENC_OR_SIG] = PKEY_CAN_ENCDEC | PKEY_CAN_SIGVER, ++ [PGP_PUBKEY_RSA_ENC_ONLY] = PKEY_CAN_ENCDEC, ++ [PGP_PUBKEY_RSA_SIG_ONLY] = PKEY_CAN_SIGVER, ++ [PGP_PUBKEY_ELGAMAL] = 0, ++ [PGP_PUBKEY_DSA] = 0, ++}; ++ ++static inline void digest_putc(struct shash_desc *digest, uint8_t ch) ++{ ++ crypto_shash_update(digest, &ch, 1); ++} ++ ++struct pgp_key_data_parse_context { ++ struct pgp_parse_context pgp; ++ struct crypto_key_subtype *subtype; ++ char *fingerprint; ++ void *payload; ++}; ++ ++/* ++ * Calculate the public key ID (RFC4880 12.2) ++ */ ++static int pgp_calc_pkey_keyid(struct shash_desc *digest, ++ struct pgp_parse_pubkey *pgp, ++ struct public_key *key) ++{ ++ unsigned nb[ARRAY_SIZE(key->mpi)]; ++ unsigned nn[ARRAY_SIZE(key->mpi)]; ++ unsigned n; ++ u8 *pp[ARRAY_SIZE(key->mpi)]; ++ u32 a32; ++ int npkey = key->algo->n_pub_mpi; ++ int i, ret = -ENOMEM; ++ ++ 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]); ++ pp[i] = mpi_get_buffer(key->mpi[i], nn + i, NULL); ++ if (!pp[i]) ++ goto error; ++ n += 2 + nn[i]; ++ } ++ ++ digest_putc(digest, 0x99); /* ctb */ ++ digest_putc(digest, n >> 8); /* 16-bit header length */ ++ digest_putc(digest, n); ++ digest_putc(digest, pgp->version); ++ ++ a32 = pgp->creation_time; ++ digest_putc(digest, a32 >> 24); ++ digest_putc(digest, a32 >> 16); ++ digest_putc(digest, a32 >> 8); ++ digest_putc(digest, a32 >> 0); ++ ++ if (pgp->version < PGP_KEY_VERSION_4) { ++ u16 a16; ++ ++ if (pgp->expires_at) ++ a16 = (pgp->expires_at - pgp->creation_time) / 86400UL; ++ else ++ a16 = 0; ++ digest_putc(digest, a16 >> 8); ++ digest_putc(digest, a16 >> 0); ++ } ++ ++ digest_putc(digest, pgp->pubkey_algo); ++ ++ for (i = 0; i < npkey; i++) { ++ digest_putc(digest, nb[i] >> 8); ++ digest_putc(digest, nb[i]); ++ crypto_shash_update(digest, pp[i], nn[i]); ++ } ++ ret = 0; ++ ++error: ++ for (i = 0; i < npkey; i++) ++ kfree(pp[i]); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Calculate the public key ID fingerprint ++ */ ++static int pgp_generate_fingerprint(struct pgp_key_data_parse_context *ctx, ++ struct pgp_parse_pubkey *pgp, ++ struct public_key *key) ++{ ++ struct crypto_shash *tfm; ++ struct shash_desc *digest; ++ char *fingerprint; ++ u8 *raw_fingerprint; ++ int digest_size, offset; ++ int ret, i; ++ ++ ret = -ENOMEM; ++ tfm = crypto_alloc_shash(pgp->version < PGP_KEY_VERSION_4 ? ++ "md5" : "sha1", 0, 0); ++ if (!tfm) ++ goto cleanup; ++ ++ digest = kmalloc(sizeof(*digest) + crypto_shash_descsize(tfm), ++ GFP_KERNEL); ++ if (!digest) ++ goto cleanup_tfm; ++ ++ digest->tfm = tfm; ++ digest->flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ ret = crypto_shash_init(digest); ++ if (ret < 0) ++ goto cleanup_hash; ++ ++ ret = pgp_calc_pkey_keyid(digest, pgp, key); ++ if (ret < 0) ++ goto cleanup_hash; ++ ++ digest_size = crypto_shash_digestsize(tfm); ++ ++ raw_fingerprint = kmalloc(digest_size, GFP_KERNEL); ++ if (!raw_fingerprint) ++ goto cleanup_hash; ++ ++ ret = crypto_shash_final(digest, raw_fingerprint); ++ if (ret < 0) ++ goto cleanup_raw_fingerprint; ++ ++ fingerprint = kmalloc(digest_size * 2 + 1, GFP_KERNEL); ++ if (!fingerprint) ++ goto cleanup_raw_fingerprint; ++ ++ offset = digest_size - 8; ++ pr_debug("offset %u/%u\n", offset, digest_size); ++ ++ for (i = 0; i < digest_size; i++) ++ sprintf(fingerprint + i * 2, "%02x", raw_fingerprint[i]); ++ pr_debug("fingerprint %s\n", fingerprint); ++ ++ memcpy(&key->key_id, raw_fingerprint + offset, 8); ++ key->key_id_size = 8; ++ ++ ctx->fingerprint = fingerprint; ++ ret = 0; ++cleanup_raw_fingerprint: ++ kfree(raw_fingerprint); ++cleanup_hash: ++ kfree(digest); ++cleanup_tfm: ++ crypto_free_shash(tfm); ++cleanup: ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Extract a public key or public subkey from the PGP stream. ++ */ ++static int pgp_process_public_key(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ const struct public_key_algorithm *algo; ++ struct pgp_key_data_parse_context *ctx = ++ container_of(context, struct pgp_key_data_parse_context, pgp); ++ struct pgp_parse_pubkey pgp; ++ struct public_key *key; ++ int i, ret; ++ ++ kenter(",%u,%u,,%zu", type, headerlen, datalen); ++ ++ if (ctx->subtype) { ++ kleave(" = -ENOKEY [already]"); ++ return -EBADMSG; ++ } ++ ++ key = kzalloc(sizeof(struct public_key), GFP_KERNEL); ++ if (!key) ++ return -ENOMEM; ++ ++ ret = pgp_parse_public_key(&data, &datalen, &pgp); ++ if (ret < 0) ++ goto cleanup; ++ ++ if (pgp.pubkey_algo >= PGP_PUBKEY__LAST || ++ !pgp_public_key_algorithms[pgp.pubkey_algo]) { ++ pr_debug("Unsupported public key algorithm %u\n", ++ pgp.pubkey_algo); ++ ret = -ENOPKG; ++ goto cleanup; ++ } ++ ++ algo = key->algo = pgp_public_key_algorithms[pgp.pubkey_algo]; ++ ++ /* It's a public key, so that only gives us encrypt and verify ++ * capabilities. ++ */ ++ key->capabilities = pgp_public_key_capabilities[pgp.pubkey_algo] & ++ (PKEY_CAN_ENCRYPT | PKEY_CAN_VERIFY); ++ ++ for (i = 0; i < algo->n_pub_mpi; i++) { ++ unsigned int remaining = datalen; ++ if (remaining == 0) { ++ pr_debug("short %zu mpi %d\n", datalen, i); ++ goto cleanup_badmsg; ++ } ++ key->mpi[i] = mpi_read_from_buffer(data, &remaining); ++ if (!key->mpi[i]) ++ goto cleanup_nomem; ++ data += remaining; ++ datalen -= remaining; ++ } ++ ++ if (datalen != 0) { ++ pr_debug("excess %zu\n", datalen); ++ goto cleanup_badmsg; ++ } ++ ++ ret = pgp_generate_fingerprint(ctx, &pgp, key); ++ if (ret < 0) ++ goto cleanup; ++ ++ /* We're pinning the module by being linked against it */ ++ __module_get(public_key_crypto_key_subtype.owner); ++ ctx->subtype = &public_key_crypto_key_subtype; ++ ctx->payload = key; ++ kleave(" = 0 [use]"); ++ return 0; ++ ++cleanup_nomem: ++ ret = -ENOMEM; ++ goto cleanup; ++cleanup_badmsg: ++ ret = -EBADMSG; ++cleanup: ++ pr_devel("cleanup"); ++ if (key) { ++ for (i = 0; i < ARRAY_SIZE(key->mpi); i++) ++ mpi_free(key->mpi[i]); ++ kfree(key); ++ } ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Attempt to parse the instantiation data blob for a key as a PGP packet ++ * message holding a key. ++ */ ++static int pgp_key_instantiate(struct key *key, ++ const void *data, size_t datalen) ++{ ++ struct pgp_key_data_parse_context ctx; ++ int ret; ++ ++ kenter(""); ++ ++ ret = key_payload_reserve(key, datalen); ++ if (ret < 0) ++ return ret; ++ ++ ctx.pgp.types_of_interest = ++ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY); ++ ctx.pgp.process_packet = pgp_process_public_key; ++ ctx.subtype = NULL; ++ ctx.fingerprint = NULL; ++ ctx.payload = NULL; ++ ++ ret = pgp_parse_packets(data, datalen, &ctx.pgp); ++ if (ret < 0) { ++ if (ctx.payload) ++ ctx.subtype->destroy(ctx.payload); ++ if (ctx.subtype) ++ module_put(ctx.subtype->owner); ++ kfree(ctx.fingerprint); ++ key_payload_reserve(key, 0); ++ return ret; ++ } ++ ++ key->type_data.p[0] = ctx.subtype; ++ key->type_data.p[1] = ctx.fingerprint; ++ key->payload.data = ctx.payload; ++ return 0; ++} ++ ++static struct crypto_key_parser pgp_key_parser = { ++ .owner = THIS_MODULE, ++ .name = "pgp", ++ .instantiate = pgp_key_instantiate, ++}; ++ ++/* ++ * Module stuff ++ */ ++static int __init pgp_key_init(void) ++{ ++ return register_crypto_key_parser(&pgp_key_parser); ++} ++ ++static void __exit pgp_key_exit(void) ++{ ++ unregister_crypto_key_parser(&pgp_key_parser); ++} ++ ++module_init(pgp_key_init); ++module_exit(pgp_key_exit); +-- +1.7.11.2 + + +From b830627f3b864530540ad88df21d2ceefcba7459 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:21 +0100 +Subject: [PATCH 12/27] 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 +public-key algorithm agnostic. The public-key verification algorithm itself +is just the last little bit and is supplied the complete hash data to process. + +This requires glue logic putting on top to make use of it - something the next +patch provides. + +Signed-off-by: David Howells +--- + security/keys/crypto/Makefile | 3 +- + security/keys/crypto/pgp_parser.h | 6 + + security/keys/crypto/pgp_sig_verify.c | 325 ++++++++++++++++++++++++++++++++++ + 3 files changed, 333 insertions(+), 1 deletion(-) + create mode 100644 security/keys/crypto/pgp_sig_verify.c + +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 35733fc..0c8b8a1 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_key_parser.o + pgp_key_parser-y := \ +- pgp_public_key.o ++ pgp_public_key.o \ ++ pgp_sig_verify.o +diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h +index 1cda231..a6192ce 100644 +--- a/security/keys/crypto/pgp_parser.h ++++ b/security/keys/crypto/pgp_parser.h +@@ -21,3 +21,9 @@ + */ + extern const + struct public_key_algorithm *pgp_public_key_algorithms[PGP_PUBKEY__LAST]; ++ ++/* ++ * pgp_pubkey_sig.c ++ */ ++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/crypto/pgp_sig_verify.c b/security/keys/crypto/pgp_sig_verify.c +new file mode 100644 +index 0000000..82c89da +--- /dev/null ++++ b/security/keys/crypto/pgp_sig_verify.c +@@ -0,0 +1,325 @@ ++/* PGP public key signature verification [RFC 4880] ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) "PGPSIG: "fmt ++#include ++#include ++#include ++#include ++#include ++#include "public_key.h" ++#include "pgp_parser.h" ++ ++static const struct { ++ enum pkey_hash_algo algo : 8; ++} pgp_pubkey_hash[PGP_HASH__LAST] = { ++ [PGP_HASH_MD5].algo = PKEY_HASH_MD5, ++ [PGP_HASH_SHA1].algo = PKEY_HASH_SHA1, ++ [PGP_HASH_RIPE_MD_160].algo = PKEY_HASH_RIPE_MD_160, ++ [PGP_HASH_SHA256].algo = PKEY_HASH_SHA256, ++ [PGP_HASH_SHA384].algo = PKEY_HASH_SHA384, ++ [PGP_HASH_SHA512].algo = PKEY_HASH_SHA512, ++ [PGP_HASH_SHA224].algo = PKEY_HASH_SHA224, ++}; ++ ++static int pgp_pkey_verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen); ++static int pgp_pkey_verify_sig_end(struct crypto_key_verify_context *ctx, ++ const u8 *sig, size_t siglen); ++static void pgp_pkey_verify_sig_cancel(struct crypto_key_verify_context *ctx); ++ ++struct pgp_pkey_sig_parse_context { ++ struct pgp_parse_context pgp; ++ struct pgp_sig_parameters params; ++}; ++ ++static int pgp_pkey_parse_signature(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct pgp_pkey_sig_parse_context *ctx = ++ container_of(context, struct pgp_pkey_sig_parse_context, pgp); ++ ++ return pgp_parse_sig_params(&data, &datalen, &ctx->params); ++} ++ ++/* ++ * Begin the process of verifying a DSA signature. ++ * ++ * This involves allocating the hash into which first the data and then the ++ * metadata will be put, and parsing the signature to check that it matches the ++ * key. ++ */ ++struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( ++ struct key *crypto_key, const u8 *sigdata, size_t siglen) ++{ ++ struct pgp_pkey_sig_parse_context p; ++ struct public_key_signature *sig; ++ struct crypto_shash *tfm; ++ const struct public_key *key = crypto_key->payload.data; ++ size_t digest_size, desc_size; ++ int ret; ++ ++ kenter("{%d},,%zu", key_serial(crypto_key), siglen); ++ ++ if (!key) { ++ kleave(" = -ENOKEY [no public key]"); ++ return ERR_PTR(-ENOKEY); ++ } ++ ++ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); ++ p.pgp.process_packet = pgp_pkey_parse_signature; ++ ret = pgp_parse_packets(sigdata, siglen, &p.pgp); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ if (p.params.pubkey_algo >= PGP_PUBKEY__LAST || ++ !pgp_public_key_algorithms[p.params.pubkey_algo]) { ++ pr_debug("Unsupported public key algorithm %u\n", ++ p.params.pubkey_algo); ++ return ERR_PTR(-ENOPKG); ++ } ++ ++ if (pgp_public_key_algorithms[p.params.pubkey_algo] != key->algo) { ++ kleave(" = -EKEYREJECTED [wrong pk algo]"); ++ return ERR_PTR(-EKEYREJECTED); ++ } ++ ++ if (!(key->capabilities & PKEY_CAN_VERIFY)) { ++ kleave(" = -EKEYREJECTED [key can't verify]"); ++ return ERR_PTR(-EKEYREJECTED); ++ } ++ ++ if (p.params.hash_algo >= PGP_HASH__LAST || ++ !pgp_hash_algorithms[p.params.hash_algo]) { ++ pr_debug("Unsupported hash algorithm %u\n", ++ p.params.hash_algo); ++ return ERR_PTR(-ENOPKG); ++ } ++ ++ pr_debug("Signature generated with %s hash\n", ++ pgp_hash_algorithms[p.params.hash_algo]); ++ ++ if (memcmp(&p.params.issuer, key->key_id, 8) != 0) { ++ kleave(" = -ENOKEY [wrong key ID]"); ++ return ERR_PTR(-ENOKEY); ++ } ++ ++ if (p.params.signature_type != PGP_SIG_BINARY_DOCUMENT_SIG && ++ p.params.signature_type != PGP_SIG_STANDALONE_SIG) { ++ /* We don't want to canonicalise */ ++ kleave(" = -EOPNOTSUPP [canon]"); ++ return ERR_PTR(-EOPNOTSUPP); ++ } ++ ++ /* Allocate the hashing algorithm we're going to need and find out how ++ * big the hash operational data will be. ++ */ ++ tfm = crypto_alloc_shash(pgp_hash_algorithms[p.params.hash_algo], 0, 0); ++ if (IS_ERR(tfm)) ++ return PTR_ERR(tfm) == -ENOENT ? ++ ERR_PTR(-ENOPKG) : ERR_CAST(tfm); ++ ++ desc_size = crypto_shash_descsize(tfm); ++ digest_size = crypto_shash_digestsize(tfm); ++ ++ /* We allocate the hash operational data storage on the end of our ++ * context data. ++ */ ++ sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); ++ if (!sig) { ++ crypto_free_shash(tfm); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ sig->base.key = crypto_key; ++ sig->base.add_data = pgp_pkey_verify_sig_add_data; ++ sig->base.end = pgp_pkey_verify_sig_end; ++ sig->base.cancel = pgp_pkey_verify_sig_cancel; ++ sig->pkey_hash_algo = pgp_pubkey_hash[p.params.hash_algo].algo; ++ sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; ++ sig->digest_size = digest_size; ++ sig->hash.tfm = tfm; ++ sig->hash.flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ ++ ret = crypto_shash_init(&sig->hash); ++ if (ret < 0) { ++ crypto_free_shash(sig->hash.tfm); ++ kfree(sig); ++ return ERR_PTR(ret); ++ } ++ ++ key_get(sig->base.key); ++ kleave(" = %p", sig); ++ return &sig->base; ++} ++ ++/* ++ * Load data into the hash ++ */ ++static int pgp_pkey_verify_sig_add_data(struct crypto_key_verify_context *ctx, ++ const void *data, size_t datalen) ++{ ++ struct public_key_signature *sig = ++ container_of(ctx, struct public_key_signature, base); ++ ++ return crypto_shash_update(&sig->hash, data, datalen); ++} ++ ++struct pgp_pkey_sig_digest_context { ++ struct pgp_parse_context pgp; ++ const struct public_key *key; ++ struct public_key_signature *sig; ++}; ++ ++/* ++ * Extract required metadata from the signature packet and add what we need to ++ * to the hash. ++ */ ++static int pgp_pkey_digest_signature(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct pgp_pkey_sig_digest_context *ctx = ++ container_of(context, struct pgp_pkey_sig_digest_context, pgp); ++ enum pgp_signature_version version; ++ int i; ++ ++ kenter(",%u,%u,,%zu", type, headerlen, datalen); ++ ++ version = *data; ++ if (version == PGP_SIG_VERSION_3) { ++ /* We just include an excerpt of the metadata from a V3 ++ * signature. ++ */ ++ crypto_shash_update(&ctx->sig->hash, data + 1, 5); ++ data += sizeof(struct pgp_signature_v3_packet); ++ datalen -= sizeof(struct pgp_signature_v3_packet); ++ } else if (version == PGP_SIG_VERSION_4) { ++ /* We add the whole metadata header and some of the hashed data ++ * for a V4 signature, plus a trailer. ++ */ ++ size_t hashedsz, unhashedsz; ++ u8 trailer[6]; ++ ++ hashedsz = 4 + 2 + (data[4] << 8) + data[5]; ++ crypto_shash_update(&ctx->sig->hash, data, hashedsz); ++ ++ trailer[0] = version; ++ trailer[1] = 0xffU; ++ trailer[2] = hashedsz >> 24; ++ trailer[3] = hashedsz >> 16; ++ trailer[4] = hashedsz >> 8; ++ trailer[5] = hashedsz; ++ ++ crypto_shash_update(&ctx->sig->hash, trailer, 6); ++ data += hashedsz; ++ datalen -= hashedsz; ++ ++ unhashedsz = 2 + (data[0] << 8) + data[1]; ++ data += unhashedsz; ++ datalen -= unhashedsz; ++ } ++ ++ if (datalen <= 2) { ++ kleave(" = -EBADMSG"); ++ return -EBADMSG; ++ } ++ ++ /* There's a quick check on the hash available. */ ++ ctx->sig->signed_hash_msw[0] = *data++; ++ ctx->sig->signed_hash_msw[1] = *data++; ++ datalen -= 2; ++ ++ /* And then the cryptographic data, which we'll need for the ++ * algorithm. ++ */ ++ for (i = 0; i < ctx->key->algo->n_sig_mpi; i++) { ++ unsigned int remaining = datalen; ++ if (remaining == 0) { ++ pr_debug("short %zu mpi %d\n", datalen, i); ++ return -EBADMSG; ++ } ++ ctx->sig->mpi[i] = mpi_read_from_buffer(data, &remaining); ++ if (!ctx->sig->mpi[i]) ++ return -ENOMEM; ++ data += remaining; ++ datalen -= remaining; ++ } ++ ++ if (datalen != 0) { ++ kleave(" = -EBADMSG [trailer %zu]", datalen); ++ return -EBADMSG; ++ } ++ ++ kleave(" = 0"); ++ return 0; ++} ++ ++/* ++ * The data is now all loaded into the hash; load the metadata, finalise the ++ * hash and perform the verification step. ++ */ ++static int pgp_pkey_verify_sig_end(struct crypto_key_verify_context *ctx, ++ const u8 *sigdata, size_t siglen) ++{ ++ struct public_key_signature *sig = ++ container_of(ctx, struct public_key_signature, base); ++ const struct public_key *key = sig->base.key->payload.data; ++ struct pgp_pkey_sig_digest_context p; ++ int ret; ++ ++ kenter(""); ++ ++ /* Firstly we add metadata, starting with some of the data from the ++ * signature packet */ ++ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); ++ p.pgp.process_packet = pgp_pkey_digest_signature; ++ p.key = key; ++ p.sig = sig; ++ ret = pgp_parse_packets(sigdata, siglen, &p.pgp); ++ if (ret < 0) ++ goto error_free_ctx; ++ ++ crypto_shash_final(&sig->hash, sig->digest); ++ ++ ret = key->algo->verify(key, sig); ++ ++error_free_ctx: ++ pgp_pkey_verify_sig_cancel(ctx); ++ kleave(" = %d", ret); ++ return ret; ++} ++ ++/* ++ * Cancel an in-progress data loading ++ */ ++static void pgp_pkey_verify_sig_cancel(struct crypto_key_verify_context *ctx) ++{ ++ struct public_key_signature *sig = ++ container_of(ctx, struct public_key_signature, base); ++ int i; ++ ++ kenter(""); ++ ++ /* !!! Do we need to tell the crypto layer to cancel too? */ ++ crypto_free_shash(sig->hash.tfm); ++ key_put(sig->base.key); ++ for (i = 0; i < ARRAY_SIZE(sig->mpi); i++) ++ mpi_free(sig->mpi[i]); ++ kfree(sig); ++ ++ kleave(""); ++} +-- +1.7.11.2 + + +From fbd1b578b58a197da42428fda49654d38c794f31 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:21 +0100 +Subject: [PATCH 13/27] 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 +and set the public-key algorithm according to the data in the signature. + +Signed-off-by: David Howells +--- + security/keys/crypto/Makefile | 1 + + security/keys/crypto/pgp_parser.h | 6 ++ + security/keys/crypto/pgp_public_key.c | 1 + + security/keys/crypto/pgp_sig_parser.c | 114 ++++++++++++++++++++++++++++++++++ + 4 files changed, 122 insertions(+) + create mode 100644 security/keys/crypto/pgp_sig_parser.c + +diff --git a/security/keys/crypto/Makefile b/security/keys/crypto/Makefile +index 0c8b8a1..a9a34c6 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_key_parser.o + pgp_key_parser-y := \ + pgp_public_key.o \ ++ pgp_sig_parser.o \ + pgp_sig_verify.o +diff --git a/security/keys/crypto/pgp_parser.h b/security/keys/crypto/pgp_parser.h +index a6192ce..73c900e 100644 +--- 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]; + + /* ++ * pgp_sig_parser.c ++ */ ++extern struct crypto_key_verify_context *pgp_verify_sig_begin( ++ struct key *keyring, const u8 *sig, size_t siglen); ++ ++/* + * pgp_pubkey_sig.c + */ + extern struct crypto_key_verify_context *pgp_pkey_verify_sig_begin( +diff --git a/security/keys/crypto/pgp_public_key.c b/security/keys/crypto/pgp_public_key.c +index 8a8b7c0..5ab926d 100644 +--- a/security/keys/crypto/pgp_public_key.c ++++ b/security/keys/crypto/pgp_public_key.c +@@ -329,6 +329,7 @@ static struct crypto_key_parser pgp_key_parser = { + .owner = THIS_MODULE, + .name = "pgp", + .instantiate = pgp_key_instantiate, ++ .verify_sig_begin = pgp_verify_sig_begin, + }; + + /* +diff --git a/security/keys/crypto/pgp_sig_parser.c b/security/keys/crypto/pgp_sig_parser.c +new file mode 100644 +index 0000000..f5feb2b +--- /dev/null ++++ b/security/keys/crypto/pgp_sig_parser.c +@@ -0,0 +1,114 @@ ++/* Handling for PGP public key signature data [RFC 4880] ++ * ++ * 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. ++ */ ++ ++#define pr_fmt(fmt) "PGPSIG: "fmt ++#include ++#include ++#include ++#include ++#include "public_key.h" ++#include "pgp_parser.h" ++ ++struct PGP_sig_parse_context { ++ struct pgp_parse_context pgp; ++ struct pgp_sig_parameters params; ++ bool found_sig; ++}; ++ ++/* ++ * Look inside signature sections for a key ID ++ */ ++static int pgp_process_signature(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, ++ u8 headerlen, ++ const u8 *data, ++ size_t datalen) ++{ ++ struct PGP_sig_parse_context *ctx = ++ container_of(context, struct PGP_sig_parse_context, pgp); ++ ++ ctx->found_sig = true; ++ return pgp_parse_sig_params(&data, &datalen, &ctx->params); ++} ++ ++/* ++ * Attempt to find a key to use for PGP signature verification, starting off by ++ * looking in the supplied keyring. ++ * ++ * The function may also look for other key sources such as a TPM. If an ++ * alternative key is found it can be added to the keyring for future ++ * reference. ++ */ ++static struct key *find_key_for_pgp_sig(struct key *keyring, ++ const u8 *sig, size_t siglen) ++{ ++ struct PGP_sig_parse_context p; ++ key_ref_t key; ++ char criterion[3 + 8 * 2 + 1]; ++ int ret; ++ ++ if (!keyring) ++ return ERR_PTR(-ENOKEY); ++ ++ /* Need to find the key ID */ ++ p.pgp.types_of_interest = (1 << PGP_PKT_SIGNATURE); ++ p.pgp.process_packet = pgp_process_signature; ++ p.found_sig = false; ++ ret = pgp_parse_packets(sig, siglen, &p.pgp); ++ if (ret < 0) ++ return ERR_PTR(ret); ++ ++ if (!p.found_sig) ++ return ERR_PTR(-ENOMSG); ++ ++ sprintf(criterion, "id:%08x%08x", ++ be32_to_cpu(p.params.issuer32[0]), ++ be32_to_cpu(p.params.issuer32[1])); ++ ++ pr_debug("Look up: %s\n", criterion); ++ ++ key = keyring_search(make_key_ref(keyring, 1), ++ &key_type_crypto, criterion); ++ 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); ++} ++ ++/* ++ * Attempt to parse a signature as a PGP packet format blob and find a ++ * matching key. ++ */ ++struct crypto_key_verify_context *pgp_verify_sig_begin( ++ struct key *keyring, const u8 *sig, size_t siglen) ++{ ++ struct crypto_key_verify_context *ctx; ++ struct key *key; ++ ++ key = find_key_for_pgp_sig(keyring, sig, siglen); ++ if (IS_ERR(key)) ++ return ERR_CAST(key); ++ ++ /* We only handle in-kernel public key signatures for the moment */ ++ ctx = pgp_pkey_verify_sig_begin(key, sig, siglen); ++ key_put(key); ++ return ctx; ++} +-- +1.7.11.2 + + +From a04615b5ce4ae2e6e0f1932cd697b6a3d41cb9f8 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:11:21 +0100 +Subject: [PATCH 14/27] 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: + + int load_PGP_keys(const u8 *pgpdata, size_t pgpdatalen, + struct key *keyring, const char *descprefix); + +The keys are labelled with descprefix plus a number to uniquify them. The keys +will actually be identified by the ID calculated from the PGP data rather than +by the description, so this shouldn't be a problem. + +The keys are attached to the keyring supplied. + +Looking as root in /proc/keys after the module signing keyring has been loaded: + +24460d1c I----- 1 perm 3f010000 0 0 crypto modsign.0: dsa 5acc2142 [] +3ca85723 I----- 1 perm 1f010000 0 0 keyring .module_sign: 1/4 + +Thanks to Tetsuo Handa for some pointing +out some errors. + +Signed-off-by: David Howells +--- + Documentation/security/keys-crypto.txt | 20 +++++++ + include/keys/crypto-type.h | 3 ++ + security/keys/crypto/Kconfig | 9 ++++ + security/keys/crypto/Makefile | 1 + + security/keys/crypto/pgp_preload.c | 96 ++++++++++++++++++++++++++++++++++ + 5 files changed, 129 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 +--- a/Documentation/security/keys-crypto.txt ++++ b/Documentation/security/keys-crypto.txt +@@ -10,6 +10,7 @@ Contents: + - Signature verification. + - Implementing crypto parsers. + - Implementing crypto subtypes. ++ - Initial PGP key preloading. + + + ======== +@@ -280,3 +281,22 @@ There are a number of operations defined by the subtype: + Mandatory. This should free the memory associated with the key. The + crypto key will look after freeing the fingerprint and releasing the + reference on the subtype module. ++ ++ ++======================= ++INITIAL PGP KEY LOADING ++======================= ++ ++A function is provided to perform an initial load of a set of public keys bound ++into a PGP packet format blob: ++ ++ int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, ++ struct key *keyring, const char *descprefix); ++ ++This takes the blob of data defined by pgpdata and pgpdatalen, extracts keys ++from them and adds them to the specified keyring. The keys are labelled with ++descprefix plus a simple uniquifier - it is not expected that the description ++will be used to identify the key. The description is required to prevent all ++but the last key being discarded when the keys are linked into the keyring. ++ ++This function is only available during initial kernel set up. +diff --git a/include/keys/crypto-type.h b/include/keys/crypto-type.h +index 6b93366..710e77f 100644 +--- a/include/keys/crypto-type.h ++++ b/include/keys/crypto-type.h +@@ -31,4 +31,7 @@ extern void verify_sig_cancel(struct crypto_key_verify_context *ctx); + * The payload is at the discretion of the subtype. + */ + ++extern __init int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, ++ struct key *keyring, const char *descprefix); ++ + #endif /* _KEYS_CRYPTO_TYPE_H */ +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. ++ ++config PGP_PRELOAD ++ bool "PGP public key preloading facility" ++ select PGP_LIBRARY ++ select CRYPTO_KEY_PGP_PARSER ++ help ++ 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/crypto/Makefile b/security/keys/crypto/Makefile +index a9a34c6..c873674 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_key_parser.o + pgp_key_parser-y := \ +diff --git a/security/keys/crypto/pgp_preload.c b/security/keys/crypto/pgp_preload.c +new file mode 100644 +index 0000000..9028788 +--- /dev/null ++++ b/security/keys/crypto/pgp_preload.c +@@ -0,0 +1,96 @@ ++/* Cryptographic key request handling ++ * ++ * 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. ++ * ++ * See Documentation/security/keys-crypto.txt ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "crypto_keys.h" ++ ++struct preload_pgp_keys_context { ++ struct pgp_parse_context pgp; ++ key_ref_t keyring; ++ char descbuf[20]; ++ u8 key_n; ++ u8 dsize; ++}; ++ ++/* ++ * Extract a public key or subkey from the PGP stream. ++ */ ++static int __init found_pgp_key(struct pgp_parse_context *context, ++ enum pgp_packet_tag type, u8 headerlen, ++ const u8 *data, size_t datalen) ++{ ++ struct preload_pgp_keys_context *ctx = ++ container_of(context, struct preload_pgp_keys_context, pgp); ++ key_ref_t key; ++ ++ if (ctx->key_n >= 255) ++ return 0; /* Don't overrun descbuf */ ++ ++ sprintf(ctx->descbuf + ctx->dsize, "%d", ctx->key_n++); ++ ++ key = key_create_or_update(ctx->keyring, "crypto", ctx->descbuf, ++ data - headerlen, datalen + headerlen, ++ KEY_POS_ALL | KEY_USR_VIEW, ++ KEY_ALLOC_NOT_IN_QUOTA); ++ ++ if (IS_ERR(key)) ++ return PTR_ERR(key); ++ ++ pr_notice("Loaded %s key: %s\n", ++ key_ref_to_ptr(key)->description, ++ crypto_key_id(key_ref_to_ptr(key))); ++ ++ key_ref_put(key); ++ return 0; ++} ++ ++/** ++ * preload_pgp_keys - Load keys from a PGP keyring blob ++ * @pgpdata: The PGP keyring blob containing the keys. ++ * @pgpdatalen: The size of the @pgpdata blob. ++ * @keyring: The keyring to add the new keys to. ++ * @descprefix: The key description prefix. ++ * ++ * Preload a pack of keys from a PGP keyring blob. ++ * ++ * The keys are given description of @descprefix + the number of the key in the ++ * list. Since keys can be matched on their key IDs independently of the key ++ * description, the description is mostly irrelevant apart from the fact that ++ * keys of the same description displace one another from a keyring. ++ * ++ * The caller should override the current creds if they want the keys to be ++ * owned by someone other than the current process's owner. Keys will not be ++ * accounted towards the owner's quota. ++ * ++ * This function may only be called whilst the kernel is booting. ++ */ ++int __init preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen, ++ struct key *keyring, const char *descprefix) ++{ ++ struct preload_pgp_keys_context ctx; ++ ++ ctx.pgp.types_of_interest = ++ (1 << PGP_PKT_PUBLIC_KEY) | (1 << PGP_PKT_PUBLIC_SUBKEY); ++ ctx.pgp.process_packet = found_pgp_key; ++ ctx.keyring = make_key_ref(keyring, 1); ++ ctx.key_n = 0; ++ ctx.dsize = strlen(descprefix); ++ BUG_ON(ctx.dsize > sizeof(ctx.descbuf) - 4); ++ strcpy(ctx.descbuf, descprefix); ++ ++ return pgp_parse_packets(pgpdata, pgpdatalen, &ctx.pgp); ++} +-- +1.7.11.2 + + +From d0e5635f09c91ca12fa5a508c2ba5197372d7487 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:13:56 +0100 +Subject: [PATCH 15/27] Make most arch asm/module.h files use + asm-generic/module.h + +Use the mapping of Elf_[SPE]hdr, Elf_Addr, Elf_Sym, Elf_Dyn, Elf_Rel/Rela, +ELF_R_TYPE() and ELF_R_SYM() to either the 32-bit version or the 64-bit version +into asm-generic/module.h for all arches bar MIPS. + +Also, use the generic definition mod_arch_specific where possible. + +To this end, I've defined three new config bools: + + (*) HAVE_MOD_ARCH_SPECIFIC + + Arches define this if they don't want to use the empty generic + mod_arch_specific struct. + + (*) MODULES_USE_ELF_RELA + + Arches define this if their modules can contain RELA records. This causes + the Elf_Rela mapping to be emitted and allows apply_relocate_add() to be + defined by the arch rather than have the core emit an error message. + + (*) MODULES_USE_ELF_REL + + Arches define this if their modules can contain REL records. This causes + the Elf_Rel mapping to be emitted and allows apply_relocate() to be + defined by the arch rather than have the core emit an error message. + +Note that it is possible to allow both REL and RELA records: m68k and mips are +two arches that do this. + +With this, some arch asm/module.h files can be deleted entirely and replaced +with a generic-y marker in the arch Kbuild file. + +Additionally, I have removed the bits from m32r and score that handle the +unsupported type of relocation record as that's now handled centrally. + +Signed-off-by: David Howells +--- + arch/Kconfig | 19 ++++++++++++++++++ + arch/alpha/Kconfig | 2 ++ + arch/alpha/include/asm/module.h | 10 ++-------- + arch/arm/Kconfig | 2 ++ + arch/arm/include/asm/module.h | 8 ++------ + arch/avr32/Kconfig | 2 ++ + arch/avr32/include/asm/module.h | 6 ++---- + arch/blackfin/Kconfig | 2 ++ + arch/blackfin/include/asm/module.h | 4 +--- + arch/c6x/Kconfig | 1 + + arch/c6x/include/asm/module.h | 12 +----------- + arch/cris/Kconfig | 1 + + arch/cris/include/asm/Kbuild | 2 ++ + arch/cris/include/asm/module.h | 9 --------- + arch/frv/include/asm/module.h | 8 +------- + arch/h8300/Kconfig | 1 + + arch/h8300/include/asm/Kbuild | 2 ++ + arch/h8300/include/asm/module.h | 11 ----------- + arch/hexagon/Kconfig | 1 + + arch/ia64/Kconfig | 2 ++ + arch/ia64/include/asm/module.h | 6 ++---- + arch/m32r/Kconfig | 1 + + arch/m32r/include/asm/Kbuild | 2 ++ + arch/m32r/include/asm/module.h | 10 ---------- + arch/m32r/kernel/module.c | 15 -------------- + arch/m68k/Kconfig | 3 +++ + arch/m68k/include/asm/module.h | 6 ++---- + arch/microblaze/Kconfig | 1 + + arch/mips/Kconfig | 3 +++ + arch/mips/include/asm/module.h | 10 ++++++++-- + arch/mips/kernel/module.c | 2 ++ + arch/mn10300/Kconfig | 1 + + arch/mn10300/include/asm/module.h | 7 +------ + arch/openrisc/Kconfig | 1 + + arch/parisc/Kconfig | 2 ++ + arch/parisc/include/asm/module.h | 16 +++------------ + arch/powerpc/Kconfig | 2 ++ + arch/powerpc/include/asm/module.h | 7 +------ + arch/s390/Kconfig | 2 ++ + arch/s390/include/asm/module.h | 18 +++-------------- + arch/score/Kconfig | 2 ++ + arch/score/include/asm/module.h | 6 +----- + arch/score/kernel/module.c | 10 ---------- + arch/sh/Kconfig | 2 ++ + arch/sh/include/asm/module.h | 14 +++---------- + arch/sparc/Kconfig | 1 + + arch/sparc/include/asm/Kbuild | 1 + + arch/sparc/include/asm/module.h | 24 ----------------------- + arch/tile/Kconfig | 1 + + arch/unicore32/Kconfig | 1 + + arch/x86/Kconfig | 2 ++ + arch/xtensa/Kconfig | 1 + + arch/xtensa/include/asm/module.h | 9 +-------- + include/asm-generic/module.h | 40 +++++++++++++++++++++++++++++++------- + include/linux/moduleloader.h | 36 ++++++++++++++++++++++++++++++---- + kernel/module.c | 20 ------------------- + 56 files changed, 167 insertions(+), 223 deletions(-) + delete mode 100644 arch/cris/include/asm/module.h + delete mode 100644 arch/h8300/include/asm/module.h + delete mode 100644 arch/m32r/include/asm/module.h + delete mode 100644 arch/sparc/include/asm/module.h + +diff --git a/arch/Kconfig b/arch/Kconfig +index 8c3d957..51acb02 100644 +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -274,4 +274,23 @@ config SECCOMP_FILTER + + See Documentation/prctl/seccomp_filter.txt for details. + ++config HAVE_MOD_ARCH_SPECIFIC ++ bool ++ help ++ The arch uses struct mod_arch_specific to store data. Many arches ++ just need a simple module loader without arch specific data - those ++ should not enable this. ++ ++config MODULES_USE_ELF_RELA ++ bool ++ help ++ Modules only use ELF RELA relocations. Modules with ELF REL ++ relocations will give an error. ++ ++config MODULES_USE_ELF_REL ++ bool ++ help ++ Modules only use ELF REL relocations. Modules with ELF RELA ++ relocations will give an error. ++ + source "kernel/gcov/Kconfig" +diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig +index 3de74c9..6f580de 100644 +--- a/arch/alpha/Kconfig ++++ b/arch/alpha/Kconfig +@@ -17,6 +17,8 @@ config ALPHA + select ARCH_HAVE_NMI_SAFE_CMPXCHG + select GENERIC_SMP_IDLE_THREAD + select GENERIC_CMOS_UPDATE ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + help + The Alpha is a 64-bit general-purpose processor designed and + marketed by the Digital Equipment Corporation of blessed memory, +diff --git a/arch/alpha/include/asm/module.h b/arch/alpha/include/asm/module.h +index 7b63743..9cd13b5 100644 +--- a/arch/alpha/include/asm/module.h ++++ b/arch/alpha/include/asm/module.h +@@ -1,19 +1,13 @@ + #ifndef _ALPHA_MODULE_H + #define _ALPHA_MODULE_H + ++#include ++ + struct mod_arch_specific + { + unsigned int gotsecindex; + }; + +-#define Elf_Sym Elf64_Sym +-#define Elf_Shdr Elf64_Shdr +-#define Elf_Ehdr Elf64_Ehdr +-#define Elf_Phdr Elf64_Phdr +-#define Elf_Dyn Elf64_Dyn +-#define Elf_Rel Elf64_Rel +-#define Elf_Rela Elf64_Rela +- + #define ARCH_SHF_SMALL SHF_ALPHA_GPREL + + #ifdef MODULE +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index c7e6d20..5fc742e 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -45,6 +45,8 @@ config ARM + select GENERIC_SMP_IDLE_THREAD + select KTIME_SCALAR + select GENERIC_CLOCKEVENTS_BROADCAST if SMP ++ select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND ++ select MODULES_USE_ELF_REL + help + The ARM series is a line of low-power-consumption RISC chip designs + licensed by ARM Ltd and targeted at embedded applications and +diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h +index 6c6809f..0d3a28d 100644 +--- a/arch/arm/include/asm/module.h ++++ b/arch/arm/include/asm/module.h +@@ -1,9 +1,7 @@ + #ifndef _ASM_ARM_MODULE_H + #define _ASM_ARM_MODULE_H + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr ++#include + + struct unwind_table; + +@@ -16,13 +14,11 @@ enum { + ARM_SEC_DEVEXIT, + ARM_SEC_MAX, + }; +-#endif + + struct mod_arch_specific { +-#ifdef CONFIG_ARM_UNWIND + struct unwind_table *unwind[ARM_SEC_MAX]; +-#endif + }; ++#endif + + /* + * Add the ARM architecture version to the version magic string +diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig +index 71d38c7..2779913 100644 +--- a/arch/avr32/Kconfig ++++ b/arch/avr32/Kconfig +@@ -14,6 +14,8 @@ config AVR32 + select ARCH_HAVE_CUSTOM_GPIO_H + select ARCH_HAVE_NMI_SAFE_CMPXCHG + select GENERIC_CLOCKEVENTS ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + help + AVR32 is a high-performance 32-bit RISC microprocessor core, + designed for cost-sensitive embedded applications, with particular +diff --git a/arch/avr32/include/asm/module.h b/arch/avr32/include/asm/module.h +index 4514445..3f083d3 100644 +--- a/arch/avr32/include/asm/module.h ++++ b/arch/avr32/include/asm/module.h +@@ -1,6 +1,8 @@ + #ifndef __ASM_AVR32_MODULE_H + #define __ASM_AVR32_MODULE_H + ++#include ++ + struct mod_arch_syminfo { + unsigned long got_offset; + int got_initialized; +@@ -17,10 +19,6 @@ struct mod_arch_specific { + struct mod_arch_syminfo *syminfo; + }; + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +- + #define MODULE_PROC_FAMILY "AVR32v1" + + #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY +diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig +index fef96f4..b8a7bc9 100644 +--- a/arch/blackfin/Kconfig ++++ b/arch/blackfin/Kconfig +@@ -40,6 +40,8 @@ config BLACKFIN + select HAVE_NMI_WATCHDOG if NMI_WATCHDOG + select GENERIC_SMP_IDLE_THREAD + select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + + config GENERIC_CSUM + def_bool y +diff --git a/arch/blackfin/include/asm/module.h b/arch/blackfin/include/asm/module.h +index ed5689b..231a149 100644 +--- a/arch/blackfin/include/asm/module.h ++++ b/arch/blackfin/include/asm/module.h +@@ -7,9 +7,7 @@ + #ifndef _ASM_BFIN_MODULE_H + #define _ASM_BFIN_MODULE_H + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr ++#include + + struct mod_arch_specific { + Elf_Shdr *text_l1; +diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig +index 052f81a..8f3a304 100644 +--- a/arch/c6x/Kconfig ++++ b/arch/c6x/Kconfig +@@ -16,6 +16,7 @@ config C6X + select OF + select OF_EARLY_FLATTREE + select GENERIC_CLOCKEVENTS ++ select MODULES_USE_ELF_RELA + + config MMU + def_bool n +diff --git a/arch/c6x/include/asm/module.h b/arch/c6x/include/asm/module.h +index a453f97..5c7269c 100644 +--- a/arch/c6x/include/asm/module.h ++++ b/arch/c6x/include/asm/module.h +@@ -13,17 +13,7 @@ + #ifndef _ASM_C6X_MODULE_H + #define _ASM_C6X_MODULE_H + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +-#define Elf_Addr Elf32_Addr +-#define Elf_Word Elf32_Word +- +-/* +- * This file contains the C6x architecture specific module code. +- */ +-struct mod_arch_specific { +-}; ++#include + + struct loaded_sections { + unsigned int new_vaddr; +diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig +index bb34465..45782c7 100644 +--- a/arch/cris/Kconfig ++++ b/arch/cris/Kconfig +@@ -46,6 +46,7 @@ config CRIS + select GENERIC_IOMAP + select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32 + select GENERIC_CMOS_UPDATE ++ select MODULES_USE_ELF_RELA + + config HZ + int +diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild +index 04d02a5..28b690d 100644 +--- a/arch/cris/include/asm/Kbuild ++++ b/arch/cris/include/asm/Kbuild +@@ -7,3 +7,5 @@ header-y += ethernet.h + header-y += etraxgpio.h + header-y += rs485.h + header-y += sync_serial.h ++ ++generic-y += module.h +diff --git a/arch/cris/include/asm/module.h b/arch/cris/include/asm/module.h +deleted file mode 100644 +index 7ee7231..0000000 +--- a/arch/cris/include/asm/module.h ++++ /dev/null +@@ -1,9 +0,0 @@ +-#ifndef _ASM_CRIS_MODULE_H +-#define _ASM_CRIS_MODULE_H +-/* cris is simple */ +-struct mod_arch_specific { }; +- +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +-#endif /* _ASM_CRIS_MODULE_H */ +diff --git a/arch/frv/include/asm/module.h b/arch/frv/include/asm/module.h +index 3d5c636..a8848f0 100644 +--- a/arch/frv/include/asm/module.h ++++ b/arch/frv/include/asm/module.h +@@ -11,13 +11,7 @@ + #ifndef _ASM_MODULE_H + #define _ASM_MODULE_H + +-struct mod_arch_specific +-{ +-}; +- +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr ++#include + + /* + * Include the architecture version. +diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig +index 56e890d..9eaefdd 100644 +--- a/arch/h8300/Kconfig ++++ b/arch/h8300/Kconfig +@@ -5,6 +5,7 @@ config H8300 + select HAVE_GENERIC_HARDIRQS + select GENERIC_IRQ_SHOW + select GENERIC_CPU_DEVICES ++ select MODULES_USE_ELF_RELA + + config SYMBOL_PREFIX + string +diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild +index c68e168..871382d 100644 +--- a/arch/h8300/include/asm/Kbuild ++++ b/arch/h8300/include/asm/Kbuild +@@ -1 +1,3 @@ + include include/asm-generic/Kbuild.asm ++ ++generic-y += module.h +diff --git a/arch/h8300/include/asm/module.h b/arch/h8300/include/asm/module.h +deleted file mode 100644 +index 8e46724..0000000 +--- a/arch/h8300/include/asm/module.h ++++ /dev/null +@@ -1,11 +0,0 @@ +-#ifndef _ASM_H8300_MODULE_H +-#define _ASM_H8300_MODULE_H +-/* +- * This file contains the H8/300 architecture specific module code. +- */ +-struct mod_arch_specific { }; +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +- +-#endif /* _ASM_H8/300_MODULE_H */ +diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig +index b2fdfb7..0744f7d 100644 +--- a/arch/hexagon/Kconfig ++++ b/arch/hexagon/Kconfig +@@ -30,6 +30,7 @@ config HEXAGON + select KTIME_SCALAR + select GENERIC_CLOCKEVENTS + select GENERIC_CLOCKEVENTS_BROADCAST ++ select MODULES_USE_ELF_RELA + ---help--- + Qualcomm Hexagon is a processor architecture designed for high + performance and low power across a wide variety of applications. +diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig +index 8186ec5..6f1b7b1 100644 +--- a/arch/ia64/Kconfig ++++ b/arch/ia64/Kconfig +@@ -39,6 +39,8 @@ config IA64 + select ARCH_THREAD_INFO_ALLOCATOR + select ARCH_CLOCKSOURCE_DATA + select GENERIC_TIME_VSYSCALL ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + default y + help + The Itanium Processor Family is Intel's 64-bit successor to +diff --git a/arch/ia64/include/asm/module.h b/arch/ia64/include/asm/module.h +index 908eaef..dfba22a 100644 +--- a/arch/ia64/include/asm/module.h ++++ b/arch/ia64/include/asm/module.h +@@ -1,6 +1,8 @@ + #ifndef _ASM_IA64_MODULE_H + #define _ASM_IA64_MODULE_H + ++#include ++ + /* + * IA-64-specific support for kernel module loader. + * +@@ -29,10 +31,6 @@ struct mod_arch_specific { + unsigned int next_got_entry; /* index of next available got entry */ + }; + +-#define Elf_Shdr Elf64_Shdr +-#define Elf_Sym Elf64_Sym +-#define Elf_Ehdr Elf64_Ehdr +- + #define MODULE_PROC_FAMILY "ia64" + #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \ + "gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__) +diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig +index b638d5b..a30478e 100644 +--- a/arch/m32r/Kconfig ++++ b/arch/m32r/Kconfig +@@ -12,6 +12,7 @@ config M32R + select GENERIC_IRQ_SHOW + select GENERIC_ATOMIC64 + select ARCH_USES_GETTIMEOFFSET ++ select MODULES_USE_ELF_RELA + + config SBUS + bool +diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild +index c68e168..871382d 100644 +--- a/arch/m32r/include/asm/Kbuild ++++ b/arch/m32r/include/asm/Kbuild +@@ -1 +1,3 @@ + include include/asm-generic/Kbuild.asm ++ ++generic-y += module.h +diff --git a/arch/m32r/include/asm/module.h b/arch/m32r/include/asm/module.h +deleted file mode 100644 +index eb73ee0..0000000 +--- a/arch/m32r/include/asm/module.h ++++ /dev/null +@@ -1,10 +0,0 @@ +-#ifndef _ASM_M32R_MODULE_H +-#define _ASM_M32R_MODULE_H +- +-struct mod_arch_specific { }; +- +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +- +-#endif /* _ASM_M32R_MODULE_H */ +diff --git a/arch/m32r/kernel/module.c b/arch/m32r/kernel/module.c +index 3071fe8..38233b6 100644 +--- a/arch/m32r/kernel/module.c ++++ b/arch/m32r/kernel/module.c +@@ -201,18 +201,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, + } + return 0; + } +- +-int apply_relocate(Elf32_Shdr *sechdrs, +- const char *strtab, +- unsigned int symindex, +- unsigned int relsec, +- struct module *me) +-{ +-#if 0 +- printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", +- me->name); +- return -ENOEXEC; +-#endif +- return 0; +- +-} +diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig +index 1471201..3694301 100644 +--- a/arch/m68k/Kconfig ++++ b/arch/m68k/Kconfig +@@ -11,6 +11,9 @@ config M68K + select GENERIC_STRNLEN_USER if MMU + select FPU if MMU + select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_REL ++ select MODULES_USE_ELF_RELA + + config RWSEM_GENERIC_SPINLOCK + bool +diff --git a/arch/m68k/include/asm/module.h b/arch/m68k/include/asm/module.h +index edffe66..8b58fce 100644 +--- a/arch/m68k/include/asm/module.h ++++ b/arch/m68k/include/asm/module.h +@@ -1,6 +1,8 @@ + #ifndef _ASM_M68K_MODULE_H + #define _ASM_M68K_MODULE_H + ++#include ++ + enum m68k_fixup_type { + m68k_fixup_memoffset, + m68k_fixup_vnode_shift, +@@ -36,8 +38,4 @@ struct module; + extern void module_fixup(struct module *mod, struct m68k_fixup_info *start, + struct m68k_fixup_info *end); + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +- + #endif /* _ASM_M68K_MODULE_H */ +diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig +index 0bf4423..ee395d3 100644 +--- a/arch/microblaze/Kconfig ++++ b/arch/microblaze/Kconfig +@@ -23,6 +23,7 @@ config MICROBLAZE + select GENERIC_CPU_DEVICES + select GENERIC_ATOMIC64 + select GENERIC_CLOCKEVENTS ++ select MODULES_USE_ELF_RELA + + config SWAP + def_bool n +diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig +index b3e10fd..5972ebd 100644 +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -34,6 +34,9 @@ config MIPS + select BUILDTIME_EXTABLE_SORT + select GENERIC_CLOCKEVENTS + select GENERIC_CMOS_UPDATE ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_REL ++ select MODULES_USE_ELF_RELA if 64BIT + + menu "Machine selection" + +diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h +index 5300080..2c6a4f21 100644 +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -34,11 +34,14 @@ typedef struct { + } Elf64_Mips_Rela; + + #ifdef CONFIG_32BIT +- + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr + #define Elf_Addr Elf32_Addr ++#define Elf_Rel Elf32_Rel ++#define Elf_Rela Elf32_Rela ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + + #define Elf_Mips_Rel Elf32_Rel + #define Elf_Mips_Rela Elf32_Rela +@@ -49,11 +52,14 @@ typedef struct { + #endif + + #ifdef CONFIG_64BIT +- + #define Elf_Shdr Elf64_Shdr + #define Elf_Sym Elf64_Sym + #define Elf_Ehdr Elf64_Ehdr + #define Elf_Addr Elf64_Addr ++#define Elf_Rel Elf64_Rel ++#define Elf_Rela Elf64_Rela ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) + + #define Elf_Mips_Rel Elf64_Mips_Rel + #define Elf_Mips_Rela Elf64_Mips_Rela +diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c +index a5066b1..1500c80 100644 +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -299,6 +299,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, + return 0; + } + ++#ifdef CONFIG_MODULES_USE_ELF_RELA + int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *me) +@@ -338,6 +339,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, + + return 0; + } ++#endif + + /* Given an address, look for it in the module exception tables. */ + const struct exception_table_entry *search_module_dbetables(unsigned long addr) +diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig +index 687f9b4..f8fec1c 100644 +--- a/arch/mn10300/Kconfig ++++ b/arch/mn10300/Kconfig +@@ -7,6 +7,7 @@ config MN10300 + select HAVE_ARCH_KGDB + select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER + select GENERIC_CLOCKEVENTS ++ select MODULES_USE_ELF_RELA + + config AM33_2 + def_bool n +diff --git a/arch/mn10300/include/asm/module.h b/arch/mn10300/include/asm/module.h +index 5d7057d..6571103 100644 +--- a/arch/mn10300/include/asm/module.h ++++ b/arch/mn10300/include/asm/module.h +@@ -12,12 +12,7 @@ + #ifndef _ASM_MODULE_H + #define _ASM_MODULE_H + +-struct mod_arch_specific { +-}; +- +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr ++#include + + /* + * Include the MN10300 architecture version. +diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig +index 49765b5..05f2ba4 100644 +--- a/arch/openrisc/Kconfig ++++ b/arch/openrisc/Kconfig +@@ -21,6 +21,7 @@ config OPENRISC + select GENERIC_CLOCKEVENTS + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER ++ select MODULES_USE_ELF_RELA + + config MMU + def_bool y +diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig +index 3ff21b5..166d991 100644 +--- a/arch/parisc/Kconfig ++++ b/arch/parisc/Kconfig +@@ -19,6 +19,8 @@ config PARISC + select ARCH_HAVE_NMI_SAFE_CMPXCHG + select GENERIC_SMP_IDLE_THREAD + select GENERIC_STRNCPY_FROM_USER ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + + help + The PA-RISC microprocessor is designed by Hewlett-Packard and used +diff --git a/arch/parisc/include/asm/module.h b/arch/parisc/include/asm/module.h +index 1f41234..bab37e9 100644 +--- a/arch/parisc/include/asm/module.h ++++ b/arch/parisc/include/asm/module.h +@@ -1,21 +1,11 @@ + #ifndef _ASM_PARISC_MODULE_H + #define _ASM_PARISC_MODULE_H ++ ++#include ++ + /* + * This file contains the parisc architecture specific module code. + */ +-#ifdef CONFIG_64BIT +-#define Elf_Shdr Elf64_Shdr +-#define Elf_Sym Elf64_Sym +-#define Elf_Ehdr Elf64_Ehdr +-#define Elf_Addr Elf64_Addr +-#define Elf_Rela Elf64_Rela +-#else +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +-#define Elf_Addr Elf32_Addr +-#define Elf_Rela Elf32_Rela +-#endif + + struct unwind_table; + +diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig +index 9a5d3cd..5a91b5b 100644 +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -137,6 +137,8 @@ config PPC + select GENERIC_CLOCKEVENTS + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + + config EARLY_PRINTK + bool +diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h +index 0192a4e..c1df590 100644 +--- a/arch/powerpc/include/asm/module.h ++++ b/arch/powerpc/include/asm/module.h +@@ -11,6 +11,7 @@ + + #include + #include ++#include + + + #ifndef __powerpc64__ +@@ -60,16 +61,10 @@ struct mod_arch_specific { + */ + + #ifdef __powerpc64__ +-# define Elf_Shdr Elf64_Shdr +-# define Elf_Sym Elf64_Sym +-# define Elf_Ehdr Elf64_Ehdr + # ifdef MODULE + asm(".section .stubs,\"ax\",@nobits; .align 3; .previous"); + # endif + #else +-# define Elf_Shdr Elf32_Shdr +-# define Elf_Sym Elf32_Sym +-# define Elf_Ehdr Elf32_Ehdr + # ifdef MODULE + asm(".section .plt,\"ax\",@nobits; .align 3; .previous"); + asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous"); +diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig +index a39b469..7c16d31 100644 +--- a/arch/s390/Kconfig ++++ b/arch/s390/Kconfig +@@ -121,6 +121,8 @@ config S390 + select GENERIC_TIME_VSYSCALL + select GENERIC_CLOCKEVENTS + select KTIME_SCALAR if 32BIT ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_RELA + + config SCHED_OMIT_FRAME_POINTER + def_bool y +diff --git a/arch/s390/include/asm/module.h b/arch/s390/include/asm/module.h +index f0b6b26..df1f861 100644 +--- a/arch/s390/include/asm/module.h ++++ b/arch/s390/include/asm/module.h +@@ -1,5 +1,8 @@ + #ifndef _ASM_S390_MODULE_H + #define _ASM_S390_MODULE_H ++ ++#include ++ + /* + * This file contains the s390 architecture specific module code. + */ +@@ -28,19 +31,4 @@ struct mod_arch_specific + struct mod_arch_syminfo *syminfo; + }; + +-#ifdef CONFIG_64BIT +-#define ElfW(x) Elf64_ ## x +-#define ELFW(x) ELF64_ ## x +-#else +-#define ElfW(x) Elf32_ ## x +-#define ELFW(x) ELF32_ ## x +-#endif +- +-#define Elf_Addr ElfW(Addr) +-#define Elf_Rela ElfW(Rela) +-#define Elf_Shdr ElfW(Shdr) +-#define Elf_Sym ElfW(Sym) +-#define Elf_Ehdr ElfW(Ehdr) +-#define ELF_R_SYM ELFW(R_SYM) +-#define ELF_R_TYPE ELFW(R_TYPE) + #endif /* _ASM_S390_MODULE_H */ +diff --git a/arch/score/Kconfig b/arch/score/Kconfig +index ba0f412..e2c8db4 100644 +--- a/arch/score/Kconfig ++++ b/arch/score/Kconfig +@@ -10,6 +10,8 @@ config SCORE + select ARCH_DISCARD_MEMBLOCK + select GENERIC_CPU_DEVICES + select GENERIC_CLOCKEVENTS ++ select HAVE_MOD_ARCH_SPECIFIC ++ select MODULES_USE_ELF_REL + + choice + prompt "System type" +diff --git a/arch/score/include/asm/module.h b/arch/score/include/asm/module.h +index f0b5dc0..abf395b 100644 +--- a/arch/score/include/asm/module.h ++++ b/arch/score/include/asm/module.h +@@ -3,6 +3,7 @@ + + #include + #include ++#include + + struct mod_arch_specific { + /* Data Bus Error exception tables */ +@@ -13,11 +14,6 @@ struct mod_arch_specific { + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr +-#define Elf_Addr Elf32_Addr +- + /* Given an address, look for it in the exception tables. */ + #ifdef CONFIG_MODULES + const struct exception_table_entry *search_module_dbetables(unsigned long addr); +diff --git a/arch/score/kernel/module.c b/arch/score/kernel/module.c +index 469e3b6..1378d99 100644 +--- a/arch/score/kernel/module.c ++++ b/arch/score/kernel/module.c +@@ -125,16 +125,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, + return 0; + } + +-int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, +- unsigned int symindex, unsigned int relsec, +- struct module *me) +-{ +- /* Non-standard return value... most other arch's return -ENOEXEC +- * for an unsupported relocation variant +- */ +- return 0; +-} +- + /* Given an address, look for it in the module exception tables. */ + const struct exception_table_entry *search_module_dbetables(unsigned long addr) + { +diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig +index a24595d..365ecf5 100644 +--- a/arch/sh/Kconfig ++++ b/arch/sh/Kconfig +@@ -34,6 +34,8 @@ config SUPERH + select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER ++ select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER ++ select MODULES_USE_ELF_RELA + help + The SuperH is a RISC processor targeted for use in embedded systems + and consumer electronics; it was also used in the Sega Dreamcast +diff --git a/arch/sh/include/asm/module.h b/arch/sh/include/asm/module.h +index b7927de..81300d8b 100644 +--- a/arch/sh/include/asm/module.h ++++ b/arch/sh/include/asm/module.h +@@ -1,21 +1,13 @@ + #ifndef _ASM_SH_MODULE_H + #define _ASM_SH_MODULE_H + +-struct mod_arch_specific { ++#include ++ + #ifdef CONFIG_DWARF_UNWINDER ++struct mod_arch_specific { + struct list_head fde_list; + struct list_head cie_list; +-#endif + }; +- +-#ifdef CONFIG_64BIT +-#define Elf_Shdr Elf64_Shdr +-#define Elf_Sym Elf64_Sym +-#define Elf_Ehdr Elf64_Ehdr +-#else +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr + #endif + + #ifdef CONFIG_CPU_LITTLE_ENDIAN +diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig +index e74ff13..acf5577 100644 +--- a/arch/sparc/Kconfig ++++ b/arch/sparc/Kconfig +@@ -36,6 +36,7 @@ config SPARC + select GENERIC_CLOCKEVENTS + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER ++ select MODULES_USE_ELF_RELA + + config SPARC32 + def_bool !64BIT +diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild +index 67f83e0..fbe1cb5 100644 +--- a/arch/sparc/include/asm/Kbuild ++++ b/arch/sparc/include/asm/Kbuild +@@ -21,4 +21,5 @@ generic-y += div64.h + generic-y += local64.h + generic-y += irq_regs.h + generic-y += local.h ++generic-y += module.h + generic-y += word-at-a-time.h +diff --git a/arch/sparc/include/asm/module.h b/arch/sparc/include/asm/module.h +deleted file mode 100644 +index ff8e02d..0000000 +--- a/arch/sparc/include/asm/module.h ++++ /dev/null +@@ -1,24 +0,0 @@ +-#ifndef __SPARC_MODULE_H +-#define __SPARC_MODULE_H +-struct mod_arch_specific { }; +- +-/* +- * Use some preprocessor magic to define the correct symbol +- * for sparc32 and sparc64. +- * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64 +- */ +-#define ___ELF(a, b, c) a##b##c +-#define __ELF(a, b, c) ___ELF(a, b, c) +-#define _Elf(t) __ELF(Elf, CONFIG_BITS, t) +-#define _ELF(t) __ELF(ELF, CONFIG_BITS, t) +- +-#define Elf_Shdr _Elf(_Shdr) +-#define Elf_Sym _Elf(_Sym) +-#define Elf_Ehdr _Elf(_Ehdr) +-#define Elf_Rela _Elf(_Rela) +-#define Elf_Addr _Elf(_Addr) +- +-#define ELF_R_SYM _ELF(_R_SYM) +-#define ELF_R_TYPE _ELF(_R_TYPE) +- +-#endif /* __SPARC_MODULE_H */ +diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig +index 932e443..1603f30 100644 +--- a/arch/tile/Kconfig ++++ b/arch/tile/Kconfig +@@ -17,6 +17,7 @@ config TILE + select SYS_HYPERVISOR + select ARCH_HAVE_NMI_SAFE_CMPXCHG + select GENERIC_CLOCKEVENTS ++ select MODULES_USE_ELF_RELA + + # FIXME: investigate whether we need/want these options. + # select HAVE_IOREMAP_PROT +diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig +index 03c9ff8..942b553 100644 +--- a/arch/unicore32/Kconfig ++++ b/arch/unicore32/Kconfig +@@ -14,6 +14,7 @@ config UNICORE32 + select GENERIC_IRQ_SHOW + select ARCH_WANT_FRAME_POINTERS + select GENERIC_IOMAP ++ select MODULES_USE_ELF_REL + help + UniCore-32 is 32-bit Instruction Set Architecture, + including a series of low-power-consumption RISC chip +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index c70684f..c38a60e 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -95,6 +95,8 @@ config X86 + select KTIME_SCALAR if X86_32 + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER ++ select MODULES_USE_ELF_REL if X86_32 ++ select MODULES_USE_ELF_RELA if X86_64 + + config INSTRUCTION_DECODER + def_bool (KPROBES || PERF_EVENTS || UPROBES) +diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig +index 8a3f835..516210a 100644 +--- a/arch/xtensa/Kconfig ++++ b/arch/xtensa/Kconfig +@@ -10,6 +10,7 @@ config XTENSA + select HAVE_GENERIC_HARDIRQS + select GENERIC_IRQ_SHOW + select GENERIC_CPU_DEVICES ++ select MODULES_USE_ELF_RELA + help + Xtensa processors are 32-bit RISC machines designed by Tensilica + primarily for embedded systems. These processors are both +diff --git a/arch/xtensa/include/asm/module.h b/arch/xtensa/include/asm/module.h +index d9b34be..488b40c 100644 +--- a/arch/xtensa/include/asm/module.h ++++ b/arch/xtensa/include/asm/module.h +@@ -13,15 +13,8 @@ + #ifndef _XTENSA_MODULE_H + #define _XTENSA_MODULE_H + +-struct mod_arch_specific +-{ +- /* No special elements, yet. */ +-}; +- + #define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " " + +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr ++#include + + #endif /* _XTENSA_MODULE_H */ +diff --git a/include/asm-generic/module.h b/include/asm-generic/module.h +index ed5b44d..14dc41d 100644 +--- a/include/asm-generic/module.h ++++ b/include/asm-generic/module.h +@@ -5,18 +5,44 @@ + * Many architectures just need a simple module + * loader without arch specific data. + */ ++#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC + struct mod_arch_specific + { + }; ++#endif + + #ifdef CONFIG_64BIT +-#define Elf_Shdr Elf64_Shdr +-#define Elf_Sym Elf64_Sym +-#define Elf_Ehdr Elf64_Ehdr +-#else +-#define Elf_Shdr Elf32_Shdr +-#define Elf_Sym Elf32_Sym +-#define Elf_Ehdr Elf32_Ehdr ++#define Elf_Shdr Elf64_Shdr ++#define Elf_Phdr Elf64_Phdr ++#define Elf_Sym Elf64_Sym ++#define Elf_Dyn Elf64_Dyn ++#define Elf_Ehdr Elf64_Ehdr ++#define Elf_Addr Elf64_Addr ++#ifdef CONFIG_MODULES_USE_ELF_REL ++#define Elf_Rel Elf64_Rel ++#endif ++#ifdef CONFIG_MODULES_USE_ELF_RELA ++#define Elf_Rela Elf64_Rela ++#endif ++#define ELF_R_TYPE(X) ELF64_R_TYPE(X) ++#define ELF_R_SYM(X) ELF64_R_SYM(X) ++ ++#else /* CONFIG_64BIT */ ++ ++#define Elf_Shdr Elf32_Shdr ++#define Elf_Phdr Elf32_Phdr ++#define Elf_Sym Elf32_Sym ++#define Elf_Dyn Elf32_Dyn ++#define Elf_Ehdr Elf32_Ehdr ++#define Elf_Addr Elf32_Addr ++#ifdef CONFIG_MODULES_USE_ELF_REL ++#define Elf_Rel Elf32_Rel ++#endif ++#ifdef CONFIG_MODULES_USE_ELF_RELA ++#define Elf_Rela Elf32_Rela ++#endif ++#define ELF_R_TYPE(X) ELF32_R_TYPE(X) ++#define ELF_R_SYM(X) ELF32_R_SYM(X) + #endif + + #endif /* __ASM_GENERIC_MODULE_H */ +diff --git a/include/linux/moduleloader.h b/include/linux/moduleloader.h +index b2be02e..560ca53 100644 +--- a/include/linux/moduleloader.h ++++ b/include/linux/moduleloader.h +@@ -28,21 +28,49 @@ void *module_alloc(unsigned long size); + /* Free memory returned from module_alloc. */ + void module_free(struct module *mod, void *module_region); + +-/* Apply the given relocation to the (simplified) ELF. Return -error +- or 0. */ ++/* ++ * Apply the given relocation to the (simplified) ELF. Return -error ++ * or 0. ++ */ ++#ifdef CONFIG_MODULES_USE_ELF_REL + int apply_relocate(Elf_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *mod); ++#else ++static inline int apply_relocate(Elf_Shdr *sechdrs, ++ const char *strtab, ++ unsigned int symindex, ++ unsigned int relsec, ++ struct module *me) ++{ ++ printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name); ++ return -ENOEXEC; ++} ++#endif + +-/* Apply the given add relocation to the (simplified) ELF. Return +- -error or 0 */ ++/* ++ * Apply the given add relocation to the (simplified) ELF. Return ++ * -error or 0 ++ */ ++#ifdef CONFIG_MODULES_USE_ELF_RELA + int apply_relocate_add(Elf_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *mod); ++#else ++static inline int apply_relocate_add(Elf_Shdr *sechdrs, ++ const char *strtab, ++ unsigned int symindex, ++ unsigned int relsec, ++ struct module *me) ++{ ++ printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name); ++ return -ENOEXEC; ++} ++#endif + + /* Any final processing of module before access. Return -error or 0. */ + int module_finalize(const Elf_Ehdr *hdr, +diff --git a/kernel/module.c b/kernel/module.c +index 4edbd9c..087aeed 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -1949,26 +1949,6 @@ static int simplify_symbols(struct module *mod, const struct load_info *info) + return ret; + } + +-int __weak apply_relocate(Elf_Shdr *sechdrs, +- const char *strtab, +- unsigned int symindex, +- unsigned int relsec, +- struct module *me) +-{ +- pr_err("module %s: REL relocation unsupported\n", me->name); +- return -ENOEXEC; +-} +- +-int __weak apply_relocate_add(Elf_Shdr *sechdrs, +- const char *strtab, +- unsigned int symindex, +- unsigned int relsec, +- struct module *me) +-{ +- pr_err("module %s: RELA relocation unsupported\n", me->name); +- return -ENOEXEC; +-} +- + static int apply_relocations(struct module *mod, const struct load_info *info) + { + unsigned int i; +-- +1.7.11.2 + + +From 3ad621a6fe31c4b1e73675facc39b2b34eaba3a3 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:13:57 +0100 +Subject: [PATCH 16/27] 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 +--- + 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 + #include + /* + * 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.11.2 + + +From ebd84cbe7656bb091c8101af3d302ea7c14e7ecf Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:00 +0100 +Subject: [PATCH 17/27] MODSIGN: Provide gitignore and make clean rules for + extra files + +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 +--- + .gitignore | 12 ++++++++++++ + Makefile | 1 + + scripts/mod/.gitignore | 1 + + 3 files changed, 14 insertions(+) + +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 + *~ + \#*# ++ ++# ++# GPG leavings from module signing ++# ++genkey ++modsign.pub ++modsign.sec ++random_seed ++trustdb.gpg +diff --git a/Makefile b/Makefile +index 4bb09e1..5afb466 100644 +--- a/Makefile ++++ b/Makefile +@@ -1239,6 +1239,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 + +-- +1.7.11.2 + + +From 5071caadfaf48a29826bb0fb934bf8046878ca00 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:01 +0100 +Subject: [PATCH 18/27] MODSIGN: Provide Documentation and Kconfig options + +Provide documentation and kernel configuration options for module signing. + +The documentation can be found in: + + Documentation/module-signing.txt + +The following configuration options are added: + + (1) CONFIG_MODULE_SIG + + Enable module signing. This will both cause the build process to sign + modules and the kernel to check modules when they're loaded. + + (2) CONFIG_MODULE_SIG_SHA1 + CONFIG_MODULE_SIG_SHA224 + CONFIG_MODULE_SIG_SHA256 + CONFIG_MODULE_SIG_SHA384 + CONFIG_MODULE_SIG_SHA512 + + 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. + + (3) CONFIG_MODULE_SIG_FORCE + + Require that any module loaded must be signed with a key compiled into + the kernel. All other modules are rejected with EKEYREJECTED. + +Signed-off-by: David Howells +--- + Documentation/module-signing.txt | 194 +++++++++++++++++++++++++++++++++++++++ + include/linux/modsign.h | 27 ++++++ + init/Kconfig | 54 +++++++++++ + 3 files changed, 275 insertions(+) + create mode 100644 Documentation/module-signing.txt + create mode 100644 include/linux/modsign.h + +diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt +new file mode 100644 +index 0000000..d75d473 +--- /dev/null ++++ b/Documentation/module-signing.txt +@@ -0,0 +1,194 @@ ++ ============================== ++ KERNEL MODULE SIGNING FACILITY ++ ============================== ++ ++The module signing facility applies cryptographic signature checking to modules ++on module load, checking the signature against a ring of public keys compiled ++into the kernel. GPG is used to do the cryptographic work and determines the ++format of the signature and key data. The facility uses GPG's MPI library to ++handle the huge numbers involved. ++ ++This facility is enabled through CONFIG_MODULE_SIG. Turning on signature ++checking will also force the module's ELF metadata to be verified before the ++signature is checked. ++ ++The signature checker in the kernel is capable of handling multiple keys of ++either DSA or RSA type, and can support any of MD5, RIPE-MD-160, SHA-1, ++SHA-224, SHA-256, SHA-384 and SHA-512 hashes - PROVIDED(!) the requisite ++algorithms are compiled into the kernel. ++ ++(!) NOTE: Modules may only be verified initially with algorithms compiled into ++the kernel. Further algorithm modules may be loaded and used - but these must ++first pass a verification step using already loaded/compiled-in algorithms. ++ ++ ++===================== ++SUPPLYING PUBLIC KEYS ++===================== ++ ++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 modsign.pub. ++ ++For example, a throwaway key could be generated automatically by something like ++the following: ++ ++ cat >genkey < ++ ++ This indicates the whereabouts of the GPG keyring that is the source of ++ the public key to be used. The default is "./modsign.pub". ++ ++ (*) MODKEYNAME= ++ ++ 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 ++ --digest-algo= ++ ++ 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 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 ++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. ++ ++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 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. ++ ++ ++========================================= ++NON-VALID SIGNATURES AND UNSIGNED MODULES ++========================================= ++ ++If CONFIG_MODULE_SIG_FORCE is enabled or "enforcemodulesig=1" is supplied on ++the kernel command line, the kernel will _only_ load validly signed modules ++for which it has a public key. Otherwise, it will also load modules that are ++unsigned. Any module for which the kernel has a key, but which proves to have ++a signature mismatch will not be permitted to load (returning EKEYREJECTED). ++ ++This table indicates the behaviours of the various situations: ++ ++ MODULE STATE PERMISSIVE MODE ENFORCING MODE ++ ======================================= =============== =============== ++ Unsigned Ok EKEYREJECTED ++ Signed, no public key ENOKEY ENOKEY ++ Validly signed, public key Ok Ok ++ Invalidly signed, public key EKEYREJECTED EKEYREJECTED ++ Validly signed, expired key EKEYEXPIRED EKEYEXPIRED ++ Signed, hash algorithm unavailable ENOPKG ENOPKG ++ Corrupt signature EBADMSG EBADMSG ++ Corrupt ELF ELIBBAD ELIBBAD +diff --git a/include/linux/modsign.h b/include/linux/modsign.h +new file mode 100644 +index 0000000..c5ac87a +--- /dev/null ++++ b/include/linux/modsign.h +@@ -0,0 +1,27 @@ ++/* Module signing definitions ++ * ++ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. ++ * Written by David Howells (dhowells@redhat.com) ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public Licence ++ * as published by the Free Software Foundation; either version ++ * 2 of the Licence, or (at your option) any later version. ++ */ ++ ++#ifndef _LINUX_MODSIGN_H ++#define _LINUX_MODSIGN_H ++ ++#ifdef CONFIG_MODULE_SIG ++ ++#include ++ ++/* ++ * The parameters of the ELF note used to carry the signature ++ */ ++#define MODSIGN_NOTE_NAME module.sig ++#define MODSIGN_NOTE_TYPE 100 ++ ++#endif ++ ++#endif /* _LINUX_MODSIGN_H */ +diff --git a/init/Kconfig b/init/Kconfig +index d07dcf9..1d1a056 100644 +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1570,6 +1570,60 @@ config MODULE_SRCVERSION_ALL + the version). With this option, such a "srcversion" field + will be created for all modules. If unsure, say N. + ++config MODULE_SIG ++ bool "Module signature verification" ++ depends on MODULES ++ select KEYS ++ select CRYPTO_KEY_TYPE ++ select CRYPTO_KEY_PKEY_ALGO_DSA ++ select CRYPTO_KEY_PKEY_ALGO_RSA ++ select PGP_PARSER ++ select PGP_PRELOAD ++ help ++ Check modules for valid signatures upon load. For more information ++ see: ++ ++ Documentation/module-signing.txt ++ ++choice ++ prompt "Which hash algorithm should modules be signed with?" ++ depends on MODULE_SIG ++ help ++ This determines which sort of hashing algorithm will be used during ++ signature generation. This algorithm _must_ be built into the kernel ++ directly so that signature verification can take place. It is not ++ possible to load a signed module containing the algorithm to check ++ the signature on that module. ++ ++config MODULE_SIG_SHA1 ++ bool "Sign modules with SHA-1" ++ select CRYPTO_SHA1 ++ ++config MODULE_SIG_SHA224 ++ bool "Sign modules with SHA-224" ++ select CRYPTO_SHA224 ++ ++config MODULE_SIG_SHA256 ++ bool "Sign modules with SHA-256" ++ select CRYPTO_SHA256 ++ ++config MODULE_SIG_SHA384 ++ bool "Sign modules with SHA-384" ++ select CRYPTO_SHA384 ++ ++config MODULE_SIG_SHA512 ++ bool "Sign modules with SHA-512" ++ select CRYPTO_SHA512 ++ ++endchoice ++ ++config MODULE_SIG_FORCE ++ bool "Required modules to be validly signed (EXPERIMENTAL)" ++ depends on MODULE_SIG ++ help ++ Reject unsigned modules or signed modules for which we don't have a ++ key. ++ + endif # MODULES + + config INIT_ALL_POSSIBLE +-- +1.7.11.2 + + +From 506ebdd9cc53b7e1fe5c1a1351bf1e42cce4c856 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:01 +0100 +Subject: [PATCH 19/27] 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 +--- + 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..17465d8 100644 +--- a/scripts/Makefile.modpost ++++ b/scripts/Makefile.modpost +@@ -14,7 +14,8 @@ + # 3) create one .mod.c file pr. module + # 4) create one Module.symvers file with CRC for all exported symbols + # 5) compile all .mod.c files +-# 6) final link of the module to a file ++# 6) final link of the module to a (or ) file ++# 7) signs the modules to a file + + # Step 3 is used to place certain information in the module's ELF + # section, including information such as: +@@ -32,6 +33,8 @@ + # Step 4 is solely used to allow module versioning in external modules, + # where the CRC of each module is retrieved from the Module.symvers file. + ++# Step 7 is dependent on CONFIG_MODULE_SIG being enabled. ++ + # KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined + # symbols in the final module linking stage + # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. +@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE + targets += $(modules:.ko=.mod.o) + + # Step 6), final link of the modules ++ifneq ($(CONFIG_MODULE_SIG),y) + quiet_cmd_ld_ko_o = LD [M] $@ + cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ +@@ -125,7 +129,88 @@ $(modules): %.ko :%.o %.mod.o FORCE + $(call if_changed,ld_ko_o) + + targets += $(modules) ++else ++quiet_cmd_ld_ko_unsigned_o = LD [M] $@ ++ cmd_ld_ko_unsigned_o = \ ++ $(LD) -r $(LDFLAGS) \ ++ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ ++ -o $@ $(filter-out FORCE,$^) \ ++ $(if $(AFTER_LINK),; $(AFTER_LINK)) ++ ++$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE ++ $(call if_changed,ld_ko_unsigned_o) ++ ++targets += $(modules:.ko=.ko.unsigned) ++ ++# Step 7), sign the modules ++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 ++KEYFLAGS += --digest-algo=SHA1 ++else ++ifdef CONFIG_MODULE_SIG_SHA224 ++KEYFLAGS += --digest-algo=SHA224 ++else ++ifdef CONFIG_MODULE_SIG_SHA256 ++KEYFLAGS += --digest-algo=SHA256 ++else ++ifdef CONFIG_MODULE_SIG_SHA384 ++KEYFLAGS += --digest-algo=SHA384 ++else ++ifdef CONFIG_MODULE_SIG_SHA512 ++KEYFLAGS += --digest-algo=SHA512 ++else ++endif ++endif ++endif ++endif ++endif ++ ++ifdef MODKEYNAME ++KEYFLAGS += --default-key $(MODKEYNAME) ++endif + ++ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY)) ++ifeq ($(KBUILD_SRC),) ++ # no O= is being used ++ SCRIPTS_DIR := scripts ++else ++ SCRIPTS_DIR := $(KBUILD_SRC)/scripts ++endif ++SIGN_MODULES := 1 ++else ++SIGN_MODULES := 0 ++endif ++ ++# only sign if it's an in-tree module ++ifneq ($(KBUILD_EXTMOD),) ++SIGN_MODULES := 0 ++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 && \ ++ rm -f $@.digest.sig && \ ++ gpg --batch --no-greeting $(KEYFLAGS) -b $@.digest && \ ++ sh $(SCRIPTS_DIR)/mod/modsign-note.sh $@.digest.sig | \ ++ $(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 $(KEYRING_DEP) FORCE ++ $(call if_changed,sign_ko_ko_unsigned) ++ ++targets += $(modules) ++endif + + # Add FORCE to the prequisites of a target to force it to be always rebuilt. + # --------------------------------------------------------------------------- +diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile +index ff954f8..4654e3b 100644 +--- a/scripts/mod/Makefile ++++ b/scripts/mod/Makefile +@@ -1,4 +1,4 @@ +-hostprogs-y := modpost mk_elfconfig ++hostprogs-y := modpost mk_elfconfig mod-extract + always := $(hostprogs-y) empty.o + + modpost-objs := modpost.o file2alias.o sumversion.o +diff --git a/scripts/mod/mod-extract.c b/scripts/mod/mod-extract.c +new file mode 100644 +index 0000000..0c0e3e3 +--- /dev/null ++++ b/scripts/mod/mod-extract.c +@@ -0,0 +1,913 @@ ++/* mod-extract.c: module extractor for signing ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void extract_elf64(void *buffer, size_t size, Elf64_Ehdr *hdr); ++static void extract_elf32(void *buffer, size_t size, Elf32_Ehdr *hdr); ++ ++struct byteorder { ++ uint16_t (*get16)(const uint16_t *); ++ uint32_t (*get32)(const uint32_t *); ++ uint64_t (*get64)(const uint64_t *); ++ void (*set16)(uint16_t *, uint16_t); ++ void (*set32)(uint32_t *, uint32_t); ++ void (*set64)(uint64_t *, uint64_t); ++}; ++ ++static uint16_t get16_le(const uint16_t *p) { return __le16_to_cpu(*p); } ++static uint32_t get32_le(const uint32_t *p) { return __le32_to_cpu(*p); } ++static uint64_t get64_le(const uint64_t *p) { return __le64_to_cpu(*p); } ++static uint16_t get16_be(const uint16_t *p) { return __be16_to_cpu(*p); } ++static uint32_t get32_be(const uint32_t *p) { return __be32_to_cpu(*p); } ++static uint64_t get64_be(const uint64_t *p) { return __be64_to_cpu(*p); } ++ ++static void set16_le(uint16_t *p, uint16_t n) { *p = __cpu_to_le16(n); } ++static void set32_le(uint32_t *p, uint32_t n) { *p = __cpu_to_le32(n); } ++static void set64_le(uint64_t *p, uint64_t n) { *p = __cpu_to_le64(n); } ++static void set16_be(uint16_t *p, uint16_t n) { *p = __cpu_to_be16(n); } ++static void set32_be(uint32_t *p, uint32_t n) { *p = __cpu_to_be32(n); } ++static void set64_be(uint64_t *p, uint64_t n) { *p = __cpu_to_be64(n); } ++ ++static const struct byteorder byteorder_le = { ++ get16_le, get32_le, get64_le, ++ set16_le, set32_le, set64_le ++}; ++static const struct byteorder byteorder_be = { ++ get16_be, get32_be, get64_be, ++ set16_be, set32_be, set64_be ++}; ++static const struct byteorder *order; ++ ++static inline uint16_t get16(const uint16_t *p) { return order->get16(p); } ++static inline uint32_t get32(const uint32_t *p) { return order->get32(p); } ++static inline uint64_t get64(const uint64_t *p) { return order->get64(p); } ++static inline void set16(uint16_t *p, uint16_t n) { order->set16(p, n); } ++static inline void set32(uint32_t *p, uint32_t n) { order->set32(p, n); } ++static inline void set64(uint64_t *p, uint64_t n) { order->set64(p, n); } ++ ++static FILE *outfd; ++static uint8_t csum, xcsum; ++ ++static void write_out(const void *data, size_t size) ++{ ++ const uint8_t *p = data; ++ size_t loop; ++ ++ for (loop = 0; loop < size; loop++) { ++ csum += p[loop]; ++ xcsum += p[loop]; ++ } ++ ++ if (fwrite(data, 1, size, outfd) != size) { ++ perror("write"); ++ exit(1); ++ } ++} ++ ++#define write_out_val(VAL) write_out(&(VAL), sizeof(VAL)) ++ ++static int is_verbose; ++ ++static __attribute__((format(printf, 1, 2))) ++void verbose(const char *fmt, ...) ++{ ++ va_list va; ++ ++ if (is_verbose) { ++ va_start(va, fmt); ++ vprintf(fmt, va); ++ va_end(va); ++ } ++} ++ ++static __attribute__((noreturn)) ++void usage(void) ++{ ++ fprintf(stderr, "Usage: mod-extract [-v] \n"); ++ exit(2); ++} ++ ++/* ++ * ++ */ ++int main(int argc, char **argv) ++{ ++ struct stat st; ++ Elf32_Ehdr *hdr32; ++ Elf64_Ehdr *hdr64; ++ size_t len; ++ void *buffer; ++ int fd, be, b64; ++ ++ while (argc > 1 && strcmp("-v", argv[1]) == 0) { ++ argv++; ++ argc--; ++ is_verbose++; ++ } ++ ++ if (argc != 3) ++ usage(); ++ ++ /* map the module into memory */ ++ fd = open(argv[1], O_RDONLY); ++ if (fd < 0) { ++ perror("open input"); ++ exit(1); ++ } ++ ++ if (fstat(fd, &st) < 0) { ++ perror("fstat"); ++ exit(1); ++ } ++ ++ len = st.st_size; ++ ++ buffer = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); ++ if (buffer == MAP_FAILED) { ++ perror("mmap"); ++ exit(1); ++ } ++ ++ if (close(fd) < 0) { ++ perror("close input"); ++ exit(1); ++ } ++ ++ /* check it's an ELF object */ ++ hdr32 = buffer; ++ hdr64 = buffer; ++ ++ if (hdr32->e_ident[EI_MAG0] != ELFMAG0 || ++ hdr32->e_ident[EI_MAG1] != ELFMAG1 || ++ hdr32->e_ident[EI_MAG2] != ELFMAG2 || ++ hdr32->e_ident[EI_MAG3] != ELFMAG3 ++ ) { ++ fprintf(stderr, "Module does not appear to be ELF\n"); ++ exit(3); ++ } ++ ++ /* determine endianness and word size */ ++ b64 = (hdr32->e_ident[EI_CLASS] == ELFCLASS64); ++ be = (hdr32->e_ident[EI_DATA] == ELFDATA2MSB); ++ order = be ? &byteorder_be : &byteorder_le; ++ ++ verbose("Module is %s-bit %s-endian\n", ++ b64 ? "64" : "32", ++ be ? "big" : "little"); ++ ++ /* open the output file */ ++ outfd = fopen(argv[2], "w"); ++ if (!outfd) { ++ perror("open output"); ++ exit(1); ++ } ++ ++ /* perform the extraction */ ++ if (b64) ++ extract_elf64(buffer, len, hdr64); ++ else ++ extract_elf32(buffer, len, hdr32); ++ ++ /* done */ ++ if (fclose(outfd) == EOF) { ++ perror("close output"); ++ exit(1); ++ } ++ ++ return 0; ++} ++ ++/* ++ * extract a RELA table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf64_rela(const void *buffer, int secix, int targetix, ++ const Elf64_Rela *relatab, size_t nrels, ++ const Elf64_Sym *symbols, size_t nsyms, ++ const Elf64_Shdr *sections, size_t nsects, int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ 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; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf64_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf64_Section st_shndx; ++ Elf64_Xword r_info; ++ ++ /* decode the relocation */ ++ r_info = get64(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ relocation.r_addend = relatab[loop].r_addend; ++ set32(&relocation.r_type, ELF64_R_TYPE(r_info)); ++ ++ if (ELF64_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n", ++ (size_t)ELF64_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF64_R_SYM(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 = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract a REL table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf64_rel(const void *buffer, int secix, int targetix, ++ const Elf64_Rel *relatab, size_t nrels, ++ const Elf64_Sym *symbols, size_t nsyms, ++ const Elf64_Shdr *sections, size_t nsects, int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ 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; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf64_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf64_Section st_shndx; ++ Elf64_Xword r_info; ++ ++ /* decode the relocation */ ++ r_info = get64(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ set32(&relocation.r_type, ELF64_R_TYPE(r_info)); ++ ++ if (ELF64_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n", ++ (size_t)ELF64_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF64_R_SYM(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 = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract the data from a 64-bit module ++ */ ++static void extract_elf64(void *buffer, size_t len, Elf64_Ehdr *hdr) ++{ ++ const Elf64_Sym *symbols; ++ Elf64_Shdr *sections; ++ const char *secstrings, *strings; ++ size_t nsyms, nstrings; ++ int loop, shnum, *canonlist, *canonmap, canon, changed, tmp; ++ ++ sections = buffer + get64(&hdr->e_shoff); ++ secstrings = buffer + get64(§ions[get16(&hdr->e_shstrndx)].sh_offset); ++ shnum = get16(&hdr->e_shnum); ++ ++ /* find the symbol table and the string table and produce a list of ++ * index numbers of sections that contribute to the kernel's module ++ * image ++ */ ++ canonlist = calloc(sizeof(int), shnum * 2); ++ if (!canonlist) { ++ perror("calloc"); ++ exit(1); ++ } ++ canonmap = canonlist + shnum; ++ canon = 0; ++ ++ symbols = NULL; ++ strings = NULL; ++ nstrings = 0; ++ nsyms = 0; ++ ++ for (loop = 1; loop < shnum; loop++) { ++ const char *sh_name = secstrings + get32(§ions[loop].sh_name); ++ Elf64_Word sh_type = get32(§ions[loop].sh_type); ++ Elf64_Xword sh_size = get64(§ions[loop].sh_size); ++ Elf64_Xword sh_flags = get64(§ions[loop].sh_flags); ++ Elf64_Word sh_info = get32(§ions[loop].sh_info); ++ Elf64_Off sh_offset = get64(§ions[loop].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ /* quick sanity check */ ++ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { ++ fprintf(stderr, "Section goes beyond EOF\n"); ++ exit(3); ++ } ++ ++ /* we only need to canonicalise allocatable sections */ ++ if (sh_flags & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ else if ((sh_type == SHT_REL || sh_type == SHT_RELA) && ++ get64(§ions[sh_info].sh_flags) & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ ++ /* keep track of certain special sections */ ++ switch (sh_type) { ++ case SHT_SYMTAB: ++ if (strcmp(sh_name, ".symtab") == 0) { ++ symbols = data; ++ nsyms = sh_size / sizeof(Elf64_Sym); ++ } ++ break; ++ ++ case SHT_STRTAB: ++ if (strcmp(sh_name, ".strtab") == 0) { ++ strings = data; ++ nstrings = sh_size; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (!symbols) { ++ fprintf(stderr, "Couldn't locate symbol table\n"); ++ exit(3); ++ } ++ ++ if (!strings) { ++ fprintf(stderr, "Couldn't locate strings table\n"); ++ exit(3); ++ } ++ ++ /* canonicalise the index numbers of the contributing section */ ++ do { ++ changed = 0; ++ ++ for (loop = 0; loop < canon - 1; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name); ++ const char *y = secstrings + get32(§ions[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 = 1; ++ } ++ } ++ ++ } while (changed); ++ ++ for (loop = 0; loop < canon; loop++) ++ canonmap[canonlist[loop]] = loop + 1; ++ ++ if (is_verbose > 1) { ++ printf("\nSection canonicalisation map:\n"); ++ for (loop = 1; loop < shnum; loop++) { ++ const char *x = secstrings + get32(§ions[loop].sh_name); ++ printf("%4d %s\n", canonmap[loop], x); ++ } ++ ++ printf("\nAllocated section list in canonical order:\n"); ++ for (loop = 0; loop < canon; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name); ++ printf("%4d %s\n", canonlist[loop], x); ++ } ++ } ++ ++ /* iterate through the section table looking for sections we want to ++ * contribute to the signature */ ++ verbose("\n"); ++ verbose("CAN FILE POS CS SECT NAME\n"); ++ verbose("=== ======== == ==== ==============================\n"); ++ ++ for (loop = 0; loop < canon; loop++) { ++ int sect = canonlist[loop]; ++ const char *sh_name = secstrings + get32(§ions[sect].sh_name); ++ Elf64_Word sh_type = get32(§ions[sect].sh_type); ++ Elf64_Xword sh_size = get64(§ions[sect].sh_size); ++ Elf64_Xword sh_flags = get64(§ions[sect].sh_flags); ++ Elf64_Word sh_info = get32(§ions[sect].sh_info); ++ Elf64_Off sh_offset = get64(§ions[sect].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ csum = 0; ++ ++ /* include canonicalised relocation sections */ ++ if (sh_type == SHT_REL || sh_type == SHT_RELA) { ++ Elf32_Word canon_sh_info; ++ ++ if (sh_info <= 0 && sh_info >= hdr->e_shnum) { ++ fprintf(stderr, ++ "Invalid ELF - REL/RELA sh_info does" ++ " not refer to a valid section\n"); ++ exit(3); ++ } ++ ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ set32(&canon_sh_info, canonmap[sh_info]); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ write_out_val(canon_sh_info); ++ ++ if (sh_type == SHT_RELA) ++ extract_elf64_rela(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf64_Rela), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ else ++ extract_elf64_rel(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf64_Rel), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ continue; ++ } ++ ++ /* include the headers of BSS sections */ ++ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ /* include allocatable loadable sections */ ++ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) ++ goto include_section; ++ ++ /* not this section */ ++ continue; ++ ++ include_section: ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ /* write out the section data */ ++ write_out(data, sh_size); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ verbose("%08lx (%lu bytes csum 0x%02x)\n", ++ ftell(outfd), ftell(outfd), xcsum); ++} ++ ++/* ++ * extract a RELA table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf32_rela(const void *buffer, int secix, int targetix, ++ const Elf32_Rela *relatab, size_t nrels, ++ const Elf32_Sym *symbols, size_t nsyms, ++ const Elf32_Shdr *sections, size_t nsects, ++ int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ 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; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf32_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf32_Section st_shndx; ++ Elf32_Word r_info; ++ ++ /* decode the relocation */ ++ r_info = get32(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ relocation.r_addend = relatab[loop].r_addend; ++ relocation.r_type = ELF32_R_TYPE(r_info); ++ ++ if (ELF32_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n", ++ ELF32_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF32_R_SYM(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 = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract a REL table ++ * - need to canonicalise the entries in case section addition/removal has ++ * rearranged the symbol table and the section table ++ */ ++static void extract_elf32_rel(const void *buffer, int secix, int targetix, ++ const Elf32_Rel *relatab, size_t nrels, ++ const Elf32_Sym *symbols, size_t nsyms, ++ const Elf32_Shdr *sections, size_t nsects, ++ int *canonmap, ++ const char *strings, size_t nstrings, ++ const char *sh_name) ++{ ++ struct { ++ 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; ++ ++ } __attribute__((packed)) relocation; ++ ++ const Elf32_Sym *symbol; ++ size_t loop; ++ ++ /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */ ++ for (loop = 0; loop < nrels; loop++) { ++ Elf32_Section st_shndx; ++ Elf32_Word r_info; ++ ++ /* decode the relocation */ ++ r_info = get32(&relatab[loop].r_info); ++ relocation.r_offset = relatab[loop].r_offset; ++ relocation.r_type = ELF32_R_TYPE(r_info); ++ ++ if (ELF32_R_SYM(r_info) >= nsyms) { ++ fprintf(stderr, "Invalid symbol ID %x in relocation %zu\n", ++ ELF32_R_SYM(r_info), loop); ++ exit(1); ++ } ++ ++ /* decode the symbol referenced by the relocation */ ++ symbol = &symbols[ELF32_R_SYM(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 = get16(&symbol->st_shndx); ++ ++ /* canonicalise the section used by the symbol */ ++ if (st_shndx > SHN_UNDEF && st_shndx < nsects) ++ set16(&relocation.st_shndx, canonmap[st_shndx]); ++ ++ write_out_val(relocation); ++ ++ /* undefined symbols must be named if referenced */ ++ if (st_shndx == SHN_UNDEF) { ++ const char *name = strings + get32(&symbol->st_name); ++ write_out(name, strlen(name) + 1); ++ } ++ } ++ ++ verbose("%02x %4d %s [canon]\n", csum, secix, sh_name); ++} ++ ++/* ++ * extract the data from a 32-bit module ++ */ ++static void extract_elf32(void *buffer, size_t len, Elf32_Ehdr *hdr) ++{ ++ const Elf32_Sym *symbols; ++ Elf32_Shdr *sections; ++ const char *secstrings, *strings; ++ size_t nsyms, nstrings; ++ int loop, shnum, *canonlist, *canonmap, canon, changed, tmp; ++ ++ sections = buffer + get32(&hdr->e_shoff); ++ secstrings = buffer + get32(§ions[get16(&hdr->e_shstrndx)].sh_offset); ++ shnum = get16(&hdr->e_shnum); ++ ++ /* find the symbol table and the string table and produce a list of ++ * index numbers of sections that contribute to the kernel's module ++ * image ++ */ ++ canonlist = calloc(sizeof(int), shnum * 2); ++ if (!canonlist) { ++ perror("calloc"); ++ exit(1); ++ } ++ canonmap = canonlist + shnum; ++ canon = 0; ++ ++ symbols = NULL; ++ strings = NULL; ++ nstrings = 0; ++ nsyms = 0; ++ ++ for (loop = 1; loop < shnum; loop++) { ++ const char *sh_name = secstrings + get32(§ions[loop].sh_name); ++ Elf32_Word sh_type = get32(§ions[loop].sh_type); ++ Elf32_Xword sh_size = get32(§ions[loop].sh_size); ++ Elf32_Xword sh_flags = get32(§ions[loop].sh_flags); ++ Elf64_Word sh_info = get32(§ions[loop].sh_info); ++ Elf32_Off sh_offset = get32(§ions[loop].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ /* quick sanity check */ ++ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { ++ fprintf(stderr, "Section goes beyond EOF\n"); ++ exit(3); ++ } ++ ++ /* we only need to canonicalise allocatable sections */ ++ if (sh_flags & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ else if ((sh_type == SHT_REL || sh_type == SHT_RELA) && ++ get32(§ions[sh_info].sh_flags) & SHF_ALLOC) ++ canonlist[canon++] = loop; ++ ++ /* keep track of certain special sections */ ++ switch (sh_type) { ++ case SHT_SYMTAB: ++ if (strcmp(sh_name, ".symtab") == 0) { ++ symbols = data; ++ nsyms = sh_size / sizeof(Elf32_Sym); ++ } ++ break; ++ ++ case SHT_STRTAB: ++ if (strcmp(sh_name, ".strtab") == 0) { ++ strings = data; ++ nstrings = sh_size; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ if (!symbols) { ++ fprintf(stderr, "Couldn't locate symbol table\n"); ++ exit(3); ++ } ++ ++ if (!strings) { ++ fprintf(stderr, "Couldn't locate strings table\n"); ++ exit(3); ++ } ++ ++ /* canonicalise the index numbers of the contributing section */ ++ do { ++ changed = 0; ++ ++ for (loop = 0; loop < canon - 1; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop + 0]].sh_name); ++ const char *y = secstrings + get32(§ions[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 = 1; ++ } ++ } ++ ++ } while (changed); ++ ++ for (loop = 0; loop < canon; loop++) ++ canonmap[canonlist[loop]] = loop + 1; ++ ++ if (is_verbose > 1) { ++ printf("\nSection canonicalisation map:\n"); ++ for (loop = 1; loop < shnum; loop++) { ++ const char *x = secstrings + get32(§ions[loop].sh_name); ++ printf("%4d %s\n", canonmap[loop], x); ++ } ++ ++ printf("\nAllocated section list in canonical order:\n"); ++ for (loop = 0; loop < canon; loop++) { ++ const char *x = secstrings + get32(§ions[canonlist[loop]].sh_name); ++ printf("%4d %s\n", canonlist[loop], x); ++ } ++ } ++ ++ /* iterate through the section table looking for sections we want to ++ * contribute to the signature */ ++ verbose("\n"); ++ verbose("CAN FILE POS CS SECT NAME\n"); ++ verbose("=== ======== == ==== ==============================\n"); ++ ++ for (loop = 0; loop < canon; loop++) { ++ int sect = canonlist[loop]; ++ const char *sh_name = secstrings + get32(§ions[sect].sh_name); ++ Elf32_Word sh_type = get32(§ions[sect].sh_type); ++ Elf32_Xword sh_size = get32(§ions[sect].sh_size); ++ Elf32_Xword sh_flags = get32(§ions[sect].sh_flags); ++ Elf32_Word sh_info = get32(§ions[sect].sh_info); ++ Elf32_Off sh_offset = get32(§ions[sect].sh_offset); ++ void *data = buffer + sh_offset; ++ ++ csum = 0; ++ ++ /* quick sanity check */ ++ if (sh_type != SHT_NOBITS && len < sh_offset + sh_size) { ++ fprintf(stderr, "section goes beyond EOF\n"); ++ exit(3); ++ } ++ ++ /* include canonicalised relocation sections */ ++ if (sh_type == SHT_REL || sh_type == SHT_RELA) { ++ Elf32_Word canon_sh_info; ++ ++ if (sh_info <= 0 && sh_info >= hdr->e_shnum) { ++ fprintf(stderr, ++ "Invalid ELF - REL/RELA sh_info does" ++ " not refer to a valid section\n"); ++ exit(3); ++ } ++ ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ set32(&canon_sh_info, canonmap[sh_info]); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ write_out_val(canon_sh_info); ++ ++ if (sh_type == SHT_RELA) ++ extract_elf32_rela(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf32_Rela), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ else ++ extract_elf32_rel(buffer, sect, sh_info, ++ data, sh_size / sizeof(Elf32_Rel), ++ symbols, nsyms, ++ sections, shnum, canonmap, ++ strings, nstrings, ++ sh_name); ++ continue; ++ } ++ ++ /* include the headers of BSS sections */ ++ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) { ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ /* include allocatable loadable sections */ ++ if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC) ++ goto include_section; ++ ++ /* not this section */ ++ continue; ++ ++ include_section: ++ verbose("%3u %08lx ", loop, ftell(outfd)); ++ ++ /* write out selected portions of the section header */ ++ write_out(sh_name, strlen(sh_name)); ++ write_out_val(sections[sect].sh_type); ++ write_out_val(sections[sect].sh_flags); ++ write_out_val(sections[sect].sh_size); ++ write_out_val(sections[sect].sh_addralign); ++ ++ /* write out the section data */ ++ write_out(data, sh_size); ++ ++ verbose("%02x %4d %s\n", csum, sect, sh_name); ++ } ++ ++ verbose("%08lx (%lu bytes csum 0x%02x)\n", ++ ftell(outfd), ftell(outfd), xcsum); ++} +diff --git a/scripts/mod/modsign-note.sh b/scripts/mod/modsign-note.sh +new file mode 100644 +index 0000000..bca67c0 +--- /dev/null ++++ b/scripts/mod/modsign-note.sh +@@ -0,0 +1,16 @@ ++#!/bin/sh ++# ++# Generate a module signature note source file ++# ++# mod-sign.sh > ++# ++ ++SIG=$1 ++ ++cat < ++ ++ELFNOTE(MODSIGN_NOTE_NAME, MODSIGN_NOTE_TYPE, .incbin "$SIG") ++EOF ++ ++exit 0 +-- +1.7.11.2 + + +From c075a55ef7dd94b37406e09c542f69994e73424c Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:01 +0100 +Subject: [PATCH 20/27] 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. + +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. + +This table indicates the behaviours in the various situations: + + MODULE STATE PERMISSIVE MODE ENFORCING MODE + ======================================= =============== =============== + Unsigned Ok EKEYREJECTED + Signed, no public key ENOKEY ENOKEY + Validly signed, public key Ok Ok + Invalidly signed, public key EKEYREJECTED EKEYREJECTED + Validly signed, expired key EKEYEXPIRED EKEYEXPIRED + Signed, hash algorithm unavailable ENOPKG ENOPKG + Corrupt signature EBADMSG EBADMSG + Corrupt ELF ELIBBAD ELIBBAD + +Signed-off-by: David Howells +--- + include/linux/module.h | 3 ++ + kernel/Makefile | 1 + + kernel/module-verify-defs.h | 77 +++++++++++++++++++++++++++++++ + kernel/module-verify.c | 110 ++++++++++++++++++++++++++++++++++++++++++++ + kernel/module-verify.h | 20 ++++++++ + kernel/module.c | 26 +++++++++-- + 6 files changed, 232 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/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]; + ++ /* 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 c0cc67a..cec222a 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -55,6 +55,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..141ddab +--- /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..4bf857e +--- /dev/null ++++ b/kernel/module-verify.c +@@ -0,0 +1,110 @@ ++/* 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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..c640634 +--- /dev/null ++++ b/kernel/module-verify.h +@@ -0,0 +1,20 @@ ++/* 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 087aeed..a59a9da 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -58,6 +58,7 @@ + #include + #include + #include ++#include "module-verify.h" + + #define CREATE_TRACE_POINTS + #include +@@ -2382,7 +2383,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; +@@ -2415,6 +2417,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; +@@ -2757,7 +2765,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; +@@ -2767,6 +2776,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) +@@ -2850,17 +2860,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; +@@ -3497,8 +3508,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.11.2 + + +From 632507c5c70caad4ac7000d573b60236e405247b Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:02 +0100 +Subject: [PATCH 21/27] 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 +--- + kernel/Makefile | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/kernel/Makefile b/kernel/Makefile +index cec222a..28cd248 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -132,3 +132,52 @@ 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) ++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 "###" >&2 ++ @echo "### Now generating a sample key generation script." >&2 ++ @echo "###" >&2 ++ @echo "### IT IS STRONGLY RECOMMENDED THAT YOU SUPPLY YOUR OWN" >&2 ++ @echo "### SCRIPT WITH APPROPRIATE NAME FIELDS FILLED IN." >&2 ++ @echo "###" >&2 ++ @echo "### If you have a hardware random number generator feeding" >&2 ++ @echo "### into /dev/random, you should drop the %no-protection" >&2 ++ @echo "### and %transient-key lines from the script." >&2 ++ @echo "###" >&2 ++ 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.11.2 + + +From bbbe230903a8c8f1d3aa7d2cc7f850930ff1539f Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:02 +0100 +Subject: [PATCH 22/27] 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 +--- + kernel/Makefile | 25 ++++++++------- + kernel/modsign-pubkey.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ + kernel/module-verify-defs.h | 4 +++ + kernel/module-verify.c | 2 -- + 4 files changed, 93 insertions(+), 13 deletions(-) + create mode 100644 kernel/modsign-pubkey.c + +diff --git a/kernel/Makefile b/kernel/Makefile +index 28cd248..1d20704 100644 +--- a/kernel/Makefile ++++ b/kernel/Makefile +@@ -55,7 +55,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 +@@ -159,16 +160,18 @@ modsign.pub modsign.sec: genkey + rm -f pubring.gpg secring.gpg trustdb.gpg + + genkey: +- @echo "###" >&2 +- @echo "### Now generating a sample key generation script." >&2 +- @echo "###" >&2 +- @echo "### IT IS STRONGLY RECOMMENDED THAT YOU SUPPLY YOUR OWN" >&2 +- @echo "### SCRIPT WITH APPROPRIATE NAME FIELDS FILLED IN." >&2 +- @echo "###" >&2 +- @echo "### If you have a hardware random number generator feeding" >&2 +- @echo "### into /dev/random, you should drop the %no-protection" >&2 +- @echo "### and %transient-key lines from the script." >&2 +- @echo "###" >&2 ++ @echo "kernel/Makefile:163: ###" >&2 ++ @echo "kernel/Makefile:163: ### CONFIG_MODULE_SIG is enabled so a public key is needed." >&2 ++ @echo "kernel/Makefile:163: ###" >&2 ++ @echo "kernel/Makefile:163: ### Now generating a sample key generation script." >&2 ++ @echo "kernel/Makefile:163: ###" >&2 ++ @echo "kernel/Makefile:163: ### IT IS STRONGLY RECOMMENDED THAT YOU SUPPLY YOUR OWN" >&2 ++ @echo "kernel/Makefile:163: ### SCRIPT WITH APPROPRIATE NAME FIELDS FILLED IN." >&2 ++ @echo "kernel/Makefile:163: ###" >&2 ++ @echo "kernel/Makefile:163: ### If you have a hardware random number generator feeding" >&2 ++ @echo "kernel/Makefile:163: ### into /dev/random, you should drop the %no-protection" >&2 ++ @echo "kernel/Makefile:163: ### and %transient-key lines from the script." >&2 ++ @echo "kernel/Makefile:163: ###" >&2 + echo "%pubring modsign.pub" >genkey + echo "%secring modsign.sec" >>genkey + echo "%no-protection: yes" >> genkey +diff --git a/kernel/modsign-pubkey.c b/kernel/modsign-pubkey.c +new file mode 100644 +index 0000000..17e02f5 +--- /dev/null ++++ b/kernel/modsign-pubkey.c +@@ -0,0 +1,75 @@ ++/* 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 ++#include ++#include ++#include ++#include ++#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 141ddab..2fe31e1 100644 +--- a/kernel/module-verify-defs.h ++++ b/kernel/module-verify-defs.h +@@ -11,6 +11,10 @@ + + #ifdef CONFIG_MODULE_SIG + ++#include ++ ++extern struct key *modsign_keyring; ++ + /* + * Internal state + */ +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 4bf857e..05473e6 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -28,8 +28,6 @@ + #include + #include + #include +-#include +-#include + #include + #include + #include +-- +1.7.11.2 + + +From e4f50fd14864d574dfa77002da3bc51bbb0046bc Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:02 +0100 +Subject: [PATCH 23/27] 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 +--- + kernel/module-verify.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 230 insertions(+) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 05473e6..2161d11 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -51,6 +51,228 @@ 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, 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 */ ++ section = &mvdata->sections[SHN_UNDEF]; ++ seccheck(section->sh_type == SHT_NULL); ++ ++ /* We also want access to the section name table */ ++ section = &mvdata->sections[hdr->e_shstrndx]; ++ seccheck(section->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); ++ if (section->sh_addralign > 1) ++ 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: ++#ifdef Elf_Rel ++ seccheck(section->sh_entsize == sizeof(Elf_Rel)); ++ seccheck(section->sh_addralign % sizeof(long) == 0); ++ break; ++#else ++ seccheck(false); ++ break; ++#endif ++ case SHT_RELA: ++#ifdef Elf_Rela ++ 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. ++ */ ++ 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; ++ ++#ifdef Elf_Rel ++ case SHT_REL: ++#endif ++#ifdef Elf_Rela ++ 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) +@@ -62,6 +284,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.11.2 + + +From b9e2653685ab246ee774d4ea0d178f9d43b003f8 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:02 +0100 +Subject: [PATCH 24/27] 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 +--- + kernel/module-verify.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 80 insertions(+) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 2161d11..646b104 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -273,6 +273,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) +@@ -303,7 +377,13 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) + goto out; + } + ++ /* Produce a canonicalisation map for the sections */ ++ ret = module_verify_canonicalise(&mvdata); ++ if (ret < 0) ++ goto out; ++ + ret = 0; ++ kfree(mvdata.canonlist); + + out: + switch (ret) { +-- +1.7.11.2 + + +From 425b80d71cb3d29ad9a5d1573b1ba62e8acc9846 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:03 +0100 +Subject: [PATCH 25/27] 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 +--- + kernel/module-verify-defs.h | 11 +- + kernel/module-verify.c | 332 +++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 337 insertions(+), 6 deletions(-) + +diff --git a/kernel/module-verify-defs.h b/kernel/module-verify-defs.h +index 2fe31e1..82952b0 100644 +--- a/kernel/module-verify-defs.h ++++ b/kernel/module-verify-defs.h +@@ -42,15 +42,16 @@ struct module_verify_data { + /* + * Whether or not we support various types of ELF relocation record + */ +-#if defined(MODULE_HAS_ELF_REL_ONLY) ++#ifdef Elf_Rel + #define is_elf_rel(sh_type) ((sh_type) == SHT_REL) +-#define is_elf_rela(sh_type) (0) +-#elif defined(MODULE_HAS_ELF_RELA_ONLY) ++#else + #define is_elf_rel(sh_type) (0) ++#endif ++ ++#ifdef Elf_Rela + #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) ++#define is_elf_rela(sh_type) (0) + #endif + + /* +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index 646b104..e275759 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -50,6 +50,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. +@@ -346,6 +362,320 @@ static int module_verify_canonicalise(struct module_verify_data *mvdata) + return 0; + } + ++#ifdef Elf_Rel ++/* ++ * 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 { ++#ifdef CONFIG_64BIT ++ 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 ++ 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; ++#endif ++ } __packed relocation; ++ ++ const Elf_Shdr *relsec, *symsec, *strsec; ++ const Elf_Rel *reloc; ++ const Elf_Sym *symbols, *symbol; ++ const char *strings; ++ unsigned long r_sym; ++ 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 ++ * { 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; ++} ++#endif ++ ++#ifdef Elf_Rela ++/* ++ * 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 { ++#ifdef CONFIG_64BIT ++ 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 ++ 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; ++#endif ++ } __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; ++} ++#endif ++ ++/* ++ * 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. ++ */ ++#ifdef Elf_Rel ++ 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; ++ } ++#endif ++ ++#ifdef Elf_Rela ++ 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; ++ } ++#endif ++ ++ /* 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 + */ +@@ -382,7 +712,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.11.2 + + +From 83b8771f504bdb2d75df57697445211ca312a08b Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:03 +0100 +Subject: [PATCH 26/27] 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 +--- + kernel/module-verify.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index e275759..bfd1286 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -97,11 +97,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.11.2 + + +From a7ec988440e9c8b0deaf769c79b4b3cfe45eb411 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 24 Jul 2012 14:14:03 +0100 +Subject: [PATCH 27/27] MODSIGN: Panic the kernel if FIPS is enabled upon + module signing failure + +If module signing fails when the kernel is running with FIPS enabled then the +kernel should panic lest the crypto layer be compromised. Possibly a panic +shouldn't happen on cases like ENOMEM. + +Reported-by: Stephan Mueller +Signed-off-by: David Howells +--- + kernel/module-verify.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index bfd1286..b9c3955 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include "module-verify.h" + #include "module-verify-defs.h" +@@ -716,6 +717,10 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) + kfree(mvdata.canonlist); + + out: ++ if (ret < 0 && fips_enabled) ++ panic("Module verification failed with error %d in FIPS mode\n", ++ ret); ++ + switch (ret) { + case 0: /* Good signature */ + *_gpgsig_ok = true; +-- +1.7.11.2 + diff --git a/secure-boot-20120724.patch b/secure-boot-20120724.patch new file mode 100644 index 0000000..862e7e0 --- /dev/null +++ b/secure-boot-20120724.patch @@ -0,0 +1,1161 @@ +From 56ce13afe1b17cd2817c596b3a9e25e51937a328 Mon Sep 17 00:00:00 2001 +From: Matt Fleming +Date: Thu, 19 Jul 2012 10:23:48 +0100 +Subject: [PATCH 01/14] x86, efi: Handover Protocol + +As things currently stand, traditional EFI boot loaders and the EFI +boot stub are carrying essentially the same initialisation code +required to setup an EFI machine for booting a kernel. There's really +no need to have this code in two places and the hope is that, with +this new protocol, initialisation and booting of the kernel can be +left solely to the kernel's EFI boot stub. The responsibilities of the +boot loader then become, + + o Loading the kernel image from boot media + +File system code still needs to be carried by boot loaders for the +scenario where the kernel and initrd files reside on a file system +that the EFI firmware doesn't natively understand, such as ext4, etc. + + o Providing a user interface + +Boot loaders still need to display any menus/interfaces, for example +to allow the user to select from a list of kernels. + +Bump the boot protocol number because we added the 'handover_offset' +field to indicate the location of the handover protocol entry point. + +Cc: H. Peter Anvin +Cc: Matthew Garrett +Cc: Peter Jones +Cc: Ingo Molnar +Signed-off-by: Matt Fleming +--- + Documentation/x86/boot.txt | 41 ++++++++ + arch/x86/boot/compressed/eboot.c | 198 ++++++++++++++++++++++--------------- + arch/x86/boot/compressed/head_32.S | 10 ++ + arch/x86/boot/compressed/head_64.S | 10 ++ + arch/x86/boot/header.S | 4 +- + arch/x86/include/asm/bootparam.h | 1 + + 6 files changed, 185 insertions(+), 79 deletions(-) + +diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt +index 7c3a880..c6539a4 100644 +--- a/Documentation/x86/boot.txt ++++ b/Documentation/x86/boot.txt +@@ -54,6 +54,9 @@ Protocol 2.10: (Kernel 2.6.31) Added a protocol for relaxed alignment + beyond the kernel_alignment added, new init_size and + pref_address fields. Added extended boot loader IDs. + ++Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover ++ protocol entry point. ++ + **** MEMORY LAYOUT + + The traditional memory map for the kernel loader, used for Image or +@@ -189,6 +192,7 @@ Offset Proto Name Meaning + of struct setup_data + 0258/8 2.10+ pref_address Preferred loading address + 0260/4 2.10+ init_size Linear memory required during initialization ++0264/4 2.11+ handover_offset Offset of handover entry point + + (1) For backwards compatibility, if the setup_sects field contains 0, the + real value is 4. +@@ -690,6 +694,16 @@ Offset/size: 0x260/4 + else + runtime_start = pref_address + ++Field name: handover_offset ++Type: read ++Offset/size: 0x264/4 ++ ++ This field is the offset from the beginning of the kernel image to ++ the EFI handover protocol entry point. Boot loaders using the EFI ++ handover protocol to boot the kernel should jump to this offset. ++ ++ See EFI HANDOVER PROTOCOL below for more details. ++ + + **** THE IMAGE CHECKSUM + +@@ -1010,3 +1024,30 @@ segment; __BOOS_CS must have execute/read permission, and __BOOT_DS + must have read/write permission; CS must be __BOOT_CS and DS, ES, SS + must be __BOOT_DS; interrupt must be disabled; %esi must hold the base + address of the struct boot_params; %ebp, %edi and %ebx must be zero. ++ ++**** EFI HANDOVER PROTOCOL ++ ++This protocol allows boot loaders to defer initialisation to the EFI ++boot stub. The boot loader is required to load the kernel/initrd(s) ++from the boot media and jump to the EFI handover protocol entry point ++which is hdr->handover_offset bytes from the beginning of ++startup_{32,64}. ++ ++The function prototype for the handover entry point looks like this, ++ ++ efi_main(void *handle, efi_system_table_t *table, struct boot_params *bp) ++ ++'handle' is the EFI image handle passed to the boot loader by the EFI ++firmware, 'table' is the EFI system table - these are the first two ++arguments of the "handoff state" as described in section 2.3 of the ++UEFI specification. 'bp' is the boot loader-allocated boot params. ++ ++The boot loader *must* fill out the following fields in bp, ++ ++ o hdr.code32_start ++ o hdr.cmd_line_ptr ++ o hdr.cmdline_size ++ o hdr.ramdisk_image (if applicable) ++ o hdr.ramdisk_size (if applicable) ++ ++All other fields should be zero. +diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c +index 4e85f5f..b3e0227 100644 +--- a/arch/x86/boot/compressed/eboot.c ++++ b/arch/x86/boot/compressed/eboot.c +@@ -729,32 +729,68 @@ fail: + * need to create one ourselves (usually the bootloader would create + * one for us). + */ +-static efi_status_t make_boot_params(struct boot_params *boot_params, +- efi_loaded_image_t *image, +- void *handle) ++struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table) + { +- struct efi_info *efi = &boot_params->efi_info; +- struct apm_bios_info *bi = &boot_params->apm_bios_info; +- struct sys_desc_table *sdt = &boot_params->sys_desc_table; +- struct e820entry *e820_map = &boot_params->e820_map[0]; +- struct e820entry *prev = NULL; +- struct setup_header *hdr = &boot_params->hdr; +- unsigned long size, key, desc_size, _size; +- efi_memory_desc_t *mem_map; +- void *options = image->load_options; +- u32 load_options_size = image->load_options_size / 2; /* ASCII */ ++ struct boot_params *boot_params; ++ struct sys_desc_table *sdt; ++ struct apm_bios_info *bi; ++ struct setup_header *hdr; ++ struct efi_info *efi; ++ efi_loaded_image_t *image; ++ void *options; ++ u32 load_options_size; ++ efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; + int options_size = 0; + efi_status_t status; +- __u32 desc_version; + unsigned long cmdline; +- u8 nr_entries; + u16 *s2; + u8 *s1; + int i; + ++ sys_table = _table; ++ ++ /* Check if we were booted by the EFI firmware */ ++ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) ++ return NULL; ++ ++ status = efi_call_phys3(sys_table->boottime->handle_protocol, ++ handle, &proto, (void *)&image); ++ if (status != EFI_SUCCESS) { ++ efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); ++ return NULL; ++ } ++ ++ status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); ++ if (status != EFI_SUCCESS) { ++ efi_printk("Failed to alloc lowmem for boot params\n"); ++ return NULL; ++ } ++ ++ memset(boot_params, 0x0, 0x4000); ++ ++ hdr = &boot_params->hdr; ++ efi = &boot_params->efi_info; ++ bi = &boot_params->apm_bios_info; ++ sdt = &boot_params->sys_desc_table; ++ ++ /* Copy the second sector to boot_params */ ++ memcpy(&hdr->jump, image->image_base + 512, 512); ++ ++ /* ++ * Fill out some of the header fields ourselves because the ++ * EFI firmware loader doesn't load the first sector. ++ */ ++ hdr->root_flags = 1; ++ hdr->vid_mode = 0xffff; ++ hdr->boot_flag = 0xAA55; ++ ++ hdr->code32_start = (__u64)(unsigned long)image->image_base; ++ + hdr->type_of_loader = 0x21; + + /* Convert unicode cmdline to ascii */ ++ options = image->load_options; ++ load_options_size = image->load_options_size / 2; /* ASCII */ + cmdline = 0; + s2 = (u16 *)options; + +@@ -791,18 +827,36 @@ static efi_status_t make_boot_params(struct boot_params *boot_params, + hdr->ramdisk_image = 0; + hdr->ramdisk_size = 0; + +- status = handle_ramdisks(image, hdr); +- if (status != EFI_SUCCESS) +- goto free_cmdline; +- +- setup_graphics(boot_params); +- + /* Clear APM BIOS info */ + memset(bi, 0, sizeof(*bi)); + + memset(sdt, 0, sizeof(*sdt)); + +- memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); ++ status = handle_ramdisks(image, hdr); ++ if (status != EFI_SUCCESS) ++ goto fail2; ++ ++ return boot_params; ++fail2: ++ if (options_size) ++ low_free(options_size, hdr->cmd_line_ptr); ++fail: ++ low_free(0x4000, (unsigned long)boot_params); ++ return NULL; ++} ++ ++static efi_status_t exit_boot(struct boot_params *boot_params, ++ void *handle) ++{ ++ struct efi_info *efi = &boot_params->efi_info; ++ struct e820entry *e820_map = &boot_params->e820_map[0]; ++ struct e820entry *prev = NULL; ++ unsigned long size, key, desc_size, _size; ++ efi_memory_desc_t *mem_map; ++ efi_status_t status; ++ __u32 desc_version; ++ u8 nr_entries; ++ int i; + + size = sizeof(*mem_map) * 32; + +@@ -811,7 +865,7 @@ again: + _size = size; + status = low_alloc(size, 1, (unsigned long *)&mem_map); + if (status != EFI_SUCCESS) +- goto free_cmdline; ++ return status; + + status = efi_call_phys5(sys_table->boottime->get_memory_map, &size, + mem_map, &key, &desc_size, &desc_version); +@@ -823,6 +877,7 @@ again: + if (status != EFI_SUCCESS) + goto free_mem_map; + ++ memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); + efi->efi_systab = (unsigned long)sys_table; + efi->efi_memdesc_size = desc_size; + efi->efi_memdesc_version = desc_version; +@@ -906,61 +961,13 @@ again: + + free_mem_map: + low_free(_size, (unsigned long)mem_map); +-free_cmdline: +- if (options_size) +- low_free(options_size, hdr->cmd_line_ptr); +-fail: + return status; + } + +-/* +- * On success we return a pointer to a boot_params structure, and NULL +- * on failure. +- */ +-struct boot_params *efi_main(void *handle, efi_system_table_t *_table) ++static efi_status_t relocate_kernel(struct setup_header *hdr) + { +- struct boot_params *boot_params; + unsigned long start, nr_pages; +- struct desc_ptr *gdt, *idt; +- efi_loaded_image_t *image; +- struct setup_header *hdr; + efi_status_t status; +- efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; +- struct desc_struct *desc; +- +- sys_table = _table; +- +- /* Check if we were booted by the EFI firmware */ +- if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) +- goto fail; +- +- status = efi_call_phys3(sys_table->boottime->handle_protocol, +- handle, &proto, (void *)&image); +- if (status != EFI_SUCCESS) { +- efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); +- goto fail; +- } +- +- status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); +- if (status != EFI_SUCCESS) { +- efi_printk("Failed to alloc lowmem for boot params\n"); +- goto fail; +- } +- +- memset(boot_params, 0x0, 0x4000); +- +- hdr = &boot_params->hdr; +- +- /* Copy the second sector to boot_params */ +- memcpy(&hdr->jump, image->image_base + 512, 512); +- +- /* +- * Fill out some of the header fields ourselves because the +- * EFI firmware loader doesn't load the first sector. +- */ +- hdr->root_flags = 1; +- hdr->vid_mode = 0xffff; +- hdr->boot_flag = 0xAA55; + + /* + * The EFI firmware loader could have placed the kernel image +@@ -978,16 +985,40 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table) + if (status != EFI_SUCCESS) { + status = low_alloc(hdr->init_size, hdr->kernel_alignment, + &start); +- if (status != EFI_SUCCESS) { ++ if (status != EFI_SUCCESS) + efi_printk("Failed to alloc mem for kernel\n"); +- goto fail; +- } + } + ++ if (status == EFI_SUCCESS) ++ memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, ++ hdr->init_size); ++ ++ hdr->pref_address = hdr->code32_start; + hdr->code32_start = (__u32)start; +- hdr->pref_address = (__u64)(unsigned long)image->image_base; + +- memcpy((void *)start, image->image_base, image->image_size); ++ return status; ++} ++ ++/* ++ * On success we return a pointer to a boot_params structure, and NULL ++ * on failure. ++ */ ++struct boot_params *efi_main(void *handle, efi_system_table_t *_table, ++ struct boot_params *boot_params) ++{ ++ struct desc_ptr *gdt, *idt; ++ efi_loaded_image_t *image; ++ struct setup_header *hdr = &boot_params->hdr; ++ efi_status_t status; ++ struct desc_struct *desc; ++ ++ sys_table = _table; ++ ++ /* Check if we were booted by the EFI firmware */ ++ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) ++ goto fail; ++ ++ setup_graphics(boot_params); + + status = efi_call_phys3(sys_table->boottime->allocate_pool, + EFI_LOADER_DATA, sizeof(*gdt), +@@ -1015,7 +1046,18 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table) + idt->size = 0; + idt->address = 0; + +- status = make_boot_params(boot_params, image, handle); ++ /* ++ * If the kernel isn't already loaded at the preferred load ++ * address, relocate it. ++ */ ++ if (hdr->pref_address != hdr->code32_start) { ++ status = relocate_kernel(hdr); ++ ++ if (status != EFI_SUCCESS) ++ goto fail; ++ } ++ ++ status = exit_boot(boot_params, handle); + if (status != EFI_SUCCESS) + goto fail; + +diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S +index c85e3ac..aa4aaf1 100644 +--- a/arch/x86/boot/compressed/head_32.S ++++ b/arch/x86/boot/compressed/head_32.S +@@ -42,6 +42,16 @@ ENTRY(startup_32) + */ + add $0x4, %esp + ++ call make_boot_params ++ cmpl $0, %eax ++ je 1f ++ movl 0x4(%esp), %esi ++ movl (%esp), %ecx ++ pushl %eax ++ pushl %esi ++ pushl %ecx ++ ++ .org 0x30,0x90 + call efi_main + cmpl $0, %eax + movl %eax, %esi +diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S +index 87e03a1..2c4b171 100644 +--- a/arch/x86/boot/compressed/head_64.S ++++ b/arch/x86/boot/compressed/head_64.S +@@ -209,6 +209,16 @@ ENTRY(startup_64) + .org 0x210 + mov %rcx, %rdi + mov %rdx, %rsi ++ pushq %rdi ++ pushq %rsi ++ call make_boot_params ++ cmpq $0,%rax ++ je 1f ++ mov %rax, %rdx ++ popq %rsi ++ popq %rdi ++ ++ .org 0x230,0x90 + call efi_main + movq %rax,%rsi + cmpq $0,%rax +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index efe5acf..cd921fe 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -283,7 +283,7 @@ _start: + # Part 2 of the header, from the old setup.S + + .ascii "HdrS" # header signature +- .word 0x020a # header version number (>= 0x0105) ++ .word 0x020b # header version number (>= 0x0105) + # or else old loadlin-1.5 will fail) + .globl realmode_swtch + realmode_swtch: .word 0, 0 # default_switch, SETUPSEG +@@ -401,6 +401,8 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr + #define INIT_SIZE VO_INIT_SIZE + #endif + init_size: .long INIT_SIZE # kernel initialization size ++handover_offset: .long 0x30 # offset to the handover ++ # protocol entry point + + # End of setup header ##################################################### + +diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h +index eb45aa6..2ad874c 100644 +--- a/arch/x86/include/asm/bootparam.h ++++ b/arch/x86/include/asm/bootparam.h +@@ -66,6 +66,7 @@ struct setup_header { + __u64 setup_data; + __u64 pref_address; + __u32 init_size; ++ __u32 handover_offset; + } __attribute__((packed)); + + struct sys_desc_table { +-- +1.7.11.2 + + +From 948fbe310f85f3a51a101ea23f38c59c70792832 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Thu, 8 Mar 2012 09:56:33 -0500 +Subject: [PATCH 02/14] Secure boot: Add new capability + +Secure boot adds certain policy requirements, including that root must not +be able to do anything that could cause the kernel to execute arbitrary code. +The simplest way to handle this would seem to be to add a new capability +and gate various functionality on that. We'll then strip it from the initial +capability set if required. + +Signed-off-by: Matthew Garrett +--- + include/linux/capability.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/include/linux/capability.h b/include/linux/capability.h +index d10b7ed..6a39163 100644 +--- a/include/linux/capability.h ++++ b/include/linux/capability.h +@@ -364,7 +364,11 @@ struct cpu_vfs_cap_data { + + #define CAP_BLOCK_SUSPEND 36 + +-#define CAP_LAST_CAP CAP_BLOCK_SUSPEND ++/* Allow things that are dangerous under secure boot */ ++ ++#define CAP_SECURE_FIRMWARE 37 ++ ++#define CAP_LAST_CAP CAP_SECURE_FIRMWARE + + #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) + +-- +1.7.11.2 + + +From 56150c6ad369f31e34e438744d34c505751a8b78 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Thu, 8 Mar 2012 10:10:38 -0500 +Subject: [PATCH 03/14] PCI: Lock down BAR access in secure boot environments + +Any hardware that can potentially generate DMA has to be locked down from +userspace in order to avoid it being possible for an attacker to cause +arbitrary kernel behaviour. Default to paranoid - in future we can +potentially relax this for sufficiently IOMMU-isolated devices. + +Signed-off-by: Matthew Garrett +--- + drivers/pci/pci-sysfs.c | 9 +++++++++ + drivers/pci/proc.c | 8 +++++++- + drivers/pci/syscall.c | 2 +- + 3 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c +index 86c63fe..d3adb7b 100644 +--- a/drivers/pci/pci-sysfs.c ++++ b/drivers/pci/pci-sysfs.c +@@ -513,6 +513,9 @@ pci_write_config(struct file* filp, struct kobject *kobj, + loff_t init_off = off; + u8 *data = (u8*) buf; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + if (off > dev->cfg_size) + return 0; + if (off + count > dev->cfg_size) { +@@ -815,6 +818,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, + resource_size_t start, end; + int i; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if (res == &pdev->resource[i]) + break; +@@ -922,6 +928,9 @@ pci_write_resource_io(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) + { ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + return pci_resource_io(filp, kobj, attr, buf, off, count, true); + } + +diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c +index 27911b5..01d4753 100644 +--- a/drivers/pci/proc.c ++++ b/drivers/pci/proc.c +@@ -135,6 +135,9 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof + int size = dp->size; + int cnt; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + if (pos >= size) + return 0; + if (nbytes >= size) +@@ -211,6 +214,9 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, + #endif /* HAVE_PCI_MMAP */ + int ret = 0; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + switch (cmd) { + case PCIIOC_CONTROLLER: + ret = pci_domain_nr(dev->bus); +@@ -251,7 +257,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) + struct pci_filp_private *fpriv = file->private_data; + int i, ret; + +- if (!capable(CAP_SYS_RAWIO)) ++ if (!capable(CAP_SYS_RAWIO) || !capable(CAP_SECURE_FIRMWARE)) + return -EPERM; + + /* Make sure the caller is mapping a real resource for this device */ +diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c +index e1c1ec5..a778ba9 100644 +--- a/drivers/pci/syscall.c ++++ b/drivers/pci/syscall.c +@@ -92,7 +92,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, + u32 dword; + int err = 0; + +- if (!capable(CAP_SYS_ADMIN)) ++ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SECURE_FIRMWARE)) + return -EPERM; + + dev = pci_get_bus_and_slot(bus, dfn); +-- +1.7.11.2 + + +From 888347d81b1ddcdcd5989cba1c212aed549928eb Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Thu, 8 Mar 2012 10:35:59 -0500 +Subject: [PATCH 04/14] x86: Lock down IO port access in secure boot + environments + +IO port access would permit users to gain access to PCI configuration +registers, which in turn (on a lot of hardware) give access to MMIO register +space. This would potentially permit root to trigger arbitrary DMA, so lock +it down by default. + +Signed-off-by: Matthew Garrett +--- + arch/x86/kernel/ioport.c | 4 ++-- + drivers/char/mem.c | 3 +++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c +index 8c96897..c3a1bb2 100644 +--- a/arch/x86/kernel/ioport.c ++++ b/arch/x86/kernel/ioport.c +@@ -28,7 +28,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) + + if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) + return -EINVAL; +- if (turn_on && !capable(CAP_SYS_RAWIO)) ++ if (turn_on && (!capable(CAP_SYS_RAWIO) || !capable(CAP_SECURE_FIRMWARE))) + return -EPERM; + + /* +@@ -102,7 +102,7 @@ long sys_iopl(unsigned int level, struct pt_regs *regs) + return -EINVAL; + /* Trying to gain more privileges? */ + if (level > old) { +- if (!capable(CAP_SYS_RAWIO)) ++ if (!capable(CAP_SYS_RAWIO) || !capable(CAP_SECURE_FIRMWARE)) + return -EPERM; + } + regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); +diff --git a/drivers/char/mem.c b/drivers/char/mem.c +index e5eedfa..8f5f872 100644 +--- a/drivers/char/mem.c ++++ b/drivers/char/mem.c +@@ -597,6 +597,9 @@ static ssize_t write_port(struct file *file, const char __user *buf, + unsigned long i = *ppos; + const char __user * tmp = buf; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + while (count-- > 0 && i < 65536) { +-- +1.7.11.2 + + +From a02e91ca8639c6a3a43c684892e2802973c02efc Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Fri, 9 Mar 2012 08:39:37 -0500 +Subject: [PATCH 05/14] ACPI: Limit access to custom_method + +It must be impossible for even root to get code executed in kernel context +under a secure boot environment. custom_method effectively allows arbitrary +access to system memory, so it needs to have a capability check here. + +Signed-off-by: Matthew Garrett +--- + drivers/acpi/custom_method.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c +index 5d42c24..3e78014 100644 +--- a/drivers/acpi/custom_method.c ++++ b/drivers/acpi/custom_method.c +@@ -29,6 +29,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, + struct acpi_table_header table; + acpi_status status; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + if (!(*ppos)) { + /* parse the table header to get the table length */ + if (count <= sizeof(struct acpi_table_header)) +-- +1.7.11.2 + + +From c523e4918f56e5c17e39c0a5997cc1e741c0f42b Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Fri, 9 Mar 2012 08:46:50 -0500 +Subject: [PATCH 06/14] asus-wmi: Restrict debugfs interface + +We have no way of validating what all of the Asus WMI methods do on a +given machine, and there's a risk that some will allow hardware state to +be manipulated in such a way that arbitrary code can be executed in the +kernel. Add a capability check to prevent that. + +Signed-off-by: Matthew Garrett +--- + drivers/platform/x86/asus-wmi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 77aadde..ba715c0 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -1504,6 +1504,9 @@ static int show_dsts(struct seq_file *m, void *data) + int err; + u32 retval = -1; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); + + if (err < 0) +@@ -1520,6 +1523,9 @@ static int show_devs(struct seq_file *m, void *data) + int err; + u32 retval = -1; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, + &retval); + +@@ -1544,6 +1550,9 @@ static int show_call(struct seq_file *m, void *data) + union acpi_object *obj; + acpi_status status; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, + 1, asus->debug.method_id, + &input, &output); +-- +1.7.11.2 + + +From 5dc9f0a45d092e5aec177eac1e5e19b62fb28cb2 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Fri, 9 Mar 2012 09:28:15 -0500 +Subject: [PATCH 07/14] Restrict /dev/mem and /dev/kmem in secure boot setups + +Allowing users to write to address space makes it possible for the kernel +to be subverted. Restrict this when we need to protect the kernel. + +Signed-off-by: Matthew Garrett +--- + drivers/char/mem.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/char/mem.c b/drivers/char/mem.c +index 8f5f872..c1de8e1 100644 +--- a/drivers/char/mem.c ++++ b/drivers/char/mem.c +@@ -158,6 +158,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf, + unsigned long copied; + void *ptr; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + if (!valid_phys_addr_range(p, count)) + return -EFAULT; + +@@ -530,6 +533,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, + char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ + int err = 0; + ++ if (!capable(CAP_SECURE_FIRMWARE)) ++ return -EPERM; ++ + if (p < (unsigned long) high_memory) { + unsigned long to_write = min_t(unsigned long, count, + (unsigned long)high_memory - p); +-- +1.7.11.2 + + +From 16a693dde4c4dca871d920e15fe9dda01000ef86 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Fri, 9 Mar 2012 11:47:56 -0500 +Subject: [PATCH 08/14] kexec: Disable in a secure boot environment + +kexec could be used as a vector for a malicious user to use a signed kernel +to circumvent the secure boot trust model. In the long run we'll want to +support signed kexec payloads, but for the moment we should just disable +loading entirely in that situation. + +Signed-off-by: Matthew Garrett +--- + kernel/kexec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/kexec.c b/kernel/kexec.c +index 4e2e472..35051f9 100644 +--- a/kernel/kexec.c ++++ b/kernel/kexec.c +@@ -944,7 +944,7 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, + int result; + + /* We only trust the superuser with rebooting the system. */ +- if (!capable(CAP_SYS_BOOT)) ++ if (!capable(CAP_SYS_BOOT) || !capable(CAP_SECURE_FIRMWARE)) + return -EPERM; + + /* +-- +1.7.11.2 + + +From 82fe599f1192ba0bae968a8e05d8cddbbadd57bc Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Mon, 25 Jun 2012 19:45:15 -0400 +Subject: [PATCH 09/14] Secure boot: Add a dummy kernel parameter that will + switch on Secure Boot mode + +This forcibly drops CAP_SECURE_FIRMWARE from both cap_permitted and cap_bset +in the init_cred struct, which everything else inherits from. This works on +any machine and can be used to develop even if the box doesn't have UEFI. + +Signed-off-by: Josh Boyer +--- + kernel/cred.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/kernel/cred.c b/kernel/cred.c +index de728ac..0d71d02 100644 +--- a/kernel/cred.c ++++ b/kernel/cred.c +@@ -623,6 +623,20 @@ void __init cred_init(void) + 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + } + ++/* Dummy Secure Boot enable option to fake out UEFI SB=1 */ ++static int __init secureboot_enable(char *str) ++{ ++ ++ int sb_enable = !!simple_strtol(str, NULL, 0); ++ pr_info("Secure Boot mode %s\n", (sb_enable ? "enabled" : "disabled")); ++ if (sb_enable) { ++ cap_lower((&init_cred)->cap_bset, CAP_SECURE_FIRMWARE); ++ cap_lower((&init_cred)->cap_permitted, CAP_SECURE_FIRMWARE); ++ } ++ return 1; ++} ++__setup("secureboot_enable=", secureboot_enable); ++ + /** + * prepare_kernel_cred - Prepare a set of credentials for a kernel service + * @daemon: A userspace daemon to be used as a reference +-- +1.7.11.2 + + +From 5aa21bbaad50af58a54cc339f6ab7bf5c163d64f Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Wed, 18 Jul 2012 11:28:00 -0400 +Subject: [PATCH 10/14] efi: Enable secure boot lockdown automatically when + enabled in firmware + +The firmware has a set of flags that indicate whether secure boot is enabled +and enforcing. Use them to indicate whether the kernel should lock itself +down. + +Signed-off-by: Matthew Garrett +--- + arch/x86/boot/compressed/eboot.c | 32 ++++++++++++++++++++++++++++++++ + arch/x86/include/asm/bootparam.h | 3 ++- + arch/x86/kernel/setup.c | 3 +++ + include/linux/cred.h | 2 ++ + kernel/cred.c | 18 +++++++++++------- + 5 files changed, 50 insertions(+), 8 deletions(-) + +diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c +index b3e0227..3789356 100644 +--- a/arch/x86/boot/compressed/eboot.c ++++ b/arch/x86/boot/compressed/eboot.c +@@ -724,6 +724,36 @@ fail: + return status; + } + ++static int get_secure_boot(efi_system_table_t *_table) ++{ ++ u8 sb, setup; ++ unsigned long datasize = sizeof(sb); ++ efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID; ++ efi_status_t status; ++ ++ status = efi_call_phys5(sys_table->runtime->get_variable, ++ L"SecureBoot", &var_guid, NULL, &datasize, &sb); ++ ++ if (status != EFI_SUCCESS) ++ return 0; ++ ++ if (sb == 0) ++ return 0; ++ ++ ++ status = efi_call_phys5(sys_table->runtime->get_variable, ++ L"SetupMode", &var_guid, NULL, &datasize, ++ &setup); ++ ++ if (status != EFI_SUCCESS) ++ return 0; ++ ++ if (setup == 1) ++ return 0; ++ ++ return 1; ++} ++ + /* + * Because the x86 boot code expects to be passed a boot_params we + * need to create one ourselves (usually the bootloader would create +@@ -1018,6 +1048,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table, + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + goto fail; + ++ boot_params->secure_boot = get_secure_boot(sys_table); ++ + setup_graphics(boot_params); + + status = efi_call_phys3(sys_table->boottime->allocate_pool, +diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h +index 2ad874c..c7338e0 100644 +--- a/arch/x86/include/asm/bootparam.h ++++ b/arch/x86/include/asm/bootparam.h +@@ -114,7 +114,8 @@ struct boot_params { + __u8 eddbuf_entries; /* 0x1e9 */ + __u8 edd_mbr_sig_buf_entries; /* 0x1ea */ + __u8 kbd_status; /* 0x1eb */ +- __u8 _pad6[5]; /* 0x1ec */ ++ __u8 secure_boot; /* 0x1ec */ ++ __u8 _pad6[4]; /* 0x1ed */ + struct setup_header hdr; /* setup header */ /* 0x1f1 */ + __u8 _pad7[0x290-0x1f1-sizeof(struct setup_header)]; + __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 0x290 */ +diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c +index f4b9b80..239bf2a 100644 +--- a/arch/x86/kernel/setup.c ++++ b/arch/x86/kernel/setup.c +@@ -947,6 +947,9 @@ void __init setup_arch(char **cmdline_p) + + io_delay_init(); + ++ if (boot_params.secure_boot) ++ secureboot_enable(); ++ + /* + * Parse the ACPI tables for possible boot-time SMP configuration. + */ +diff --git a/include/linux/cred.h b/include/linux/cred.h +index ebbed2c..a24faf1 100644 +--- a/include/linux/cred.h ++++ b/include/linux/cred.h +@@ -170,6 +170,8 @@ extern int set_security_override_from_ctx(struct cred *, const char *); + extern int set_create_files_as(struct cred *, struct inode *); + extern void __init cred_init(void); + ++extern void secureboot_enable(void); ++ + /* + * check for validity of credentials + */ +diff --git a/kernel/cred.c b/kernel/cred.c +index 0d71d02..c43e2b0 100644 +--- a/kernel/cred.c ++++ b/kernel/cred.c +@@ -623,19 +623,23 @@ void __init cred_init(void) + 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + } + ++void __init secureboot_enable() ++{ ++ pr_info("Secure boot enabled\n"); ++ cap_lower((&init_cred)->cap_bset, CAP_SECURE_FIRMWARE); ++ cap_lower((&init_cred)->cap_permitted, CAP_SECURE_FIRMWARE); ++} ++ + /* Dummy Secure Boot enable option to fake out UEFI SB=1 */ +-static int __init secureboot_enable(char *str) ++static int __init secureboot_enable_opt(char *str) + { + + int sb_enable = !!simple_strtol(str, NULL, 0); +- pr_info("Secure Boot mode %s\n", (sb_enable ? "enabled" : "disabled")); +- if (sb_enable) { +- cap_lower((&init_cred)->cap_bset, CAP_SECURE_FIRMWARE); +- cap_lower((&init_cred)->cap_permitted, CAP_SECURE_FIRMWARE); +- } ++ if (sb_enable) ++ secureboot_enable(); + return 1; + } +-__setup("secureboot_enable=", secureboot_enable); ++__setup("secureboot_enable=", secureboot_enable_opt); + + /** + * prepare_kernel_cred - Prepare a set of credentials for a kernel service +-- +1.7.11.2 + + +From 7b875c254033d29fa05b0c026b8097f8e5e1b96c Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Mon, 25 Jun 2012 19:57:30 -0400 +Subject: [PATCH 11/14] acpi: Ignore acpi_rsdp kernel parameter in a secure + boot environment + +This option allows userspace to pass the RSDP address to the kernel. This +could potentially be used to circumvent the secure boot trust model. +We ignore the setting if we don't have the CAP_SECURE_FIRMWARE capability. + +Signed-off-by: Josh Boyer +--- + drivers/acpi/osl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c +index c3881b2..fb84388 100644 +--- a/drivers/acpi/osl.c ++++ b/drivers/acpi/osl.c +@@ -246,7 +246,7 @@ early_param("acpi_rsdp", setup_acpi_rsdp); + acpi_physical_address __init acpi_os_get_root_pointer(void) + { + #ifdef CONFIG_KEXEC +- if (acpi_rsdp) ++ if (acpi_rsdp && capable(CAP_SECURE_FIRMWARE)) + return acpi_rsdp; + #endif + +-- +1.7.11.2 + + +From 5ba183ef3e556bf11bbe73abd2cba50dc097881d Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Mon, 25 Jun 2012 21:29:46 -0400 +Subject: [PATCH 12/14] Documentation: kernel-parameters.txt remove + capability.disable + +Remove the documentation for capability.disable. The code supporting this +parameter was removed with: + + commit 5915eb53861c5776cfec33ca4fcc1fd20d66dd27 + Author: Miklos Szeredi + Date: Thu Jul 3 20:56:05 2008 +0200 + + security: remove dummy module + +Signed-off-by: Josh Boyer +--- + Documentation/kernel-parameters.txt | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index 12783fa..cec4bf2 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -446,12 +446,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. + possible to determine what the correct size should be. + This option provides an override for these situations. + +- capability.disable= +- [SECURITY] Disable capabilities. This would normally +- be used only if an alternative security model is to be +- configured. Potentially dangerous and should only be +- used if you are entirely sure of the consequences. +- + ccw_timeout_log [S390] + See Documentation/s390/CommonIO for details. + +-- +1.7.11.2 + + +From 220f3a8cc351d220156e4903bf03c28ab44db6e3 Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Tue, 26 Jun 2012 14:15:51 -0400 +Subject: [PATCH 13/14] SELinux: define mapping for new Secure Boot capability + +Add the name of the new Secure Boot capability. This allows SELinux +policies to properly map CAP_SECURE_FIRMWARE to the appropriate +capability class. + +Signed-off-by: Josh Boyer +--- + security/selinux/include/classmap.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h +index df2de54..0a1e348 100644 +--- a/security/selinux/include/classmap.h ++++ b/security/selinux/include/classmap.h +@@ -146,8 +146,8 @@ struct security_class_mapping secclass_map[] = { + { "memprotect", { "mmap_zero", NULL } }, + { "peer", { "recv", NULL } }, + { "capability2", +- { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", +- NULL } }, ++ { "mac_override", "mac_admin", "syslog", "wake_alarm", ++ "block_suspend", "secure_firmware", NULL } }, + { "kernel_service", { "use_as_override", "create_files_as", NULL } }, + { "tun_socket", + { COMMON_SOCK_PERMS, NULL } }, +-- +1.7.11.2 + + +From e5df15082c685dbf5c6917b891af73106342c0bb Mon Sep 17 00:00:00 2001 +From: Josh Boyer +Date: Tue, 26 Jun 2012 16:27:26 -0400 +Subject: [PATCH 14/14] modsign: Reject unsigned modules in a Secure Boot + environment + +If a machine is booted into a Secure Boot environment, we need to +protect the trust model. This requires that all modules be signed +with a key that is in the kernel's _modsign keyring. We add a +capability check and reject modules that are not signed. + +Signed-off-by: Josh Boyer +--- + kernel/module-verify.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/module-verify.c b/kernel/module-verify.c +index b9c3955..f35532a 100644 +--- a/kernel/module-verify.c ++++ b/kernel/module-verify.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include "module-verify.h" + #include "module-verify-defs.h" +@@ -699,7 +700,7 @@ int module_verify(const Elf_Ehdr *hdr, size_t size, bool *_gpgsig_ok) + /* The ELF checker found the sig for us if it exists */ + if (mvdata.sig_index <= 0) { + /* Deal with an unsigned module */ +- if (modsign_signedonly) { ++ if (modsign_signedonly || !capable(CAP_SECURE_FIRMWARE)) { + pr_err("An attempt to load unsigned module was rejected\n"); + return -EKEYREJECTED; + } else { +-- +1.7.11.2 +