summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/ima_policy1
-rw-r--r--MAINTAINERS4
-rw-r--r--arch/arm/configs/colibri_pxa270_defconfig1
-rw-r--r--arch/arm/configs/iop13xx_defconfig1
-rw-r--r--arch/arm/configs/iop32x_defconfig1
-rw-r--r--arch/arm/configs/trizeps4_defconfig1
-rw-r--r--arch/microblaze/configs/mmu_defconfig1
-rw-r--r--arch/microblaze/configs/nommu_defconfig1
-rw-r--r--arch/mips/configs/bigsur_defconfig1
-rw-r--r--arch/mips/configs/ip22_defconfig1
-rw-r--r--arch/mips/configs/ip27_defconfig1
-rw-r--r--arch/mips/configs/ip32_defconfig1
-rw-r--r--arch/mips/configs/jazz_defconfig1
-rw-r--r--arch/mips/configs/lemote2f_defconfig1
-rw-r--r--arch/mips/configs/rm200_defconfig1
-rw-r--r--arch/mips/configs/sb1250_swarm_defconfig1
-rw-r--r--arch/parisc/configs/712_defconfig1
-rw-r--r--arch/parisc/configs/a500_defconfig1
-rw-r--r--arch/parisc/configs/default_defconfig1
-rw-r--r--arch/parisc/configs/generic-32bit_defconfig1
-rw-r--r--arch/powerpc/configs/c2k_defconfig1
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig1
-rw-r--r--arch/score/configs/spct6600_defconfig1
-rw-r--r--arch/tile/configs/tilegx_defconfig1
-rw-r--r--arch/tile/configs/tilepro_defconfig1
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--certs/Kconfig16
-rw-r--r--certs/Makefile33
-rw-r--r--certs/system_certificates.S13
-rw-r--r--certs/system_keyring.c4
-rw-r--r--crypto/asymmetric_keys/Kconfig7
-rw-r--r--crypto/asymmetric_keys/Makefile8
-rw-r--r--crypto/asymmetric_keys/mscode_parser.c14
-rw-r--r--crypto/asymmetric_keys/pkcs7_parser.c32
-rw-r--r--crypto/asymmetric_keys/pkcs7_trust.c2
-rw-r--r--crypto/asymmetric_keys/pkcs7_verify.c10
-rw-r--r--crypto/asymmetric_keys/public_key.c154
-rw-r--r--crypto/asymmetric_keys/public_key.h36
-rw-r--r--crypto/asymmetric_keys/rsa.c278
-rw-r--r--crypto/asymmetric_keys/verify_pefile.c4
-rw-r--r--crypto/asymmetric_keys/verify_pefile.h2
-rw-r--r--crypto/asymmetric_keys/x509_cert_parser.c75
-rw-r--r--crypto/asymmetric_keys/x509_public_key.c34
-rw-r--r--crypto/asymmetric_keys/x509_rsakey.asn14
-rw-r--r--crypto/rsa-pkcs1pad.c182
-rw-r--r--drivers/base/firmware_class.c78
-rw-r--r--drivers/char/tpm/tpm-chip.c19
-rw-r--r--drivers/char/tpm/tpm.h7
-rw-r--r--drivers/char/tpm/tpm2-cmd.c22
-rw-r--r--drivers/char/tpm/tpm_crb.c196
-rw-r--r--drivers/char/tpm/tpm_eventlog.c14
-rw-r--r--drivers/char/tpm/tpm_tis.c253
-rw-r--r--fs/exec.c92
-rw-r--r--include/crypto/public_key.h76
-rw-r--r--include/keys/trusted-type.h2
-rw-r--r--include/linux/fs.h15
-rw-r--r--include/linux/ima.h10
-rw-r--r--include/linux/key.h1
-rw-r--r--include/linux/lsm_hooks.h35
-rw-r--r--include/linux/security.h16
-rw-r--r--init/Kconfig2
-rw-r--r--kernel/kexec_file.c73
-rw-r--r--kernel/module.c68
-rw-r--r--kernel/module_signing.c7
-rw-r--r--kernel/time/time.c9
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile1
-rwxr-xr-xscripts/extract-sys-certs.pl29
-rw-r--r--scripts/insert-sys-cert.c410
-rwxr-xr-xscripts/sign-file.c238
-rw-r--r--security/integrity/Kconfig2
-rw-r--r--security/integrity/digsig_asymmetric.c16
-rw-r--r--security/integrity/iint.c4
-rw-r--r--security/integrity/ima/ima.h49
-rw-r--r--security/integrity/ima/ima_api.c25
-rw-r--r--security/integrity/ima/ima_appraise.c69
-rw-r--r--security/integrity/ima/ima_crypto.c120
-rw-r--r--security/integrity/ima/ima_fs.c53
-rw-r--r--security/integrity/ima/ima_init.c2
-rw-r--r--security/integrity/ima/ima_main.c92
-rw-r--r--security/integrity/ima/ima_policy.c115
-rw-r--r--security/integrity/ima/ima_template.c2
-rw-r--r--security/integrity/ima/ima_template_lib.c1
-rw-r--r--security/integrity/integrity.h17
-rw-r--r--security/keys/big_key.c15
-rw-r--r--security/keys/key.c2
-rw-r--r--security/keys/trusted.c11
-rw-r--r--security/security.c34
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/smack/smack_lsm.c46
91 files changed, 1924 insertions, 1365 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index 0a378a8..bb0f9a1 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -27,6 +27,7 @@ Description:
base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
[FIRMWARE_CHECK]
+ [KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC]
fsmagic:= hex value
diff --git a/MAINTAINERS b/MAINTAINERS
index 99bd725..5e6f388 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11126,8 +11126,8 @@ M: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
R: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
W: http://tpmdd.sourceforge.net
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
-Q: git git://github.com/PeterHuewe/linux-tpmdd.git
-T: git https://github.com/PeterHuewe/linux-tpmdd
+Q: https://patchwork.kernel.org/project/tpmdd-devel/list/
+T: git git://git.infradead.org/users/jjs/linux-tpmdd.git
S: Maintained
F: drivers/char/tpm/
diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig
index 18c311a..0b9211b 100644
--- a/arch/arm/configs/colibri_pxa270_defconfig
+++ b/arch/arm/configs/colibri_pxa270_defconfig
@@ -166,7 +166,6 @@ CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
CONFIG_DEBUG_LL=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_SHA1=m
diff --git a/arch/arm/configs/iop13xx_defconfig b/arch/arm/configs/iop13xx_defconfig
index 4fa94a1..652b7bd 100644
--- a/arch/arm/configs/iop13xx_defconfig
+++ b/arch/arm/configs/iop13xx_defconfig
@@ -95,7 +95,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_LRW=y
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/arm/configs/iop32x_defconfig b/arch/arm/configs/iop32x_defconfig
index c3058da..aa3af0a 100644
--- a/arch/arm/configs/iop32x_defconfig
+++ b/arch/arm/configs/iop32x_defconfig
@@ -108,7 +108,6 @@ CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
CONFIG_DEBUG_LL_UART_8250=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_LRW=y
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig
index 4bc8700..0ada29d 100644
--- a/arch/arm/configs/trizeps4_defconfig
+++ b/arch/arm/configs/trizeps4_defconfig
@@ -214,7 +214,6 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_SHA256=m
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index e2f6543..dc5dd5b 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -87,5 +87,4 @@ CONFIG_KGDB_KDB=y
CONFIG_EARLY_PRINTK=y
CONFIG_KEYS=y
CONFIG_ENCRYPTED_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/microblaze/configs/nommu_defconfig b/arch/microblaze/configs/nommu_defconfig
index a29ebd4..4cdaf56 100644
--- a/arch/microblaze/configs/nommu_defconfig
+++ b/arch/microblaze/configs/nommu_defconfig
@@ -92,7 +92,6 @@ CONFIG_DEBUG_INFO=y
CONFIG_EARLY_PRINTK=y
CONFIG_KEYS=y
CONFIG_ENCRYPTED_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=y
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index b3e7a1b..e070dac 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -247,7 +247,6 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_NETWORK_XFRM=y
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index 57ed466..6ba9ce9 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -358,7 +358,6 @@ CONFIG_DLM=m
CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_CRYPTD=m
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index 48e16d9..77e9f50 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -346,7 +346,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_DLM=m
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITYFS=y
CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_NULL=m
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index fe48220..f9af98f 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -181,7 +181,6 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_ECB=y
diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig
index 4f37a59..a5e85e1 100644
--- a/arch/mips/configs/jazz_defconfig
+++ b/arch/mips/configs/jazz_defconfig
@@ -362,7 +362,6 @@ CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
CONFIG_DLM=m
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_LRW=m
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index 004cf52..d1f198b 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -412,7 +412,6 @@ CONFIG_DEBUG_FS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_FIPS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_CRYPTD=m
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index db029f4..82db4e3 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -453,7 +453,6 @@ CONFIG_NLS_KOI8_R=m
CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
CONFIG_DLM=m
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_LRW=m
diff --git a/arch/mips/configs/sb1250_swarm_defconfig b/arch/mips/configs/sb1250_swarm_defconfig
index 51bab13..7fca09fe 100644
--- a/arch/mips/configs/sb1250_swarm_defconfig
+++ b/arch/mips/configs/sb1250_swarm_defconfig
@@ -87,7 +87,6 @@ CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_DLM=m
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_AUTHENC=m
diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig
index 9387cc2..db8f56b 100644
--- a/arch/parisc/configs/712_defconfig
+++ b/arch/parisc/configs/712_defconfig
@@ -183,7 +183,6 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MUTEXES=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_DEBUG_RODATA=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_HMAC=y
diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
index 0490199..1a4f776 100644
--- a/arch/parisc/configs/a500_defconfig
+++ b/arch/parisc/configs/a500_defconfig
@@ -193,7 +193,6 @@ CONFIG_HEADERS_CHECK=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_HMAC=y
diff --git a/arch/parisc/configs/default_defconfig b/arch/parisc/configs/default_defconfig
index 4d8127e..310b665 100644
--- a/arch/parisc/configs/default_defconfig
+++ b/arch/parisc/configs/default_defconfig
@@ -211,7 +211,6 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MUTEXES=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_MD4=m
diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig
index 0ffb08f..5b04d70 100644
--- a/arch/parisc/configs/generic-32bit_defconfig
+++ b/arch/parisc/configs/generic-32bit_defconfig
@@ -301,7 +301,6 @@ CONFIG_RCU_CPU_STALL_INFO=y
CONFIG_LATENCYTOP=y
CONFIG_LKDTM=m
CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_HMAC=y
diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig
index 9186229..340685c 100644
--- a/arch/powerpc/configs/c2k_defconfig
+++ b/arch/powerpc/configs/c2k_defconfig
@@ -387,7 +387,6 @@ CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_BOOTX_TEXT=y
CONFIG_PPC_EARLY_DEBUG=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index e5d2c3d..99ccbeba 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -1175,7 +1175,6 @@ CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_XMON=y
CONFIG_BOOTX_TEXT=y
CONFIG_PPC_EARLY_DEBUG=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_NETWORK_XFRM=y
diff --git a/arch/score/configs/spct6600_defconfig b/arch/score/configs/spct6600_defconfig
index df1edbf..b2d8802 100644
--- a/arch/score/configs/spct6600_defconfig
+++ b/arch/score/configs/spct6600_defconfig
@@ -70,7 +70,6 @@ CONFIG_NFSD=y
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_CRYPTO_NULL=y
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig
index 37dc936..c1387b7 100644
--- a/arch/tile/configs/tilegx_defconfig
+++ b/arch/tile/configs/tilegx_defconfig
@@ -374,7 +374,6 @@ CONFIG_DEBUG_CREDENTIALS=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_KGDB=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_NETWORK=y
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig
index 76a2781..6d9ce8a 100644
--- a/arch/tile/configs/tilepro_defconfig
+++ b/arch/tile/configs/tilepro_defconfig
@@ -486,7 +486,6 @@ CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_CREDENTIALS=y
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_ASYNC_RAID6_TEST=m
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_NETWORK=y
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index e25a163..265901a 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -303,7 +303,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_RODATA_TEST is not set
CONFIG_DEBUG_BOOT_PARAMS=y
CONFIG_OPTIMIZE_INLINING=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index cb5b3ab..4f404a6 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -300,7 +300,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_RODATA_TEST is not set
CONFIG_DEBUG_BOOT_PARAMS=y
CONFIG_OPTIMIZE_INLINING=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX=y
diff --git a/certs/Kconfig b/certs/Kconfig
index b030b9c..f0f8a44 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -39,4 +39,20 @@ config SYSTEM_TRUSTED_KEYS
form of DER-encoded *.x509 files in the top-level build directory,
those are no longer used. You will need to set this option instead.
+config SYSTEM_EXTRA_CERTIFICATE
+ bool "Reserve area for inserting a certificate without recompiling"
+ depends on SYSTEM_TRUSTED_KEYRING
+ help
+ If set, space for an extra certificate will be reserved in the kernel
+ image. This allows introducing a trusted certificate to the default
+ system keyring without recompiling the kernel.
+
+config SYSTEM_EXTRA_CERTIFICATE_SIZE
+ int "Number of bytes to reserve for the extra certificate"
+ depends on SYSTEM_EXTRA_CERTIFICATE
+ default 4096
+ help
+ This is the number of bytes reserved in the kernel image for a
+ certificate to be inserted.
+
endmenu
diff --git a/certs/Makefile b/certs/Makefile
index 28ac694..2773c4a 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -36,29 +36,34 @@ ifndef CONFIG_MODULE_SIG_HASH
$(error Could not determine digest type to use from kernel config)
endif
+redirect_openssl = 2>&1
+quiet_redirect_openssl = 2>&1
+silent_redirect_openssl = 2>/dev/null
+
# We do it this way rather than having a boolean option for enabling an
# external private key, because 'make randconfig' might enable such a
# boolean option and we unfortunately can't make it depend on !RANDCONFIG.
ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
$(obj)/signing_key.pem: $(obj)/x509.genkey
- @echo "###"
- @echo "### Now generating an X.509 key pair to be used for signing modules."
- @echo "###"
- @echo "### If this takes a long time, you might wish to run rngd in the"
- @echo "### background to keep the supply of entropy topped up. It"
- @echo "### needs to be run as root, and uses a hardware random"
- @echo "### number generator if one is available."
- @echo "###"
- openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
+ @$(kecho) "###"
+ @$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
+ @$(kecho) "###"
+ @$(kecho) "### If this takes a long time, you might wish to run rngd in the"
+ @$(kecho) "### background to keep the supply of entropy topped up. It"
+ @$(kecho) "### needs to be run as root, and uses a hardware random"
+ @$(kecho) "### number generator if one is available."
+ @$(kecho) "###"
+ $(Q)openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
-batch -x509 -config $(obj)/x509.genkey \
-outform PEM -out $(obj)/signing_key.pem \
- -keyout $(obj)/signing_key.pem 2>&1
- @echo "###"
- @echo "### Key pair generated."
- @echo "###"
+ -keyout $(obj)/signing_key.pem \
+ $($(quiet)redirect_openssl)
+ @$(kecho) "###"
+ @$(kecho) "### Key pair generated."
+ @$(kecho) "###"
$(obj)/x509.genkey:
- @echo Generating X.509 key generation config
+ @$(kecho) Generating X.509 key generation config
@echo >$@ "[ req ]"
@echo >>$@ "default_bits = 4096"
@echo >>$@ "distinguished_name = req_distinguished_name"
diff --git a/certs/system_certificates.S b/certs/system_certificates.S
index 9216e8c..c9ceb71 100644
--- a/certs/system_certificates.S
+++ b/certs/system_certificates.S
@@ -13,6 +13,19 @@ __cert_list_start:
.incbin "certs/x509_certificate_list"
__cert_list_end:
+#ifdef CONFIG_SYSTEM_EXTRA_CERTIFICATE
+ .globl VMLINUX_SYMBOL(system_extra_cert)
+ .size system_extra_cert, CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE
+VMLINUX_SYMBOL(system_extra_cert):
+ .fill CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE, 1, 0
+
+ .align 4
+ .globl VMLINUX_SYMBOL(system_extra_cert_used)
+VMLINUX_SYMBOL(system_extra_cert_used):
+ .int 0
+
+#endif /* CONFIG_SYSTEM_EXTRA_CERTIFICATE */
+
.align 8
.globl VMLINUX_SYMBOL(system_certificate_list_size)
VMLINUX_SYMBOL(system_certificate_list_size):
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 2570598..f418032 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -84,12 +84,12 @@ static __init int load_system_certificate_list(void)
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA |
- KEY_ALLOC_TRUSTED);
+ KEY_ALLOC_TRUSTED |
+ KEY_ALLOC_BUILT_IN);
if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
} else {
- set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description);
key_ref_put(key);
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 4870f28..91a7e04 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -12,7 +12,6 @@ if ASYMMETRIC_KEY_TYPE
config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
tristate "Asymmetric public-key crypto algorithm subtype"
select MPILIB
- select PUBLIC_KEY_ALGO_RSA
select CRYPTO_HASH_INFO
help
This option provides support for asymmetric public key type handling.
@@ -20,12 +19,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
appropriate hash algorithms (such as SHA-1) must be available.
ENOPKG will be reported if the requisite algorithm is unavailable.
-config PUBLIC_KEY_ALGO_RSA
- tristate "RSA public-key algorithm"
- select MPILIB
- help
- This option enables support for the RSA algorithm (PKCS#1, RFC3447).
-
config X509_CERTIFICATE_PARSER
tristate "X.509 certificate parser"
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index cd1406f..f904862 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
asymmetric_keys-y := asymmetric_type.o signature.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
-obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
#
# X.509 Certificate handling
@@ -16,21 +15,18 @@ obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
x509_key_parser-y := \
x509-asn1.o \
x509_akid-asn1.o \
- x509_rsakey-asn1.o \
x509_cert_parser.o \
x509_public_key.o
$(obj)/x509_cert_parser.o: \
$(obj)/x509-asn1.h \
- $(obj)/x509_akid-asn1.h \
- $(obj)/x509_rsakey-asn1.h
+ $(obj)/x509_akid-asn1.h
+
$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
$(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h
-$(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
clean-files += x509-asn1.c x509-asn1.h
clean-files += x509_akid-asn1.c x509_akid-asn1.h
-clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
#
# PKCS#7 message handling
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
index adcef59..3242cbf 100644
--- a/crypto/asymmetric_keys/mscode_parser.c
+++ b/crypto/asymmetric_keys/mscode_parser.c
@@ -86,25 +86,25 @@ int mscode_note_digest_algo(void *context, size_t hdrlen,
oid = look_up_OID(value, vlen);
switch (oid) {
case OID_md4:
- ctx->digest_algo = HASH_ALGO_MD4;
+ ctx->digest_algo = "md4";
break;
case OID_md5:
- ctx->digest_algo = HASH_ALGO_MD5;
+ ctx->digest_algo = "md5";
break;
case OID_sha1:
- ctx->digest_algo = HASH_ALGO_SHA1;
+ ctx->digest_algo = "sha1";
break;
case OID_sha256:
- ctx->digest_algo = HASH_ALGO_SHA256;
+ ctx->digest_algo = "sha256";
break;
case OID_sha384:
- ctx->digest_algo = HASH_ALGO_SHA384;
+ ctx->digest_algo = "sha384";
break;
case OID_sha512:
- ctx->digest_algo = HASH_ALGO_SHA512;
+ ctx->digest_algo = "sha512";
break;
case OID_sha224:
- ctx->digest_algo = HASH_ALGO_SHA224;
+ ctx->digest_algo = "sha224";
break;
case OID__NR:
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 8f3056c..40de03f 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -15,7 +15,7 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
#include "pkcs7_parser.h"
#include "pkcs7-asn1.h"
@@ -44,7 +44,7 @@ struct pkcs7_parse_context {
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
{
if (sinfo) {
- mpi_free(sinfo->sig.mpi[0]);
+ kfree(sinfo->sig.s);
kfree(sinfo->sig.digest);
kfree(sinfo->signing_cert_id);
kfree(sinfo);
@@ -87,7 +87,7 @@ EXPORT_SYMBOL_GPL(pkcs7_free_message);
static int pkcs7_check_authattrs(struct pkcs7_message *msg)
{
struct pkcs7_signed_info *sinfo;
- bool want;
+ bool want = false;
sinfo = msg->signed_infos;
if (sinfo->authattrs) {
@@ -218,25 +218,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_md4:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
+ ctx->sinfo->sig.hash_algo = "md4";
break;
case OID_md5:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
+ ctx->sinfo->sig.hash_algo = "md5";
break;
case OID_sha1:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
+ ctx->sinfo->sig.hash_algo = "sha1";
break;
case OID_sha256:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
+ ctx->sinfo->sig.hash_algo = "sha256";
break;
case OID_sha384:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384;
+ ctx->sinfo->sig.hash_algo = "sha384";
break;
case OID_sha512:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512;
+ ctx->sinfo->sig.hash_algo = "sha512";
break;
case OID_sha224:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224;
+ ctx->sinfo->sig.hash_algo = "sha224";
default:
printk("Unsupported digest algo: %u\n", ctx->last_oid);
return -ENOPKG;
@@ -255,7 +255,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_rsaEncryption:
- ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->sinfo->sig.pkey_algo = "rsa";
break;
default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
@@ -614,16 +614,12 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;
- MPI mpi;
- BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
-
- mpi = mpi_read_raw_data(value, vlen);
- if (!mpi)
+ ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL);
+ if (!ctx->sinfo->sig.s)
return -ENOMEM;
- ctx->sinfo->sig.mpi[0] = mpi;
- ctx->sinfo->sig.nr_mpi = 1;
+ ctx->sinfo->sig.s_size = vlen;
return 0;
}
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 90d6d47..3bbdcc7 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -17,7 +17,7 @@
#include <linux/asn1.h>
#include <linux/key.h>
#include <keys/asymmetric-type.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
#include "pkcs7_parser.h"
/**
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 325575c..50be2a1 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -16,7 +16,7 @@
#include <linux/err.h>
#include <linux/asn1.h>
#include <crypto/hash.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
#include "pkcs7_parser.h"
/*
@@ -31,17 +31,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
void *digest;
int ret;
- kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
+ kenter(",%u,%s", sinfo->index, sinfo->sig.hash_algo);
- if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
- !hash_algo_name[sinfo->sig.pkey_hash_algo])
+ if (!sinfo->sig.hash_algo)
return -ENOPKG;
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
- tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
- 0, 0);
+ tfm = crypto_alloc_shash(sinfo->sig.hash_algo, 0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 6db4c01..0f8b264 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -17,32 +17,13 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
#include <keys/asymmetric-subtype.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
+#include <crypto/akcipher.h>
MODULE_LICENSE("GPL");
-const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
- [PKEY_ALGO_DSA] = "DSA",
- [PKEY_ALGO_RSA] = "RSA",
-};
-EXPORT_SYMBOL_GPL(pkey_algo_name);
-
-const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = {
-#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
- defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
- [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
-#endif
-};
-EXPORT_SYMBOL_GPL(pkey_algo);
-
-const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
- [PKEY_ID_PGP] = "PGP",
- [PKEY_ID_X509] = "X509",
- [PKEY_ID_PKCS7] = "PKCS#7",
-};
-EXPORT_SYMBOL_GPL(pkey_id_type_name);
-
/*
* Provide a part of a description of the key for /proc/keys.
*/
@@ -52,8 +33,7 @@ static void public_key_describe(const struct key *asymmetric_key,
struct public_key *key = asymmetric_key->payload.data[asym_crypto];
if (key)
- seq_printf(m, "%s.%s",
- pkey_id_type_name[key->id_type], key->algo->name);
+ seq_printf(m, "%s.%s", key->id_type, key->pkey_algo);
}
/*
@@ -62,50 +42,116 @@ static void public_key_describe(const struct key *asymmetric_key,
void public_key_destroy(void *payload)
{
struct public_key *key = payload;
- int i;
- if (key) {
- for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
- mpi_free(key->mpi[i]);
- kfree(key);
- }
+ if (key)
+ kfree(key->key);
+ kfree(key);
}
EXPORT_SYMBOL_GPL(public_key_destroy);
+struct public_key_completion {
+ struct completion completion;
+ int err;
+};
+
+static void public_key_verify_done(struct crypto_async_request *req, int err)
+{
+ struct public_key_completion *compl = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ compl->err = err;
+ complete(&compl->completion);
+}
+
/*
* Verify a signature using a public key.
*/
-int public_key_verify_signature(const struct public_key *pk,
+int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig)
{
- const struct public_key_algorithm *algo;
-
- BUG_ON(!pk);
- BUG_ON(!pk->mpi[0]);
- BUG_ON(!pk->mpi[1]);
+ struct public_key_completion compl;
+ struct crypto_akcipher *tfm;
+ struct akcipher_request *req;
+ struct scatterlist sig_sg, digest_sg;
+ const char *alg_name;
+ char alg_name_buf[CRYPTO_MAX_ALG_NAME];
+ void *output;
+ unsigned int outlen;
+ int ret = -ENOMEM;
+
+ pr_devel("==>%s()\n", __func__);
+
+ BUG_ON(!pkey);
BUG_ON(!sig);
BUG_ON(!sig->digest);
- BUG_ON(!sig->mpi[0]);
-
- algo = pk->algo;
- if (!algo) {
- if (pk->pkey_algo >= PKEY_ALGO__LAST)
- return -ENOPKG;
- algo = pkey_algo[pk->pkey_algo];
- if (!algo)
- return -ENOPKG;
+ BUG_ON(!sig->s);
+
+ alg_name = sig->pkey_algo;
+ if (strcmp(sig->pkey_algo, "rsa") == 0) {
+ /* The data wangled by the RSA algorithm is typically padded
+ * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
+ * sec 8.2].
+ */
+ if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
+ "pkcs1pad(rsa,%s)", sig->hash_algo
+ ) >= CRYPTO_MAX_ALG_NAME)
+ return -EINVAL;
+ alg_name = alg_name_buf;
}
- if (!algo->verify_signature)
- return -ENOTSUPP;
-
- if (sig->nr_mpi != algo->n_sig_mpi) {
- pr_debug("Signature has %u MPI not %u\n",
- sig->nr_mpi, algo->n_sig_mpi);
- return -EINVAL;
+ tfm = crypto_alloc_akcipher(alg_name, 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ req = akcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req)
+ goto error_free_tfm;
+
+ ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
+ if (ret)
+ goto error_free_req;
+
+ outlen = crypto_akcipher_maxsize(tfm);
+ output = kmalloc(outlen, GFP_KERNEL);
+ if (!output)
+ goto error_free_req;
+
+ sg_init_one(&sig_sg, sig->s, sig->s_size);
+ sg_init_one(&digest_sg, output, outlen);
+ akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
+ outlen);
+ init_completion(&compl.completion);
+ akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ public_key_verify_done, &compl);
+
+ /* Perform the verification calculation. This doesn't actually do the
+ * verification, but rather calculates the hash expected by the
+ * signature and returns that to us.
+ */
+ ret = crypto_akcipher_verify(req);
+ if (ret == -EINPROGRESS) {
+ wait_for_completion(&compl.completion);
+ ret = compl.err;
}
-
- return algo->verify_signature(pk, sig);
+ if (ret < 0)
+ goto out_free_output;
+
+ /* Do the actual verification step. */
+ if (req->dst_len != sig->digest_size ||
+ memcmp(sig->digest, output, sig->digest_size) != 0)
+ ret = -EKEYREJECTED;
+
+out_free_output:
+ kfree(output);
+error_free_req:
+ akcipher_request_free(req);
+error_free_tfm:
+ crypto_free_akcipher(tfm);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(public_key_verify_signature);
diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
deleted file mode 100644
index 5c37a22..0000000
--- a/crypto/asymmetric_keys/public_key.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Public key algorithm internals
- *
- * See Documentation/crypto/asymmetric-keys.txt
- *
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#include <crypto/public_key.h>
-
-extern struct asymmetric_key_subtype public_key_subtype;
-
-/*
- * Public key algorithm definition.
- */
-struct public_key_algorithm {
- const char *name;
- u8 n_pub_mpi; /* Number of MPIs in public key */
- u8 n_sec_mpi; /* Number of MPIs in secret key */
- u8 n_sig_mpi; /* Number of MPIs in a signature */
- int (*verify_signature)(const struct public_key *key,
- const struct public_key_signature *sig);
-};
-
-extern const struct public_key_algorithm RSA_public_key_algorithm;
-
-/*
- * public_key.c
- */
-extern int public_key_verify_signature(const struct public_key *pk,
- const struct public_key_signature *sig);
diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
deleted file mode 100644
index 508b57b..0000000
--- a/crypto/asymmetric_keys/rsa.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/* RSA asymmetric public-key algorithm [RFC3447]
- *
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#define pr_fmt(fmt) "RSA: "fmt
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <crypto/algapi.h>
-#include "public_key.h"
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("RSA Public Key Algorithm");
-
-#define kenter(FMT, ...) \
- pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
-#define kleave(FMT, ...) \
- pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
-
-/*
- * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
- */
-static const u8 RSA_digest_info_MD5[] = {
- 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
- 0x05, 0x00, 0x04, 0x10
-};
-
-static const u8 RSA_digest_info_SHA1[] = {
- 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
- 0x2B, 0x0E, 0x03, 0x02, 0x1A,
- 0x05, 0x00, 0x04, 0x14
-};
-
-static const u8 RSA_digest_info_RIPE_MD_160[] = {
- 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
- 0x2B, 0x24, 0x03, 0x02, 0x01,
- 0x05, 0x00, 0x04, 0x14
-};
-
-static const u8 RSA_digest_info_SHA224[] = {
- 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
- 0x05, 0x00, 0x04, 0x1C
-};
-
-static const u8 RSA_digest_info_SHA256[] = {
- 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
- 0x05, 0x00, 0x04, 0x20
-};
-
-static const u8 RSA_digest_info_SHA384[] = {
- 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
- 0x05, 0x00, 0x04, 0x30
-};
-
-static const u8 RSA_digest_info_SHA512[] = {
- 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
- 0x05, 0x00, 0x04, 0x40
-};
-
-static const struct {
- const u8 *data;
- size_t size;
-} RSA_ASN1_templates[PKEY_HASH__LAST] = {
-#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
- [HASH_ALGO_MD5] = _(MD5),
- [HASH_ALGO_SHA1] = _(SHA1),
- [HASH_ALGO_RIPE_MD_160] = _(RIPE_MD_160),
- [HASH_ALGO_SHA256] = _(SHA256),
- [HASH_ALGO_SHA384] = _(SHA384),
- [HASH_ALGO_SHA512] = _(SHA512),
- [HASH_ALGO_SHA224] = _(SHA224),
-#undef _
-};
-
-/*
- * RSAVP1() function [RFC3447 sec 5.2.2]
- */
-static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
-{
- MPI m;
- int ret;
-
- /* (1) Validate 0 <= s < n */
- if (mpi_cmp_ui(s, 0) < 0) {
- kleave(" = -EBADMSG [s < 0]");
- return -EBADMSG;
- }
- if (mpi_cmp(s, key->rsa.n) >= 0) {
- kleave(" = -EBADMSG [s >= n]");
- return -EBADMSG;
- }
-
- m = mpi_alloc(0);
- if (!m)
- return -ENOMEM;
-
- /* (2) m = s^e mod n */
- ret = mpi_powm(m, s, key->rsa.e, key->rsa.n);
- if (ret < 0) {
- mpi_free(m);
- return ret;
- }
-
- *_m = m;
- return 0;
-}
-
-/*
- * Integer to Octet String conversion [RFC3447 sec 4.1]
- */
-static int RSA_I2OSP(MPI x, size_t xLen, u8 **pX)
-{
- unsigned X_size, x_size;
- int X_sign;
- u8 *X;
-
- /* Make sure the string is the right length. The number should begin
- * with { 0x00, 0x01, ... } so we have to account for 15 leading zero
- * bits not being reported by MPI.
- */
- x_size = mpi_get_nbits(x);
- pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8);
- if (x_size != xLen * 8 - 15)
- return -ERANGE;
-
- X = mpi_get_buffer(x, &X_size, &X_sign);
- if (!X)
- return -ENOMEM;
- if (X_sign < 0) {
- kfree(X);
- return -EBADMSG;
- }
- if (X_size != xLen - 1) {
- kfree(X);
- return -EBADMSG;
- }
-
- *pX = X;
- return 0;
-}
-
-/*
- * Perform the RSA signature verification.
- * @H: Value of hash of data and metadata
- * @EM: The computed signature value
- * @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
- * @hash_size: The size of H
- * @asn1_template: The DigestInfo ASN.1 template
- * @asn1_size: Size of asm1_template[]
- */
-static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
- const u8 *asn1_template, size_t asn1_size)
-{
- unsigned PS_end, T_offset, i;
-
- kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
-
- if (k < 2 + 1 + asn1_size + hash_size)
- return -EBADMSG;
-
- /* Decode the EMSA-PKCS1-v1_5 */
- if (EM[1] != 0x01) {
- kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]);
- return -EBADMSG;
- }
-
- T_offset = k - (asn1_size + hash_size);
- PS_end = T_offset - 1;
- if (EM[PS_end] != 0x00) {
- kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
- return -EBADMSG;
- }
-
- for (i = 2; i < PS_end; i++) {
- if (EM[i] != 0xff) {
- kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
- return -EBADMSG;
- }
- }
-
- if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) {
- kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
- return -EBADMSG;
- }
-
- if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) {
- kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
- return -EKEYREJECTED;
- }
-
- kleave(" = 0");
- return 0;
-}
-
-/*
- * Perform the verification step [RFC3447 sec 8.2.2].
- */
-static int RSA_verify_signature(const struct public_key *key,
- const struct public_key_signature *sig)
-{
- size_t tsize;
- int ret;
-
- /* Variables as per RFC3447 sec 8.2.2 */
- const u8 *H = sig->digest;
- u8 *EM = NULL;
- MPI m = NULL;
- size_t k;
-
- kenter("");
-
- if (!RSA_ASN1_templates[sig->pkey_hash_algo].data)
- return -ENOTSUPP;
-
- /* (1) Check the signature size against the public key modulus size */
- k = mpi_get_nbits(key->rsa.n);
- tsize = mpi_get_nbits(sig->rsa.s);
-
- /* According to RFC 4880 sec 3.2, length of MPI is computed starting
- * from most significant bit. So the RFC 3447 sec 8.2.2 size check
- * must be relaxed to conform with shorter signatures - so we fail here
- * only if signature length is longer than modulus size.
- */
- pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
- if (k < tsize) {
- ret = -EBADMSG;
- goto error;
- }
-
- /* Round up and convert to octets */
- k = (k + 7) / 8;
-
- /* (2b) Apply the RSAVP1 verification primitive to the public key */
- ret = RSAVP1(key, sig->rsa.s, &m);
- if (ret < 0)
- goto error;
-
- /* (2c) Convert the message representative (m) to an encoded message
- * (EM) of length k octets.
- *
- * NOTE! The leading zero byte is suppressed by MPI, so we pass a
- * pointer to the _preceding_ byte to RSA_verify()!
- */
- ret = RSA_I2OSP(m, k, &EM);
- if (ret < 0)
- goto error;
-
- ret = RSA_verify(H, EM - 1, k, sig->digest_size,
- RSA_ASN1_templates[sig->pkey_hash_algo].data,
- RSA_ASN1_templates[sig->pkey_hash_algo].size);
-
-error:
- kfree(EM);
- mpi_free(m);
- kleave(" = %d", ret);
- return ret;
-}
-
-const struct public_key_algorithm RSA_public_key_algorithm = {
- .name = "RSA",
- .n_pub_mpi = 2,
- .n_sec_mpi = 3,
- .n_sig_mpi = 1,
- .verify_signature = RSA_verify_signature,
-};
-EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 897b734..7e8c233 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -328,12 +328,12 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
void *digest;
int ret;
- kenter(",%u", ctx->digest_algo);
+ kenter(",%s", ctx->digest_algo);
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
- tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0);
+ tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h
index 55d5f7e..a133eb8 100644
--- a/crypto/asymmetric_keys/verify_pefile.h
+++ b/crypto/asymmetric_keys/verify_pefile.h
@@ -28,7 +28,7 @@ struct pefile_context {
/* PKCS#7 MS Individual Code Signing content */
const void *digest; /* Digest */
unsigned digest_len; /* Digest length */
- enum hash_algo digest_algo; /* Digest algorithm */
+ const char *digest_algo; /* Digest algorithm */
};
#define kenter(FMT, ...) \
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 021d39c..4a29bac 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -15,11 +15,10 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
-#include "public_key.h"
+#include <crypto/public_key.h>
#include "x509_parser.h"
#include "x509-asn1.h"
#include "x509_akid-asn1.h"
-#include "x509_rsakey-asn1.h"
struct x509_parse_context {
struct x509_certificate *cert; /* Certificate being constructed */
@@ -56,7 +55,7 @@ void x509_free_certificate(struct x509_certificate *cert)
kfree(cert->akid_id);
kfree(cert->akid_skid);
kfree(cert->sig.digest);
- mpi_free(cert->sig.rsa.s);
+ kfree(cert->sig.s);
kfree(cert);
}
}
@@ -103,12 +102,12 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
}
}
- /* Decode the public key */
- ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx,
- ctx->key, ctx->key_size);
- if (ret < 0)
+ cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
+ if (!cert->pub->key)
goto error_decode;
+ cert->pub->keylen = ctx->key_size;
+
/* Generate cert issuer + serial number key ID */
kid = asymmetric_key_generate_id(cert->raw_serial,
cert->raw_serial_size,
@@ -124,6 +123,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
return cert;
error_decode:
+ kfree(cert->pub->key);
kfree(ctx);
error_no_ctx:
x509_free_certificate(cert);
@@ -188,33 +188,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
return -ENOPKG; /* Unsupported combination */
case OID_md4WithRSAEncryption:
- ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5;
- ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->sig.hash_algo = "md4";
+ ctx->cert->sig.pkey_algo = "rsa";
break;
case OID_sha1WithRSAEncryption:
- ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1;
- ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->sig.hash_algo = "sha1";
+ ctx->cert->sig.pkey_algo = "rsa";
break;
case OID_sha256WithRSAEncryption:
- ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256;
- ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->sig.hash_algo = "sha256";
+ ctx->cert->sig.pkey_algo = "rsa";
break;
case OID_sha384WithRSAEncryption:
- ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384;
- ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->sig.hash_algo = "sha384";
+ ctx->cert->sig.pkey_algo = "rsa";
break;
case OID_sha512WithRSAEncryption:
- ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512;
- ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->sig.hash_algo = "sha512";
+ ctx->cert->sig.pkey_algo = "rsa";
break;
case OID_sha224WithRSAEncryption:
- ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224;
- ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->sig.hash_algo = "sha224";
+ ctx->cert->sig.pkey_algo = "rsa";
break;
}
@@ -396,7 +396,7 @@ int x509_extract_key_data(void *context, size_t hdrlen,
if (ctx->last_oid != OID_rsaEncryption)
return -ENOPKG;
- ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA;
+ ctx->cert->pub->pkey_algo = "rsa";
/* Discard the BIT STRING metadata */
ctx->key = value + 1;
@@ -404,29 +404,6 @@ int x509_extract_key_data(void *context, size_t hdrlen,
return 0;
}
-/*
- * Extract a RSA public key value
- */
-int rsa_extract_mpi(void *context, size_t hdrlen,
- unsigned char tag,
- const void *value, size_t vlen)
-{
- struct x509_parse_context *ctx = context;
- MPI mpi;
-
- if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) {
- pr_err("Too many public key MPIs in certificate\n");
- return -EBADMSG;
- }
-
- mpi = mpi_read_raw_data(value, vlen);
- if (!mpi)
- return -ENOMEM;
-
- ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi;
- return 0;
-}
-
/* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
#define SEQ_TAG_KEYID (ASN1_CONT << 6)
@@ -494,7 +471,7 @@ int x509_decode_time(time64_t *_t, size_t hdrlen,
unsigned char tag,
const unsigned char *value, size_t vlen)
{
- static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30,
+ static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 };
const unsigned char *p = value;
unsigned year, mon, day, hour, min, sec, mon_len;
@@ -540,17 +517,17 @@ int x509_decode_time(time64_t *_t, size_t hdrlen,
if (year % 4 == 0) {
mon_len = 29;
if (year % 100 == 0) {
- year /= 100;
- if (year % 4 != 0)
- mon_len = 28;
+ mon_len = 28;
+ if (year % 400 == 0)
+ mon_len = 29;
}
}
}
if (day < 1 || day > mon_len ||
- hour > 23 ||
+ hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
min > 59 ||
- sec > 59)
+ sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
goto invalid_time;
*_t = mktime64(year, mon, day, hour, min, sec);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 9e9e5a6..733c046 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -13,15 +13,11 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/mpi.h>
-#include <linux/asn1_decoder.h>
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <keys/system_keyring.h>
#include <crypto/hash.h>
#include "asymmetric_keys.h"
-#include "public_key.h"
#include "x509_parser.h"
static bool use_builtin_keys;
@@ -167,18 +163,20 @@ int x509_get_sig_params(struct x509_certificate *cert)
if (cert->unsupported_crypto)
return -ENOPKG;
- if (cert->sig.rsa.s)
+ if (cert->sig.s)
return 0;
- cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
- if (!cert->sig.rsa.s)
+ cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size,
+ GFP_KERNEL);
+ if (!cert->sig.s)
return -ENOMEM;
- cert->sig.nr_mpi = 1;
+
+ cert->sig.s_size = cert->raw_sig_size;
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
- tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
+ tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0);
if (IS_ERR(tfm)) {
if (PTR_ERR(tfm) == -ENOENT) {
cert->unsupported_crypto = true;
@@ -293,24 +291,20 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
pr_devel("Cert Issuer: %s\n", cert->issuer);
pr_devel("Cert Subject: %s\n", cert->subject);
- if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
- cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
- cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
- !pkey_algo[cert->pub->pkey_algo] ||
- !pkey_algo[cert->sig.pkey_algo] ||
- !hash_algo_name[cert->sig.pkey_hash_algo]) {
+ if (!cert->pub->pkey_algo ||
+ !cert->sig.pkey_algo ||
+ !cert->sig.hash_algo) {
ret = -ENOPKG;
goto error_free_cert;
}
- pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
+ pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
pr_devel("Cert Signature: %s + %s\n",
- pkey_algo_name[cert->sig.pkey_algo],
- hash_algo_name[cert->sig.pkey_hash_algo]);
+ cert->sig.pkey_algo,
+ cert->sig.hash_algo);
- cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
- cert->pub->id_type = PKEY_ID_X509;
+ cert->pub->id_type = "X509";
/* Check the signature on the key if it appears to be self-signed */
if ((!cert->akid_skid && !cert->akid_id) ||
diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1
deleted file mode 100644
index 4ec7cc6..0000000
--- a/crypto/asymmetric_keys/x509_rsakey.asn1
+++ /dev/null
@@ -1,4 +0,0 @@
-RSAPublicKey ::= SEQUENCE {
- modulus INTEGER ({ rsa_extract_mpi }), -- n
- publicExponent INTEGER ({ rsa_extract_mpi }) -- e
- }
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 50f5c97..1cea67d 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -18,12 +18,89 @@
#include <linux/module.h>
#include <linux/random.h>
+/*
+ * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
+ */
+static const u8 rsa_digest_info_md5[] = {
+ 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */
+ 0x05, 0x00, 0x04, 0x10
+};
+
+static const u8 rsa_digest_info_sha1[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+ 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+ 0x05, 0x00, 0x04, 0x14
+};
+
+static const u8 rsa_digest_info_rmd160[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+ 0x2b, 0x24, 0x03, 0x02, 0x01,
+ 0x05, 0x00, 0x04, 0x14
+};
+
+static const u8 rsa_digest_info_sha224[] = {
+ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
+ 0x05, 0x00, 0x04, 0x1c
+};
+
+static const u8 rsa_digest_info_sha256[] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x04, 0x20
+};
+
+static const u8 rsa_digest_info_sha384[] = {
+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
+ 0x05, 0x00, 0x04, 0x30
+};
+
+static const u8 rsa_digest_info_sha512[] = {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+ 0x05, 0x00, 0x04, 0x40
+};
+
+static const struct rsa_asn1_template {
+ const char *name;
+ const u8 *data;
+ size_t size;
+} rsa_asn1_templates[] = {
+#define _(X) { #X, rsa_digest_info_##X, sizeof(rsa_digest_info_##X) }
+ _(md5),
+ _(sha1),
+ _(rmd160),
+ _(sha256),
+ _(sha384),
+ _(sha512),
+ _(sha224),
+ { NULL }
+#undef _
+};
+
+static const struct rsa_asn1_template *rsa_lookup_asn1(const char *name)
+{
+ const struct rsa_asn1_template *p;
+
+ for (p = rsa_asn1_templates; p->name; p++)
+ if (strcmp(name, p->name) == 0)
+ return p;
+ return NULL;
+}
+
struct pkcs1pad_ctx {
struct crypto_akcipher *child;
-
+ const char *hash_name;
unsigned int key_size;
};
+struct pkcs1pad_inst_ctx {
+ struct crypto_akcipher_spawn spawn;
+ const char *hash_name;
+};
+
struct pkcs1pad_request {
struct akcipher_request child_req;
@@ -339,13 +416,22 @@ static int pkcs1pad_sign(struct akcipher_request *req)
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
+ const struct rsa_asn1_template *digest_info = NULL;
int err;
- unsigned int ps_end;
+ unsigned int ps_end, digest_size = 0;
if (!ctx->key_size)
return -EINVAL;
- if (req->src_len > ctx->key_size - 11)
+ if (ctx->hash_name) {
+ digest_info = rsa_lookup_asn1(ctx->hash_name);
+ if (!digest_info)
+ return -EINVAL;
+
+ digest_size = digest_info->size;
+ }
+
+ if (req->src_len + digest_size > ctx->key_size - 11)
return -EOVERFLOW;
if (req->dst_len < ctx->key_size) {
@@ -371,11 +457,16 @@ static int pkcs1pad_sign(struct akcipher_request *req)
if (!req_ctx->in_buf)
return -ENOMEM;
- ps_end = ctx->key_size - req->src_len - 2;
+ ps_end = ctx->key_size - digest_size - req->src_len - 2;
req_ctx->in_buf[0] = 0x01;
memset(req_ctx->in_buf + 1, 0xff, ps_end - 1);
req_ctx->in_buf[ps_end] = 0x00;
+ if (digest_info) {
+ memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data,
+ digest_info->size);
+ }
+
pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf,
ctx->key_size - 1 - req->src_len, req->src);
@@ -408,6 +499,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
+ const struct rsa_asn1_template *digest_info;
unsigned int pos;
if (err == -EOVERFLOW)
@@ -422,20 +514,33 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
goto done;
}
- if (req_ctx->out_buf[0] != 0x01) {
- err = -EINVAL;
+ err = -EBADMSG;
+ if (req_ctx->out_buf[0] != 0x01)
goto done;
- }
+
for (pos = 1; pos < req_ctx->child_req.dst_len; pos++)
if (req_ctx->out_buf[pos] != 0xff)
break;
+
if (pos < 9 || pos == req_ctx->child_req.dst_len ||
- req_ctx->out_buf[pos] != 0x00) {
- err = -EINVAL;
+ req_ctx->out_buf[pos] != 0x00)
goto done;
- }
pos++;
+ if (ctx->hash_name) {
+ digest_info = rsa_lookup_asn1(ctx->hash_name);
+ if (!digest_info)
+ goto done;
+
+ if (memcmp(req_ctx->out_buf + pos, digest_info->data,
+ digest_info->size))
+ goto done;
+
+ pos += digest_info->size;
+ }
+
+ err = 0;
+
if (req->dst_len < req_ctx->child_req.dst_len - pos)
err = -EOVERFLOW;
req->dst_len = req_ctx->child_req.dst_len - pos;
@@ -444,7 +549,6 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
sg_copy_from_buffer(req->dst,
sg_nents_for_len(req->dst, req->dst_len),
req_ctx->out_buf + pos, req->dst_len);
-
done:
kzfree(req_ctx->out_buf);
@@ -481,7 +585,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
int err;
- if (!ctx->key_size || req->src_len != ctx->key_size)
+ if (!ctx->key_size || req->src_len < ctx->key_size)
return -EINVAL;
if (ctx->key_size > PAGE_SIZE)
@@ -518,6 +622,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
{
struct akcipher_instance *inst = akcipher_alg_instance(tfm);
+ struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
struct crypto_akcipher *child_tfm;
@@ -526,7 +631,7 @@ static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm)
return PTR_ERR(child_tfm);
ctx->child = child_tfm;
-
+ ctx->hash_name = ictx->hash_name;
return 0;
}
@@ -539,10 +644,11 @@ static void pkcs1pad_exit_tfm(struct crypto_akcipher *tfm)
static void pkcs1pad_free(struct akcipher_instance *inst)
{
- struct crypto_akcipher_spawn *spawn = akcipher_instance_ctx(inst);
+ struct pkcs1pad_inst_ctx *ctx = akcipher_instance_ctx(inst);
+ struct crypto_akcipher_spawn *spawn = &ctx->spawn;
crypto_drop_akcipher(spawn);
-
+ kfree(ctx->hash_name);
kfree(inst);
}
@@ -550,9 +656,11 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
{
struct crypto_attr_type *algt;
struct akcipher_instance *inst;
+ struct pkcs1pad_inst_ctx *ctx;
struct crypto_akcipher_spawn *spawn;
struct akcipher_alg *rsa_alg;
const char *rsa_alg_name;
+ const char *hash_name;
int err;
algt = crypto_get_attr_type(tb);
@@ -566,11 +674,18 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
if (IS_ERR(rsa_alg_name))
return PTR_ERR(rsa_alg_name);
- inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+ hash_name = crypto_attr_alg_name(tb[2]);
+ if (IS_ERR(hash_name))
+ hash_name = NULL;
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
if (!inst)
return -ENOMEM;
- spawn = akcipher_instance_ctx(inst);
+ ctx = akcipher_instance_ctx(inst);
+ spawn = &ctx->spawn;
+ ctx->hash_name = hash_name ? kstrdup(hash_name, GFP_KERNEL) : NULL;
+
crypto_set_spawn(&spawn->base, akcipher_crypto_instance(inst));
err = crypto_grab_akcipher(spawn, rsa_alg_name, 0,
crypto_requires_sync(algt->type, algt->mask));
@@ -580,15 +695,28 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
rsa_alg = crypto_spawn_akcipher_alg(spawn);
err = -ENAMETOOLONG;
- if (snprintf(inst->alg.base.cra_name,
- CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
- rsa_alg->base.cra_name) >=
- CRYPTO_MAX_ALG_NAME ||
- snprintf(inst->alg.base.cra_driver_name,
- CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
- rsa_alg->base.cra_driver_name) >=
- CRYPTO_MAX_ALG_NAME)
+
+ if (!hash_name) {
+ if (snprintf(inst->alg.base.cra_name,
+ CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
+ rsa_alg->base.cra_name) >=
+ CRYPTO_MAX_ALG_NAME ||
+ snprintf(inst->alg.base.cra_driver_name,
+ CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)",
+ rsa_alg->base.cra_driver_name) >=
+ CRYPTO_MAX_ALG_NAME)
goto out_drop_alg;
+ } else {
+ if (snprintf(inst->alg.base.cra_name,
+ CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
+ rsa_alg->base.cra_name, hash_name) >=
+ CRYPTO_MAX_ALG_NAME ||
+ snprintf(inst->alg.base.cra_driver_name,
+ CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)",
+ rsa_alg->base.cra_driver_name, hash_name) >=
+ CRYPTO_MAX_ALG_NAME)
+ goto out_free_hash;
+ }
inst->alg.base.cra_flags = rsa_alg->base.cra_flags & CRYPTO_ALG_ASYNC;
inst->alg.base.cra_priority = rsa_alg->base.cra_priority;
@@ -610,10 +738,12 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb)
err = akcipher_register_instance(tmpl, inst);
if (err)
- goto out_drop_alg;
+ goto out_free_hash;
return 0;
+out_free_hash:
+ kfree(ctx->hash_name);
out_drop_alg:
crypto_drop_akcipher(spawn);
out_free_inst:
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b9250e5..f3f7215 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -23,6 +23,7 @@
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/list.h>
+#include <linux/fs.h>
#include <linux/async.h>
#include <linux/pm.h>
#include <linux/suspend.h>
@@ -291,40 +292,19 @@ static const char * const fw_path[] = {
module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
-static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
+static void fw_finish_direct_load(struct device *device,
+ struct firmware_buf *buf)
{
- int size;
- char *buf;
- int rc;
-
- if (!S_ISREG(file_inode(file)->i_mode))
- return -EINVAL;
- size = i_size_read(file_inode(file));
- if (size <= 0)
- return -EINVAL;
- buf = vmalloc(size);
- if (!buf)
- return -ENOMEM;
- rc = kernel_read(file, 0, buf, size);
- if (rc != size) {
- if (rc > 0)
- rc = -EIO;
- goto fail;
- }
- rc = security_kernel_fw_from_file(file, buf, size);
- if (rc)
- goto fail;
- fw_buf->data = buf;
- fw_buf->size = size;
- return 0;
-fail:
- vfree(buf);
- return rc;
+ mutex_lock(&fw_lock);
+ set_bit(FW_STATUS_DONE, &buf->status);
+ complete_all(&buf->completion);
+ mutex_unlock(&fw_lock);
}
static int fw_get_filesystem_firmware(struct device *device,
struct firmware_buf *buf)
{
+ loff_t size;
int i, len;
int rc = -ENOENT;
char *path;
@@ -334,8 +314,6 @@ static int fw_get_filesystem_firmware(struct device *device,
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
- struct file *file;
-
/* skip the unset customized path */
if (!fw_path[i][0])
continue;
@@ -347,28 +325,25 @@ static int fw_get_filesystem_firmware(struct device *device,
break;
}
- file = filp_open(path, O_RDONLY, 0);
- if (IS_ERR(file))
+ buf->size = 0;
+ rc = kernel_read_file_from_path(path, &buf->data, &size,
+ INT_MAX, READING_FIRMWARE);
+ if (rc) {
+ if (rc == -ENOENT)
+ dev_dbg(device, "loading %s failed with error %d\n",
+ path, rc);
+ else
+ dev_warn(device, "loading %s failed with error %d\n",
+ path, rc);
continue;
- rc = fw_read_file_contents(file, buf);
- fput(file);
- if (rc)
- dev_warn(device, "firmware, attempted to load %s, but failed with error %d\n",
- path, rc);
- else
- break;
+ }
+ dev_dbg(device, "direct-loading %s\n", buf->fw_id);
+ buf->size = size;
+ fw_finish_direct_load(device, buf);
+ break;
}
__putname(path);
- if (!rc) {
- dev_dbg(device, "firmware: direct-loading firmware %s\n",
- buf->fw_id);
- mutex_lock(&fw_lock);
- set_bit(FW_STATUS_DONE, &buf->status);
- complete_all(&buf->completion);
- mutex_unlock(&fw_lock);
- }
-
return rc;
}
@@ -685,8 +660,9 @@ static ssize_t firmware_loading_store(struct device *dev,
dev_err(dev, "%s: map pages failed\n",
__func__);
else
- rc = security_kernel_fw_from_file(NULL,
- fw_buf->data, fw_buf->size);
+ rc = security_kernel_post_read_file(NULL,
+ fw_buf->data, fw_buf->size,
+ READING_FIRMWARE);
/*
* Same logic as fw_load_abort, only the DONE bit
@@ -1051,7 +1027,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
}
if (fw_get_builtin_firmware(firmware, name)) {
- dev_dbg(device, "firmware: using built-in firmware %s\n", name);
+ dev_dbg(device, "using built-in %s\n", name);
return 0; /* assigned */
}
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 45cc39a..274dd01 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -88,6 +88,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
const struct tpm_class_ops *ops)
{
struct tpm_chip *chip;
+ int rc;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
@@ -136,11 +137,17 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
chip->cdev.owner = chip->pdev->driver->owner;
chip->cdev.kobj.parent = &chip->dev.kobj;
+ rc = devm_add_action(dev, (void (*)(void *)) put_device, &chip->dev);
+ if (rc) {
+ put_device(&chip->dev);
+ return ERR_PTR(rc);
+ }
+
return chip;
}
EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
-static int tpm_dev_add_device(struct tpm_chip *chip)
+static int tpm_add_char_device(struct tpm_chip *chip)
{
int rc;
@@ -151,7 +158,6 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
chip->devname, MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
- device_unregister(&chip->dev);
return rc;
}
@@ -162,16 +168,17 @@ static int tpm_dev_add_device(struct tpm_chip *chip)
chip->devname, MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
+ cdev_del(&chip->cdev);
return rc;
}
return rc;
}
-static void tpm_dev_del_device(struct tpm_chip *chip)
+static void tpm_del_char_device(struct tpm_chip *chip)
{
cdev_del(&chip->cdev);
- device_unregister(&chip->dev);
+ device_del(&chip->dev);
}
static int tpm1_chip_register(struct tpm_chip *chip)
@@ -222,7 +229,7 @@ int tpm_chip_register(struct tpm_chip *chip)
tpm_add_ppi(chip);
- rc = tpm_dev_add_device(chip);
+ rc = tpm_add_char_device(chip);
if (rc)
goto out_err;
@@ -274,6 +281,6 @@ void tpm_chip_unregister(struct tpm_chip *chip)
sysfs_remove_link(&chip->pdev->kobj, "ppi");
tpm1_chip_unregister(chip);
- tpm_dev_del_device(chip);
+ tpm_del_char_device(chip);
}
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 542a80c..28b477e 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -128,13 +128,6 @@ enum tpm2_startup_types {
TPM2_SU_STATE = 0x0001,
};
-enum tpm2_start_method {
- TPM2_START_ACPI = 2,
- TPM2_START_FIFO = 6,
- TPM2_START_CRB = 7,
- TPM2_START_CRB_WITH_ACPI = 8,
-};
-
struct tpm_chip;
struct tpm_vendor_specific {
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 45a6340..b28e4da 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -20,7 +20,11 @@
#include <keys/trusted-type.h>
enum tpm2_object_attributes {
- TPM2_ATTR_USER_WITH_AUTH = BIT(6),
+ TPM2_OA_USER_WITH_AUTH = BIT(6),
+};
+
+enum tpm2_session_attributes {
+ TPM2_SA_CONTINUE_SESSION = BIT(0),
};
struct tpm2_startup_in {
@@ -478,22 +482,18 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
tpm_buf_append_u8(&buf, payload->migratable);
/* public */
- if (options->policydigest)
- tpm_buf_append_u16(&buf, 14 + options->digest_len);
- else
- tpm_buf_append_u16(&buf, 14);
-
+ tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
tpm_buf_append_u16(&buf, hash);
/* policy */
- if (options->policydigest) {
+ if (options->policydigest_len) {
tpm_buf_append_u32(&buf, 0);
- tpm_buf_append_u16(&buf, options->digest_len);
+ tpm_buf_append_u16(&buf, options->policydigest_len);
tpm_buf_append(&buf, options->policydigest,
- options->digest_len);
+ options->policydigest_len);
} else {
- tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
+ tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
tpm_buf_append_u16(&buf, 0);
}
@@ -631,7 +631,7 @@ static int tpm2_unseal(struct tpm_chip *chip,
options->policyhandle ?
options->policyhandle : TPM2_RS_PW,
NULL /* nonce */, 0,
- 0 /* session_attributes */,
+ TPM2_SA_CONTINUE_SESSION,
options->blobauth /* hmac */,
TPM_DIGEST_SIZE);
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 8342cf5..a12b319 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -34,14 +34,6 @@ enum crb_defaults {
CRB_ACPI_START_INDEX = 1,
};
-struct acpi_tpm2 {
- struct acpi_table_header hdr;
- u16 platform_class;
- u16 reserved;
- u64 control_area_pa;
- u32 start_method;
-} __packed;
-
enum crb_ca_request {
CRB_CA_REQ_GO_IDLE = BIT(0),
CRB_CA_REQ_CMD_READY = BIT(1),
@@ -85,6 +77,8 @@ enum crb_flags {
struct crb_priv {
unsigned int flags;
+ struct resource res;
+ void __iomem *iobase;
struct crb_control_area __iomem *cca;
u8 __iomem *cmd;
u8 __iomem *rsp;
@@ -97,7 +91,7 @@ static u8 crb_status(struct tpm_chip *chip)
struct crb_priv *priv = chip->vendor.priv;
u8 sts = 0;
- if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) !=
+ if ((ioread32(&priv->cca->start) & CRB_START_INVOKE) !=
CRB_START_INVOKE)
sts |= CRB_STS_COMPLETE;
@@ -113,7 +107,7 @@ static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
if (count < 6)
return -EIO;
- if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR)
+ if (ioread32(&priv->cca->sts) & CRB_CA_STS_ERROR)
return -EIO;
memcpy_fromio(buf, priv->rsp, 6);
@@ -149,11 +143,11 @@ static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
struct crb_priv *priv = chip->vendor.priv;
int rc = 0;
- if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
+ if (len > ioread32(&priv->cca->cmd_size)) {
dev_err(&chip->dev,
"invalid command count value %x %zx\n",
(unsigned int) len,
- (size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size)));
+ (size_t) ioread32(&priv->cca->cmd_size));
return -E2BIG;
}
@@ -189,7 +183,7 @@ static void crb_cancel(struct tpm_chip *chip)
static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
{
struct crb_priv *priv = chip->vendor.priv;
- u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel));
+ u32 cancel = ioread32(&priv->cca->cancel);
return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
}
@@ -204,97 +198,145 @@ static const struct tpm_class_ops tpm_crb = {
.req_complete_val = CRB_STS_COMPLETE,
};
-static int crb_acpi_add(struct acpi_device *device)
+static int crb_init(struct acpi_device *device, struct crb_priv *priv)
{
struct tpm_chip *chip;
- struct acpi_tpm2 *buf;
+ int rc;
+
+ chip = tpmm_chip_alloc(&device->dev, &tpm_crb);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ chip->vendor.priv = priv;
+ chip->acpi_dev_handle = device->handle;
+ chip->flags = TPM_CHIP_FLAG_TPM2;
+
+ rc = tpm_get_timeouts(chip);
+ if (rc)
+ return rc;
+
+ rc = tpm2_do_selftest(chip);
+ if (rc)
+ return rc;
+
+ return tpm_chip_register(chip);
+}
+
+static int crb_check_resource(struct acpi_resource *ares, void *data)
+{
+ struct crb_priv *priv = data;
+ struct resource res;
+
+ if (acpi_dev_resource_memory(ares, &res)) {
+ priv->res = res;
+ priv->res.name = NULL;
+ }
+
+ return 1;
+}
+
+static void __iomem *crb_map_res(struct device *dev, struct crb_priv *priv,
+ u64 start, u32 size)
+{
+ struct resource new_res = {
+ .start = start,
+ .end = start + size - 1,
+ .flags = IORESOURCE_MEM,
+ };
+
+ /* Detect a 64 bit address on a 32 bit system */
+ if (start != new_res.start)
+ return ERR_PTR(-EINVAL);
+
+ if (!resource_contains(&priv->res, &new_res))
+ return devm_ioremap_resource(dev, &new_res);
+
+ return priv->iobase + (new_res.start - priv->res.start);
+}
+
+static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
+ struct acpi_table_tpm2 *buf)
+{
+ struct list_head resources;
+ struct device *dev = &device->dev;
+ u64 pa;
+ int ret;
+
+ INIT_LIST_HEAD(&resources);
+ ret = acpi_dev_get_resources(device, &resources, crb_check_resource,
+ priv);
+ if (ret < 0)
+ return ret;
+ acpi_dev_free_resource_list(&resources);
+
+ if (resource_type(&priv->res) != IORESOURCE_MEM) {
+ dev_err(dev,
+ FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+ return -EINVAL;
+ }
+
+ priv->iobase = devm_ioremap_resource(dev, &priv->res);
+ if (IS_ERR(priv->iobase))
+ return PTR_ERR(priv->iobase);
+
+ priv->cca = crb_map_res(dev, priv, buf->control_address, 0x1000);
+ if (IS_ERR(priv->cca))
+ return PTR_ERR(priv->cca);
+
+ pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) |
+ (u64) ioread32(&priv->cca->cmd_pa_low);
+ priv->cmd = crb_map_res(dev, priv, pa, ioread32(&priv->cca->cmd_size));
+ if (IS_ERR(priv->cmd))
+ return PTR_ERR(priv->cmd);
+
+ memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
+ pa = le64_to_cpu(pa);
+ priv->rsp = crb_map_res(dev, priv, pa, ioread32(&priv->cca->rsp_size));
+ return PTR_ERR_OR_ZERO(priv->rsp);
+}
+
+static int crb_acpi_add(struct acpi_device *device)
+{
+ struct acpi_table_tpm2 *buf;
struct crb_priv *priv;
struct device *dev = &device->dev;
acpi_status status;
u32 sm;
- u64 pa;
int rc;
status = acpi_get_table(ACPI_SIG_TPM2, 1,
(struct acpi_table_header **) &buf);
- if (ACPI_FAILURE(status)) {
- dev_err(dev, "failed to get TPM2 ACPI table\n");
- return -ENODEV;
+ if (ACPI_FAILURE(status) || buf->header.length < sizeof(*buf)) {
+ dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
+ return -EINVAL;
}
/* Should the FIFO driver handle this? */
- if (buf->start_method == TPM2_START_FIFO)
+ sm = buf->start_method;
+ if (sm == ACPI_TPM2_MEMORY_MAPPED)
return -ENODEV;
- chip = tpmm_chip_alloc(dev, &tpm_crb);
- if (IS_ERR(chip))
- return PTR_ERR(chip);
-
- chip->flags = TPM_CHIP_FLAG_TPM2;
-
- if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
- dev_err(dev, "TPM2 ACPI table has wrong size");
- return -EINVAL;
- }
-
- priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv),
- GFP_KERNEL);
- if (!priv) {
- dev_err(dev, "failed to devm_kzalloc for private data\n");
+ priv = devm_kzalloc(dev, sizeof(struct crb_priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }
-
- sm = le32_to_cpu(buf->start_method);
/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
* report only ACPI start but in practice seems to require both
* ACPI start and CRB start.
*/
- if (sm == TPM2_START_CRB || sm == TPM2_START_FIFO ||
+ if (sm == ACPI_TPM2_COMMAND_BUFFER || sm == ACPI_TPM2_MEMORY_MAPPED ||
!strcmp(acpi_device_hid(device), "MSFT0101"))
priv->flags |= CRB_FL_CRB_START;
- if (sm == TPM2_START_ACPI || sm == TPM2_START_CRB_WITH_ACPI)
+ if (sm == ACPI_TPM2_START_METHOD ||
+ sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
priv->flags |= CRB_FL_ACPI_START;
- priv->cca = (struct crb_control_area __iomem *)
- devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
- if (!priv->cca) {
- dev_err(dev, "ioremap of the control area failed\n");
- return -ENOMEM;
- }
-
- pa = ((u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_high)) << 32) |
- (u64) le32_to_cpu(ioread32(&priv->cca->cmd_pa_low));
- priv->cmd = devm_ioremap_nocache(dev, pa,
- ioread32(&priv->cca->cmd_size));
- if (!priv->cmd) {
- dev_err(dev, "ioremap of the command buffer failed\n");
- return -ENOMEM;
- }
-
- memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
- pa = le64_to_cpu(pa);
- priv->rsp = devm_ioremap_nocache(dev, pa,
- ioread32(&priv->cca->rsp_size));
- if (!priv->rsp) {
- dev_err(dev, "ioremap of the response buffer failed\n");
- return -ENOMEM;
- }
-
- chip->vendor.priv = priv;
-
- rc = tpm_get_timeouts(chip);
+ rc = crb_map_io(device, priv, buf);
if (rc)
return rc;
- chip->acpi_dev_handle = device->handle;
-
- rc = tpm2_do_selftest(chip);
- if (rc)
- return rc;
-
- return tpm_chip_register(chip);
+ return crb_init(device, priv);
}
static int crb_acpi_remove(struct acpi_device *device)
@@ -302,11 +344,11 @@ static int crb_acpi_remove(struct acpi_device *device)
struct device *dev = &device->dev;
struct tpm_chip *chip = dev_get_drvdata(dev);
- tpm_chip_unregister(chip);
-
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_CLEAR);
+ tpm_chip_unregister(chip);
+
return 0;
}
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c
index bd72fb0..4e6940a 100644
--- a/drivers/char/tpm/tpm_eventlog.c
+++ b/drivers/char/tpm/tpm_eventlog.c
@@ -232,7 +232,7 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
{
struct tcpa_event *event = v;
struct tcpa_event temp_event;
- char *tempPtr;
+ char *temp_ptr;
int i;
memcpy(&temp_event, event, sizeof(struct tcpa_event));
@@ -242,10 +242,16 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
temp_event.event_type = do_endian_conversion(event->event_type);
temp_event.event_size = do_endian_conversion(event->event_size);
- tempPtr = (char *)&temp_event;
+ temp_ptr = (char *) &temp_event;
- for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++)
- seq_putc(m, tempPtr[i]);
+ for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
+ seq_putc(m, temp_ptr[i]);
+
+ temp_ptr = (char *) v;
+
+ for (i = (sizeof(struct tcpa_event) - 1);
+ i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
+ seq_putc(m, temp_ptr[i]);
return 0;
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 8a3509c..a507006 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -28,7 +28,6 @@
#include <linux/wait.h>
#include <linux/acpi.h>
#include <linux/freezer.h>
-#include <acpi/actbl2.h>
#include "tpm.h"
enum tis_access {
@@ -60,22 +59,18 @@ enum tis_int_flags {
};
enum tis_defaults {
- TIS_MEM_BASE = 0xFED40000,
TIS_MEM_LEN = 0x5000,
TIS_SHORT_TIMEOUT = 750, /* ms */
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
};
struct tpm_info {
- unsigned long start;
- unsigned long len;
- unsigned int irq;
-};
-
-static struct tpm_info tis_default_info = {
- .start = TIS_MEM_BASE,
- .len = TIS_MEM_LEN,
- .irq = 0,
+ struct resource res;
+ /* irq > 0 means: use irq $irq;
+ * irq = 0 means: autoprobe for an irq;
+ * irq = -1 means: no irq support
+ */
+ int irq;
};
/* Some timeout values are needed before it is known whether the chip is
@@ -118,39 +113,11 @@ static inline int is_itpm(struct acpi_device *dev)
{
return has_hid(dev, "INTC0102");
}
-
-static inline int is_fifo(struct acpi_device *dev)
-{
- struct acpi_table_tpm2 *tbl;
- acpi_status st;
-
- /* TPM 1.2 FIFO */
- if (!has_hid(dev, "MSFT0101"))
- return 1;
-
- st = acpi_get_table(ACPI_SIG_TPM2, 1,
- (struct acpi_table_header **) &tbl);
- if (ACPI_FAILURE(st)) {
- dev_err(&dev->dev, "failed to get TPM2 ACPI table\n");
- return 0;
- }
-
- if (le32_to_cpu(tbl->start_method) != TPM2_START_FIFO)
- return 0;
-
- /* TPM 2.0 FIFO */
- return 1;
-}
#else
static inline int is_itpm(struct acpi_device *dev)
{
return 0;
}
-
-static inline int is_fifo(struct acpi_device *dev)
-{
- return 1;
-}
#endif
/* Before we attempt to access the TPM we must see that the valid bit is set.
@@ -716,9 +683,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
chip->acpi_dev_handle = acpi_dev_handle;
#endif
- chip->vendor.iobase = devm_ioremap(dev, tpm_info->start, tpm_info->len);
- if (!chip->vendor.iobase)
- return -EIO;
+ chip->vendor.iobase = devm_ioremap_resource(dev, &tpm_info->res);
+ if (IS_ERR(chip->vendor.iobase))
+ return PTR_ERR(chip->vendor.iobase);
/* Maximum timeouts */
chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
@@ -807,7 +774,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
/* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
- if (interrupts) {
+ if (interrupts && tpm_info->irq != -1) {
if (tpm_info->irq) {
tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
tpm_info->irq);
@@ -893,29 +860,29 @@ static int tpm_tis_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
-#ifdef CONFIG_PNP
static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
- const struct pnp_device_id *pnp_id)
+ const struct pnp_device_id *pnp_id)
{
- struct tpm_info tpm_info = tis_default_info;
+ struct tpm_info tpm_info = {};
acpi_handle acpi_dev_handle = NULL;
+ struct resource *res;
- tpm_info.start = pnp_mem_start(pnp_dev, 0);
- tpm_info.len = pnp_mem_len(pnp_dev, 0);
+ res = pnp_get_resource(pnp_dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ tpm_info.res = *res;
if (pnp_irq_valid(pnp_dev, 0))
tpm_info.irq = pnp_irq(pnp_dev, 0);
else
- interrupts = false;
+ tpm_info.irq = -1;
-#ifdef CONFIG_ACPI
if (pnp_acpi_device(pnp_dev)) {
if (is_itpm(pnp_acpi_device(pnp_dev)))
itpm = true;
- acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
+ acpi_dev_handle = ACPI_HANDLE(&pnp_dev->dev);
}
-#endif
return tpm_tis_init(&pnp_dev->dev, &tpm_info, acpi_dev_handle);
}
@@ -956,7 +923,6 @@ static struct pnp_driver tis_pnp_driver = {
module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
-#endif
#ifdef CONFIG_ACPI
static int tpm_check_resource(struct acpi_resource *ares, void *data)
@@ -964,11 +930,11 @@ static int tpm_check_resource(struct acpi_resource *ares, void *data)
struct tpm_info *tpm_info = (struct tpm_info *) data;
struct resource res;
- if (acpi_dev_resource_interrupt(ares, 0, &res)) {
+ if (acpi_dev_resource_interrupt(ares, 0, &res))
tpm_info->irq = res.start;
- } else if (acpi_dev_resource_memory(ares, &res)) {
- tpm_info->start = res.start;
- tpm_info->len = resource_size(&res);
+ else if (acpi_dev_resource_memory(ares, &res)) {
+ tpm_info->res = res;
+ tpm_info->res.name = NULL;
}
return 1;
@@ -976,14 +942,25 @@ static int tpm_check_resource(struct acpi_resource *ares, void *data)
static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
{
+ struct acpi_table_tpm2 *tbl;
+ acpi_status st;
struct list_head resources;
- struct tpm_info tpm_info = tis_default_info;
+ struct tpm_info tpm_info = {};
int ret;
- if (!is_fifo(acpi_dev))
+ st = acpi_get_table(ACPI_SIG_TPM2, 1,
+ (struct acpi_table_header **) &tbl);
+ if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
+ dev_err(&acpi_dev->dev,
+ FW_BUG "failed to get TPM2 ACPI table\n");
+ return -EINVAL;
+ }
+
+ if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
return -ENODEV;
INIT_LIST_HEAD(&resources);
+ tpm_info.irq = -1;
ret = acpi_dev_get_resources(acpi_dev, &resources, tpm_check_resource,
&tpm_info);
if (ret < 0)
@@ -991,8 +968,11 @@ static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
acpi_dev_free_resource_list(&resources);
- if (!tpm_info.irq)
- interrupts = false;
+ if (resource_type(&tpm_info.res) != IORESOURCE_MEM) {
+ dev_err(&acpi_dev->dev,
+ FW_BUG "TPM2 ACPI table does not define a memory resource\n");
+ return -EINVAL;
+ }
if (is_itpm(acpi_dev))
itpm = true;
@@ -1031,80 +1011,135 @@ static struct acpi_driver tis_acpi_driver = {
};
#endif
+static struct platform_device *force_pdev;
+
+static int tpm_tis_plat_probe(struct platform_device *pdev)
+{
+ struct tpm_info tpm_info = {};
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ return -ENODEV;
+ }
+ tpm_info.res = *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res) {
+ tpm_info.irq = res->start;
+ } else {
+ if (pdev == force_pdev)
+ tpm_info.irq = -1;
+ else
+ /* When forcing auto probe the IRQ */
+ tpm_info.irq = 0;
+ }
+
+ return tpm_tis_init(&pdev->dev, &tpm_info, NULL);
+}
+
+static int tpm_tis_plat_remove(struct platform_device *pdev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
+ tpm_chip_unregister(chip);
+ tpm_tis_remove(chip);
+
+ return 0;
+}
+
static struct platform_driver tis_drv = {
+ .probe = tpm_tis_plat_probe,
+ .remove = tpm_tis_plat_remove,
.driver = {
.name = "tpm_tis",
.pm = &tpm_tis_pm,
},
};
-static struct platform_device *pdev;
-
static bool force;
+#ifdef CONFIG_X86
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
+#endif
+
+static int tpm_tis_force_device(void)
+{
+ struct platform_device *pdev;
+ static const struct resource x86_resources[] = {
+ {
+ .start = 0xFED40000,
+ .end = 0xFED40000 + TIS_MEM_LEN - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+
+ if (!force)
+ return 0;
+
+ /* The driver core will match the name tpm_tis of the device to
+ * the tpm_tis platform driver and complete the setup via
+ * tpm_tis_plat_probe
+ */
+ pdev = platform_device_register_simple("tpm_tis", -1, x86_resources,
+ ARRAY_SIZE(x86_resources));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+ force_pdev = pdev;
+
+ return 0;
+}
+
static int __init init_tis(void)
{
int rc;
-#ifdef CONFIG_PNP
- if (!force) {
- rc = pnp_register_driver(&tis_pnp_driver);
- if (rc)
- return rc;
- }
-#endif
+
+ rc = tpm_tis_force_device();
+ if (rc)
+ goto err_force;
+
+ rc = platform_driver_register(&tis_drv);
+ if (rc)
+ goto err_platform;
+
#ifdef CONFIG_ACPI
- if (!force) {
- rc = acpi_bus_register_driver(&tis_acpi_driver);
- if (rc) {
-#ifdef CONFIG_PNP
- pnp_unregister_driver(&tis_pnp_driver);
-#endif
- return rc;
- }
- }
+ rc = acpi_bus_register_driver(&tis_acpi_driver);
+ if (rc)
+ goto err_acpi;
#endif
- if (!force)
- return 0;
- rc = platform_driver_register(&tis_drv);
- if (rc < 0)
- return rc;
- pdev = platform_device_register_simple("tpm_tis", -1, NULL, 0);
- if (IS_ERR(pdev)) {
- rc = PTR_ERR(pdev);
- goto err_dev;
+ if (IS_ENABLED(CONFIG_PNP)) {
+ rc = pnp_register_driver(&tis_pnp_driver);
+ if (rc)
+ goto err_pnp;
}
- rc = tpm_tis_init(&pdev->dev, &tis_default_info, NULL);
- if (rc)
- goto err_init;
+
return 0;
-err_init:
- platform_device_unregister(pdev);
-err_dev:
- platform_driver_unregister(&tis_drv);
+
+err_pnp:
+#ifdef CONFIG_ACPI
+ acpi_bus_unregister_driver(&tis_acpi_driver);
+err_acpi:
+#endif
+ platform_device_unregister(force_pdev);
+err_platform:
+ if (force_pdev)
+ platform_device_unregister(force_pdev);
+err_force:
return rc;
}
static void __exit cleanup_tis(void)
{
- struct tpm_chip *chip;
-#if defined(CONFIG_PNP) || defined(CONFIG_ACPI)
- if (!force) {
+ pnp_unregister_driver(&tis_pnp_driver);
#ifdef CONFIG_ACPI
- acpi_bus_unregister_driver(&tis_acpi_driver);
-#endif
-#ifdef CONFIG_PNP
- pnp_unregister_driver(&tis_pnp_driver);
+ acpi_bus_unregister_driver(&tis_acpi_driver);
#endif
- return;
- }
-#endif
- chip = dev_get_drvdata(&pdev->dev);
- tpm_chip_unregister(chip);
- tpm_tis_remove(chip);
- platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
+
+ if (force_pdev)
+ platform_device_unregister(force_pdev);
}
module_init(init_tis);
diff --git a/fs/exec.c b/fs/exec.c
index dcd4ac7..9bdf0ed 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -56,6 +56,7 @@
#include <linux/pipe_fs_i.h>
#include <linux/oom.h>
#include <linux/compat.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -831,6 +832,97 @@ int kernel_read(struct file *file, loff_t offset,
EXPORT_SYMBOL(kernel_read);
+int kernel_read_file(struct file *file, void **buf, loff_t *size,
+ loff_t max_size, enum kernel_read_file_id id)
+{
+ loff_t i_size, pos;
+ ssize_t bytes = 0;
+ int ret;
+
+ if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0)
+ return -EINVAL;
+
+ ret = security_kernel_read_file(file, id);
+ if (ret)
+ return ret;
+
+ i_size = i_size_read(file_inode(file));
+ if (max_size > 0 && i_size > max_size)
+ return -EFBIG;
+ if (i_size <= 0)
+ return -EINVAL;
+
+ *buf = vmalloc(i_size);
+ if (!*buf)
+ return -ENOMEM;
+
+ pos = 0;
+ while (pos < i_size) {
+ bytes = kernel_read(file, pos, (char *)(*buf) + pos,
+ i_size - pos);
+ if (bytes < 0) {
+ ret = bytes;
+ goto out;
+ }
+
+ if (bytes == 0)
+ break;
+ pos += bytes;
+ }
+
+ if (pos != i_size) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = security_kernel_post_read_file(file, *buf, i_size, id);
+ if (!ret)
+ *size = pos;
+
+out:
+ if (ret < 0) {
+ vfree(*buf);
+ *buf = NULL;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kernel_read_file);
+
+int kernel_read_file_from_path(char *path, void **buf, loff_t *size,
+ loff_t max_size, enum kernel_read_file_id id)
+{
+ struct file *file;
+ int ret;
+
+ if (!path || !*path)
+ return -EINVAL;
+
+ file = filp_open(path, O_RDONLY, 0);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ ret = kernel_read_file(file, buf, size, max_size, id);
+ fput(file);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
+
+int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
+ enum kernel_read_file_id id)
+{
+ struct fd f = fdget(fd);
+ int ret = -EBADF;
+
+ if (!f.file)
+ goto out;
+
+ ret = kernel_read_file(f.file, buf, size, max_size, id);
+out:
+ fdput(f);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kernel_read_file_from_fd);
+
ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len)
{
ssize_t res = vfs_read(file, (void __user *)addr, len, &pos);
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index cc2516d..aa730ea 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -14,30 +14,6 @@
#ifndef _LINUX_PUBLIC_KEY_H
#define _LINUX_PUBLIC_KEY_H
-#include <linux/mpi.h>
-#include <crypto/hash_info.h>
-
-enum pkey_algo {
- PKEY_ALGO_DSA,
- PKEY_ALGO_RSA,
- PKEY_ALGO__LAST
-};
-
-extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
-extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST];
-
-/* asymmetric key implementation supports only up to SHA224 */
-#define PKEY_HASH__LAST (HASH_ALGO_SHA224 + 1)
-
-enum pkey_id_type {
- PKEY_ID_PGP, /* OpenPGP generated key ID */
- PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
- PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
- PKEY_ID_TYPE__LAST
-};
-
-extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
-
/*
* The use to which an asymmetric key is being put.
*/
@@ -59,31 +35,10 @@ extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
* part.
*/
struct public_key {
- const struct public_key_algorithm *algo;
- u8 capabilities;
-#define PKEY_CAN_ENCRYPT 0x01
-#define PKEY_CAN_DECRYPT 0x02
-#define PKEY_CAN_SIGN 0x04
-#define PKEY_CAN_VERIFY 0x08
- enum pkey_algo pkey_algo : 8;
- enum pkey_id_type id_type : 8;
- union {
- MPI mpi[5];
- struct {
- MPI p; /* DSA prime */
- MPI q; /* DSA group order */
- MPI g; /* DSA group generator */
- MPI y; /* DSA public-key value = g^x mod p */
- MPI x; /* DSA secret exponent (if present) */
- } dsa;
- struct {
- MPI n; /* RSA public modulus */
- MPI e; /* RSA public encryption exponent */
- MPI d; /* RSA secret encryption exponent (if present) */
- MPI p; /* RSA secret prime (if present) */
- MPI q; /* RSA secret prime (if present) */
- } rsa;
- };
+ void *key;
+ u32 keylen;
+ const char *id_type;
+ const char *pkey_algo;
};
extern void public_key_destroy(void *payload);
@@ -92,23 +47,15 @@ extern void public_key_destroy(void *payload);
* Public key cryptography signature data
*/
struct public_key_signature {
+ u8 *s; /* Signature */
+ u32 s_size; /* Number of bytes in signature */
u8 *digest;
- u8 digest_size; /* Number of bytes in digest */
- u8 nr_mpi; /* Occupancy of mpi[] */
- enum pkey_algo pkey_algo : 8;
- enum hash_algo pkey_hash_algo : 8;
- union {
- MPI mpi[2];
- struct {
- MPI s; /* m^d mod n */
- } rsa;
- struct {
- MPI r;
- MPI s;
- } dsa;
- };
+ u8 digest_size; /* Number of bytes in digest */
+ const char *pkey_algo;
+ const char *hash_algo;
};
+extern struct asymmetric_key_subtype public_key_subtype;
struct key;
extern int verify_signature(const struct key *key,
const struct public_key_signature *sig);
@@ -119,4 +66,7 @@ extern struct key *x509_request_asymmetric_key(struct key *keyring,
const struct asymmetric_key_id *skid,
bool partial);
+int public_key_verify_signature(const struct public_key *pkey,
+ const struct public_key_signature *sig);
+
#endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 42cf2d9..4ea7e55 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -38,7 +38,7 @@ struct trusted_key_options {
unsigned char pcrinfo[MAX_PCRINFO_SIZE];
int pcrlock;
uint32_t hash;
- uint32_t digest_len;
+ uint32_t policydigest_len;
unsigned char policydigest[MAX_DIGEST_SIZE];
uint32_t policyhandle;
};
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ae68100..e514f76 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2576,7 +2576,22 @@ static inline void i_readcount_inc(struct inode *inode)
#endif
extern int do_pipe_flags(int *, int);
+enum kernel_read_file_id {
+ READING_FIRMWARE = 1,
+ READING_MODULE,
+ READING_KEXEC_IMAGE,
+ READING_KEXEC_INITRAMFS,
+ READING_POLICY,
+ READING_MAX_ID
+};
+
extern int kernel_read(struct file *, loff_t, char *, unsigned long);
+extern int kernel_read_file(struct file *, void **, loff_t *, loff_t,
+ enum kernel_read_file_id);
+extern int kernel_read_file_from_path(char *, void **, loff_t *, loff_t,
+ enum kernel_read_file_id);
+extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t,
+ enum kernel_read_file_id);
extern ssize_t kernel_write(struct file *, const char *, size_t, loff_t);
extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
extern struct file * open_exec(const char *);
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 120ccc5..e6516cb 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -18,8 +18,9 @@ extern int ima_bprm_check(struct linux_binprm *bprm);
extern int ima_file_check(struct file *file, int mask, int opened);
extern void ima_file_free(struct file *file);
extern int ima_file_mmap(struct file *file, unsigned long prot);
-extern int ima_module_check(struct file *file);
-extern int ima_fw_from_file(struct file *file, char *buf, size_t size);
+extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
+extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
+ enum kernel_read_file_id id);
#else
static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -42,12 +43,13 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
return 0;
}
-static inline int ima_module_check(struct file *file)
+static inline int ima_read_file(struct file *file, enum kernel_read_file_id id)
{
return 0;
}
-static inline int ima_fw_from_file(struct file *file, char *buf, size_t size)
+static inline int ima_post_read_file(struct file *file, void *buf, loff_t size,
+ enum kernel_read_file_id id)
{
return 0;
}
diff --git a/include/linux/key.h b/include/linux/key.h
index 7321ab8..5f5b112 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -219,6 +219,7 @@ extern struct key *key_alloc(struct key_type *type,
#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
+#define KEY_ALLOC_BUILT_IN 0x0008 /* Key is built into kernel */
extern void key_revoke(struct key *key);
extern void key_invalidate(struct key *key);
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 71969de..cdee11c 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -541,25 +541,24 @@
* @inode points to the inode to use as a reference.
* The current task must be the one that nominated @inode.
* Return 0 if successful.
- * @kernel_fw_from_file:
- * Load firmware from userspace (not called for built-in firmware).
- * @file contains the file structure pointing to the file containing
- * the firmware to load. This argument will be NULL if the firmware
- * was loaded via the uevent-triggered blob-based interface exposed
- * by CONFIG_FW_LOADER_USER_HELPER.
- * @buf pointer to buffer containing firmware contents.
- * @size length of the firmware contents.
- * Return 0 if permission is granted.
* @kernel_module_request:
* Ability to trigger the kernel to automatically upcall to userspace for
* userspace to load a kernel module with the given name.
* @kmod_name name of the module requested by the kernel
* Return 0 if successful.
- * @kernel_module_from_file:
- * Load a kernel module from userspace.
- * @file contains the file structure pointing to the file containing
- * the kernel module to load. If the module is being loaded from a blob,
- * this argument will be NULL.
+ * @kernel_read_file:
+ * Read a file specified by userspace.
+ * @file contains the file structure pointing to the file being read
+ * by the kernel.
+ * @id kernel read file identifier
+ * Return 0 if permission is granted.
+ * @kernel_post_read_file:
+ * Read a file specified by userspace.
+ * @file contains the file structure pointing to the file being read
+ * by the kernel.
+ * @buf pointer to buffer containing the file contents.
+ * @size length of the file contents.
+ * @id kernel read file identifier
* Return 0 if permission is granted.
* @task_fix_setuid:
* Update the module's state after setting one or more of the user
@@ -1454,9 +1453,11 @@ union security_list_options {
void (*cred_transfer)(struct cred *new, const struct cred *old);
int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
- int (*kernel_fw_from_file)(struct file *file, char *buf, size_t size);
int (*kernel_module_request)(char *kmod_name);
int (*kernel_module_from_file)(struct file *file);
+ int (*kernel_read_file)(struct file *file, enum kernel_read_file_id id);
+ int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size,
+ enum kernel_read_file_id id);
int (*task_fix_setuid)(struct cred *new, const struct cred *old,
int flags);
int (*task_setpgid)(struct task_struct *p, pid_t pgid);
@@ -1715,9 +1716,9 @@ struct security_hook_heads {
struct list_head cred_transfer;
struct list_head kernel_act_as;
struct list_head kernel_create_files_as;
- struct list_head kernel_fw_from_file;
+ struct list_head kernel_read_file;
+ struct list_head kernel_post_read_file;
struct list_head kernel_module_request;
- struct list_head kernel_module_from_file;
struct list_head task_fix_setuid;
struct list_head task_setpgid;
struct list_head task_getpgid;
diff --git a/include/linux/security.h b/include/linux/security.h
index 4824a4c..157f0cb 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -24,10 +24,12 @@
#include <linux/key.h>
#include <linux/capability.h>
+#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/fs.h>
struct linux_binprm;
struct cred;
@@ -298,9 +300,11 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_transfer_creds(struct cred *new, const struct cred *old);
int security_kernel_act_as(struct cred *new, u32 secid);
int security_kernel_create_files_as(struct cred *new, struct inode *inode);
-int security_kernel_fw_from_file(struct file *file, char *buf, size_t size);
int security_kernel_module_request(char *kmod_name);
int security_kernel_module_from_file(struct file *file);
+int security_kernel_read_file(struct file *file, enum kernel_read_file_id id);
+int security_kernel_post_read_file(struct file *file, char *buf, loff_t size,
+ enum kernel_read_file_id id);
int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags);
int security_task_setpgid(struct task_struct *p, pid_t pgid);
@@ -850,18 +854,20 @@ static inline int security_kernel_create_files_as(struct cred *cred,
return 0;
}
-static inline int security_kernel_fw_from_file(struct file *file,
- char *buf, size_t size)
+static inline int security_kernel_module_request(char *kmod_name)
{
return 0;
}
-static inline int security_kernel_module_request(char *kmod_name)
+static inline int security_kernel_read_file(struct file *file,
+ enum kernel_read_file_id id)
{
return 0;
}
-static inline int security_kernel_module_from_file(struct file *file)
+static inline int security_kernel_post_read_file(struct file *file,
+ char *buf, loff_t size,
+ enum kernel_read_file_id id)
{
return 0;
}
diff --git a/init/Kconfig b/init/Kconfig
index fd664b3..2d70c8c 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1779,9 +1779,9 @@ config SYSTEM_DATA_VERIFICATION
select SYSTEM_TRUSTED_KEYRING
select KEYS
select CRYPTO
+ select CRYPTO_RSA
select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
- select PUBLIC_KEY_ALGO_RSA
select ASN1
select OID_REGISTRY
select X509_CERTIFICATE_PARSER
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 56b18eb..c72d2ff 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -18,6 +18,7 @@
#include <linux/kexec.h>
#include <linux/mutex.h>
#include <linux/list.h>
+#include <linux/fs.h>
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <linux/syscalls.h>
@@ -33,65 +34,6 @@ size_t __weak kexec_purgatory_size = 0;
static int kexec_calculate_store_digests(struct kimage *image);
-static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len)
-{
- struct fd f = fdget(fd);
- int ret;
- struct kstat stat;
- loff_t pos;
- ssize_t bytes = 0;
-
- if (!f.file)
- return -EBADF;
-
- ret = vfs_getattr(&f.file->f_path, &stat);
- if (ret)
- goto out;
-
- if (stat.size > INT_MAX) {
- ret = -EFBIG;
- goto out;
- }
-
- /* Don't hand 0 to vmalloc, it whines. */
- if (stat.size == 0) {
- ret = -EINVAL;
- goto out;
- }
-
- *buf = vmalloc(stat.size);
- if (!*buf) {
- ret = -ENOMEM;
- goto out;
- }
-
- pos = 0;
- while (pos < stat.size) {
- bytes = kernel_read(f.file, pos, (char *)(*buf) + pos,
- stat.size - pos);
- if (bytes < 0) {
- vfree(*buf);
- ret = bytes;
- goto out;
- }
-
- if (bytes == 0)
- break;
- pos += bytes;
- }
-
- if (pos != stat.size) {
- ret = -EBADF;
- vfree(*buf);
- goto out;
- }
-
- *buf_len = pos;
-out:
- fdput(f);
- return ret;
-}
-
/* Architectures can provide this probe function */
int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
unsigned long buf_len)
@@ -182,16 +124,17 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
{
int ret = 0;
void *ldata;
+ loff_t size;
- ret = copy_file_from_fd(kernel_fd, &image->kernel_buf,
- &image->kernel_buf_len);
+ ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf,
+ &size, INT_MAX, READING_KEXEC_IMAGE);
if (ret)
return ret;
+ image->kernel_buf_len = size;
/* Call arch image probe handlers */
ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
image->kernel_buf_len);
-
if (ret)
goto out;
@@ -206,10 +149,12 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
#endif
/* It is possible that there no initramfs is being loaded */
if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
- ret = copy_file_from_fd(initrd_fd, &image->initrd_buf,
- &image->initrd_buf_len);
+ ret = kernel_read_file_from_fd(initrd_fd, &image->initrd_buf,
+ &size, INT_MAX,
+ READING_KEXEC_INITRAMFS);
if (ret)
goto out;
+ image->initrd_buf_len = size;
}
if (cmdline_len) {
diff --git a/kernel/module.c b/kernel/module.c
index 794ebe8..87cfeb2 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2675,7 +2675,7 @@ static int copy_module_from_user(const void __user *umod, unsigned long len,
if (info->len < sizeof(*(info->hdr)))
return -ENOEXEC;
- err = security_kernel_module_from_file(NULL);
+ err = security_kernel_read_file(NULL, READING_MODULE);
if (err)
return err;
@@ -2693,63 +2693,6 @@ static int copy_module_from_user(const void __user *umod, unsigned long len,
return 0;
}
-/* Sets info->hdr and info->len. */
-static int copy_module_from_fd(int fd, struct load_info *info)
-{
- struct fd f = fdget(fd);
- int err;
- struct kstat stat;
- loff_t pos;
- ssize_t bytes = 0;
-
- if (!f.file)
- return -ENOEXEC;
-
- err = security_kernel_module_from_file(f.file);
- if (err)
- goto out;
-
- err = vfs_getattr(&f.file->f_path, &stat);
- if (err)
- goto out;
-
- if (stat.size > INT_MAX) {
- err = -EFBIG;
- goto out;
- }
-
- /* Don't hand 0 to vmalloc, it whines. */
- if (stat.size == 0) {
- err = -EINVAL;
- goto out;
- }
-
- info->hdr = vmalloc(stat.size);
- if (!info->hdr) {
- err = -ENOMEM;
- goto out;
- }
-
- pos = 0;
- while (pos < stat.size) {
- bytes = kernel_read(f.file, pos, (char *)(info->hdr) + pos,
- stat.size - pos);
- if (bytes < 0) {
- vfree(info->hdr);
- err = bytes;
- goto out;
- }
- if (bytes == 0)
- break;
- pos += bytes;
- }
- info->len = pos;
-
-out:
- fdput(f);
- return err;
-}
-
static void free_copy(struct load_info *info)
{
vfree(info->hdr);
@@ -3611,8 +3554,10 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
{
- int err;
struct load_info info = { };
+ loff_t size;
+ void *hdr;
+ int err;
err = may_init_module();
if (err)
@@ -3624,9 +3569,12 @@ SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|MODULE_INIT_IGNORE_VERMAGIC))
return -EINVAL;
- err = copy_module_from_fd(fd, &info);
+ err = kernel_read_file_from_fd(fd, &hdr, &size, INT_MAX,
+ READING_MODULE);
if (err)
return err;
+ info.hdr = hdr;
+ info.len = size;
return load_module(&info, uargs, flags);
}
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 6528a79..64b9dea 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -11,10 +11,17 @@
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/string.h>
#include <keys/system_keyring.h>
#include <crypto/public_key.h>
#include "module-internal.h"
+enum pkey_id_type {
+ PKEY_ID_PGP, /* OpenPGP generated key ID */
+ PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
+ PKEY_ID_PKCS7, /* Signature in PKCS#7 message */
+};
+
/*
* Module signature information block.
*
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 86751c6..be115b0 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -322,6 +322,13 @@ EXPORT_SYMBOL(timespec_trunc);
* -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
+ *
+ * A leap second can be indicated by calling this function with sec as
+ * 60 (allowable under ISO 8601). The leap second is treated the same
+ * as the following second since they don't exist in UNIX time.
+ *
+ * An encoding of midnight at the end of the day as 24:00:00 - ie. midnight
+ * tomorrow - (allowable under ISO 8601) is supported.
*/
time64_t mktime64(const unsigned int year0, const unsigned int mon0,
const unsigned int day, const unsigned int hour,
@@ -338,7 +345,7 @@ time64_t mktime64(const unsigned int year0, const unsigned int mon0,
return ((((time64_t)
(year/4 - year/100 + year/400 + 367*mon/12 + day) +
year*365 - 719499
- )*24 + hour /* now have hours */
+ )*24 + hour /* now have hours - midnight tomorrow handled here */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
}
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 1f78169..e063daa 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -13,3 +13,4 @@ sortextable
asn1_compiler
extract-cert
sign-file
+insert-sys-cert
diff --git a/scripts/Makefile b/scripts/Makefile
index fd0d53d..822ab4a 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -19,6 +19,7 @@ hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
hostprogs-$(CONFIG_ASN1) += asn1_compiler
hostprogs-$(CONFIG_MODULE_SIG) += sign-file
hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
+hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl
index d476e7d..8227ca1 100755
--- a/scripts/extract-sys-certs.pl
+++ b/scripts/extract-sys-certs.pl
@@ -91,13 +91,15 @@ print "Have $nr_symbols symbols\n";
die "Can't find system certificate list"
unless (exists($symbols{"__cert_list_start"}) &&
- exists($symbols{"__cert_list_end"}));
+ exists($symbols{"system_certificate_list_size"}));
my $start = Math::BigInt->new($symbols{"__cert_list_start"});
-my $end = Math::BigInt->new($symbols{"__cert_list_end"});
-my $size = $end - $start;
+my $end;
+my $size;
+my $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"});
-printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
+open FD, "<$vmlinux" || die $vmlinux;
+binmode(FD);
my $s = undef;
foreach my $sec (@sections) {
@@ -110,11 +112,24 @@ foreach my $sec (@sections) {
next unless ($start >= $s_vma);
next if ($start >= $s_vend);
- die "Cert object partially overflows section $s_name\n"
- if ($end > $s_vend);
+ die "Certificate list size was not found on the same section\n"
+ if ($size_sym < $s_vma || $size_sym > $s_vend);
die "Cert object in multiple sections: ", $s_name, " and ", $s->{name}, "\n"
if ($s);
+
+ my $size_off = $size_sym -$s_vma + $s_foff;
+ my $packed;
+ die $vmlinux if (!defined(sysseek(FD, $size_off, SEEK_SET)));
+ sysread(FD, $packed, 8);
+ $size = unpack 'L!', $packed;
+ $end = $start + $size;
+
+ printf "Have %u bytes of certs at VMA 0x%x\n", $size, $start;
+
+ die "Cert object partially overflows section $s_name\n"
+ if ($end > $s_vend);
+
$s = $sec;
}
@@ -127,8 +142,6 @@ my $foff = $start - $s->{vma} + $s->{foff};
printf "Certificate list at file offset 0x%x\n", $foff;
-open FD, "<$vmlinux" || die $vmlinux;
-binmode(FD);
die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
my $buf = "";
my $len = sysread(FD, $buf, $size);
diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
new file mode 100644
index 0000000..8902836
--- /dev/null
+++ b/scripts/insert-sys-cert.c
@@ -0,0 +1,410 @@
+/* Write the contents of the <certfile> into kernel symbol system_extra_cert
+ *
+ * Copyright (C) IBM Corporation, 2015
+ *
+ * Author: Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Usage: insert-sys-cert [-s <System.map> -b <vmlinux> -c <certfile>
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <elf.h>
+
+#define CERT_SYM "system_extra_cert"
+#define USED_SYM "system_extra_cert_used"
+#define LSIZE_SYM "system_certificate_list_size"
+
+#define info(format, args...) fprintf(stderr, "INFO: " format, ## args)
+#define warn(format, args...) fprintf(stdout, "WARNING: " format, ## args)
+#define err(format, args...) fprintf(stderr, "ERROR: " format, ## args)
+
+#if UINTPTR_MAX == 0xffffffff
+#define CURRENT_ELFCLASS ELFCLASS32
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#else
+#define CURRENT_ELFCLASS ELFCLASS64
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Sym Elf64_Sym
+#endif
+
+static unsigned char endianness(void)
+{
+ uint16_t two_byte = 0x00FF;
+ uint8_t low_address = *((uint8_t *)&two_byte);
+
+ if (low_address == 0)
+ return ELFDATA2MSB;
+ else
+ return ELFDATA2LSB;
+}
+
+struct sym {
+ char *name;
+ unsigned long address;
+ unsigned long offset;
+ void *content;
+ int size;
+};
+
+static unsigned long get_offset_from_address(Elf_Ehdr *hdr, unsigned long addr)
+{
+ Elf_Shdr *x;
+ unsigned int i, num_sections;
+
+ x = (void *)hdr + hdr->e_shoff;
+ if (hdr->e_shnum == SHN_UNDEF)
+ num_sections = x[0].sh_size;
+ else
+ num_sections = hdr->e_shnum;
+
+ for (i = 1; i < num_sections; i++) {
+ unsigned long start = x[i].sh_addr;
+ unsigned long end = start + x[i].sh_size;
+ unsigned long offset = x[i].sh_offset;
+
+ if (addr >= start && addr <= end)
+ return addr - start + offset;
+ }
+ return 0;
+}
+
+
+#define LINE_SIZE 100
+
+static void get_symbol_from_map(Elf_Ehdr *hdr, FILE *f, char *name,
+ struct sym *s)
+{
+ char l[LINE_SIZE];
+ char *w, *p, *n;
+
+ s->size = 0;
+ s->address = 0;
+ s->offset = 0;
+ if (fseek(f, 0, SEEK_SET) != 0) {
+ perror("File seek failed");
+ exit(EXIT_FAILURE);
+ }
+ while (fgets(l, LINE_SIZE, f)) {
+ p = strchr(l, '\n');
+ if (!p) {
+ err("Missing line ending.\n");
+ return;
+ }
+ n = strstr(l, name);
+ if (n)
+ break;
+ }
+ if (!n) {
+ err("Unable to find symbol: %s\n", name);
+ return;
+ }
+ w = strchr(l, ' ');
+ if (!w)
+ return;
+
+ *w = '\0';
+ s->address = strtoul(l, NULL, 16);
+ if (s->address == 0)
+ return;
+ s->offset = get_offset_from_address(hdr, s->address);
+ s->name = name;
+ s->content = (void *)hdr + s->offset;
+}
+
+static Elf_Sym *find_elf_symbol(Elf_Ehdr *hdr, Elf_Shdr *symtab, char *name)
+{
+ Elf_Sym *sym, *symtab_start;
+ char *strtab, *symname;
+ unsigned int link;
+ Elf_Shdr *x;
+ int i, n;
+
+ x = (void *)hdr + hdr->e_shoff;
+ link = symtab->sh_link;
+ symtab_start = (void *)hdr + symtab->sh_offset;
+ n = symtab->sh_size / symtab->sh_entsize;
+ strtab = (void *)hdr + x[link].sh_offset;
+
+ for (i = 0; i < n; i++) {
+ sym = &symtab_start[i];
+ symname = strtab + sym->st_name;
+ if (strcmp(symname, name) == 0)
+ return sym;
+ }
+ err("Unable to find symbol: %s\n", name);
+ return NULL;
+}
+
+static void get_symbol_from_table(Elf_Ehdr *hdr, Elf_Shdr *symtab,
+ char *name, struct sym *s)
+{
+ Elf_Shdr *sec;
+ int secndx;
+ Elf_Sym *elf_sym;
+ Elf_Shdr *x;
+
+ x = (void *)hdr + hdr->e_shoff;
+ s->size = 0;
+ s->address = 0;
+ s->offset = 0;
+ elf_sym = find_elf_symbol(hdr, symtab, name);
+ if (!elf_sym)
+ return;
+ secndx = elf_sym->st_shndx;
+ if (!secndx)
+ return;
+ sec = &x[secndx];
+ s->size = elf_sym->st_size;
+ s->address = elf_sym->st_value;
+ s->offset = s->address - sec->sh_addr
+ + sec->sh_offset;
+ s->name = name;
+ s->content = (void *)hdr + s->offset;
+}
+
+static Elf_Shdr *get_symbol_table(Elf_Ehdr *hdr)
+{
+ Elf_Shdr *x;
+ unsigned int i, num_sections;
+
+ x = (void *)hdr + hdr->e_shoff;
+ if (hdr->e_shnum == SHN_UNDEF)
+ num_sections = x[0].sh_size;
+ else
+ num_sections = hdr->e_shnum;
+
+ for (i = 1; i < num_sections; i++)
+ if (x[i].sh_type == SHT_SYMTAB)
+ return &x[i];
+ return NULL;
+}
+
+static void *map_file(char *file_name, int *size)
+{
+ struct stat st;
+ void *map;
+ int fd;
+
+ fd = open(file_name, O_RDWR);
+ if (fd < 0) {
+ perror(file_name);
+ return NULL;
+ }
+ if (fstat(fd, &st)) {
+ perror("Could not determine file size");
+ close(fd);
+ return NULL;
+ }
+ *size = st.st_size;
+ map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) {
+ perror("Mapping to memory failed");
+ close(fd);
+ return NULL;
+ }
+ close(fd);
+ return map;
+}
+
+static char *read_file(char *file_name, int *size)
+{
+ struct stat st;
+ char *buf;
+ int fd;
+
+ fd = open(file_name, O_RDONLY);
+ if (fd < 0) {
+ perror(file_name);
+ return NULL;
+ }
+ if (fstat(fd, &st)) {
+ perror("Could not determine file size");
+ close(fd);
+ return NULL;
+ }
+ *size = st.st_size;
+ buf = malloc(*size);
+ if (!buf) {
+ perror("Allocating memory failed");
+ close(fd);
+ return NULL;
+ }
+ if (read(fd, buf, *size) != *size) {
+ perror("File read failed");
+ close(fd);
+ return NULL;
+ }
+ close(fd);
+ return buf;
+}
+
+static void print_sym(Elf_Ehdr *hdr, struct sym *s)
+{
+ info("sym: %s\n", s->name);
+ info("addr: 0x%lx\n", s->address);
+ info("size: %d\n", s->size);
+ info("offset: 0x%lx\n", (unsigned long)s->offset);
+}
+
+static void print_usage(char *e)
+{
+ printf("Usage %s [-s <System.map>] -b <vmlinux> -c <certfile>\n", e);
+}
+
+int main(int argc, char **argv)
+{
+ char *system_map_file = NULL;
+ char *vmlinux_file = NULL;
+ char *cert_file = NULL;
+ int vmlinux_size;
+ int cert_size;
+ Elf_Ehdr *hdr;
+ char *cert;
+ FILE *system_map;
+ unsigned long *lsize;
+ int *used;
+ int opt;
+ Elf_Shdr *symtab = NULL;
+ struct sym cert_sym, lsize_sym, used_sym;
+
+ while ((opt = getopt(argc, argv, "b:c:s:")) != -1) {
+ switch (opt) {
+ case 's':
+ system_map_file = optarg;
+ break;
+ case 'b':
+ vmlinux_file = optarg;
+ break;
+ case 'c':
+ cert_file = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!vmlinux_file || !cert_file) {
+ print_usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ cert = read_file(cert_file, &cert_size);
+ if (!cert)
+ exit(EXIT_FAILURE);
+
+ hdr = map_file(vmlinux_file, &vmlinux_size);
+ if (!hdr)
+ exit(EXIT_FAILURE);
+
+ if (vmlinux_size < sizeof(*hdr)) {
+ err("Invalid ELF file.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ err("Invalid ELF magic.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (hdr->e_ident[EI_CLASS] != CURRENT_ELFCLASS) {
+ err("ELF class mismatch.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (hdr->e_ident[EI_DATA] != endianness()) {
+ err("ELF endian mismatch.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (hdr->e_shoff > vmlinux_size) {
+ err("Could not find section header.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ symtab = get_symbol_table(hdr);
+ if (!symtab) {
+ warn("Could not find the symbol table.\n");
+ if (!system_map_file) {
+ err("Please provide a System.map file.\n");
+ print_usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ system_map = fopen(system_map_file, "r");
+ if (!system_map) {
+ perror(system_map_file);
+ exit(EXIT_FAILURE);
+ }
+ get_symbol_from_map(hdr, system_map, CERT_SYM, &cert_sym);
+ get_symbol_from_map(hdr, system_map, USED_SYM, &used_sym);
+ get_symbol_from_map(hdr, system_map, LSIZE_SYM, &lsize_sym);
+ cert_sym.size = used_sym.address - cert_sym.address;
+ } else {
+ info("Symbol table found.\n");
+ if (system_map_file)
+ warn("System.map is ignored.\n");
+ get_symbol_from_table(hdr, symtab, CERT_SYM, &cert_sym);
+ get_symbol_from_table(hdr, symtab, USED_SYM, &used_sym);
+ get_symbol_from_table(hdr, symtab, LSIZE_SYM, &lsize_sym);
+ }
+
+ if (!cert_sym.offset || !lsize_sym.offset || !used_sym.offset)
+ exit(EXIT_FAILURE);
+
+ print_sym(hdr, &cert_sym);
+ print_sym(hdr, &used_sym);
+ print_sym(hdr, &lsize_sym);
+
+ lsize = (unsigned long *)lsize_sym.content;
+ used = (int *)used_sym.content;
+
+ if (cert_sym.size < cert_size) {
+ err("Certificate is larger than the reserved area!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* If the existing cert is the same, don't overwrite */
+ if (cert_size == *used &&
+ strncmp(cert_sym.content, cert, cert_size) == 0) {
+ warn("Certificate was already inserted.\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ if (*used > 0)
+ warn("Replacing previously inserted certificate.\n");
+
+ memcpy(cert_sym.content, cert, cert_size);
+ if (cert_size < cert_sym.size)
+ memset(cert_sym.content + cert_size,
+ 0, cert_sym.size - cert_size);
+
+ *lsize = *lsize + cert_size - *used;
+ *used = cert_size;
+ info("Inserted the contents of %s into %lx.\n", cert_file,
+ cert_sym.address);
+ info("Used %d bytes out of %d bytes reserved.\n", *used,
+ cert_sym.size);
+ exit(EXIT_SUCCESS);
+}
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 250a7a6..d912d5a 100755
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -2,9 +2,11 @@
*
* Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
* Copyright © 2015 Intel Corporation.
+ * Copyright © 2016 Hewlett Packard Enterprise Development LP
*
* Authors: David Howells <dhowells@redhat.com>
* David Woodhouse <dwmw2@infradead.org>
+ * Juerg Haefliger <juerg.haefliger@hpe.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -39,7 +41,7 @@
* signing with anything other than SHA1 - so we're stuck with that if such is
* the case.
*/
-#if OPENSSL_VERSION_NUMBER < 0x10000000L
+#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS)
#define USE_PKCS7
#endif
#ifndef USE_PKCS7
@@ -67,6 +69,8 @@ void format(void)
{
fprintf(stderr,
"Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n");
+ fprintf(stderr,
+ " scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n");
exit(2);
}
@@ -126,26 +130,84 @@ static int pem_pw_cb(char *buf, int len, int w, void *v)
return pwlen;
}
+static EVP_PKEY *read_private_key(const char *private_key_name)
+{
+ EVP_PKEY *private_key;
+
+ if (!strncmp(private_key_name, "pkcs11:", 7)) {
+ ENGINE *e;
+
+ ENGINE_load_builtin_engines();
+ drain_openssl_errors();
+ e = ENGINE_by_id("pkcs11");
+ ERR(!e, "Load PKCS#11 ENGINE");
+ if (ENGINE_init(e))
+ drain_openssl_errors();
+ else
+ ERR(1, "ENGINE_init");
+ if (key_pass)
+ ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0),
+ "Set PKCS#11 PIN");
+ private_key = ENGINE_load_private_key(e, private_key_name,
+ NULL, NULL);
+ ERR(!private_key, "%s", private_key_name);
+ } else {
+ BIO *b;
+
+ b = BIO_new_file(private_key_name, "rb");
+ ERR(!b, "%s", private_key_name);
+ private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
+ NULL);
+ ERR(!private_key, "%s", private_key_name);
+ BIO_free(b);
+ }
+
+ return private_key;
+}
+
+static X509 *read_x509(const char *x509_name)
+{
+ X509 *x509;
+ BIO *b;
+
+ b = BIO_new_file(x509_name, "rb");
+ ERR(!b, "%s", x509_name);
+ x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
+ if (!x509) {
+ ERR(BIO_reset(b) != 1, "%s", x509_name);
+ x509 = PEM_read_bio_X509(b, NULL, NULL,
+ NULL); /* PEM encoded X.509 */
+ if (x509)
+ drain_openssl_errors();
+ }
+ BIO_free(b);
+ ERR(!x509, "%s", x509_name);
+
+ return x509;
+}
+
int main(int argc, char **argv)
{
struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
char *hash_algo = NULL;
- char *private_key_name, *x509_name, *module_name, *dest_name;
+ char *private_key_name = NULL, *raw_sig_name = NULL;
+ char *x509_name, *module_name, *dest_name;
bool save_sig = false, replace_orig;
bool sign_only = false;
+ bool raw_sig = false;
unsigned char buf[4096];
unsigned long module_size, sig_size;
unsigned int use_signed_attrs;
const EVP_MD *digest_algo;
EVP_PKEY *private_key;
#ifndef USE_PKCS7
- CMS_ContentInfo *cms;
+ CMS_ContentInfo *cms = NULL;
unsigned int use_keyid = 0;
#else
- PKCS7 *pkcs7;
+ PKCS7 *pkcs7 = NULL;
#endif
X509 *x509;
- BIO *b, *bd = NULL, *bm;
+ BIO *bd, *bm;
int opt, n;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
@@ -160,8 +222,9 @@ int main(int argc, char **argv)
#endif
do {
- opt = getopt(argc, argv, "dpk");
+ opt = getopt(argc, argv, "sdpk");
switch (opt) {
+ case 's': raw_sig = true; break;
case 'p': save_sig = true; break;
case 'd': sign_only = true; save_sig = true; break;
#ifndef USE_PKCS7
@@ -177,8 +240,13 @@ int main(int argc, char **argv)
if (argc < 4 || argc > 5)
format();
- hash_algo = argv[0];
- private_key_name = argv[1];
+ if (raw_sig) {
+ raw_sig_name = argv[0];
+ hash_algo = argv[1];
+ } else {
+ hash_algo = argv[0];
+ private_key_name = argv[1];
+ }
x509_name = argv[2];
module_name = argv[3];
if (argc == 5) {
@@ -198,101 +266,74 @@ int main(int argc, char **argv)
}
#endif
- /* Read the private key and the X.509 cert the PKCS#7 message
- * will point to.
- */
- if (!strncmp(private_key_name, "pkcs11:", 7)) {
- ENGINE *e;
-
- ENGINE_load_builtin_engines();
- drain_openssl_errors();
- e = ENGINE_by_id("pkcs11");
- ERR(!e, "Load PKCS#11 ENGINE");
- if (ENGINE_init(e))
- drain_openssl_errors();
- else
- ERR(1, "ENGINE_init");
- if (key_pass)
- ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
- private_key = ENGINE_load_private_key(e, private_key_name, NULL,
- NULL);
- ERR(!private_key, "%s", private_key_name);
- } else {
- b = BIO_new_file(private_key_name, "rb");
- ERR(!b, "%s", private_key_name);
- private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL);
- ERR(!private_key, "%s", private_key_name);
- BIO_free(b);
- }
-
- b = BIO_new_file(x509_name, "rb");
- ERR(!b, "%s", x509_name);
- x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
- if (!x509) {
- ERR(BIO_reset(b) != 1, "%s", x509_name);
- x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */
- if (x509)
- drain_openssl_errors();
- }
- BIO_free(b);
- ERR(!x509, "%s", x509_name);
-
- /* Open the destination file now so that we can shovel the module data
- * across as we read it.
- */
- if (!sign_only) {
- bd = BIO_new_file(dest_name, "wb");
- ERR(!bd, "%s", dest_name);
- }
-
- /* Digest the module data. */
- OpenSSL_add_all_digests();
- display_openssl_errors(__LINE__);
- digest_algo = EVP_get_digestbyname(hash_algo);
- ERR(!digest_algo, "EVP_get_digestbyname");
-
+ /* Open the module file */
bm = BIO_new_file(module_name, "rb");
ERR(!bm, "%s", module_name);
+ if (!raw_sig) {
+ /* Read the private key and the X.509 cert the PKCS#7 message
+ * will point to.
+ */
+ private_key = read_private_key(private_key_name);
+ x509 = read_x509(x509_name);
+
+ /* Digest the module data. */
+ OpenSSL_add_all_digests();
+ display_openssl_errors(__LINE__);
+ digest_algo = EVP_get_digestbyname(hash_algo);
+ ERR(!digest_algo, "EVP_get_digestbyname");
+
#ifndef USE_PKCS7
- /* Load the signature message from the digest buffer. */
- cms = CMS_sign(NULL, NULL, NULL, NULL,
- CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM);
- ERR(!cms, "CMS_sign");
-
- ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
- CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
- use_keyid | use_signed_attrs),
- "CMS_add1_signer");
- ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
- "CMS_final");
+ /* Load the signature message from the digest buffer. */
+ cms = CMS_sign(NULL, NULL, NULL, NULL,
+ CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
+ CMS_DETACHED | CMS_STREAM);
+ ERR(!cms, "CMS_sign");
+
+ ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
+ CMS_NOCERTS | CMS_BINARY |
+ CMS_NOSMIMECAP | use_keyid |
+ use_signed_attrs),
+ "CMS_add1_signer");
+ ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
+ "CMS_final");
#else
- pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
- PKCS7_NOCERTS | PKCS7_BINARY |
- PKCS7_DETACHED | use_signed_attrs);
- ERR(!pkcs7, "PKCS7_sign");
+ pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
+ PKCS7_NOCERTS | PKCS7_BINARY |
+ PKCS7_DETACHED | use_signed_attrs);
+ ERR(!pkcs7, "PKCS7_sign");
#endif
- if (save_sig) {
- char *sig_file_name;
+ if (save_sig) {
+ char *sig_file_name;
+ BIO *b;
- ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
- "asprintf");
- b = BIO_new_file(sig_file_name, "wb");
- ERR(!b, "%s", sig_file_name);
+ ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
+ "asprintf");
+ b = BIO_new_file(sig_file_name, "wb");
+ ERR(!b, "%s", sig_file_name);
#ifndef USE_PKCS7
- ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0,
- "%s", sig_file_name);
+ ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0,
+ "%s", sig_file_name);
#else
- ERR(i2d_PKCS7_bio(b, pkcs7) < 0,
- "%s", sig_file_name);
+ ERR(i2d_PKCS7_bio(b, pkcs7) < 0,
+ "%s", sig_file_name);
#endif
- BIO_free(b);
+ BIO_free(b);
+ }
+
+ if (sign_only) {
+ BIO_free(bm);
+ return 0;
+ }
}
- if (sign_only)
- return 0;
+ /* Open the destination file now so that we can shovel the module data
+ * across as we read it.
+ */
+ bd = BIO_new_file(dest_name, "wb");
+ ERR(!bd, "%s", dest_name);
/* Append the marker and the PKCS#7 message to the destination file */
ERR(BIO_reset(bm) < 0, "%s", module_name);
@@ -300,14 +341,29 @@ int main(int argc, char **argv)
n > 0) {
ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
}
+ BIO_free(bm);
ERR(n < 0, "%s", module_name);
module_size = BIO_number_written(bd);
+ if (!raw_sig) {
#ifndef USE_PKCS7
- ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
+ ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
#else
- ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
+ ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
#endif
+ } else {
+ BIO *b;
+
+ /* Read the raw signature file and write the data to the
+ * destination file
+ */
+ b = BIO_new_file(raw_sig_name, "rb");
+ ERR(!b, "%s", raw_sig_name);
+ while ((n = BIO_read(b, buf, sizeof(buf))), n > 0)
+ ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
+ BIO_free(b);
+ }
+
sig_size = BIO_number_written(bd) - module_size;
sig_info.sig_len = htonl(sig_size);
ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 21d7568..979be65 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -36,6 +36,7 @@ config INTEGRITY_ASYMMETRIC_KEYS
select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select PUBLIC_KEY_ALGO_RSA
+ select CRYPTO_RSA
select X509_CERTIFICATE_PARSER
help
This option enables digital signature verification using
@@ -45,7 +46,6 @@ config INTEGRITY_TRUSTED_KEYRING
bool "Require all keys on the integrity keyrings be signed"
depends on SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
- select KEYS_DEBUG_PROC_KEYS
default y
help
This option requires that all keys added to the .ima and
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 5ade2a7..80052ed 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -16,6 +16,7 @@
#include <linux/ratelimit.h>
#include <linux/key-type.h>
#include <crypto/public_key.h>
+#include <crypto/hash_info.h>
#include <keys/asymmetric-type.h>
#include <keys/system_keyring.h>
@@ -94,7 +95,7 @@ int asymmetric_verify(struct key *keyring, const char *sig,
if (siglen != __be16_to_cpu(hdr->sig_size))
return -EBADMSG;
- if (hdr->hash_algo >= PKEY_HASH__LAST)
+ if (hdr->hash_algo >= HASH_ALGO__LAST)
return -ENOPKG;
key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
@@ -103,16 +104,13 @@ int asymmetric_verify(struct key *keyring, const char *sig,
memset(&pks, 0, sizeof(pks));
- pks.pkey_hash_algo = hdr->hash_algo;
+ pks.pkey_algo = "rsa";
+ pks.hash_algo = hash_algo_name[hdr->hash_algo];
pks.digest = (u8 *)data;
pks.digest_size = datalen;
- pks.nr_mpi = 1;
- pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen);
-
- if (pks.rsa.s)
- ret = verify_signature(key, &pks);
-
- mpi_free(pks.rsa.s);
+ pks.s = hdr->sig;
+ pks.s_size = siglen;
+ ret = verify_signature(key, &pks);
key_put(key);
pr_debug("%s() = %d\n", __func__, ret);
return ret;
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 8f1ab37..345b759 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -77,7 +77,7 @@ static void iint_free(struct integrity_iint_cache *iint)
iint->ima_file_status = INTEGRITY_UNKNOWN;
iint->ima_mmap_status = INTEGRITY_UNKNOWN;
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
- iint->ima_module_status = INTEGRITY_UNKNOWN;
+ iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
kmem_cache_free(iint_cache, iint);
}
@@ -157,7 +157,7 @@ static void init_once(void *foo)
iint->ima_file_status = INTEGRITY_UNKNOWN;
iint->ima_mmap_status = INTEGRITY_UNKNOWN;
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
- iint->ima_module_status = INTEGRITY_UNKNOWN;
+ iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
}
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 585af61..5d0f611 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -19,10 +19,12 @@
#include <linux/types.h>
#include <linux/crypto.h>
+#include <linux/fs.h>
#include <linux/security.h>
#include <linux/hash.h>
#include <linux/tpm.h>
#include <linux/audit.h>
+#include <crypto/hash_info.h>
#include "../integrity.h"
@@ -106,6 +108,8 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode,
const unsigned char *filename);
int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash);
+int ima_calc_buffer_hash(const void *buf, loff_t len,
+ struct ima_digest_data *hash);
int ima_calc_field_array_hash(struct ima_field_data *field_data,
struct ima_template_desc *desc, int num_fields,
struct ima_digest_data *hash);
@@ -136,13 +140,25 @@ static inline unsigned long ima_hash_key(u8 *digest)
return hash_long(*digest, IMA_HASH_BITS);
}
+enum ima_hooks {
+ FILE_CHECK = 1,
+ MMAP_CHECK,
+ BPRM_CHECK,
+ POST_SETATTR,
+ MODULE_CHECK,
+ FIRMWARE_CHECK,
+ KEXEC_KERNEL_CHECK,
+ KEXEC_INITRAMFS_CHECK,
+ POLICY_CHECK,
+ MAX_CHECK
+};
+
/* LIM API function definitions */
-int ima_get_action(struct inode *inode, int mask, int function);
-int ima_must_measure(struct inode *inode, int mask, int function);
+int ima_get_action(struct inode *inode, int mask, enum ima_hooks func);
+int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct integrity_iint_cache *iint,
- struct file *file,
- struct evm_ima_xattr_data **xattr_value,
- int *xattr_len);
+ struct file *file, void *buf, loff_t size,
+ enum hash_algo algo);
void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
@@ -157,8 +173,6 @@ void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(struct path *path, char **pathbuf);
/* IMA policy related functions */
-enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
-
int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
void ima_init_policy(void);
@@ -178,23 +192,25 @@ int ima_policy_show(struct seq_file *m, void *v);
#define IMA_APPRAISE_LOG 0x04
#define IMA_APPRAISE_MODULES 0x08
#define IMA_APPRAISE_FIRMWARE 0x10
+#define IMA_APPRAISE_POLICY 0x20
#ifdef CONFIG_IMA_APPRAISE
-int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
+int ima_appraise_measurement(enum ima_hooks func,
+ struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, int opened);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
- int func);
-void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
- struct ima_digest_data *hash);
+ enum ima_hooks func);
+enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
+ int xattr_len);
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value);
#else
-static inline int ima_appraise_measurement(int func,
+static inline int ima_appraise_measurement(enum ima_hooks func,
struct integrity_iint_cache *iint,
struct file *file,
const unsigned char *filename,
@@ -216,15 +232,16 @@ static inline void ima_update_xattr(struct integrity_iint_cache *iint,
}
static inline enum integrity_status ima_get_cache_status(struct integrity_iint_cache
- *iint, int func)
+ *iint,
+ enum ima_hooks func)
{
return INTEGRITY_UNKNOWN;
}
-static inline void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
- int xattr_len,
- struct ima_digest_data *hash)
+static inline enum hash_algo
+ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len)
{
+ return ima_hash_algo;
}
static inline int ima_read_xattr(struct dentry *dentry,
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 1d950fb..370e42d 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -18,7 +18,7 @@
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/evm.h>
-#include <crypto/hash_info.h>
+
#include "ima.h"
/*
@@ -156,7 +156,7 @@ err_out:
* ima_get_action - appraise & measure decision based on policy.
* @inode: pointer to inode to measure
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
- * @function: calling function (FILE_CHECK, BPRM_CHECK, MMAP_CHECK, MODULE_CHECK)
+ * @func: caller identifier
*
* The policy is defined in terms of keypairs:
* subj=, obj=, type=, func=, mask=, fsmagic=
@@ -168,13 +168,13 @@ err_out:
* Returns IMA_MEASURE, IMA_APPRAISE mask.
*
*/
-int ima_get_action(struct inode *inode, int mask, int function)
+int ima_get_action(struct inode *inode, int mask, enum ima_hooks func)
{
int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
flags &= ima_policy_flag;
- return ima_match_policy(inode, function, mask, flags);
+ return ima_match_policy(inode, func, mask, flags);
}
/*
@@ -188,9 +188,8 @@ int ima_get_action(struct inode *inode, int mask, int function)
* Return 0 on success, error code otherwise
*/
int ima_collect_measurement(struct integrity_iint_cache *iint,
- struct file *file,
- struct evm_ima_xattr_data **xattr_value,
- int *xattr_len)
+ struct file *file, void *buf, loff_t size,
+ enum hash_algo algo)
{
const char *audit_cause = "failed";
struct inode *inode = file_inode(file);
@@ -201,9 +200,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
- if (xattr_value)
- *xattr_len = ima_read_xattr(file->f_path.dentry, xattr_value);
-
if (!(iint->flags & IMA_COLLECTED)) {
u64 i_version = file_inode(file)->i_version;
@@ -213,13 +209,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
goto out;
}
- /* use default hash algorithm */
- hash.hdr.algo = ima_hash_algo;
-
- if (xattr_value)
- ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr);
+ hash.hdr.algo = algo;
- result = ima_calc_file_hash(file, &hash.hdr);
+ result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) :
+ ima_calc_buffer_hash(buf, size, &hash.hdr);
if (!result) {
int length = sizeof(hash.hdr) + hash.hdr.length;
void *tmpbuf = krealloc(iint->ima_hash, length,
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 1873b55..6b4694a 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -15,7 +15,6 @@
#include <linux/magic.h>
#include <linux/ima.h>
#include <linux/evm.h>
-#include <crypto/hash_info.h>
#include "ima.h"
@@ -68,25 +67,25 @@ static int ima_fix_xattr(struct dentry *dentry,
/* Return specific func appraised cached result */
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
- int func)
+ enum ima_hooks func)
{
switch (func) {
case MMAP_CHECK:
return iint->ima_mmap_status;
case BPRM_CHECK:
return iint->ima_bprm_status;
- case MODULE_CHECK:
- return iint->ima_module_status;
- case FIRMWARE_CHECK:
- return iint->ima_firmware_status;
case FILE_CHECK:
- default:
+ case POST_SETATTR:
return iint->ima_file_status;
+ case MODULE_CHECK ... MAX_CHECK - 1:
+ default:
+ return iint->ima_read_status;
}
}
static void ima_set_cache_status(struct integrity_iint_cache *iint,
- int func, enum integrity_status status)
+ enum ima_hooks func,
+ enum integrity_status status)
{
switch (func) {
case MMAP_CHECK:
@@ -95,20 +94,19 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
case BPRM_CHECK:
iint->ima_bprm_status = status;
break;
- case MODULE_CHECK:
- iint->ima_module_status = status;
- break;
- case FIRMWARE_CHECK:
- iint->ima_firmware_status = status;
- break;
case FILE_CHECK:
- default:
+ case POST_SETATTR:
iint->ima_file_status = status;
break;
+ case MODULE_CHECK ... MAX_CHECK - 1:
+ default:
+ iint->ima_read_status = status;
+ break;
}
}
-static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
+static void ima_cache_flags(struct integrity_iint_cache *iint,
+ enum ima_hooks func)
{
switch (func) {
case MMAP_CHECK:
@@ -117,49 +115,51 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
case BPRM_CHECK:
iint->flags |= (IMA_BPRM_APPRAISED | IMA_APPRAISED);
break;
- case MODULE_CHECK:
- iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED);
- break;
- case FIRMWARE_CHECK:
- iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED);
- break;
case FILE_CHECK:
- default:
+ case POST_SETATTR:
iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
break;
+ case MODULE_CHECK ... MAX_CHECK - 1:
+ default:
+ iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED);
+ break;
}
}
-void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
- struct ima_digest_data *hash)
+enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
+ int xattr_len)
{
struct signature_v2_hdr *sig;
if (!xattr_value || xattr_len < 2)
- return;
+ /* return default hash algo */
+ return ima_hash_algo;
switch (xattr_value->type) {
case EVM_IMA_XATTR_DIGSIG:
sig = (typeof(sig))xattr_value;
if (sig->version != 2 || xattr_len <= sizeof(*sig))
- return;
- hash->algo = sig->hash_algo;
+ return ima_hash_algo;
+ return sig->hash_algo;
break;
case IMA_XATTR_DIGEST_NG:
- hash->algo = xattr_value->digest[0];
+ return xattr_value->digest[0];
break;
case IMA_XATTR_DIGEST:
/* this is for backward compatibility */
if (xattr_len == 21) {
unsigned int zero = 0;
if (!memcmp(&xattr_value->digest[16], &zero, 4))
- hash->algo = HASH_ALGO_MD5;
+ return HASH_ALGO_MD5;
else
- hash->algo = HASH_ALGO_SHA1;
+ return HASH_ALGO_SHA1;
} else if (xattr_len == 17)
- hash->algo = HASH_ALGO_MD5;
+ return HASH_ALGO_MD5;
break;
}
+
+ /* return default hash algo */
+ return ima_hash_algo;
}
int ima_read_xattr(struct dentry *dentry,
@@ -182,7 +182,8 @@ int ima_read_xattr(struct dentry *dentry,
*
* Return 0 on success, error code otherwise
*/
-int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
+int ima_appraise_measurement(enum ima_hooks func,
+ struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, int opened)
@@ -296,7 +297,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
if (iint->flags & IMA_DIGSIG)
return;
- rc = ima_collect_measurement(iint, file, NULL, NULL);
+ rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);
if (rc < 0)
return;
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 6eb6293..38f2ed8 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -24,7 +24,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <crypto/hash.h>
-#include <crypto/hash_info.h>
+
#include "ima.h"
struct ahash_completion {
@@ -519,6 +519,124 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
return rc;
}
+static int calc_buffer_ahash_atfm(const void *buf, loff_t len,
+ struct ima_digest_data *hash,
+ struct crypto_ahash *tfm)
+{
+ struct ahash_request *req;
+ struct scatterlist sg;
+ struct ahash_completion res;
+ int rc, ahash_rc = 0;
+
+ hash->length = crypto_ahash_digestsize(tfm);
+
+ req = ahash_request_alloc(tfm, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ init_completion(&res.completion);
+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ ahash_complete, &res);
+
+ rc = ahash_wait(crypto_ahash_init(req), &res);
+ if (rc)
+ goto out;
+
+ sg_init_one(&sg, buf, len);
+ ahash_request_set_crypt(req, &sg, NULL, len);
+
+ ahash_rc = crypto_ahash_update(req);
+
+ /* wait for the update request to complete */
+ rc = ahash_wait(ahash_rc, &res);
+ if (!rc) {
+ ahash_request_set_crypt(req, NULL, hash->digest, 0);
+ rc = ahash_wait(crypto_ahash_final(req), &res);
+ }
+out:
+ ahash_request_free(req);
+ return rc;
+}
+
+static int calc_buffer_ahash(const void *buf, loff_t len,
+ struct ima_digest_data *hash)
+{
+ struct crypto_ahash *tfm;
+ int rc;
+
+ tfm = ima_alloc_atfm(hash->algo);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ rc = calc_buffer_ahash_atfm(buf, len, hash, tfm);
+
+ ima_free_atfm(tfm);
+
+ return rc;
+}
+
+static int calc_buffer_shash_tfm(const void *buf, loff_t size,
+ struct ima_digest_data *hash,
+ struct crypto_shash *tfm)
+{
+ SHASH_DESC_ON_STACK(shash, tfm);
+ unsigned int len;
+ int rc;
+
+ shash->tfm = tfm;
+ shash->flags = 0;
+
+ hash->length = crypto_shash_digestsize(tfm);
+
+ rc = crypto_shash_init(shash);
+ if (rc != 0)
+ return rc;
+
+ while (size) {
+ len = size < PAGE_SIZE ? size : PAGE_SIZE;
+ rc = crypto_shash_update(shash, buf, len);
+ if (rc)
+ break;
+ buf += len;
+ size -= len;
+ }
+
+ if (!rc)
+ rc = crypto_shash_final(shash, hash->digest);
+ return rc;
+}
+
+static int calc_buffer_shash(const void *buf, loff_t len,
+ struct ima_digest_data *hash)
+{
+ struct crypto_shash *tfm;
+ int rc;
+
+ tfm = ima_alloc_tfm(hash->algo);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ rc = calc_buffer_shash_tfm(buf, len, hash, tfm);
+
+ ima_free_tfm(tfm);
+ return rc;
+}
+
+int ima_calc_buffer_hash(const void *buf, loff_t len,
+ struct ima_digest_data *hash)
+{
+ int rc;
+
+ if (ima_ahash_minsize && len >= ima_ahash_minsize) {
+ rc = calc_buffer_ahash(buf, len, hash);
+ if (!rc)
+ return 0;
+ }
+
+ return calc_buffer_shash(buf, len, hash);
+}
+
static void __init ima_pcrread(int idx, u8 *pcr)
{
if (!ima_used_chip)
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index f355231..60d011a 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -22,6 +22,7 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/parser.h>
+#include <linux/vmalloc.h>
#include "ima.h"
@@ -258,6 +259,43 @@ static const struct file_operations ima_ascii_measurements_ops = {
.release = seq_release,
};
+static ssize_t ima_read_policy(char *path)
+{
+ void *data;
+ char *datap;
+ loff_t size;
+ int rc, pathlen = strlen(path);
+
+ char *p;
+
+ /* remove \n */
+ datap = path;
+ strsep(&datap, "\n");
+
+ rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY);
+ if (rc < 0) {
+ pr_err("Unable to open file: %s (%d)", path, rc);
+ return rc;
+ }
+
+ datap = data;
+ while (size > 0 && (p = strsep(&datap, "\n"))) {
+ pr_debug("rule: %s\n", p);
+ rc = ima_parse_add_rule(p);
+ if (rc < 0)
+ break;
+ size -= rc;
+ }
+
+ vfree(data);
+ if (rc < 0)
+ return rc;
+ else if (size)
+ return -EINVAL;
+ else
+ return pathlen;
+}
+
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
@@ -286,9 +324,20 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
result = mutex_lock_interruptible(&ima_write_mutex);
if (result < 0)
goto out_free;
- result = ima_parse_add_rule(data);
- mutex_unlock(&ima_write_mutex);
+ if (data[0] == '/') {
+ result = ima_read_policy(data);
+ } else if (ima_appraise & IMA_APPRAISE_POLICY) {
+ pr_err("IMA: signed policy file (specified as an absolute pathname) required\n");
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
+ "policy_update", "signed policy required",
+ 1, 0);
+ if (ima_appraise & IMA_APPRAISE_ENFORCE)
+ result = -EACCES;
+ } else {
+ result = ima_parse_add_rule(data);
+ }
+ mutex_unlock(&ima_write_mutex);
out_free:
kfree(data);
out:
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index bd79f25..5d679a6 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -21,7 +21,7 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <crypto/hash_info.h>
+
#include "ima.h"
/* name for boot aggregate entry */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 9d96551..391f417 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -24,7 +24,6 @@
#include <linux/slab.h>
#include <linux/xattr.h>
#include <linux/ima.h>
-#include <crypto/hash_info.h>
#include "ima.h"
@@ -154,8 +153,8 @@ void ima_file_free(struct file *file)
ima_check_last_writer(iint, inode, file);
}
-static int process_measurement(struct file *file, int mask, int function,
- int opened)
+static int process_measurement(struct file *file, char *buf, loff_t size,
+ int mask, enum ima_hooks func, int opened)
{
struct inode *inode = file_inode(file);
struct integrity_iint_cache *iint = NULL;
@@ -163,9 +162,10 @@ static int process_measurement(struct file *file, int mask, int function,
char *pathbuf = NULL;
const char *pathname = NULL;
int rc = -ENOMEM, action, must_appraise;
- struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
+ struct evm_ima_xattr_data *xattr_value = NULL;
int xattr_len = 0;
bool violation_check;
+ enum hash_algo hash_algo;
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
@@ -174,8 +174,8 @@ static int process_measurement(struct file *file, int mask, int function,
* bitmask based on the appraise/audit/measurement policy.
* Included is the appraise submask.
*/
- action = ima_get_action(inode, mask, function);
- violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) &&
+ action = ima_get_action(inode, mask, func);
+ violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
return 0;
@@ -184,7 +184,7 @@ static int process_measurement(struct file *file, int mask, int function,
/* Is the appraise rule hook specific? */
if (action & IMA_FILE_APPRAISE)
- function = FILE_CHECK;
+ func = FILE_CHECK;
inode_lock(inode);
@@ -214,16 +214,19 @@ static int process_measurement(struct file *file, int mask, int function,
/* Nothing to do, just return existing appraised status */
if (!action) {
if (must_appraise)
- rc = ima_get_cache_status(iint, function);
+ rc = ima_get_cache_status(iint, func);
goto out_digsig;
}
template_desc = ima_template_desc_current();
if ((action & IMA_APPRAISE_SUBMASK) ||
strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
- xattr_ptr = &xattr_value;
+ /* read 'security.ima' */
+ xattr_len = ima_read_xattr(file->f_path.dentry, &xattr_value);
- rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
+ hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
+
+ rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
if (rc != 0) {
if (file->f_flags & O_DIRECT)
rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES;
@@ -237,7 +240,7 @@ static int process_measurement(struct file *file, int mask, int function,
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len);
if (action & IMA_APPRAISE_SUBMASK)
- rc = ima_appraise_measurement(function, iint, file, pathname,
+ rc = ima_appraise_measurement(func, iint, file, pathname,
xattr_value, xattr_len, opened);
if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname);
@@ -270,7 +273,8 @@ out:
int ima_file_mmap(struct file *file, unsigned long prot)
{
if (file && (prot & PROT_EXEC))
- return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0);
+ return process_measurement(file, NULL, 0, MAY_EXEC,
+ MMAP_CHECK, 0);
return 0;
}
@@ -289,7 +293,8 @@ int ima_file_mmap(struct file *file, unsigned long prot)
*/
int ima_bprm_check(struct linux_binprm *bprm)
{
- return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0);
+ return process_measurement(bprm->file, NULL, 0, MAY_EXEC,
+ BPRM_CHECK, 0);
}
/**
@@ -304,24 +309,26 @@ int ima_bprm_check(struct linux_binprm *bprm)
*/
int ima_file_check(struct file *file, int mask, int opened)
{
- return process_measurement(file,
+ return process_measurement(file, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK, opened);
}
EXPORT_SYMBOL_GPL(ima_file_check);
/**
- * ima_module_check - based on policy, collect/store/appraise measurement.
- * @file: pointer to the file to be measured/appraised
+ * ima_read_file - pre-measure/appraise hook decision based on policy
+ * @file: pointer to the file to be measured/appraised/audit
+ * @read_id: caller identifier
*
- * Measure/appraise kernel modules based on policy.
+ * Permit reading a file based on policy. The policy rules are written
+ * in terms of the policy identifier. Appraising the integrity of
+ * a file requires a file descriptor.
*
- * On success return 0. On integrity appraisal error, assuming the file
- * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
+ * For permission return 0, otherwise return -EACCES.
*/
-int ima_module_check(struct file *file)
+int ima_read_file(struct file *file, enum kernel_read_file_id read_id)
{
- if (!file) {
+ if (!file && read_id == READING_MODULE) {
#ifndef CONFIG_MODULE_SIG_FORCE
if ((ima_appraise & IMA_APPRAISE_MODULES) &&
(ima_appraise & IMA_APPRAISE_ENFORCE))
@@ -329,18 +336,53 @@ int ima_module_check(struct file *file)
#endif
return 0; /* We rely on module signature checking */
}
- return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0);
+ return 0;
}
-int ima_fw_from_file(struct file *file, char *buf, size_t size)
+static int read_idmap[READING_MAX_ID] = {
+ [READING_FIRMWARE] = FIRMWARE_CHECK,
+ [READING_MODULE] = MODULE_CHECK,
+ [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK,
+ [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK,
+ [READING_POLICY] = POLICY_CHECK
+};
+
+/**
+ * ima_post_read_file - in memory collect/appraise/audit measurement
+ * @file: pointer to the file to be measured/appraised/audit
+ * @buf: pointer to in memory file contents
+ * @size: size of in memory file contents
+ * @read_id: caller identifier
+ *
+ * Measure/appraise/audit in memory file based on policy. Policy rules
+ * are written in terms of a policy identifier.
+ *
+ * On success return 0. On integrity appraisal error, assuming the file
+ * is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
+ */
+int ima_post_read_file(struct file *file, void *buf, loff_t size,
+ enum kernel_read_file_id read_id)
{
- if (!file) {
+ enum ima_hooks func;
+
+ if (!file && read_id == READING_FIRMWARE) {
if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
(ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES; /* INTEGRITY_UNKNOWN */
return 0;
}
- return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0);
+
+ if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */
+ return 0;
+
+ if (!file || !buf || size == 0) { /* should never happen */
+ if (ima_appraise & IMA_APPRAISE_ENFORCE)
+ return -EACCES;
+ return 0;
+ }
+
+ func = read_idmap[read_id] ?: FILE_CHECK;
+ return process_measurement(file, buf, size, MAY_READ, func, 0);
}
static int __init init_ima(void)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 0a3b781..be09e2c 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -12,6 +12,7 @@
*/
#include <linux/module.h>
#include <linux/list.h>
+#include <linux/fs.h>
#include <linux/security.h>
#include <linux/magic.h>
#include <linux/parser.h>
@@ -113,6 +114,7 @@ static struct ima_rule_entry default_measurement_rules[] = {
.uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID},
{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
+ {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC},
};
static struct ima_rule_entry default_appraise_rules[] = {
@@ -127,6 +129,10 @@ static struct ima_rule_entry default_appraise_rules[] = {
{.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
+#ifdef CONFIG_IMA_WRITE_POLICY
+ {.action = APPRAISE, .func = POLICY_CHECK,
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+#endif
#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER},
#else
@@ -207,8 +213,8 @@ static void ima_lsm_update_rules(void)
*
* Returns true on rule match, false on failure.
*/
-static bool ima_match_rules(struct ima_rule_entry *rule,
- struct inode *inode, enum ima_hooks func, int mask)
+static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode,
+ enum ima_hooks func, int mask)
{
struct task_struct *tsk = current;
const struct cred *cred = current_cred();
@@ -289,7 +295,7 @@ retry:
* In addition to knowing that we need to appraise the file in general,
* we need to differentiate between calling hooks, for hook specific rules.
*/
-static int get_subaction(struct ima_rule_entry *rule, int func)
+static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
{
if (!(rule->flags & IMA_FUNC))
return IMA_FILE_APPRAISE;
@@ -299,13 +305,12 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
return IMA_MMAP_APPRAISE;
case BPRM_CHECK:
return IMA_BPRM_APPRAISE;
- case MODULE_CHECK:
- return IMA_MODULE_APPRAISE;
- case FIRMWARE_CHECK:
- return IMA_FIRMWARE_APPRAISE;
case FILE_CHECK:
- default:
+ case POST_SETATTR:
return IMA_FILE_APPRAISE;
+ case MODULE_CHECK ... MAX_CHECK - 1:
+ default:
+ return IMA_READ_APPRAISE;
}
}
@@ -411,13 +416,16 @@ void __init ima_init_policy(void)
for (i = 0; i < appraise_entries; i++) {
list_add_tail(&default_appraise_rules[i].list,
&ima_default_rules);
+ if (default_appraise_rules[i].func == POLICY_CHECK)
+ temp_ima_appraise |= IMA_APPRAISE_POLICY;
}
ima_rules = &ima_default_rules;
+ ima_update_policy_flag();
}
/* Make sure we have a valid policy, at least containing some rules. */
-int ima_check_policy()
+int ima_check_policy(void)
{
if (list_empty(&ima_temp_rules))
return -EINVAL;
@@ -612,6 +620,14 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->func = MMAP_CHECK;
else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
entry->func = BPRM_CHECK;
+ else if (strcmp(args[0].from, "KEXEC_KERNEL_CHECK") ==
+ 0)
+ entry->func = KEXEC_KERNEL_CHECK;
+ else if (strcmp(args[0].from, "KEXEC_INITRAMFS_CHECK")
+ == 0)
+ entry->func = KEXEC_INITRAMFS_CHECK;
+ else if (strcmp(args[0].from, "POLICY_CHECK") == 0)
+ entry->func = POLICY_CHECK;
else
result = -EINVAL;
if (!result)
@@ -770,6 +786,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
temp_ima_appraise |= IMA_APPRAISE_MODULES;
else if (entry->func == FIRMWARE_CHECK)
temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
+ else if (entry->func == POLICY_CHECK)
+ temp_ima_appraise |= IMA_APPRAISE_POLICY;
audit_log_format(ab, "res=%d", !result);
audit_log_end(ab);
return result;
@@ -855,7 +873,9 @@ static char *mask_tokens[] = {
enum {
func_file = 0, func_mmap, func_bprm,
- func_module, func_firmware, func_post
+ func_module, func_firmware, func_post,
+ func_kexec_kernel, func_kexec_initramfs,
+ func_policy
};
static char *func_tokens[] = {
@@ -864,6 +884,9 @@ static char *func_tokens[] = {
"BPRM_CHECK",
"MODULE_CHECK",
"FIRMWARE_CHECK",
+ "KEXEC_KERNEL_CHECK",
+ "KEXEC_INITRAMFS_CHECK",
+ "POLICY_CHECK",
"POST_SETATTR"
};
@@ -903,6 +926,49 @@ void ima_policy_stop(struct seq_file *m, void *v)
#define mt(token) mask_tokens[token]
#define ft(token) func_tokens[token]
+/*
+ * policy_func_show - display the ima_hooks policy rule
+ */
+static void policy_func_show(struct seq_file *m, enum ima_hooks func)
+{
+ char tbuf[64] = {0,};
+
+ switch (func) {
+ case FILE_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_file));
+ break;
+ case MMAP_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_mmap));
+ break;
+ case BPRM_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_bprm));
+ break;
+ case MODULE_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_module));
+ break;
+ case FIRMWARE_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_firmware));
+ break;
+ case POST_SETATTR:
+ seq_printf(m, pt(Opt_func), ft(func_post));
+ break;
+ case KEXEC_KERNEL_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_kexec_kernel));
+ break;
+ case KEXEC_INITRAMFS_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_kexec_initramfs));
+ break;
+ case POLICY_CHECK:
+ seq_printf(m, pt(Opt_func), ft(func_policy));
+ break;
+ default:
+ snprintf(tbuf, sizeof(tbuf), "%d", func);
+ seq_printf(m, pt(Opt_func), tbuf);
+ break;
+ }
+ seq_puts(m, " ");
+}
+
int ima_policy_show(struct seq_file *m, void *v)
{
struct ima_rule_entry *entry = v;
@@ -924,33 +990,8 @@ int ima_policy_show(struct seq_file *m, void *v)
seq_puts(m, " ");
- if (entry->flags & IMA_FUNC) {
- switch (entry->func) {
- case FILE_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_file));
- break;
- case MMAP_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_mmap));
- break;
- case BPRM_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_bprm));
- break;
- case MODULE_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_module));
- break;
- case FIRMWARE_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_firmware));
- break;
- case POST_SETATTR:
- seq_printf(m, pt(Opt_func), ft(func_post));
- break;
- default:
- snprintf(tbuf, sizeof(tbuf), "%d", entry->func);
- seq_printf(m, pt(Opt_func), tbuf);
- break;
- }
- seq_puts(m, " ");
- }
+ if (entry->flags & IMA_FUNC)
+ policy_func_show(m, entry->func);
if (entry->flags & IMA_MASK) {
if (entry->mask & MAY_EXEC)
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 0b7404e..febd12e 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -15,8 +15,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <crypto/hash_info.h>
-
#include "ima.h"
#include "ima_template_lib.h"
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 2934e3d..f9bae04 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -12,7 +12,6 @@
* File: ima_template_lib.c
* Library of supported template fields.
*/
-#include <crypto/hash_info.h>
#include "ima_template_lib.h"
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 5efe2ec..e08935c 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -45,16 +45,12 @@
#define IMA_MMAP_APPRAISED 0x00000800
#define IMA_BPRM_APPRAISE 0x00001000
#define IMA_BPRM_APPRAISED 0x00002000
-#define IMA_MODULE_APPRAISE 0x00004000
-#define IMA_MODULE_APPRAISED 0x00008000
-#define IMA_FIRMWARE_APPRAISE 0x00010000
-#define IMA_FIRMWARE_APPRAISED 0x00020000
+#define IMA_READ_APPRAISE 0x00004000
+#define IMA_READ_APPRAISED 0x00008000
#define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
- IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \
- IMA_FIRMWARE_APPRAISE)
+ IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
- IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \
- IMA_FIRMWARE_APPRAISED)
+ IMA_BPRM_APPRAISED | IMA_READ_APPRAISED)
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,
@@ -94,7 +90,7 @@ struct ima_digest_data {
struct signature_v2_hdr {
uint8_t type; /* xattr type */
uint8_t version; /* signature format version */
- uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
+ uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */
uint32_t keyid; /* IMA key identifier - not X509/PGP specific */
uint16_t sig_size; /* signature size */
uint8_t sig[0]; /* signature payload */
@@ -109,8 +105,7 @@ struct integrity_iint_cache {
enum integrity_status ima_file_status:4;
enum integrity_status ima_mmap_status:4;
enum integrity_status ima_bprm_status:4;
- enum integrity_status ima_module_status:4;
- enum integrity_status ima_firmware_status:4;
+ enum integrity_status ima_read_status:4;
enum integrity_status evm_status:4;
struct ima_digest_data *ima_hash;
};
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index 907c152..c721e39 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -9,7 +9,6 @@
* 2 of the Licence, or (at your option) any later version.
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/file.h>
@@ -18,8 +17,6 @@
#include <keys/user-type.h>
#include <keys/big_key-type.h>
-MODULE_LICENSE("GPL");
-
/*
* Layout of key payload words.
*/
@@ -212,18 +209,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
return ret;
}
-/*
- * Module stuff
- */
static int __init big_key_init(void)
{
return register_key_type(&key_type_big_key);
}
-
-static void __exit big_key_cleanup(void)
-{
- unregister_key_type(&key_type_big_key);
-}
-
-module_init(big_key_init);
-module_exit(big_key_cleanup);
+device_initcall(big_key_init);
diff --git a/security/keys/key.c b/security/keys/key.c
index 09ef276..b287551 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -296,6 +296,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
if (flags & KEY_ALLOC_TRUSTED)
key->flags |= 1 << KEY_FLAG_TRUSTED;
+ if (flags & KEY_ALLOC_BUILT_IN)
+ key->flags |= 1 << KEY_FLAG_BUILTIN;
#ifdef KEY_DEBUGGING
key->magic = KEY_DEBUG_MAGIC;
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 0dcab20..90d6175 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -744,6 +744,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
unsigned long handle;
unsigned long lock;
unsigned long token_mask = 0;
+ unsigned int digest_len;
int i;
int tpm2;
@@ -752,7 +753,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
return tpm2;
opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
- opt->digest_len = hash_digest_size[opt->hash];
while ((p = strsep(&c, " \t"))) {
if (*p == '\0' || *p == ' ' || *p == '\t')
@@ -812,8 +812,6 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
for (i = 0; i < HASH_ALGO__LAST; i++) {
if (!strcmp(args[0].from, hash_algo_name[i])) {
opt->hash = i;
- opt->digest_len =
- hash_digest_size[opt->hash];
break;
}
}
@@ -825,13 +823,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
}
break;
case Opt_policydigest:
- if (!tpm2 ||
- strlen(args[0].from) != (2 * opt->digest_len))
+ digest_len = hash_digest_size[opt->hash];
+ if (!tpm2 || strlen(args[0].from) != (2 * digest_len))
return -EINVAL;
res = hex2bin(opt->policydigest, args[0].from,
- opt->digest_len);
+ digest_len);
if (res < 0)
return -EINVAL;
+ opt->policydigest_len = digest_len;
break;
case Opt_policyhandle:
if (!tpm2)
diff --git a/security/security.c b/security/security.c
index e8ffd92..3644b034 100644
--- a/security/security.c
+++ b/security/security.c
@@ -884,31 +884,33 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
return call_int_hook(kernel_create_files_as, 0, new, inode);
}
-int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
+int security_kernel_module_request(char *kmod_name)
+{
+ return call_int_hook(kernel_module_request, 0, kmod_name);
+}
+
+int security_kernel_read_file(struct file *file, enum kernel_read_file_id id)
{
int ret;
- ret = call_int_hook(kernel_fw_from_file, 0, file, buf, size);
+ ret = call_int_hook(kernel_read_file, 0, file, id);
if (ret)
return ret;
- return ima_fw_from_file(file, buf, size);
-}
-EXPORT_SYMBOL_GPL(security_kernel_fw_from_file);
-
-int security_kernel_module_request(char *kmod_name)
-{
- return call_int_hook(kernel_module_request, 0, kmod_name);
+ return ima_read_file(file, id);
}
+EXPORT_SYMBOL_GPL(security_kernel_read_file);
-int security_kernel_module_from_file(struct file *file)
+int security_kernel_post_read_file(struct file *file, char *buf, loff_t size,
+ enum kernel_read_file_id id)
{
int ret;
- ret = call_int_hook(kernel_module_from_file, 0, file);
+ ret = call_int_hook(kernel_post_read_file, 0, file, buf, size, id);
if (ret)
return ret;
- return ima_module_check(file);
+ return ima_post_read_file(file, buf, size, id);
}
+EXPORT_SYMBOL_GPL(security_kernel_post_read_file);
int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags)
@@ -1691,12 +1693,12 @@ struct security_hook_heads security_hook_heads = {
LIST_HEAD_INIT(security_hook_heads.kernel_act_as),
.kernel_create_files_as =
LIST_HEAD_INIT(security_hook_heads.kernel_create_files_as),
- .kernel_fw_from_file =
- LIST_HEAD_INIT(security_hook_heads.kernel_fw_from_file),
.kernel_module_request =
LIST_HEAD_INIT(security_hook_heads.kernel_module_request),
- .kernel_module_from_file =
- LIST_HEAD_INIT(security_hook_heads.kernel_module_from_file),
+ .kernel_read_file =
+ LIST_HEAD_INIT(security_hook_heads.kernel_read_file),
+ .kernel_post_read_file =
+ LIST_HEAD_INIT(security_hook_heads.kernel_post_read_file),
.task_fix_setuid =
LIST_HEAD_INIT(security_hook_heads.task_fix_setuid),
.task_setpgid = LIST_HEAD_INIT(security_hook_heads.task_setpgid),
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index ad5cd76..3411c33 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -13,7 +13,7 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
selinux-$(CONFIG_NETLABEL) += netlabel.o
-ccflags-y := -Isecurity/selinux -Isecurity/selinux/include
+ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
$(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2d6e9bd..11f7901 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1442,9 +1442,13 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
* Don't do anything special for these.
* XATTR_NAME_SMACKIPIN
* XATTR_NAME_SMACKIPOUT
- * XATTR_NAME_SMACKEXEC
*/
- if (strcmp(name, XATTR_NAME_SMACK) == 0)
+ if (strcmp(name, XATTR_NAME_SMACK) == 0) {
+ struct super_block *sbp = d_backing_inode(dentry)->i_sb;
+ struct superblock_smack *sbsp = sbp->s_security;
+
+ isp->smk_inode = sbsp->smk_default;
+ } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
isp->smk_task = NULL;
else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
isp->smk_mmap = NULL;
@@ -1545,12 +1549,8 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid)
* File Hooks
*/
-/**
- * smack_file_permission - Smack check on file operations
- * @file: unused
- * @mask: unused
- *
- * Returns 0
+/*
+ * There is no smack_file_permission hook
*
* Should access checks be done on each read or write?
* UNICOS and SELinux say yes.
@@ -1559,10 +1559,6 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid)
* I'll say no for now. Smack does not do the frequent
* label changing that SELinux does.
*/
-static int smack_file_permission(struct file *file, int mask)
-{
- return 0;
-}
/**
* smack_file_alloc_security - assign a file security blob
@@ -4503,16 +4499,10 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
return 0;
}
-/**
- * smack_audit_rule_free - free smack rule representation
- * @vrule: rule to be freed.
- *
+/*
+ * There is no need for a smack_audit_rule_free hook.
* No memory was allocated.
*/
-static void smack_audit_rule_free(void *vrule)
-{
- /* No-op */
-}
#endif /* CONFIG_AUDIT */
@@ -4563,16 +4553,11 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
return 0;
}
-/**
- * smack_release_secctx - don't do anything.
- * @secdata: unused
- * @seclen: unused
- *
- * Exists to make sure nothing gets done, and properly
+/*
+ * There used to be a smack_release_secctx hook
+ * that did nothing back when hooks were in a vector.
+ * Now that there's a list such a hook adds cost.
*/
-static void smack_release_secctx(char *secdata, u32 seclen)
-{
-}
static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
@@ -4631,7 +4616,6 @@ static struct security_hook_list smack_hooks[] = {
LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity),
LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
- LSM_HOOK_INIT(file_permission, smack_file_permission),
LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
LSM_HOOK_INIT(file_free_security, smack_file_free_security),
LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
@@ -4726,13 +4710,11 @@ static struct security_hook_list smack_hooks[] = {
LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init),
LSM_HOOK_INIT(audit_rule_known, smack_audit_rule_known),
LSM_HOOK_INIT(audit_rule_match, smack_audit_rule_match),
- LSM_HOOK_INIT(audit_rule_free, smack_audit_rule_free),
#endif /* CONFIG_AUDIT */
LSM_HOOK_INIT(ismaclabel, smack_ismaclabel),
LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
- LSM_HOOK_INIT(release_secctx, smack_release_secctx),
LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
OpenPOWER on IntegriCloud