Browse Source

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security subsystem updates from James Morris:
 "In this release:

   - PKCS#7 parser for the key management subsystem from David Howells
   - appoint Kees Cook as seccomp maintainer
   - bugfixes and general maintenance across the subsystem"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (94 commits)
  X.509: Need to export x509_request_asymmetric_key()
  netlabel: shorter names for the NetLabel catmap funcs/structs
  netlabel: fix the catmap walking functions
  netlabel: fix the horribly broken catmap functions
  netlabel: fix a problem when setting bits below the previously lowest bit
  PKCS#7: X.509 certificate issuer and subject are mandatory fields in the ASN.1
  tpm: simplify code by using %*phN specifier
  tpm: Provide a generic means to override the chip returned timeouts
  tpm: missing tpm_chip_put in tpm_get_random()
  tpm: Properly clean sysfs entries in error path
  tpm: Add missing tpm_do_selftest to ST33 I2C driver
  PKCS#7: Use x509_request_asymmetric_key()
  Revert "selinux: fix the default socket labeling in sock_graft()"
  X.509: x509_request_asymmetric_keys() doesn't need string length arguments
  PKCS#7: fix sparse non static symbol warning
  KEYS: revert encrypted key change
  ima: add support for measuring and appraising firmware
  firmware_class: perform new LSM checks
  security: introduce kernel_fw_from_file hook
  PKCS#7: Missing inclusion of linux/err.h
  ...
Linus Torvalds 11 years ago
parent
commit
bb2cbf5e93
100 changed files with 4332 additions and 587 deletions
  1. 3 1
      Documentation/ABI/testing/ima_policy
  2. 22 0
      Documentation/kernel-parameters.txt
  3. 10 4
      Documentation/security/keys.txt
  4. 10 0
      MAINTAINERS
  5. 1 0
      arch/Kconfig
  6. 1 0
      arch/arm/include/uapi/asm/unistd.h
  7. 1 0
      arch/arm/kernel/calls.S
  8. 9 6
      arch/mips/include/uapi/asm/unistd.h
  9. 1 0
      arch/mips/kernel/scall32-o32.S
  10. 1 0
      arch/mips/kernel/scall64-64.S
  11. 1 0
      arch/mips/kernel/scall64-n32.S
  12. 1 0
      arch/mips/kernel/scall64-o32.S
  13. 1 0
      arch/x86/syscalls/syscall_32.tbl
  14. 1 0
      arch/x86/syscalls/syscall_64.tbl
  15. 32 2
      crypto/asymmetric_keys/Kconfig
  16. 37 0
      crypto/asymmetric_keys/Makefile
  17. 2 0
      crypto/asymmetric_keys/asymmetric_keys.h
  18. 34 44
      crypto/asymmetric_keys/asymmetric_type.c
  19. 28 0
      crypto/asymmetric_keys/mscode.asn1
  20. 126 0
      crypto/asymmetric_keys/mscode_parser.c
  21. 127 0
      crypto/asymmetric_keys/pkcs7.asn1
  22. 100 0
      crypto/asymmetric_keys/pkcs7_key_type.c
  23. 396 0
      crypto/asymmetric_keys/pkcs7_parser.c
  24. 61 0
      crypto/asymmetric_keys/pkcs7_parser.h
  25. 166 0
      crypto/asymmetric_keys/pkcs7_trust.c
  26. 321 0
      crypto/asymmetric_keys/pkcs7_verify.c
  27. 457 0
      crypto/asymmetric_keys/verify_pefile.c
  28. 42 0
      crypto/asymmetric_keys/verify_pefile.h
  29. 1 1
      crypto/asymmetric_keys/x509.asn1
  30. 20 0
      crypto/asymmetric_keys/x509_cert_parser.c
  31. 12 1
      crypto/asymmetric_keys/x509_parser.h
  32. 113 2
      crypto/asymmetric_keys/x509_public_key.c
  33. 26 4
      drivers/base/firmware_class.c
  34. 48 25
      drivers/char/tpm/tpm-interface.c
  35. 1 3
      drivers/char/tpm/tpm_eventlog.c
  36. 1 0
      drivers/char/tpm/tpm_i2c_stm_st33.c
  37. 31 0
      drivers/char/tpm/tpm_tis.c
  38. 3 3
      fs/exec.c
  39. 8 2
      fs/nfs/idmap.c
  40. 1 10
      fs/proc/array.c
  41. 36 0
      include/crypto/pkcs7.h
  42. 4 0
      include/crypto/public_key.h
  43. 2 1
      include/keys/big_key-type.h
  44. 9 1
      include/keys/system_keyring.h
  45. 2 1
      include/keys/user-type.h
  46. 4 1
      include/linux/capability.h
  47. 6 0
      include/linux/ima.h
  48. 4 1
      include/linux/key-type.h
  49. 2 0
      include/linux/key.h
  50. 7 1
      include/linux/oid_registry.h
  51. 448 0
      include/linux/pe.h
  52. 15 3
      include/linux/sched.h
  53. 5 3
      include/linux/seccomp.h
  54. 17 0
      include/linux/security.h
  55. 2 0
      include/linux/syscalls.h
  56. 3 0
      include/linux/tpm.h
  57. 18 0
      include/linux/verify_pefile.h
  58. 53 41
      include/net/netlabel.h
  59. 3 1
      include/uapi/asm-generic/unistd.h
  60. 7 0
      include/uapi/linux/seccomp.h
  61. 1 1
      kernel/audit.c
  62. 4 0
      kernel/capability.c
  63. 48 1
      kernel/fork.c
  64. 353 59
      kernel/seccomp.c
  65. 2 2
      kernel/sys.c
  66. 3 0
      kernel/sys_ni.c
  67. 1 0
      kernel/system_keyring.c
  68. 2 1
      lib/Kconfig
  69. 14 12
      net/ceph/crypto.c
  70. 25 18
      net/dns_resolver/dns_key.c
  71. 1 0
      net/dns_resolver/dns_query.c
  72. 16 31
      net/ipv4/cipso_ipv4.c
  73. 227 100
      net/netlabel/netlabel_kapi.c
  74. 97 68
      net/rxrpc/ar-key.c
  75. 0 1
      scripts/selinux/genheaders/Makefile
  76. 1 1
      scripts/selinux/mdp/Makefile
  77. 2 2
      security/apparmor/domain.c
  78. 6 0
      security/capability.c
  79. 33 42
      security/commoncap.c
  80. 28 0
      security/integrity/digsig.c
  81. 10 0
      security/integrity/ima/Kconfig
  82. 14 1
      security/integrity/ima/ima.h
  83. 9 1
      security/integrity/ima/ima_appraise.c
  84. 309 3
      security/integrity/ima/ima_crypto.c
  85. 21 7
      security/integrity/ima/ima_main.c
  86. 10 3
      security/integrity/ima/ima_policy.c
  87. 12 2
      security/integrity/integrity.h
  88. 25 16
      security/keys/big_key.c
  89. 44 5
      security/keys/key.c
  90. 18 3
      security/keys/keyctl.c
  91. 23 11
      security/keys/keyring.c
  92. 13 0
      security/keys/request_key_auth.c
  93. 22 19
      security/keys/user_defined.c
  94. 11 0
      security/security.c
  95. 14 0
      security/selinux/hooks.c
  96. 2 0
      security/selinux/include/netif.h
  97. 2 0
      security/selinux/include/netnode.h
  98. 2 0
      security/selinux/include/netport.h
  99. 2 1
      security/selinux/include/security.h
  100. 1 14
      security/selinux/netif.c

+ 3 - 1
Documentation/ABI/testing/ima_policy

@@ -26,6 +26,7 @@ Description:
 			option:	[[appraise_type=]] [permit_directio]
 			option:	[[appraise_type=]] [permit_directio]
 
 
 		base: 	func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
 		base: 	func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK]
+				[FIRMWARE_CHECK]
 			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
 			mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
 			fsmagic:= hex value
 			fsmagic:= hex value
 			fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6)
 			fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6)
@@ -57,7 +58,8 @@ Description:
 			measure func=BPRM_CHECK
 			measure func=BPRM_CHECK
 			measure func=FILE_MMAP mask=MAY_EXEC
 			measure func=FILE_MMAP mask=MAY_EXEC
 			measure func=FILE_CHECK mask=MAY_READ uid=0
 			measure func=FILE_CHECK mask=MAY_READ uid=0
-			measure func=MODULE_CHECK uid=0
+			measure func=MODULE_CHECK
+			measure func=FIRMWARE_CHECK
 			appraise fowner=0
 			appraise fowner=0
 
 
 		The default policy measures all executables in bprm_check,
 		The default policy measures all executables in bprm_check,

+ 22 - 0
Documentation/kernel-parameters.txt

@@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			possible to determine what the correct size should be.
 			possible to determine what the correct size should be.
 			This option provides an override for these situations.
 			This option provides an override for these situations.
 
 
+	ca_keys=	[KEYS] This parameter identifies a specific key(s) on
+			the system trusted keyring to be used for certificate
+			trust validation.
+			format: { id:<keyid> | builtin }
+
 	ccw_timeout_log [S390]
 	ccw_timeout_log [S390]
 			See Documentation/s390/CommonIO for details.
 			See Documentation/s390/CommonIO for details.
 
 
@@ -1319,6 +1324,23 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			Formats: { "ima" | "ima-ng" }
 			Formats: { "ima" | "ima-ng" }
 			Default: "ima-ng"
 			Default: "ima-ng"
 
 
+	ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage
+			Format: <min_file_size>
+			Set the minimal file size for using asynchronous hash.
+			If left unspecified, ahash usage is disabled.
+
+			ahash performance varies for different data sizes on
+			different crypto accelerators. This option can be used
+			to achieve the best performance for a particular HW.
+
+	ima.ahash_bufsize= [IMA] Asynchronous hash buffer size
+			Format: <bufsize>
+			Set hashing buffer size. Default: 4k.
+
+			ahash performance varies for different chunk sizes on
+			different crypto accelerators. This option can be used
+			to achieve best performance for particular HW.
+
 	init=		[KNL]
 	init=		[KNL]
 			Format: <full_path>
 			Format: <full_path>
 			Run specified binary instead of /sbin/init as init
 			Run specified binary instead of /sbin/init as init

+ 10 - 4
Documentation/security/keys.txt

@@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory:
 		const void	*data;
 		const void	*data;
 		size_t		datalen;
 		size_t		datalen;
 		size_t		quotalen;
 		size_t		quotalen;
+		time_t		expiry;
 	};
 	};
 
 
      Before calling the method, the caller will fill in data and datalen with
      Before calling the method, the caller will fill in data and datalen with
      the payload blob parameters; quotalen will be filled in with the default
      the payload blob parameters; quotalen will be filled in with the default
-     quota size from the key type and the rest will be cleared.
+     quota size from the key type; expiry will be set to TIME_T_MAX and the
+     rest will be cleared.
 
 
      If a description can be proposed from the payload contents, that should be
      If a description can be proposed from the payload contents, that should be
      attached as a string to the description field.  This will be used for the
      attached as a string to the description field.  This will be used for the
      key description if the caller of add_key() passes NULL or "".
      key description if the caller of add_key() passes NULL or "".
 
 
      The method can attach anything it likes to type_data[] and payload.  These
      The method can attach anything it likes to type_data[] and payload.  These
-     are merely passed along to the instantiate() or update() operations.
+     are merely passed along to the instantiate() or update() operations.  If
+     set, the expiry time will be applied to the key if it is instantiated from
+     this data.
 
 
-     The method should return 0 if success ful or a negative error code
+     The method should return 0 if successful or a negative error code
      otherwise.
      otherwise.
 
 
      
      
@@ -1172,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory:
      This method is only required if the preparse() method is provided,
      This method is only required if the preparse() method is provided,
      otherwise it is unused.  It cleans up anything attached to the
      otherwise it is unused.  It cleans up anything attached to the
      description, type_data and payload fields of the key_preparsed_payload
      description, type_data and payload fields of the key_preparsed_payload
-     struct as filled in by the preparse() method.
+     struct as filled in by the preparse() method.  It will always be called
+     after preparse() returns successfully, even if instantiate() or update()
+     succeed.
 
 
 
 
  (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
  (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);

+ 10 - 0
MAINTAINERS

@@ -8002,6 +8002,16 @@ S:	Maintained
 F:	drivers/mmc/host/sdhci.*
 F:	drivers/mmc/host/sdhci.*
 F:	drivers/mmc/host/sdhci-pltfm.[ch]
 F:	drivers/mmc/host/sdhci-pltfm.[ch]
 
 
+SECURE COMPUTING
+M:	Kees Cook <keescook@chromium.org>
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
+S:	Supported
+F:	kernel/seccomp.c
+F:	include/uapi/linux/seccomp.h
+F:	include/linux/seccomp.h
+K:	\bsecure_computing
+K:	\bTIF_SECCOMP\b
+
 SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
 SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
 M:	Anton Vorontsov <anton@enomsg.org>
 M:	Anton Vorontsov <anton@enomsg.org>
 L:	linuxppc-dev@lists.ozlabs.org
 L:	linuxppc-dev@lists.ozlabs.org

+ 1 - 0
arch/Kconfig

@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER
 	  - secure_computing is called from a ptrace_event()-safe context
 	  - secure_computing is called from a ptrace_event()-safe context
 	  - secure_computing return value is checked and a return value of -1
 	  - secure_computing return value is checked and a return value of -1
 	    results in the system call being skipped immediately.
 	    results in the system call being skipped immediately.
+	  - seccomp syscall wired up
 
 
 config SECCOMP_FILTER
 config SECCOMP_FILTER
 	def_bool y
 	def_bool y

+ 1 - 0
arch/arm/include/uapi/asm/unistd.h

@@ -409,6 +409,7 @@
 #define __NR_sched_setattr		(__NR_SYSCALL_BASE+380)
 #define __NR_sched_setattr		(__NR_SYSCALL_BASE+380)
 #define __NR_sched_getattr		(__NR_SYSCALL_BASE+381)
 #define __NR_sched_getattr		(__NR_SYSCALL_BASE+381)
 #define __NR_renameat2			(__NR_SYSCALL_BASE+382)
 #define __NR_renameat2			(__NR_SYSCALL_BASE+382)
+#define __NR_seccomp			(__NR_SYSCALL_BASE+383)
 
 
 /*
 /*
  * The following SWIs are ARM private.
  * The following SWIs are ARM private.

+ 1 - 0
arch/arm/kernel/calls.S

@@ -392,6 +392,7 @@
 /* 380 */	CALL(sys_sched_setattr)
 /* 380 */	CALL(sys_sched_setattr)
 		CALL(sys_sched_getattr)
 		CALL(sys_sched_getattr)
 		CALL(sys_renameat2)
 		CALL(sys_renameat2)
+		CALL(sys_seccomp)
 #ifndef syscalls_counted
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
 #define syscalls_counted

+ 9 - 6
arch/mips/include/uapi/asm/unistd.h

@@ -372,16 +372,17 @@
 #define __NR_sched_setattr		(__NR_Linux + 349)
 #define __NR_sched_setattr		(__NR_Linux + 349)
 #define __NR_sched_getattr		(__NR_Linux + 350)
 #define __NR_sched_getattr		(__NR_Linux + 350)
 #define __NR_renameat2			(__NR_Linux + 351)
 #define __NR_renameat2			(__NR_Linux + 351)
+#define __NR_seccomp			(__NR_Linux + 352)
 
 
 /*
 /*
  * Offset of the last Linux o32 flavoured syscall
  * Offset of the last Linux o32 flavoured syscall
  */
  */
-#define __NR_Linux_syscalls		351
+#define __NR_Linux_syscalls		352
 
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 
 #define __NR_O32_Linux			4000
 #define __NR_O32_Linux			4000
-#define __NR_O32_Linux_syscalls		351
+#define __NR_O32_Linux_syscalls		352
 
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 
@@ -701,16 +702,17 @@
 #define __NR_sched_setattr		(__NR_Linux + 309)
 #define __NR_sched_setattr		(__NR_Linux + 309)
 #define __NR_sched_getattr		(__NR_Linux + 310)
 #define __NR_sched_getattr		(__NR_Linux + 310)
 #define __NR_renameat2			(__NR_Linux + 311)
 #define __NR_renameat2			(__NR_Linux + 311)
+#define __NR_seccomp			(__NR_Linux + 312)
 
 
 /*
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  * Offset of the last Linux 64-bit flavoured syscall
  */
  */
-#define __NR_Linux_syscalls		311
+#define __NR_Linux_syscalls		312
 
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 
 #define __NR_64_Linux			5000
 #define __NR_64_Linux			5000
-#define __NR_64_Linux_syscalls		311
+#define __NR_64_Linux_syscalls		312
 
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 
@@ -1034,15 +1036,16 @@
 #define __NR_sched_setattr		(__NR_Linux + 313)
 #define __NR_sched_setattr		(__NR_Linux + 313)
 #define __NR_sched_getattr		(__NR_Linux + 314)
 #define __NR_sched_getattr		(__NR_Linux + 314)
 #define __NR_renameat2			(__NR_Linux + 315)
 #define __NR_renameat2			(__NR_Linux + 315)
+#define __NR_seccomp			(__NR_Linux + 316)
 
 
 /*
 /*
  * Offset of the last N32 flavoured syscall
  * Offset of the last N32 flavoured syscall
  */
  */
-#define __NR_Linux_syscalls		315
+#define __NR_Linux_syscalls		316
 
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 
 #define __NR_N32_Linux			6000
 #define __NR_N32_Linux			6000
-#define __NR_N32_Linux_syscalls		315
+#define __NR_N32_Linux_syscalls		316
 
 
 #endif /* _UAPI_ASM_UNISTD_H */
 #endif /* _UAPI_ASM_UNISTD_H */

+ 1 - 0
arch/mips/kernel/scall32-o32.S

@@ -578,3 +578,4 @@ EXPORT(sys_call_table)
 	PTR	sys_sched_setattr
 	PTR	sys_sched_setattr
 	PTR	sys_sched_getattr		/* 4350 */
 	PTR	sys_sched_getattr		/* 4350 */
 	PTR	sys_renameat2
 	PTR	sys_renameat2
+	PTR	sys_seccomp

+ 1 - 0
arch/mips/kernel/scall64-64.S

@@ -431,4 +431,5 @@ EXPORT(sys_call_table)
 	PTR	sys_sched_setattr
 	PTR	sys_sched_setattr
 	PTR	sys_sched_getattr		/* 5310 */
 	PTR	sys_sched_getattr		/* 5310 */
 	PTR	sys_renameat2
 	PTR	sys_renameat2
+	PTR	sys_seccomp
 	.size	sys_call_table,.-sys_call_table
 	.size	sys_call_table,.-sys_call_table

+ 1 - 0
arch/mips/kernel/scall64-n32.S

@@ -424,4 +424,5 @@ EXPORT(sysn32_call_table)
 	PTR	sys_sched_setattr
 	PTR	sys_sched_setattr
 	PTR	sys_sched_getattr
 	PTR	sys_sched_getattr
 	PTR	sys_renameat2			/* 6315 */
 	PTR	sys_renameat2			/* 6315 */
+	PTR	sys_seccomp
 	.size	sysn32_call_table,.-sysn32_call_table
 	.size	sysn32_call_table,.-sysn32_call_table

+ 1 - 0
arch/mips/kernel/scall64-o32.S

@@ -557,4 +557,5 @@ EXPORT(sys32_call_table)
 	PTR	sys_sched_setattr
 	PTR	sys_sched_setattr
 	PTR	sys_sched_getattr		/* 4350 */
 	PTR	sys_sched_getattr		/* 4350 */
 	PTR	sys_renameat2
 	PTR	sys_renameat2
+	PTR	sys_seccomp
 	.size	sys32_call_table,.-sys32_call_table
 	.size	sys32_call_table,.-sys32_call_table

+ 1 - 0
arch/x86/syscalls/syscall_32.tbl

@@ -360,3 +360,4 @@
 351	i386	sched_setattr		sys_sched_setattr
 351	i386	sched_setattr		sys_sched_setattr
 352	i386	sched_getattr		sys_sched_getattr
 352	i386	sched_getattr		sys_sched_getattr
 353	i386	renameat2		sys_renameat2
 353	i386	renameat2		sys_renameat2
+354	i386	seccomp			sys_seccomp

+ 1 - 0
arch/x86/syscalls/syscall_64.tbl

@@ -323,6 +323,7 @@
 314	common	sched_setattr		sys_sched_setattr
 314	common	sched_setattr		sys_sched_setattr
 315	common	sched_getattr		sys_sched_getattr
 315	common	sched_getattr		sys_sched_getattr
 316	common	renameat2		sys_renameat2
 316	common	renameat2		sys_renameat2
+317	common	seccomp			sys_seccomp
 
 
 #
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
 # x32-specific system call numbers start at 512 to avoid cache impact

+ 32 - 2
crypto/asymmetric_keys/Kconfig

@@ -22,7 +22,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
 
 
 config PUBLIC_KEY_ALGO_RSA
 config PUBLIC_KEY_ALGO_RSA
 	tristate "RSA public-key algorithm"
 	tristate "RSA public-key algorithm"
-	select MPILIB_EXTRA
 	select MPILIB
 	select MPILIB
 	help
 	help
 	  This option enables support for the RSA algorithm (PKCS#1, RFC3447).
 	  This option enables support for the RSA algorithm (PKCS#1, RFC3447).
@@ -33,8 +32,39 @@ config X509_CERTIFICATE_PARSER
 	select ASN1
 	select ASN1
 	select OID_REGISTRY
 	select OID_REGISTRY
 	help
 	help
-	  This option procides support for parsing X.509 format blobs for key
+	  This option provides support for parsing X.509 format blobs for key
 	  data and provides the ability to instantiate a crypto key from a
 	  data and provides the ability to instantiate a crypto key from a
 	  public key packet found inside the certificate.
 	  public key packet found inside the certificate.
 
 
+config PKCS7_MESSAGE_PARSER
+	tristate "PKCS#7 message parser"
+	depends on X509_CERTIFICATE_PARSER
+	select ASN1
+	select OID_REGISTRY
+	help
+	  This option provides support for parsing PKCS#7 format messages for
+	  signature data and provides the ability to verify the signature.
+
+config PKCS7_TEST_KEY
+	tristate "PKCS#7 testing key type"
+	depends on PKCS7_MESSAGE_PARSER
+	select SYSTEM_TRUSTED_KEYRING
+	help
+	  This option provides a type of key that can be loaded up from a
+	  PKCS#7 message - provided the message is signed by a trusted key.  If
+	  it is, the PKCS#7 wrapper is discarded and reading the key returns
+	  just the payload.  If it isn't, adding the key will fail with an
+	  error.
+
+	  This is intended for testing the PKCS#7 parser.
+
+config SIGNED_PE_FILE_VERIFICATION
+	bool "Support for PE file signature verification"
+	depends on PKCS7_MESSAGE_PARSER=y
+	select ASN1
+	select OID_REGISTRY
+	help
+	  This option provides support for verifying the signature(s) on a
+	  signed PE binary.
+
 endif # ASYMMETRIC_KEY_TYPE
 endif # ASYMMETRIC_KEY_TYPE

+ 37 - 0
crypto/asymmetric_keys/Makefile

@@ -25,3 +25,40 @@ $(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-asn1.c x509-asn1.h
 clean-files	+= x509_rsakey-asn1.c x509_rsakey-asn1.h
 clean-files	+= x509_rsakey-asn1.c x509_rsakey-asn1.h
+
+#
+# PKCS#7 message handling
+#
+obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
+pkcs7_message-y := \
+	pkcs7-asn1.o \
+	pkcs7_parser.o \
+	pkcs7_trust.o \
+	pkcs7_verify.o
+
+$(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
+$(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h
+
+clean-files	+= pkcs7-asn1.c pkcs7-asn1.h
+
+#
+# PKCS#7 parser testing key
+#
+obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o
+pkcs7_test_key-y := \
+	pkcs7_key_type.o
+
+#
+# Signed PE binary-wrapped key handling
+#
+obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o
+
+verify_signed_pefile-y := \
+	verify_pefile.o \
+	mscode_parser.o \
+	mscode-asn1.o
+
+$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h
+$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h
+
+clean-files	+= mscode-asn1.c mscode-asn1.h

+ 2 - 0
crypto/asymmetric_keys/asymmetric_keys.h

@@ -9,6 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  * 2 of the Licence, or (at your option) any later version.
  */
  */
 
 
+int asymmetric_keyid_match(const char *kid, const char *id);
+
 static inline const char *asymmetric_key_id(const struct key *key)
 static inline const char *asymmetric_key_id(const struct key *key)
 {
 {
 	return key->type_data.p[1];
 	return key->type_data.p[1];

+ 34 - 44
crypto/asymmetric_keys/asymmetric_type.c

@@ -22,6 +22,35 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(asymmetric_key_parsers);
 static LIST_HEAD(asymmetric_key_parsers);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 
 
+/*
+ * Match asymmetric key id with partial match
+ * @id:		key id to match in a form "id:<id>"
+ */
+int asymmetric_keyid_match(const char *kid, const char *id)
+{
+	size_t idlen, kidlen;
+
+	if (!kid || !id)
+		return 0;
+
+	/* make it possible to use id as in the request: "id:<id>" */
+	if (strncmp(id, "id:", 3) == 0)
+		id += 3;
+
+	/* Anything after here requires a partial match on the ID string */
+	idlen = strlen(id);
+	kidlen = strlen(kid);
+	if (idlen > kidlen)
+		return 0;
+
+	kid += kidlen - idlen;
+	if (strcasecmp(id, kid) != 0)
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
+
 /*
 /*
  * Match asymmetric keys on (part of) their name
  * Match asymmetric keys on (part of) their name
  * We have some shorthand methods for matching keys.  We allow:
  * We have some shorthand methods for matching keys.  We allow:
@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
 {
 {
 	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
 	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
 	const char *spec = description;
 	const char *spec = description;
-	const char *id, *kid;
+	const char *id;
 	ptrdiff_t speclen;
 	ptrdiff_t speclen;
-	size_t idlen, kidlen;
 
 
 	if (!subtype || !spec || !*spec)
 	if (!subtype || !spec || !*spec)
 		return 0;
 		return 0;
@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
 	speclen = id - spec;
 	speclen = id - spec;
 	id++;
 	id++;
 
 
-	/* Anything after here requires a partial match on the ID string */
-	kid = asymmetric_key_id(key);
-	if (!kid)
-		return 0;
-
-	idlen = strlen(id);
-	kidlen = strlen(kid);
-	if (idlen > kidlen)
-		return 0;
-
-	kid += kidlen - idlen;
-	if (strcasecmp(id, kid) != 0)
-		return 0;
-
-	if (speclen == 2 &&
-	    memcmp(spec, "id", 2) == 0)
-		return 1;
+	if (speclen == 2 && memcmp(spec, "id", 2) == 0)
+		return asymmetric_keyid_match(asymmetric_key_id(key), id);
 
 
 	if (speclen == subtype->name_len &&
 	if (speclen == subtype->name_len &&
 	    memcmp(spec, subtype->name, speclen) == 0)
 	    memcmp(spec, subtype->name, speclen) == 0)
@@ -156,36 +169,13 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 	pr_devel("==>%s()\n", __func__);
 	pr_devel("==>%s()\n", __func__);
 
 
 	if (subtype) {
 	if (subtype) {
-		subtype->destroy(prep->payload);
+		subtype->destroy(prep->payload[0]);
 		module_put(subtype->owner);
 		module_put(subtype->owner);
 	}
 	}
 	kfree(prep->type_data[1]);
 	kfree(prep->type_data[1]);
 	kfree(prep->description);
 	kfree(prep->description);
 }
 }
 
 
-/*
- * Instantiate a asymmetric_key defined key.  The key was preparsed, so we just
- * have to transfer the data here.
- */
-static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
-{
-	int ret;
-
-	pr_devel("==>%s()\n", __func__);
-
-	ret = key_payload_reserve(key, prep->quotalen);
-	if (ret == 0) {
-		key->type_data.p[0] = prep->type_data[0];
-		key->type_data.p[1] = prep->type_data[1];
-		key->payload.data = prep->payload;
-		prep->type_data[0] = NULL;
-		prep->type_data[1] = NULL;
-		prep->payload = NULL;
-	}
-	pr_devel("<==%s() = %d\n", __func__, ret);
-	return ret;
-}
-
 /*
 /*
  * dispose of the data dangling from the corpse of a asymmetric key
  * dispose of the data dangling from the corpse of a asymmetric key
  */
  */
@@ -205,7 +195,7 @@ struct key_type key_type_asymmetric = {
 	.name		= "asymmetric",
 	.name		= "asymmetric",
 	.preparse	= asymmetric_key_preparse,
 	.preparse	= asymmetric_key_preparse,
 	.free_preparse	= asymmetric_key_free_preparse,
 	.free_preparse	= asymmetric_key_free_preparse,
-	.instantiate	= asymmetric_key_instantiate,
+	.instantiate	= generic_key_instantiate,
 	.match		= asymmetric_key_match,
 	.match		= asymmetric_key_match,
 	.destroy	= asymmetric_key_destroy,
 	.destroy	= asymmetric_key_destroy,
 	.describe	= asymmetric_key_describe,
 	.describe	= asymmetric_key_describe,

+ 28 - 0
crypto/asymmetric_keys/mscode.asn1

@@ -0,0 +1,28 @@
+--- Microsoft individual code signing data blob parser
+---
+--- 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.
+---
+
+MSCode ::= SEQUENCE {
+	type			SEQUENCE {
+		contentType	ContentType,
+		parameters	ANY
+	},
+	content			SEQUENCE {
+		digestAlgorithm	DigestAlgorithmIdentifier,
+		digest		OCTET STRING ({ mscode_note_digest })
+	}
+}
+
+ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
+
+DigestAlgorithmIdentifier ::= SEQUENCE {
+	algorithm   OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
+	parameters  ANY OPTIONAL
+}

+ 126 - 0
crypto/asymmetric_keys/mscode_parser.c

@@ -0,0 +1,126 @@
+/* Parse a Microsoft Individual Code Signing blob
+ *
+ * Copyright (C) 2014 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) "MSCODE: "fmt
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#include <crypto/pkcs7.h>
+#include "verify_pefile.h"
+#include "mscode-asn1.h"
+
+/*
+ * Parse a Microsoft Individual Code Signing blob
+ */
+int mscode_parse(struct pefile_context *ctx)
+{
+	const void *content_data;
+	size_t data_len;
+	int ret;
+
+	ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
+
+	if (ret) {
+		pr_debug("PKCS#7 message does not contain data\n");
+		return ret;
+	}
+
+	pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
+		 content_data);
+
+	return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
+}
+
+/*
+ * Check the content type OID
+ */
+int mscode_note_content_type(void *context, size_t hdrlen,
+			     unsigned char tag,
+			     const void *value, size_t vlen)
+{
+	enum OID oid;
+
+	oid = look_up_OID(value, vlen);
+	if (oid == OID__NR) {
+		char buffer[50];
+
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_err("Unknown OID: %s\n", buffer);
+		return -EBADMSG;
+	}
+
+	/*
+	 * pesign utility had a bug where it was putting
+	 * OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
+	 * So allow both OIDs.
+	 */
+	if (oid != OID_msPeImageDataObjId &&
+	    oid != OID_msIndividualSPKeyPurpose) {
+		pr_err("Unexpected content type OID %u\n", oid);
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/*
+ * Note the digest algorithm OID
+ */
+int mscode_note_digest_algo(void *context, size_t hdrlen,
+			    unsigned char tag,
+			    const void *value, size_t vlen)
+{
+	struct pefile_context *ctx = context;
+	char buffer[50];
+	enum OID oid;
+
+	oid = look_up_OID(value, vlen);
+	switch (oid) {
+	case OID_md4:
+		ctx->digest_algo = HASH_ALGO_MD4;
+		break;
+	case OID_md5:
+		ctx->digest_algo = HASH_ALGO_MD5;
+		break;
+	case OID_sha1:
+		ctx->digest_algo = HASH_ALGO_SHA1;
+		break;
+	case OID_sha256:
+		ctx->digest_algo = HASH_ALGO_SHA256;
+		break;
+
+	case OID__NR:
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_err("Unknown OID: %s\n", buffer);
+		return -EBADMSG;
+
+	default:
+		pr_err("Unsupported content type: %u\n", oid);
+		return -ENOPKG;
+	}
+
+	return 0;
+}
+
+/*
+ * Note the digest we're guaranteeing with this certificate
+ */
+int mscode_note_digest(void *context, size_t hdrlen,
+		       unsigned char tag,
+		       const void *value, size_t vlen)
+{
+	struct pefile_context *ctx = context;
+
+	ctx->digest = value;
+	ctx->digest_len = vlen;
+	return 0;
+}

+ 127 - 0
crypto/asymmetric_keys/pkcs7.asn1

@@ -0,0 +1,127 @@
+PKCS7ContentInfo ::= SEQUENCE {
+	contentType	ContentType,
+	content		[0] EXPLICIT SignedData OPTIONAL
+}
+
+ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
+
+SignedData ::= SEQUENCE {
+	version			INTEGER,
+	digestAlgorithms	DigestAlgorithmIdentifiers,
+	contentInfo		ContentInfo,
+	certificates		CHOICE {
+		certSet		[0] IMPLICIT ExtendedCertificatesAndCertificates,
+		certSequence	[2] IMPLICIT Certificates
+	} OPTIONAL ({ pkcs7_note_certificate_list }),
+	crls CHOICE {
+		crlSet		[1] IMPLICIT CertificateRevocationLists,
+		crlSequence	[3] IMPLICIT CRLSequence
+	} OPTIONAL,
+	signerInfos		SignerInfos
+}
+
+ContentInfo ::= SEQUENCE {
+	contentType	ContentType,
+	content		[0] EXPLICIT Data OPTIONAL
+}
+
+Data ::= ANY ({ pkcs7_note_data })
+
+DigestAlgorithmIdentifiers ::= CHOICE {
+	daSet			SET OF DigestAlgorithmIdentifier,
+	daSequence		SEQUENCE OF DigestAlgorithmIdentifier
+}
+
+DigestAlgorithmIdentifier ::= SEQUENCE {
+	algorithm   OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+	parameters  ANY OPTIONAL
+}
+
+--
+-- Certificates and certificate lists
+--
+ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate
+
+ExtendedCertificateOrCertificate ::= CHOICE {
+  certificate		Certificate,				-- X.509
+  extendedCertificate	[0] IMPLICIT ExtendedCertificate	-- PKCS#6
+}
+
+ExtendedCertificate ::= Certificate -- cheating
+
+Certificates ::= SEQUENCE OF Certificate
+
+CertificateRevocationLists ::= SET OF CertificateList
+
+CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
+
+CRLSequence ::= SEQUENCE OF CertificateList
+
+Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509
+
+--
+-- Signer information
+--
+SignerInfos ::= CHOICE {
+	siSet		SET OF SignerInfo,
+	siSequence	SEQUENCE OF SignerInfo
+}
+
+SignerInfo ::= SEQUENCE {
+	version			INTEGER,
+	issuerAndSerialNumber	IssuerAndSerialNumber,
+	digestAlgorithm		DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
+	authenticatedAttributes	CHOICE {
+		aaSet		[0] IMPLICIT SetOfAuthenticatedAttribute
+					({ pkcs7_sig_note_set_of_authattrs }),
+		aaSequence	[2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
+			-- Explicit because easier to compute digest on
+			-- sequence of attributes and then reuse encoded
+			-- sequence in aaSequence.
+	} OPTIONAL,
+	digestEncryptionAlgorithm
+				DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }),
+	encryptedDigest		EncryptedDigest,
+	unauthenticatedAttributes CHOICE {
+		uaSet		[1] IMPLICIT SET OF UnauthenticatedAttribute,
+		uaSequence	[3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
+	} OPTIONAL
+} ({ pkcs7_note_signed_info })
+
+IssuerAndSerialNumber ::= SEQUENCE {
+	issuer			Name ({ pkcs7_sig_note_issuer }),
+	serialNumber		CertificateSerialNumber ({ pkcs7_sig_note_serial })
+}
+
+CertificateSerialNumber ::= INTEGER
+
+SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
+
+AuthenticatedAttribute ::= SEQUENCE {
+	type			OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+	values			SET OF ANY ({ pkcs7_sig_note_authenticated_attr })
+}
+
+UnauthenticatedAttribute ::= SEQUENCE {
+	type			OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+	values			SET OF ANY
+}
+
+DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
+	algorithm		OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+	parameters		ANY OPTIONAL
+}
+
+EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
+
+---
+--- X.500 Name
+---
+Name ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::= SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+	attributeType		OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+	attributeValue		ANY
+}

+ 100 - 0
crypto/asymmetric_keys/pkcs7_key_type.c

@@ -0,0 +1,100 @@
+/* Testing module to load key from trusted PKCS#7 message
+ *
+ * Copyright (C) 2014 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) "PKCS7key: "fmt
+#include <linux/key.h>
+#include <linux/err.h>
+#include <linux/key-type.h>
+#include <crypto/pkcs7.h>
+#include <keys/user-type.h>
+#include <keys/system_keyring.h>
+#include "pkcs7_parser.h"
+
+/*
+ * Preparse a PKCS#7 wrapped and validated data blob.
+ */
+static int pkcs7_preparse(struct key_preparsed_payload *prep)
+{
+	struct pkcs7_message *pkcs7;
+	const void *data, *saved_prep_data;
+	size_t datalen, saved_prep_datalen;
+	bool trusted;
+	int ret;
+
+	kenter("");
+
+	saved_prep_data = prep->data;
+	saved_prep_datalen = prep->datalen;
+	pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
+	if (IS_ERR(pkcs7)) {
+		ret = PTR_ERR(pkcs7);
+		goto error;
+	}
+
+	ret = pkcs7_verify(pkcs7);
+	if (ret < 0)
+		goto error_free;
+
+	ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
+	if (ret < 0)
+		goto error_free;
+	if (!trusted)
+		pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
+
+	ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
+	if (ret < 0)
+		goto error_free;
+
+	prep->data = data;
+	prep->datalen = datalen;
+	ret = user_preparse(prep);
+	prep->data = saved_prep_data;
+	prep->datalen = saved_prep_datalen;
+
+error_free:
+	pkcs7_free_message(pkcs7);
+error:
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * user defined keys take an arbitrary string as the description and an
+ * arbitrary blob of data as the payload
+ */
+static struct key_type key_type_pkcs7 = {
+	.name			= "pkcs7_test",
+	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
+	.preparse		= pkcs7_preparse,
+	.free_preparse		= user_free_preparse,
+	.instantiate		= generic_key_instantiate,
+	.match			= user_match,
+	.revoke			= user_revoke,
+	.destroy		= user_destroy,
+	.describe		= user_describe,
+	.read			= user_read,
+};
+
+/*
+ * Module stuff
+ */
+static int __init pkcs7_key_init(void)
+{
+	return register_key_type(&key_type_pkcs7);
+}
+
+static void __exit pkcs7_key_cleanup(void)
+{
+	unregister_key_type(&key_type_pkcs7);
+}
+
+module_init(pkcs7_key_init);
+module_exit(pkcs7_key_cleanup);

+ 396 - 0
crypto/asymmetric_keys/pkcs7_parser.c

@@ -0,0 +1,396 @@
+/* PKCS#7 parser
+ *
+ * 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) "PKCS7: "fmt
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#include "public_key.h"
+#include "pkcs7_parser.h"
+#include "pkcs7-asn1.h"
+
+struct pkcs7_parse_context {
+	struct pkcs7_message	*msg;		/* Message being constructed */
+	struct pkcs7_signed_info *sinfo;	/* SignedInfo being constructed */
+	struct pkcs7_signed_info **ppsinfo;
+	struct x509_certificate *certs;		/* Certificate cache */
+	struct x509_certificate **ppcerts;
+	unsigned long	data;			/* Start of data */
+	enum OID	last_oid;		/* Last OID encountered */
+	unsigned	x509_index;
+	unsigned	sinfo_index;
+};
+
+/**
+ * pkcs7_free_message - Free a PKCS#7 message
+ * @pkcs7: The PKCS#7 message to free
+ */
+void pkcs7_free_message(struct pkcs7_message *pkcs7)
+{
+	struct x509_certificate *cert;
+	struct pkcs7_signed_info *sinfo;
+
+	if (pkcs7) {
+		while (pkcs7->certs) {
+			cert = pkcs7->certs;
+			pkcs7->certs = cert->next;
+			x509_free_certificate(cert);
+		}
+		while (pkcs7->crl) {
+			cert = pkcs7->crl;
+			pkcs7->crl = cert->next;
+			x509_free_certificate(cert);
+		}
+		while (pkcs7->signed_infos) {
+			sinfo = pkcs7->signed_infos;
+			pkcs7->signed_infos = sinfo->next;
+			mpi_free(sinfo->sig.mpi[0]);
+			kfree(sinfo->sig.digest);
+			kfree(sinfo);
+		}
+		kfree(pkcs7);
+	}
+}
+EXPORT_SYMBOL_GPL(pkcs7_free_message);
+
+/**
+ * pkcs7_parse_message - Parse a PKCS#7 message
+ * @data: The raw binary ASN.1 encoded message to be parsed
+ * @datalen: The size of the encoded message
+ */
+struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
+{
+	struct pkcs7_parse_context *ctx;
+	struct pkcs7_message *msg;
+	long ret;
+
+	ret = -ENOMEM;
+	msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
+	if (!msg)
+		goto error_no_sig;
+	ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
+	if (!ctx)
+		goto error_no_ctx;
+	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
+	if (!ctx->sinfo)
+		goto error_no_sinfo;
+
+	ctx->msg = msg;
+	ctx->data = (unsigned long)data;
+	ctx->ppcerts = &ctx->certs;
+	ctx->ppsinfo = &ctx->msg->signed_infos;
+
+	/* Attempt to decode the signature */
+	ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
+	if (ret < 0)
+		goto error_decode;
+
+	while (ctx->certs) {
+		struct x509_certificate *cert = ctx->certs;
+		ctx->certs = cert->next;
+		x509_free_certificate(cert);
+	}
+	mpi_free(ctx->sinfo->sig.mpi[0]);
+	kfree(ctx->sinfo->sig.digest);
+	kfree(ctx->sinfo);
+	kfree(ctx);
+	return msg;
+
+error_decode:
+	mpi_free(ctx->sinfo->sig.mpi[0]);
+	kfree(ctx->sinfo->sig.digest);
+	kfree(ctx->sinfo);
+error_no_sinfo:
+	kfree(ctx);
+error_no_ctx:
+	pkcs7_free_message(msg);
+error_no_sig:
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(pkcs7_parse_message);
+
+/**
+ * pkcs7_get_content_data - Get access to the PKCS#7 content
+ * @pkcs7: The preparsed PKCS#7 message to access
+ * @_data: Place to return a pointer to the data
+ * @_data_len: Place to return the data length
+ * @want_wrapper: True if the ASN.1 object header should be included in the data
+ *
+ * Get access to the data content of the PKCS#7 message, including, optionally,
+ * the header of the ASN.1 object that contains it.  Returns -ENODATA if the
+ * data object was missing from the message.
+ */
+int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
+			   const void **_data, size_t *_data_len,
+			   bool want_wrapper)
+{
+	size_t wrapper;
+
+	if (!pkcs7->data)
+		return -ENODATA;
+
+	wrapper = want_wrapper ? pkcs7->data_hdrlen : 0;
+	*_data = pkcs7->data - wrapper;
+	*_data_len = pkcs7->data_len + wrapper;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
+
+/*
+ * Note an OID when we find one for later processing when we know how
+ * to interpret it.
+ */
+int pkcs7_note_OID(void *context, size_t hdrlen,
+		   unsigned char tag,
+		   const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	ctx->last_oid = look_up_OID(value, vlen);
+	if (ctx->last_oid == OID__NR) {
+		char buffer[50];
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		printk("PKCS7: Unknown OID: [%lu] %s\n",
+		       (unsigned long)value - ctx->data, buffer);
+	}
+	return 0;
+}
+
+/*
+ * Note the digest algorithm for the signature.
+ */
+int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
+			       unsigned char tag,
+			       const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	switch (ctx->last_oid) {
+	case OID_md4:
+		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
+		break;
+	case OID_md5:
+		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
+		break;
+	case OID_sha1:
+		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
+		break;
+	case OID_sha256:
+		ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
+		break;
+	default:
+		printk("Unsupported digest algo: %u\n", ctx->last_oid);
+		return -ENOPKG;
+	}
+	return 0;
+}
+
+/*
+ * Note the public key algorithm for the signature.
+ */
+int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
+			     unsigned char tag,
+			     const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	switch (ctx->last_oid) {
+	case OID_rsaEncryption:
+		ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
+		break;
+	default:
+		printk("Unsupported pkey algo: %u\n", ctx->last_oid);
+		return -ENOPKG;
+	}
+	return 0;
+}
+
+/*
+ * Extract a certificate and store it in the context.
+ */
+int pkcs7_extract_cert(void *context, size_t hdrlen,
+		       unsigned char tag,
+		       const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+	struct x509_certificate *x509;
+
+	if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
+		pr_debug("Cert began with tag %02x at %lu\n",
+			 tag, (unsigned long)ctx - ctx->data);
+		return -EBADMSG;
+	}
+
+	/* We have to correct for the header so that the X.509 parser can start
+	 * from the beginning.  Note that since X.509 stipulates DER, there
+	 * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
+	 * stipulates BER).
+	 */
+	value -= hdrlen;
+	vlen += hdrlen;
+
+	if (((u8*)value)[1] == 0x80)
+		vlen += 2; /* Indefinite length - there should be an EOC */
+
+	x509 = x509_cert_parse(value, vlen);
+	if (IS_ERR(x509))
+		return PTR_ERR(x509);
+
+	pr_debug("Got cert for %s\n", x509->subject);
+	pr_debug("- fingerprint %s\n", x509->fingerprint);
+
+	x509->index = ++ctx->x509_index;
+	*ctx->ppcerts = x509;
+	ctx->ppcerts = &x509->next;
+	return 0;
+}
+
+/*
+ * Save the certificate list
+ */
+int pkcs7_note_certificate_list(void *context, size_t hdrlen,
+				unsigned char tag,
+				const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	pr_devel("Got cert list (%02x)\n", tag);
+
+	*ctx->ppcerts = ctx->msg->certs;
+	ctx->msg->certs = ctx->certs;
+	ctx->certs = NULL;
+	ctx->ppcerts = &ctx->certs;
+	return 0;
+}
+
+/*
+ * Extract the data from the message and store that and its content type OID in
+ * the context.
+ */
+int pkcs7_note_data(void *context, size_t hdrlen,
+		    unsigned char tag,
+		    const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	pr_debug("Got data\n");
+
+	ctx->msg->data = value;
+	ctx->msg->data_len = vlen;
+	ctx->msg->data_hdrlen = hdrlen;
+	ctx->msg->data_type = ctx->last_oid;
+	return 0;
+}
+
+/*
+ * Parse authenticated attributes
+ */
+int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
+				      unsigned char tag,
+				      const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
+
+	switch (ctx->last_oid) {
+	case OID_messageDigest:
+		if (tag != ASN1_OTS)
+			return -EBADMSG;
+		ctx->sinfo->msgdigest = value;
+		ctx->sinfo->msgdigest_len = vlen;
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Note the set of auth attributes for digestion purposes [RFC2315 9.3]
+ */
+int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
+				    unsigned char tag,
+				    const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
+	ctx->sinfo->authattrs = value - (hdrlen - 1);
+	ctx->sinfo->authattrs_len = vlen + (hdrlen - 1);
+	return 0;
+}
+
+/*
+ * Note the issuing certificate serial number
+ */
+int pkcs7_sig_note_serial(void *context, size_t hdrlen,
+			  unsigned char tag,
+			  const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+	ctx->sinfo->raw_serial = value;
+	ctx->sinfo->raw_serial_size = vlen;
+	return 0;
+}
+
+/*
+ * Note the issuer's name
+ */
+int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
+			  unsigned char tag,
+			  const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+	ctx->sinfo->raw_issuer = value;
+	ctx->sinfo->raw_issuer_size = vlen;
+	return 0;
+}
+
+/*
+ * Note the signature data
+ */
+int pkcs7_sig_note_signature(void *context, size_t hdrlen,
+			     unsigned char tag,
+			     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)
+		return -ENOMEM;
+
+	ctx->sinfo->sig.mpi[0] = mpi;
+	ctx->sinfo->sig.nr_mpi = 1;
+	return 0;
+}
+
+/*
+ * Note a signature information block
+ */
+int pkcs7_note_signed_info(void *context, size_t hdrlen,
+			   unsigned char tag,
+			   const void *value, size_t vlen)
+{
+	struct pkcs7_parse_context *ctx = context;
+
+	ctx->sinfo->index = ++ctx->sinfo_index;
+	*ctx->ppsinfo = ctx->sinfo;
+	ctx->ppsinfo = &ctx->sinfo->next;
+	ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
+	if (!ctx->sinfo)
+		return -ENOMEM;
+	return 0;
+}

+ 61 - 0
crypto/asymmetric_keys/pkcs7_parser.h

@@ -0,0 +1,61 @@
+/* PKCS#7 crypto data parser internal definitions
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/oid_registry.h>
+#include <crypto/pkcs7.h>
+#include "x509_parser.h"
+
+#define kenter(FMT, ...) \
+	pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+	pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+
+struct pkcs7_signed_info {
+	struct pkcs7_signed_info *next;
+	struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
+	unsigned index;
+	bool trusted;
+
+	/* Message digest - the digest of the Content Data (or NULL) */
+	const void	*msgdigest;
+	unsigned	msgdigest_len;
+
+	/* Authenticated Attribute data (or NULL) */
+	unsigned	authattrs_len;
+	const void	*authattrs;
+
+	/* Issuing cert serial number and issuer's name */
+	const void	*raw_serial;
+	unsigned	raw_serial_size;
+	unsigned	raw_issuer_size;
+	const void	*raw_issuer;
+
+	/* Message signature.
+	 *
+	 * This contains the generated digest of _either_ the Content Data or
+	 * the Authenticated Attributes [RFC2315 9.3].  If the latter, one of
+	 * the attributes contains the digest of the the Content Data within
+	 * it.
+	 */
+	struct public_key_signature sig;
+};
+
+struct pkcs7_message {
+	struct x509_certificate *certs;	/* Certificate list */
+	struct x509_certificate *crl;	/* Revocation list */
+	struct pkcs7_signed_info *signed_infos;
+
+	/* Content Data (or NULL) */
+	enum OID	data_type;	/* Type of Data */
+	size_t		data_len;	/* Length of Data */
+	size_t		data_hdrlen;	/* Length of Data ASN.1 header */
+	const void	*data;		/* Content Data (or 0) */
+};

+ 166 - 0
crypto/asymmetric_keys/pkcs7_trust.c

@@ -0,0 +1,166 @@
+/* Validate the trust chain of a PKCS#7 message.
+ *
+ * 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) "PKCS7: "fmt
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/asn1.h>
+#include <linux/key.h>
+#include <keys/asymmetric-type.h>
+#include "public_key.h"
+#include "pkcs7_parser.h"
+
+/**
+ * Check the trust on one PKCS#7 SignedInfo block.
+ */
+int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
+			     struct pkcs7_signed_info *sinfo,
+			     struct key *trust_keyring)
+{
+	struct public_key_signature *sig = &sinfo->sig;
+	struct x509_certificate *x509, *last = NULL, *p;
+	struct key *key;
+	bool trusted;
+	int ret;
+
+	kenter(",%u,", sinfo->index);
+
+	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
+		if (x509->seen) {
+			if (x509->verified) {
+				trusted = x509->trusted;
+				goto verified;
+			}
+			kleave(" = -ENOKEY [cached]");
+			return -ENOKEY;
+		}
+		x509->seen = true;
+
+		/* Look to see if this certificate is present in the trusted
+		 * keys.
+		 */
+		key = x509_request_asymmetric_key(trust_keyring, x509->subject,
+						  x509->fingerprint);
+		if (!IS_ERR(key))
+			/* One of the X.509 certificates in the PKCS#7 message
+			 * is apparently the same as one we already trust.
+			 * Verify that the trusted variant can also validate
+			 * the signature on the descendant.
+			 */
+			goto matched;
+		if (key == ERR_PTR(-ENOMEM))
+			return -ENOMEM;
+
+		 /* Self-signed certificates form roots of their own, and if we
+		  * don't know them, then we can't accept them.
+		  */
+		if (x509->next == x509) {
+			kleave(" = -ENOKEY [unknown self-signed]");
+			return -ENOKEY;
+		}
+
+		might_sleep();
+		last = x509;
+		sig = &last->sig;
+	}
+
+	/* No match - see if the root certificate has a signer amongst the
+	 * trusted keys.
+	 */
+	if (!last || !last->issuer || !last->authority) {
+		kleave(" = -ENOKEY [no backref]");
+		return -ENOKEY;
+	}
+
+	key = x509_request_asymmetric_key(trust_keyring, last->issuer,
+					  last->authority);
+	if (IS_ERR(key))
+		return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
+	x509 = last;
+
+matched:
+	ret = verify_signature(key, sig);
+	trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
+	key_put(key);
+	if (ret < 0) {
+		if (ret == -ENOMEM)
+			return ret;
+		kleave(" = -EKEYREJECTED [verify %d]", ret);
+		return -EKEYREJECTED;
+	}
+
+verified:
+	x509->verified = true;
+	for (p = sinfo->signer; p != x509; p = p->signer) {
+		p->verified = true;
+		p->trusted = trusted;
+	}
+	sinfo->trusted = trusted;
+	kleave(" = 0");
+	return 0;
+}
+
+/**
+ * pkcs7_validate_trust - Validate PKCS#7 trust chain
+ * @pkcs7: The PKCS#7 certificate to validate
+ * @trust_keyring: Signing certificates to use as starting points
+ * @_trusted: Set to true if trustworth, false otherwise
+ *
+ * Validate that the certificate chain inside the PKCS#7 message intersects
+ * keys we already know and trust.
+ *
+ * Returns, in order of descending priority:
+ *
+ *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
+ *	key, or:
+ *
+ *  (*) 0 if at least one signature chain intersects with the keys in the trust
+ *	keyring, or:
+ *
+ *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
+ *	chain.
+ *
+ *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
+ *	the message.
+ *
+ * May also return -ENOMEM.
+ */
+int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
+			 struct key *trust_keyring,
+			 bool *_trusted)
+{
+	struct pkcs7_signed_info *sinfo;
+	struct x509_certificate *p;
+	int cached_ret = 0, ret;
+
+	for (p = pkcs7->certs; p; p = p->next)
+		p->seen = false;
+
+	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
+		ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
+		if (ret < 0) {
+			if (ret == -ENOPKG) {
+				cached_ret = -ENOPKG;
+			} else if (ret == -ENOKEY) {
+				if (cached_ret == 0)
+					cached_ret = -ENOKEY;
+			} else {
+				return ret;
+			}
+		}
+		*_trusted |= sinfo->trusted;
+	}
+
+	return cached_ret;
+}
+EXPORT_SYMBOL_GPL(pkcs7_validate_trust);

+ 321 - 0
crypto/asymmetric_keys/pkcs7_verify.c

@@ -0,0 +1,321 @@
+/* Verify the signature on a PKCS#7 message.
+ *
+ * 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) "PKCS7: "fmt
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/asn1.h>
+#include <crypto/hash.h>
+#include "public_key.h"
+#include "pkcs7_parser.h"
+
+/*
+ * Digest the relevant parts of the PKCS#7 data
+ */
+static int pkcs7_digest(struct pkcs7_message *pkcs7,
+			struct pkcs7_signed_info *sinfo)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	size_t digest_size, desc_size;
+	void *digest;
+	int ret;
+
+	kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
+
+	if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
+	    !hash_algo_name[sinfo->sig.pkey_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);
+	if (IS_ERR(tfm))
+		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
+
+	ret = -ENOMEM;
+	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+	if (!digest)
+		goto error_no_desc;
+
+	desc = digest + digest_size;
+	desc->tfm   = tfm;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	/* Digest the message [RFC2315 9.3] */
+	ret = crypto_shash_init(desc);
+	if (ret < 0)
+		goto error;
+	ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
+	if (ret < 0)
+		goto error;
+	pr_devel("MsgDigest = [%*ph]\n", 8, digest);
+
+	/* However, if there are authenticated attributes, there must be a
+	 * message digest attribute amongst them which corresponds to the
+	 * digest we just calculated.
+	 */
+	if (sinfo->msgdigest) {
+		u8 tag;
+
+		if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
+			pr_debug("Sig %u: Invalid digest size (%u)\n",
+				 sinfo->index, sinfo->msgdigest_len);
+			ret = -EBADMSG;
+			goto error;
+		}
+
+		if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
+			pr_debug("Sig %u: Message digest doesn't match\n",
+				 sinfo->index);
+			ret = -EKEYREJECTED;
+			goto error;
+		}
+
+		/* We then calculate anew, using the authenticated attributes
+		 * as the contents of the digest instead.  Note that we need to
+		 * convert the attributes from a CONT.0 into a SET before we
+		 * hash it.
+		 */
+		memset(digest, 0, sinfo->sig.digest_size);
+
+		ret = crypto_shash_init(desc);
+		if (ret < 0)
+			goto error;
+		tag = ASN1_CONS_BIT | ASN1_SET;
+		ret = crypto_shash_update(desc, &tag, 1);
+		if (ret < 0)
+			goto error;
+		ret = crypto_shash_finup(desc, sinfo->authattrs,
+					 sinfo->authattrs_len, digest);
+		if (ret < 0)
+			goto error;
+		pr_devel("AADigest = [%*ph]\n", 8, digest);
+	}
+
+	sinfo->sig.digest = digest;
+	digest = NULL;
+
+error:
+	kfree(digest);
+error_no_desc:
+	crypto_free_shash(tfm);
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/*
+ * Find the key (X.509 certificate) to use to verify a PKCS#7 message.  PKCS#7
+ * uses the issuer's name and the issuing certificate serial number for
+ * matching purposes.  These must match the certificate issuer's name (not
+ * subject's name) and the certificate serial number [RFC 2315 6.7].
+ */
+static int pkcs7_find_key(struct pkcs7_message *pkcs7,
+			  struct pkcs7_signed_info *sinfo)
+{
+	struct x509_certificate *x509;
+	unsigned certix = 1;
+
+	kenter("%u,%u,%u",
+	       sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
+
+	for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
+		/* I'm _assuming_ that the generator of the PKCS#7 message will
+		 * encode the fields from the X.509 cert in the same way in the
+		 * PKCS#7 message - but I can't be 100% sure of that.  It's
+		 * possible this will need element-by-element comparison.
+		 */
+		if (x509->raw_serial_size != sinfo->raw_serial_size ||
+		    memcmp(x509->raw_serial, sinfo->raw_serial,
+			   sinfo->raw_serial_size) != 0)
+			continue;
+		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
+			 sinfo->index, certix);
+
+		if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
+		    memcmp(x509->raw_issuer, sinfo->raw_issuer,
+			   sinfo->raw_issuer_size) != 0) {
+			pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
+				sinfo->index);
+			continue;
+		}
+
+		if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
+			pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
+				sinfo->index);
+			continue;
+		}
+
+		sinfo->signer = x509;
+		return 0;
+	}
+	pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
+		sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
+	return -ENOKEY;
+}
+
+/*
+ * Verify the internal certificate chain as best we can.
+ */
+static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
+				  struct pkcs7_signed_info *sinfo)
+{
+	struct x509_certificate *x509 = sinfo->signer, *p;
+	int ret;
+
+	kenter("");
+
+	for (p = pkcs7->certs; p; p = p->next)
+		p->seen = false;
+
+	for (;;) {
+		pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
+		x509->seen = true;
+		ret = x509_get_sig_params(x509);
+		if (ret < 0)
+			return ret;
+
+		pr_debug("- issuer %s\n", x509->issuer);
+		if (x509->authority)
+			pr_debug("- authkeyid %s\n", x509->authority);
+
+		if (!x509->authority ||
+		    strcmp(x509->subject, x509->issuer) == 0) {
+			/* If there's no authority certificate specified, then
+			 * the certificate must be self-signed and is the root
+			 * of the chain.  Likewise if the cert is its own
+			 * authority.
+			 */
+			pr_debug("- no auth?\n");
+			if (x509->raw_subject_size != x509->raw_issuer_size ||
+			    memcmp(x509->raw_subject, x509->raw_issuer,
+				   x509->raw_issuer_size) != 0)
+				return 0;
+
+			ret = x509_check_signature(x509->pub, x509);
+			if (ret < 0)
+				return ret;
+			x509->signer = x509;
+			pr_debug("- self-signed\n");
+			return 0;
+		}
+
+		/* Look through the X.509 certificates in the PKCS#7 message's
+		 * list to see if the next one is there.
+		 */
+		pr_debug("- want %s\n", x509->authority);
+		for (p = pkcs7->certs; p; p = p->next) {
+			pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
+			if (p->raw_subject_size == x509->raw_issuer_size &&
+			    strcmp(p->fingerprint, x509->authority) == 0 &&
+			    memcmp(p->raw_subject, x509->raw_issuer,
+				   x509->raw_issuer_size) == 0)
+				goto found_issuer;
+		}
+
+		/* We didn't find the root of this chain */
+		pr_debug("- top\n");
+		return 0;
+
+	found_issuer:
+		pr_debug("- issuer %s\n", p->subject);
+		if (p->seen) {
+			pr_warn("Sig %u: X.509 chain contains loop\n",
+				sinfo->index);
+			return 0;
+		}
+		ret = x509_check_signature(p->pub, x509);
+		if (ret < 0)
+			return ret;
+		x509->signer = p;
+		if (x509 == p) {
+			pr_debug("- self-signed\n");
+			return 0;
+		}
+		x509 = p;
+		might_sleep();
+	}
+}
+
+/*
+ * Verify one signed information block from a PKCS#7 message.
+ */
+static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
+			    struct pkcs7_signed_info *sinfo)
+{
+	int ret;
+
+	kenter(",%u", sinfo->index);
+
+	/* First of all, digest the data in the PKCS#7 message and the
+	 * signed information block
+	 */
+	ret = pkcs7_digest(pkcs7, sinfo);
+	if (ret < 0)
+		return ret;
+
+	/* Find the key for the signature */
+	ret = pkcs7_find_key(pkcs7, sinfo);
+	if (ret < 0)
+		return ret;
+
+	pr_devel("Using X.509[%u] for sig %u\n",
+		 sinfo->signer->index, sinfo->index);
+
+	/* Verify the PKCS#7 binary against the key */
+	ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
+	if (ret < 0)
+		return ret;
+
+	pr_devel("Verified signature %u\n", sinfo->index);
+
+	/* Verify the internal certificate chain */
+	return pkcs7_verify_sig_chain(pkcs7, sinfo);
+}
+
+/**
+ * pkcs7_verify - Verify a PKCS#7 message
+ * @pkcs7: The PKCS#7 message to be verified
+ */
+int pkcs7_verify(struct pkcs7_message *pkcs7)
+{
+	struct pkcs7_signed_info *sinfo;
+	struct x509_certificate *x509;
+	int ret, n;
+
+	kenter("");
+
+	for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
+		ret = x509_get_sig_params(x509);
+		if (ret < 0)
+			return ret;
+		pr_debug("X.509[%u] %s\n", n, x509->authority);
+	}
+
+	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
+		ret = pkcs7_verify_one(pkcs7, sinfo);
+		if (ret < 0) {
+			kleave(" = %d", ret);
+			return ret;
+		}
+	}
+
+	kleave(" = 0");
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pkcs7_verify);

+ 457 - 0
crypto/asymmetric_keys/verify_pefile.c

@@ -0,0 +1,457 @@
+/* Parse a signed PE binary
+ *
+ * Copyright (C) 2014 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) "PEFILE: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/pe.h>
+#include <linux/asn1.h>
+#include <crypto/pkcs7.h>
+#include <crypto/hash.h>
+#include "verify_pefile.h"
+
+/*
+ * Parse a PE binary.
+ */
+static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
+			       struct pefile_context *ctx)
+{
+	const struct mz_hdr *mz = pebuf;
+	const struct pe_hdr *pe;
+	const struct pe32_opt_hdr *pe32;
+	const struct pe32plus_opt_hdr *pe64;
+	const struct data_directory *ddir;
+	const struct data_dirent *dde;
+	const struct section_header *secs, *sec;
+	size_t cursor, datalen = pelen;
+
+	kenter("");
+
+#define chkaddr(base, x, s)						\
+	do {								\
+		if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
+			return -ELIBBAD;				\
+	} while (0)
+
+	chkaddr(0, 0, sizeof(*mz));
+	if (mz->magic != MZ_MAGIC)
+		return -ELIBBAD;
+	cursor = sizeof(*mz);
+
+	chkaddr(cursor, mz->peaddr, sizeof(*pe));
+	pe = pebuf + mz->peaddr;
+	if (pe->magic != PE_MAGIC)
+		return -ELIBBAD;
+	cursor = mz->peaddr + sizeof(*pe);
+
+	chkaddr(0, cursor, sizeof(pe32->magic));
+	pe32 = pebuf + cursor;
+	pe64 = pebuf + cursor;
+
+	switch (pe32->magic) {
+	case PE_OPT_MAGIC_PE32:
+		chkaddr(0, cursor, sizeof(*pe32));
+		ctx->image_checksum_offset =
+			(unsigned long)&pe32->csum - (unsigned long)pebuf;
+		ctx->header_size = pe32->header_size;
+		cursor += sizeof(*pe32);
+		ctx->n_data_dirents = pe32->data_dirs;
+		break;
+
+	case PE_OPT_MAGIC_PE32PLUS:
+		chkaddr(0, cursor, sizeof(*pe64));
+		ctx->image_checksum_offset =
+			(unsigned long)&pe64->csum - (unsigned long)pebuf;
+		ctx->header_size = pe64->header_size;
+		cursor += sizeof(*pe64);
+		ctx->n_data_dirents = pe64->data_dirs;
+		break;
+
+	default:
+		pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
+		return -ELIBBAD;
+	}
+
+	pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
+	pr_debug("header size = %x\n", ctx->header_size);
+
+	if (cursor >= ctx->header_size || ctx->header_size >= datalen)
+		return -ELIBBAD;
+
+	if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
+		return -ELIBBAD;
+
+	ddir = pebuf + cursor;
+	cursor += sizeof(*dde) * ctx->n_data_dirents;
+
+	ctx->cert_dirent_offset =
+		(unsigned long)&ddir->certs - (unsigned long)pebuf;
+	ctx->certs_size = ddir->certs.size;
+
+	if (!ddir->certs.virtual_address || !ddir->certs.size) {
+		pr_debug("Unsigned PE binary\n");
+		return -EKEYREJECTED;
+	}
+
+	chkaddr(ctx->header_size, ddir->certs.virtual_address,
+		ddir->certs.size);
+	ctx->sig_offset = ddir->certs.virtual_address;
+	ctx->sig_len = ddir->certs.size;
+	pr_debug("cert = %x @%x [%*ph]\n",
+		 ctx->sig_len, ctx->sig_offset,
+		 ctx->sig_len, pebuf + ctx->sig_offset);
+
+	ctx->n_sections = pe->sections;
+	if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
+		return -ELIBBAD;
+	ctx->secs = secs = pebuf + cursor;
+
+	return 0;
+}
+
+/*
+ * Check and strip the PE wrapper from around the signature and check that the
+ * remnant looks something like PKCS#7.
+ */
+static int pefile_strip_sig_wrapper(const void *pebuf,
+				    struct pefile_context *ctx)
+{
+	struct win_certificate wrapper;
+	const u8 *pkcs7;
+
+	if (ctx->sig_len < sizeof(wrapper)) {
+		pr_debug("Signature wrapper too short\n");
+		return -ELIBBAD;
+	}
+
+	memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
+	pr_debug("sig wrapper = { %x, %x, %x }\n",
+		 wrapper.length, wrapper.revision, wrapper.cert_type);
+
+	/* Both pesign and sbsign round up the length of certificate table
+	 * (in optional header data directories) to 8 byte alignment.
+	 */
+	if (round_up(wrapper.length, 8) != ctx->sig_len) {
+		pr_debug("Signature wrapper len wrong\n");
+		return -ELIBBAD;
+	}
+	if (wrapper.revision != WIN_CERT_REVISION_2_0) {
+		pr_debug("Signature is not revision 2.0\n");
+		return -ENOTSUPP;
+	}
+	if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+		pr_debug("Signature certificate type is not PKCS\n");
+		return -ENOTSUPP;
+	}
+
+	/* Looks like actual pkcs signature length is in wrapper->length.
+	 * size obtained from data dir entries lists the total size of
+	 * certificate table which is also aligned to octawrod boundary.
+	 *
+	 * So set signature length field appropriately.
+	 */
+	ctx->sig_len = wrapper.length;
+	ctx->sig_offset += sizeof(wrapper);
+	ctx->sig_len -= sizeof(wrapper);
+	if (ctx->sig_len == 0) {
+		pr_debug("Signature data missing\n");
+		return -EKEYREJECTED;
+	}
+
+	/* What's left should a PKCS#7 cert */
+	pkcs7 = pebuf + ctx->sig_offset;
+	if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
+		if (pkcs7[1] == 0x82 &&
+		    pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
+		    pkcs7[3] ==  ((ctx->sig_len - 4)       & 0xff))
+			return 0;
+		if (pkcs7[1] == 0x80)
+			return 0;
+		if (pkcs7[1] > 0x82)
+			return -EMSGSIZE;
+	}
+
+	pr_debug("Signature data not PKCS#7\n");
+	return -ELIBBAD;
+}
+
+/*
+ * Compare two sections for canonicalisation.
+ */
+static int pefile_compare_shdrs(const void *a, const void *b)
+{
+	const struct section_header *shdra = a;
+	const struct section_header *shdrb = b;
+	int rc;
+
+	if (shdra->data_addr > shdrb->data_addr)
+		return 1;
+	if (shdrb->data_addr > shdra->data_addr)
+		return -1;
+
+	if (shdra->virtual_address > shdrb->virtual_address)
+		return 1;
+	if (shdrb->virtual_address > shdra->virtual_address)
+		return -1;
+
+	rc = strcmp(shdra->name, shdrb->name);
+	if (rc != 0)
+		return rc;
+
+	if (shdra->virtual_size > shdrb->virtual_size)
+		return 1;
+	if (shdrb->virtual_size > shdra->virtual_size)
+		return -1;
+
+	if (shdra->raw_data_size > shdrb->raw_data_size)
+		return 1;
+	if (shdrb->raw_data_size > shdra->raw_data_size)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Load the contents of the PE binary into the digest, leaving out the image
+ * checksum and the certificate data block.
+ */
+static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
+				     struct pefile_context *ctx,
+				     struct shash_desc *desc)
+{
+	unsigned *canon, tmp, loop, i, hashed_bytes;
+	int ret;
+
+	/* Digest the header and data directory, but leave out the image
+	 * checksum and the data dirent for the signature.
+	 */
+	ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
+	if (ret < 0)
+		return ret;
+
+	tmp = ctx->image_checksum_offset + sizeof(uint32_t);
+	ret = crypto_shash_update(desc, pebuf + tmp,
+				  ctx->cert_dirent_offset - tmp);
+	if (ret < 0)
+		return ret;
+
+	tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
+	ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
+	if (ret < 0)
+		return ret;
+
+	canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
+	if (!canon)
+		return -ENOMEM;
+
+	/* We have to canonicalise the section table, so we perform an
+	 * insertion sort.
+	 */
+	canon[0] = 0;
+	for (loop = 1; loop < ctx->n_sections; loop++) {
+		for (i = 0; i < loop; i++) {
+			if (pefile_compare_shdrs(&ctx->secs[canon[i]],
+						 &ctx->secs[loop]) > 0) {
+				memmove(&canon[i + 1], &canon[i],
+					(loop - i) * sizeof(canon[0]));
+				break;
+			}
+		}
+		canon[i] = loop;
+	}
+
+	hashed_bytes = ctx->header_size;
+	for (loop = 0; loop < ctx->n_sections; loop++) {
+		i = canon[loop];
+		if (ctx->secs[i].raw_data_size == 0)
+			continue;
+		ret = crypto_shash_update(desc,
+					  pebuf + ctx->secs[i].data_addr,
+					  ctx->secs[i].raw_data_size);
+		if (ret < 0) {
+			kfree(canon);
+			return ret;
+		}
+		hashed_bytes += ctx->secs[i].raw_data_size;
+	}
+	kfree(canon);
+
+	if (pelen > hashed_bytes) {
+		tmp = hashed_bytes + ctx->certs_size;
+		ret = crypto_shash_update(desc,
+					  pebuf + hashed_bytes,
+					  pelen - tmp);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Digest the contents of the PE binary, leaving out the image checksum and the
+ * certificate data block.
+ */
+static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
+			    struct pefile_context *ctx)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	size_t digest_size, desc_size;
+	void *digest;
+	int ret;
+
+	kenter(",%u", 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);
+	if (IS_ERR(tfm))
+		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	digest_size = crypto_shash_digestsize(tfm);
+
+	if (digest_size != ctx->digest_len) {
+		pr_debug("Digest size mismatch (%zx != %x)\n",
+			 digest_size, ctx->digest_len);
+		ret = -EBADMSG;
+		goto error_no_desc;
+	}
+	pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
+
+	ret = -ENOMEM;
+	desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
+	if (!desc)
+		goto error_no_desc;
+
+	desc->tfm   = tfm;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = crypto_shash_init(desc);
+	if (ret < 0)
+		goto error;
+
+	ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
+	if (ret < 0)
+		goto error;
+
+	digest = (void *)desc + desc_size;
+	ret = crypto_shash_final(desc, digest);
+	if (ret < 0)
+		goto error;
+
+	pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
+
+	/* Check that the PE file digest matches that in the MSCODE part of the
+	 * PKCS#7 certificate.
+	 */
+	if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
+		pr_debug("Digest mismatch\n");
+		ret = -EKEYREJECTED;
+	} else {
+		pr_debug("The digests match!\n");
+	}
+
+error:
+	kfree(desc);
+error_no_desc:
+	crypto_free_shash(tfm);
+	kleave(" = %d", ret);
+	return ret;
+}
+
+/**
+ * verify_pefile_signature - Verify the signature on a PE binary image
+ * @pebuf: Buffer containing the PE binary image
+ * @pelen: Length of the binary image
+ * @trust_keyring: Signing certificates to use as starting points
+ * @_trusted: Set to true if trustworth, false otherwise
+ *
+ * Validate that the certificate chain inside the PKCS#7 message inside the PE
+ * binary image intersects keys we already know and trust.
+ *
+ * Returns, in order of descending priority:
+ *
+ *  (*) -ELIBBAD if the image cannot be parsed, or:
+ *
+ *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
+ *	key, or:
+ *
+ *  (*) 0 if at least one signature chain intersects with the keys in the trust
+ *	keyring, or:
+ *
+ *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
+ *	chain.
+ *
+ *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
+ *	the message.
+ *
+ * May also return -ENOMEM.
+ */
+int verify_pefile_signature(const void *pebuf, unsigned pelen,
+			    struct key *trusted_keyring, bool *_trusted)
+{
+	struct pkcs7_message *pkcs7;
+	struct pefile_context ctx;
+	const void *data;
+	size_t datalen;
+	int ret;
+
+	kenter("");
+
+	memset(&ctx, 0, sizeof(ctx));
+	ret = pefile_parse_binary(pebuf, pelen, &ctx);
+	if (ret < 0)
+		return ret;
+
+	ret = pefile_strip_sig_wrapper(pebuf, &ctx);
+	if (ret < 0)
+		return ret;
+
+	pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
+	if (IS_ERR(pkcs7))
+		return PTR_ERR(pkcs7);
+	ctx.pkcs7 = pkcs7;
+
+	ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
+	if (ret < 0 || datalen == 0) {
+		pr_devel("PKCS#7 message does not contain data\n");
+		ret = -EBADMSG;
+		goto error;
+	}
+
+	ret = mscode_parse(&ctx);
+	if (ret < 0)
+		goto error;
+
+	pr_debug("Digest: %u [%*ph]\n",
+		 ctx.digest_len, ctx.digest_len, ctx.digest);
+
+	/* Generate the digest and check against the PKCS7 certificate
+	 * contents.
+	 */
+	ret = pefile_digest_pe(pebuf, pelen, &ctx);
+	if (ret < 0)
+		goto error;
+
+	ret = pkcs7_verify(pkcs7);
+	if (ret < 0)
+		goto error;
+
+	ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
+
+error:
+	pkcs7_free_message(ctx.pkcs7);
+	return ret;
+}

+ 42 - 0
crypto/asymmetric_keys/verify_pefile.h

@@ -0,0 +1,42 @@
+/* PE Binary parser bits
+ *
+ * Copyright (C) 2014 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 <linux/verify_pefile.h>
+#include <crypto/pkcs7.h>
+#include <crypto/hash_info.h>
+
+struct pefile_context {
+	unsigned	header_size;
+	unsigned	image_checksum_offset;
+	unsigned	cert_dirent_offset;
+	unsigned	n_data_dirents;
+	unsigned	n_sections;
+	unsigned	certs_size;
+	unsigned	sig_offset;
+	unsigned	sig_len;
+	const struct section_header *secs;
+	struct pkcs7_message *pkcs7;
+
+	/* PKCS#7 MS Individual Code Signing content */
+	const void	*digest;		/* Digest */
+	unsigned	digest_len;		/* Digest length */
+	enum hash_algo	digest_algo;		/* Digest algorithm */
+};
+
+#define kenter(FMT, ...)					\
+	pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+	pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+
+/*
+ * mscode_parser.c
+ */
+extern int mscode_parse(struct pefile_context *ctx);

+ 1 - 1
crypto/asymmetric_keys/x509.asn1

@@ -6,7 +6,7 @@ Certificate ::= SEQUENCE {
 
 
 TBSCertificate ::= SEQUENCE {
 TBSCertificate ::= SEQUENCE {
 	version           [ 0 ]	Version DEFAULT,
 	version           [ 0 ]	Version DEFAULT,
-	serialNumber		CertificateSerialNumber,
+	serialNumber		CertificateSerialNumber ({ x509_note_serial }),
 	signature		AlgorithmIdentifier ({ x509_note_pkey_algo }),
 	signature		AlgorithmIdentifier ({ x509_note_pkey_algo }),
 	issuer			Name ({ x509_note_issuer }),
 	issuer			Name ({ x509_note_issuer }),
 	validity		Validity,
 	validity		Validity,

+ 20 - 0
crypto/asymmetric_keys/x509_cert_parser.c

@@ -11,6 +11,7 @@
 
 
 #define pr_fmt(fmt) "X.509: "fmt
 #define pr_fmt(fmt) "X.509: "fmt
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/oid_registry.h>
 #include <linux/oid_registry.h>
@@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert)
 		kfree(cert);
 		kfree(cert);
 	}
 	}
 }
 }
+EXPORT_SYMBOL_GPL(x509_free_certificate);
 
 
 /*
 /*
  * Parse an X.509 certificate
  * Parse an X.509 certificate
@@ -97,6 +99,7 @@ error_no_ctx:
 error_no_cert:
 error_no_cert:
 	return ERR_PTR(ret);
 	return ERR_PTR(ret);
 }
 }
+EXPORT_SYMBOL_GPL(x509_cert_parse);
 
 
 /*
 /*
  * Note an OID when we find one for later processing when we know how
  * Note an OID when we find one for later processing when we know how
@@ -210,6 +213,19 @@ int x509_note_signature(void *context, size_t hdrlen,
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Note the certificate serial number
+ */
+int x509_note_serial(void *context, size_t hdrlen,
+		     unsigned char tag,
+		     const void *value, size_t vlen)
+{
+	struct x509_parse_context *ctx = context;
+	ctx->cert->raw_serial = value;
+	ctx->cert->raw_serial_size = vlen;
+	return 0;
+}
+
 /*
 /*
  * Note some of the name segments from which we'll fabricate a name.
  * Note some of the name segments from which we'll fabricate a name.
  */
  */
@@ -322,6 +338,8 @@ int x509_note_issuer(void *context, size_t hdrlen,
 		     const void *value, size_t vlen)
 		     const void *value, size_t vlen)
 {
 {
 	struct x509_parse_context *ctx = context;
 	struct x509_parse_context *ctx = context;
+	ctx->cert->raw_issuer = value;
+	ctx->cert->raw_issuer_size = vlen;
 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
 }
 }
 
 
@@ -330,6 +348,8 @@ int x509_note_subject(void *context, size_t hdrlen,
 		      const void *value, size_t vlen)
 		      const void *value, size_t vlen)
 {
 {
 	struct x509_parse_context *ctx = context;
 	struct x509_parse_context *ctx = context;
+	ctx->cert->raw_subject = value;
+	ctx->cert->raw_subject_size = vlen;
 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
 }
 }
 
 

+ 12 - 1
crypto/asymmetric_keys/x509_parser.h

@@ -14,7 +14,9 @@
 
 
 struct x509_certificate {
 struct x509_certificate {
 	struct x509_certificate *next;
 	struct x509_certificate *next;
+	struct x509_certificate *signer;	/* Certificate that signed this one */
 	struct public_key *pub;			/* Public key details */
 	struct public_key *pub;			/* Public key details */
+	struct public_key_signature sig;	/* Signature parameters */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*subject;		/* Name of certificate subject */
 	char		*subject;		/* Name of certificate subject */
 	char		*fingerprint;		/* Key fingerprint as hex */
 	char		*fingerprint;		/* Key fingerprint as hex */
@@ -25,7 +27,16 @@ struct x509_certificate {
 	unsigned	tbs_size;		/* Size of signed data */
 	unsigned	tbs_size;		/* Size of signed data */
 	unsigned	raw_sig_size;		/* Size of sigature */
 	unsigned	raw_sig_size;		/* Size of sigature */
 	const void	*raw_sig;		/* Signature data */
 	const void	*raw_sig;		/* Signature data */
-	struct public_key_signature sig;	/* Signature parameters */
+	const void	*raw_serial;		/* Raw serial number in ASN.1 */
+	unsigned	raw_serial_size;
+	unsigned	raw_issuer_size;
+	const void	*raw_issuer;		/* Raw issuer name in ASN.1 */
+	const void	*raw_subject;		/* Raw subject name in ASN.1 */
+	unsigned	raw_subject_size;
+	unsigned	index;
+	bool		seen;			/* Infinite recursion prevention */
+	bool		verified;
+	bool		trusted;
 };
 };
 
 
 /*
 /*

+ 113 - 2
crypto/asymmetric_keys/x509_public_key.c

@@ -18,11 +18,86 @@
 #include <linux/asn1_decoder.h>
 #include <linux/asn1_decoder.h>
 #include <keys/asymmetric-subtype.h>
 #include <keys/asymmetric-subtype.h>
 #include <keys/asymmetric-parser.h>
 #include <keys/asymmetric-parser.h>
+#include <keys/system_keyring.h>
 #include <crypto/hash.h>
 #include <crypto/hash.h>
 #include "asymmetric_keys.h"
 #include "asymmetric_keys.h"
 #include "public_key.h"
 #include "public_key.h"
 #include "x509_parser.h"
 #include "x509_parser.h"
 
 
+static bool use_builtin_keys;
+static char *ca_keyid;
+
+#ifndef MODULE
+static int __init ca_keys_setup(char *str)
+{
+	if (!str)		/* default system keyring */
+		return 1;
+
+	if (strncmp(str, "id:", 3) == 0)
+		ca_keyid = str;	/* owner key 'id:xxxxxx' */
+	else if (strcmp(str, "builtin") == 0)
+		use_builtin_keys = true;
+
+	return 1;
+}
+__setup("ca_keys=", ca_keys_setup);
+#endif
+
+/**
+ * x509_request_asymmetric_key - Request a key by X.509 certificate params.
+ * @keyring: The keys to search.
+ * @subject: The name of the subject to whom the key belongs.
+ * @key_id: The subject key ID as a hex string.
+ *
+ * Find a key in the given keyring by subject name and key ID.  These might,
+ * for instance, be the issuer name and the authority key ID of an X.509
+ * certificate that needs to be verified.
+ */
+struct key *x509_request_asymmetric_key(struct key *keyring,
+					const char *subject,
+					const char *key_id)
+{
+	key_ref_t key;
+	size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
+	char *id;
+
+	/* Construct an identifier "<subjname>:<keyid>". */
+	id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
+	if (!id)
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(id, subject, subject_len);
+	id[subject_len + 0] = ':';
+	id[subject_len + 1] = ' ';
+	memcpy(id + subject_len + 2, key_id, key_id_len);
+	id[subject_len + 2 + key_id_len] = 0;
+
+	pr_debug("Look up: \"%s\"\n", id);
+
+	key = keyring_search(make_key_ref(keyring, 1),
+			     &key_type_asymmetric, id);
+	if (IS_ERR(key))
+		pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
+	kfree(id);
+
+	if (IS_ERR(key)) {
+		switch (PTR_ERR(key)) {
+			/* Hide some search errors */
+		case -EACCES:
+		case -ENOTDIR:
+		case -EAGAIN:
+			return ERR_PTR(-ENOKEY);
+		default:
+			return ERR_CAST(key);
+		}
+	}
+
+	pr_devel("<==%s() = 0 [%x]\n", __func__,
+		 key_serial(key_ref_to_ptr(key)));
+	return key_ref_to_ptr(key);
+}
+EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
+
 /*
 /*
  * Set up the signature parameters in an X.509 certificate.  This involves
  * Set up the signature parameters in an X.509 certificate.  This involves
  * digesting the signed data and extracting the signature.
  * digesting the signed data and extracting the signature.
@@ -102,6 +177,38 @@ int x509_check_signature(const struct public_key *pub,
 }
 }
 EXPORT_SYMBOL_GPL(x509_check_signature);
 EXPORT_SYMBOL_GPL(x509_check_signature);
 
 
+/*
+ * Check the new certificate against the ones in the trust keyring.  If one of
+ * those is the signing key and validates the new certificate, then mark the
+ * new certificate as being trusted.
+ *
+ * Return 0 if the new certificate was successfully validated, 1 if we couldn't
+ * find a matching parent certificate in the trusted list and an error if there
+ * is a matching certificate but the signature check fails.
+ */
+static int x509_validate_trust(struct x509_certificate *cert,
+			       struct key *trust_keyring)
+{
+	struct key *key;
+	int ret = 1;
+
+	if (!trust_keyring)
+		return -EOPNOTSUPP;
+
+	if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
+		return -EPERM;
+
+	key = x509_request_asymmetric_key(trust_keyring,
+					  cert->issuer, cert->authority);
+	if (!IS_ERR(key))  {
+		if (!use_builtin_keys
+		    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
+			ret = x509_check_signature(key->payload.data, cert);
+		key_put(key);
+	}
+	return ret;
+}
+
 /*
 /*
  * Attempt to parse a data blob for a key as an X509 certificate.
  * Attempt to parse a data blob for a key as an X509 certificate.
  */
  */
@@ -155,9 +262,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	/* Check the signature on the key if it appears to be self-signed */
 	/* Check the signature on the key if it appears to be self-signed */
 	if (!cert->authority ||
 	if (!cert->authority ||
 	    strcmp(cert->fingerprint, cert->authority) == 0) {
 	    strcmp(cert->fingerprint, cert->authority) == 0) {
-		ret = x509_check_signature(cert->pub, cert);
+		ret = x509_check_signature(cert->pub, cert); /* self-signed */
 		if (ret < 0)
 		if (ret < 0)
 			goto error_free_cert;
 			goto error_free_cert;
+	} else if (!prep->trusted) {
+		ret = x509_validate_trust(cert, get_system_trusted_keyring());
+		if (!ret)
+			prep->trusted = 1;
 	}
 	}
 
 
 	/* Propose a description */
 	/* Propose a description */
@@ -177,7 +288,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	__module_get(public_key_subtype.owner);
 	__module_get(public_key_subtype.owner);
 	prep->type_data[0] = &public_key_subtype;
 	prep->type_data[0] = &public_key_subtype;
 	prep->type_data[1] = cert->fingerprint;
 	prep->type_data[1] = cert->fingerprint;
-	prep->payload = cert->pub;
+	prep->payload[0] = cert->pub;
 	prep->description = desc;
 	prep->description = desc;
 	prep->quotalen = 100;
 	prep->quotalen = 100;
 
 

+ 26 - 4
drivers/base/firmware_class.c

@@ -28,6 +28,7 @@
 #include <linux/suspend.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/syscore_ops.h>
 #include <linux/reboot.h>
 #include <linux/reboot.h>
+#include <linux/security.h>
 
 
 #include <generated/utsrelease.h>
 #include <generated/utsrelease.h>
 
 
@@ -303,12 +304,17 @@ static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf)
 	if (rc != size) {
 	if (rc != size) {
 		if (rc > 0)
 		if (rc > 0)
 			rc = -EIO;
 			rc = -EIO;
-		vfree(buf);
-		return rc;
+		goto fail;
 	}
 	}
+	rc = security_kernel_fw_from_file(file, buf, size);
+	if (rc)
+		goto fail;
 	fw_buf->data = buf;
 	fw_buf->data = buf;
 	fw_buf->size = size;
 	fw_buf->size = size;
 	return 0;
 	return 0;
+fail:
+	vfree(buf);
+	return rc;
 }
 }
 
 
 static int fw_get_filesystem_firmware(struct device *device,
 static int fw_get_filesystem_firmware(struct device *device,
@@ -612,6 +618,7 @@ static ssize_t firmware_loading_store(struct device *dev,
 {
 {
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	struct firmware_priv *fw_priv = to_firmware_priv(dev);
 	struct firmware_buf *fw_buf;
 	struct firmware_buf *fw_buf;
+	ssize_t written = count;
 	int loading = simple_strtol(buf, NULL, 10);
 	int loading = simple_strtol(buf, NULL, 10);
 	int i;
 	int i;
 
 
@@ -635,6 +642,8 @@ static ssize_t firmware_loading_store(struct device *dev,
 		break;
 		break;
 	case 0:
 	case 0:
 		if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
 		if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) {
+			int rc;
+
 			set_bit(FW_STATUS_DONE, &fw_buf->status);
 			set_bit(FW_STATUS_DONE, &fw_buf->status);
 			clear_bit(FW_STATUS_LOADING, &fw_buf->status);
 			clear_bit(FW_STATUS_LOADING, &fw_buf->status);
 
 
@@ -644,10 +653,23 @@ static ssize_t firmware_loading_store(struct device *dev,
 			 * see the mapped 'buf->data' once the loading
 			 * see the mapped 'buf->data' once the loading
 			 * is completed.
 			 * is completed.
 			 * */
 			 * */
-			if (fw_map_pages_buf(fw_buf))
+			rc = fw_map_pages_buf(fw_buf);
+			if (rc)
 				dev_err(dev, "%s: map pages failed\n",
 				dev_err(dev, "%s: map pages failed\n",
 					__func__);
 					__func__);
+			else
+				rc = security_kernel_fw_from_file(NULL,
+						fw_buf->data, fw_buf->size);
+
+			/*
+			 * Same logic as fw_load_abort, only the DONE bit
+			 * is ignored and we set ABORT only on failure.
+			 */
 			list_del_init(&fw_buf->pending_list);
 			list_del_init(&fw_buf->pending_list);
+			if (rc) {
+				set_bit(FW_STATUS_ABORT, &fw_buf->status);
+				written = rc;
+			}
 			complete_all(&fw_buf->completion);
 			complete_all(&fw_buf->completion);
 			break;
 			break;
 		}
 		}
@@ -661,7 +683,7 @@ static ssize_t firmware_loading_store(struct device *dev,
 	}
 	}
 out:
 out:
 	mutex_unlock(&fw_lock);
 	mutex_unlock(&fw_lock);
-	return count;
+	return written;
 }
 }
 
 
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
 static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);

+ 48 - 25
drivers/char/tpm/tpm-interface.c

@@ -491,11 +491,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 int tpm_get_timeouts(struct tpm_chip *chip)
 int tpm_get_timeouts(struct tpm_chip *chip)
 {
 {
 	struct tpm_cmd_t tpm_cmd;
 	struct tpm_cmd_t tpm_cmd;
-	struct timeout_t *timeout_cap;
+	unsigned long new_timeout[4];
+	unsigned long old_timeout[4];
 	struct duration_t *duration_cap;
 	struct duration_t *duration_cap;
 	ssize_t rc;
 	ssize_t rc;
-	u32 timeout;
-	unsigned int scale = 1;
 
 
 	tpm_cmd.header.in = tpm_getcap_header;
 	tpm_cmd.header.in = tpm_getcap_header;
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
@@ -529,25 +528,46 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	    != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
 	    != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
-	/* Don't overwrite default if value is 0 */
-	timeout = be32_to_cpu(timeout_cap->a);
-	if (timeout && timeout < 1000) {
-		/* timeouts in msec rather usec */
-		scale = 1000;
-		chip->vendor.timeout_adjusted = true;
+	old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a);
+	old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b);
+	old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c);
+	old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d);
+	memcpy(new_timeout, old_timeout, sizeof(new_timeout));
+
+	/*
+	 * Provide ability for vendor overrides of timeout values in case
+	 * of misreporting.
+	 */
+	if (chip->ops->update_timeouts != NULL)
+		chip->vendor.timeout_adjusted =
+			chip->ops->update_timeouts(chip, new_timeout);
+
+	if (!chip->vendor.timeout_adjusted) {
+		/* Don't overwrite default if value is 0 */
+		if (new_timeout[0] != 0 && new_timeout[0] < 1000) {
+			int i;
+
+			/* timeouts in msec rather usec */
+			for (i = 0; i != ARRAY_SIZE(new_timeout); i++)
+				new_timeout[i] *= 1000;
+			chip->vendor.timeout_adjusted = true;
+		}
+	}
+
+	/* Report adjusted timeouts */
+	if (chip->vendor.timeout_adjusted) {
+		dev_info(chip->dev,
+			 HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
+			 old_timeout[0], new_timeout[0],
+			 old_timeout[1], new_timeout[1],
+			 old_timeout[2], new_timeout[2],
+			 old_timeout[3], new_timeout[3]);
 	}
 	}
-	if (timeout)
-		chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale);
-	timeout = be32_to_cpu(timeout_cap->b);
-	if (timeout)
-		chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale);
-	timeout = be32_to_cpu(timeout_cap->c);
-	if (timeout)
-		chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale);
-	timeout = be32_to_cpu(timeout_cap->d);
-	if (timeout)
-		chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale);
+
+	chip->vendor.timeout_a = usecs_to_jiffies(new_timeout[0]);
+	chip->vendor.timeout_b = usecs_to_jiffies(new_timeout[1]);
+	chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]);
+	chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]);
 
 
 duration:
 duration:
 	tpm_cmd.header.in = tpm_getcap_header;
 	tpm_cmd.header.in = tpm_getcap_header;
@@ -991,13 +1011,13 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 	int err, total = 0, retries = 5;
 	int err, total = 0, retries = 5;
 	u8 *dest = out;
 	u8 *dest = out;
 
 
+	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
+		return -EINVAL;
+
 	chip = tpm_chip_find_get(chip_num);
 	chip = tpm_chip_find_get(chip_num);
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
-		return -EINVAL;
-
 	do {
 	do {
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
@@ -1016,6 +1036,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 		num_bytes -= recd;
 		num_bytes -= recd;
 	} while (retries-- && total < max);
 	} while (retries-- && total < max);
 
 
+	tpm_chip_put(chip);
 	return total ? total : -EIO;
 	return total ? total : -EIO;
 }
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 EXPORT_SYMBOL_GPL(tpm_get_random);
@@ -1095,7 +1116,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
 		goto del_misc;
 		goto del_misc;
 
 
 	if (tpm_add_ppi(&dev->kobj))
 	if (tpm_add_ppi(&dev->kobj))
-		goto del_misc;
+		goto del_sysfs;
 
 
 	chip->bios_dir = tpm_bios_log_setup(chip->devname);
 	chip->bios_dir = tpm_bios_log_setup(chip->devname);
 
 
@@ -1106,6 +1127,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
 
 
 	return chip;
 	return chip;
 
 
+del_sysfs:
+	tpm_sysfs_del_device(chip);
 del_misc:
 del_misc:
 	tpm_dev_del_device(chip);
 	tpm_dev_del_device(chip);
 put_device:
 put_device:

+ 1 - 3
drivers/char/tpm/tpm_eventlog.c

@@ -235,7 +235,6 @@ static int tpm_bios_measurements_release(struct inode *inode,
 static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
 static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
 {
 {
 	int len = 0;
 	int len = 0;
-	int i;
 	char *eventname;
 	char *eventname;
 	struct tcpa_event *event = v;
 	struct tcpa_event *event = v;
 	unsigned char *event_entry =
 	unsigned char *event_entry =
@@ -251,8 +250,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
 	seq_printf(m, "%2d ", event->pcr_index);
 	seq_printf(m, "%2d ", event->pcr_index);
 
 
 	/* 2nd: SHA1 */
 	/* 2nd: SHA1 */
-	for (i = 0; i < 20; i++)
-		seq_printf(m, "%02x", event->pcr_value[i]);
+	seq_printf(m, "%20phN", event->pcr_value);
 
 
 	/* 3rd: event type identifier */
 	/* 3rd: event type identifier */
 	seq_printf(m, " %02x", event->event_type);
 	seq_printf(m, " %02x", event->event_type);

+ 1 - 0
drivers/char/tpm/tpm_i2c_stm_st33.c

@@ -714,6 +714,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	}
 	}
 
 
 	tpm_get_timeouts(chip);
 	tpm_get_timeouts(chip);
+	tpm_do_selftest(chip);
 
 
 	dev_info(chip->dev, "TPM I2C Initialized\n");
 	dev_info(chip->dev, "TPM I2C Initialized\n");
 	return 0;
 	return 0;

+ 31 - 0
drivers/char/tpm/tpm_tis.c

@@ -373,6 +373,36 @@ out_err:
 	return rc;
 	return rc;
 }
 }
 
 
+struct tis_vendor_timeout_override {
+	u32 did_vid;
+	unsigned long timeout_us[4];
+};
+
+static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = {
+	/* Atmel 3204 */
+	{ 0x32041114, { (TIS_SHORT_TIMEOUT*1000), (TIS_LONG_TIMEOUT*1000),
+			(TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } },
+};
+
+static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
+				    unsigned long *timeout_cap)
+{
+	int i;
+	u32 did_vid;
+
+	did_vid = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+
+	for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
+		if (vendor_timeout_overrides[i].did_vid != did_vid)
+			continue;
+		memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
+		       sizeof(vendor_timeout_overrides[i].timeout_us));
+		return true;
+	}
+
+	return false;
+}
+
 /*
 /*
  * Early probing for iTPM with STS_DATA_EXPECT flaw.
  * Early probing for iTPM with STS_DATA_EXPECT flaw.
  * Try sending command without itpm flag set and if that
  * Try sending command without itpm flag set and if that
@@ -437,6 +467,7 @@ static const struct tpm_class_ops tpm_tis = {
 	.recv = tpm_tis_recv,
 	.recv = tpm_tis_recv,
 	.send = tpm_tis_send,
 	.send = tpm_tis_send,
 	.cancel = tpm_tis_ready,
 	.cancel = tpm_tis_ready,
+	.update_timeouts = tpm_tis_update_timeouts,
 	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 	.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 	.req_canceled = tpm_tis_req_canceled,
 	.req_canceled = tpm_tis_req_canceled,

+ 3 - 3
fs/exec.c

@@ -1216,7 +1216,7 @@ EXPORT_SYMBOL(install_exec_creds);
 /*
 /*
  * determine how safe it is to execute the proposed program
  * determine how safe it is to execute the proposed program
  * - the caller must hold ->cred_guard_mutex to protect against
  * - the caller must hold ->cred_guard_mutex to protect against
- *   PTRACE_ATTACH
+ *   PTRACE_ATTACH or seccomp thread-sync
  */
  */
 static void check_unsafe_exec(struct linux_binprm *bprm)
 static void check_unsafe_exec(struct linux_binprm *bprm)
 {
 {
@@ -1234,7 +1234,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
 	 * This isn't strictly necessary, but it makes it harder for LSMs to
 	 * This isn't strictly necessary, but it makes it harder for LSMs to
 	 * mess up.
 	 * mess up.
 	 */
 	 */
-	if (current->no_new_privs)
+	if (task_no_new_privs(current))
 		bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
 		bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
 
 
 	t = p;
 	t = p;
@@ -1272,7 +1272,7 @@ int prepare_binprm(struct linux_binprm *bprm)
 	bprm->cred->egid = current_egid();
 	bprm->cred->egid = current_egid();
 
 
 	if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
 	if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
-	    !current->no_new_privs &&
+	    !task_no_new_privs(current) &&
 	    kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
 	    kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
 	    kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
 	    kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
 		/* Set-uid? */
 		/* Set-uid? */

+ 8 - 2
fs/nfs/idmap.c

@@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
 
 
 static struct key_type key_type_id_resolver = {
 static struct key_type key_type_id_resolver = {
 	.name		= "id_resolver",
 	.name		= "id_resolver",
-	.instantiate	= user_instantiate,
+	.preparse	= user_preparse,
+	.free_preparse	= user_free_preparse,
+	.instantiate	= generic_key_instantiate,
 	.match		= user_match,
 	.match		= user_match,
 	.revoke		= user_revoke,
 	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.destroy	= user_destroy,
@@ -282,6 +284,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
 						desc, "", 0, idmap);
 						desc, "", 0, idmap);
 		mutex_unlock(&idmap->idmap_mutex);
 		mutex_unlock(&idmap->idmap_mutex);
 	}
 	}
+	if (!IS_ERR(rkey))
+		set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
 
 
 	kfree(desc);
 	kfree(desc);
 	return rkey;
 	return rkey;
@@ -394,7 +398,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = {
 
 
 static struct key_type key_type_id_resolver_legacy = {
 static struct key_type key_type_id_resolver_legacy = {
 	.name		= "id_legacy",
 	.name		= "id_legacy",
-	.instantiate	= user_instantiate,
+	.preparse	= user_preparse,
+	.free_preparse	= user_free_preparse,
+	.instantiate	= generic_key_instantiate,
 	.match		= user_match,
 	.match		= user_match,
 	.revoke		= user_revoke,
 	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.destroy	= user_destroy,

+ 1 - 10
fs/proc/array.c

@@ -297,15 +297,11 @@ static void render_cap_t(struct seq_file *m, const char *header,
 	seq_puts(m, header);
 	seq_puts(m, header);
 	CAP_FOR_EACH_U32(__capi) {
 	CAP_FOR_EACH_U32(__capi) {
 		seq_printf(m, "%08x",
 		seq_printf(m, "%08x",
-			   a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]);
+			   a->cap[CAP_LAST_U32 - __capi]);
 	}
 	}
 	seq_putc(m, '\n');
 	seq_putc(m, '\n');
 }
 }
 
 
-/* Remove non-existent capabilities */
-#define NORM_CAPS(v) (v.cap[CAP_TO_INDEX(CAP_LAST_CAP)] &= \
-				CAP_TO_MASK(CAP_LAST_CAP + 1) - 1)
-
 static inline void task_cap(struct seq_file *m, struct task_struct *p)
 static inline void task_cap(struct seq_file *m, struct task_struct *p)
 {
 {
 	const struct cred *cred;
 	const struct cred *cred;
@@ -319,11 +315,6 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p)
 	cap_bset	= cred->cap_bset;
 	cap_bset	= cred->cap_bset;
 	rcu_read_unlock();
 	rcu_read_unlock();
 
 
-	NORM_CAPS(cap_inheritable);
-	NORM_CAPS(cap_permitted);
-	NORM_CAPS(cap_effective);
-	NORM_CAPS(cap_bset);
-
 	render_cap_t(m, "CapInh:\t", &cap_inheritable);
 	render_cap_t(m, "CapInh:\t", &cap_inheritable);
 	render_cap_t(m, "CapPrm:\t", &cap_permitted);
 	render_cap_t(m, "CapPrm:\t", &cap_permitted);
 	render_cap_t(m, "CapEff:\t", &cap_effective);
 	render_cap_t(m, "CapEff:\t", &cap_effective);

+ 36 - 0
include/crypto/pkcs7.h

@@ -0,0 +1,36 @@
+/* PKCS#7 crypto data parser
+ *
+ * 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.
+ */
+
+struct key;
+struct pkcs7_message;
+
+/*
+ * pkcs7_parser.c
+ */
+extern struct pkcs7_message *pkcs7_parse_message(const void *data,
+						 size_t datalen);
+extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
+
+extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
+				  const void **_data, size_t *_datalen,
+				  bool want_wrapper);
+
+/*
+ * pkcs7_trust.c
+ */
+extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
+				struct key *trust_keyring,
+				bool *_trusted);
+
+/*
+ * pkcs7_verify.c
+ */
+extern int pkcs7_verify(struct pkcs7_message *pkcs7);

+ 4 - 0
include/crypto/public_key.h

@@ -98,4 +98,8 @@ struct key;
 extern int verify_signature(const struct key *key,
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
 			    const struct public_key_signature *sig);
 
 
+extern struct key *x509_request_asymmetric_key(struct key *keyring,
+					       const char *issuer,
+					       const char *key_id);
+
 #endif /* _LINUX_PUBLIC_KEY_H */
 #endif /* _LINUX_PUBLIC_KEY_H */

+ 2 - 1
include/keys/big_key-type.h

@@ -16,7 +16,8 @@
 
 
 extern struct key_type key_type_big_key;
 extern struct key_type key_type_big_key;
 
 
-extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
+extern int big_key_preparse(struct key_preparsed_payload *prep);
+extern void big_key_free_preparse(struct key_preparsed_payload *prep);
 extern void big_key_revoke(struct key *key);
 extern void big_key_revoke(struct key *key);
 extern void big_key_destroy(struct key *key);
 extern void big_key_destroy(struct key *key);
 extern void big_key_describe(const struct key *big_key, struct seq_file *m);
 extern void big_key_describe(const struct key *big_key, struct seq_file *m);

+ 9 - 1
include/keys/system_keyring.h

@@ -17,7 +17,15 @@
 #include <linux/key.h>
 #include <linux/key.h>
 
 
 extern struct key *system_trusted_keyring;
 extern struct key *system_trusted_keyring;
-
+static inline struct key *get_system_trusted_keyring(void)
+{
+	return system_trusted_keyring;
+}
+#else
+static inline struct key *get_system_trusted_keyring(void)
+{
+	return NULL;
+}
 #endif
 #endif
 
 
 #endif /* _KEYS_SYSTEM_KEYRING_H */
 #endif /* _KEYS_SYSTEM_KEYRING_H */

+ 2 - 1
include/keys/user-type.h

@@ -37,7 +37,8 @@ extern struct key_type key_type_logon;
 
 
 struct key_preparsed_payload;
 struct key_preparsed_payload;
 
 
-extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep);
+extern int user_preparse(struct key_preparsed_payload *prep);
+extern void user_free_preparse(struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
 extern int user_match(const struct key *key, const void *criterion);
 extern int user_match(const struct key *key, const void *criterion);
 extern void user_revoke(struct key *key);
 extern void user_revoke(struct key *key);

+ 4 - 1
include/linux/capability.h

@@ -78,8 +78,11 @@ extern const kernel_cap_t __cap_init_eff_set;
 # error Fix up hand-coded capability macro initializers
 # error Fix up hand-coded capability macro initializers
 #else /* HAND-CODED capability initializers */
 #else /* HAND-CODED capability initializers */
 
 
+#define CAP_LAST_U32			((_KERNEL_CAPABILITY_U32S) - 1)
+#define CAP_LAST_U32_VALID_MASK		(CAP_TO_MASK(CAP_LAST_CAP + 1) -1)
+
 # define CAP_EMPTY_SET    ((kernel_cap_t){{ 0, 0 }})
 # define CAP_EMPTY_SET    ((kernel_cap_t){{ 0, 0 }})
-# define CAP_FULL_SET     ((kernel_cap_t){{ ~0, ~0 }})
+# define CAP_FULL_SET     ((kernel_cap_t){{ ~0, CAP_LAST_U32_VALID_MASK }})
 # define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0 \
 # define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0 \
 				    | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
 				    | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
 				    CAP_FS_MASK_B1 } })
 				    CAP_FS_MASK_B1 } })

+ 6 - 0
include/linux/ima.h

@@ -19,6 +19,7 @@ extern int ima_file_check(struct file *file, int mask);
 extern void ima_file_free(struct file *file);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
 extern int ima_module_check(struct file *file);
 extern int ima_module_check(struct file *file);
+extern int ima_fw_from_file(struct file *file, char *buf, size_t size);
 
 
 #else
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -46,6 +47,11 @@ static inline int ima_module_check(struct file *file)
 	return 0;
 	return 0;
 }
 }
 
 
+static inline int ima_fw_from_file(struct file *file, char *buf, size_t size)
+{
+	return 0;
+}
+
 #endif /* CONFIG_IMA */
 #endif /* CONFIG_IMA */
 
 
 #ifdef CONFIG_IMA_APPRAISE
 #ifdef CONFIG_IMA_APPRAISE

+ 4 - 1
include/linux/key-type.h

@@ -41,10 +41,11 @@ struct key_construction {
 struct key_preparsed_payload {
 struct key_preparsed_payload {
 	char		*description;	/* Proposed key description (or NULL) */
 	char		*description;	/* Proposed key description (or NULL) */
 	void		*type_data[2];	/* Private key-type data */
 	void		*type_data[2];	/* Private key-type data */
-	void		*payload;	/* Proposed payload */
+	void		*payload[2];	/* Proposed payload */
 	const void	*data;		/* Raw data */
 	const void	*data;		/* Raw data */
 	size_t		datalen;	/* Raw datalen */
 	size_t		datalen;	/* Raw datalen */
 	size_t		quotalen;	/* Quota length for proposed payload */
 	size_t		quotalen;	/* Quota length for proposed payload */
+	time_t		expiry;		/* Expiry time of key */
 	bool		trusted;	/* True if key is trusted */
 	bool		trusted;	/* True if key is trusted */
 };
 };
 
 
@@ -159,5 +160,7 @@ static inline int key_negate_and_link(struct key *key,
 	return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey);
 	return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey);
 }
 }
 
 
+extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
+
 #endif /* CONFIG_KEYS */
 #endif /* CONFIG_KEYS */
 #endif /* _LINUX_KEY_TYPE_H */
 #endif /* _LINUX_KEY_TYPE_H */

+ 2 - 0
include/linux/key.h

@@ -170,6 +170,8 @@ struct key {
 #define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
 #define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
 #define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
 #define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
 #define KEY_FLAG_TRUSTED_ONLY	9	/* set if keyring only accepts links to trusted keys */
 #define KEY_FLAG_TRUSTED_ONLY	9	/* set if keyring only accepts links to trusted keys */
+#define KEY_FLAG_BUILTIN	10	/* set if key is builtin */
+#define KEY_FLAG_ROOT_CAN_INVAL	11	/* set if key can be invalidated by root without permission */
 
 
 	/* the key type and key description string
 	/* the key type and key description string
 	 * - the desc is used to match a key against search criteria
 	 * - the desc is used to match a key against search criteria

+ 7 - 1
include/linux/oid_registry.h

@@ -52,9 +52,15 @@ enum OID {
 	OID_md4,			/* 1.2.840.113549.2.4 */
 	OID_md4,			/* 1.2.840.113549.2.4 */
 	OID_md5,			/* 1.2.840.113549.2.5 */
 	OID_md5,			/* 1.2.840.113549.2.5 */
 
 
-	OID_certAuthInfoAccess,		/* 1.3.6.1.5.5.7.1.1 */
+	/* Microsoft Authenticode & Software Publishing */
+	OID_msIndirectData,		/* 1.3.6.1.4.1.311.2.1.4 */
+	OID_msPeImageDataObjId,		/* 1.3.6.1.4.1.311.2.1.15 */
+	OID_msIndividualSPKeyPurpose,	/* 1.3.6.1.4.1.311.2.1.21 */
 	OID_msOutlookExpress,		/* 1.3.6.1.4.1.311.16.4 */
 	OID_msOutlookExpress,		/* 1.3.6.1.4.1.311.16.4 */
+
+	OID_certAuthInfoAccess,		/* 1.3.6.1.5.5.7.1.1 */
 	OID_sha1,			/* 1.3.14.3.2.26 */
 	OID_sha1,			/* 1.3.14.3.2.26 */
+	OID_sha256,			/* 2.16.840.1.101.3.4.2.1 */
 
 
 	/* Distinguished Name attribute IDs [RFC 2256] */
 	/* Distinguished Name attribute IDs [RFC 2256] */
 	OID_commonName,			/* 2.5.4.3 */
 	OID_commonName,			/* 2.5.4.3 */

+ 448 - 0
include/linux/pe.h

@@ -0,0 +1,448 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+#ifndef __LINUX_PE_H
+#define __LINUX_PE_H
+
+#include <linux/types.h>
+
+#define MZ_MAGIC	0x5a4d	/* "MZ" */
+
+struct mz_hdr {
+	uint16_t magic;		/* MZ_MAGIC */
+	uint16_t lbsize;	/* size of last used block */
+	uint16_t blocks;	/* pages in file, 0x3 */
+	uint16_t relocs;	/* relocations */
+	uint16_t hdrsize;	/* header size in "paragraphs" */
+	uint16_t min_extra_pps;	/* .bss */
+	uint16_t max_extra_pps;	/* runtime limit for the arena size */
+	uint16_t ss;		/* relative stack segment */
+	uint16_t sp;		/* initial %sp register */
+	uint16_t checksum;	/* word checksum */
+	uint16_t ip;		/* initial %ip register */
+	uint16_t cs;		/* initial %cs relative to load segment */
+	uint16_t reloc_table_offset;	/* offset of the first relocation */
+	uint16_t overlay_num;	/* overlay number.  set to 0. */
+	uint16_t reserved0[4];	/* reserved */
+	uint16_t oem_id;	/* oem identifier */
+	uint16_t oem_info;	/* oem specific */
+	uint16_t reserved1[10];	/* reserved */
+	uint32_t peaddr;	/* address of pe header */
+	char     message[64];	/* message to print */
+};
+
+struct mz_reloc {
+	uint16_t offset;
+	uint16_t segment;
+};
+
+#define PE_MAGIC		0x00004550	/* "PE\0\0" */
+#define PE_OPT_MAGIC_PE32	0x010b
+#define PE_OPT_MAGIC_PE32_ROM	0x0107
+#define PE_OPT_MAGIC_PE32PLUS	0x020b
+
+/* machine type */
+#define	IMAGE_FILE_MACHINE_UNKNOWN	0x0000
+#define	IMAGE_FILE_MACHINE_AM33		0x01d3
+#define	IMAGE_FILE_MACHINE_AMD64	0x8664
+#define	IMAGE_FILE_MACHINE_ARM		0x01c0
+#define	IMAGE_FILE_MACHINE_ARMV7	0x01c4
+#define	IMAGE_FILE_MACHINE_EBC		0x0ebc
+#define	IMAGE_FILE_MACHINE_I386		0x014c
+#define	IMAGE_FILE_MACHINE_IA64		0x0200
+#define	IMAGE_FILE_MACHINE_M32R		0x9041
+#define	IMAGE_FILE_MACHINE_MIPS16	0x0266
+#define	IMAGE_FILE_MACHINE_MIPSFPU	0x0366
+#define	IMAGE_FILE_MACHINE_MIPSFPU16	0x0466
+#define	IMAGE_FILE_MACHINE_POWERPC	0x01f0
+#define	IMAGE_FILE_MACHINE_POWERPCFP	0x01f1
+#define	IMAGE_FILE_MACHINE_R4000	0x0166
+#define	IMAGE_FILE_MACHINE_SH3		0x01a2
+#define	IMAGE_FILE_MACHINE_SH3DSP	0x01a3
+#define	IMAGE_FILE_MACHINE_SH3E		0x01a4
+#define	IMAGE_FILE_MACHINE_SH4		0x01a6
+#define	IMAGE_FILE_MACHINE_SH5		0x01a8
+#define	IMAGE_FILE_MACHINE_THUMB	0x01c2
+#define	IMAGE_FILE_MACHINE_WCEMIPSV2	0x0169
+
+/* flags */
+#define IMAGE_FILE_RELOCS_STRIPPED           0x0001
+#define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002
+#define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008
+#define IMAGE_FILE_AGGRESSIVE_WS_TRIM        0x0010
+#define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020
+#define IMAGE_FILE_16BIT_MACHINE             0x0040
+#define IMAGE_FILE_BYTES_REVERSED_LO         0x0080
+#define IMAGE_FILE_32BIT_MACHINE             0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED            0x0200
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400
+#define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800
+#define IMAGE_FILE_SYSTEM                    0x1000
+#define IMAGE_FILE_DLL                       0x2000
+#define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000
+#define IMAGE_FILE_BYTES_REVERSED_HI         0x8000
+
+struct pe_hdr {
+	uint32_t magic;		/* PE magic */
+	uint16_t machine;	/* machine type */
+	uint16_t sections;	/* number of sections */
+	uint32_t timestamp;	/* time_t */
+	uint32_t symbol_table;	/* symbol table offset */
+	uint32_t symbols;	/* number of symbols */
+	uint16_t opt_hdr_size;	/* size of optional header */
+	uint16_t flags;		/* flags */
+};
+
+#define IMAGE_FILE_OPT_ROM_MAGIC	0x107
+#define IMAGE_FILE_OPT_PE32_MAGIC	0x10b
+#define IMAGE_FILE_OPT_PE32_PLUS_MAGIC	0x20b
+
+#define IMAGE_SUBSYSTEM_UNKNOWN			 0
+#define IMAGE_SUBSYSTEM_NATIVE			 1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI		 2
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI		 3
+#define IMAGE_SUBSYSTEM_POSIX_CUI		 7
+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI		 9
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION		10
+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER	11
+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER	12
+#define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE		13
+#define IMAGE_SUBSYSTEM_XBOX			14
+
+#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE          0x0040
+#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY       0x0080
+#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT             0x0100
+#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION           0x0200
+#define IMAGE_DLLCHARACTERISTICS_NO_SEH                 0x0400
+#define IMAGE_DLLCHARACTERISTICS_NO_BIND                0x0800
+#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER             0x2000
+#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE  0x8000
+
+/* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't
+ * work right.  vomit. */
+struct pe32_opt_hdr {
+	/* "standard" header */
+	uint16_t magic;		/* file type */
+	uint8_t  ld_major;	/* linker major version */
+	uint8_t  ld_minor;	/* linker minor version */
+	uint32_t text_size;	/* size of text section(s) */
+	uint32_t data_size;	/* size of data section(s) */
+	uint32_t bss_size;	/* size of bss section(s) */
+	uint32_t entry_point;	/* file offset of entry point */
+	uint32_t code_base;	/* relative code addr in ram */
+	uint32_t data_base;	/* relative data addr in ram */
+	/* "windows" header */
+	uint32_t image_base;	/* preferred load address */
+	uint32_t section_align;	/* alignment in bytes */
+	uint32_t file_align;	/* file alignment in bytes */
+	uint16_t os_major;	/* major OS version */
+	uint16_t os_minor;	/* minor OS version */
+	uint16_t image_major;	/* major image version */
+	uint16_t image_minor;	/* minor image version */
+	uint16_t subsys_major;	/* major subsystem version */
+	uint16_t subsys_minor;	/* minor subsystem version */
+	uint32_t win32_version;	/* reserved, must be 0 */
+	uint32_t image_size;	/* image size */
+	uint32_t header_size;	/* header size rounded up to
+				   file_align */
+	uint32_t csum;		/* checksum */
+	uint16_t subsys;	/* subsystem */
+	uint16_t dll_flags;	/* more flags! */
+	uint32_t stack_size_req;/* amt of stack requested */
+	uint32_t stack_size;	/* amt of stack required */
+	uint32_t heap_size_req;	/* amt of heap requested */
+	uint32_t heap_size;	/* amt of heap required */
+	uint32_t loader_flags;	/* reserved, must be 0 */
+	uint32_t data_dirs;	/* number of data dir entries */
+};
+
+struct pe32plus_opt_hdr {
+	uint16_t magic;		/* file type */
+	uint8_t  ld_major;	/* linker major version */
+	uint8_t  ld_minor;	/* linker minor version */
+	uint32_t text_size;	/* size of text section(s) */
+	uint32_t data_size;	/* size of data section(s) */
+	uint32_t bss_size;	/* size of bss section(s) */
+	uint32_t entry_point;	/* file offset of entry point */
+	uint32_t code_base;	/* relative code addr in ram */
+	/* "windows" header */
+	uint64_t image_base;	/* preferred load address */
+	uint32_t section_align;	/* alignment in bytes */
+	uint32_t file_align;	/* file alignment in bytes */
+	uint16_t os_major;	/* major OS version */
+	uint16_t os_minor;	/* minor OS version */
+	uint16_t image_major;	/* major image version */
+	uint16_t image_minor;	/* minor image version */
+	uint16_t subsys_major;	/* major subsystem version */
+	uint16_t subsys_minor;	/* minor subsystem version */
+	uint32_t win32_version;	/* reserved, must be 0 */
+	uint32_t image_size;	/* image size */
+	uint32_t header_size;	/* header size rounded up to
+				   file_align */
+	uint32_t csum;		/* checksum */
+	uint16_t subsys;	/* subsystem */
+	uint16_t dll_flags;	/* more flags! */
+	uint64_t stack_size_req;/* amt of stack requested */
+	uint64_t stack_size;	/* amt of stack required */
+	uint64_t heap_size_req;	/* amt of heap requested */
+	uint64_t heap_size;	/* amt of heap required */
+	uint32_t loader_flags;	/* reserved, must be 0 */
+	uint32_t data_dirs;	/* number of data dir entries */
+};
+
+struct data_dirent {
+	uint32_t virtual_address;	/* relative to load address */
+	uint32_t size;
+};
+
+struct data_directory {
+	struct data_dirent exports;		/* .edata */
+	struct data_dirent imports;		/* .idata */
+	struct data_dirent resources;		/* .rsrc */
+	struct data_dirent exceptions;		/* .pdata */
+	struct data_dirent certs;		/* certs */
+	struct data_dirent base_relocations;	/* .reloc */
+	struct data_dirent debug;		/* .debug */
+	struct data_dirent arch;		/* reservered */
+	struct data_dirent global_ptr;		/* global pointer reg. Size=0 */
+	struct data_dirent tls;			/* .tls */
+	struct data_dirent load_config;		/* load configuration structure */
+	struct data_dirent bound_imports;	/* no idea */
+	struct data_dirent import_addrs;	/* import address table */
+	struct data_dirent delay_imports;	/* delay-load import table */
+	struct data_dirent clr_runtime_hdr;	/* .cor (object only) */
+	struct data_dirent reserved;
+};
+
+struct section_header {
+	char name[8];			/* name or "/12\0" string tbl offset */
+	uint32_t virtual_size;		/* size of loaded section in ram */
+	uint32_t virtual_address;	/* relative virtual address */
+	uint32_t raw_data_size;		/* size of the section */
+	uint32_t data_addr;		/* file pointer to first page of sec */
+	uint32_t relocs;		/* file pointer to relocation entries */
+	uint32_t line_numbers;		/* line numbers! */
+	uint16_t num_relocs;		/* number of relocations */
+	uint16_t num_lin_numbers;	/* srsly. */
+	uint32_t flags;
+};
+
+/* they actually defined 0x00000000 as well, but I think we'll skip that one. */
+#define IMAGE_SCN_RESERVED_0	0x00000001
+#define IMAGE_SCN_RESERVED_1	0x00000002
+#define IMAGE_SCN_RESERVED_2	0x00000004
+#define IMAGE_SCN_TYPE_NO_PAD	0x00000008 /* don't pad - obsolete */
+#define IMAGE_SCN_RESERVED_3	0x00000010
+#define IMAGE_SCN_CNT_CODE	0x00000020 /* .text */
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */
+#define IMAGE_SCN_LNK_OTHER	0x00000100 /* reserved */
+#define IMAGE_SCN_LNK_INFO	0x00000200 /* .drectve comments */
+#define IMAGE_SCN_RESERVED_4	0x00000400
+#define IMAGE_SCN_LNK_REMOVE	0x00000800 /* .o only - scn to be rm'd*/
+#define IMAGE_SCN_LNK_COMDAT	0x00001000 /* .o only - COMDAT data */
+#define IMAGE_SCN_RESERVED_5	0x00002000 /* spec omits this */
+#define IMAGE_SCN_RESERVED_6	0x00004000 /* spec omits this */
+#define IMAGE_SCN_GPREL		0x00008000 /* global pointer referenced data */
+/* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */
+#define IMAGE_SCN_MEM_PURGEABLE	0x00010000 /* reserved for "future" use */
+#define IMAGE_SCN_16BIT		0x00020000 /* reserved for "future" use */
+#define IMAGE_SCN_LOCKED	0x00040000 /* reserved for "future" use */
+#define IMAGE_SCN_PRELOAD	0x00080000 /* reserved for "future" use */
+/* and here they just stuck a 1-byte integer in the middle of a bitfield */
+#define IMAGE_SCN_ALIGN_1BYTES	0x00100000 /* it does what it says on the box */
+#define IMAGE_SCN_ALIGN_2BYTES	0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES	0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES	0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES	0x00500000
+#define IMAGE_SCN_ALIGN_32BYTES	0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES	0x00700000
+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
+#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
+#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
+#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
+#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
+#define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */
+#define IMAGE_SCN_MEM_NOT_PAGED	0x08000000 /* not pageable */
+#define IMAGE_SCN_MEM_SHARED	0x10000000 /* can be shared */
+#define IMAGE_SCN_MEM_EXECUTE	0x20000000 /* can be executed as code */
+#define IMAGE_SCN_MEM_READ	0x40000000 /* readable */
+#define IMAGE_SCN_MEM_WRITE	0x80000000 /* writeable */
+
+enum x64_coff_reloc_type {
+	IMAGE_REL_AMD64_ABSOLUTE = 0,
+	IMAGE_REL_AMD64_ADDR64,
+	IMAGE_REL_AMD64_ADDR32,
+	IMAGE_REL_AMD64_ADDR32N,
+	IMAGE_REL_AMD64_REL32,
+	IMAGE_REL_AMD64_REL32_1,
+	IMAGE_REL_AMD64_REL32_2,
+	IMAGE_REL_AMD64_REL32_3,
+	IMAGE_REL_AMD64_REL32_4,
+	IMAGE_REL_AMD64_REL32_5,
+	IMAGE_REL_AMD64_SECTION,
+	IMAGE_REL_AMD64_SECREL,
+	IMAGE_REL_AMD64_SECREL7,
+	IMAGE_REL_AMD64_TOKEN,
+	IMAGE_REL_AMD64_SREL32,
+	IMAGE_REL_AMD64_PAIR,
+	IMAGE_REL_AMD64_SSPAN32,
+};
+
+enum arm_coff_reloc_type {
+	IMAGE_REL_ARM_ABSOLUTE,
+	IMAGE_REL_ARM_ADDR32,
+	IMAGE_REL_ARM_ADDR32N,
+	IMAGE_REL_ARM_BRANCH2,
+	IMAGE_REL_ARM_BRANCH1,
+	IMAGE_REL_ARM_SECTION,
+	IMAGE_REL_ARM_SECREL,
+};
+
+enum sh_coff_reloc_type {
+	IMAGE_REL_SH3_ABSOLUTE,
+	IMAGE_REL_SH3_DIRECT16,
+	IMAGE_REL_SH3_DIRECT32,
+	IMAGE_REL_SH3_DIRECT8,
+	IMAGE_REL_SH3_DIRECT8_WORD,
+	IMAGE_REL_SH3_DIRECT8_LONG,
+	IMAGE_REL_SH3_DIRECT4,
+	IMAGE_REL_SH3_DIRECT4_WORD,
+	IMAGE_REL_SH3_DIRECT4_LONG,
+	IMAGE_REL_SH3_PCREL8_WORD,
+	IMAGE_REL_SH3_PCREL8_LONG,
+	IMAGE_REL_SH3_PCREL12_WORD,
+	IMAGE_REL_SH3_STARTOF_SECTION,
+	IMAGE_REL_SH3_SIZEOF_SECTION,
+	IMAGE_REL_SH3_SECTION,
+	IMAGE_REL_SH3_SECREL,
+	IMAGE_REL_SH3_DIRECT32_NB,
+	IMAGE_REL_SH3_GPREL4_LONG,
+	IMAGE_REL_SH3_TOKEN,
+	IMAGE_REL_SHM_PCRELPT,
+	IMAGE_REL_SHM_REFLO,
+	IMAGE_REL_SHM_REFHALF,
+	IMAGE_REL_SHM_RELLO,
+	IMAGE_REL_SHM_RELHALF,
+	IMAGE_REL_SHM_PAIR,
+	IMAGE_REL_SHM_NOMODE,
+};
+
+enum ppc_coff_reloc_type {
+	IMAGE_REL_PPC_ABSOLUTE,
+	IMAGE_REL_PPC_ADDR64,
+	IMAGE_REL_PPC_ADDR32,
+	IMAGE_REL_PPC_ADDR24,
+	IMAGE_REL_PPC_ADDR16,
+	IMAGE_REL_PPC_ADDR14,
+	IMAGE_REL_PPC_REL24,
+	IMAGE_REL_PPC_REL14,
+	IMAGE_REL_PPC_ADDR32N,
+	IMAGE_REL_PPC_SECREL,
+	IMAGE_REL_PPC_SECTION,
+	IMAGE_REL_PPC_SECREL16,
+	IMAGE_REL_PPC_REFHI,
+	IMAGE_REL_PPC_REFLO,
+	IMAGE_REL_PPC_PAIR,
+	IMAGE_REL_PPC_SECRELLO,
+	IMAGE_REL_PPC_GPREL,
+	IMAGE_REL_PPC_TOKEN,
+};
+
+enum x86_coff_reloc_type {
+	IMAGE_REL_I386_ABSOLUTE,
+	IMAGE_REL_I386_DIR16,
+	IMAGE_REL_I386_REL16,
+	IMAGE_REL_I386_DIR32,
+	IMAGE_REL_I386_DIR32NB,
+	IMAGE_REL_I386_SEG12,
+	IMAGE_REL_I386_SECTION,
+	IMAGE_REL_I386_SECREL,
+	IMAGE_REL_I386_TOKEN,
+	IMAGE_REL_I386_SECREL7,
+	IMAGE_REL_I386_REL32,
+};
+
+enum ia64_coff_reloc_type {
+	IMAGE_REL_IA64_ABSOLUTE,
+	IMAGE_REL_IA64_IMM14,
+	IMAGE_REL_IA64_IMM22,
+	IMAGE_REL_IA64_IMM64,
+	IMAGE_REL_IA64_DIR32,
+	IMAGE_REL_IA64_DIR64,
+	IMAGE_REL_IA64_PCREL21B,
+	IMAGE_REL_IA64_PCREL21M,
+	IMAGE_REL_IA64_PCREL21F,
+	IMAGE_REL_IA64_GPREL22,
+	IMAGE_REL_IA64_LTOFF22,
+	IMAGE_REL_IA64_SECTION,
+	IMAGE_REL_IA64_SECREL22,
+	IMAGE_REL_IA64_SECREL64I,
+	IMAGE_REL_IA64_SECREL32,
+	IMAGE_REL_IA64_DIR32NB,
+	IMAGE_REL_IA64_SREL14,
+	IMAGE_REL_IA64_SREL22,
+	IMAGE_REL_IA64_SREL32,
+	IMAGE_REL_IA64_UREL32,
+	IMAGE_REL_IA64_PCREL60X,
+	IMAGE_REL_IA64_PCREL60B,
+	IMAGE_REL_IA64_PCREL60F,
+	IMAGE_REL_IA64_PCREL60I,
+	IMAGE_REL_IA64_PCREL60M,
+	IMAGE_REL_IA64_IMMGPREL6,
+	IMAGE_REL_IA64_TOKEN,
+	IMAGE_REL_IA64_GPREL32,
+	IMAGE_REL_IA64_ADDEND,
+};
+
+struct coff_reloc {
+	uint32_t virtual_address;
+	uint32_t symbol_table_index;
+	union {
+		enum x64_coff_reloc_type  x64_type;
+		enum arm_coff_reloc_type  arm_type;
+		enum sh_coff_reloc_type   sh_type;
+		enum ppc_coff_reloc_type  ppc_type;
+		enum x86_coff_reloc_type  x86_type;
+		enum ia64_coff_reloc_type ia64_type;
+		uint16_t data;
+	};
+};
+
+/*
+ * Definitions for the contents of the certs data block
+ */
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA	0x0002
+#define WIN_CERT_TYPE_EFI_OKCS115	0x0EF0
+#define WIN_CERT_TYPE_EFI_GUID		0x0EF1
+
+#define WIN_CERT_REVISION_1_0	0x0100
+#define WIN_CERT_REVISION_2_0	0x0200
+
+struct win_certificate {
+	uint32_t length;
+	uint16_t revision;
+	uint16_t cert_type;
+};
+
+#endif /* __LINUX_PE_H */

+ 15 - 3
include/linux/sched.h

@@ -1304,13 +1304,12 @@ struct task_struct {
 				 * execve */
 				 * execve */
 	unsigned in_iowait:1;
 	unsigned in_iowait:1;
 
 
-	/* task may not gain privileges */
-	unsigned no_new_privs:1;
-
 	/* Revert to default priority/policy when forking */
 	/* Revert to default priority/policy when forking */
 	unsigned sched_reset_on_fork:1;
 	unsigned sched_reset_on_fork:1;
 	unsigned sched_contributes_to_load:1;
 	unsigned sched_contributes_to_load:1;
 
 
+	unsigned long atomic_flags; /* Flags needing atomic access. */
+
 	pid_t pid;
 	pid_t pid;
 	pid_t tgid;
 	pid_t tgid;
 
 
@@ -1962,6 +1961,19 @@ static inline void memalloc_noio_restore(unsigned int flags)
 	current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags;
 	current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags;
 }
 }
 
 
+/* Per-process atomic flags. */
+#define PFA_NO_NEW_PRIVS 0x00000001	/* May not gain new privileges. */
+
+static inline bool task_no_new_privs(struct task_struct *p)
+{
+	return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
+}
+
+static inline void task_set_no_new_privs(struct task_struct *p)
+{
+	set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
+}
+
 /*
 /*
  * task->jobctl flags
  * task->jobctl flags
  */
  */

+ 5 - 3
include/linux/seccomp.h

@@ -3,6 +3,8 @@
 
 
 #include <uapi/linux/seccomp.h>
 #include <uapi/linux/seccomp.h>
 
 
+#define SECCOMP_FILTER_FLAG_MASK	(SECCOMP_FILTER_FLAG_TSYNC)
+
 #ifdef CONFIG_SECCOMP
 #ifdef CONFIG_SECCOMP
 
 
 #include <linux/thread_info.h>
 #include <linux/thread_info.h>
@@ -14,11 +16,11 @@ struct seccomp_filter;
  *
  *
  * @mode:  indicates one of the valid values above for controlled
  * @mode:  indicates one of the valid values above for controlled
  *         system calls available to a process.
  *         system calls available to a process.
- * @filter: The metadata and ruleset for determining what system calls
- *          are allowed for a task.
+ * @filter: must always point to a valid seccomp-filter or NULL as it is
+ *          accessed without locking during system call entry.
  *
  *
  *          @filter must only be accessed from the context of current as there
  *          @filter must only be accessed from the context of current as there
- *          is no locking.
+ *          is no read locking.
  */
  */
 struct seccomp {
 struct seccomp {
 	int mode;
 	int mode;

+ 17 - 0
include/linux/security.h

@@ -702,6 +702,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@inode points to the inode to use as a reference.
  *	@inode points to the inode to use as a reference.
  *	The current task must be the one that nominated @inode.
  *	The current task must be the one that nominated @inode.
  *	Return 0 if successful.
  *	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:
  * @kernel_module_request:
  *	Ability to trigger the kernel to automatically upcall to userspace for
  *	Ability to trigger the kernel to automatically upcall to userspace for
  *	userspace to load a kernel module with the given name.
  *	userspace to load a kernel module with the given name.
@@ -1565,6 +1574,7 @@ struct security_operations {
 	void (*cred_transfer)(struct cred *new, const struct cred *old);
 	void (*cred_transfer)(struct cred *new, const struct cred *old);
 	int (*kernel_act_as)(struct cred *new, u32 secid);
 	int (*kernel_act_as)(struct cred *new, u32 secid);
 	int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
 	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_request)(char *kmod_name);
 	int (*kernel_module_from_file)(struct file *file);
 	int (*kernel_module_from_file)(struct file *file);
 	int (*task_fix_setuid) (struct cred *new, const struct cred *old,
 	int (*task_fix_setuid) (struct cred *new, const struct cred *old,
@@ -1837,6 +1847,7 @@ 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);
 void security_transfer_creds(struct cred *new, const struct cred *old);
 int security_kernel_act_as(struct cred *new, u32 secid);
 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_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_request(char *kmod_name);
 int security_kernel_module_from_file(struct file *file);
 int security_kernel_module_from_file(struct file *file);
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
@@ -2363,6 +2374,12 @@ static inline int security_kernel_create_files_as(struct cred *cred,
 	return 0;
 	return 0;
 }
 }
 
 
+static inline int security_kernel_fw_from_file(struct file *file,
+					       char *buf, size_t size)
+{
+	return 0;
+}
+
 static inline int security_kernel_module_request(char *kmod_name)
 static inline int security_kernel_module_request(char *kmod_name)
 {
 {
 	return 0;
 	return 0;

+ 2 - 0
include/linux/syscalls.h

@@ -866,4 +866,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
 			 unsigned long idx1, unsigned long idx2);
 			 unsigned long idx1, unsigned long idx2);
 asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
 asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
+asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
+			    const char __user *uargs);
 #endif
 #endif

+ 3 - 0
include/linux/tpm.h

@@ -39,6 +39,9 @@ struct tpm_class_ops {
 	int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
 	int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
 	void (*cancel) (struct tpm_chip *chip);
 	void (*cancel) (struct tpm_chip *chip);
 	u8 (*status) (struct tpm_chip *chip);
 	u8 (*status) (struct tpm_chip *chip);
+	bool (*update_timeouts)(struct tpm_chip *chip,
+				unsigned long *timeout_cap);
+
 };
 };
 
 
 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)

+ 18 - 0
include/linux/verify_pefile.h

@@ -0,0 +1,18 @@
+/* Signed PE file verification
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_VERIFY_PEFILE_H
+#define _LINUX_VERIFY_PEFILE_H
+
+extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
+				   struct key *trusted_keyring, bool *_trusted);
+
+#endif /* _LINUX_VERIFY_PEFILE_H */

+ 53 - 41
include/net/netlabel.h

@@ -139,7 +139,7 @@ struct netlbl_lsm_cache {
 };
 };
 
 
 /**
 /**
- * struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap
+ * struct netlbl_lsm_catmap - NetLabel LSM secattr category bitmap
  * @startbit: the value of the lowest order bit in the bitmap
  * @startbit: the value of the lowest order bit in the bitmap
  * @bitmap: the category bitmap
  * @bitmap: the category bitmap
  * @next: pointer to the next bitmap "node" or NULL
  * @next: pointer to the next bitmap "node" or NULL
@@ -162,10 +162,10 @@ struct netlbl_lsm_cache {
 #define NETLBL_CATMAP_SIZE              (NETLBL_CATMAP_MAPSIZE * \
 #define NETLBL_CATMAP_SIZE              (NETLBL_CATMAP_MAPSIZE * \
 					 NETLBL_CATMAP_MAPCNT)
 					 NETLBL_CATMAP_MAPCNT)
 #define NETLBL_CATMAP_BIT               (NETLBL_CATMAP_MAPTYPE)0x01
 #define NETLBL_CATMAP_BIT               (NETLBL_CATMAP_MAPTYPE)0x01
-struct netlbl_lsm_secattr_catmap {
+struct netlbl_lsm_catmap {
 	u32 startbit;
 	u32 startbit;
 	NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT];
 	NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT];
-	struct netlbl_lsm_secattr_catmap *next;
+	struct netlbl_lsm_catmap *next;
 };
 };
 
 
 /**
 /**
@@ -209,7 +209,7 @@ struct netlbl_lsm_secattr {
 	struct netlbl_lsm_cache *cache;
 	struct netlbl_lsm_cache *cache;
 	struct {
 	struct {
 		struct {
 		struct {
-			struct netlbl_lsm_secattr_catmap *cat;
+			struct netlbl_lsm_catmap *cat;
 			u32 lvl;
 			u32 lvl;
 		} mls;
 		} mls;
 		u32 secid;
 		u32 secid;
@@ -258,7 +258,7 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
 }
 }
 
 
 /**
 /**
- * netlbl_secattr_catmap_alloc - Allocate a LSM secattr catmap
+ * netlbl_catmap_alloc - Allocate a LSM secattr catmap
  * @flags: memory allocation flags
  * @flags: memory allocation flags
  *
  *
  * Description:
  * Description:
@@ -266,30 +266,28 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
  * on failure.
  * on failure.
  *
  *
  */
  */
-static inline struct netlbl_lsm_secattr_catmap *netlbl_secattr_catmap_alloc(
-	                                                           gfp_t flags)
+static inline struct netlbl_lsm_catmap *netlbl_catmap_alloc(gfp_t flags)
 {
 {
-	return kzalloc(sizeof(struct netlbl_lsm_secattr_catmap), flags);
+	return kzalloc(sizeof(struct netlbl_lsm_catmap), flags);
 }
 }
 
 
 /**
 /**
- * netlbl_secattr_catmap_free - Free a LSM secattr catmap
+ * netlbl_catmap_free - Free a LSM secattr catmap
  * @catmap: the category bitmap
  * @catmap: the category bitmap
  *
  *
  * Description:
  * Description:
  * Free a LSM secattr catmap.
  * Free a LSM secattr catmap.
  *
  *
  */
  */
-static inline void netlbl_secattr_catmap_free(
-	                              struct netlbl_lsm_secattr_catmap *catmap)
+static inline void netlbl_catmap_free(struct netlbl_lsm_catmap *catmap)
 {
 {
-	struct netlbl_lsm_secattr_catmap *iter;
+	struct netlbl_lsm_catmap *iter;
 
 
-	do {
+	while (catmap) {
 		iter = catmap;
 		iter = catmap;
 		catmap = catmap->next;
 		catmap = catmap->next;
 		kfree(iter);
 		kfree(iter);
-	} while (catmap);
+	}
 }
 }
 
 
 /**
 /**
@@ -321,7 +319,7 @@ static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
 	if (secattr->flags & NETLBL_SECATTR_CACHE)
 	if (secattr->flags & NETLBL_SECATTR_CACHE)
 		netlbl_secattr_cache_free(secattr->cache);
 		netlbl_secattr_cache_free(secattr->cache);
 	if (secattr->flags & NETLBL_SECATTR_MLS_CAT)
 	if (secattr->flags & NETLBL_SECATTR_MLS_CAT)
-		netlbl_secattr_catmap_free(secattr->attr.mls.cat);
+		netlbl_catmap_free(secattr->attr.mls.cat);
 }
 }
 
 
 /**
 /**
@@ -390,17 +388,22 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
 /*
 /*
  * LSM security attribute operations
  * LSM security attribute operations
  */
  */
-int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
-			       u32 offset);
-int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
-				   u32 offset);
-int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
-				 u32 bit,
-				 gfp_t flags);
-int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
-				 u32 start,
-				 u32 end,
-				 gfp_t flags);
+int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset);
+int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset);
+int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
+			  u32 *offset,
+			  unsigned long *bitmap);
+int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
+			 u32 bit,
+			 gfp_t flags);
+int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
+			 u32 start,
+			 u32 end,
+			 gfp_t flags);
+int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
+			  u32 offset,
+			  unsigned long bitmap,
+			  gfp_t flags);
 
 
 /*
 /*
  * LSM protocol operations (NetLabel LSM/kernel API)
  * LSM protocol operations (NetLabel LSM/kernel API)
@@ -492,30 +495,39 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
 {
 {
 	return -ENOSYS;
 	return -ENOSYS;
 }
 }
-static inline int netlbl_secattr_catmap_walk(
-	                              struct netlbl_lsm_secattr_catmap *catmap,
-				      u32 offset)
+static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap,
+				     u32 offset)
 {
 {
 	return -ENOENT;
 	return -ENOENT;
 }
 }
-static inline int netlbl_secattr_catmap_walk_rng(
-				      struct netlbl_lsm_secattr_catmap *catmap,
-				      u32 offset)
+static inline int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap,
+					u32 offset)
 {
 {
 	return -ENOENT;
 	return -ENOENT;
 }
 }
-static inline int netlbl_secattr_catmap_setbit(
-	                              struct netlbl_lsm_secattr_catmap *catmap,
-				      u32 bit,
-				      gfp_t flags)
+static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
+					u32 *offset,
+					unsigned long *bitmap)
 {
 {
 	return 0;
 	return 0;
 }
 }
-static inline int netlbl_secattr_catmap_setrng(
-	                              struct netlbl_lsm_secattr_catmap *catmap,
-				      u32 start,
-				      u32 end,
-				      gfp_t flags)
+static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
+				       u32 bit,
+				       gfp_t flags)
+{
+	return 0;
+}
+static inline int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
+				       u32 start,
+				       u32 end,
+				       gfp_t flags)
+{
+	return 0;
+}
+static int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
+				 u32 offset,
+				 unsigned long bitmap,
+				 gfp_t flags)
 {
 {
 	return 0;
 	return 0;
 }
 }

+ 3 - 1
include/uapi/asm-generic/unistd.h

@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
 __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
 __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
 #define __NR_renameat2 276
 #define __NR_renameat2 276
 __SYSCALL(__NR_renameat2, sys_renameat2)
 __SYSCALL(__NR_renameat2, sys_renameat2)
+#define __NR_seccomp 277
+__SYSCALL(__NR_seccomp, sys_seccomp)
 
 
 #undef __NR_syscalls
 #undef __NR_syscalls
-#define __NR_syscalls 277
+#define __NR_syscalls 278
 
 
 /*
 /*
  * All syscalls below here should go away really,
  * All syscalls below here should go away really,

+ 7 - 0
include/uapi/linux/seccomp.h

@@ -10,6 +10,13 @@
 #define SECCOMP_MODE_STRICT	1 /* uses hard-coded filter. */
 #define SECCOMP_MODE_STRICT	1 /* uses hard-coded filter. */
 #define SECCOMP_MODE_FILTER	2 /* uses user-supplied filter. */
 #define SECCOMP_MODE_FILTER	2 /* uses user-supplied filter. */
 
 
+/* Valid operations for seccomp syscall. */
+#define SECCOMP_SET_MODE_STRICT	0
+#define SECCOMP_SET_MODE_FILTER	1
+
+/* Valid flags for SECCOMP_SET_MODE_FILTER */
+#define SECCOMP_FILTER_FLAG_TSYNC	1
+
 /*
 /*
  * All BPF programs must return a 32-bit value.
  * All BPF programs must return a 32-bit value.
  * The bottom 16-bits are for optional return data.
  * The bottom 16-bits are for optional return data.

+ 1 - 1
kernel/audit.c

@@ -1677,7 +1677,7 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
 	audit_log_format(ab, " %s=", prefix);
 	audit_log_format(ab, " %s=", prefix);
 	CAP_FOR_EACH_U32(i) {
 	CAP_FOR_EACH_U32(i) {
 		audit_log_format(ab, "%08x",
 		audit_log_format(ab, "%08x",
-				 cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+				 cap->cap[CAP_LAST_U32 - i]);
 	}
 	}
 }
 }
 
 

+ 4 - 0
kernel/capability.c

@@ -258,6 +258,10 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
 		i++;
 		i++;
 	}
 	}
 
 
+	effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+	permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+	inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+
 	new = prepare_creds();
 	new = prepare_creds();
 	if (!new)
 	if (!new)
 		return -ENOMEM;
 		return -ENOMEM;

+ 48 - 1
kernel/fork.c

@@ -315,6 +315,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 		goto free_ti;
 		goto free_ti;
 
 
 	tsk->stack = ti;
 	tsk->stack = ti;
+#ifdef CONFIG_SECCOMP
+	/*
+	 * We must handle setting up seccomp filters once we're under
+	 * the sighand lock in case orig has changed between now and
+	 * then. Until then, filter must be NULL to avoid messing up
+	 * the usage counts on the error path calling free_task.
+	 */
+	tsk->seccomp.filter = NULL;
+#endif
 
 
 	setup_thread_stack(tsk, orig);
 	setup_thread_stack(tsk, orig);
 	clear_user_return_notifier(tsk);
 	clear_user_return_notifier(tsk);
@@ -1081,6 +1090,39 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 	return 0;
 	return 0;
 }
 }
 
 
+static void copy_seccomp(struct task_struct *p)
+{
+#ifdef CONFIG_SECCOMP
+	/*
+	 * Must be called with sighand->lock held, which is common to
+	 * all threads in the group. Holding cred_guard_mutex is not
+	 * needed because this new task is not yet running and cannot
+	 * be racing exec.
+	 */
+	BUG_ON(!spin_is_locked(&current->sighand->siglock));
+
+	/* Ref-count the new filter user, and assign it. */
+	get_seccomp_filter(current);
+	p->seccomp = current->seccomp;
+
+	/*
+	 * Explicitly enable no_new_privs here in case it got set
+	 * between the task_struct being duplicated and holding the
+	 * sighand lock. The seccomp state and nnp must be in sync.
+	 */
+	if (task_no_new_privs(current))
+		task_set_no_new_privs(p);
+
+	/*
+	 * If the parent gained a seccomp mode after copying thread
+	 * flags and between before we held the sighand lock, we have
+	 * to manually enable the seccomp thread flag here.
+	 */
+	if (p->seccomp.mode != SECCOMP_MODE_DISABLED)
+		set_tsk_thread_flag(p, TIF_SECCOMP);
+#endif
+}
+
 SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)
 SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)
 {
 {
 	current->clear_child_tid = tidptr;
 	current->clear_child_tid = tidptr;
@@ -1195,7 +1237,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 		goto fork_out;
 		goto fork_out;
 
 
 	ftrace_graph_init_task(p);
 	ftrace_graph_init_task(p);
-	get_seccomp_filter(p);
 
 
 	rt_mutex_init_task(p);
 	rt_mutex_init_task(p);
 
 
@@ -1434,6 +1475,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
 
 	spin_lock(&current->sighand->siglock);
 	spin_lock(&current->sighand->siglock);
 
 
+	/*
+	 * Copy seccomp details explicitly here, in case they were changed
+	 * before holding sighand lock.
+	 */
+	copy_seccomp(p);
+
 	/*
 	/*
 	 * Process group and session signals need to be delivered to just the
 	 * Process group and session signals need to be delivered to just the
 	 * parent before the fork or both the parent and the child after the
 	 * parent before the fork or both the parent and the child after the

+ 353 - 59
kernel/seccomp.c

@@ -18,15 +18,17 @@
 #include <linux/compat.h>
 #include <linux/compat.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/seccomp.h>
 #include <linux/seccomp.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
 
 
 /* #define SECCOMP_DEBUG 1 */
 /* #define SECCOMP_DEBUG 1 */
 
 
 #ifdef CONFIG_SECCOMP_FILTER
 #ifdef CONFIG_SECCOMP_FILTER
 #include <asm/syscall.h>
 #include <asm/syscall.h>
 #include <linux/filter.h>
 #include <linux/filter.h>
+#include <linux/pid.h>
 #include <linux/ptrace.h>
 #include <linux/ptrace.h>
 #include <linux/security.h>
 #include <linux/security.h>
-#include <linux/slab.h>
 #include <linux/tracehook.h>
 #include <linux/tracehook.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 
 
@@ -172,21 +174,24 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
  */
  */
 static u32 seccomp_run_filters(int syscall)
 static u32 seccomp_run_filters(int syscall)
 {
 {
-	struct seccomp_filter *f;
+	struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
 	struct seccomp_data sd;
 	struct seccomp_data sd;
 	u32 ret = SECCOMP_RET_ALLOW;
 	u32 ret = SECCOMP_RET_ALLOW;
 
 
 	/* Ensure unexpected behavior doesn't result in failing open. */
 	/* Ensure unexpected behavior doesn't result in failing open. */
-	if (WARN_ON(current->seccomp.filter == NULL))
+	if (unlikely(WARN_ON(f == NULL)))
 		return SECCOMP_RET_KILL;
 		return SECCOMP_RET_KILL;
 
 
+	/* Make sure cross-thread synced filter points somewhere sane. */
+	smp_read_barrier_depends();
+
 	populate_seccomp_data(&sd);
 	populate_seccomp_data(&sd);
 
 
 	/*
 	/*
 	 * All filters in the list are evaluated and the lowest BPF return
 	 * All filters in the list are evaluated and the lowest BPF return
 	 * value always takes priority (ignoring the DATA).
 	 * value always takes priority (ignoring the DATA).
 	 */
 	 */
-	for (f = current->seccomp.filter; f; f = f->prev) {
+	for (; f; f = f->prev) {
 		u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd);
 		u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd);
 
 
 		if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
 		if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
@@ -194,29 +199,159 @@ static u32 seccomp_run_filters(int syscall)
 	}
 	}
 	return ret;
 	return ret;
 }
 }
+#endif /* CONFIG_SECCOMP_FILTER */
+
+static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
+{
+	BUG_ON(!spin_is_locked(&current->sighand->siglock));
+
+	if (current->seccomp.mode && current->seccomp.mode != seccomp_mode)
+		return false;
+
+	return true;
+}
+
+static inline void seccomp_assign_mode(struct task_struct *task,
+				       unsigned long seccomp_mode)
+{
+	BUG_ON(!spin_is_locked(&task->sighand->siglock));
+
+	task->seccomp.mode = seccomp_mode;
+	/*
+	 * Make sure TIF_SECCOMP cannot be set before the mode (and
+	 * filter) is set.
+	 */
+	smp_mb__before_atomic();
+	set_tsk_thread_flag(task, TIF_SECCOMP);
+}
+
+#ifdef CONFIG_SECCOMP_FILTER
+/* Returns 1 if the parent is an ancestor of the child. */
+static int is_ancestor(struct seccomp_filter *parent,
+		       struct seccomp_filter *child)
+{
+	/* NULL is the root ancestor. */
+	if (parent == NULL)
+		return 1;
+	for (; child; child = child->prev)
+		if (child == parent)
+			return 1;
+	return 0;
+}
 
 
 /**
 /**
- * seccomp_attach_filter: Attaches a seccomp filter to current.
+ * seccomp_can_sync_threads: checks if all threads can be synchronized
+ *
+ * Expects sighand and cred_guard_mutex locks to be held.
+ *
+ * Returns 0 on success, -ve on error, or the pid of a thread which was
+ * either not in the correct seccomp mode or it did not have an ancestral
+ * seccomp filter.
+ */
+static inline pid_t seccomp_can_sync_threads(void)
+{
+	struct task_struct *thread, *caller;
+
+	BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
+	BUG_ON(!spin_is_locked(&current->sighand->siglock));
+
+	/* Validate all threads being eligible for synchronization. */
+	caller = current;
+	for_each_thread(caller, thread) {
+		pid_t failed;
+
+		/* Skip current, since it is initiating the sync. */
+		if (thread == caller)
+			continue;
+
+		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED ||
+		    (thread->seccomp.mode == SECCOMP_MODE_FILTER &&
+		     is_ancestor(thread->seccomp.filter,
+				 caller->seccomp.filter)))
+			continue;
+
+		/* Return the first thread that cannot be synchronized. */
+		failed = task_pid_vnr(thread);
+		/* If the pid cannot be resolved, then return -ESRCH */
+		if (unlikely(WARN_ON(failed == 0)))
+			failed = -ESRCH;
+		return failed;
+	}
+
+	return 0;
+}
+
+/**
+ * seccomp_sync_threads: sets all threads to use current's filter
+ *
+ * Expects sighand and cred_guard_mutex locks to be held, and for
+ * seccomp_can_sync_threads() to have returned success already
+ * without dropping the locks.
+ *
+ */
+static inline void seccomp_sync_threads(void)
+{
+	struct task_struct *thread, *caller;
+
+	BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
+	BUG_ON(!spin_is_locked(&current->sighand->siglock));
+
+	/* Synchronize all threads. */
+	caller = current;
+	for_each_thread(caller, thread) {
+		/* Skip current, since it needs no changes. */
+		if (thread == caller)
+			continue;
+
+		/* Get a task reference for the new leaf node. */
+		get_seccomp_filter(caller);
+		/*
+		 * Drop the task reference to the shared ancestor since
+		 * current's path will hold a reference.  (This also
+		 * allows a put before the assignment.)
+		 */
+		put_seccomp_filter(thread);
+		smp_store_release(&thread->seccomp.filter,
+				  caller->seccomp.filter);
+		/*
+		 * Opt the other thread into seccomp if needed.
+		 * As threads are considered to be trust-realm
+		 * equivalent (see ptrace_may_access), it is safe to
+		 * allow one thread to transition the other.
+		 */
+		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) {
+			/*
+			 * Don't let an unprivileged task work around
+			 * the no_new_privs restriction by creating
+			 * a thread that sets it up, enters seccomp,
+			 * then dies.
+			 */
+			if (task_no_new_privs(caller))
+				task_set_no_new_privs(thread);
+
+			seccomp_assign_mode(thread, SECCOMP_MODE_FILTER);
+		}
+	}
+}
+
+/**
+ * seccomp_prepare_filter: Prepares a seccomp filter for use.
  * @fprog: BPF program to install
  * @fprog: BPF program to install
  *
  *
- * Returns 0 on success or an errno on failure.
+ * Returns filter on success or an ERR_PTR on failure.
  */
  */
-static long seccomp_attach_filter(struct sock_fprog *fprog)
+static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
 {
 {
 	struct seccomp_filter *filter;
 	struct seccomp_filter *filter;
-	unsigned long fp_size = fprog->len * sizeof(struct sock_filter);
-	unsigned long total_insns = fprog->len;
+	unsigned long fp_size;
 	struct sock_filter *fp;
 	struct sock_filter *fp;
 	int new_len;
 	int new_len;
 	long ret;
 	long ret;
 
 
 	if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
 	if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
-		return -EINVAL;
-
-	for (filter = current->seccomp.filter; filter; filter = filter->prev)
-		total_insns += filter->prog->len + 4;  /* include a 4 instr penalty */
-	if (total_insns > MAX_INSNS_PER_PATH)
-		return -ENOMEM;
+		return ERR_PTR(-EINVAL);
+	BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
+	fp_size = fprog->len * sizeof(struct sock_filter);
 
 
 	/*
 	/*
 	 * Installing a seccomp filter requires that the task has
 	 * Installing a seccomp filter requires that the task has
@@ -224,14 +359,14 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
 	 * This avoids scenarios where unprivileged tasks can affect the
 	 * This avoids scenarios where unprivileged tasks can affect the
 	 * behavior of privileged children.
 	 * behavior of privileged children.
 	 */
 	 */
-	if (!current->no_new_privs &&
+	if (!task_no_new_privs(current) &&
 	    security_capable_noaudit(current_cred(), current_user_ns(),
 	    security_capable_noaudit(current_cred(), current_user_ns(),
 				     CAP_SYS_ADMIN) != 0)
 				     CAP_SYS_ADMIN) != 0)
-		return -EACCES;
+		return ERR_PTR(-EACCES);
 
 
 	fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
 	fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
 	if (!fp)
 	if (!fp)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 
 	/* Copy the instructions from fprog. */
 	/* Copy the instructions from fprog. */
 	ret = -EFAULT;
 	ret = -EFAULT;
@@ -275,13 +410,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
 
 
 	sk_filter_select_runtime(filter->prog);
 	sk_filter_select_runtime(filter->prog);
 
 
-	/*
-	 * If there is an existing filter, make it the prev and don't drop its
-	 * task reference.
-	 */
-	filter->prev = current->seccomp.filter;
-	current->seccomp.filter = filter;
-	return 0;
+	return filter;
 
 
 free_filter_prog:
 free_filter_prog:
 	kfree(filter->prog);
 	kfree(filter->prog);
@@ -289,19 +418,20 @@ free_filter:
 	kfree(filter);
 	kfree(filter);
 free_prog:
 free_prog:
 	kfree(fp);
 	kfree(fp);
-	return ret;
+	return ERR_PTR(ret);
 }
 }
 
 
 /**
 /**
- * seccomp_attach_user_filter - attaches a user-supplied sock_fprog
+ * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog
  * @user_filter: pointer to the user data containing a sock_fprog.
  * @user_filter: pointer to the user data containing a sock_fprog.
  *
  *
  * Returns 0 on success and non-zero otherwise.
  * Returns 0 on success and non-zero otherwise.
  */
  */
-static long seccomp_attach_user_filter(char __user *user_filter)
+static struct seccomp_filter *
+seccomp_prepare_user_filter(const char __user *user_filter)
 {
 {
 	struct sock_fprog fprog;
 	struct sock_fprog fprog;
-	long ret = -EFAULT;
+	struct seccomp_filter *filter = ERR_PTR(-EFAULT);
 
 
 #ifdef CONFIG_COMPAT
 #ifdef CONFIG_COMPAT
 	if (is_compat_task()) {
 	if (is_compat_task()) {
@@ -314,9 +444,56 @@ static long seccomp_attach_user_filter(char __user *user_filter)
 #endif
 #endif
 	if (copy_from_user(&fprog, user_filter, sizeof(fprog)))
 	if (copy_from_user(&fprog, user_filter, sizeof(fprog)))
 		goto out;
 		goto out;
-	ret = seccomp_attach_filter(&fprog);
+	filter = seccomp_prepare_filter(&fprog);
 out:
 out:
-	return ret;
+	return filter;
+}
+
+/**
+ * seccomp_attach_filter: validate and attach filter
+ * @flags:  flags to change filter behavior
+ * @filter: seccomp filter to add to the current process
+ *
+ * Caller must be holding current->sighand->siglock lock.
+ *
+ * Returns 0 on success, -ve on error.
+ */
+static long seccomp_attach_filter(unsigned int flags,
+				  struct seccomp_filter *filter)
+{
+	unsigned long total_insns;
+	struct seccomp_filter *walker;
+
+	BUG_ON(!spin_is_locked(&current->sighand->siglock));
+
+	/* Validate resulting filter length. */
+	total_insns = filter->prog->len;
+	for (walker = current->seccomp.filter; walker; walker = walker->prev)
+		total_insns += walker->prog->len + 4;  /* 4 instr penalty */
+	if (total_insns > MAX_INSNS_PER_PATH)
+		return -ENOMEM;
+
+	/* If thread sync has been requested, check that it is possible. */
+	if (flags & SECCOMP_FILTER_FLAG_TSYNC) {
+		int ret;
+
+		ret = seccomp_can_sync_threads();
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * If there is an existing filter, make it the prev and don't drop its
+	 * task reference.
+	 */
+	filter->prev = current->seccomp.filter;
+	current->seccomp.filter = filter;
+
+	/* Now that the new filter is in place, synchronize to all threads. */
+	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
+		seccomp_sync_threads();
+
+	return 0;
 }
 }
 
 
 /* get_seccomp_filter - increments the reference count of the filter on @tsk */
 /* get_seccomp_filter - increments the reference count of the filter on @tsk */
@@ -329,6 +506,14 @@ void get_seccomp_filter(struct task_struct *tsk)
 	atomic_inc(&orig->usage);
 	atomic_inc(&orig->usage);
 }
 }
 
 
+static inline void seccomp_filter_free(struct seccomp_filter *filter)
+{
+	if (filter) {
+		sk_filter_free(filter->prog);
+		kfree(filter);
+	}
+}
+
 /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
 /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
 void put_seccomp_filter(struct task_struct *tsk)
 void put_seccomp_filter(struct task_struct *tsk)
 {
 {
@@ -337,8 +522,7 @@ void put_seccomp_filter(struct task_struct *tsk)
 	while (orig && atomic_dec_and_test(&orig->usage)) {
 	while (orig && atomic_dec_and_test(&orig->usage)) {
 		struct seccomp_filter *freeme = orig;
 		struct seccomp_filter *freeme = orig;
 		orig = orig->prev;
 		orig = orig->prev;
-		sk_filter_free(freeme->prog);
-		kfree(freeme);
+		seccomp_filter_free(freeme);
 	}
 	}
 }
 }
 
 
@@ -382,12 +566,17 @@ static int mode1_syscalls_32[] = {
 
 
 int __secure_computing(int this_syscall)
 int __secure_computing(int this_syscall)
 {
 {
-	int mode = current->seccomp.mode;
 	int exit_sig = 0;
 	int exit_sig = 0;
 	int *syscall;
 	int *syscall;
 	u32 ret;
 	u32 ret;
 
 
-	switch (mode) {
+	/*
+	 * Make sure that any changes to mode from another thread have
+	 * been seen after TIF_SECCOMP was seen.
+	 */
+	rmb();
+
+	switch (current->seccomp.mode) {
 	case SECCOMP_MODE_STRICT:
 	case SECCOMP_MODE_STRICT:
 		syscall = mode1_syscalls;
 		syscall = mode1_syscalls;
 #ifdef CONFIG_COMPAT
 #ifdef CONFIG_COMPAT
@@ -473,47 +662,152 @@ long prctl_get_seccomp(void)
 }
 }
 
 
 /**
 /**
- * prctl_set_seccomp: configures current->seccomp.mode
- * @seccomp_mode: requested mode to use
- * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
+ * seccomp_set_mode_strict: internal function for setting strict seccomp
  *
  *
- * This function may be called repeatedly with a @seccomp_mode of
- * SECCOMP_MODE_FILTER to install additional filters.  Every filter
- * successfully installed will be evaluated (in reverse order) for each system
- * call the task makes.
+ * Once current->seccomp.mode is non-zero, it may not be changed.
+ *
+ * Returns 0 on success or -EINVAL on failure.
+ */
+static long seccomp_set_mode_strict(void)
+{
+	const unsigned long seccomp_mode = SECCOMP_MODE_STRICT;
+	long ret = -EINVAL;
+
+	spin_lock_irq(&current->sighand->siglock);
+
+	if (!seccomp_may_assign_mode(seccomp_mode))
+		goto out;
+
+#ifdef TIF_NOTSC
+	disable_TSC();
+#endif
+	seccomp_assign_mode(current, seccomp_mode);
+	ret = 0;
+
+out:
+	spin_unlock_irq(&current->sighand->siglock);
+
+	return ret;
+}
+
+#ifdef CONFIG_SECCOMP_FILTER
+/**
+ * seccomp_set_mode_filter: internal function for setting seccomp filter
+ * @flags:  flags to change filter behavior
+ * @filter: struct sock_fprog containing filter
+ *
+ * This function may be called repeatedly to install additional filters.
+ * Every filter successfully installed will be evaluated (in reverse order)
+ * for each system call the task makes.
  *
  *
  * Once current->seccomp.mode is non-zero, it may not be changed.
  * Once current->seccomp.mode is non-zero, it may not be changed.
  *
  *
  * Returns 0 on success or -EINVAL on failure.
  * Returns 0 on success or -EINVAL on failure.
  */
  */
-long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
+static long seccomp_set_mode_filter(unsigned int flags,
+				    const char __user *filter)
 {
 {
+	const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
+	struct seccomp_filter *prepared = NULL;
 	long ret = -EINVAL;
 	long ret = -EINVAL;
 
 
-	if (current->seccomp.mode &&
-	    current->seccomp.mode != seccomp_mode)
+	/* Validate flags. */
+	if (flags & ~SECCOMP_FILTER_FLAG_MASK)
+		return -EINVAL;
+
+	/* Prepare the new filter before holding any locks. */
+	prepared = seccomp_prepare_user_filter(filter);
+	if (IS_ERR(prepared))
+		return PTR_ERR(prepared);
+
+	/*
+	 * Make sure we cannot change seccomp or nnp state via TSYNC
+	 * while another thread is in the middle of calling exec.
+	 */
+	if (flags & SECCOMP_FILTER_FLAG_TSYNC &&
+	    mutex_lock_killable(&current->signal->cred_guard_mutex))
+		goto out_free;
+
+	spin_lock_irq(&current->sighand->siglock);
+
+	if (!seccomp_may_assign_mode(seccomp_mode))
+		goto out;
+
+	ret = seccomp_attach_filter(flags, prepared);
+	if (ret)
 		goto out;
 		goto out;
+	/* Do not free the successfully attached filter. */
+	prepared = NULL;
+
+	seccomp_assign_mode(current, seccomp_mode);
+out:
+	spin_unlock_irq(&current->sighand->siglock);
+	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
+		mutex_unlock(&current->signal->cred_guard_mutex);
+out_free:
+	seccomp_filter_free(prepared);
+	return ret;
+}
+#else
+static inline long seccomp_set_mode_filter(unsigned int flags,
+					   const char __user *filter)
+{
+	return -EINVAL;
+}
+#endif
+
+/* Common entry point for both prctl and syscall. */
+static long do_seccomp(unsigned int op, unsigned int flags,
+		       const char __user *uargs)
+{
+	switch (op) {
+	case SECCOMP_SET_MODE_STRICT:
+		if (flags != 0 || uargs != NULL)
+			return -EINVAL;
+		return seccomp_set_mode_strict();
+	case SECCOMP_SET_MODE_FILTER:
+		return seccomp_set_mode_filter(flags, uargs);
+	default:
+		return -EINVAL;
+	}
+}
+
+SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags,
+			 const char __user *, uargs)
+{
+	return do_seccomp(op, flags, uargs);
+}
+
+/**
+ * prctl_set_seccomp: configures current->seccomp.mode
+ * @seccomp_mode: requested mode to use
+ * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
+ *
+ * Returns 0 on success or -EINVAL on failure.
+ */
+long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
+{
+	unsigned int op;
+	char __user *uargs;
 
 
 	switch (seccomp_mode) {
 	switch (seccomp_mode) {
 	case SECCOMP_MODE_STRICT:
 	case SECCOMP_MODE_STRICT:
-		ret = 0;
-#ifdef TIF_NOTSC
-		disable_TSC();
-#endif
+		op = SECCOMP_SET_MODE_STRICT;
+		/*
+		 * Setting strict mode through prctl always ignored filter,
+		 * so make sure it is always NULL here to pass the internal
+		 * check in do_seccomp().
+		 */
+		uargs = NULL;
 		break;
 		break;
-#ifdef CONFIG_SECCOMP_FILTER
 	case SECCOMP_MODE_FILTER:
 	case SECCOMP_MODE_FILTER:
-		ret = seccomp_attach_user_filter(filter);
-		if (ret)
-			goto out;
+		op = SECCOMP_SET_MODE_FILTER;
+		uargs = filter;
 		break;
 		break;
-#endif
 	default:
 	default:
-		goto out;
+		return -EINVAL;
 	}
 	}
 
 
-	current->seccomp.mode = seccomp_mode;
-	set_thread_flag(TIF_SECCOMP);
-out:
-	return ret;
+	/* prctl interface doesn't have flags, so they are always zero. */
+	return do_seccomp(op, 0, uargs);
 }
 }

+ 2 - 2
kernel/sys.c

@@ -1990,12 +1990,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 		if (arg2 != 1 || arg3 || arg4 || arg5)
 		if (arg2 != 1 || arg3 || arg4 || arg5)
 			return -EINVAL;
 			return -EINVAL;
 
 
-		current->no_new_privs = 1;
+		task_set_no_new_privs(current);
 		break;
 		break;
 	case PR_GET_NO_NEW_PRIVS:
 	case PR_GET_NO_NEW_PRIVS:
 		if (arg2 || arg3 || arg4 || arg5)
 		if (arg2 || arg3 || arg4 || arg5)
 			return -EINVAL;
 			return -EINVAL;
-		return current->no_new_privs ? 1 : 0;
+		return task_no_new_privs(current) ? 1 : 0;
 	case PR_GET_THP_DISABLE:
 	case PR_GET_THP_DISABLE:
 		if (arg2 || arg3 || arg4 || arg5)
 		if (arg2 || arg3 || arg4 || arg5)
 			return -EINVAL;
 			return -EINVAL;

+ 3 - 0
kernel/sys_ni.c

@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at);
 
 
 /* compare kernel pointers */
 /* compare kernel pointers */
 cond_syscall(sys_kcmp);
 cond_syscall(sys_kcmp);
+
+/* operate on Secure Computing state */
+cond_syscall(sys_seccomp);

+ 1 - 0
kernel/system_keyring.c

@@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void)
 			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
 			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
 			       PTR_ERR(key));
 			       PTR_ERR(key));
 		} else {
 		} else {
+			set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
 			pr_notice("Loaded X.509 cert '%s'\n",
 			pr_notice("Loaded X.509 cert '%s'\n",
 				  key_ref_to_ptr(key)->description);
 				  key_ref_to_ptr(key)->description);
 			key_ref_put(key);
 			key_ref_put(key);

+ 2 - 1
lib/Kconfig

@@ -451,7 +451,8 @@ config MPILIB
 
 
 config SIGNATURE
 config SIGNATURE
 	tristate
 	tristate
-	depends on KEYS && CRYPTO
+	depends on KEYS
+	select CRYPTO
 	select CRYPTO_SHA1
 	select CRYPTO_SHA1
 	select MPILIB
 	select MPILIB
 	help
 	help

+ 14 - 12
net/ceph/crypto.c

@@ -8,6 +8,7 @@
 #include <linux/key-type.h>
 #include <linux/key-type.h>
 
 
 #include <keys/ceph-type.h>
 #include <keys/ceph-type.h>
+#include <keys/user-type.h>
 #include <linux/ceph/decode.h>
 #include <linux/ceph/decode.h>
 #include "crypto.h"
 #include "crypto.h"
 
 
@@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 	}
 	}
 }
 }
 
 
-static int ceph_key_instantiate(struct key *key,
-				struct key_preparsed_payload *prep)
+static int ceph_key_preparse(struct key_preparsed_payload *prep)
 {
 {
 	struct ceph_crypto_key *ckey;
 	struct ceph_crypto_key *ckey;
 	size_t datalen = prep->datalen;
 	size_t datalen = prep->datalen;
@@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key,
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		goto err;
 		goto err;
 
 
-	ret = key_payload_reserve(key, datalen);
-	if (ret < 0)
-		goto err;
-
 	ret = -ENOMEM;
 	ret = -ENOMEM;
 	ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
 	ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
 	if (!ckey)
 	if (!ckey)
@@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key,
 	if (ret < 0)
 	if (ret < 0)
 		goto err_ckey;
 		goto err_ckey;
 
 
-	key->payload.data = ckey;
+	prep->payload[0] = ckey;
+	prep->quotalen = datalen;
 	return 0;
 	return 0;
 
 
 err_ckey:
 err_ckey:
@@ -459,12 +456,15 @@ err:
 	return ret;
 	return ret;
 }
 }
 
 
-static int ceph_key_match(const struct key *key, const void *description)
+static void ceph_key_free_preparse(struct key_preparsed_payload *prep)
 {
 {
-	return strcmp(key->description, description) == 0;
+	struct ceph_crypto_key *ckey = prep->payload[0];
+	ceph_crypto_key_destroy(ckey);
+	kfree(ckey);
 }
 }
 
 
-static void ceph_key_destroy(struct key *key) {
+static void ceph_key_destroy(struct key *key)
+{
 	struct ceph_crypto_key *ckey = key->payload.data;
 	struct ceph_crypto_key *ckey = key->payload.data;
 
 
 	ceph_crypto_key_destroy(ckey);
 	ceph_crypto_key_destroy(ckey);
@@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) {
 
 
 struct key_type key_type_ceph = {
 struct key_type key_type_ceph = {
 	.name		= "ceph",
 	.name		= "ceph",
-	.instantiate	= ceph_key_instantiate,
-	.match		= ceph_key_match,
+	.preparse	= ceph_key_preparse,
+	.free_preparse	= ceph_key_free_preparse,
+	.instantiate	= generic_key_instantiate,
+	.match		= user_match,
 	.destroy	= ceph_key_destroy,
 	.destroy	= ceph_key_destroy,
 };
 };
 
 

+ 25 - 18
net/dns_resolver/dns_key.c

@@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache;
 #define	DNS_ERRORNO_OPTION	"dnserror"
 #define	DNS_ERRORNO_OPTION	"dnserror"
 
 
 /*
 /*
- * Instantiate a user defined key for dns_resolver.
+ * Preparse instantiation data for a dns_resolver key.
  *
  *
  * The data must be a NUL-terminated string, with the NUL char accounted in
  * The data must be a NUL-terminated string, with the NUL char accounted in
  * datalen.
  * datalen.
@@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache;
  *        "ip1,ip2,...#foo=bar"
  *        "ip1,ip2,...#foo=bar"
  */
  */
 static int
 static int
-dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
+dns_resolver_preparse(struct key_preparsed_payload *prep)
 {
 {
 	struct user_key_payload *upayload;
 	struct user_key_payload *upayload;
 	unsigned long derrno;
 	unsigned long derrno;
 	int ret;
 	int ret;
-	size_t datalen = prep->datalen, result_len = 0;
+	int datalen = prep->datalen, result_len = 0;
 	const char *data = prep->data, *end, *opt;
 	const char *data = prep->data, *end, *opt;
 
 
-	kenter("%%%d,%s,'%*.*s',%zu",
-	       key->serial, key->description,
-	       (int)datalen, (int)datalen, data, datalen);
+	kenter("'%*.*s',%u", datalen, datalen, data, datalen);
 
 
 	if (datalen <= 1 || !data || data[datalen - 1] != '\0')
 	if (datalen <= 1 || !data || data[datalen - 1] != '\0')
 		return -EINVAL;
 		return -EINVAL;
@@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
 			opt_len = next_opt - opt;
 			opt_len = next_opt - opt;
 			if (!opt_len) {
 			if (!opt_len) {
 				printk(KERN_WARNING
 				printk(KERN_WARNING
-				       "Empty option to dns_resolver key %d\n",
-				       key->serial);
+				       "Empty option to dns_resolver key\n");
 				return -EINVAL;
 				return -EINVAL;
 			}
 			}
 
 
@@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
 					goto bad_option_value;
 					goto bad_option_value;
 
 
 				kdebug("dns error no. = %lu", derrno);
 				kdebug("dns error no. = %lu", derrno);
-				key->type_data.x[0] = -derrno;
+				prep->type_data[0] = ERR_PTR(-derrno);
 				continue;
 				continue;
 			}
 			}
 
 
 		bad_option_value:
 		bad_option_value:
 			printk(KERN_WARNING
 			printk(KERN_WARNING
-			       "Option '%*.*s' to dns_resolver key %d:"
+			       "Option '%*.*s' to dns_resolver key:"
 			       " bad/missing value\n",
 			       " bad/missing value\n",
-			       opt_nlen, opt_nlen, opt, key->serial);
+			       opt_nlen, opt_nlen, opt);
 			return -EINVAL;
 			return -EINVAL;
 		} while (opt = next_opt + 1, opt < end);
 		} while (opt = next_opt + 1, opt < end);
 	}
 	}
 
 
 	/* don't cache the result if we're caching an error saying there's no
 	/* don't cache the result if we're caching an error saying there's no
 	 * result */
 	 * result */
-	if (key->type_data.x[0]) {
-		kleave(" = 0 [h_error %ld]", key->type_data.x[0]);
+	if (prep->type_data[0]) {
+		kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
 		return 0;
 		return 0;
 	}
 	}
 
 
 	kdebug("store result");
 	kdebug("store result");
-	ret = key_payload_reserve(key, result_len);
-	if (ret < 0)
-		return -EINVAL;
+	prep->quotalen = result_len;
 
 
 	upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
 	upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
 	if (!upayload) {
 	if (!upayload) {
@@ -159,12 +154,22 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
 	upayload->datalen = result_len;
 	upayload->datalen = result_len;
 	memcpy(upayload->data, data, result_len);
 	memcpy(upayload->data, data, result_len);
 	upayload->data[result_len] = '\0';
 	upayload->data[result_len] = '\0';
-	rcu_assign_pointer(key->payload.data, upayload);
 
 
+	prep->payload[0] = upayload;
 	kleave(" = 0");
 	kleave(" = 0");
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Clean up the preparse data
+ */
+static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
+{
+	pr_devel("==>%s()\n", __func__);
+
+	kfree(prep->payload[0]);
+}
+
 /*
 /*
  * The description is of the form "[<type>:]<domain_name>"
  * The description is of the form "[<type>:]<domain_name>"
  *
  *
@@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key,
 
 
 struct key_type key_type_dns_resolver = {
 struct key_type key_type_dns_resolver = {
 	.name		= "dns_resolver",
 	.name		= "dns_resolver",
-	.instantiate	= dns_resolver_instantiate,
+	.preparse	= dns_resolver_preparse,
+	.free_preparse	= dns_resolver_free_preparse,
+	.instantiate	= generic_key_instantiate,
 	.match		= dns_resolver_match,
 	.match		= dns_resolver_match,
 	.revoke		= user_revoke,
 	.revoke		= user_revoke,
 	.destroy	= user_destroy,
 	.destroy	= user_destroy,

+ 1 - 0
net/dns_resolver/dns_query.c

@@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
 	}
 	}
 
 
 	down_read(&rkey->sem);
 	down_read(&rkey->sem);
+	set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
 	rkey->perm |= KEY_USR_VIEW;
 	rkey->perm |= KEY_USR_VIEW;
 
 
 	ret = key_validate(rkey);
 	ret = key_validate(rkey);

+ 16 - 31
net/ipv4/cipso_ipv4.c

@@ -890,8 +890,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
 	}
 	}
 
 
 	for (;;) {
 	for (;;) {
-		host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
-						       host_spot + 1);
+		host_spot = netlbl_catmap_walk(secattr->attr.mls.cat,
+					       host_spot + 1);
 		if (host_spot < 0)
 		if (host_spot < 0)
 			break;
 			break;
 
 
@@ -973,7 +973,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
 				return -EPERM;
 				return -EPERM;
 			break;
 			break;
 		}
 		}
-		ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
+		ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
 						       host_spot,
 						       host_spot,
 						       GFP_ATOMIC);
 						       GFP_ATOMIC);
 		if (ret_val != 0)
 		if (ret_val != 0)
@@ -1039,8 +1039,7 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def,
 	u32 cat_iter = 0;
 	u32 cat_iter = 0;
 
 
 	for (;;) {
 	for (;;) {
-		cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
-						 cat + 1);
+		cat = netlbl_catmap_walk(secattr->attr.mls.cat, cat + 1);
 		if (cat < 0)
 		if (cat < 0)
 			break;
 			break;
 		if ((cat_iter + 2) > net_cat_len)
 		if ((cat_iter + 2) > net_cat_len)
@@ -1075,9 +1074,9 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
 	u32 iter;
 	u32 iter;
 
 
 	for (iter = 0; iter < net_cat_len; iter += 2) {
 	for (iter = 0; iter < net_cat_len; iter += 2) {
-		ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
-				get_unaligned_be16(&net_cat[iter]),
-				GFP_ATOMIC);
+		ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat,
+					     get_unaligned_be16(&net_cat[iter]),
+					     GFP_ATOMIC);
 		if (ret_val != 0)
 		if (ret_val != 0)
 			return ret_val;
 			return ret_val;
 	}
 	}
@@ -1155,8 +1154,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
 		return -ENOSPC;
 		return -ENOSPC;
 
 
 	for (;;) {
 	for (;;) {
-		iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
-						  iter + 1);
+		iter = netlbl_catmap_walk(secattr->attr.mls.cat, iter + 1);
 		if (iter < 0)
 		if (iter < 0)
 			break;
 			break;
 		cat_size += (iter == 0 ? 0 : sizeof(u16));
 		cat_size += (iter == 0 ? 0 : sizeof(u16));
@@ -1164,8 +1162,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
 			return -ENOSPC;
 			return -ENOSPC;
 		array[array_cnt++] = iter;
 		array[array_cnt++] = iter;
 
 
-		iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat,
-						      iter);
+		iter = netlbl_catmap_walkrng(secattr->attr.mls.cat, iter);
 		if (iter < 0)
 		if (iter < 0)
 			return -EFAULT;
 			return -EFAULT;
 		cat_size += sizeof(u16);
 		cat_size += sizeof(u16);
@@ -1217,10 +1214,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
 		else
 		else
 			cat_low = 0;
 			cat_low = 0;
 
 
-		ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat,
-						       cat_low,
-						       cat_high,
-						       GFP_ATOMIC);
+		ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat,
+					       cat_low,
+					       cat_high,
+					       GFP_ATOMIC);
 		if (ret_val != 0)
 		if (ret_val != 0)
 			return ret_val;
 			return ret_val;
 	}
 	}
@@ -1335,16 +1332,12 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 
 
 	if (tag_len > 4) {
 	if (tag_len > 4) {
-		secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
-		if (secattr->attr.mls.cat == NULL)
-			return -ENOMEM;
-
 		ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
 		ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
 						    &tag[4],
 						    &tag[4],
 						    tag_len - 4,
 						    tag_len - 4,
 						    secattr);
 						    secattr);
 		if (ret_val != 0) {
 		if (ret_val != 0) {
-			netlbl_secattr_catmap_free(secattr->attr.mls.cat);
+			netlbl_catmap_free(secattr->attr.mls.cat);
 			return ret_val;
 			return ret_val;
 		}
 		}
 
 
@@ -1430,16 +1423,12 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 
 
 	if (tag_len > 4) {
 	if (tag_len > 4) {
-		secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
-		if (secattr->attr.mls.cat == NULL)
-			return -ENOMEM;
-
 		ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
 		ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
 						     &tag[4],
 						     &tag[4],
 						     tag_len - 4,
 						     tag_len - 4,
 						     secattr);
 						     secattr);
 		if (ret_val != 0) {
 		if (ret_val != 0) {
-			netlbl_secattr_catmap_free(secattr->attr.mls.cat);
+			netlbl_catmap_free(secattr->attr.mls.cat);
 			return ret_val;
 			return ret_val;
 		}
 		}
 
 
@@ -1524,16 +1513,12 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 	secattr->flags |= NETLBL_SECATTR_MLS_LVL;
 
 
 	if (tag_len > 4) {
 	if (tag_len > 4) {
-		secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
-		if (secattr->attr.mls.cat == NULL)
-			return -ENOMEM;
-
 		ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
 		ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
 						    &tag[4],
 						    &tag[4],
 						    tag_len - 4,
 						    tag_len - 4,
 						    secattr);
 						    secattr);
 		if (ret_val != 0) {
 		if (ret_val != 0) {
-			netlbl_secattr_catmap_free(secattr->attr.mls.cat);
+			netlbl_catmap_free(secattr->attr.mls.cat);
 			return ret_val;
 			return ret_val;
 		}
 		}
 
 

+ 227 - 100
net/netlabel/netlabel_kapi.c

@@ -405,8 +405,72 @@ out_entry:
  * Security Attribute Functions
  * Security Attribute Functions
  */
  */
 
 
+#define _CM_F_NONE	0x00000000
+#define _CM_F_ALLOC	0x00000001
+#define _CM_F_WALK	0x00000002
+
 /**
 /**
- * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit
+ * _netlbl_catmap_getnode - Get a individual node from a catmap
+ * @catmap: pointer to the category bitmap
+ * @offset: the requested offset
+ * @cm_flags: catmap flags, see _CM_F_*
+ * @gfp_flags: memory allocation flags
+ *
+ * Description:
+ * Iterate through the catmap looking for the node associated with @offset.
+ * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node,
+ * one will be created and inserted into the catmap.  If the _CM_F_WALK flag is
+ * set in @cm_flags and there is no associated node, the next highest node will
+ * be returned.  Returns a pointer to the node on success, NULL on failure.
+ *
+ */
+static struct netlbl_lsm_catmap *_netlbl_catmap_getnode(
+					     struct netlbl_lsm_catmap **catmap,
+					     u32 offset,
+					     unsigned int cm_flags,
+					     gfp_t gfp_flags)
+{
+	struct netlbl_lsm_catmap *iter = *catmap;
+	struct netlbl_lsm_catmap *prev = NULL;
+
+	if (iter == NULL)
+		goto catmap_getnode_alloc;
+	if (offset < iter->startbit)
+		goto catmap_getnode_walk;
+	while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
+		prev = iter;
+		iter = iter->next;
+	}
+	if (iter == NULL || offset < iter->startbit)
+		goto catmap_getnode_walk;
+
+	return iter;
+
+catmap_getnode_walk:
+	if (cm_flags & _CM_F_WALK)
+		return iter;
+catmap_getnode_alloc:
+	if (!(cm_flags & _CM_F_ALLOC))
+		return NULL;
+
+	iter = netlbl_catmap_alloc(gfp_flags);
+	if (iter == NULL)
+		return NULL;
+	iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1);
+
+	if (prev == NULL) {
+		iter->next = *catmap;
+		*catmap = iter;
+	} else {
+		iter->next = prev->next;
+		prev->next = iter;
+	}
+
+	return iter;
+}
+
+/**
+ * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit
  * @catmap: the category bitmap
  * @catmap: the category bitmap
  * @offset: the offset to start searching at, in bits
  * @offset: the offset to start searching at, in bits
  *
  *
@@ -415,54 +479,51 @@ out_entry:
  * returns the spot of the first set bit or -ENOENT if no bits are set.
  * returns the spot of the first set bit or -ENOENT if no bits are set.
  *
  *
  */
  */
-int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
-			       u32 offset)
+int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
 {
 {
-	struct netlbl_lsm_secattr_catmap *iter = catmap;
-	u32 node_idx;
-	u32 node_bit;
+	struct netlbl_lsm_catmap *iter = catmap;
+	u32 idx;
+	u32 bit;
 	NETLBL_CATMAP_MAPTYPE bitmap;
 	NETLBL_CATMAP_MAPTYPE bitmap;
 
 
+	iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
+	if (iter == NULL)
+		return -ENOENT;
 	if (offset > iter->startbit) {
 	if (offset > iter->startbit) {
-		while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
-			iter = iter->next;
-			if (iter == NULL)
-				return -ENOENT;
-		}
-		node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
-		node_bit = offset - iter->startbit -
-			   (NETLBL_CATMAP_MAPSIZE * node_idx);
+		offset -= iter->startbit;
+		idx = offset / NETLBL_CATMAP_MAPSIZE;
+		bit = offset % NETLBL_CATMAP_MAPSIZE;
 	} else {
 	} else {
-		node_idx = 0;
-		node_bit = 0;
+		idx = 0;
+		bit = 0;
 	}
 	}
-	bitmap = iter->bitmap[node_idx] >> node_bit;
+	bitmap = iter->bitmap[idx] >> bit;
 
 
 	for (;;) {
 	for (;;) {
 		if (bitmap != 0) {
 		if (bitmap != 0) {
 			while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
 			while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
 				bitmap >>= 1;
 				bitmap >>= 1;
-				node_bit++;
+				bit++;
 			}
 			}
 			return iter->startbit +
 			return iter->startbit +
-				(NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit;
+			       (NETLBL_CATMAP_MAPSIZE * idx) + bit;
 		}
 		}
-		if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
+		if (++idx >= NETLBL_CATMAP_MAPCNT) {
 			if (iter->next != NULL) {
 			if (iter->next != NULL) {
 				iter = iter->next;
 				iter = iter->next;
-				node_idx = 0;
+				idx = 0;
 			} else
 			} else
 				return -ENOENT;
 				return -ENOENT;
 		}
 		}
-		bitmap = iter->bitmap[node_idx];
-		node_bit = 0;
+		bitmap = iter->bitmap[idx];
+		bit = 0;
 	}
 	}
 
 
 	return -ENOENT;
 	return -ENOENT;
 }
 }
 
 
 /**
 /**
- * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits
+ * netlbl_catmap_walkrng - Find the end of a string of set bits
  * @catmap: the category bitmap
  * @catmap: the category bitmap
  * @offset: the offset to start searching at, in bits
  * @offset: the offset to start searching at, in bits
  *
  *
@@ -472,57 +533,105 @@ int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
  * the end of the bitmap.
  * the end of the bitmap.
  *
  *
  */
  */
-int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
-				   u32 offset)
+int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset)
 {
 {
-	struct netlbl_lsm_secattr_catmap *iter = catmap;
-	u32 node_idx;
-	u32 node_bit;
+	struct netlbl_lsm_catmap *iter;
+	struct netlbl_lsm_catmap *prev = NULL;
+	u32 idx;
+	u32 bit;
 	NETLBL_CATMAP_MAPTYPE bitmask;
 	NETLBL_CATMAP_MAPTYPE bitmask;
 	NETLBL_CATMAP_MAPTYPE bitmap;
 	NETLBL_CATMAP_MAPTYPE bitmap;
 
 
+	iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0);
+	if (iter == NULL)
+		return -ENOENT;
 	if (offset > iter->startbit) {
 	if (offset > iter->startbit) {
-		while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
-			iter = iter->next;
-			if (iter == NULL)
-				return -ENOENT;
-		}
-		node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
-		node_bit = offset - iter->startbit -
-			   (NETLBL_CATMAP_MAPSIZE * node_idx);
+		offset -= iter->startbit;
+		idx = offset / NETLBL_CATMAP_MAPSIZE;
+		bit = offset % NETLBL_CATMAP_MAPSIZE;
 	} else {
 	} else {
-		node_idx = 0;
-		node_bit = 0;
+		idx = 0;
+		bit = 0;
 	}
 	}
-	bitmask = NETLBL_CATMAP_BIT << node_bit;
+	bitmask = NETLBL_CATMAP_BIT << bit;
 
 
 	for (;;) {
 	for (;;) {
-		bitmap = iter->bitmap[node_idx];
+		bitmap = iter->bitmap[idx];
 		while (bitmask != 0 && (bitmap & bitmask) != 0) {
 		while (bitmask != 0 && (bitmap & bitmask) != 0) {
 			bitmask <<= 1;
 			bitmask <<= 1;
-			node_bit++;
+			bit++;
 		}
 		}
 
 
-		if (bitmask != 0)
+		if (prev && idx == 0 && bit == 0)
+			return prev->startbit + NETLBL_CATMAP_SIZE - 1;
+		else if (bitmask != 0)
 			return iter->startbit +
 			return iter->startbit +
-				(NETLBL_CATMAP_MAPSIZE * node_idx) +
-				node_bit - 1;
-		else if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
+				(NETLBL_CATMAP_MAPSIZE * idx) + bit - 1;
+		else if (++idx >= NETLBL_CATMAP_MAPCNT) {
 			if (iter->next == NULL)
 			if (iter->next == NULL)
-				return iter->startbit +	NETLBL_CATMAP_SIZE - 1;
+				return iter->startbit + NETLBL_CATMAP_SIZE - 1;
+			prev = iter;
 			iter = iter->next;
 			iter = iter->next;
-			node_idx = 0;
+			idx = 0;
 		}
 		}
 		bitmask = NETLBL_CATMAP_BIT;
 		bitmask = NETLBL_CATMAP_BIT;
-		node_bit = 0;
+		bit = 0;
 	}
 	}
 
 
 	return -ENOENT;
 	return -ENOENT;
 }
 }
 
 
 /**
 /**
- * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap
- * @catmap: the category bitmap
+ * netlbl_catmap_getlong - Export an unsigned long bitmap
+ * @catmap: pointer to the category bitmap
+ * @offset: pointer to the requested offset
+ * @bitmap: the exported bitmap
+ *
+ * Description:
+ * Export a bitmap with an offset greater than or equal to @offset and return
+ * it in @bitmap.  The @offset must be aligned to an unsigned long and will be
+ * updated on return if different from what was requested; if the catmap is
+ * empty at the requested offset and beyond, the @offset is set to (u32)-1.
+ * Returns zero on sucess, negative values on failure.
+ *
+ */
+int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
+			  u32 *offset,
+			  unsigned long *bitmap)
+{
+	struct netlbl_lsm_catmap *iter;
+	u32 off = *offset;
+	u32 idx;
+
+	/* only allow aligned offsets */
+	if ((off & (BITS_PER_LONG - 1)) != 0)
+		return -EINVAL;
+
+	if (off < catmap->startbit) {
+		off = catmap->startbit;
+		*offset = off;
+	}
+	iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0);
+	if (iter == NULL) {
+		*offset = (u32)-1;
+		return 0;
+	}
+
+	if (off < iter->startbit) {
+		off = iter->startbit;
+		*offset = off;
+	} else
+		off -= iter->startbit;
+
+	idx = off / NETLBL_CATMAP_MAPSIZE;
+	*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE);
+
+	return 0;
+}
+
+/**
+ * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap
+ * @catmap: pointer to the category bitmap
  * @bit: the bit to set
  * @bit: the bit to set
  * @flags: memory allocation flags
  * @flags: memory allocation flags
  *
  *
@@ -531,36 +640,27 @@ int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
  * negative values on failure.
  * negative values on failure.
  *
  *
  */
  */
-int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
-				 u32 bit,
-				 gfp_t flags)
+int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
+			 u32 bit,
+			 gfp_t flags)
 {
 {
-	struct netlbl_lsm_secattr_catmap *iter = catmap;
-	u32 node_bit;
-	u32 node_idx;
+	struct netlbl_lsm_catmap *iter;
+	u32 idx;
 
 
-	while (iter->next != NULL &&
-	       bit >= (iter->startbit + NETLBL_CATMAP_SIZE))
-		iter = iter->next;
-	if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
-		iter->next = netlbl_secattr_catmap_alloc(flags);
-		if (iter->next == NULL)
-			return -ENOMEM;
-		iter = iter->next;
-		iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1);
-	}
+	iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags);
+	if (iter == NULL)
+		return -ENOMEM;
 
 
-	/* gcc always rounds to zero when doing integer division */
-	node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
-	node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx);
-	iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit;
+	bit -= iter->startbit;
+	idx = bit / NETLBL_CATMAP_MAPSIZE;
+	iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 /**
 /**
- * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap
- * @catmap: the category bitmap
+ * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
+ * @catmap: pointer to the category bitmap
  * @start: the starting bit
  * @start: the starting bit
  * @end: the last bit in the string
  * @end: the last bit in the string
  * @flags: memory allocation flags
  * @flags: memory allocation flags
@@ -570,36 +670,63 @@ int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
  * on success, negative values on failure.
  * on success, negative values on failure.
  *
  *
  */
  */
-int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
-				 u32 start,
-				 u32 end,
-				 gfp_t flags)
+int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap,
+			 u32 start,
+			 u32 end,
+			 gfp_t flags)
 {
 {
-	int ret_val = 0;
-	struct netlbl_lsm_secattr_catmap *iter = catmap;
-	u32 iter_max_spot;
-	u32 spot;
-
-	/* XXX - This could probably be made a bit faster by combining writes
-	 * to the catmap instead of setting a single bit each time, but for
-	 * right now skipping to the start of the range in the catmap should
-	 * be a nice improvement over calling the individual setbit function
-	 * repeatedly from a loop. */
-
-	while (iter->next != NULL &&
-	       start >= (iter->startbit + NETLBL_CATMAP_SIZE))
-		iter = iter->next;
-	iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
-
-	for (spot = start; spot <= end && ret_val == 0; spot++) {
-		if (spot >= iter_max_spot && iter->next != NULL) {
-			iter = iter->next;
-			iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
-		}
-		ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags);
+	int rc = 0;
+	u32 spot = start;
+
+	while (rc == 0 && spot <= end) {
+		if (((spot & (BITS_PER_LONG - 1)) != 0) &&
+		    ((end - spot) > BITS_PER_LONG)) {
+			rc = netlbl_catmap_setlong(catmap,
+						   spot,
+						   (unsigned long)-1,
+						   flags);
+			spot += BITS_PER_LONG;
+		} else
+			rc = netlbl_catmap_setbit(catmap, spot++, flags);
 	}
 	}
 
 
-	return ret_val;
+	return rc;
+}
+
+/**
+ * netlbl_catmap_setlong - Import an unsigned long bitmap
+ * @catmap: pointer to the category bitmap
+ * @offset: offset to the start of the imported bitmap
+ * @bitmap: the bitmap to import
+ * @flags: memory allocation flags
+ *
+ * Description:
+ * Import the bitmap specified in @bitmap into @catmap, using the offset
+ * in @offset.  The offset must be aligned to an unsigned long.  Returns zero
+ * on success, negative values on failure.
+ *
+ */
+int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
+			  u32 offset,
+			  unsigned long bitmap,
+			  gfp_t flags)
+{
+	struct netlbl_lsm_catmap *iter;
+	u32 idx;
+
+	/* only allow aligned offsets */
+	if ((offset & (BITS_PER_LONG - 1)) != 0)
+		return -EINVAL;
+
+	iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags);
+	if (iter == NULL)
+		return -ENOMEM;
+
+	offset -= iter->startbit;
+	idx = offset / NETLBL_CATMAP_MAPSIZE;
+	iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE);
+
+	return 0;
 }
 }
 
 
 /*
 /*

+ 97 - 68
net/rxrpc/ar-key.c

@@ -26,8 +26,10 @@
 #include "ar-internal.h"
 #include "ar-internal.h"
 
 
 static int rxrpc_vet_description_s(const char *);
 static int rxrpc_vet_description_s(const char *);
-static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
-static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
+static int rxrpc_preparse(struct key_preparsed_payload *);
+static int rxrpc_preparse_s(struct key_preparsed_payload *);
+static void rxrpc_free_preparse(struct key_preparsed_payload *);
+static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
 static void rxrpc_destroy(struct key *);
 static void rxrpc_destroy(struct key *);
 static void rxrpc_destroy_s(struct key *);
 static void rxrpc_destroy_s(struct key *);
 static void rxrpc_describe(const struct key *, struct seq_file *);
 static void rxrpc_describe(const struct key *, struct seq_file *);
@@ -39,7 +41,9 @@ static long rxrpc_read(const struct key *, char __user *, size_t);
  */
  */
 struct key_type key_type_rxrpc = {
 struct key_type key_type_rxrpc = {
 	.name		= "rxrpc",
 	.name		= "rxrpc",
-	.instantiate	= rxrpc_instantiate,
+	.preparse	= rxrpc_preparse,
+	.free_preparse	= rxrpc_free_preparse,
+	.instantiate	= generic_key_instantiate,
 	.match		= user_match,
 	.match		= user_match,
 	.destroy	= rxrpc_destroy,
 	.destroy	= rxrpc_destroy,
 	.describe	= rxrpc_describe,
 	.describe	= rxrpc_describe,
@@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc);
 struct key_type key_type_rxrpc_s = {
 struct key_type key_type_rxrpc_s = {
 	.name		= "rxrpc_s",
 	.name		= "rxrpc_s",
 	.vet_description = rxrpc_vet_description_s,
 	.vet_description = rxrpc_vet_description_s,
-	.instantiate	= rxrpc_instantiate_s,
+	.preparse	= rxrpc_preparse_s,
+	.free_preparse	= rxrpc_free_preparse_s,
+	.instantiate	= generic_key_instantiate,
 	.match		= user_match,
 	.match		= user_match,
 	.destroy	= rxrpc_destroy_s,
 	.destroy	= rxrpc_destroy_s,
 	.describe	= rxrpc_describe,
 	.describe	= rxrpc_describe,
@@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc)
  * parse an RxKAD type XDR format token
  * parse an RxKAD type XDR format token
  * - the caller guarantees we have at least 4 words
  * - the caller guarantees we have at least 4 words
  */
  */
-static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
-				       unsigned int toklen)
+static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
+				    size_t datalen,
+				    const __be32 *xdr, unsigned int toklen)
 {
 {
 	struct rxrpc_key_token *token, **pptoken;
 	struct rxrpc_key_token *token, **pptoken;
 	size_t plen;
 	size_t plen;
 	u32 tktlen;
 	u32 tktlen;
-	int ret;
 
 
 	_enter(",{%x,%x,%x,%x},%u",
 	_enter(",{%x,%x,%x,%x},%u",
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@@ -103,9 +109,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
 		return -EKEYREJECTED;
 		return -EKEYREJECTED;
 
 
 	plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
 	plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
-	ret = key_payload_reserve(key, key->datalen + plen);
-	if (ret < 0)
-		return ret;
+	prep->quotalen = datalen + plen;
 
 
 	plen -= sizeof(*token);
 	plen -= sizeof(*token);
 	token = kzalloc(sizeof(*token), GFP_KERNEL);
 	token = kzalloc(sizeof(*token), GFP_KERNEL);
@@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
 		       token->kad->ticket[6], token->kad->ticket[7]);
 		       token->kad->ticket[6], token->kad->ticket[7]);
 
 
 	/* count the number of tokens attached */
 	/* count the number of tokens attached */
-	key->type_data.x[0]++;
+	prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
 
 
 	/* attach the data */
 	/* attach the data */
-	for (pptoken = (struct rxrpc_key_token **)&key->payload.data;
+	for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
 	     *pptoken;
 	     *pptoken;
 	     pptoken = &(*pptoken)->next)
 	     pptoken = &(*pptoken)->next)
 		continue;
 		continue;
 	*pptoken = token;
 	*pptoken = token;
-	if (token->kad->expiry < key->expiry)
-		key->expiry = token->kad->expiry;
+	if (token->kad->expiry < prep->expiry)
+		prep->expiry = token->kad->expiry;
 
 
 	_leave(" = 0");
 	_leave(" = 0");
 	return 0;
 	return 0;
@@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
  * parse an RxK5 type XDR format token
  * parse an RxK5 type XDR format token
  * - the caller guarantees we have at least 4 words
  * - the caller guarantees we have at least 4 words
  */
  */
-static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
-				      unsigned int toklen)
+static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
+				   size_t datalen,
+				   const __be32 *xdr, unsigned int toklen)
 {
 {
 	struct rxrpc_key_token *token, **pptoken;
 	struct rxrpc_key_token *token, **pptoken;
 	struct rxk5_key *rxk5;
 	struct rxk5_key *rxk5;
@@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
 
 
 	/* reserve some payload space for this subkey - the length of the token
 	/* reserve some payload space for this subkey - the length of the token
 	 * is a reasonable approximation */
 	 * is a reasonable approximation */
-	ret = key_payload_reserve(key, key->datalen + toklen);
-	if (ret < 0)
-		return ret;
+	prep->quotalen = datalen + toklen;
 
 
 	token = kzalloc(sizeof(*token), GFP_KERNEL);
 	token = kzalloc(sizeof(*token), GFP_KERNEL);
 	if (!token)
 	if (!token)
@@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
 	if (toklen != 0)
 	if (toklen != 0)
 		goto inval;
 		goto inval;
 
 
-	/* attach the payload to the key */
-	for (pptoken = (struct rxrpc_key_token **)&key->payload.data;
+	/* attach the payload */
+	for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
 	     *pptoken;
 	     *pptoken;
 	     pptoken = &(*pptoken)->next)
 	     pptoken = &(*pptoken)->next)
 		continue;
 		continue;
 	*pptoken = token;
 	*pptoken = token;
-	if (token->kad->expiry < key->expiry)
-		key->expiry = token->kad->expiry;
+	if (token->kad->expiry < prep->expiry)
+		prep->expiry = token->kad->expiry;
 
 
 	_leave(" = 0");
 	_leave(" = 0");
 	return 0;
 	return 0;
@@ -545,16 +548,17 @@ error:
  * attempt to parse the data as the XDR format
  * attempt to parse the data as the XDR format
  * - the caller guarantees we have more than 7 words
  * - the caller guarantees we have more than 7 words
  */
  */
-static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen)
+static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
 {
 {
-	const __be32 *xdr = data, *token;
+	const __be32 *xdr = prep->data, *token;
 	const char *cp;
 	const char *cp;
 	unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
 	unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
+	size_t datalen = prep->datalen;
 	int ret;
 	int ret;
 
 
 	_enter(",{%x,%x,%x,%x},%zu",
 	_enter(",{%x,%x,%x,%x},%zu",
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
 	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
-	       datalen);
+	       prep->datalen);
 
 
 	if (datalen > AFSTOKEN_LENGTH_MAX)
 	if (datalen > AFSTOKEN_LENGTH_MAX)
 		goto not_xdr;
 		goto not_xdr;
@@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal
 
 
 		switch (sec_ix) {
 		switch (sec_ix) {
 		case RXRPC_SECURITY_RXKAD:
 		case RXRPC_SECURITY_RXKAD:
-			ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen);
+			ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen);
 			if (ret != 0)
 			if (ret != 0)
 				goto error;
 				goto error;
 			break;
 			break;
 
 
 		case RXRPC_SECURITY_RXK5:
 		case RXRPC_SECURITY_RXK5:
-			ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen);
+			ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen);
 			if (ret != 0)
 			if (ret != 0)
 				goto error;
 				goto error;
 			break;
 			break;
@@ -665,8 +669,9 @@ error:
 }
 }
 
 
 /*
 /*
- * instantiate an rxrpc defined key
- * data should be of the form:
+ * Preparse an rxrpc defined key.
+ *
+ * Data should be of the form:
  *	OFFSET	LEN	CONTENT
  *	OFFSET	LEN	CONTENT
  *	0	4	key interface version number
  *	0	4	key interface version number
  *	4	2	security index (type)
  *	4	2	security index (type)
@@ -678,7 +683,7 @@ error:
  *
  *
  * if no data is provided, then a no-security key is made
  * if no data is provided, then a no-security key is made
  */
  */
-static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)
+static int rxrpc_preparse(struct key_preparsed_payload *prep)
 {
 {
 	const struct rxrpc_key_data_v1 *v1;
 	const struct rxrpc_key_data_v1 *v1;
 	struct rxrpc_key_token *token, **pp;
 	struct rxrpc_key_token *token, **pp;
@@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
 	u32 kver;
 	u32 kver;
 	int ret;
 	int ret;
 
 
-	_enter("{%x},,%zu", key_serial(key), prep->datalen);
+	_enter("%zu", prep->datalen);
 
 
 	/* handle a no-security key */
 	/* handle a no-security key */
 	if (!prep->data && prep->datalen == 0)
 	if (!prep->data && prep->datalen == 0)
@@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
 
 
 	/* determine if the XDR payload format is being used */
 	/* determine if the XDR payload format is being used */
 	if (prep->datalen > 7 * 4) {
 	if (prep->datalen > 7 * 4) {
-		ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
+		ret = rxrpc_preparse_xdr(prep);
 		if (ret != -EPROTO)
 		if (ret != -EPROTO)
 			return ret;
 			return ret;
 	}
 	}
@@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
 		goto error;
 		goto error;
 
 
 	plen = sizeof(*token->kad) + v1->ticket_length;
 	plen = sizeof(*token->kad) + v1->ticket_length;
-	ret = key_payload_reserve(key, plen + sizeof(*token));
-	if (ret < 0)
-		goto error;
+	prep->quotalen = plen + sizeof(*token);
 
 
 	ret = -ENOMEM;
 	ret = -ENOMEM;
 	token = kzalloc(sizeof(*token), GFP_KERNEL);
 	token = kzalloc(sizeof(*token), GFP_KERNEL);
@@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
 	memcpy(&token->kad->session_key, &v1->session_key, 8);
 	memcpy(&token->kad->session_key, &v1->session_key, 8);
 	memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
 	memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
 
 
-	/* attach the data */
-	key->type_data.x[0]++;
+	/* count the number of tokens attached */
+	prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
 
 
-	pp = (struct rxrpc_key_token **)&key->payload.data;
+	/* attach the data */
+	pp = (struct rxrpc_key_token **)&prep->payload[0];
 	while (*pp)
 	while (*pp)
 		pp = &(*pp)->next;
 		pp = &(*pp)->next;
 	*pp = token;
 	*pp = token;
-	if (token->kad->expiry < key->expiry)
-		key->expiry = token->kad->expiry;
+	if (token->kad->expiry < prep->expiry)
+		prep->expiry = token->kad->expiry;
 	token = NULL;
 	token = NULL;
 	ret = 0;
 	ret = 0;
 
 
@@ -781,20 +785,55 @@ error:
 }
 }
 
 
 /*
 /*
- * instantiate a server secret key
- * data should be a pointer to the 8-byte secret key
+ * Free token list.
  */
  */
-static int rxrpc_instantiate_s(struct key *key,
-			       struct key_preparsed_payload *prep)
+static void rxrpc_free_token_list(struct rxrpc_key_token *token)
+{
+	struct rxrpc_key_token *next;
+
+	for (; token; token = next) {
+		next = token->next;
+		switch (token->security_index) {
+		case RXRPC_SECURITY_RXKAD:
+			kfree(token->kad);
+			break;
+		case RXRPC_SECURITY_RXK5:
+			if (token->k5)
+				rxrpc_rxk5_free(token->k5);
+			break;
+		default:
+			printk(KERN_ERR "Unknown token type %x on rxrpc key\n",
+			       token->security_index);
+			BUG();
+		}
+
+		kfree(token);
+	}
+}
+
+/*
+ * Clean up preparse data.
+ */
+static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
+{
+	rxrpc_free_token_list(prep->payload[0]);
+}
+
+/*
+ * Preparse a server secret key.
+ *
+ * The data should be the 8-byte secret key.
+ */
+static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
 {
 {
 	struct crypto_blkcipher *ci;
 	struct crypto_blkcipher *ci;
 
 
-	_enter("{%x},,%zu", key_serial(key), prep->datalen);
+	_enter("%zu", prep->datalen);
 
 
 	if (prep->datalen != 8)
 	if (prep->datalen != 8)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	memcpy(&key->type_data, prep->data, 8);
+	memcpy(&prep->type_data, prep->data, 8);
 
 
 	ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
 	ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(ci)) {
 	if (IS_ERR(ci)) {
@@ -805,36 +844,26 @@ static int rxrpc_instantiate_s(struct key *key,
 	if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
 	if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
 		BUG();
 		BUG();
 
 
-	key->payload.data = ci;
+	prep->payload[0] = ci;
 	_leave(" = 0");
 	_leave(" = 0");
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Clean up preparse data.
+ */
+static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
+{
+	if (prep->payload[0])
+		crypto_free_blkcipher(prep->payload[0]);
+}
+
 /*
 /*
  * dispose of the data dangling from the corpse of a rxrpc key
  * dispose of the data dangling from the corpse of a rxrpc key
  */
  */
 static void rxrpc_destroy(struct key *key)
 static void rxrpc_destroy(struct key *key)
 {
 {
-	struct rxrpc_key_token *token;
-
-	while ((token = key->payload.data)) {
-		key->payload.data = token->next;
-		switch (token->security_index) {
-		case RXRPC_SECURITY_RXKAD:
-			kfree(token->kad);
-			break;
-		case RXRPC_SECURITY_RXK5:
-			if (token->k5)
-				rxrpc_rxk5_free(token->k5);
-			break;
-		default:
-			printk(KERN_ERR "Unknown token type %x on rxrpc key\n",
-			       token->security_index);
-			BUG();
-		}
-
-		kfree(token);
-	}
+	rxrpc_free_token_list(key->payload.data);
 }
 }
 
 
 /*
 /*

+ 0 - 1
scripts/selinux/genheaders/Makefile

@@ -2,4 +2,3 @@ hostprogs-y	:= genheaders
 HOST_EXTRACFLAGS += -Isecurity/selinux/include
 HOST_EXTRACFLAGS += -Isecurity/selinux/include
 
 
 always		:= $(hostprogs-y)
 always		:= $(hostprogs-y)
-clean-files	:= $(hostprogs-y)

+ 1 - 1
scripts/selinux/mdp/Makefile

@@ -2,4 +2,4 @@ hostprogs-y	:= mdp
 HOST_EXTRACFLAGS += -Isecurity/selinux/include
 HOST_EXTRACFLAGS += -Isecurity/selinux/include
 
 
 always		:= $(hostprogs-y)
 always		:= $(hostprogs-y)
-clean-files	:= $(hostprogs-y) policy.* file_contexts
+clean-files	:= policy.* file_contexts

+ 2 - 2
security/apparmor/domain.c

@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 	 * There is no exception for unconfined as change_hat is not
 	 * There is no exception for unconfined as change_hat is not
 	 * available.
 	 * available.
 	 */
 	 */
-	if (current->no_new_privs)
+	if (task_no_new_privs(current))
 		return -EPERM;
 		return -EPERM;
 
 
 	/* released below */
 	/* released below */
@@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
 	 * no_new_privs is set because this aways results in a reduction
 	 * no_new_privs is set because this aways results in a reduction
 	 * of permissions.
 	 * of permissions.
 	 */
 	 */
-	if (current->no_new_privs && !unconfined(profile)) {
+	if (task_no_new_privs(current) && !unconfined(profile)) {
 		put_cred(cred);
 		put_cred(cred);
 		return -EPERM;
 		return -EPERM;
 	}
 	}

+ 6 - 0
security/capability.c

@@ -401,6 +401,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
 	return 0;
 	return 0;
 }
 }
 
 
+static int cap_kernel_fw_from_file(struct file *file, char *buf, size_t size)
+{
+	return 0;
+}
+
 static int cap_kernel_module_request(char *kmod_name)
 static int cap_kernel_module_request(char *kmod_name)
 {
 {
 	return 0;
 	return 0;
@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, cred_transfer);
 	set_to_cap_if_null(ops, cred_transfer);
 	set_to_cap_if_null(ops, kernel_act_as);
 	set_to_cap_if_null(ops, kernel_act_as);
 	set_to_cap_if_null(ops, kernel_create_files_as);
 	set_to_cap_if_null(ops, kernel_create_files_as);
+	set_to_cap_if_null(ops, kernel_fw_from_file);
 	set_to_cap_if_null(ops, kernel_module_request);
 	set_to_cap_if_null(ops, kernel_module_request);
 	set_to_cap_if_null(ops, kernel_module_from_file);
 	set_to_cap_if_null(ops, kernel_module_from_file);
 	set_to_cap_if_null(ops, task_fix_setuid);
 	set_to_cap_if_null(ops, task_fix_setuid);

+ 33 - 42
security/commoncap.c

@@ -421,6 +421,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
 		cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
 		cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
 	}
 	}
 
 
+	cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+	cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -822,15 +825,20 @@ int cap_task_setnice(struct task_struct *p, int nice)
  * Implement PR_CAPBSET_DROP.  Attempt to remove the specified capability from
  * Implement PR_CAPBSET_DROP.  Attempt to remove the specified capability from
  * the current task's bounding set.  Returns 0 on success, -ve on error.
  * the current task's bounding set.  Returns 0 on success, -ve on error.
  */
  */
-static long cap_prctl_drop(struct cred *new, unsigned long cap)
+static int cap_prctl_drop(unsigned long cap)
 {
 {
+	struct cred *new;
+
 	if (!ns_capable(current_user_ns(), CAP_SETPCAP))
 	if (!ns_capable(current_user_ns(), CAP_SETPCAP))
 		return -EPERM;
 		return -EPERM;
 	if (!cap_valid(cap))
 	if (!cap_valid(cap))
 		return -EINVAL;
 		return -EINVAL;
 
 
+	new = prepare_creds();
+	if (!new)
+		return -ENOMEM;
 	cap_lower(new->cap_bset, cap);
 	cap_lower(new->cap_bset, cap);
-	return 0;
+	return commit_creds(new);
 }
 }
 
 
 /**
 /**
@@ -848,26 +856,17 @@ static long cap_prctl_drop(struct cred *new, unsigned long cap)
 int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 		   unsigned long arg4, unsigned long arg5)
 		   unsigned long arg4, unsigned long arg5)
 {
 {
+	const struct cred *old = current_cred();
 	struct cred *new;
 	struct cred *new;
-	long error = 0;
-
-	new = prepare_creds();
-	if (!new)
-		return -ENOMEM;
 
 
 	switch (option) {
 	switch (option) {
 	case PR_CAPBSET_READ:
 	case PR_CAPBSET_READ:
-		error = -EINVAL;
 		if (!cap_valid(arg2))
 		if (!cap_valid(arg2))
-			goto error;
-		error = !!cap_raised(new->cap_bset, arg2);
-		goto no_change;
+			return -EINVAL;
+		return !!cap_raised(old->cap_bset, arg2);
 
 
 	case PR_CAPBSET_DROP:
 	case PR_CAPBSET_DROP:
-		error = cap_prctl_drop(new, arg2);
-		if (error < 0)
-			goto error;
-		goto changed;
+		return cap_prctl_drop(arg2);
 
 
 	/*
 	/*
 	 * The next four prctl's remain to assist with transitioning a
 	 * The next four prctl's remain to assist with transitioning a
@@ -889,10 +888,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 	 * capability-based-privilege environment.
 	 * capability-based-privilege environment.
 	 */
 	 */
 	case PR_SET_SECUREBITS:
 	case PR_SET_SECUREBITS:
-		error = -EPERM;
-		if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
-		     & (new->securebits ^ arg2))			/*[1]*/
-		    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))	/*[2]*/
+		if ((((old->securebits & SECURE_ALL_LOCKS) >> 1)
+		     & (old->securebits ^ arg2))			/*[1]*/
+		    || ((old->securebits & SECURE_ALL_LOCKS & ~arg2))	/*[2]*/
 		    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))	/*[3]*/
 		    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))	/*[3]*/
 		    || (cap_capable(current_cred(),
 		    || (cap_capable(current_cred(),
 				    current_cred()->user_ns, CAP_SETPCAP,
 				    current_cred()->user_ns, CAP_SETPCAP,
@@ -906,46 +904,39 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 			 */
 			 */
 		    )
 		    )
 			/* cannot change a locked bit */
 			/* cannot change a locked bit */
-			goto error;
+			return -EPERM;
+
+		new = prepare_creds();
+		if (!new)
+			return -ENOMEM;
 		new->securebits = arg2;
 		new->securebits = arg2;
-		goto changed;
+		return commit_creds(new);
 
 
 	case PR_GET_SECUREBITS:
 	case PR_GET_SECUREBITS:
-		error = new->securebits;
-		goto no_change;
+		return old->securebits;
 
 
 	case PR_GET_KEEPCAPS:
 	case PR_GET_KEEPCAPS:
-		if (issecure(SECURE_KEEP_CAPS))
-			error = 1;
-		goto no_change;
+		return !!issecure(SECURE_KEEP_CAPS);
 
 
 	case PR_SET_KEEPCAPS:
 	case PR_SET_KEEPCAPS:
-		error = -EINVAL;
 		if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
 		if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
-			goto error;
-		error = -EPERM;
+			return -EINVAL;
 		if (issecure(SECURE_KEEP_CAPS_LOCKED))
 		if (issecure(SECURE_KEEP_CAPS_LOCKED))
-			goto error;
+			return -EPERM;
+
+		new = prepare_creds();
+		if (!new)
+			return -ENOMEM;
 		if (arg2)
 		if (arg2)
 			new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
 			new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
 		else
 		else
 			new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
 			new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
-		goto changed;
+		return commit_creds(new);
 
 
 	default:
 	default:
 		/* No functionality available - continue with default */
 		/* No functionality available - continue with default */
-		error = -ENOSYS;
-		goto error;
+		return -ENOSYS;
 	}
 	}
-
-	/* Functionality provided */
-changed:
-	return commit_creds(new);
-
-no_change:
-error:
-	abort_creds(new);
-	return error;
 }
 }
 
 
 /**
 /**

+ 28 - 0
security/integrity/digsig.c

@@ -13,7 +13,9 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 
 #include <linux/err.h>
 #include <linux/err.h>
+#include <linux/sched.h>
 #include <linux/rbtree.h>
 #include <linux/rbtree.h>
+#include <linux/cred.h>
 #include <linux/key-type.h>
 #include <linux/key-type.h>
 #include <linux/digsig.h>
 #include <linux/digsig.h>
 
 
@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
 static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
 static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
 	"_evm",
 	"_evm",
 	"_module",
 	"_module",
+#ifndef CONFIG_IMA_TRUSTED_KEYRING
 	"_ima",
 	"_ima",
+#else
+	".ima",
+#endif
 };
 };
 
 
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
@@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 
 
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
+
+int integrity_init_keyring(const unsigned int id)
+{
+	const struct cred *cred = current_cred();
+	int err = 0;
+
+	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
+				    KGIDT_INIT(0), cred,
+				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				     KEY_USR_VIEW | KEY_USR_READ |
+				     KEY_USR_WRITE | KEY_USR_SEARCH),
+				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
+	if (!IS_ERR(keyring[id]))
+		set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
+	else {
+		err = PTR_ERR(keyring[id]);
+		pr_info("Can't allocate %s keyring (%d)\n",
+			keyring_name[id], err);
+		keyring[id] = NULL;
+	}
+	return err;
+}

+ 10 - 0
security/integrity/ima/Kconfig

@@ -123,3 +123,13 @@ config IMA_APPRAISE
 	  For more information on integrity appraisal refer to:
 	  For more information on integrity appraisal refer to:
 	  <http://linux-ima.sourceforge.net>
 	  <http://linux-ima.sourceforge.net>
 	  If unsure, say N.
 	  If unsure, say N.
+
+config IMA_TRUSTED_KEYRING
+	bool "Require all keys on the .ima keyring be signed"
+	depends on IMA_APPRAISE && 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
+	   keyring be signed by a key on the system trusted keyring.

+ 14 - 1
security/integrity/ima/ima.h

@@ -158,7 +158,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
 
 /* IMA policy related functions */
 /* IMA policy related functions */
-enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
+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 ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
 		     int flags);
 		     int flags);
@@ -171,6 +171,7 @@ void ima_delete_rules(void);
 #define IMA_APPRAISE_ENFORCE	0x01
 #define IMA_APPRAISE_ENFORCE	0x01
 #define IMA_APPRAISE_FIX	0x02
 #define IMA_APPRAISE_FIX	0x02
 #define IMA_APPRAISE_MODULES	0x04
 #define IMA_APPRAISE_MODULES	0x04
+#define IMA_APPRAISE_FIRMWARE	0x08
 
 
 #ifdef CONFIG_IMA_APPRAISE
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
 int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
@@ -249,4 +250,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 #endif /* CONFIG_IMA_LSM_RULES */
 #endif /* CONFIG_IMA_LSM_RULES */
+
+#ifdef CONFIG_IMA_TRUSTED_KEYRING
+static inline int ima_init_keyring(const unsigned int id)
+{
+	return integrity_init_keyring(id);
+}
+#else
+static inline int ima_init_keyring(const unsigned int id)
+{
+	return 0;
+}
+#endif /* CONFIG_IMA_TRUSTED_KEYRING */
 #endif
 #endif

+ 9 - 1
security/integrity/ima/ima_appraise.c

@@ -75,6 +75,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
 		return iint->ima_bprm_status;
 		return iint->ima_bprm_status;
 	case MODULE_CHECK:
 	case MODULE_CHECK:
 		return iint->ima_module_status;
 		return iint->ima_module_status;
+	case FIRMWARE_CHECK:
+		return iint->ima_firmware_status;
 	case FILE_CHECK:
 	case FILE_CHECK:
 	default:
 	default:
 		return iint->ima_file_status;
 		return iint->ima_file_status;
@@ -94,6 +96,9 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
 	case MODULE_CHECK:
 	case MODULE_CHECK:
 		iint->ima_module_status = status;
 		iint->ima_module_status = status;
 		break;
 		break;
+	case FIRMWARE_CHECK:
+		iint->ima_firmware_status = status;
+		break;
 	case FILE_CHECK:
 	case FILE_CHECK:
 	default:
 	default:
 		iint->ima_file_status = status;
 		iint->ima_file_status = status;
@@ -113,6 +118,9 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func)
 	case MODULE_CHECK:
 	case MODULE_CHECK:
 		iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED);
 		iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED);
 		break;
 		break;
+	case FIRMWARE_CHECK:
+		iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED);
+		break;
 	case FILE_CHECK:
 	case FILE_CHECK:
 	default:
 	default:
 		iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
 		iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED);
@@ -214,7 +222,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
 		hash_start = 1;
 		hash_start = 1;
 	case IMA_XATTR_DIGEST:
 	case IMA_XATTR_DIGEST:
 		if (iint->flags & IMA_DIGSIG_REQUIRED) {
 		if (iint->flags & IMA_DIGSIG_REQUIRED) {
-			cause = "IMA signature required";
+			cause = "IMA-signature-required";
 			status = INTEGRITY_FAIL;
 			status = INTEGRITY_FAIL;
 			break;
 			break;
 		}
 		}

+ 309 - 3
security/integrity/ima/ima_crypto.c

@@ -16,6 +16,8 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
 #include <linux/file.h>
 #include <linux/file.h>
 #include <linux/crypto.h>
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
@@ -25,7 +27,45 @@
 #include <crypto/hash_info.h>
 #include <crypto/hash_info.h>
 #include "ima.h"
 #include "ima.h"
 
 
+struct ahash_completion {
+	struct completion completion;
+	int err;
+};
+
+/* minimum file size for ahash use */
+static unsigned long ima_ahash_minsize;
+module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644);
+MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use");
+
+/* default is 0 - 1 page. */
+static int ima_maxorder;
+static unsigned int ima_bufsize = PAGE_SIZE;
+
+static int param_set_bufsize(const char *val, const struct kernel_param *kp)
+{
+	unsigned long long size;
+	int order;
+
+	size = memparse(val, NULL);
+	order = get_order(size);
+	if (order >= MAX_ORDER)
+		return -EINVAL;
+	ima_maxorder = order;
+	ima_bufsize = PAGE_SIZE << order;
+	return 0;
+}
+
+static struct kernel_param_ops param_ops_bufsize = {
+	.set = param_set_bufsize,
+	.get = param_get_uint,
+};
+#define param_check_bufsize(name, p) __param_check(name, p, unsigned int)
+
+module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644);
+MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size");
+
 static struct crypto_shash *ima_shash_tfm;
 static struct crypto_shash *ima_shash_tfm;
+static struct crypto_ahash *ima_ahash_tfm;
 
 
 /**
 /**
  * ima_kernel_read - read file content
  * ima_kernel_read - read file content
@@ -93,9 +133,246 @@ static void ima_free_tfm(struct crypto_shash *tfm)
 		crypto_free_shash(tfm);
 		crypto_free_shash(tfm);
 }
 }
 
 
-/*
- * Calculate the MD5/SHA1 file digest
+/**
+ * ima_alloc_pages() - Allocate contiguous pages.
+ * @max_size:       Maximum amount of memory to allocate.
+ * @allocated_size: Returned size of actual allocation.
+ * @last_warn:      Should the min_size allocation warn or not.
+ *
+ * Tries to do opportunistic allocation for memory first trying to allocate
+ * max_size amount of memory and then splitting that until zero order is
+ * reached. Allocation is tried without generating allocation warnings unless
+ * last_warn is set. Last_warn set affects only last allocation of zero order.
+ *
+ * By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL)
+ *
+ * Return pointer to allocated memory, or NULL on failure.
+ */
+static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size,
+			     int last_warn)
+{
+	void *ptr;
+	int order = ima_maxorder;
+	gfp_t gfp_mask = __GFP_WAIT | __GFP_NOWARN | __GFP_NORETRY;
+
+	if (order)
+		order = min(get_order(max_size), order);
+
+	for (; order; order--) {
+		ptr = (void *)__get_free_pages(gfp_mask, order);
+		if (ptr) {
+			*allocated_size = PAGE_SIZE << order;
+			return ptr;
+		}
+	}
+
+	/* order is zero - one page */
+
+	gfp_mask = GFP_KERNEL;
+
+	if (!last_warn)
+		gfp_mask |= __GFP_NOWARN;
+
+	ptr = (void *)__get_free_pages(gfp_mask, 0);
+	if (ptr) {
+		*allocated_size = PAGE_SIZE;
+		return ptr;
+	}
+
+	*allocated_size = 0;
+	return NULL;
+}
+
+/**
+ * ima_free_pages() - Free pages allocated by ima_alloc_pages().
+ * @ptr:  Pointer to allocated pages.
+ * @size: Size of allocated buffer.
  */
  */
+static void ima_free_pages(void *ptr, size_t size)
+{
+	if (!ptr)
+		return;
+	free_pages((unsigned long)ptr, get_order(size));
+}
+
+static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
+{
+	struct crypto_ahash *tfm = ima_ahash_tfm;
+	int rc;
+
+	if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
+		tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
+		if (!IS_ERR(tfm)) {
+			if (algo == ima_hash_algo)
+				ima_ahash_tfm = tfm;
+		} else {
+			rc = PTR_ERR(tfm);
+			pr_err("Can not allocate %s (reason: %d)\n",
+			       hash_algo_name[algo], rc);
+		}
+	}
+	return tfm;
+}
+
+static void ima_free_atfm(struct crypto_ahash *tfm)
+{
+	if (tfm != ima_ahash_tfm)
+		crypto_free_ahash(tfm);
+}
+
+static void ahash_complete(struct crypto_async_request *req, int err)
+{
+	struct ahash_completion *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+	res->err = err;
+	complete(&res->completion);
+}
+
+static int ahash_wait(int err, struct ahash_completion *res)
+{
+	switch (err) {
+	case 0:
+		break;
+	case -EINPROGRESS:
+	case -EBUSY:
+		wait_for_completion(&res->completion);
+		reinit_completion(&res->completion);
+		err = res->err;
+		/* fall through */
+	default:
+		pr_crit_ratelimited("ahash calculation failed: err: %d\n", err);
+	}
+
+	return err;
+}
+
+static int ima_calc_file_hash_atfm(struct file *file,
+				   struct ima_digest_data *hash,
+				   struct crypto_ahash *tfm)
+{
+	loff_t i_size, offset;
+	char *rbuf[2] = { NULL, };
+	int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0;
+	struct ahash_request *req;
+	struct scatterlist sg[1];
+	struct ahash_completion res;
+	size_t rbuf_size[2];
+
+	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 out1;
+
+	i_size = i_size_read(file_inode(file));
+
+	if (i_size == 0)
+		goto out2;
+
+	/*
+	 * Try to allocate maximum size of memory.
+	 * Fail if even a single page cannot be allocated.
+	 */
+	rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1);
+	if (!rbuf[0]) {
+		rc = -ENOMEM;
+		goto out1;
+	}
+
+	/* Only allocate one buffer if that is enough. */
+	if (i_size > rbuf_size[0]) {
+		/*
+		 * Try to allocate secondary buffer. If that fails fallback to
+		 * using single buffering. Use previous memory allocation size
+		 * as baseline for possible allocation size.
+		 */
+		rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0],
+					  &rbuf_size[1], 0);
+	}
+
+	if (!(file->f_mode & FMODE_READ)) {
+		file->f_mode |= FMODE_READ;
+		read = 1;
+	}
+
+	for (offset = 0; offset < i_size; offset += rbuf_len) {
+		if (!rbuf[1] && offset) {
+			/* Not using two buffers, and it is not the first
+			 * read/request, wait for the completion of the
+			 * previous ahash_update() request.
+			 */
+			rc = ahash_wait(ahash_rc, &res);
+			if (rc)
+				goto out3;
+		}
+		/* read buffer */
+		rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]);
+		rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len);
+		if (rc != rbuf_len)
+			goto out3;
+
+		if (rbuf[1] && offset) {
+			/* Using two buffers, and it is not the first
+			 * read/request, wait for the completion of the
+			 * previous ahash_update() request.
+			 */
+			rc = ahash_wait(ahash_rc, &res);
+			if (rc)
+				goto out3;
+		}
+
+		sg_init_one(&sg[0], rbuf[active], rbuf_len);
+		ahash_request_set_crypt(req, sg, NULL, rbuf_len);
+
+		ahash_rc = crypto_ahash_update(req);
+
+		if (rbuf[1])
+			active = !active; /* swap buffers, if we use two */
+	}
+	/* wait for the last update request to complete */
+	rc = ahash_wait(ahash_rc, &res);
+out3:
+	if (read)
+		file->f_mode &= ~FMODE_READ;
+	ima_free_pages(rbuf[0], rbuf_size[0]);
+	ima_free_pages(rbuf[1], rbuf_size[1]);
+out2:
+	if (!rc) {
+		ahash_request_set_crypt(req, NULL, hash->digest, 0);
+		rc = ahash_wait(crypto_ahash_final(req), &res);
+	}
+out1:
+	ahash_request_free(req);
+	return rc;
+}
+
+static int ima_calc_file_ahash(struct file *file, 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 = ima_calc_file_hash_atfm(file, hash, tfm);
+
+	ima_free_atfm(tfm);
+
+	return rc;
+}
+
 static int ima_calc_file_hash_tfm(struct file *file,
 static int ima_calc_file_hash_tfm(struct file *file,
 				  struct ima_digest_data *hash,
 				  struct ima_digest_data *hash,
 				  struct crypto_shash *tfm)
 				  struct crypto_shash *tfm)
@@ -156,7 +433,7 @@ out:
 	return rc;
 	return rc;
 }
 }
 
 
-int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
+static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash)
 {
 {
 	struct crypto_shash *tfm;
 	struct crypto_shash *tfm;
 	int rc;
 	int rc;
@@ -172,6 +449,35 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
 	return rc;
 	return rc;
 }
 }
 
 
+/*
+ * ima_calc_file_hash - calculate file hash
+ *
+ * Asynchronous hash (ahash) allows using HW acceleration for calculating
+ * a hash. ahash performance varies for different data sizes on different
+ * crypto accelerators. shash performance might be better for smaller files.
+ * The 'ima.ahash_minsize' module parameter allows specifying the best
+ * minimum file size for using ahash on the system.
+ *
+ * If the ima.ahash_minsize parameter is not specified, this function uses
+ * shash for the hash calculation.  If ahash fails, it falls back to using
+ * shash.
+ */
+int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
+{
+	loff_t i_size;
+	int rc;
+
+	i_size = i_size_read(file_inode(file));
+
+	if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
+		rc = ima_calc_file_ahash(file, hash);
+		if (!rc)
+			return 0;
+	}
+
+	return ima_calc_file_shash(file, hash);
+}
+
 /*
 /*
  * Calculate the hash of template data
  * Calculate the hash of template data
  */
  */

+ 21 - 7
security/integrity/ima/ima_main.c

@@ -88,8 +88,6 @@ static void ima_rdwr_violation_check(struct file *file)
 	if (!S_ISREG(inode->i_mode) || !ima_initialized)
 	if (!S_ISREG(inode->i_mode) || !ima_initialized)
 		return;
 		return;
 
 
-	mutex_lock(&inode->i_mutex);	/* file metadata: permissions, xattr */
-
 	if (mode & FMODE_WRITE) {
 	if (mode & FMODE_WRITE) {
 		if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
 		if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
 			struct integrity_iint_cache *iint;
 			struct integrity_iint_cache *iint;
@@ -104,8 +102,6 @@ static void ima_rdwr_violation_check(struct file *file)
 			send_writers = true;
 			send_writers = true;
 	}
 	}
 
 
-	mutex_unlock(&inode->i_mutex);
-
 	if (!send_tomtou && !send_writers)
 	if (!send_tomtou && !send_writers)
 		return;
 		return;
 
 
@@ -163,7 +159,7 @@ static int process_measurement(struct file *file, const char *filename,
 {
 {
 	struct inode *inode = file_inode(file);
 	struct inode *inode = file_inode(file);
 	struct integrity_iint_cache *iint;
 	struct integrity_iint_cache *iint;
-	struct ima_template_desc *template_desc = ima_template_desc_current();
+	struct ima_template_desc *template_desc;
 	char *pathbuf = NULL;
 	char *pathbuf = NULL;
 	const char *pathname = NULL;
 	const char *pathname = NULL;
 	int rc = -ENOMEM, action, must_appraise, _func;
 	int rc = -ENOMEM, action, must_appraise, _func;
@@ -207,6 +203,7 @@ static int process_measurement(struct file *file, const char *filename,
 		goto out_digsig;
 		goto out_digsig;
 	}
 	}
 
 
+	template_desc = ima_template_desc_current();
 	if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
 	if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
 		if (action & IMA_APPRAISE_SUBMASK)
 		if (action & IMA_APPRAISE_SUBMASK)
 			xattr_ptr = &xattr_value;
 			xattr_ptr = &xattr_value;
@@ -322,14 +319,31 @@ int ima_module_check(struct file *file)
 	return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
 	return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
 }
 }
 
 
+int ima_fw_from_file(struct file *file, char *buf, size_t size)
+{
+	if (!file) {
+		if ((ima_appraise & IMA_APPRAISE_FIRMWARE) &&
+		    (ima_appraise & IMA_APPRAISE_ENFORCE))
+			return -EACCES;	/* INTEGRITY_UNKNOWN */
+		return 0;
+	}
+	return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
+}
+
 static int __init init_ima(void)
 static int __init init_ima(void)
 {
 {
 	int error;
 	int error;
 
 
 	hash_setup(CONFIG_IMA_DEFAULT_HASH);
 	hash_setup(CONFIG_IMA_DEFAULT_HASH);
 	error = ima_init();
 	error = ima_init();
-	if (!error)
-		ima_initialized = 1;
+	if (error)
+		goto out;
+
+	error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+	if (error)
+		goto out;
+	ima_initialized = 1;
+out:
 	return error;
 	return error;
 }
 }
 
 

+ 10 - 3
security/integrity/ima/ima_policy.c

@@ -84,6 +84,7 @@ static struct ima_rule_entry default_rules[] = {
 	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID,
 	{.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID,
 	 .flags = IMA_FUNC | IMA_MASK | IMA_UID},
 	 .flags = IMA_FUNC | IMA_MASK | IMA_UID},
 	{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
 	{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
+	{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
 };
 };
 
 
 static struct ima_rule_entry default_appraise_rules[] = {
 static struct ima_rule_entry default_appraise_rules[] = {
@@ -241,6 +242,8 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
 		return IMA_BPRM_APPRAISE;
 		return IMA_BPRM_APPRAISE;
 	case MODULE_CHECK:
 	case MODULE_CHECK:
 		return IMA_MODULE_APPRAISE;
 		return IMA_MODULE_APPRAISE;
+	case FIRMWARE_CHECK:
+		return IMA_FIRMWARE_APPRAISE;
 	case FILE_CHECK:
 	case FILE_CHECK:
 	default:
 	default:
 		return IMA_FILE_APPRAISE;
 		return IMA_FILE_APPRAISE;
@@ -332,7 +335,7 @@ void __init ima_init_policy(void)
 void ima_update_policy(void)
 void ima_update_policy(void)
 {
 {
 	static const char op[] = "policy_update";
 	static const char op[] = "policy_update";
-	const char *cause = "already exists";
+	const char *cause = "already-exists";
 	int result = 1;
 	int result = 1;
 	int audit_info = 0;
 	int audit_info = 0;
 
 
@@ -486,6 +489,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 				entry->func = FILE_CHECK;
 				entry->func = FILE_CHECK;
 			else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
 			else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
 				entry->func = MODULE_CHECK;
 				entry->func = MODULE_CHECK;
+			else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0)
+				entry->func = FIRMWARE_CHECK;
 			else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
 			else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
 				|| (strcmp(args[0].from, "MMAP_CHECK") == 0))
 				|| (strcmp(args[0].from, "MMAP_CHECK") == 0))
 				entry->func = MMAP_CHECK;
 				entry->func = MMAP_CHECK;
@@ -636,6 +641,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 		result = -EINVAL;
 		result = -EINVAL;
 	else if (entry->func == MODULE_CHECK)
 	else if (entry->func == MODULE_CHECK)
 		ima_appraise |= IMA_APPRAISE_MODULES;
 		ima_appraise |= IMA_APPRAISE_MODULES;
+	else if (entry->func == FIRMWARE_CHECK)
+		ima_appraise |= IMA_APPRAISE_FIRMWARE;
 	audit_log_format(ab, "res=%d", !result);
 	audit_log_format(ab, "res=%d", !result);
 	audit_log_end(ab);
 	audit_log_end(ab);
 	return result;
 	return result;
@@ -659,7 +666,7 @@ ssize_t ima_parse_add_rule(char *rule)
 	/* Prevent installed policy from changing */
 	/* Prevent installed policy from changing */
 	if (ima_rules != &ima_default_rules) {
 	if (ima_rules != &ima_default_rules) {
 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
-				    NULL, op, "already exists",
+				    NULL, op, "already-exists",
 				    -EACCES, audit_info);
 				    -EACCES, audit_info);
 		return -EACCES;
 		return -EACCES;
 	}
 	}
@@ -685,7 +692,7 @@ ssize_t ima_parse_add_rule(char *rule)
 	if (result) {
 	if (result) {
 		kfree(entry);
 		kfree(entry);
 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
 		integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
-				    NULL, op, "invalid policy", result,
+				    NULL, op, "invalid-policy", result,
 				    audit_info);
 				    audit_info);
 		return result;
 		return result;
 	}
 	}

+ 12 - 2
security/integrity/integrity.h

@@ -46,10 +46,14 @@
 #define IMA_BPRM_APPRAISED	0x00002000
 #define IMA_BPRM_APPRAISED	0x00002000
 #define IMA_MODULE_APPRAISE	0x00004000
 #define IMA_MODULE_APPRAISE	0x00004000
 #define IMA_MODULE_APPRAISED	0x00008000
 #define IMA_MODULE_APPRAISED	0x00008000
+#define IMA_FIRMWARE_APPRAISE	0x00010000
+#define IMA_FIRMWARE_APPRAISED	0x00020000
 #define IMA_APPRAISE_SUBMASK	(IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
 #define IMA_APPRAISE_SUBMASK	(IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \
-				 IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE)
+				 IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \
+				 IMA_FIRMWARE_APPRAISE)
 #define IMA_APPRAISED_SUBMASK	(IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
 #define IMA_APPRAISED_SUBMASK	(IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
-				 IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED)
+				 IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \
+				 IMA_FIRMWARE_APPRAISED)
 
 
 enum evm_ima_xattr_type {
 enum evm_ima_xattr_type {
 	IMA_XATTR_DIGEST = 0x01,
 	IMA_XATTR_DIGEST = 0x01,
@@ -104,6 +108,7 @@ struct integrity_iint_cache {
 	enum integrity_status ima_mmap_status:4;
 	enum integrity_status ima_mmap_status:4;
 	enum integrity_status ima_bprm_status:4;
 	enum integrity_status ima_bprm_status:4;
 	enum integrity_status ima_module_status:4;
 	enum integrity_status ima_module_status:4;
+	enum integrity_status ima_firmware_status:4;
 	enum integrity_status evm_status:4;
 	enum integrity_status evm_status:4;
 	struct ima_digest_data *ima_hash;
 	struct ima_digest_data *ima_hash;
 };
 };
@@ -124,6 +129,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 			    const char *digest, int digestlen);
 			    const char *digest, int digestlen);
 
 
+int integrity_init_keyring(const unsigned int id);
 #else
 #else
 
 
 static inline int integrity_digsig_verify(const unsigned int id,
 static inline int integrity_digsig_verify(const unsigned int id,
@@ -133,6 +139,10 @@ static inline int integrity_digsig_verify(const unsigned int id,
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 
+static inline int integrity_init_keyring(const unsigned int id)
+{
+	return 0;
+}
 #endif /* CONFIG_INTEGRITY_SIGNATURE */
 #endif /* CONFIG_INTEGRITY_SIGNATURE */
 
 
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS

+ 25 - 16
security/keys/big_key.c

@@ -34,7 +34,9 @@ MODULE_LICENSE("GPL");
 struct key_type key_type_big_key = {
 struct key_type key_type_big_key = {
 	.name			= "big_key",
 	.name			= "big_key",
 	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
-	.instantiate		= big_key_instantiate,
+	.preparse		= big_key_preparse,
+	.free_preparse		= big_key_free_preparse,
+	.instantiate		= generic_key_instantiate,
 	.match			= user_match,
 	.match			= user_match,
 	.revoke			= big_key_revoke,
 	.revoke			= big_key_revoke,
 	.destroy		= big_key_destroy,
 	.destroy		= big_key_destroy,
@@ -43,11 +45,11 @@ struct key_type key_type_big_key = {
 };
 };
 
 
 /*
 /*
- * Instantiate a big key
+ * Preparse a big key
  */
  */
-int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+int big_key_preparse(struct key_preparsed_payload *prep)
 {
 {
-	struct path *path = (struct path *)&key->payload.data2;
+	struct path *path = (struct path *)&prep->payload;
 	struct file *file;
 	struct file *file;
 	ssize_t written;
 	ssize_t written;
 	size_t datalen = prep->datalen;
 	size_t datalen = prep->datalen;
@@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 		goto error;
 		goto error;
 
 
 	/* Set an arbitrary quota */
 	/* Set an arbitrary quota */
-	ret = key_payload_reserve(key, 16);
-	if (ret < 0)
-		goto error;
+	prep->quotalen = 16;
 
 
-	key->type_data.x[1] = datalen;
+	prep->type_data[1] = (void *)(unsigned long)datalen;
 
 
 	if (datalen > BIG_KEY_FILE_THRESHOLD) {
 	if (datalen > BIG_KEY_FILE_THRESHOLD) {
 		/* Create a shmem file to store the data in.  This will permit the data
 		/* Create a shmem file to store the data in.  This will permit the data
@@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 		file = shmem_kernel_file_setup("", datalen, 0);
 		file = shmem_kernel_file_setup("", datalen, 0);
 		if (IS_ERR(file)) {
 		if (IS_ERR(file)) {
 			ret = PTR_ERR(file);
 			ret = PTR_ERR(file);
-			goto err_quota;
+			goto error;
 		}
 		}
 
 
 		written = kernel_write(file, prep->data, prep->datalen, 0);
 		written = kernel_write(file, prep->data, prep->datalen, 0);
@@ -93,23 +93,32 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 	} else {
 	} else {
 		/* Just store the data in a buffer */
 		/* Just store the data in a buffer */
 		void *data = kmalloc(datalen, GFP_KERNEL);
 		void *data = kmalloc(datalen, GFP_KERNEL);
-		if (!data) {
-			ret = -ENOMEM;
-			goto err_quota;
-		}
+		if (!data)
+			return -ENOMEM;
 
 
-		key->payload.data = memcpy(data, prep->data, prep->datalen);
+		prep->payload[0] = memcpy(data, prep->data, prep->datalen);
 	}
 	}
 	return 0;
 	return 0;
 
 
 err_fput:
 err_fput:
 	fput(file);
 	fput(file);
-err_quota:
-	key_payload_reserve(key, 0);
 error:
 error:
 	return ret;
 	return ret;
 }
 }
 
 
+/*
+ * Clear preparsement.
+ */
+void big_key_free_preparse(struct key_preparsed_payload *prep)
+{
+	if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
+		struct path *path = (struct path *)&prep->payload;
+		path_put(path);
+	} else {
+		kfree(prep->payload[0]);
+	}
+}
+
 /*
 /*
  * dispose of the links from a revoked keyring
  * dispose of the links from a revoked keyring
  * - called with the key sem write-locked
  * - called with the key sem write-locked

+ 44 - 5
security/keys/key.c

@@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key,
 			/* disable the authorisation key */
 			/* disable the authorisation key */
 			if (authkey)
 			if (authkey)
 				key_revoke(authkey);
 				key_revoke(authkey);
+
+			if (prep->expiry != TIME_T_MAX) {
+				key->expiry = prep->expiry;
+				key_schedule_gc(prep->expiry + key_gc_delay);
+			}
 		}
 		}
 	}
 	}
 
 
@@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key,
 	prep.data = data;
 	prep.data = data;
 	prep.datalen = datalen;
 	prep.datalen = datalen;
 	prep.quotalen = key->type->def_datalen;
 	prep.quotalen = key->type->def_datalen;
+	prep.expiry = TIME_T_MAX;
 	if (key->type->preparse) {
 	if (key->type->preparse) {
 		ret = key->type->preparse(&prep);
 		ret = key->type->preparse(&prep);
 		if (ret < 0)
 		if (ret < 0)
@@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key,
 	if (keyring) {
 	if (keyring) {
 		ret = __key_link_begin(keyring, &key->index_key, &edit);
 		ret = __key_link_begin(keyring, &key->index_key, &edit);
 		if (ret < 0)
 		if (ret < 0)
-			goto error_free_preparse;
+			goto error;
 	}
 	}
 
 
 	ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
 	ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
@@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key,
 	if (keyring)
 	if (keyring)
 		__key_link_end(keyring, &key->index_key, edit);
 		__key_link_end(keyring, &key->index_key, edit);
 
 
-error_free_preparse:
+error:
 	if (key->type->preparse)
 	if (key->type->preparse)
 		key->type->free_preparse(&prep);
 		key->type->free_preparse(&prep);
-error:
 	return ret;
 	return ret;
 }
 }
 
 
@@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 	prep.datalen = plen;
 	prep.datalen = plen;
 	prep.quotalen = index_key.type->def_datalen;
 	prep.quotalen = index_key.type->def_datalen;
 	prep.trusted = flags & KEY_ALLOC_TRUSTED;
 	prep.trusted = flags & KEY_ALLOC_TRUSTED;
+	prep.expiry = TIME_T_MAX;
 	if (index_key.type->preparse) {
 	if (index_key.type->preparse) {
 		ret = index_key.type->preparse(&prep);
 		ret = index_key.type->preparse(&prep);
 		if (ret < 0) {
 		if (ret < 0) {
 			key_ref = ERR_PTR(ret);
 			key_ref = ERR_PTR(ret);
-			goto error_put_type;
+			goto error_free_prep;
 		}
 		}
 		if (!index_key.description)
 		if (!index_key.description)
 			index_key.description = prep.description;
 			index_key.description = prep.description;
@@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 	prep.data = payload;
 	prep.data = payload;
 	prep.datalen = plen;
 	prep.datalen = plen;
 	prep.quotalen = key->type->def_datalen;
 	prep.quotalen = key->type->def_datalen;
+	prep.expiry = TIME_T_MAX;
 	if (key->type->preparse) {
 	if (key->type->preparse) {
 		ret = key->type->preparse(&prep);
 		ret = key->type->preparse(&prep);
 		if (ret < 0)
 		if (ret < 0)
@@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 
 
 	up_write(&key->sem);
 	up_write(&key->sem);
 
 
+error:
 	if (key->type->preparse)
 	if (key->type->preparse)
 		key->type->free_preparse(&prep);
 		key->type->free_preparse(&prep);
-error:
 	return ret;
 	return ret;
 }
 }
 EXPORT_SYMBOL(key_update);
 EXPORT_SYMBOL(key_update);
@@ -1023,6 +1030,38 @@ void key_invalidate(struct key *key)
 }
 }
 EXPORT_SYMBOL(key_invalidate);
 EXPORT_SYMBOL(key_invalidate);
 
 
+/**
+ * generic_key_instantiate - Simple instantiation of a key from preparsed data
+ * @key: The key to be instantiated
+ * @prep: The preparsed data to load.
+ *
+ * Instantiate a key from preparsed data.  We assume we can just copy the data
+ * in directly and clear the old pointers.
+ *
+ * This can be pointed to directly by the key type instantiate op pointer.
+ */
+int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
+{
+	int ret;
+
+	pr_devel("==>%s()\n", __func__);
+
+	ret = key_payload_reserve(key, prep->quotalen);
+	if (ret == 0) {
+		key->type_data.p[0] = prep->type_data[0];
+		key->type_data.p[1] = prep->type_data[1];
+		rcu_assign_keypointer(key, prep->payload[0]);
+		key->payload.data2[1] = prep->payload[1];
+		prep->type_data[0] = NULL;
+		prep->type_data[1] = NULL;
+		prep->payload[0] = NULL;
+		prep->payload[1] = NULL;
+	}
+	pr_devel("<==%s() = %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(generic_key_instantiate);
+
 /**
 /**
  * register_key_type - Register a type of key.
  * register_key_type - Register a type of key.
  * @ktype: The new key type.
  * @ktype: The new key type.

+ 18 - 3
security/keys/keyctl.c

@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type,
 		return ret;
 		return ret;
 	if (ret == 0 || ret >= len)
 	if (ret == 0 || ret >= len)
 		return -EINVAL;
 		return -EINVAL;
-	if (type[0] == '.')
-		return -EPERM;
 	type[len - 1] = '\0';
 	type[len - 1] = '\0';
 	return 0;
 	return 0;
 }
 }
@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
 		if (!*description) {
 		if (!*description) {
 			kfree(description);
 			kfree(description);
 			description = NULL;
 			description = NULL;
+		} else if ((description[0] == '.') &&
+			   (strncmp(type, "keyring", 7) == 0)) {
+			ret = -EPERM;
+			goto error2;
 		}
 		}
 	}
 	}
 
 
@@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id)
 	key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
 	key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
 	if (IS_ERR(key_ref)) {
 	if (IS_ERR(key_ref)) {
 		ret = PTR_ERR(key_ref);
 		ret = PTR_ERR(key_ref);
+
+		/* Root is permitted to invalidate certain special keys */
+		if (capable(CAP_SYS_ADMIN)) {
+			key_ref = lookup_user_key(id, 0, 0);
+			if (IS_ERR(key_ref))
+				goto error;
+			if (test_bit(KEY_FLAG_ROOT_CAN_INVAL,
+				     &key_ref_to_ptr(key_ref)->flags))
+				goto invalidate;
+			goto error_put;
+		}
+
 		goto error;
 		goto error;
 	}
 	}
 
 
+invalidate:
 	key_invalidate(key_ref_to_ptr(key_ref));
 	key_invalidate(key_ref_to_ptr(key_ref));
 	ret = 0;
 	ret = 0;
-
+error_put:
 	key_ref_put(key_ref);
 	key_ref_put(key_ref);
 error:
 error:
 	kleave(" = %ld", ret);
 	kleave(" = %ld", ret);

+ 23 - 11
security/keys/keyring.c

@@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc)
  * can be treated as ordinary keys in addition to having their own special
  * can be treated as ordinary keys in addition to having their own special
  * operations.
  * operations.
  */
  */
+static int keyring_preparse(struct key_preparsed_payload *prep);
+static void keyring_free_preparse(struct key_preparsed_payload *prep);
 static int keyring_instantiate(struct key *keyring,
 static int keyring_instantiate(struct key *keyring,
 			       struct key_preparsed_payload *prep);
 			       struct key_preparsed_payload *prep);
 static void keyring_revoke(struct key *keyring);
 static void keyring_revoke(struct key *keyring);
@@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring,
 struct key_type key_type_keyring = {
 struct key_type key_type_keyring = {
 	.name		= "keyring",
 	.name		= "keyring",
 	.def_datalen	= 0,
 	.def_datalen	= 0,
+	.preparse	= keyring_preparse,
+	.free_preparse	= keyring_free_preparse,
 	.instantiate	= keyring_instantiate,
 	.instantiate	= keyring_instantiate,
 	.match		= user_match,
 	.match		= user_match,
 	.revoke		= keyring_revoke,
 	.revoke		= keyring_revoke,
@@ -122,6 +126,21 @@ static void keyring_publish_name(struct key *keyring)
 	}
 	}
 }
 }
 
 
+/*
+ * Preparse a keyring payload
+ */
+static int keyring_preparse(struct key_preparsed_payload *prep)
+{
+	return prep->datalen != 0 ? -EINVAL : 0;
+}
+
+/*
+ * Free a preparse of a user defined key payload
+ */
+static void keyring_free_preparse(struct key_preparsed_payload *prep)
+{
+}
+
 /*
 /*
  * Initialise a keyring.
  * Initialise a keyring.
  *
  *
@@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring)
 static int keyring_instantiate(struct key *keyring,
 static int keyring_instantiate(struct key *keyring,
 			       struct key_preparsed_payload *prep)
 			       struct key_preparsed_payload *prep)
 {
 {
-	int ret;
-
-	ret = -EINVAL;
-	if (prep->datalen == 0) {
-		assoc_array_init(&keyring->keys);
-		/* make the keyring available by name if it has one */
-		keyring_publish_name(keyring);
-		ret = 0;
-	}
-
-	return ret;
+	assoc_array_init(&keyring->keys);
+	/* make the keyring available by name if it has one */
+	keyring_publish_name(keyring);
+	return 0;
 }
 }
 
 
 /*
 /*

+ 13 - 0
security/keys/request_key_auth.c

@@ -20,6 +20,8 @@
 #include "internal.h"
 #include "internal.h"
 #include <keys/user-type.h>
 #include <keys/user-type.h>
 
 
+static int request_key_auth_preparse(struct key_preparsed_payload *);
+static void request_key_auth_free_preparse(struct key_preparsed_payload *);
 static int request_key_auth_instantiate(struct key *,
 static int request_key_auth_instantiate(struct key *,
 					struct key_preparsed_payload *);
 					struct key_preparsed_payload *);
 static void request_key_auth_describe(const struct key *, struct seq_file *);
 static void request_key_auth_describe(const struct key *, struct seq_file *);
@@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t);
 struct key_type key_type_request_key_auth = {
 struct key_type key_type_request_key_auth = {
 	.name		= ".request_key_auth",
 	.name		= ".request_key_auth",
 	.def_datalen	= sizeof(struct request_key_auth),
 	.def_datalen	= sizeof(struct request_key_auth),
+	.preparse	= request_key_auth_preparse,
+	.free_preparse	= request_key_auth_free_preparse,
 	.instantiate	= request_key_auth_instantiate,
 	.instantiate	= request_key_auth_instantiate,
 	.describe	= request_key_auth_describe,
 	.describe	= request_key_auth_describe,
 	.revoke		= request_key_auth_revoke,
 	.revoke		= request_key_auth_revoke,
@@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = {
 	.read		= request_key_auth_read,
 	.read		= request_key_auth_read,
 };
 };
 
 
+int request_key_auth_preparse(struct key_preparsed_payload *prep)
+{
+	return 0;
+}
+
+void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
+{
+}
+
 /*
 /*
  * Instantiate a request-key authorisation key.
  * Instantiate a request-key authorisation key.
  */
  */

+ 22 - 19
security/keys/user_defined.c

@@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc);
 struct key_type key_type_user = {
 struct key_type key_type_user = {
 	.name			= "user",
 	.name			= "user",
 	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
-	.instantiate		= user_instantiate,
+	.preparse		= user_preparse,
+	.free_preparse		= user_free_preparse,
+	.instantiate		= generic_key_instantiate,
 	.update			= user_update,
 	.update			= user_update,
 	.match			= user_match,
 	.match			= user_match,
 	.revoke			= user_revoke,
 	.revoke			= user_revoke,
@@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user);
 struct key_type key_type_logon = {
 struct key_type key_type_logon = {
 	.name			= "logon",
 	.name			= "logon",
 	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
 	.def_lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
-	.instantiate		= user_instantiate,
+	.preparse		= user_preparse,
+	.free_preparse		= user_free_preparse,
+	.instantiate		= generic_key_instantiate,
 	.update			= user_update,
 	.update			= user_update,
 	.match			= user_match,
 	.match			= user_match,
 	.revoke			= user_revoke,
 	.revoke			= user_revoke,
@@ -58,38 +62,37 @@ struct key_type key_type_logon = {
 EXPORT_SYMBOL_GPL(key_type_logon);
 EXPORT_SYMBOL_GPL(key_type_logon);
 
 
 /*
 /*
- * instantiate a user defined key
+ * Preparse a user defined key payload
  */
  */
-int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
+int user_preparse(struct key_preparsed_payload *prep)
 {
 {
 	struct user_key_payload *upayload;
 	struct user_key_payload *upayload;
 	size_t datalen = prep->datalen;
 	size_t datalen = prep->datalen;
-	int ret;
 
 
-	ret = -EINVAL;
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
-		goto error;
-
-	ret = key_payload_reserve(key, datalen);
-	if (ret < 0)
-		goto error;
+		return -EINVAL;
 
 
-	ret = -ENOMEM;
 	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
 	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
 	if (!upayload)
 	if (!upayload)
-		goto error;
+		return -ENOMEM;
 
 
 	/* attach the data */
 	/* attach the data */
+	prep->quotalen = datalen;
+	prep->payload[0] = upayload;
 	upayload->datalen = datalen;
 	upayload->datalen = datalen;
 	memcpy(upayload->data, prep->data, datalen);
 	memcpy(upayload->data, prep->data, datalen);
-	rcu_assign_keypointer(key, upayload);
-	ret = 0;
-
-error:
-	return ret;
+	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(user_preparse);
 
 
-EXPORT_SYMBOL_GPL(user_instantiate);
+/*
+ * Free a preparse of a user defined key payload
+ */
+void user_free_preparse(struct key_preparsed_payload *prep)
+{
+	kfree(prep->payload[0]);
+}
+EXPORT_SYMBOL_GPL(user_free_preparse);
 
 
 /*
 /*
  * update a user defined key
  * update a user defined key

+ 11 - 0
security/security.c

@@ -845,6 +845,17 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
 	return security_ops->kernel_create_files_as(new, inode);
 	return security_ops->kernel_create_files_as(new, inode);
 }
 }
 
 
+int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
+{
+	int ret;
+
+	ret = security_ops->kernel_fw_from_file(file, buf, size);
+	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)
 int security_kernel_module_request(char *kmod_name)
 {
 {
 	return security_ops->kernel_module_request(kmod_name);
 	return security_ops->kernel_module_request(kmod_name);

+ 14 - 0
security/selinux/hooks.c

@@ -161,6 +161,17 @@ static int selinux_peerlbl_enabled(void)
 	return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
 	return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
 }
 }
 
 
+static int selinux_netcache_avc_callback(u32 event)
+{
+	if (event == AVC_CALLBACK_RESET) {
+		sel_netif_flush();
+		sel_netnode_flush();
+		sel_netport_flush();
+		synchronize_net();
+	}
+	return 0;
+}
+
 /*
 /*
  * initialise the security for the init task
  * initialise the security for the init task
  */
  */
@@ -5993,6 +6004,9 @@ static __init int selinux_init(void)
 	if (register_security(&selinux_ops))
 	if (register_security(&selinux_ops))
 		panic("SELinux: Unable to register with kernel.\n");
 		panic("SELinux: Unable to register with kernel.\n");
 
 
+	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
+		panic("SELinux: Unable to register AVC netcache callback\n");
+
 	if (selinux_enforcing)
 	if (selinux_enforcing)
 		printk(KERN_DEBUG "SELinux:  Starting in enforcing mode\n");
 		printk(KERN_DEBUG "SELinux:  Starting in enforcing mode\n");
 	else
 	else

+ 2 - 0
security/selinux/include/netif.h

@@ -17,6 +17,8 @@
 #ifndef _SELINUX_NETIF_H_
 #ifndef _SELINUX_NETIF_H_
 #define _SELINUX_NETIF_H_
 #define _SELINUX_NETIF_H_
 
 
+void sel_netif_flush(void);
+
 int sel_netif_sid(int ifindex, u32 *sid);
 int sel_netif_sid(int ifindex, u32 *sid);
 
 
 #endif	/* _SELINUX_NETIF_H_ */
 #endif	/* _SELINUX_NETIF_H_ */

+ 2 - 0
security/selinux/include/netnode.h

@@ -27,6 +27,8 @@
 #ifndef _SELINUX_NETNODE_H
 #ifndef _SELINUX_NETNODE_H
 #define _SELINUX_NETNODE_H
 #define _SELINUX_NETNODE_H
 
 
+void sel_netnode_flush(void);
+
 int sel_netnode_sid(void *addr, u16 family, u32 *sid);
 int sel_netnode_sid(void *addr, u16 family, u32 *sid);
 
 
 #endif
 #endif

+ 2 - 0
security/selinux/include/netport.h

@@ -26,6 +26,8 @@
 #ifndef _SELINUX_NETPORT_H
 #ifndef _SELINUX_NETPORT_H
 #define _SELINUX_NETPORT_H
 #define _SELINUX_NETPORT_H
 
 
+void sel_netport_flush(void);
+
 int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid);
 int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid);
 
 
 #endif
 #endif

+ 2 - 1
security/selinux/include/security.h

@@ -8,6 +8,7 @@
 #ifndef _SELINUX_SECURITY_H_
 #ifndef _SELINUX_SECURITY_H_
 #define _SELINUX_SECURITY_H_
 #define _SELINUX_SECURITY_H_
 
 
+#include <linux/compiler.h>
 #include <linux/dcache.h>
 #include <linux/dcache.h>
 #include <linux/magic.h>
 #include <linux/magic.h>
 #include <linux/types.h>
 #include <linux/types.h>
@@ -220,7 +221,7 @@ struct selinux_kernel_status {
 	/*
 	/*
 	 * The version > 0 supports above members.
 	 * The version > 0 supports above members.
 	 */
 	 */
-} __attribute__((packed));
+} __packed;
 
 
 extern void selinux_status_update_setenforce(int enforcing);
 extern void selinux_status_update_setenforce(int enforcing);
 extern void selinux_status_update_policyload(int seqno);
 extern void selinux_status_update_policyload(int seqno);

+ 1 - 14
security/selinux/netif.c

@@ -240,7 +240,7 @@ static void sel_netif_kill(int ifindex)
  * Remove all entries from the network interface table.
  * Remove all entries from the network interface table.
  *
  *
  */
  */
-static void sel_netif_flush(void)
+void sel_netif_flush(void)
 {
 {
 	int idx;
 	int idx;
 	struct sel_netif *netif;
 	struct sel_netif *netif;
@@ -252,15 +252,6 @@ static void sel_netif_flush(void)
 	spin_unlock_bh(&sel_netif_lock);
 	spin_unlock_bh(&sel_netif_lock);
 }
 }
 
 
-static int sel_netif_avc_callback(u32 event)
-{
-	if (event == AVC_CALLBACK_RESET) {
-		sel_netif_flush();
-		synchronize_net();
-	}
-	return 0;
-}
-
 static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
 static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
 					     unsigned long event, void *ptr)
 					     unsigned long event, void *ptr)
 {
 {
@@ -291,10 +282,6 @@ static __init int sel_netif_init(void)
 
 
 	register_netdevice_notifier(&sel_netif_netdev_notifier);
 	register_netdevice_notifier(&sel_netif_netdev_notifier);
 
 
-	err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET);
-	if (err)
-		panic("avc_add_callback() failed, error %d\n", err);
-
 	return err;
 	return err;
 }
 }
 
 

Some files were not shown because too many files changed in this diff