*.so.dbg
*.mod.c
*.i
+*.ko.unsigned
+*.ko.digest.sig
+*.ko.digest
*.lst
*.symtypes
*.order
mpi_free(v);
return rc;
}
+EXPORT_SYMBOL_GPL(DSA_verify);
/*
*
*/
-static void ksign_calc_pk_keyid(struct hash_desc *sha1,
+static void ksign_calc_pk_keyid(struct shash_desc *digest,
struct ksign_public_key *pk)
{
unsigned n;
int i;
int npkey = DSA_NPKEY;
- crypto_hash_init(sha1);
-
n = pk->version < 4 ? 8 : 6;
for (i = 0; i < npkey; i++) {
nb[i] = mpi_get_nbits(pk->pkey[i]);
n += 2 + nn[i];
}
- SHA1_putc(sha1, 0x99); /* ctb */
- SHA1_putc(sha1, n >> 8); /* 2 uint8_t length header */
- SHA1_putc(sha1, n);
+ SHA1_putc(digest, 0x99); /* ctb */
+ SHA1_putc(digest, n >> 8); /* 2 uint8_t length header */
+ SHA1_putc(digest, n);
if (pk->version < 4)
- SHA1_putc(sha1, 3);
+ SHA1_putc(digest, 3);
else
- SHA1_putc(sha1, 4);
+ SHA1_putc(digest, 4);
a32 = pk->timestamp;
- SHA1_putc(sha1, a32 >> 24 );
- SHA1_putc(sha1, a32 >> 16 );
- SHA1_putc(sha1, a32 >> 8 );
- SHA1_putc(sha1, a32 >> 0 );
+ SHA1_putc(digest, a32 >> 24 );
+ SHA1_putc(digest, a32 >> 16 );
+ SHA1_putc(digest, a32 >> 8 );
+ SHA1_putc(digest, a32 >> 0 );
if (pk->version < 4) {
uint16_t a16;
((pk->expiredate - pk->timestamp) / 86400L);
else
a16 = 0;
- SHA1_putc(sha1, a16 >> 8);
- SHA1_putc(sha1, a16 >> 0);
+ SHA1_putc(digest, a16 >> 8);
+ SHA1_putc(digest, a16 >> 0);
}
- SHA1_putc(sha1, PUBKEY_ALGO_DSA);
+ SHA1_putc(digest, PUBKEY_ALGO_DSA);
for (i = 0; i < npkey; i++) {
- SHA1_putc(sha1, nb[i] >> 8);
- SHA1_putc(sha1, nb[i]);
- SHA1_write(sha1, pp[i], nn[i]);
+ SHA1_putc(digest, nb[i] >> 8);
+ SHA1_putc(digest, nb[i]);
+ SHA1_write(digest, pp[i], nn[i]);
kfree(pp[i]);
}
}
ksign_public_key_actor_t pkfnx, void *fnxdata)
{
struct ksign_public_key *pk;
- struct hash_desc sha1;
+ struct crypto_shash *tfm;
+ struct shash_desc *digest;
unsigned long timestamp, expiredate;
- uint8_t hash[SHA1_DIGEST_SIZE];
+ uint8_t sha1[SHA1_DIGEST_SIZE];
int i, version;
int is_v4 = 0;
int rc = 0;
rc = -ENOMEM;
- sha1.tfm = crypto_alloc_hash("sha1", 0, 0);
- if (!sha1.tfm)
- goto cleanup;
- sha1.flags = 0;
+ tfm = crypto_alloc_shash("sha1", 0, 0);
+ if (!tfm)
+ goto cleanup_pubkey;
+
+ 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;
+ rc = crypto_shash_init(digest);
+ if (rc < 0)
+ goto cleanup_sha1;
+
+ ksign_calc_pk_keyid(digest, pk);
- ksign_calc_pk_keyid(&sha1, pk);
- crypto_hash_final(&sha1, hash);
- crypto_free_hash(sha1.tfm);
+ rc = crypto_shash_final(digest, sha1);
+ if (rc < 0)
+ goto cleanup_sha1;
- pk->keyid[0] = hash[12] << 24 | hash[13] << 16 | hash[14] << 8 | hash[15];
- pk->keyid[1] = hash[16] << 24 | hash[17] << 16 | hash[18] << 8 | hash[19];
+ pk->keyid[0] = sha1[12] << 24 | sha1[13] << 16 | sha1[14] << 8 | sha1[15];
+ pk->keyid[1] = sha1[16] << 24 | sha1[17] << 16 | sha1[18] << 8 | sha1[19];
rc = 0;
if (pkfnx)
rc = pkfnx(pk, fnxdata);
-cleanup:
+cleanup_sha1:
+ kfree(digest);
+cleanup_tfm:
+ crypto_free_shash(tfm);
+cleanup_pubkey:
ksign_put_public_key(pk);
return rc;
}
#include <asm/errno.h>
#include "local.h"
-#if 0
-#define _debug(FMT, ...) printk(KERN_DEBUG FMT, ##__VA_ARGS__)
-#else
-#define _debug(FMT, ...) do { ; } while (0)
-#endif
+int ksign_debug;
+core_param(ksign_debug, ksign_debug, bool, 0644);
+
+#define _debug(FMT, ...) \
+ do { \
+ if (unlikely(ksign_debug)) \
+ printk(KERN_DEBUG FMT, ##__VA_ARGS__); \
+ } while(0)
/*
* check the signature which is contained in SIG.
*/
static int ksign_signature_check(const struct ksign_signature *sig,
- struct crypto_hash *sha1_tfm)
+ struct shash_desc *digest)
{
struct ksign_public_key *pk;
- struct hash_desc sha1_d;
uint8_t sha1[SHA1_DIGEST_SIZE];
MPI result = NULL;
int rc = 0;
pk->timestamp - sig->timestamp,
pk->timestamp, sig->timestamp);
- sha1_d.tfm = sha1_tfm;
- sha1_d.flags = 0;
-
/* complete the digest */
if (sig->version >= 4)
- SHA1_putc(&sha1_d, sig->version);
- SHA1_putc(&sha1_d, sig->sig_class);
+ SHA1_putc(digest, sig->version);
+ SHA1_putc(digest, sig->sig_class);
if (sig->version < 4) {
u32 a = sig->timestamp;
- SHA1_putc(&sha1_d, (a >> 24) & 0xff);
- SHA1_putc(&sha1_d, (a >> 16) & 0xff);
- SHA1_putc(&sha1_d, (a >> 8) & 0xff);
- SHA1_putc(&sha1_d, (a >> 0) & 0xff);
+ SHA1_putc(digest, (a >> 24) & 0xff);
+ SHA1_putc(digest, (a >> 16) & 0xff);
+ SHA1_putc(digest, (a >> 8) & 0xff);
+ SHA1_putc(digest, (a >> 0) & 0xff);
}
else {
uint8_t buf[6];
size_t n;
- SHA1_putc(&sha1_d, PUBKEY_ALGO_DSA);
- SHA1_putc(&sha1_d, DIGEST_ALGO_SHA1);
+ SHA1_putc(digest, PUBKEY_ALGO_DSA);
+ SHA1_putc(digest, DIGEST_ALGO_SHA1);
if (sig->hashed_data) {
n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
- SHA1_write(&sha1_d, sig->hashed_data, n + 2);
+ SHA1_write(digest, sig->hashed_data, n + 2);
n += 6;
}
else {
buf[3] = n >> 16;
buf[4] = n >> 8;
buf[5] = n;
- SHA1_write(&sha1_d, buf, 6);
+ SHA1_write(digest, buf, 6);
}
-
- crypto_hash_final(&sha1_d, sha1);
- crypto_free_hash(sha1_tfm);
-
+ crypto_shash_final(digest, sha1);
rc = -ENOMEM;
result = mpi_alloc((SHA1_DIGEST_SIZE + BYTES_PER_MPI_LIMB - 1) /
BYTES_PER_MPI_LIMB);
/*
* verify the signature of some data with one of the kernel's known public keys
- * - the SHA1 context should be currently open with the signed data digested
- * into it so that more data can be appended
- * - the SHA1 context is finalised and freed before returning
+ * - the SHA1 digest supplied should have the data to be checked already loaded
+ * in to it
*/
int ksign_verify_signature(const char *sigdata, unsigned sig_size,
- struct crypto_hash *sha1)
+ struct shash_desc *partial_digest)
{
struct ksign_signature *sig = NULL;
- int retval;
+ struct shash_desc *digest = NULL;
+ uint8_t sha1[SHA1_DIGEST_SIZE];
+ void *export_buf = NULL;
+ int retval, loop;
+
+ /* copy the current state of the digest, something that we have to do
+ * by exporting the old state and importing into the new state
+ */
+ export_buf = kmalloc(crypto_shash_statesize(partial_digest->tfm),
+ GFP_KERNEL);
+ if (!export_buf)
+ return -ENOMEM;
+
+ retval = crypto_shash_export(partial_digest, export_buf);
+ if (retval < 0)
+ goto cleanup;
+
+ retval = -ENOMEM;
+ digest = kmalloc(sizeof(*partial_digest) +
+ crypto_shash_descsize(partial_digest->tfm),
+ GFP_KERNEL);
+ if (!digest)
+ goto cleanup;
+
+ digest->tfm = partial_digest->tfm;
+ digest->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ if (ksign_debug) {
+ /* print the partial digest for debugging purposes */
+ retval = crypto_shash_import(digest, export_buf);
+ if (retval < 0)
+ goto cleanup;
+
+ crypto_shash_final(digest, sha1);
+ printk(KERN_WARNING "Modsign digest: ");
+ for (loop = 0; loop < sizeof(sha1); loop++)
+ printk("%02x", sha1[loop]);
+ printk("\n");
+ }
+
+ retval = crypto_shash_import(digest, export_buf);
+ if (retval < 0)
+ goto cleanup;
+
+ kfree(export_buf);
+ export_buf = NULL;
/* parse the signature data to get the actual signature */
retval = ksign_parse_packets(sigdata, sig_size,
if (!sig) {
printk(KERN_NOTICE
"Couldn't find valid DSA signature in module\n");
- return -ENOENT;
+ retval = -ENOENT;
+ goto cleanup;
}
_debug("signature keyid: %08x%08x ver=%u\n",
sig->keyid[0], sig->keyid[1], sig->version);
/* check the data SHA1 transformation against the public key */
- retval = ksign_signature_check(sig, sha1);
+ retval = ksign_signature_check(sig, digest);
switch (retval) {
case 0:
_debug("ksign: Signature check succeeded\n");
_debug("ksign: Signature check ENOMEM\n");
break;
default:
- _debug("ksign: Signature check failed\n");
+ _debug("ksign: Signature check failed: %d\n", retval);
if (retval != -ENOKEY)
retval = -EKEYREJECTED;
break;
}
- cleanup:
+cleanup:
if (sig)
ksign_free_signature(sig);
-
+ kfree(export_buf);
+ kfree(digest);
return retval;
}
* - we _know_ the data is locked into kernel memory, so we don't want to have
* to kmap() it
*/
-static inline void SHA1_putc(struct hash_desc *sha1, uint8_t ch)
+static inline void SHA1_putc(struct shash_desc *digest, uint8_t ch)
{
- struct scatterlist sg;
-
- sg_init_one(&sg, &ch, 1);
- crypto_hash_update(sha1, &sg, 1);
+ crypto_shash_update(digest, &ch, 1);
}
-static inline void SHA1_write(struct hash_desc *sha1, const void *s, size_t n)
+static inline void SHA1_write(struct shash_desc *digest, const void *s, size_t n)
{
- struct scatterlist sg;
-
- sg_init_one(&sg, s, n);
- crypto_hash_update(sha1, &sg, n);
+ crypto_shash_update(digest, s, n);
}
};
#ifdef CONFIG_64BIT
+#define MODULES_ARE_ELF64
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Rel Elf64_Rel
+#define Elf_Rela Elf64_Rela
+#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
+#define ELF_R_SYM(X) ELF64_R_SYM(X)
#else
+#define MODULES_ARE_ELF32
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Rel Elf32_Rel
+#define Elf_Rela Elf32_Rela
+#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
+#define ELF_R_SYM(X) ELF32_R_SYM(X)
#endif
#endif /* __ASM_GENERIC_MODULE_H */
#ifndef _LINUX_CRYPTO_KSIGN_H
#define _LINUX_CRYPTO_KSIGN_H
-#include <linux/types.h>
-
#ifdef CONFIG_CRYPTO_SIGNATURE
+
+#include <crypto/hash.h>
+
extern int ksign_verify_signature(const char *sig, unsigned sig_size,
- struct crypto_hash *sha1);
+ struct shash_desc *digest);
#endif
#endif /* _LINUX_CRYPTO_KSIGN_H */
#define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc)
#define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc)
-#define ELFNOTE_NAME(name) #name
-#define ELFNOTE_SECTION(name) ".note."#name
+#define ELFNOTE_NAME(name) __stringify(name)
+#define ELFNOTE_SECTION(name) ".note."ELFNOTE_NAME(name)
#endif /* __ASSEMBLER__ */
#endif /* _LINUX_ELFNOTE_H */
#include <linux/slab.h>
#include <linux/elf.h>
#include <linux/ctype.h>
-#include <linux/module-verify.h>
-#include <linux/elf.h>
-#include <linux/module-verify-elf.h>
+#include "module-verify.h"
#if 0
#define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__)
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/elf.h>
-#include <linux/scatterlist.h>
-#include <linux/crypto.h>
#include <linux/crypto/ksign.h>
#include <linux/modsign.h>
-#include <linux/module-verify.h>
-#include <linux/module-verify-elf.h>
+#include "module-verify.h"
-#undef MODSIGN_DEBUG
+int modsign_debug;
+core_param(modsign_debug, modsign_debug, bool, 0644);
-#ifdef MODSIGN_DEBUG
-#define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__)
-#else
-#define _debug(FMT, ...) do {} while (0)
-#endif
+#define _debug(FMT, ...) \
+ do { \
+ if (unlikely(modsign_debug)) \
+ printk(FMT, ##__VA_ARGS__); \
+ } while(0)
#ifdef MODSIGN_DEBUG
#define count_and_csum(C, __p, __n) \
#define crypto_digest_update_data(C, PTR, N) \
do { \
- struct scatterlist sg; \
uint8_t *__p = (uint8_t *)(PTR); \
size_t __n = (N); \
count_and_csum((C), __p, __n); \
- sg_init_one(&sg, __p, __n); \
- crypto_hash_update(&(C)->hash, &sg, __n); \
+ crypto_shash_update((C)->hash, __p, __n); \
} while (0)
-#define crypto_digest_update_val(C, VAL) \
+#define crypto_digest_update_val(C, VAL) \
do { \
- struct scatterlist sg; \
uint8_t *__p = (uint8_t *)&(VAL); \
size_t __n = sizeof(VAL); \
count_and_csum((C), __p, __n); \
- sg_init_one(&sg, __p, __n); \
- crypto_hash_update(&(C)->hash, &sg, __n); \
+ crypto_shash_update((C)->hash, __p, __n); \
} while (0)
static int module_verify_canonicalise(struct module_verify_data *mvdata);
int *_gpgsig_ok)
{
const struct elf_note *note;
+ struct crypto_shash *tfm;
const Elf_Shdr *sechdrs = mvdata->sections;
const char *secstrings = mvdata->secstrings;
const char *sig;
unsigned note_size, sig_size, note_namesz;
- int i, ret;
+ int loop, ret;
- for (i = 1; i < mvdata->nsects; i++) {
- switch (sechdrs[i].sh_type) {
+ _debug("looking for sig section '%s'\n", modsign_note_section);
+
+ for (loop = 1; loop < mvdata->nsects; loop++) {
+ switch (sechdrs[loop].sh_type) {
case SHT_NOTE:
- if (strcmp(mvdata->secstrings + sechdrs[i].sh_name,
+ if (strcmp(mvdata->secstrings + sechdrs[loop].sh_name,
modsign_note_section) == 0)
- mvdata->sig_index = i;
+ mvdata->sig_index = loop;
break;
}
}
/* grab an SHA1 transformation context
* - !!! if this tries to load the sha1.ko module, we will deadlock!!!
*/
- mvdata->hash.tfm = crypto_alloc_hash("sha1", 0, 0);
- if (!mvdata->hash.tfm) {
- printk("Couldn't load module - SHA1 transform unavailable\n");
+ tfm = crypto_alloc_shash("sha1", 0, 0);
+ if (!tfm) {
+ printk(KERN_ERR
+ "Couldn't load module - SHA1 transform unavailable\n");
return -EPERM;
}
- crypto_hash_init(&mvdata->hash);
+ mvdata->hash = kmalloc(sizeof(*mvdata->hash) +
+ crypto_shash_descsize(tfm),
+ GFP_KERNEL);
+ if (!mvdata->hash) {
+ crypto_free_shash(tfm);
+ return -ENOMEM;
+ }
+
+ mvdata->hash->tfm = tfm;
+ mvdata->hash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ ret = crypto_shash_init(mvdata->hash);
+ if (ret < 0) {
+ crypto_free_shash(mvdata->hash->tfm);
+ kfree(mvdata->hash);
+ return -ENOMEM;
+ }
#ifdef MODSIGN_DEBUG
mvdata->xcsum = 0;
#endif
/* load data from each relevant section into the digest */
- for (i = 1; i < mvdata->nsects; i++) {
- unsigned long sh_type = sechdrs[i].sh_type;
- unsigned long sh_info = sechdrs[i].sh_info;
- unsigned long sh_size = sechdrs[i].sh_size;
- unsigned long sh_flags = sechdrs[i].sh_flags;
- const char *sh_name = secstrings + sechdrs[i].sh_name;
- const void *data = mvdata->buffer + sechdrs[i].sh_offset;
-
- if (i == mvdata->sig_index)
- continue;
+ for (loop = 0; loop < mvdata->ncanon; loop++) {
+ int sect = mvdata->canonlist[loop];
+ unsigned long sh_type = sechdrs[sect].sh_type;
+ unsigned long sh_info = sechdrs[sect].sh_info;
+ unsigned long sh_size = sechdrs[sect].sh_size;
+ unsigned long sh_flags = sechdrs[sect].sh_flags;
+ const char *sh_name = secstrings + sechdrs[sect].sh_name;
+ const void *data = mvdata->buffer + sechdrs[sect].sh_offset;
#ifdef MODSIGN_DEBUG
mvdata->csum = 0;
* contents, because the symtab gets changed when sections are
* added or removed */
if (sh_type == SHT_REL || sh_type == SHT_RELA) {
- if (mvdata->canonlist[sh_info]) {
- uint32_t xsh_info = mvdata->canonmap[sh_info];
-
- crypto_digest_update_data(mvdata, sh_name, strlen(sh_name));
- crypto_digest_update_val(mvdata, sechdrs[i].sh_type);
- crypto_digest_update_val(mvdata, sechdrs[i].sh_flags);
- crypto_digest_update_val(mvdata, sechdrs[i].sh_size);
- crypto_digest_update_val(mvdata, sechdrs[i].sh_addralign);
- crypto_digest_update_val(mvdata, xsh_info);
-
- if (sh_type == SHT_RELA)
- ret = extract_elf_rela(
- mvdata, i,
- data,
- sh_size / sizeof(Elf_Rela),
- sh_name);
- else
- ret = extract_elf_rel(
- mvdata, i,
- data,
- sh_size / sizeof(Elf_Rel),
- sh_name);
-
- if (ret < 0)
- goto format_error;
- }
-
+ uint32_t xsh_info = mvdata->canonmap[sh_info];
+
+ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name));
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign);
+ crypto_digest_update_val(mvdata, xsh_info);
+
+ if (sh_type == SHT_RELA)
+ ret = extract_elf_rela(
+ mvdata, sect,
+ data,
+ sh_size / sizeof(Elf_Rela),
+ sh_name);
+ else
+ ret = extract_elf_rel(
+ mvdata, sect,
+ data,
+ sh_size / sizeof(Elf_Rel),
+ sh_name);
+
+ if (ret < 0)
+ goto format_error;
continue;
}
+ /* include the headers of BSS sections */
+ if (sh_type == SHT_NOBITS && sh_flags & SHF_ALLOC) {
+ crypto_digest_update_data(mvdata, sh_name, strlen(sh_name));
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign);
+ goto digested;
+ }
+
/* ignore gcc's build ID section as it seems to get modified by
* the build process */
if (strcmp(sh_name, ".note.gnu.build-id") == 0)
include_section:
crypto_digest_update_data(mvdata, sh_name, strlen(sh_name));
- crypto_digest_update_val(mvdata, sechdrs[i].sh_type);
- crypto_digest_update_val(mvdata, sechdrs[i].sh_flags);
- crypto_digest_update_val(mvdata, sechdrs[i].sh_size);
- crypto_digest_update_val(mvdata, sechdrs[i].sh_addralign);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_type);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_flags);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_size);
+ crypto_digest_update_val(mvdata, sechdrs[sect].sh_addralign);
+
crypto_digest_update_data(mvdata, data, sh_size);
+ digested:
_debug("%08zx %02x digested the %s section, size %ld\n",
mvdata->signed_size, mvdata->csum, sh_name, sh_size);
-
- mvdata->canonlist[i] = 1;
}
_debug("Contributed %zu bytes to the digest (csum 0x%02x)\n",
mvdata->signed_size, mvdata->xcsum);
/* do the actual signature verification */
- ret = ksign_verify_signature(sig, sig_size, mvdata->hash.tfm);
+ ret = ksign_verify_signature(sig, sig_size, mvdata->hash);
+
+ crypto_free_shash(mvdata->hash->tfm);
+ kfree(mvdata->hash);
_debug("verify-sig : %d\n", ret);
return ret;
format_error:
- crypto_free_hash(mvdata->hash.tfm);
+ crypto_free_shash(mvdata->hash->tfm);
+ kfree(mvdata->hash);
format_error_no_free:
printk(KERN_ERR "Module format error encountered\n");
return -ELIBBAD;
/* deal with the case of an unsigned module */
no_signature:
+ _debug("no signature found\n");
if (!signedonly)
return 0;
printk(KERN_ERR "An attempt to load unsigned module was rejected\n");
for (loop = 1; loop < mvdata->nsects; loop++) {
const Elf_Shdr *section = mvdata->sections + loop;
- if (loop != mvdata->sig_index) {
- /* we only need to canonicalise allocatable sections */
- if (section->sh_flags & SHF_ALLOC)
- mvdata->canonlist[canon++] = loop;
- }
+ if (loop == mvdata->sig_index)
+ continue;
+
+ /* we only need to canonicalise allocatable sections */
+ if (section->sh_flags & SHF_ALLOC)
+ mvdata->canonlist[canon++] = loop;
+ else if ((section->sh_type == SHT_REL ||
+ section->sh_type == SHT_RELA) &&
+ mvdata->sections[section->sh_info].sh_flags & SHF_ALLOC)
+ mvdata->canonlist[canon++] = loop;
}
/* canonicalise the index numbers of the contributing section */
for (loop = 0; loop < canon; loop++)
mvdata->canonmap[mvdata->canonlist[loop]] = loop + 1;
-
+ mvdata->ncanon = canon;
return 0;
}
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/module-verify.h>
+#include <linux/fips.h>
+#include "module-verify.h"
/*
* verify a module's integrity
}
ret = module_verify_signature(&mvdata, _gpgsig_ok);
+#ifdef CONFIG_CRYPTO_FIPS
+ if (ret < 0 && fips_enabled)
+ panic("Module verification failed with error %d in FIPS mode\n",
+ ret);
+#endif
error:
kfree(mvdata.secsizes);
*/
#include <linux/types.h>
-#include <linux/crypto.h>
+#include <crypto/hash.h>
#include <asm/module.h>
#ifdef CONFIG_MODULE_VERIFY
struct module_verify_data {
- struct hash_desc hash; /* module signature digest */
+ struct shash_desc *hash; /* module signature digest (SHA1) */
const void *buffer; /* module buffer */
const Elf_Ehdr *hdr; /* ELF header */
const Elf_Shdr *sections; /* ELF section table */
size_t signed_size; /* count of bytes contributed to digest */
int *canonlist; /* list of canonicalised sections */
int *canonmap; /* section canonicalisation map */
+ int ncanon; /* number of canonicalised sections */
int sig_index; /* module signature section index */
uint8_t xcsum; /* checksum of bytes contributed to digest */
uint8_t csum; /* checksum of bytes representing a section */
#include <linux/jump_label.h>
#include <linux/pfn.h>
#include <linux/bsearch.h>
-#include <linux/module-verify.h>
+#include "module-verify.h"
#define CREATE_TRACE_POINTS
#include <trace/events/module.h>
$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
$(call if_changed,ld_ko_unsigned_o)
-targets += $(modules)
+targets += $(modules:.ko=.ko.unsigned)
# Step 7), sign the modules
MODSECKEY = ./kernel.sec
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)
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/mod/modsign-note.sh $@.digest.sig | \
+ sh $(SCRIPTS_DIR)/mod/modsign-note.sh $@.digest.sig | \
$(CC) -x assembler-with-cpp $(c_flags) $(CFLAGS_MODULE) -c -o $@.note.o - && \
- $(LD) -r -o $@ $< $@.note.o
+ $(LD) -r $(LDFLAGS) -o $@ $< $@.note.o
else
quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
cmd_sign_ko_ko_unsigned = \
void (*set64)(uint64_t *, uint64_t);
};
-uint16_t get16_le(const uint16_t *p) { return __le16_to_cpu(*p); }
-uint32_t get32_le(const uint32_t *p) { return __le32_to_cpu(*p); }
-uint64_t get64_le(const uint64_t *p) { return __le64_to_cpu(*p); }
-uint16_t get16_be(const uint16_t *p) { return __be16_to_cpu(*p); }
-uint32_t get32_be(const uint32_t *p) { return __be32_to_cpu(*p); }
-uint64_t get64_be(const uint64_t *p) { return __be64_to_cpu(*p); }
-
-void set16_le(uint16_t *p, uint16_t n) { *p = __cpu_to_le16(n); }
-void set32_le(uint32_t *p, uint32_t n) { *p = __cpu_to_le32(n); }
-void set64_le(uint64_t *p, uint64_t n) { *p = __cpu_to_le64(n); }
-void set16_be(uint16_t *p, uint16_t n) { *p = __cpu_to_be16(n); }
-void set32_be(uint32_t *p, uint32_t n) { *p = __cpu_to_be32(n); }
-void set64_be(uint64_t *p, uint64_t n) { *p = __cpu_to_be64(n); }
-
-const struct byteorder byteorder_le = {
+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
};
-const struct byteorder byteorder_be = {
+static const struct byteorder byteorder_be = {
get16_be, get32_be, get64_be,
set16_be, set32_be, set64_be
};
-const struct byteorder *order;
+static const struct byteorder *order;
-uint16_t get16(const uint16_t *p) { return order->get16(p); }
-uint32_t get32(const uint32_t *p) { return order->get32(p); }
-uint64_t get64(const uint64_t *p) { return order->get64(p); }
-void set16(uint16_t *p, uint16_t n) { order->set16(p, n); }
-void set32(uint32_t *p, uint32_t n) { order->set32(p, n); }
-void set64(uint64_t *p, uint64_t n) { order->set64(p, n); }
+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); }
-FILE *outfd;
-uint8_t csum, xcsum;
+static FILE *outfd;
+static uint8_t csum, xcsum;
static void write_out(const void *data, size_t size)
{
set32(&relocation.r_type, ELF64_R_TYPE(r_info));
if (ELF64_R_SYM(r_info) >= nsyms) {
- fprintf(stderr, "Invalid symbol ID %lx in relocation %zu\n",
- ELF64_R_SYM(r_info), loop);
+ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n",
+ (size_t)ELF64_R_SYM(r_info), loop);
exit(1);
}
set32(&relocation.r_type, ELF64_R_TYPE(r_info));
if (ELF64_R_SYM(r_info) >= nsyms) {
- fprintf(stderr, "Invalid symbol ID %lx in relocation %zi\n",
- ELF64_R_SYM(r_info), loop);
+ fprintf(stderr, "Invalid symbol ID %zx in relocation %zu\n",
+ (size_t)ELF64_R_SYM(r_info), loop);
exit(1);
}
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;
/* 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) {
}
}
- memset(canonlist, 0, sizeof(int) * shnum);
-
/* iterate through the section table looking for sections we want to
* contribute to the signature */
verbose("\n");
- verbose("FILE POS CS SECT NAME\n");
- verbose("======== == ==== ==============================\n");
-
- 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);
+ 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"
exit(3);
}
- if (canonlist[sh_info]) {
- Elf32_Word xsh_info;
-
- verbose("%08lx ", ftell(outfd));
-
- set32(&xsh_info, canonmap[sh_info]);
-
- /* write out selected portions of the section
- * header */
- write_out(sh_name, strlen(sh_name));
- write_out_val(sections[loop].sh_type);
- write_out_val(sections[loop].sh_flags);
- write_out_val(sections[loop].sh_size);
- write_out_val(sections[loop].sh_addralign);
- write_out_val(xsh_info);
-
- if (sh_type == SHT_RELA)
- extract_elf64_rela(buffer, loop, sh_info,
- data, sh_size / sizeof(Elf64_Rela),
- symbols, nsyms,
- sections, shnum, canonmap,
- strings, nstrings,
- sh_name);
- else
- extract_elf64_rel(buffer, loop, sh_info,
- data, sh_size / sizeof(Elf64_Rel),
- symbols, nsyms,
- sections, shnum, canonmap,
- strings, nstrings,
- sh_name);
- }
-
+ 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);
+ }
+
/* ignore gcc's build ID section as it seems to get modified by
* the build process */
if (strcmp(sh_name, ".note.gnu.build-id") == 0)
continue;
include_section:
- verbose("%08lx ", ftell(outfd));
+ 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[loop].sh_type);
- write_out_val(sections[loop].sh_flags);
- write_out_val(sections[loop].sh_size);
- write_out_val(sections[loop].sh_addralign);
+ 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, loop, sh_name);
-
- /* note the section has been written */
- canonlist[loop] = 1;
+ verbose("%02x %4d %s\n", csum, sect, sh_name);
}
verbose("%08lx (%lu bytes csum 0x%02x)\n",
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;
/* 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) {
}
}
- memset(canonlist, 0, sizeof(int) * shnum);
-
/* iterate through the section table looking for sections we want to
* contribute to the signature */
verbose("\n");
- verbose("FILE POS CS SECT NAME\n");
- verbose("======== == ==== ==============================\n");
-
- 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);
- Elf32_Word sh_info = get32(§ions[loop].sh_info);
- Elf32_Off sh_offset = get32(§ions[loop].sh_offset);
+ 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;
/* 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"
exit(3);
}
- if (canonlist[sh_info]) {
- Elf32_Word xsh_info;
-
- verbose("%08lx ", ftell(outfd));
-
- set32(&xsh_info, canonmap[sh_info]);
-
- /* write out selected portions of the section header */
- write_out(sh_name, strlen(sh_name));
- write_out_val(sections[loop].sh_type);
- write_out_val(sections[loop].sh_flags);
- write_out_val(sections[loop].sh_size);
- write_out_val(sections[loop].sh_addralign);
- write_out_val(xsh_info);
-
- if (sh_type == SHT_RELA)
- extract_elf32_rela(buffer, loop, sh_info,
- data, sh_size / sizeof(Elf32_Rela),
- symbols, nsyms,
- sections, shnum, canonmap,
- strings, nstrings,
- sh_name);
- else
- extract_elf32_rel(buffer, loop, sh_info,
- data, sh_size / sizeof(Elf32_Rel),
- symbols, nsyms,
- sections, shnum, canonmap,
- strings, nstrings,
- sh_name);
- }
-
+ 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);
+ }
+
/* ignore gcc's build ID section as it seems to get modified by
* the build process */
if (strcmp(sh_name, ".note.gnu.build-id") == 0)
continue;
include_section:
- verbose("%08lx ", ftell(outfd));
+ 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[loop].sh_type);
- write_out_val(sections[loop].sh_flags);
- write_out_val(sections[loop].sh_size);
- write_out_val(sections[loop].sh_addralign);
+ 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, loop, sh_name);
-
- /* note the section has been written */
- canonlist[loop] = 1;
+ verbose("%02x %4d %s\n", csum, sect, sh_name);
}
verbose("%08lx (%lu bytes csum 0x%02x)\n",
# get rid of unwanted files resulting from patch fuzz
find . \( -name "*.orig" -o -name "*~" \) -exec rm -f {} \; >/dev/null
%if %{signmodules}
- cp %{SOURCE19} .
- pwd
- gpg --homedir . --batch --gen-key %{SOURCE11}
-# if there're external keys to be included
- if [ -s %{SOURCE19} ]; then
- gpg --homedir . --no-default-keyring --keyring kernel.pub --import %{SOURCE19}
- fi
- gpg --homedir . --export --keyring kernel.pub Oracle > extract.pub
- gcc -o scripts/bin2c scripts/bin2c.c
- scripts/bin2c ksign_def_public_key __initdata < extract.pub >crypto/signature/key.h
-%endif
-
+cp %{SOURCE19} .
+cat <<EOF
+###
+### Now generating a PGP key pair to be used for signing modules.
+###
+### If this takes a long time, you might wish to run rngd in the background to
+### keep the supply of entropy topped up. It needs to be run as root, and
+### should use a hardware random number generator if one is available, eg:
+###
+### rngd -r /dev/hwrandom
+###
+### If one isn't available, the pseudo-random number generator can be used:
+###
+### rngd -r /dev/urandom
+###
+EOF
+gpg --homedir . --batch --gen-key %{SOURCE11}
+cat <<EOF
+###
+### Key pair generated.
+###
+EOF
-cd ..
+if [ -s %{SOURCE19} ]; then
+ gpg --homedir . --no-default-keyring --keyring kernel.pub --import %{SOURCE19}
+fi
+gpg --homedir . --export --keyring ./kernel.pub Oracle > extract.pub
+gcc -o scripts/bin2c scripts/bin2c.c
+scripts/bin2c ksign_def_public_key __initdata <extract.pub >crypto/signature/key.h
+%endif
###
### build
# get rid of unwanted files resulting from patch fuzz
find . \( -name "*.orig" -o -name "*~" \) -exec rm -f {} \; >/dev/null
%if %{signmodules}
- cp %{SOURCE19} .
- pwd
- gpg --homedir . --batch --gen-key %{SOURCE11}
+cp %{SOURCE19} .
+cat <<EOF
+###
+### Now generating a PGP key pair to be used for signing modules.
+###
+### If this takes a long time, you might wish to run rngd in the background to
+### keep the supply of entropy topped up. It needs to be run as root, and
+### should use a hardware random number generator if one is available, eg:
+###
+### rngd -r /dev/hwrandom
+###
+### If one isn't available, the pseudo-random number generator can be used:
+###
+### rngd -r /dev/urandom
+###
+EOF
+gpg --homedir . --batch --gen-key %{SOURCE11}
+cat <<EOF
+###
+### Key pair generated.
+###
+EOF
# if there're external keys to be included
- if [ -s %{SOURCE19} ]; then
- gpg --homedir . --no-default-keyring --keyring kernel.pub --import %{SOURCE19}
- fi
- gpg --homedir . --export --keyring kernel.pub Oracle > extract.pub
- gcc -o scripts/bin2c scripts/bin2c.c
- scripts/bin2c ksign_def_public_key __initdata < extract.pub >crypto/signature/key.h
+if [ -s %{SOURCE19} ]; then
+ gpg --homedir . --no-default-keyring --keyring kernel.pub --import %{SOURCE19}
+fi
+gpg --homedir . --export --keyring ./kernel.pub Oracle > extract.pub
+gcc -o scripts/bin2c scripts/bin2c.c
+scripts/bin2c ksign_def_public_key __initdata <extract.pub >crypto/signature/key.h
%endif
-
-
-cd ..
###
### build