History

Merge branch 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity

Pull integrity updates from Mimi Zohar: "The major feature in this time is IMA support for measuring and appraising appended file signatures. In addition are a couple of bug fixes and code cleanup to use struct_size(). In addition to the PE/COFF and IMA xattr signatures, the kexec kernel image may be signed with an appended signature, using the same scripts/sign-file tool that is used to sign kernel modules. Similarly, the initramfs may contain an appended signature. This contained a lot of refactoring of the existing appended signature verification code, so that IMA could retain the existing framework of calculating the file hash once, storing it in the IMA measurement list and extending the TPM, verifying the file's integrity based on a file hash or signature (eg. xattrs), and adding an audit record containing the file hash, all based on policy. (The IMA support for appended signatures patch set was posted and reviewed 11 times.) The support for appended signature paves the way for adding other signature verification methods, such as fs-verity, based on a single system-wide policy. The file hash used for verifying the signature and the signature, itself, can be included in the IMA measurement list" * 'next-integrity' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity: ima: ima_api: Use struct_size() in kzalloc() ima: use struct_size() in kzalloc() sefltest/ima: support appended signatures (modsig) ima: Fix use after free in ima_read_modsig() MODSIGN: make new include file self contained ima: fix freeing ongoing ahash_request ima: always return negative code for error ima: Store the measurement again when appraising a modsig ima: Define ima-modsig template ima: Collect modsig ima: Implement support for module-style appended signatures ima: Factor xattr_verify() out of ima_appraise_measurement() ima: Add modsig appraise_type option for module-style appended signatures integrity: Select CONFIG_KEYS instead of depending on it PKCS#7: Introduce pkcs7_get_digest() PKCS#7: Refactor verify_pkcs7_signature() MODSIGN: Export module signature definitions ima: initialize the "template" field with the default template

Linus Torvalds committed 7 years ago

Commit f1f2f612 parents 298fb76 2a7f0e532 files · +871 −203Browse files

Unified · Split

32 files
  1. Documentation/ABI/testing/ima_policy +5 −1
  2. Documentation/security/IMA-templates.rst +3 −0
  3. arch/s390/Kconfig +1 −1
  4. arch/s390/kernel/machine_kexec_file.c +1 −23
  5. certs/system_keyring.c +45 −16
  6. crypto/asymmetric_keys/pkcs7_verify.c +33 −0
  7. include/crypto/pkcs7.h +4 −0
  8. include/linux/module.h +0 −3
  9. include/linux/module_signature.h +46 −0
  10. include/linux/verification.h +10 −0
  11. init/Kconfig +5 −1
  12. kernel/Makefile +1 −0
  13. kernel/module.c +1 −0
  14. kernel/module_signature.c +46 −0
  15. kernel/module_signing.c +8 −48
  16. scripts/Makefile +1 −1
  17. security/integrity/Kconfig +1 −1
  18. security/integrity/digsig.c +34 −9
  19. security/integrity/ima/Kconfig +13 −0
  20. security/integrity/ima/Makefile +1 −0
  21. security/integrity/ima/ima.h +56 −4
  22. security/integrity/ima/ima_api.c +21 −6
  23. security/integrity/ima/ima_appraise.c +129 −65
  24. security/integrity/ima/ima_crypto.c +9 −1
  25. security/integrity/ima/ima_main.c +20 −4
  26. security/integrity/ima/ima_modsig.c +168 −0
  27. security/integrity/ima/ima_policy.c +61 −10
  28. security/integrity/ima/ima_template.c +27 −4
  29. security/integrity/ima/ima_template_lib.c +63 −1
  30. security/integrity/ima/ima_template_lib.h +4 −0
  31. security/integrity/integrity.h +20 −0
  32. tools/testing/selftests/kexec/test_kexec_file_load.sh +34 −4
Documentation/ABI/testing/ima_policy+5−1
@@ -37,7 +37,7 @@ Description: · 36 unmodified lines
3737 euid:= decimal value
3838 fowner:= decimal value
3939 lsm: are LSM specific
40− option: appraise_type:= [imasig]
40+ option: appraise_type:= [imasig] [imasig|modsig]
4141 template:= name of a defined IMA template type
4242 (eg, ima-ng). Only valid when action is "measure".
4343 pcr:= decimal value
@@ -105,3 +105,7 @@ Description: · 61 unmodified lines
105105
106106 measure func=KEXEC_KERNEL_CHECK pcr=4
107107 measure func=KEXEC_INITRAMFS_CHECK pcr=5
108+
109+ Example of appraise rule allowing modsig appended signatures:
110+
111+ appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig|modsig
Documentation/security/IMA-templates.rst+3−0
@@ -68,8 +68,10 @@ descriptors by adding their identifier to the format string · 67 unmodified lines
6868 - 'd-ng': the digest of the event, calculated with an arbitrary hash
6969 algorithm (field format: [<hash algo>:]digest, where the digest
7070 prefix is shown only if the hash algorithm is not SHA1 or MD5);
71+ - 'd-modsig': the digest of the event without the appended modsig;
7172 - 'n-ng': the name of the event, without size limitations;
7273 - 'sig': the file signature;
74+ - 'modsig' the appended file signature;
7375 - 'buf': the buffer data that was used to generate the hash without size limitations;
7476
7577
@@ -79,6 +81,7 @@ Below, there is the list of defined template descriptors: · 3 unmodified lines
7981 - "ima-ng" (default): its format is ``d-ng|n-ng``;
8082 - "ima-sig": its format is ``d-ng|n-ng|sig``;
8183 - "ima-buf": its format is ``d-ng|n-ng|buf``;
84+ - "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
8285
8386
8487 Use
arch/s390/Kconfig+1−1
@@ -556,7 +556,7 @@ config ARCH_HAS_KEXEC_PURGATORY · 555 unmodified lines
556556
557557 config KEXEC_VERIFY_SIG
558558 bool "Verify kernel signature during kexec_file_load() syscall"
559− depends on KEXEC_FILE && SYSTEM_DATA_VERIFICATION
559+ depends on KEXEC_FILE && MODULE_SIG_FORMAT
560560 help
561561 This option makes kernel signature verification mandatory for
562562 the kexec_file_load() syscall.
arch/s390/kernel/machine_kexec_file.c+1−23
@@ -10,7 +10,7 @@ · 9 unmodified lines
1010 #include <linux/elf.h>
1111 #include <linux/errno.h>
1212 #include <linux/kexec.h>
13−#include <linux/module.h>
13+#include <linux/module_signature.h>
1414 #include <linux/verification.h>
1515 #include <asm/boot_data.h>
1616 #include <asm/ipl.h>
@@ -23,28 +23,6 @@ const struct kexec_file_ops * const kexec_file_loaders[] = { · 6 unmodified lines
2323 };
2424
2525 #ifdef CONFIG_KEXEC_VERIFY_SIG
26−/*
27− * Module signature information block.
28− *
29− * The constituents of the signature section are, in order:
30− *
31− * - Signer's name
32− * - Key identifier
33− * - Signature data
34− * - Information block
35− */
36−struct module_signature {
37− u8 algo; /* Public-key crypto algorithm [0] */
38− u8 hash; /* Digest algorithm [0] */
39− u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
40− u8 signer_len; /* Length of signer's name [0] */
41− u8 key_id_len; /* Length of key identifier [0] */
42− u8 __pad[3];
43− __be32 sig_len; /* Length of signature data */
44−};
45−
46−#define PKEY_ID_PKCS7 2
47−
4826 int s390_verify_sig(const char *kernel, unsigned long kernel_len)
4927 {
5028 const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
certs/system_keyring.c+45−16
@@ -190,33 +190,27 @@ late_initcall(load_system_certificate_list); · 189 unmodified lines
190190 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
191191
192192 /**
193− * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
193+ * verify_pkcs7_message_sig - Verify a PKCS#7-based signature on system data.
194194 * @data: The data to be verified (NULL if expecting internal data).
195195 * @len: Size of @data.
196− * @raw_pkcs7: The PKCS#7 message that is the signature.
197− * @pkcs7_len: The size of @raw_pkcs7.
196+ * @pkcs7: The PKCS#7 message that is the signature.
198197 * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
199198 * (void *)1UL for all trusted keys).
200199 * @usage: The use to which the key is being put.
201200 * @view_content: Callback to gain access to content.
202201 * @ctx: Context for callback.
203202 */
204−int verify_pkcs7_signature(const void *data, size_t len,
205− const void *raw_pkcs7, size_t pkcs7_len,
206− struct key *trusted_keys,
207− enum key_being_used_for usage,
208− int (*view_content)(void *ctx,
209− const void *data, size_t len,
210− size_t asn1hdrlen),
211− void *ctx)
203+int verify_pkcs7_message_sig(const void *data, size_t len,
204+ struct pkcs7_message *pkcs7,
205+ struct key *trusted_keys,
206+ enum key_being_used_for usage,
207+ int (*view_content)(void *ctx,
208+ const void *data, size_t len,
209+ size_t asn1hdrlen),
210+ void *ctx)
212211 {
213− struct pkcs7_message *pkcs7;
214212 int ret;
215213
216− pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
217− if (IS_ERR(pkcs7))
218− return PTR_ERR(pkcs7);
219−
220214 /* The data should be detached - so we need to supply it. */
221215 if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
222216 pr_err("PKCS#7 signature with non-detached data\n");
@@ -269,6 +263,41 @@ int verify_pkcs7_signature(const void *data, size_t len, · 46 unmodified lines
269263 }
270264
271265 error:
266+ pr_devel("<==%s() = %d\n", __func__, ret);
267+ return ret;
268+}
269+
270+/**
271+ * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
272+ * @data: The data to be verified (NULL if expecting internal data).
273+ * @len: Size of @data.
274+ * @raw_pkcs7: The PKCS#7 message that is the signature.
275+ * @pkcs7_len: The size of @raw_pkcs7.
276+ * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
277+ * (void *)1UL for all trusted keys).
278+ * @usage: The use to which the key is being put.
279+ * @view_content: Callback to gain access to content.
280+ * @ctx: Context for callback.
281+ */
282+int verify_pkcs7_signature(const void *data, size_t len,
283+ const void *raw_pkcs7, size_t pkcs7_len,
284+ struct key *trusted_keys,
285+ enum key_being_used_for usage,
286+ int (*view_content)(void *ctx,
287+ const void *data, size_t len,
288+ size_t asn1hdrlen),
289+ void *ctx)
290+{
291+ struct pkcs7_message *pkcs7;
292+ int ret;
293+
294+ pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
295+ if (IS_ERR(pkcs7))
296+ return PTR_ERR(pkcs7);
297+
298+ ret = verify_pkcs7_message_sig(data, len, pkcs7, trusted_keys, usage,
299+ view_content, ctx);
300+
272301 pkcs7_free_message(pkcs7);
273302 pr_devel("<==%s() = %d\n", __func__, ret);
274303 return ret;
crypto/asymmetric_keys/pkcs7_verify.c+33−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include <linux/err.h>
1313 #include <linux/asn1.h>
1414 #include <crypto/hash.h>
15+#include <crypto/hash_info.h>
1516 #include <crypto/public_key.h>
1617 #include "pkcs7_parser.h"
1718
@@ -29,6 +30,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, · 11 unmodified lines
2930
3031 kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
3132
33+ /* The digest was calculated already. */
34+ if (sig->digest)
35+ return 0;
36+
3237 if (!sinfo->sig->hash_algo)
3338 return -ENOPKG;
3439
@@ -117,6 +122,34 @@ error_no_desc: · 82 unmodified lines
117122 return ret;
118123 }
119124
125+int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
126+ enum hash_algo *hash_algo)
127+{
128+ struct pkcs7_signed_info *sinfo = pkcs7->signed_infos;
129+ int i, ret;
130+
131+ /*
132+ * This function doesn't support messages with more than one signature.
133+ */
134+ if (sinfo == NULL || sinfo->next != NULL)
135+ return -EBADMSG;
136+
137+ ret = pkcs7_digest(pkcs7, sinfo);
138+ if (ret)
139+ return ret;
140+
141+ *buf = sinfo->sig->digest;
142+ *len = sinfo->sig->digest_size;
143+
144+ for (i = 0; i < HASH_ALGO__LAST; i++)
145+ if (!strcmp(hash_algo_name[i], sinfo->sig->hash_algo)) {
146+ *hash_algo = i;
147+ break;
148+ }
149+
150+ return 0;
151+}
152+
120153 /*
121154 * Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
122155 * uses the issuer's name and the issuing certificate serial number for
include/crypto/pkcs7.h+4−0
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #define _CRYPTO_PKCS7_H
1010
1111 #include <linux/verification.h>
12+#include <linux/hash_info.h>
1213 #include <crypto/public_key.h>
1314
1415 struct key;
@@ -40,4 +41,7 @@ extern int pkcs7_verify(struct pkcs7_message *pkcs7, · 25 unmodified lines
4041 extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
4142 const void *data, size_t datalen);
4243
44+extern int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf,
45+ u32 *len, enum hash_algo *hash_algo);
46+
4347 #endif /* _CRYPTO_PKCS7_H */
include/linux/module.h+0−3
@@ -26,9 +26,6 @@ · 25 unmodified lines
2626 #include <linux/percpu.h>
2727 #include <asm/module.h>
2828
29−/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
30−#define MODULE_SIG_STRING "~Module signature appended~\n"
31−
3229 /* Not Yet Implemented */
3330 #define MODULE_SUPPORTED_DEVICE(name)
3431
include/linux/module_signature.h+46−0
@@ -0,0 +1,46 @@
1+/* SPDX-License-Identifier: GPL-2.0+ */
2+/*
3+ * Module signature handling.
4+ *
5+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
6+ * Written by David Howells (dhowells@redhat.com)
7+ */
8+
9+#ifndef _LINUX_MODULE_SIGNATURE_H
10+#define _LINUX_MODULE_SIGNATURE_H
11+
12+#include <linux/types.h>
13+
14+/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
15+#define MODULE_SIG_STRING "~Module signature appended~\n"
16+
17+enum pkey_id_type {
18+ PKEY_ID_PGP, /* OpenPGP generated key ID */
19+ PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
20+ PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
21+};
22+
23+/*
24+ * Module signature information block.
25+ *
26+ * The constituents of the signature section are, in order:
27+ *
28+ * - Signer's name
29+ * - Key identifier
30+ * - Signature data
31+ * - Information block
32+ */
33+struct module_signature {
34+ u8 algo; /* Public-key crypto algorithm [0] */
35+ u8 hash; /* Digest algorithm [0] */
36+ u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
37+ u8 signer_len; /* Length of signer's name [0] */
38+ u8 key_id_len; /* Length of key identifier [0] */
39+ u8 __pad[3];
40+ __be32 sig_len; /* Length of signature data */
41+};
42+
43+int mod_check_sig(const struct module_signature *ms, size_t file_len,
44+ const char *name);
45+
46+#endif /* _LINUX_MODULE_SIGNATURE_H */
include/linux/verification.h+10−0
@@ -32,6 +32,7 @@ extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; · 31 unmodified lines
3232 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
3333
3434 struct key;
35+struct pkcs7_message;
3536
3637 extern int verify_pkcs7_signature(const void *data, size_t len,
3738 const void *raw_pkcs7, size_t pkcs7_len,
@@ -41,6 +42,15 @@ extern int verify_pkcs7_signature(const void *data, size_t len, · 3 unmodified lines
4142 const void *data, size_t len,
4243 size_t asn1hdrlen),
4344 void *ctx);
45+extern int verify_pkcs7_message_sig(const void *data, size_t len,
46+ struct pkcs7_message *pkcs7,
47+ struct key *trusted_keys,
48+ enum key_being_used_for usage,
49+ int (*view_content)(void *ctx,
50+ const void *data,
51+ size_t len,
52+ size_t asn1hdrlen),
53+ void *ctx);
4454
4555 #ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
4656 extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
init/Kconfig+5−1
@@ -1963,6 +1963,10 @@ config BASE_SMALL · 1962 unmodified lines
19631963 default 0 if BASE_FULL
19641964 default 1 if !BASE_FULL
19651965
1966+config MODULE_SIG_FORMAT
1967+ def_bool n
1968+ select SYSTEM_DATA_VERIFICATION
1969+
19661970 menuconfig MODULES
19671971 bool "Enable loadable module support"
19681972 option modules
@@ -2047,7 +2051,7 @@ config MODULE_SRCVERSION_ALL · 78 unmodified lines
20472051
20482052 config MODULE_SIG
20492053 bool "Module signature verification"
2050− select SYSTEM_DATA_VERIFICATION
2054+ select MODULE_SIG_FORMAT
20512055 help
20522056 Check modules for valid signatures upon load: the signature
20532057 is simply appended to the module. For more information see
kernel/Makefile+1−0
@@ -58,6 +58,7 @@ endif · 57 unmodified lines
5858 obj-$(CONFIG_UID16) += uid16.o
5959 obj-$(CONFIG_MODULES) += module.o
6060 obj-$(CONFIG_MODULE_SIG) += module_signing.o
61+obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signature.o
6162 obj-$(CONFIG_KALLSYMS) += kallsyms.o
6263 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
6364 obj-$(CONFIG_CRASH_CORE) += crash_core.o
kernel/module.c+1−0
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 #include <linux/export.h>
88 #include <linux/extable.h>
99 #include <linux/moduleloader.h>
10+#include <linux/module_signature.h>
1011 #include <linux/trace_events.h>
1112 #include <linux/init.h>
1213 #include <linux/kallsyms.h>
kernel/module_signature.c+46−0
@@ -0,0 +1,46 @@
1+// SPDX-License-Identifier: GPL-2.0+
2+/*
3+ * Module signature checker
4+ *
5+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
6+ * Written by David Howells (dhowells@redhat.com)
7+ */
8+
9+#include <linux/errno.h>
10+#include <linux/printk.h>
11+#include <linux/module_signature.h>
12+#include <asm/byteorder.h>
13+
14+/**
15+ * mod_check_sig - check that the given signature is sane
16+ *
17+ * @ms: Signature to check.
18+ * @file_len: Size of the file to which @ms is appended.
19+ * @name: What is being checked. Used for error messages.
20+ */
21+int mod_check_sig(const struct module_signature *ms, size_t file_len,
22+ const char *name)
23+{
24+ if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms))
25+ return -EBADMSG;
26+
27+ if (ms->id_type != PKEY_ID_PKCS7) {
28+ pr_err("%s: Module is not signed with expected PKCS#7 message\n",
29+ name);
30+ return -ENOPKG;
31+ }
32+
33+ if (ms->algo != 0 ||
34+ ms->hash != 0 ||
35+ ms->signer_len != 0 ||
36+ ms->key_id_len != 0 ||
37+ ms->__pad[0] != 0 ||
38+ ms->__pad[1] != 0 ||
39+ ms->__pad[2] != 0) {
40+ pr_err("%s: PKCS#7 signature info has unexpected non-zero params\n",
41+ name);
42+ return -EBADMSG;
43+ }
44+
45+ return 0;
46+}
kernel/module_signing.c+8−48
@@ -7,37 +7,13 @@ · 6 unmodified lines
77
88 #include <linux/kernel.h>
99 #include <linux/errno.h>
10+#include <linux/module.h>
11+#include <linux/module_signature.h>
1012 #include <linux/string.h>
1113 #include <linux/verification.h>
1214 #include <crypto/public_key.h>
1315 #include "module-internal.h"
1416
15−enum pkey_id_type {
16− PKEY_ID_PGP, /* OpenPGP generated key ID */
17− PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
18− PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
19−};
20−
21−/*
22− * Module signature information block.
23− *
24− * The constituents of the signature section are, in order:
25− *
26− * - Signer's name
27− * - Key identifier
28− * - Signature data
29− * - Information block
30− */
31−struct module_signature {
32− u8 algo; /* Public-key crypto algorithm [0] */
33− u8 hash; /* Digest algorithm [0] */
34− u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */
35− u8 signer_len; /* Length of signer's name [0] */
36− u8 key_id_len; /* Length of key identifier [0] */
37− u8 __pad[3];
38− __be32 sig_len; /* Length of signature data */
39−};
40−
4117 /*
4218 * Verify the signature on a module.
4319 */
@@ -45,6 +21,7 @@ int mod_verify_sig(const void *mod, struct load_info *info) · 1 unmodified line
4521 {
4622 struct module_signature ms;
4723 size_t sig_len, modlen = info->len;
24+ int ret;
4825
4926 pr_devel("==>%s(,%zu)\n", __func__, modlen);
5027
@@ -52,32 +29,15 @@ int mod_verify_sig(const void *mod, struct load_info *info) · 1 unmodified line
5229 return -EBADMSG;
5330
5431 memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
55− modlen -= sizeof(ms);
32+
33+ ret = mod_check_sig(&ms, modlen, info->name);
34+ if (ret)
35+ return ret;
5636
5737 sig_len = be32_to_cpu(ms.sig_len);
58− if (sig_len >= modlen)
59− return -EBADMSG;
60− modlen -= sig_len;
38+ modlen -= sig_len + sizeof(ms);
6139 info->len = modlen;
6240
63− if (ms.id_type != PKEY_ID_PKCS7) {
64− pr_err("%s: Module is not signed with expected PKCS#7 message\n",
65− info->name);
66− return -ENOPKG;
67− }
68−
69− if (ms.algo != 0 ||
70− ms.hash != 0 ||
71− ms.signer_len != 0 ||
72− ms.key_id_len != 0 ||
73− ms.__pad[0] != 0 ||
74− ms.__pad[1] != 0 ||
75− ms.__pad[2] != 0) {
76− pr_err("%s: PKCS#7 signature info has unexpected non-zero params\n",
77− info->name);
78− return -EBADMSG;
79− }
80−
8141 return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
8242 VERIFY_USE_SECONDARY_KEYRING,
8343 VERIFYING_MODULE_SIGNATURE,
scripts/Makefile+1−1
@@ -17,7 +17,7 @@ hostprogs-$(CONFIG_VT) += conmakehash · 16 unmodified lines
1717 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
1818 hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
1919 hostprogs-$(CONFIG_ASN1) += asn1_compiler
20−hostprogs-$(CONFIG_MODULE_SIG) += sign-file
20+hostprogs-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
2121 hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
2222 hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
2323
security/integrity/Kconfig+1−1
@@ -18,8 +18,8 @@ if INTEGRITY · 17 unmodified lines
1818
1919 config INTEGRITY_SIGNATURE
2020 bool "Digital signature verification using multiple keyrings"
21− depends on KEYS
2221 default n
22+ select KEYS
2323 select SIGNATURE
2424 help
2525 This option enables digital signature verification support
security/integrity/digsig.c+34−9
@@ -39,11 +39,10 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = { · 38 unmodified lines
3939 #define restrict_link_to_ima restrict_link_by_builtin_trusted
4040 #endif
4141
42−int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
43− const char *digest, int digestlen)
42+static struct key *integrity_keyring_from_id(const unsigned int id)
4443 {
45− if (id >= INTEGRITY_KEYRING_MAX || siglen < 2)
46− return -EINVAL;
44+ if (id >= INTEGRITY_KEYRING_MAX)
45+ return ERR_PTR(-EINVAL);
4746
4847 if (!keyring[id]) {
4948 keyring[id] =
@@ -52,23 +51,49 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, · 2 unmodified lines
5251 int err = PTR_ERR(keyring[id]);
5352 pr_err("no %s keyring: %d\n", keyring_name[id], err);
5453 keyring[id] = NULL;
55− return err;
54+ return ERR_PTR(err);
5655 }
5756 }
5857
58+ return keyring[id];
59+}
60+
61+int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
62+ const char *digest, int digestlen)
63+{
64+ struct key *keyring;
65+
66+ if (siglen < 2)
67+ return -EINVAL;
68+
69+ keyring = integrity_keyring_from_id(id);
70+ if (IS_ERR(keyring))
71+ return PTR_ERR(keyring);
72+
5973 switch (sig[1]) {
6074 case 1:
6175 /* v1 API expect signature without xattr type */
62− return digsig_verify(keyring[id], sig + 1, siglen - 1,
63− digest, digestlen);
76+ return digsig_verify(keyring, sig + 1, siglen - 1, digest,
77+ digestlen);
6478 case 2:
65− return asymmetric_verify(keyring[id], sig, siglen,
66− digest, digestlen);
79+ return asymmetric_verify(keyring, sig, siglen, digest,
80+ digestlen);
6781 }
6882
6983 return -EOPNOTSUPP;
7084 }
7185
86+int integrity_modsig_verify(const unsigned int id, const struct modsig *modsig)
87+{
88+ struct key *keyring;
89+
90+ keyring = integrity_keyring_from_id(id);
91+ if (IS_ERR(keyring))
92+ return PTR_ERR(keyring);
93+
94+ return ima_modsig_verify(keyring, modsig);
95+}
96+
7297 static int __init __integrity_init_keyring(const unsigned int id,
7398 key_perm_t perm,
7499 struct key_restriction *restriction)
security/integrity/ima/Kconfig+13−0
@@ -233,6 +233,19 @@ config IMA_APPRAISE_BOOTPARAM · 232 unmodified lines
233233 This option enables the different "ima_appraise=" modes
234234 (eg. fix, log) from the boot command line.
235235
236+config IMA_APPRAISE_MODSIG
237+ bool "Support module-style signatures for appraisal"
238+ depends on IMA_APPRAISE
239+ depends on INTEGRITY_ASYMMETRIC_KEYS
240+ select PKCS7_MESSAGE_PARSER
241+ select MODULE_SIG_FORMAT
242+ default n
243+ help
244+ Adds support for signatures appended to files. The format of the
245+ appended signature is the same used for signed kernel modules.
246+ The modsig keyword can be used in the IMA policy to allow a hook
247+ to accept such signatures.
248+
236249 config IMA_TRUSTED_KEYRING
237250 bool "Require all keys on the .ima keyring be signed (deprecated)"
238251 depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
security/integrity/ima/Makefile+1−0
@@ -9,5 +9,6 @@ obj-$(CONFIG_IMA) += ima.o · 8 unmodified lines
99 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
1010 ima_policy.o ima_template.o ima_template_lib.o
1111 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
12+ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
1213 ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
1314 obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
security/integrity/ima/ima.h+56−4
@@ -60,6 +60,7 @@ struct ima_event_data { · 59 unmodified lines
6060 const unsigned char *filename;
6161 struct evm_ima_xattr_data *xattr_value;
6262 int xattr_len;
63+ const struct modsig *modsig;
6364 const char *violation;
6465 const void *buf;
6566 int buf_len;
@@ -149,6 +150,7 @@ int template_desc_init_fields(const char *template_fmt, · 83 unmodified lines
149150 int *num_fields);
150151 struct ima_template_desc *ima_template_desc_current(void);
151152 struct ima_template_desc *lookup_template_desc(const char *name);
153+bool ima_template_has_modsig(const struct ima_template_desc *ima_template);
152154 int ima_restore_measurement_entry(struct ima_template_entry *entry);
153155 int ima_restore_measurement_list(loff_t bufsize, void *buf);
154156 int ima_measurements_show(struct seq_file *m, void *v);
@@ -196,6 +198,10 @@ enum ima_hooks { · 41 unmodified lines
196198 __ima_hooks(__ima_hook_enumify)
197199 };
198200
201+extern const char *const func_tokens[];
202+
203+struct modsig;
204+
199205 /* LIM API function definitions */
200206 int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid,
201207 int mask, enum ima_hooks func, int *pcr,
@@ -203,11 +209,11 @@ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, · 1 unmodified line
203209 int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
204210 int ima_collect_measurement(struct integrity_iint_cache *iint,
205211 struct file *file, void *buf, loff_t size,
206− enum hash_algo algo);
212+ enum hash_algo algo, struct modsig *modsig);
207213 void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
208214 const unsigned char *filename,
209215 struct evm_ima_xattr_data *xattr_value,
210− int xattr_len, int pcr,
216+ int xattr_len, const struct modsig *modsig, int pcr,
211217 struct ima_template_desc *template_desc);
212218 void ima_audit_measurement(struct integrity_iint_cache *iint,
213219 const unsigned char *filename);
@@ -249,7 +255,7 @@ int ima_appraise_measurement(enum ima_hooks func, · 35 unmodified lines
249255 struct integrity_iint_cache *iint,
250256 struct file *file, const unsigned char *filename,
251257 struct evm_ima_xattr_data *xattr_value,
252− int xattr_len);
258+ int xattr_len, const struct modsig *modsig);
253259 int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
254260 void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
255261 enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -265,7 +271,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func, · 9 unmodified lines
265271 struct file *file,
266272 const unsigned char *filename,
267273 struct evm_ima_xattr_data *xattr_value,
268− int xattr_len)
274+ int xattr_len,
275+ const struct modsig *modsig)
269276 {
270277 return INTEGRITY_UNKNOWN;
271278 }
@@ -302,6 +309,51 @@ static inline int ima_read_xattr(struct dentry *dentry, · 30 unmodified lines
302309
303310 #endif /* CONFIG_IMA_APPRAISE */
304311
312+#ifdef CONFIG_IMA_APPRAISE_MODSIG
313+bool ima_hook_supports_modsig(enum ima_hooks func);
314+int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
315+ struct modsig **modsig);
316+void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size);
317+int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
318+ const u8 **digest, u32 *digest_size);
319+int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
320+ u32 *data_len);
321+void ima_free_modsig(struct modsig *modsig);
322+#else
323+static inline bool ima_hook_supports_modsig(enum ima_hooks func)
324+{
325+ return false;
326+}
327+
328+static inline int ima_read_modsig(enum ima_hooks func, const void *buf,
329+ loff_t buf_len, struct modsig **modsig)
330+{
331+ return -EOPNOTSUPP;
332+}
333+
334+static inline void ima_collect_modsig(struct modsig *modsig, const void *buf,
335+ loff_t size)
336+{
337+}
338+
339+static inline int ima_get_modsig_digest(const struct modsig *modsig,
340+ enum hash_algo *algo, const u8 **digest,
341+ u32 *digest_size)
342+{
343+ return -EOPNOTSUPP;
344+}
345+
346+static inline int ima_get_raw_modsig(const struct modsig *modsig,
347+ const void **data, u32 *data_len)
348+{
349+ return -EOPNOTSUPP;
350+}
351+
352+static inline void ima_free_modsig(struct modsig *modsig)
353+{
354+}
355+#endif /* CONFIG_IMA_APPRAISE_MODSIG */
356+
305357 /* LSM based policy rules require audit */
306358 #ifdef CONFIG_IMA_LSM_RULES
307359
security/integrity/ima/ima_api.c+21−6
@@ -45,8 +45,8 @@ int ima_alloc_init_template(struct ima_event_data *event_data, · 44 unmodified lines
4545 else
4646 template_desc = ima_template_desc_current();
4747
48− *entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
49− sizeof(struct ima_field_data), GFP_NOFS);
48+ *entry = kzalloc(struct_size(*entry, template_data,
49+ template_desc->num_fields), GFP_NOFS);
5050 if (!*entry)
5151 return -ENOMEM;
5252
@@ -205,7 +205,7 @@ int ima_get_action(struct inode *inode, const struct cred *cred, u32 secid, · 152 unmodified lines
205205 */
206206 int ima_collect_measurement(struct integrity_iint_cache *iint,
207207 struct file *file, void *buf, loff_t size,
208− enum hash_algo algo)
208+ enum hash_algo algo, struct modsig *modsig)
209209 {
210210 const char *audit_cause = "failed";
211211 struct inode *inode = file_inode(file);
@@ -219,6 +219,14 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, · 7 unmodified lines
219219 char digest[IMA_MAX_DIGEST_SIZE];
220220 } hash;
221221
222+ /*
223+ * Always collect the modsig, because IMA might have already collected
224+ * the file digest without collecting the modsig in a previous
225+ * measurement rule.
226+ */
227+ if (modsig)
228+ ima_collect_modsig(modsig, buf, size);
229+
222230 if (iint->flags & IMA_COLLECTED)
223231 goto out;
224232
@@ -285,7 +293,7 @@ out: · 60 unmodified lines
285293 void ima_store_measurement(struct integrity_iint_cache *iint,
286294 struct file *file, const unsigned char *filename,
287295 struct evm_ima_xattr_data *xattr_value,
288− int xattr_len, int pcr,
296+ int xattr_len, const struct modsig *modsig, int pcr,
289297 struct ima_template_desc *template_desc)
290298 {
291299 static const char op[] = "add_template_measure";
@@ -297,10 +305,17 @@ void ima_store_measurement(struct integrity_iint_cache *iint, · 5 unmodified lines
297305 .file = file,
298306 .filename = filename,
299307 .xattr_value = xattr_value,
300− .xattr_len = xattr_len };
308+ .xattr_len = xattr_len,
309+ .modsig = modsig };
301310 int violation = 0;
302311
303− if (iint->measured_pcrs & (0x1 << pcr))
312+ /*
313+ * We still need to store the measurement in the case of MODSIG because
314+ * we only have its contents to put in the list at the time of
315+ * appraisal, but a file measurement from earlier might already exist in
316+ * the measurement list.
317+ */
318+ if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
304319 return;
305320
306321 result = ima_alloc_init_template(&event_data, &entry, template_desc);
security/integrity/ima/ima_appraise.c+129−65
@@ -199,6 +199,110 @@ int ima_read_xattr(struct dentry *dentry, · 198 unmodified lines
199199 return ret;
200200 }
201201
202+/*
203+ * xattr_verify - verify xattr digest or signature
204+ *
205+ * Verify whether the hash or signature matches the file contents.
206+ *
207+ * Return 0 on success, error code otherwise.
208+ */
209+static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
210+ struct evm_ima_xattr_data *xattr_value, int xattr_len,
211+ enum integrity_status *status, const char **cause)
212+{
213+ int rc = -EINVAL, hash_start = 0;
214+
215+ switch (xattr_value->type) {
216+ case IMA_XATTR_DIGEST_NG:
217+ /* first byte contains algorithm id */
218+ hash_start = 1;
219+ /* fall through */
220+ case IMA_XATTR_DIGEST:
221+ if (iint->flags & IMA_DIGSIG_REQUIRED) {
222+ *cause = "IMA-signature-required";
223+ *status = INTEGRITY_FAIL;
224+ break;
225+ }
226+ clear_bit(IMA_DIGSIG, &iint->atomic_flags);
227+ if (xattr_len - sizeof(xattr_value->type) - hash_start >=
228+ iint->ima_hash->length)
229+ /*
230+ * xattr length may be longer. md5 hash in previous
231+ * version occupied 20 bytes in xattr, instead of 16
232+ */
233+ rc = memcmp(&xattr_value->data[hash_start],
234+ iint->ima_hash->digest,
235+ iint->ima_hash->length);
236+ else
237+ rc = -EINVAL;
238+ if (rc) {
239+ *cause = "invalid-hash";
240+ *status = INTEGRITY_FAIL;
241+ break;
242+ }
243+ *status = INTEGRITY_PASS;
244+ break;
245+ case EVM_IMA_XATTR_DIGSIG:
246+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
247+ rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
248+ (const char *)xattr_value,
249+ xattr_len,
250+ iint->ima_hash->digest,
251+ iint->ima_hash->length);
252+ if (rc == -EOPNOTSUPP) {
253+ *status = INTEGRITY_UNKNOWN;
254+ break;
255+ }
256+ if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
257+ func == KEXEC_KERNEL_CHECK)
258+ rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
259+ (const char *)xattr_value,
260+ xattr_len,
261+ iint->ima_hash->digest,
262+ iint->ima_hash->length);
263+ if (rc) {
264+ *cause = "invalid-signature";
265+ *status = INTEGRITY_FAIL;
266+ } else {
267+ *status = INTEGRITY_PASS;
268+ }
269+ break;
270+ default:
271+ *status = INTEGRITY_UNKNOWN;
272+ *cause = "unknown-ima-data";
273+ break;
274+ }
275+
276+ return rc;
277+}
278+
279+/*
280+ * modsig_verify - verify modsig signature
281+ *
282+ * Verify whether the signature matches the file contents.
283+ *
284+ * Return 0 on success, error code otherwise.
285+ */
286+static int modsig_verify(enum ima_hooks func, const struct modsig *modsig,
287+ enum integrity_status *status, const char **cause)
288+{
289+ int rc;
290+
291+ rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
292+ if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
293+ func == KEXEC_KERNEL_CHECK)
294+ rc = integrity_modsig_verify(INTEGRITY_KEYRING_PLATFORM,
295+ modsig);
296+ if (rc) {
297+ *cause = "invalid-signature";
298+ *status = INTEGRITY_FAIL;
299+ } else {
300+ *status = INTEGRITY_PASS;
301+ }
302+
303+ return rc;
304+}
305+
202306 /*
203307 * ima_appraise_measurement - appraise file measurement
204308 *
@@ -211,19 +315,22 @@ int ima_appraise_measurement(enum ima_hooks func, · 6 unmodified lines
211315 struct integrity_iint_cache *iint,
212316 struct file *file, const unsigned char *filename,
213317 struct evm_ima_xattr_data *xattr_value,
214− int xattr_len)
318+ int xattr_len, const struct modsig *modsig)
215319 {
216320 static const char op[] = "appraise_data";
217321 const char *cause = "unknown";
218322 struct dentry *dentry = file_dentry(file);
219323 struct inode *inode = d_backing_inode(dentry);
220324 enum integrity_status status = INTEGRITY_UNKNOWN;
221− int rc = xattr_len, hash_start = 0;
325+ int rc = xattr_len;
326+ bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
222327
223− if (!(inode->i_opflags & IOP_XATTR))
328+ /* If not appraising a modsig, we need an xattr. */
329+ if (!(inode->i_opflags & IOP_XATTR) && !try_modsig)
224330 return INTEGRITY_UNKNOWN;
225331
226− if (rc <= 0) {
332+ /* If reading the xattr failed and there's no modsig, error out. */
333+ if (rc <= 0 && !try_modsig) {
227334 if (rc && rc != -ENODATA)
228335 goto out;
229336
@@ -246,6 +353,10 @@ int ima_appraise_measurement(enum ima_hooks func, · 16 unmodified lines
246353 case INTEGRITY_UNKNOWN:
247354 break;
248355 case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */
356+ /* It's fine not to have xattrs when using a modsig. */
357+ if (try_modsig)
358+ break;
359+ /* fall through */
249360 case INTEGRITY_NOLABEL: /* No security.evm xattr. */
250361 cause = "missing-HMAC";
251362 goto out;
@@ -256,65 +367,18 @@ int ima_appraise_measurement(enum ima_hooks func, · 4 unmodified lines
256367 WARN_ONCE(true, "Unexpected integrity status %d\n", status);
257368 }
258369
259− switch (xattr_value->type) {
260− case IMA_XATTR_DIGEST_NG:
261− /* first byte contains algorithm id */
262− hash_start = 1;
263− /* fall through */
264− case IMA_XATTR_DIGEST:
265− if (iint->flags & IMA_DIGSIG_REQUIRED) {
266− cause = "IMA-signature-required";
267− status = INTEGRITY_FAIL;
268− break;
269− }
270− clear_bit(IMA_DIGSIG, &iint->atomic_flags);
271− if (xattr_len - sizeof(xattr_value->type) - hash_start >=
272− iint->ima_hash->length)
273− /* xattr length may be longer. md5 hash in previous
274− version occupied 20 bytes in xattr, instead of 16
275− */
276− rc = memcmp(&xattr_value->data[hash_start],
277− iint->ima_hash->digest,
278− iint->ima_hash->length);
279− else
280− rc = -EINVAL;
281− if (rc) {
282− cause = "invalid-hash";
283− status = INTEGRITY_FAIL;
284− break;
285− }
286− status = INTEGRITY_PASS;
287− break;
288− case EVM_IMA_XATTR_DIGSIG:
289− set_bit(IMA_DIGSIG, &iint->atomic_flags);
290− rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
291− (const char *)xattr_value,
292− xattr_len,
293− iint->ima_hash->digest,
294− iint->ima_hash->length);
295− if (rc == -EOPNOTSUPP) {
296− status = INTEGRITY_UNKNOWN;
297− break;
298− }
299− if (IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING) && rc &&
300− func == KEXEC_KERNEL_CHECK)
301− rc = integrity_digsig_verify(INTEGRITY_KEYRING_PLATFORM,
302− (const char *)xattr_value,
303− xattr_len,
304− iint->ima_hash->digest,
305− iint->ima_hash->length);
306− if (rc) {
307− cause = "invalid-signature";
308− status = INTEGRITY_FAIL;
309− } else {
310− status = INTEGRITY_PASS;
311− }
312− break;
313− default:
314− status = INTEGRITY_UNKNOWN;
315− cause = "unknown-ima-data";
316− break;
317− }
370+ if (xattr_value)
371+ rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
372+ &cause);
373+
374+ /*
375+ * If we have a modsig and either no imasig or the imasig's key isn't
376+ * known, then try verifying the modsig.
377+ */
378+ if (try_modsig &&
379+ (!xattr_value || xattr_value->type == IMA_XATTR_DIGEST_NG ||
380+ rc == -ENOKEY))
381+ rc = modsig_verify(func, modsig, &status, &cause);
318382
319383 out:
320384 /*
@@ -332,7 +396,7 @@ out: · 11 unmodified lines
332396 op, cause, rc, 0);
333397 } else if (status != INTEGRITY_PASS) {
334398 /* Fix mode, but don't replace file signatures. */
335− if ((ima_appraise & IMA_APPRAISE_FIX) &&
399+ if ((ima_appraise & IMA_APPRAISE_FIX) && !try_modsig &&
336400 (!xattr_value ||
337401 xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
338402 if (!ima_fix_xattr(dentry, iint))
@@ -371,7 +435,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) · 32 unmodified lines
371435 !(iint->flags & IMA_HASH))
372436 return;
373437
374− rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
438+ rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo, NULL);
375439 if (rc < 0)
376440 return;
377441
security/integrity/ima/ima_crypto.c+9−1
@@ -268,8 +268,16 @@ static int ima_calc_file_hash_atfm(struct file *file, · 267 unmodified lines
268268 rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
269269 rc = integrity_kernel_read(file, offset, rbuf[active],
270270 rbuf_len);
271− if (rc != rbuf_len)
271+ if (rc != rbuf_len) {
272+ if (rc >= 0)
273+ rc = -EINVAL;
274+ /*
275+ * Forward current rc, do not overwrite with return value
276+ * from ahash_wait()
277+ */
278+ ahash_wait(ahash_rc, &wait);
272279 goto out3;
280+ }
273281
274282 if (rbuf[1] && offset) {
275283 /* Using two buffers, and it is not the first
security/integrity/ima/ima_main.c+20−4
@@ -202,6 +202,7 @@ static int process_measurement(struct file *file, const struct cred *cred, · 201 unmodified lines
202202 int rc = 0, action, must_appraise = 0;
203203 int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
204204 struct evm_ima_xattr_data *xattr_value = NULL;
205+ struct modsig *modsig = NULL;
205206 int xattr_len = 0;
206207 bool violation_check;
207208 enum hash_algo hash_algo;
@@ -302,13 +303,27 @@ static int process_measurement(struct file *file, const struct cred *cred, · 94 unmodified lines
302303 }
303304
304305 if ((action & IMA_APPRAISE_SUBMASK) ||
305− strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
306+ strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0) {
306307 /* read 'security.ima' */
307308 xattr_len = ima_read_xattr(file_dentry(file), &xattr_value);
308309
310+ /*
311+ * Read the appended modsig if allowed by the policy, and allow
312+ * an additional measurement list entry, if needed, based on the
313+ * template format and whether the file was already measured.
314+ */
315+ if (iint->flags & IMA_MODSIG_ALLOWED) {
316+ rc = ima_read_modsig(func, buf, size, &modsig);
317+
318+ if (!rc && ima_template_has_modsig(template_desc) &&
319+ iint->flags & IMA_MEASURED)
320+ action |= IMA_MEASURE;
321+ }
322+ }
323+
309324 hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
310325
311− rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
326+ rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig);
312327 if (rc != 0 && rc != -EBADF && rc != -EINVAL)
313328 goto out_locked;
314329
@@ -317,12 +332,12 @@ static int process_measurement(struct file *file, const struct cred *cred, · 2 unmodified lines
317332
318333 if (action & IMA_MEASURE)
319334 ima_store_measurement(iint, file, pathname,
320− xattr_value, xattr_len, pcr,
335+ xattr_value, xattr_len, modsig, pcr,
321336 template_desc);
322337 if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
323338 inode_lock(inode);
324339 rc = ima_appraise_measurement(func, iint, file, pathname,
325− xattr_value, xattr_len);
340+ xattr_value, xattr_len, modsig);
326341 inode_unlock(inode);
327342 if (!rc)
328343 rc = mmap_violation_check(func, file, &pathbuf,
@@ -339,6 +354,7 @@ out_locked: · 10 unmodified lines
339354 rc = -EACCES;
340355 mutex_unlock(&iint->mutex);
341356 kfree(xattr_value);
357+ ima_free_modsig(modsig);
342358 out:
343359 if (pathbuf)
344360 __putname(pathbuf);
security/integrity/ima/ima_modsig.c+168−0
@@ -0,0 +1,168 @@
1+// SPDX-License-Identifier: GPL-2.0+
2+/*
3+ * IMA support for appraising module-style appended signatures.
4+ *
5+ * Copyright (C) 2019 IBM Corporation
6+ *
7+ * Author:
8+ * Thiago Jung Bauermann <bauerman@linux.ibm.com>
9+ */
10+
11+#include <linux/types.h>
12+#include <linux/module_signature.h>
13+#include <keys/asymmetric-type.h>
14+#include <crypto/pkcs7.h>
15+
16+#include "ima.h"
17+
18+struct modsig {
19+ struct pkcs7_message *pkcs7_msg;
20+
21+ enum hash_algo hash_algo;
22+
23+ /* This digest will go in the 'd-modsig' field of the IMA template. */
24+ const u8 *digest;
25+ u32 digest_size;
26+
27+ /*
28+ * This is what will go to the measurement list if the template requires
29+ * storing the signature.
30+ */
31+ int raw_pkcs7_len;
32+ u8 raw_pkcs7[];
33+};
34+
35+/**
36+ * ima_hook_supports_modsig - can the policy allow modsig for this hook?
37+ *
38+ * modsig is only supported by hooks using ima_post_read_file(), because only
39+ * they preload the contents of the file in a buffer. FILE_CHECK does that in
40+ * some cases, but not when reached from vfs_open(). POLICY_CHECK can support
41+ * it, but it's not useful in practice because it's a text file so deny.
42+ */
43+bool ima_hook_supports_modsig(enum ima_hooks func)
44+{
45+ switch (func) {
46+ case KEXEC_KERNEL_CHECK:
47+ case KEXEC_INITRAMFS_CHECK:
48+ case MODULE_CHECK:
49+ return true;
50+ default:
51+ return false;
52+ }
53+}
54+
55+/*
56+ * ima_read_modsig - Read modsig from buf.
57+ *
58+ * Return: 0 on success, error code otherwise.
59+ */
60+int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
61+ struct modsig **modsig)
62+{
63+ const size_t marker_len = strlen(MODULE_SIG_STRING);
64+ const struct module_signature *sig;
65+ struct modsig *hdr;
66+ size_t sig_len;
67+ const void *p;
68+ int rc;
69+
70+ if (buf_len <= marker_len + sizeof(*sig))
71+ return -ENOENT;
72+
73+ p = buf + buf_len - marker_len;
74+ if (memcmp(p, MODULE_SIG_STRING, marker_len))
75+ return -ENOENT;
76+
77+ buf_len -= marker_len;
78+ sig = (const struct module_signature *)(p - sizeof(*sig));
79+
80+ rc = mod_check_sig(sig, buf_len, func_tokens[func]);
81+ if (rc)
82+ return rc;
83+
84+ sig_len = be32_to_cpu(sig->sig_len);
85+ buf_len -= sig_len + sizeof(*sig);
86+
87+ /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
88+ hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
89+ if (!hdr)
90+ return -ENOMEM;
91+
92+ hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
93+ if (IS_ERR(hdr->pkcs7_msg)) {
94+ rc = PTR_ERR(hdr->pkcs7_msg);
95+ kfree(hdr);
96+ return rc;
97+ }
98+
99+ memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
100+ hdr->raw_pkcs7_len = sig_len;
101+
102+ /* We don't know the hash algorithm yet. */
103+ hdr->hash_algo = HASH_ALGO__LAST;
104+
105+ *modsig = hdr;
106+
107+ return 0;
108+}
109+
110+/**
111+ * ima_collect_modsig - Calculate the file hash without the appended signature.
112+ *
113+ * Since the modsig is part of the file contents, the hash used in its signature
114+ * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
115+ * calculates a separate one for signature verification.
116+ */
117+void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
118+{
119+ int rc;
120+
121+ /*
122+ * Provide the file contents (minus the appended sig) so that the PKCS7
123+ * code can calculate the file hash.
124+ */
125+ size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
126+ sizeof(struct module_signature);
127+ rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
128+ if (rc)
129+ return;
130+
131+ /* Ask the PKCS7 code to calculate the file hash. */
132+ rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
133+ &modsig->digest_size, &modsig->hash_algo);
134+}
135+
136+int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
137+{
138+ return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring,
139+ VERIFYING_MODULE_SIGNATURE, NULL, NULL);
140+}
141+
142+int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
143+ const u8 **digest, u32 *digest_size)
144+{
145+ *algo = modsig->hash_algo;
146+ *digest = modsig->digest;
147+ *digest_size = modsig->digest_size;
148+
149+ return 0;
150+}
151+
152+int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
153+ u32 *data_len)
154+{
155+ *data = &modsig->raw_pkcs7;
156+ *data_len = modsig->raw_pkcs7_len;
157+
158+ return 0;
159+}
160+
161+void ima_free_modsig(struct modsig *modsig)
162+{
163+ if (!modsig)
164+ return;
165+
166+ pkcs7_free_message(modsig->pkcs7_msg);
167+ kfree(modsig);
168+}
security/integrity/ima/ima_policy.c+61−10
@@ -6,6 +6,9 @@ · 5 unmodified lines
66 * ima_policy.c
77 * - initialize default measure policy rules
88 */
9+
10+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11+
912 #include <linux/init.h>
1013 #include <linux/list.h>
1114 #include <linux/fs.h>
@@ -491,6 +494,9 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, · 479 unmodified lines
491494 struct ima_rule_entry *entry;
492495 int action = 0, actmask = flags | (flags << 1);
493496
497+ if (template_desc)
498+ *template_desc = ima_template_desc_current();
499+
494500 rcu_read_lock();
495501 list_for_each_entry_rcu(entry, ima_rules, list) {
496502
@@ -510,6 +516,7 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, · 13 unmodified lines
510516 action |= IMA_FAIL_UNVERIFIABLE_SIGS;
511517 }
512518
519+
513520 if (entry->action & IMA_DO_MASK)
514521 actmask &= ~(entry->action | entry->action << 1);
515522 else
@@ -520,8 +527,6 @@ int ima_match_policy(struct inode *inode, const struct cred *cred, u32 secid, · 4 unmodified lines
520527
521528 if (template_desc && entry->template)
522529 *template_desc = entry->template;
523− else if (template_desc)
524− *template_desc = ima_template_desc_current();
525530
526531 if (!actmask)
527532 break;
@@ -843,6 +848,38 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value) · 315 unmodified lines
843848 ima_log_string_op(ab, key, value, NULL);
844849 }
845850
851+/*
852+ * Validating the appended signature included in the measurement list requires
853+ * the file hash calculated without the appended signature (i.e., the 'd-modsig'
854+ * field). Therefore, notify the user if they have the 'modsig' field but not
855+ * the 'd-modsig' field in the template.
856+ */
857+static void check_template_modsig(const struct ima_template_desc *template)
858+{
859+#define MSG "template with 'modsig' field also needs 'd-modsig' field\n"
860+ bool has_modsig, has_dmodsig;
861+ static bool checked;
862+ int i;
863+
864+ /* We only need to notify the user once. */
865+ if (checked)
866+ return;
867+
868+ has_modsig = has_dmodsig = false;
869+ for (i = 0; i < template->num_fields; i++) {
870+ if (!strcmp(template->fields[i]->field_id, "modsig"))
871+ has_modsig = true;
872+ else if (!strcmp(template->fields[i]->field_id, "d-modsig"))
873+ has_dmodsig = true;
874+ }
875+
876+ if (has_modsig && !has_dmodsig)
877+ pr_notice(MSG);
878+
879+ checked = true;
880+#undef MSG
881+}
882+
846883 static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
847884 {
848885 struct audit_buffer *ab;
@@ -1128,6 +1165,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) · 279 unmodified lines
11281165 ima_log_string(ab, "appraise_type", args[0].from);
11291166 if ((strcmp(args[0].from, "imasig")) == 0)
11301167 entry->flags |= IMA_DIGSIG_REQUIRED;
1168+ else if (ima_hook_supports_modsig(entry->func) &&
1169+ strcmp(args[0].from, "imasig|modsig") == 0)
1170+ entry->flags |= IMA_DIGSIG_REQUIRED |
1171+ IMA_MODSIG_ALLOWED;
11311172 else
11321173 result = -EINVAL;
11331174 break;
@@ -1181,6 +1222,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) · 47 unmodified lines
11811222 else if (entry->action == APPRAISE)
11821223 temp_ima_appraise |= ima_appraise_flag(entry->func);
11831224
1225+ if (!result && entry->flags & IMA_MODSIG_ALLOWED) {
1226+ template_desc = entry->template ? entry->template :
1227+ ima_template_desc_current();
1228+ check_template_modsig(template_desc);
1229+ }
1230+
11841231 audit_log_format(ab, "res=%d", !result);
11851232 audit_log_end(ab);
11861233 return result;
@@ -1252,6 +1299,12 @@ void ima_delete_rules(void) · 65 unmodified lines
12521299 }
12531300 }
12541301
1302+#define __ima_hook_stringify(str) (#str),
1303+
1304+const char *const func_tokens[] = {
1305+ __ima_hooks(__ima_hook_stringify)
1306+};
1307+
12551308 #ifdef CONFIG_IMA_READ_POLICY
12561309 enum {
12571310 mask_exec = 0, mask_write, mask_read, mask_append
@@ -1264,12 +1317,6 @@ static const char *const mask_tokens[] = { · 6 unmodified lines
12641317 "^MAY_APPEND"
12651318 };
12661319
1267−#define __ima_hook_stringify(str) (#str),
1268−
1269−static const char *const func_tokens[] = {
1270− __ima_hooks(__ima_hook_stringify)
1271−};
1272−
12731320 void *ima_policy_start(struct seq_file *m, loff_t *pos)
12741321 {
12751322 loff_t l = *pos;
@@ -1447,8 +1494,12 @@ int ima_policy_show(struct seq_file *m, void *v) · 171 unmodified lines
14471494 }
14481495 if (entry->template)
14491496 seq_printf(m, "template=%s ", entry->template->name);
1450− if (entry->flags & IMA_DIGSIG_REQUIRED)
1451− seq_puts(m, "appraise_type=imasig ");
1497+ if (entry->flags & IMA_DIGSIG_REQUIRED) {
1498+ if (entry->flags & IMA_MODSIG_ALLOWED)
1499+ seq_puts(m, "appraise_type=imasig|modsig ");
1500+ else
1501+ seq_puts(m, "appraise_type=imasig ");
1502+ }
14521503 if (entry->flags & IMA_PERMIT_DIRECTIO)
14531504 seq_puts(m, "permit_directio ");
14541505 rcu_read_unlock();
security/integrity/ima/ima_template.c+27−4
@@ -23,6 +23,7 @@ static struct ima_template_desc builtin_templates[] = { · 22 unmodified lines
2323 {.name = "ima-ng", .fmt = "d-ng|n-ng"},
2424 {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
2525 {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
26+ {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
2627 {.name = "", .fmt = ""}, /* placeholder for a custom format */
2728 };
2829
@@ -42,6 +43,10 @@ static const struct ima_template_field supported_fields[] = { · 13 unmodified lines
4243 .field_show = ima_show_template_sig},
4344 {.field_id = "buf", .field_init = ima_eventbuf_init,
4445 .field_show = ima_show_template_buf},
46+ {.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,
47+ .field_show = ima_show_template_digest_ng},
48+ {.field_id = "modsig", .field_init = ima_eventmodsig_init,
49+ .field_show = ima_show_template_sig},
4550 };
4651
4752 /*
@@ -49,10 +54,29 @@ static const struct ima_template_field supported_fields[] = { · 1 unmodified line
4954 * need to be accounted for since they shouldn't be defined in the same template
5055 * description as 'd-ng' and 'n-ng' respectively.
5156 */
52−#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf")
57+#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
5358
5459 static struct ima_template_desc *ima_template;
5560
61+/**
62+ * ima_template_has_modsig - Check whether template has modsig-related fields.
63+ * @ima_template: IMA template to check.
64+ *
65+ * Tells whether the given template has fields referencing a file's appended
66+ * signature.
67+ */
68+bool ima_template_has_modsig(const struct ima_template_desc *ima_template)
69+{
70+ int i;
71+
72+ for (i = 0; i < ima_template->num_fields; i++)
73+ if (!strcmp(ima_template->fields[i]->field_id, "modsig") ||
74+ !strcmp(ima_template->fields[i]->field_id, "d-modsig"))
75+ return true;
76+
77+ return false;
78+}
79+
5680 static int __init ima_template_setup(char *str)
5781 {
5882 struct ima_template_desc *template_desc;
@@ -282,9 +306,8 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, · 223 unmodified lines
282306 int ret = 0;
283307 int i;
284308
285− *entry = kzalloc(sizeof(**entry) +
286− template_desc->num_fields * sizeof(struct ima_field_data),
287− GFP_NOFS);
309+ *entry = kzalloc(struct_size(*entry, template_data,
310+ template_desc->num_fields), GFP_NOFS);
288311 if (!*entry)
289312 return -ENOMEM;
290313
security/integrity/ima/ima_template_lib.c+63−1
@@ -225,7 +225,8 @@ int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp, · 224 unmodified lines
225225 return 0;
226226 }
227227
228−static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
228+static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
229+ u8 hash_algo,
229230 struct ima_field_data *field_data)
230231 {
231232 /*
@@ -328,6 +329,41 @@ out: · 96 unmodified lines
328329 hash_algo, field_data);
329330 }
330331
332+/*
333+ * This function writes the digest of the file which is expected to match the
334+ * digest contained in the file's appended signature.
335+ */
336+int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
337+ struct ima_field_data *field_data)
338+{
339+ enum hash_algo hash_algo;
340+ const u8 *cur_digest;
341+ u32 cur_digestsize;
342+
343+ if (!event_data->modsig)
344+ return 0;
345+
346+ if (event_data->violation) {
347+ /* Recording a violation. */
348+ hash_algo = HASH_ALGO_SHA1;
349+ cur_digest = NULL;
350+ cur_digestsize = 0;
351+ } else {
352+ int rc;
353+
354+ rc = ima_get_modsig_digest(event_data->modsig, &hash_algo,
355+ &cur_digest, &cur_digestsize);
356+ if (rc)
357+ return rc;
358+ else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0)
359+ /* There was some error collecting the digest. */
360+ return -EINVAL;
361+ }
362+
363+ return ima_eventdigest_init_common(cur_digest, cur_digestsize,
364+ hash_algo, field_data);
365+}
366+
331367 static int ima_eventname_init_common(struct ima_event_data *event_data,
332368 struct ima_field_data *field_data,
333369 bool size_limit)
@@ -406,3 +442,29 @@ int ima_eventbuf_init(struct ima_event_data *event_data, · 72 unmodified lines
406442 event_data->buf_len, DATA_FMT_HEX,
407443 field_data);
408444 }
445+
446+/*
447+ * ima_eventmodsig_init - include the appended file signature as part of the
448+ * template data
449+ */
450+int ima_eventmodsig_init(struct ima_event_data *event_data,
451+ struct ima_field_data *field_data)
452+{
453+ const void *data;
454+ u32 data_len;
455+ int rc;
456+
457+ if (!event_data->modsig)
458+ return 0;
459+
460+ /*
461+ * modsig is a runtime structure containing pointers. Get its raw data
462+ * instead.
463+ */
464+ rc = ima_get_raw_modsig(event_data->modsig, &data, &data_len);
465+ if (rc)
466+ return rc;
467+
468+ return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
469+ field_data);
470+}
security/integrity/ima/ima_template_lib.h+4−0
@@ -36,10 +36,14 @@ int ima_eventname_init(struct ima_event_data *event_data, · 35 unmodified lines
3636 struct ima_field_data *field_data);
3737 int ima_eventdigest_ng_init(struct ima_event_data *event_data,
3838 struct ima_field_data *field_data);
39+int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
40+ struct ima_field_data *field_data);
3941 int ima_eventname_ng_init(struct ima_event_data *event_data,
4042 struct ima_field_data *field_data);
4143 int ima_eventsig_init(struct ima_event_data *event_data,
4244 struct ima_field_data *field_data);
4345 int ima_eventbuf_init(struct ima_event_data *event_data,
4446 struct ima_field_data *field_data);
47+int ima_eventmodsig_init(struct ima_event_data *event_data,
48+ struct ima_field_data *field_data);
4549 #endif /* __LINUX_IMA_TEMPLATE_LIB_H */
security/integrity/integrity.h+20−0
@@ -31,6 +31,7 @@ · 30 unmodified lines
3131 #define IMA_NEW_FILE 0x04000000
3232 #define EVM_IMMUTABLE_DIGSIG 0x08000000
3333 #define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
34+#define IMA_MODSIG_ALLOWED 0x20000000
3435
3536 #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
3637 IMA_HASH | IMA_APPRAISE_SUBMASK)
@@ -147,10 +148,13 @@ int integrity_kernel_read(struct file *file, loff_t offset, · 110 unmodified lines
147148
148149 extern struct dentry *integrity_dir;
149150
151+struct modsig;
152+
150153 #ifdef CONFIG_INTEGRITY_SIGNATURE
151154
152155 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
153156 const char *digest, int digestlen);
157+int integrity_modsig_verify(unsigned int id, const struct modsig *modsig);
154158
155159 int __init integrity_init_keyring(const unsigned int id);
156160 int __init integrity_load_x509(const unsigned int id, const char *path);
@@ -165,6 +169,12 @@ static inline int integrity_digsig_verify(const unsigned int id, · 8 unmodified lines
165169 return -EOPNOTSUPP;
166170 }
167171
172+static inline int integrity_modsig_verify(unsigned int id,
173+ const struct modsig *modsig)
174+{
175+ return -EOPNOTSUPP;
176+}
177+
168178 static inline int integrity_init_keyring(const unsigned int id)
169179 {
170180 return 0;
@@ -190,6 +200,16 @@ static inline int asymmetric_verify(struct key *keyring, const char *sig, · 19 unmodified lines
190200 }
191201 #endif
192202
203+#ifdef CONFIG_IMA_APPRAISE_MODSIG
204+int ima_modsig_verify(struct key *keyring, const struct modsig *modsig);
205+#else
206+static inline int ima_modsig_verify(struct key *keyring,
207+ const struct modsig *modsig)
208+{
209+ return -EOPNOTSUPP;
210+}
211+#endif
212+
193213 #ifdef CONFIG_IMA_LOAD_X509
194214 void __init ima_load_x509(void);
195215 #else
tools/testing/selftests/kexec/test_kexec_file_load.sh+34−4
@@ -37,11 +37,20 @@ is_ima_sig_required() · 36 unmodified lines
3737 # sequentially. As a result, a policy rule may be defined, but
3838 # might not necessarily be used. This test assumes if a policy
3939 # rule is specified, that is the intent.
40+
41+ # First check for appended signature (modsig), then xattr
4042 if [ $ima_read_policy -eq 1 ]; then
4143 check_ima_policy "appraise" "func=KEXEC_KERNEL_CHECK" \
42− "appraise_type=imasig"
44+ "appraise_type=imasig|modsig"
4345 ret=$?
44− [ $ret -eq 1 ] && log_info "IMA signature required";
46+ if [ $ret -eq 1 ]; then
47+ log_info "IMA or appended(modsig) signature required"
48+ else
49+ check_ima_policy "appraise" "func=KEXEC_KERNEL_CHECK" \
50+ "appraise_type=imasig"
51+ ret=$?
52+ [ $ret -eq 1 ] && log_info "IMA signature required";
53+ fi
4554 fi
4655 return $ret
4756 }
@@ -84,6 +93,22 @@ check_for_imasig() · 36 unmodified lines
8493 return $ret
8594 }
8695
96+# Return 1 for appended signature (modsig) found and 0 for not found.
97+check_for_modsig()
98+{
99+ local module_sig_string="~Module signature appended~"
100+ local sig="$(tail --bytes $((${#module_sig_string} + 1)) $KERNEL_IMAGE)"
101+ local ret=0
102+
103+ if [ "$sig" == "$module_sig_string" ]; then
104+ ret=1
105+ log_info "kexec kernel image modsig signed"
106+ else
107+ log_info "kexec kernel image not modsig signed"
108+ fi
109+ return $ret
110+}
111+
87112 kexec_file_load_test()
88113 {
89114 local succeed_msg="kexec_file_load succeeded"
@@ -98,7 +123,8 @@ kexec_file_load_test() · 8 unmodified lines
98123 # In secureboot mode with an architecture specific
99124 # policy, make sure either an IMA or PE signature exists.
100125 if [ $secureboot -eq 1 ] && [ $arch_policy -eq 1 ] && \
101− [ $ima_signed -eq 0 ] && [ $pe_signed -eq 0 ]; then
126+ [ $ima_signed -eq 0 ] && [ $pe_signed -eq 0 ] \
127+ && [ $ima_modsig -eq 0 ]; then
102128 log_fail "$succeed_msg (missing sig)"
103129 fi
104130
@@ -107,7 +133,8 @@ kexec_file_load_test() · 2 unmodified lines
107133 log_fail "$succeed_msg (missing PE sig)"
108134 fi
109135
110− if [ $ima_sig_required -eq 1 ] && [ $ima_signed -eq 0 ]; then
136+ if [ $ima_sig_required -eq 1 ] && [ $ima_signed -eq 0 ] \
137+ && [ $ima_modsig -eq 0 ]; then
111138 log_fail "$succeed_msg (missing IMA sig)"
112139 fi
113140
@@ -204,5 +231,8 @@ pe_signed=$? · 90 unmodified lines
204231 check_for_imasig
205232 ima_signed=$?
206233
234+check_for_modsig
235+ima_modsig=$?
236+
207237 # Test loading the kernel image via kexec_file_load syscall
208238 kexec_file_load_test