Pārlūkot izejas kodu

MODSIGN: Move the magic string to the end of a module and eliminate the search

Emit the magic string that indicates a module has a signature after the
signature data instead of before it.  This allows module_sig_check() to
be made simpler and faster by the elimination of the search for the
magic string.  Instead we just need to do a single memcmp().

This works because at the end of the signature data there is the
fixed-length signature information block.  This block then falls
immediately prior to the magic number.

From the contents of the information block, it is trivial to calculate
the size of the signature data and thus the size of the actual module
data.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
David Howells 12 gadi atpakaļ
vecāks
revīzija
caabe24057
4 mainītis faili ar 28 papildinājumiem un 31 dzēšanām
  1. 1 2
      kernel/module-internal.h
  2. 9 17
      kernel/module.c
  3. 15 9
      kernel/module_signing.c
  4. 3 3
      scripts/sign-file

+ 1 - 2
kernel/module-internal.h

@@ -11,5 +11,4 @@
 
 
 extern struct key *modsign_keyring;
 extern struct key *modsign_keyring;
 
 
-extern int mod_verify_sig(const void *mod, unsigned long modlen,
-			  const void *sig, unsigned long siglen);
+extern int mod_verify_sig(const void *mod, unsigned long *_modlen);

+ 9 - 17
kernel/module.c

@@ -2421,25 +2421,17 @@ static inline void kmemleak_load_module(const struct module *mod,
 
 
 #ifdef CONFIG_MODULE_SIG
 #ifdef CONFIG_MODULE_SIG
 static int module_sig_check(struct load_info *info,
 static int module_sig_check(struct load_info *info,
-			    const void *mod, unsigned long *len)
+			    const void *mod, unsigned long *_len)
 {
 {
 	int err = -ENOKEY;
 	int err = -ENOKEY;
-	const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
-	const void *p = mod, *end = mod + *len;
-
-	/* Poor man's memmem. */
-	while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
-		if (p + markerlen > end)
-			break;
-
-		if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
-			const void *sig = p + markerlen;
-			/* Truncate module up to signature. */
-			*len = p - mod;
-			err = mod_verify_sig(mod, *len, sig, end - sig);
-			break;
-		}
-		p++;
+	unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+	unsigned long len = *_len;
+
+	if (len > markerlen &&
+	    memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
+		/* We truncate the module to discard the signature */
+		*_len -= markerlen;
+		err = mod_verify_sig(mod, _len);
 	}
 	}
 
 
 	if (!err) {
 	if (!err) {

+ 15 - 9
kernel/module_signing.c

@@ -183,27 +183,33 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
 /*
 /*
  * Verify the signature on a module.
  * Verify the signature on a module.
  */
  */
-int mod_verify_sig(const void *mod, unsigned long modlen,
-		   const void *sig, unsigned long siglen)
+int mod_verify_sig(const void *mod, unsigned long *_modlen)
 {
 {
 	struct public_key_signature *pks;
 	struct public_key_signature *pks;
 	struct module_signature ms;
 	struct module_signature ms;
 	struct key *key;
 	struct key *key;
-	size_t sig_len;
+	const void *sig;
+	size_t modlen = *_modlen, sig_len;
 	int ret;
 	int ret;
 
 
-	pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen);
+	pr_devel("==>%s(,%lu)\n", __func__, modlen);
 
 
-	if (siglen <= sizeof(ms))
+	if (modlen <= sizeof(ms))
 		return -EBADMSG;
 		return -EBADMSG;
 
 
-	memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms));
-	siglen -= sizeof(ms);
+	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
+	modlen -= sizeof(ms);
 
 
 	sig_len = be32_to_cpu(ms.sig_len);
 	sig_len = be32_to_cpu(ms.sig_len);
-	if (sig_len >= siglen ||
-	    siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len)
+	if (sig_len >= modlen)
 		return -EBADMSG;
 		return -EBADMSG;
+	modlen -= sig_len;
+	if ((size_t)ms.signer_len + ms.key_id_len >= modlen)
+		return -EBADMSG;
+	modlen -= (size_t)ms.signer_len + ms.key_id_len;
+
+	*_modlen = modlen;
+	sig = mod + modlen;
 
 
 	/* For the moment, only support RSA and X.509 identifiers */
 	/* For the moment, only support RSA and X.509 identifiers */
 	if (ms.algo != PKEY_ALGO_RSA ||
 	if (ms.algo != PKEY_ALGO_RSA ||

+ 3 - 3
scripts/sign-file

@@ -403,11 +403,11 @@ my $info = pack("CCCCCxxxN",
 
 
 if ($verbose) {
 if ($verbose) {
     print "Size of unsigned module: ", length($unsigned_module), "\n";
     print "Size of unsigned module: ", length($unsigned_module), "\n";
-    print "Size of magic number   : ", length($magic_number), "\n";
     print "Size of signer's name  : ", length($signers_name), "\n";
     print "Size of signer's name  : ", length($signers_name), "\n";
     print "Size of key identifier : ", length($key_identifier), "\n";
     print "Size of key identifier : ", length($key_identifier), "\n";
     print "Size of signature      : ", length($signature), "\n";
     print "Size of signature      : ", length($signature), "\n";
     print "Size of informaton     : ", length($info), "\n";
     print "Size of informaton     : ", length($info), "\n";
+    print "Size of magic number   : ", length($magic_number), "\n";
     print "Signer's name          : '", $signers_name, "'\n";
     print "Signer's name          : '", $signers_name, "'\n";
     print "Digest                 : $dgst\n";
     print "Digest                 : $dgst\n";
 }
 }
@@ -416,11 +416,11 @@ open(FD, ">$dest") || die $dest;
 binmode FD;
 binmode FD;
 print FD
 print FD
     $unsigned_module,
     $unsigned_module,
-    $magic_number,
     $signers_name,
     $signers_name,
     $key_identifier,
     $key_identifier,
     $signature,
     $signature,
-    $info
+    $info,
+    $magic_number
     ;
     ;
 close FD || die $dest;
 close FD || die $dest;