diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:06:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:06:39 -0400 |
commit | bb2cbf5e9367d8598fecd0c48dead69560750223 (patch) | |
tree | fb2c620451b90f41a31726bdd82077813f941e39 | |
parent | e7fda6c4c3c1a7d6996dd75fd84670fa0b5d448f (diff) | |
parent | 478d085524c57cf4283699f529d5a4c22188ea69 (diff) |
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
...
110 files changed, 4480 insertions, 834 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy index 4c3efe434806..d0d0c578324c 100644 --- a/Documentation/ABI/testing/ima_policy +++ b/Documentation/ABI/testing/ima_policy | |||
@@ -26,6 +26,7 @@ Description: | |||
26 | option: [[appraise_type=]] [permit_directio] | 26 | option: [[appraise_type=]] [permit_directio] |
27 | 27 | ||
28 | base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] | 28 | base: func:= [BPRM_CHECK][MMAP_CHECK][FILE_CHECK][MODULE_CHECK] |
29 | [FIRMWARE_CHECK] | ||
29 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] | 30 | mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC] |
30 | fsmagic:= hex value | 31 | fsmagic:= hex value |
31 | fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6) | 32 | fsuuid:= file system UUID (e.g 8bcbe394-4f13-4144-be8e-5aa9ea2ce2f6) |
@@ -57,7 +58,8 @@ Description: | |||
57 | measure func=BPRM_CHECK | 58 | measure func=BPRM_CHECK |
58 | measure func=FILE_MMAP mask=MAY_EXEC | 59 | measure func=FILE_MMAP mask=MAY_EXEC |
59 | measure func=FILE_CHECK mask=MAY_READ uid=0 | 60 | measure func=FILE_CHECK mask=MAY_READ uid=0 |
60 | measure func=MODULE_CHECK uid=0 | 61 | measure func=MODULE_CHECK |
62 | measure func=FIRMWARE_CHECK | ||
61 | appraise fowner=0 | 63 | appraise fowner=0 |
62 | 64 | ||
63 | The default policy measures all executables in bprm_check, | 65 | The default policy measures all executables in bprm_check, |
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6c062a64a796..883901b9ac4f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
566 | possible to determine what the correct size should be. | 566 | possible to determine what the correct size should be. |
567 | This option provides an override for these situations. | 567 | This option provides an override for these situations. |
568 | 568 | ||
569 | ca_keys= [KEYS] This parameter identifies a specific key(s) on | ||
570 | the system trusted keyring to be used for certificate | ||
571 | trust validation. | ||
572 | format: { id:<keyid> | builtin } | ||
573 | |||
569 | ccw_timeout_log [S390] | 574 | ccw_timeout_log [S390] |
570 | See Documentation/s390/CommonIO for details. | 575 | See Documentation/s390/CommonIO for details. |
571 | 576 | ||
@@ -1319,6 +1324,23 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
1319 | Formats: { "ima" | "ima-ng" } | 1324 | Formats: { "ima" | "ima-ng" } |
1320 | Default: "ima-ng" | 1325 | Default: "ima-ng" |
1321 | 1326 | ||
1327 | ima.ahash_minsize= [IMA] Minimum file size for asynchronous hash usage | ||
1328 | Format: <min_file_size> | ||
1329 | Set the minimal file size for using asynchronous hash. | ||
1330 | If left unspecified, ahash usage is disabled. | ||
1331 | |||
1332 | ahash performance varies for different data sizes on | ||
1333 | different crypto accelerators. This option can be used | ||
1334 | to achieve the best performance for a particular HW. | ||
1335 | |||
1336 | ima.ahash_bufsize= [IMA] Asynchronous hash buffer size | ||
1337 | Format: <bufsize> | ||
1338 | Set hashing buffer size. Default: 4k. | ||
1339 | |||
1340 | ahash performance varies for different chunk sizes on | ||
1341 | different crypto accelerators. This option can be used | ||
1342 | to achieve best performance for particular HW. | ||
1343 | |||
1322 | init= [KNL] | 1344 | init= [KNL] |
1323 | Format: <full_path> | 1345 | Format: <full_path> |
1324 | Run specified binary instead of /sbin/init as init | 1346 | Run specified binary instead of /sbin/init as init |
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index a4c33f1a7c6d..8727c194ca16 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt | |||
@@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory: | |||
1150 | const void *data; | 1150 | const void *data; |
1151 | size_t datalen; | 1151 | size_t datalen; |
1152 | size_t quotalen; | 1152 | size_t quotalen; |
1153 | time_t expiry; | ||
1153 | }; | 1154 | }; |
1154 | 1155 | ||
1155 | Before calling the method, the caller will fill in data and datalen with | 1156 | Before calling the method, the caller will fill in data and datalen with |
1156 | the payload blob parameters; quotalen will be filled in with the default | 1157 | the payload blob parameters; quotalen will be filled in with the default |
1157 | quota size from the key type and the rest will be cleared. | 1158 | quota size from the key type; expiry will be set to TIME_T_MAX and the |
1159 | rest will be cleared. | ||
1158 | 1160 | ||
1159 | If a description can be proposed from the payload contents, that should be | 1161 | If a description can be proposed from the payload contents, that should be |
1160 | attached as a string to the description field. This will be used for the | 1162 | attached as a string to the description field. This will be used for the |
1161 | key description if the caller of add_key() passes NULL or "". | 1163 | key description if the caller of add_key() passes NULL or "". |
1162 | 1164 | ||
1163 | The method can attach anything it likes to type_data[] and payload. These | 1165 | The method can attach anything it likes to type_data[] and payload. These |
1164 | are merely passed along to the instantiate() or update() operations. | 1166 | are merely passed along to the instantiate() or update() operations. If |
1167 | set, the expiry time will be applied to the key if it is instantiated from | ||
1168 | this data. | ||
1165 | 1169 | ||
1166 | The method should return 0 if success ful or a negative error code | 1170 | The method should return 0 if successful or a negative error code |
1167 | otherwise. | 1171 | otherwise. |
1168 | 1172 | ||
1169 | 1173 | ||
@@ -1172,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory: | |||
1172 | This method is only required if the preparse() method is provided, | 1176 | This method is only required if the preparse() method is provided, |
1173 | otherwise it is unused. It cleans up anything attached to the | 1177 | otherwise it is unused. It cleans up anything attached to the |
1174 | description, type_data and payload fields of the key_preparsed_payload | 1178 | description, type_data and payload fields of the key_preparsed_payload |
1175 | struct as filled in by the preparse() method. | 1179 | struct as filled in by the preparse() method. It will always be called |
1180 | after preparse() returns successfully, even if instantiate() or update() | ||
1181 | succeed. | ||
1176 | 1182 | ||
1177 | 1183 | ||
1178 | (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); | 1184 | (*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep); |
diff --git a/MAINTAINERS b/MAINTAINERS index f77776304406..b9d02936c1df 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -8002,6 +8002,16 @@ S: Maintained | |||
8002 | F: drivers/mmc/host/sdhci.* | 8002 | F: drivers/mmc/host/sdhci.* |
8003 | F: drivers/mmc/host/sdhci-pltfm.[ch] | 8003 | F: drivers/mmc/host/sdhci-pltfm.[ch] |
8004 | 8004 | ||
8005 | SECURE COMPUTING | ||
8006 | M: Kees Cook <keescook@chromium.org> | ||
8007 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp | ||
8008 | S: Supported | ||
8009 | F: kernel/seccomp.c | ||
8010 | F: include/uapi/linux/seccomp.h | ||
8011 | F: include/linux/seccomp.h | ||
8012 | K: \bsecure_computing | ||
8013 | K: \bTIF_SECCOMP\b | ||
8014 | |||
8005 | SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF) | 8015 | SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF) |
8006 | M: Anton Vorontsov <anton@enomsg.org> | 8016 | M: Anton Vorontsov <anton@enomsg.org> |
8007 | L: linuxppc-dev@lists.ozlabs.org | 8017 | L: linuxppc-dev@lists.ozlabs.org |
diff --git a/arch/Kconfig b/arch/Kconfig index 97ff872c7acc..0eae9df35b88 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER | |||
321 | - secure_computing is called from a ptrace_event()-safe context | 321 | - secure_computing is called from a ptrace_event()-safe context |
322 | - secure_computing return value is checked and a return value of -1 | 322 | - secure_computing return value is checked and a return value of -1 |
323 | results in the system call being skipped immediately. | 323 | results in the system call being skipped immediately. |
324 | - seccomp syscall wired up | ||
324 | 325 | ||
325 | config SECCOMP_FILTER | 326 | config SECCOMP_FILTER |
326 | def_bool y | 327 | def_bool y |
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index acd5b66ea3aa..767ea204334e 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h | |||
@@ -409,6 +409,7 @@ | |||
409 | #define __NR_sched_setattr (__NR_SYSCALL_BASE+380) | 409 | #define __NR_sched_setattr (__NR_SYSCALL_BASE+380) |
410 | #define __NR_sched_getattr (__NR_SYSCALL_BASE+381) | 410 | #define __NR_sched_getattr (__NR_SYSCALL_BASE+381) |
411 | #define __NR_renameat2 (__NR_SYSCALL_BASE+382) | 411 | #define __NR_renameat2 (__NR_SYSCALL_BASE+382) |
412 | #define __NR_seccomp (__NR_SYSCALL_BASE+383) | ||
412 | 413 | ||
413 | /* | 414 | /* |
414 | * The following SWIs are ARM private. | 415 | * The following SWIs are ARM private. |
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 8f51bdcdacbb..bea85f97f363 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S | |||
@@ -392,6 +392,7 @@ | |||
392 | /* 380 */ CALL(sys_sched_setattr) | 392 | /* 380 */ CALL(sys_sched_setattr) |
393 | CALL(sys_sched_getattr) | 393 | CALL(sys_sched_getattr) |
394 | CALL(sys_renameat2) | 394 | CALL(sys_renameat2) |
395 | CALL(sys_seccomp) | ||
395 | #ifndef syscalls_counted | 396 | #ifndef syscalls_counted |
396 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls | 397 | .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls |
397 | #define syscalls_counted | 398 | #define syscalls_counted |
diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index 5805414777e0..9bc13eaf9d67 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h | |||
@@ -372,16 +372,17 @@ | |||
372 | #define __NR_sched_setattr (__NR_Linux + 349) | 372 | #define __NR_sched_setattr (__NR_Linux + 349) |
373 | #define __NR_sched_getattr (__NR_Linux + 350) | 373 | #define __NR_sched_getattr (__NR_Linux + 350) |
374 | #define __NR_renameat2 (__NR_Linux + 351) | 374 | #define __NR_renameat2 (__NR_Linux + 351) |
375 | #define __NR_seccomp (__NR_Linux + 352) | ||
375 | 376 | ||
376 | /* | 377 | /* |
377 | * Offset of the last Linux o32 flavoured syscall | 378 | * Offset of the last Linux o32 flavoured syscall |
378 | */ | 379 | */ |
379 | #define __NR_Linux_syscalls 351 | 380 | #define __NR_Linux_syscalls 352 |
380 | 381 | ||
381 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ | 382 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ |
382 | 383 | ||
383 | #define __NR_O32_Linux 4000 | 384 | #define __NR_O32_Linux 4000 |
384 | #define __NR_O32_Linux_syscalls 351 | 385 | #define __NR_O32_Linux_syscalls 352 |
385 | 386 | ||
386 | #if _MIPS_SIM == _MIPS_SIM_ABI64 | 387 | #if _MIPS_SIM == _MIPS_SIM_ABI64 |
387 | 388 | ||
@@ -701,16 +702,17 @@ | |||
701 | #define __NR_sched_setattr (__NR_Linux + 309) | 702 | #define __NR_sched_setattr (__NR_Linux + 309) |
702 | #define __NR_sched_getattr (__NR_Linux + 310) | 703 | #define __NR_sched_getattr (__NR_Linux + 310) |
703 | #define __NR_renameat2 (__NR_Linux + 311) | 704 | #define __NR_renameat2 (__NR_Linux + 311) |
705 | #define __NR_seccomp (__NR_Linux + 312) | ||
704 | 706 | ||
705 | /* | 707 | /* |
706 | * Offset of the last Linux 64-bit flavoured syscall | 708 | * Offset of the last Linux 64-bit flavoured syscall |
707 | */ | 709 | */ |
708 | #define __NR_Linux_syscalls 311 | 710 | #define __NR_Linux_syscalls 312 |
709 | 711 | ||
710 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ | 712 | #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ |
711 | 713 | ||
712 | #define __NR_64_Linux 5000 | 714 | #define __NR_64_Linux 5000 |
713 | #define __NR_64_Linux_syscalls 311 | 715 | #define __NR_64_Linux_syscalls 312 |
714 | 716 | ||
715 | #if _MIPS_SIM == _MIPS_SIM_NABI32 | 717 | #if _MIPS_SIM == _MIPS_SIM_NABI32 |
716 | 718 | ||
@@ -1034,15 +1036,16 @@ | |||
1034 | #define __NR_sched_setattr (__NR_Linux + 313) | 1036 | #define __NR_sched_setattr (__NR_Linux + 313) |
1035 | #define __NR_sched_getattr (__NR_Linux + 314) | 1037 | #define __NR_sched_getattr (__NR_Linux + 314) |
1036 | #define __NR_renameat2 (__NR_Linux + 315) | 1038 | #define __NR_renameat2 (__NR_Linux + 315) |
1039 | #define __NR_seccomp (__NR_Linux + 316) | ||
1037 | 1040 | ||
1038 | /* | 1041 | /* |
1039 | * Offset of the last N32 flavoured syscall | 1042 | * Offset of the last N32 flavoured syscall |
1040 | */ | 1043 | */ |
1041 | #define __NR_Linux_syscalls 315 | 1044 | #define __NR_Linux_syscalls 316 |
1042 | 1045 | ||
1043 | #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ | 1046 | #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ |
1044 | 1047 | ||
1045 | #define __NR_N32_Linux 6000 | 1048 | #define __NR_N32_Linux 6000 |
1046 | #define __NR_N32_Linux_syscalls 315 | 1049 | #define __NR_N32_Linux_syscalls 316 |
1047 | 1050 | ||
1048 | #endif /* _UAPI_ASM_UNISTD_H */ | 1051 | #endif /* _UAPI_ASM_UNISTD_H */ |
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 3245474f19d5..ab02d14f1b5c 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S | |||
@@ -578,3 +578,4 @@ EXPORT(sys_call_table) | |||
578 | PTR sys_sched_setattr | 578 | PTR sys_sched_setattr |
579 | PTR sys_sched_getattr /* 4350 */ | 579 | PTR sys_sched_getattr /* 4350 */ |
580 | PTR sys_renameat2 | 580 | PTR sys_renameat2 |
581 | PTR sys_seccomp | ||
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index be2fedd4ae33..010dccf128ec 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S | |||
@@ -431,4 +431,5 @@ EXPORT(sys_call_table) | |||
431 | PTR sys_sched_setattr | 431 | PTR sys_sched_setattr |
432 | PTR sys_sched_getattr /* 5310 */ | 432 | PTR sys_sched_getattr /* 5310 */ |
433 | PTR sys_renameat2 | 433 | PTR sys_renameat2 |
434 | PTR sys_seccomp | ||
434 | .size sys_call_table,.-sys_call_table | 435 | .size sys_call_table,.-sys_call_table |
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index c1dbcda4b816..c3b3b6525df5 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
@@ -424,4 +424,5 @@ EXPORT(sysn32_call_table) | |||
424 | PTR sys_sched_setattr | 424 | PTR sys_sched_setattr |
425 | PTR sys_sched_getattr | 425 | PTR sys_sched_getattr |
426 | PTR sys_renameat2 /* 6315 */ | 426 | PTR sys_renameat2 /* 6315 */ |
427 | PTR sys_seccomp | ||
427 | .size sysn32_call_table,.-sysn32_call_table | 428 | .size sysn32_call_table,.-sysn32_call_table |
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index f1343ccd7ed7..bb1550b1f501 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S | |||
@@ -557,4 +557,5 @@ EXPORT(sys32_call_table) | |||
557 | PTR sys_sched_setattr | 557 | PTR sys_sched_setattr |
558 | PTR sys_sched_getattr /* 4350 */ | 558 | PTR sys_sched_getattr /* 4350 */ |
559 | PTR sys_renameat2 | 559 | PTR sys_renameat2 |
560 | PTR sys_seccomp | ||
560 | .size sys32_call_table,.-sys32_call_table | 561 | .size sys32_call_table,.-sys32_call_table |
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index d6b867921612..7527eac24122 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl | |||
@@ -360,3 +360,4 @@ | |||
360 | 351 i386 sched_setattr sys_sched_setattr | 360 | 351 i386 sched_setattr sys_sched_setattr |
361 | 352 i386 sched_getattr sys_sched_getattr | 361 | 352 i386 sched_getattr sys_sched_getattr |
362 | 353 i386 renameat2 sys_renameat2 | 362 | 353 i386 renameat2 sys_renameat2 |
363 | 354 i386 seccomp sys_seccomp | ||
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index ec255a1646d2..16272a6c12b7 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl | |||
@@ -323,6 +323,7 @@ | |||
323 | 314 common sched_setattr sys_sched_setattr | 323 | 314 common sched_setattr sys_sched_setattr |
324 | 315 common sched_getattr sys_sched_getattr | 324 | 315 common sched_getattr sys_sched_getattr |
325 | 316 common renameat2 sys_renameat2 | 325 | 316 common renameat2 sys_renameat2 |
326 | 317 common seccomp sys_seccomp | ||
326 | 327 | ||
327 | # | 328 | # |
328 | # x32-specific system call numbers start at 512 to avoid cache impact | 329 | # x32-specific system call numbers start at 512 to avoid cache impact |
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 03a6eb95ab50..4870f28403f5 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig | |||
@@ -22,7 +22,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE | |||
22 | 22 | ||
23 | config PUBLIC_KEY_ALGO_RSA | 23 | config PUBLIC_KEY_ALGO_RSA |
24 | tristate "RSA public-key algorithm" | 24 | tristate "RSA public-key algorithm" |
25 | select MPILIB_EXTRA | ||
26 | select MPILIB | 25 | select MPILIB |
27 | help | 26 | help |
28 | This option enables support for the RSA algorithm (PKCS#1, RFC3447). | 27 | This option enables support for the RSA algorithm (PKCS#1, RFC3447). |
@@ -33,8 +32,39 @@ config X509_CERTIFICATE_PARSER | |||
33 | select ASN1 | 32 | select ASN1 |
34 | select OID_REGISTRY | 33 | select OID_REGISTRY |
35 | help | 34 | help |
36 | This option procides support for parsing X.509 format blobs for key | 35 | This option provides support for parsing X.509 format blobs for key |
37 | data and provides the ability to instantiate a crypto key from a | 36 | data and provides the ability to instantiate a crypto key from a |
38 | public key packet found inside the certificate. | 37 | public key packet found inside the certificate. |
39 | 38 | ||
39 | config PKCS7_MESSAGE_PARSER | ||
40 | tristate "PKCS#7 message parser" | ||
41 | depends on X509_CERTIFICATE_PARSER | ||
42 | select ASN1 | ||
43 | select OID_REGISTRY | ||
44 | help | ||
45 | This option provides support for parsing PKCS#7 format messages for | ||
46 | signature data and provides the ability to verify the signature. | ||
47 | |||
48 | config PKCS7_TEST_KEY | ||
49 | tristate "PKCS#7 testing key type" | ||
50 | depends on PKCS7_MESSAGE_PARSER | ||
51 | select SYSTEM_TRUSTED_KEYRING | ||
52 | help | ||
53 | This option provides a type of key that can be loaded up from a | ||
54 | PKCS#7 message - provided the message is signed by a trusted key. If | ||
55 | it is, the PKCS#7 wrapper is discarded and reading the key returns | ||
56 | just the payload. If it isn't, adding the key will fail with an | ||
57 | error. | ||
58 | |||
59 | This is intended for testing the PKCS#7 parser. | ||
60 | |||
61 | config SIGNED_PE_FILE_VERIFICATION | ||
62 | bool "Support for PE file signature verification" | ||
63 | depends on PKCS7_MESSAGE_PARSER=y | ||
64 | select ASN1 | ||
65 | select OID_REGISTRY | ||
66 | help | ||
67 | This option provides support for verifying the signature(s) on a | ||
68 | signed PE binary. | ||
69 | |||
40 | endif # ASYMMETRIC_KEY_TYPE | 70 | endif # ASYMMETRIC_KEY_TYPE |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index 0727204aab68..e47fcd9ac5e8 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
@@ -25,3 +25,40 @@ $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | |||
25 | 25 | ||
26 | clean-files += x509-asn1.c x509-asn1.h | 26 | clean-files += x509-asn1.c x509-asn1.h |
27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
28 | |||
29 | # | ||
30 | # PKCS#7 message handling | ||
31 | # | ||
32 | obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o | ||
33 | pkcs7_message-y := \ | ||
34 | pkcs7-asn1.o \ | ||
35 | pkcs7_parser.o \ | ||
36 | pkcs7_trust.o \ | ||
37 | pkcs7_verify.o | ||
38 | |||
39 | $(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h | ||
40 | $(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h | ||
41 | |||
42 | clean-files += pkcs7-asn1.c pkcs7-asn1.h | ||
43 | |||
44 | # | ||
45 | # PKCS#7 parser testing key | ||
46 | # | ||
47 | obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o | ||
48 | pkcs7_test_key-y := \ | ||
49 | pkcs7_key_type.o | ||
50 | |||
51 | # | ||
52 | # Signed PE binary-wrapped key handling | ||
53 | # | ||
54 | obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o | ||
55 | |||
56 | verify_signed_pefile-y := \ | ||
57 | verify_pefile.o \ | ||
58 | mscode_parser.o \ | ||
59 | mscode-asn1.o | ||
60 | |||
61 | $(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h | ||
62 | $(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h | ||
63 | |||
64 | clean-files += mscode-asn1.c mscode-asn1.h | ||
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h index 515b63430812..a63c551c6557 100644 --- a/crypto/asymmetric_keys/asymmetric_keys.h +++ b/crypto/asymmetric_keys/asymmetric_keys.h | |||
@@ -9,6 +9,8 @@ | |||
9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | int asymmetric_keyid_match(const char *kid, const char *id); | ||
13 | |||
12 | static inline const char *asymmetric_key_id(const struct key *key) | 14 | static inline const char *asymmetric_key_id(const struct key *key) |
13 | { | 15 | { |
14 | return key->type_data.p[1]; | 16 | return key->type_data.p[1]; |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index b77eb5304788..eb8cd46961a5 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
@@ -23,6 +23,35 @@ static LIST_HEAD(asymmetric_key_parsers); | |||
23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Match asymmetric key id with partial match | ||
27 | * @id: key id to match in a form "id:<id>" | ||
28 | */ | ||
29 | int asymmetric_keyid_match(const char *kid, const char *id) | ||
30 | { | ||
31 | size_t idlen, kidlen; | ||
32 | |||
33 | if (!kid || !id) | ||
34 | return 0; | ||
35 | |||
36 | /* make it possible to use id as in the request: "id:<id>" */ | ||
37 | if (strncmp(id, "id:", 3) == 0) | ||
38 | id += 3; | ||
39 | |||
40 | /* Anything after here requires a partial match on the ID string */ | ||
41 | idlen = strlen(id); | ||
42 | kidlen = strlen(kid); | ||
43 | if (idlen > kidlen) | ||
44 | return 0; | ||
45 | |||
46 | kid += kidlen - idlen; | ||
47 | if (strcasecmp(id, kid) != 0) | ||
48 | return 0; | ||
49 | |||
50 | return 1; | ||
51 | } | ||
52 | EXPORT_SYMBOL_GPL(asymmetric_keyid_match); | ||
53 | |||
54 | /* | ||
26 | * Match asymmetric keys on (part of) their name | 55 | * Match asymmetric keys on (part of) their name |
27 | * We have some shorthand methods for matching keys. We allow: | 56 | * We have some shorthand methods for matching keys. We allow: |
28 | * | 57 | * |
@@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) | |||
34 | { | 63 | { |
35 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | 64 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); |
36 | const char *spec = description; | 65 | const char *spec = description; |
37 | const char *id, *kid; | 66 | const char *id; |
38 | ptrdiff_t speclen; | 67 | ptrdiff_t speclen; |
39 | size_t idlen, kidlen; | ||
40 | 68 | ||
41 | if (!subtype || !spec || !*spec) | 69 | if (!subtype || !spec || !*spec) |
42 | return 0; | 70 | return 0; |
@@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description) | |||
55 | speclen = id - spec; | 83 | speclen = id - spec; |
56 | id++; | 84 | id++; |
57 | 85 | ||
58 | /* Anything after here requires a partial match on the ID string */ | 86 | if (speclen == 2 && memcmp(spec, "id", 2) == 0) |
59 | kid = asymmetric_key_id(key); | 87 | return asymmetric_keyid_match(asymmetric_key_id(key), id); |
60 | if (!kid) | ||
61 | return 0; | ||
62 | |||
63 | idlen = strlen(id); | ||
64 | kidlen = strlen(kid); | ||
65 | if (idlen > kidlen) | ||
66 | return 0; | ||
67 | |||
68 | kid += kidlen - idlen; | ||
69 | if (strcasecmp(id, kid) != 0) | ||
70 | return 0; | ||
71 | |||
72 | if (speclen == 2 && | ||
73 | memcmp(spec, "id", 2) == 0) | ||
74 | return 1; | ||
75 | 88 | ||
76 | if (speclen == subtype->name_len && | 89 | if (speclen == subtype->name_len && |
77 | memcmp(spec, subtype->name, speclen) == 0) | 90 | memcmp(spec, subtype->name, speclen) == 0) |
@@ -156,7 +169,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |||
156 | pr_devel("==>%s()\n", __func__); | 169 | pr_devel("==>%s()\n", __func__); |
157 | 170 | ||
158 | if (subtype) { | 171 | if (subtype) { |
159 | subtype->destroy(prep->payload); | 172 | subtype->destroy(prep->payload[0]); |
160 | module_put(subtype->owner); | 173 | module_put(subtype->owner); |
161 | } | 174 | } |
162 | kfree(prep->type_data[1]); | 175 | kfree(prep->type_data[1]); |
@@ -164,29 +177,6 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |||
164 | } | 177 | } |
165 | 178 | ||
166 | /* | 179 | /* |
167 | * Instantiate a asymmetric_key defined key. The key was preparsed, so we just | ||
168 | * have to transfer the data here. | ||
169 | */ | ||
170 | static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
171 | { | ||
172 | int ret; | ||
173 | |||
174 | pr_devel("==>%s()\n", __func__); | ||
175 | |||
176 | ret = key_payload_reserve(key, prep->quotalen); | ||
177 | if (ret == 0) { | ||
178 | key->type_data.p[0] = prep->type_data[0]; | ||
179 | key->type_data.p[1] = prep->type_data[1]; | ||
180 | key->payload.data = prep->payload; | ||
181 | prep->type_data[0] = NULL; | ||
182 | prep->type_data[1] = NULL; | ||
183 | prep->payload = NULL; | ||
184 | } | ||
185 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * dispose of the data dangling from the corpse of a asymmetric key | 180 | * dispose of the data dangling from the corpse of a asymmetric key |
191 | */ | 181 | */ |
192 | static void asymmetric_key_destroy(struct key *key) | 182 | static void asymmetric_key_destroy(struct key *key) |
@@ -205,7 +195,7 @@ struct key_type key_type_asymmetric = { | |||
205 | .name = "asymmetric", | 195 | .name = "asymmetric", |
206 | .preparse = asymmetric_key_preparse, | 196 | .preparse = asymmetric_key_preparse, |
207 | .free_preparse = asymmetric_key_free_preparse, | 197 | .free_preparse = asymmetric_key_free_preparse, |
208 | .instantiate = asymmetric_key_instantiate, | 198 | .instantiate = generic_key_instantiate, |
209 | .match = asymmetric_key_match, | 199 | .match = asymmetric_key_match, |
210 | .destroy = asymmetric_key_destroy, | 200 | .destroy = asymmetric_key_destroy, |
211 | .describe = asymmetric_key_describe, | 201 | .describe = asymmetric_key_describe, |
diff --git a/crypto/asymmetric_keys/mscode.asn1 b/crypto/asymmetric_keys/mscode.asn1 new file mode 100644 index 000000000000..6d09ba48c41c --- /dev/null +++ b/crypto/asymmetric_keys/mscode.asn1 | |||
@@ -0,0 +1,28 @@ | |||
1 | --- Microsoft individual code signing data blob parser | ||
2 | --- | ||
3 | --- Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | --- Written by David Howells (dhowells@redhat.com) | ||
5 | --- | ||
6 | --- This program is free software; you can redistribute it and/or | ||
7 | --- modify it under the terms of the GNU General Public Licence | ||
8 | --- as published by the Free Software Foundation; either version | ||
9 | --- 2 of the Licence, or (at your option) any later version. | ||
10 | --- | ||
11 | |||
12 | MSCode ::= SEQUENCE { | ||
13 | type SEQUENCE { | ||
14 | contentType ContentType, | ||
15 | parameters ANY | ||
16 | }, | ||
17 | content SEQUENCE { | ||
18 | digestAlgorithm DigestAlgorithmIdentifier, | ||
19 | digest OCTET STRING ({ mscode_note_digest }) | ||
20 | } | ||
21 | } | ||
22 | |||
23 | ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type }) | ||
24 | |||
25 | DigestAlgorithmIdentifier ::= SEQUENCE { | ||
26 | algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }), | ||
27 | parameters ANY OPTIONAL | ||
28 | } | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c new file mode 100644 index 000000000000..214a992123cd --- /dev/null +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* Parse a Microsoft Individual Code Signing blob | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "MSCODE: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/oid_registry.h> | ||
17 | #include <crypto/pkcs7.h> | ||
18 | #include "verify_pefile.h" | ||
19 | #include "mscode-asn1.h" | ||
20 | |||
21 | /* | ||
22 | * Parse a Microsoft Individual Code Signing blob | ||
23 | */ | ||
24 | int mscode_parse(struct pefile_context *ctx) | ||
25 | { | ||
26 | const void *content_data; | ||
27 | size_t data_len; | ||
28 | int ret; | ||
29 | |||
30 | ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1); | ||
31 | |||
32 | if (ret) { | ||
33 | pr_debug("PKCS#7 message does not contain data\n"); | ||
34 | return ret; | ||
35 | } | ||
36 | |||
37 | pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len), | ||
38 | content_data); | ||
39 | |||
40 | return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len); | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * Check the content type OID | ||
45 | */ | ||
46 | int mscode_note_content_type(void *context, size_t hdrlen, | ||
47 | unsigned char tag, | ||
48 | const void *value, size_t vlen) | ||
49 | { | ||
50 | enum OID oid; | ||
51 | |||
52 | oid = look_up_OID(value, vlen); | ||
53 | if (oid == OID__NR) { | ||
54 | char buffer[50]; | ||
55 | |||
56 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
57 | pr_err("Unknown OID: %s\n", buffer); | ||
58 | return -EBADMSG; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * pesign utility had a bug where it was putting | ||
63 | * OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId | ||
64 | * So allow both OIDs. | ||
65 | */ | ||
66 | if (oid != OID_msPeImageDataObjId && | ||
67 | oid != OID_msIndividualSPKeyPurpose) { | ||
68 | pr_err("Unexpected content type OID %u\n", oid); | ||
69 | return -EBADMSG; | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * Note the digest algorithm OID | ||
77 | */ | ||
78 | int mscode_note_digest_algo(void *context, size_t hdrlen, | ||
79 | unsigned char tag, | ||
80 | const void *value, size_t vlen) | ||
81 | { | ||
82 | struct pefile_context *ctx = context; | ||
83 | char buffer[50]; | ||
84 | enum OID oid; | ||
85 | |||
86 | oid = look_up_OID(value, vlen); | ||
87 | switch (oid) { | ||
88 | case OID_md4: | ||
89 | ctx->digest_algo = HASH_ALGO_MD4; | ||
90 | break; | ||
91 | case OID_md5: | ||
92 | ctx->digest_algo = HASH_ALGO_MD5; | ||
93 | break; | ||
94 | case OID_sha1: | ||
95 | ctx->digest_algo = HASH_ALGO_SHA1; | ||
96 | break; | ||
97 | case OID_sha256: | ||
98 | ctx->digest_algo = HASH_ALGO_SHA256; | ||
99 | break; | ||
100 | |||
101 | case OID__NR: | ||
102 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
103 | pr_err("Unknown OID: %s\n", buffer); | ||
104 | return -EBADMSG; | ||
105 | |||
106 | default: | ||
107 | pr_err("Unsupported content type: %u\n", oid); | ||
108 | return -ENOPKG; | ||
109 | } | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Note the digest we're guaranteeing with this certificate | ||
116 | */ | ||
117 | int mscode_note_digest(void *context, size_t hdrlen, | ||
118 | unsigned char tag, | ||
119 | const void *value, size_t vlen) | ||
120 | { | ||
121 | struct pefile_context *ctx = context; | ||
122 | |||
123 | ctx->digest = value; | ||
124 | ctx->digest_len = vlen; | ||
125 | return 0; | ||
126 | } | ||
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1 new file mode 100644 index 000000000000..a5a14ef28c86 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7.asn1 | |||
@@ -0,0 +1,127 @@ | |||
1 | PKCS7ContentInfo ::= SEQUENCE { | ||
2 | contentType ContentType, | ||
3 | content [0] EXPLICIT SignedData OPTIONAL | ||
4 | } | ||
5 | |||
6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | ||
7 | |||
8 | SignedData ::= SEQUENCE { | ||
9 | version INTEGER, | ||
10 | digestAlgorithms DigestAlgorithmIdentifiers, | ||
11 | contentInfo ContentInfo, | ||
12 | certificates CHOICE { | ||
13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, | ||
14 | certSequence [2] IMPLICIT Certificates | ||
15 | } OPTIONAL ({ pkcs7_note_certificate_list }), | ||
16 | crls CHOICE { | ||
17 | crlSet [1] IMPLICIT CertificateRevocationLists, | ||
18 | crlSequence [3] IMPLICIT CRLSequence | ||
19 | } OPTIONAL, | ||
20 | signerInfos SignerInfos | ||
21 | } | ||
22 | |||
23 | ContentInfo ::= SEQUENCE { | ||
24 | contentType ContentType, | ||
25 | content [0] EXPLICIT Data OPTIONAL | ||
26 | } | ||
27 | |||
28 | Data ::= ANY ({ pkcs7_note_data }) | ||
29 | |||
30 | DigestAlgorithmIdentifiers ::= CHOICE { | ||
31 | daSet SET OF DigestAlgorithmIdentifier, | ||
32 | daSequence SEQUENCE OF DigestAlgorithmIdentifier | ||
33 | } | ||
34 | |||
35 | DigestAlgorithmIdentifier ::= SEQUENCE { | ||
36 | algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
37 | parameters ANY OPTIONAL | ||
38 | } | ||
39 | |||
40 | -- | ||
41 | -- Certificates and certificate lists | ||
42 | -- | ||
43 | ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate | ||
44 | |||
45 | ExtendedCertificateOrCertificate ::= CHOICE { | ||
46 | certificate Certificate, -- X.509 | ||
47 | extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6 | ||
48 | } | ||
49 | |||
50 | ExtendedCertificate ::= Certificate -- cheating | ||
51 | |||
52 | Certificates ::= SEQUENCE OF Certificate | ||
53 | |||
54 | CertificateRevocationLists ::= SET OF CertificateList | ||
55 | |||
56 | CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly | ||
57 | |||
58 | CRLSequence ::= SEQUENCE OF CertificateList | ||
59 | |||
60 | Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509 | ||
61 | |||
62 | -- | ||
63 | -- Signer information | ||
64 | -- | ||
65 | SignerInfos ::= CHOICE { | ||
66 | siSet SET OF SignerInfo, | ||
67 | siSequence SEQUENCE OF SignerInfo | ||
68 | } | ||
69 | |||
70 | SignerInfo ::= SEQUENCE { | ||
71 | version INTEGER, | ||
72 | issuerAndSerialNumber IssuerAndSerialNumber, | ||
73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), | ||
74 | authenticatedAttributes CHOICE { | ||
75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute | ||
76 | ({ pkcs7_sig_note_set_of_authattrs }), | ||
77 | aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute | ||
78 | -- Explicit because easier to compute digest on | ||
79 | -- sequence of attributes and then reuse encoded | ||
80 | -- sequence in aaSequence. | ||
81 | } OPTIONAL, | ||
82 | digestEncryptionAlgorithm | ||
83 | DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }), | ||
84 | encryptedDigest EncryptedDigest, | ||
85 | unauthenticatedAttributes CHOICE { | ||
86 | uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute, | ||
87 | uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute | ||
88 | } OPTIONAL | ||
89 | } ({ pkcs7_note_signed_info }) | ||
90 | |||
91 | IssuerAndSerialNumber ::= SEQUENCE { | ||
92 | issuer Name ({ pkcs7_sig_note_issuer }), | ||
93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | ||
94 | } | ||
95 | |||
96 | CertificateSerialNumber ::= INTEGER | ||
97 | |||
98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | ||
99 | |||
100 | AuthenticatedAttribute ::= SEQUENCE { | ||
101 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
102 | values SET OF ANY ({ pkcs7_sig_note_authenticated_attr }) | ||
103 | } | ||
104 | |||
105 | UnauthenticatedAttribute ::= SEQUENCE { | ||
106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
107 | values SET OF ANY | ||
108 | } | ||
109 | |||
110 | DigestEncryptionAlgorithmIdentifier ::= SEQUENCE { | ||
111 | algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
112 | parameters ANY OPTIONAL | ||
113 | } | ||
114 | |||
115 | EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature }) | ||
116 | |||
117 | --- | ||
118 | --- X.500 Name | ||
119 | --- | ||
120 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
121 | |||
122 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
123 | |||
124 | AttributeValueAssertion ::= SEQUENCE { | ||
125 | attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }), | ||
126 | attributeValue ANY | ||
127 | } | ||
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c new file mode 100644 index 000000000000..3de5fb011de0 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* Testing module to load key from trusted PKCS#7 message | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7key: "fmt | ||
13 | #include <linux/key.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/key-type.h> | ||
16 | #include <crypto/pkcs7.h> | ||
17 | #include <keys/user-type.h> | ||
18 | #include <keys/system_keyring.h> | ||
19 | #include "pkcs7_parser.h" | ||
20 | |||
21 | /* | ||
22 | * Preparse a PKCS#7 wrapped and validated data blob. | ||
23 | */ | ||
24 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | ||
25 | { | ||
26 | struct pkcs7_message *pkcs7; | ||
27 | const void *data, *saved_prep_data; | ||
28 | size_t datalen, saved_prep_datalen; | ||
29 | bool trusted; | ||
30 | int ret; | ||
31 | |||
32 | kenter(""); | ||
33 | |||
34 | saved_prep_data = prep->data; | ||
35 | saved_prep_datalen = prep->datalen; | ||
36 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | ||
37 | if (IS_ERR(pkcs7)) { | ||
38 | ret = PTR_ERR(pkcs7); | ||
39 | goto error; | ||
40 | } | ||
41 | |||
42 | ret = pkcs7_verify(pkcs7); | ||
43 | if (ret < 0) | ||
44 | goto error_free; | ||
45 | |||
46 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
47 | if (ret < 0) | ||
48 | goto error_free; | ||
49 | if (!trusted) | ||
50 | pr_warn("PKCS#7 message doesn't chain back to a trusted key\n"); | ||
51 | |||
52 | ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false); | ||
53 | if (ret < 0) | ||
54 | goto error_free; | ||
55 | |||
56 | prep->data = data; | ||
57 | prep->datalen = datalen; | ||
58 | ret = user_preparse(prep); | ||
59 | prep->data = saved_prep_data; | ||
60 | prep->datalen = saved_prep_datalen; | ||
61 | |||
62 | error_free: | ||
63 | pkcs7_free_message(pkcs7); | ||
64 | error: | ||
65 | kleave(" = %d", ret); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * user defined keys take an arbitrary string as the description and an | ||
71 | * arbitrary blob of data as the payload | ||
72 | */ | ||
73 | static struct key_type key_type_pkcs7 = { | ||
74 | .name = "pkcs7_test", | ||
75 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | ||
76 | .preparse = pkcs7_preparse, | ||
77 | .free_preparse = user_free_preparse, | ||
78 | .instantiate = generic_key_instantiate, | ||
79 | .match = user_match, | ||
80 | .revoke = user_revoke, | ||
81 | .destroy = user_destroy, | ||
82 | .describe = user_describe, | ||
83 | .read = user_read, | ||
84 | }; | ||
85 | |||
86 | /* | ||
87 | * Module stuff | ||
88 | */ | ||
89 | static int __init pkcs7_key_init(void) | ||
90 | { | ||
91 | return register_key_type(&key_type_pkcs7); | ||
92 | } | ||
93 | |||
94 | static void __exit pkcs7_key_cleanup(void) | ||
95 | { | ||
96 | unregister_key_type(&key_type_pkcs7); | ||
97 | } | ||
98 | |||
99 | module_init(pkcs7_key_init); | ||
100 | module_exit(pkcs7_key_cleanup); | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c new file mode 100644 index 000000000000..42e56aa7d277 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* PKCS#7 parser | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/oid_registry.h> | ||
18 | #include "public_key.h" | ||
19 | #include "pkcs7_parser.h" | ||
20 | #include "pkcs7-asn1.h" | ||
21 | |||
22 | struct pkcs7_parse_context { | ||
23 | struct pkcs7_message *msg; /* Message being constructed */ | ||
24 | struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */ | ||
25 | struct pkcs7_signed_info **ppsinfo; | ||
26 | struct x509_certificate *certs; /* Certificate cache */ | ||
27 | struct x509_certificate **ppcerts; | ||
28 | unsigned long data; /* Start of data */ | ||
29 | enum OID last_oid; /* Last OID encountered */ | ||
30 | unsigned x509_index; | ||
31 | unsigned sinfo_index; | ||
32 | }; | ||
33 | |||
34 | /** | ||
35 | * pkcs7_free_message - Free a PKCS#7 message | ||
36 | * @pkcs7: The PKCS#7 message to free | ||
37 | */ | ||
38 | void pkcs7_free_message(struct pkcs7_message *pkcs7) | ||
39 | { | ||
40 | struct x509_certificate *cert; | ||
41 | struct pkcs7_signed_info *sinfo; | ||
42 | |||
43 | if (pkcs7) { | ||
44 | while (pkcs7->certs) { | ||
45 | cert = pkcs7->certs; | ||
46 | pkcs7->certs = cert->next; | ||
47 | x509_free_certificate(cert); | ||
48 | } | ||
49 | while (pkcs7->crl) { | ||
50 | cert = pkcs7->crl; | ||
51 | pkcs7->crl = cert->next; | ||
52 | x509_free_certificate(cert); | ||
53 | } | ||
54 | while (pkcs7->signed_infos) { | ||
55 | sinfo = pkcs7->signed_infos; | ||
56 | pkcs7->signed_infos = sinfo->next; | ||
57 | mpi_free(sinfo->sig.mpi[0]); | ||
58 | kfree(sinfo->sig.digest); | ||
59 | kfree(sinfo); | ||
60 | } | ||
61 | kfree(pkcs7); | ||
62 | } | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(pkcs7_free_message); | ||
65 | |||
66 | /** | ||
67 | * pkcs7_parse_message - Parse a PKCS#7 message | ||
68 | * @data: The raw binary ASN.1 encoded message to be parsed | ||
69 | * @datalen: The size of the encoded message | ||
70 | */ | ||
71 | struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | ||
72 | { | ||
73 | struct pkcs7_parse_context *ctx; | ||
74 | struct pkcs7_message *msg; | ||
75 | long ret; | ||
76 | |||
77 | ret = -ENOMEM; | ||
78 | msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); | ||
79 | if (!msg) | ||
80 | goto error_no_sig; | ||
81 | ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL); | ||
82 | if (!ctx) | ||
83 | goto error_no_ctx; | ||
84 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | ||
85 | if (!ctx->sinfo) | ||
86 | goto error_no_sinfo; | ||
87 | |||
88 | ctx->msg = msg; | ||
89 | ctx->data = (unsigned long)data; | ||
90 | ctx->ppcerts = &ctx->certs; | ||
91 | ctx->ppsinfo = &ctx->msg->signed_infos; | ||
92 | |||
93 | /* Attempt to decode the signature */ | ||
94 | ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen); | ||
95 | if (ret < 0) | ||
96 | goto error_decode; | ||
97 | |||
98 | while (ctx->certs) { | ||
99 | struct x509_certificate *cert = ctx->certs; | ||
100 | ctx->certs = cert->next; | ||
101 | x509_free_certificate(cert); | ||
102 | } | ||
103 | mpi_free(ctx->sinfo->sig.mpi[0]); | ||
104 | kfree(ctx->sinfo->sig.digest); | ||
105 | kfree(ctx->sinfo); | ||
106 | kfree(ctx); | ||
107 | return msg; | ||
108 | |||
109 | error_decode: | ||
110 | mpi_free(ctx->sinfo->sig.mpi[0]); | ||
111 | kfree(ctx->sinfo->sig.digest); | ||
112 | kfree(ctx->sinfo); | ||
113 | error_no_sinfo: | ||
114 | kfree(ctx); | ||
115 | error_no_ctx: | ||
116 | pkcs7_free_message(msg); | ||
117 | error_no_sig: | ||
118 | return ERR_PTR(ret); | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(pkcs7_parse_message); | ||
121 | |||
122 | /** | ||
123 | * pkcs7_get_content_data - Get access to the PKCS#7 content | ||
124 | * @pkcs7: The preparsed PKCS#7 message to access | ||
125 | * @_data: Place to return a pointer to the data | ||
126 | * @_data_len: Place to return the data length | ||
127 | * @want_wrapper: True if the ASN.1 object header should be included in the data | ||
128 | * | ||
129 | * Get access to the data content of the PKCS#7 message, including, optionally, | ||
130 | * the header of the ASN.1 object that contains it. Returns -ENODATA if the | ||
131 | * data object was missing from the message. | ||
132 | */ | ||
133 | int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | ||
134 | const void **_data, size_t *_data_len, | ||
135 | bool want_wrapper) | ||
136 | { | ||
137 | size_t wrapper; | ||
138 | |||
139 | if (!pkcs7->data) | ||
140 | return -ENODATA; | ||
141 | |||
142 | wrapper = want_wrapper ? pkcs7->data_hdrlen : 0; | ||
143 | *_data = pkcs7->data - wrapper; | ||
144 | *_data_len = pkcs7->data_len + wrapper; | ||
145 | return 0; | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(pkcs7_get_content_data); | ||
148 | |||
149 | /* | ||
150 | * Note an OID when we find one for later processing when we know how | ||
151 | * to interpret it. | ||
152 | */ | ||
153 | int pkcs7_note_OID(void *context, size_t hdrlen, | ||
154 | unsigned char tag, | ||
155 | const void *value, size_t vlen) | ||
156 | { | ||
157 | struct pkcs7_parse_context *ctx = context; | ||
158 | |||
159 | ctx->last_oid = look_up_OID(value, vlen); | ||
160 | if (ctx->last_oid == OID__NR) { | ||
161 | char buffer[50]; | ||
162 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
163 | printk("PKCS7: Unknown OID: [%lu] %s\n", | ||
164 | (unsigned long)value - ctx->data, buffer); | ||
165 | } | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Note the digest algorithm for the signature. | ||
171 | */ | ||
172 | int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | ||
173 | unsigned char tag, | ||
174 | const void *value, size_t vlen) | ||
175 | { | ||
176 | struct pkcs7_parse_context *ctx = context; | ||
177 | |||
178 | switch (ctx->last_oid) { | ||
179 | case OID_md4: | ||
180 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4; | ||
181 | break; | ||
182 | case OID_md5: | ||
183 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5; | ||
184 | break; | ||
185 | case OID_sha1: | ||
186 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1; | ||
187 | break; | ||
188 | case OID_sha256: | ||
189 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; | ||
190 | break; | ||
191 | default: | ||
192 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | ||
193 | return -ENOPKG; | ||
194 | } | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Note the public key algorithm for the signature. | ||
200 | */ | ||
201 | int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | ||
202 | unsigned char tag, | ||
203 | const void *value, size_t vlen) | ||
204 | { | ||
205 | struct pkcs7_parse_context *ctx = context; | ||
206 | |||
207 | switch (ctx->last_oid) { | ||
208 | case OID_rsaEncryption: | ||
209 | ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA; | ||
210 | break; | ||
211 | default: | ||
212 | printk("Unsupported pkey algo: %u\n", ctx->last_oid); | ||
213 | return -ENOPKG; | ||
214 | } | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Extract a certificate and store it in the context. | ||
220 | */ | ||
221 | int pkcs7_extract_cert(void *context, size_t hdrlen, | ||
222 | unsigned char tag, | ||
223 | const void *value, size_t vlen) | ||
224 | { | ||
225 | struct pkcs7_parse_context *ctx = context; | ||
226 | struct x509_certificate *x509; | ||
227 | |||
228 | if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) { | ||
229 | pr_debug("Cert began with tag %02x at %lu\n", | ||
230 | tag, (unsigned long)ctx - ctx->data); | ||
231 | return -EBADMSG; | ||
232 | } | ||
233 | |||
234 | /* We have to correct for the header so that the X.509 parser can start | ||
235 | * from the beginning. Note that since X.509 stipulates DER, there | ||
236 | * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which | ||
237 | * stipulates BER). | ||
238 | */ | ||
239 | value -= hdrlen; | ||
240 | vlen += hdrlen; | ||
241 | |||
242 | if (((u8*)value)[1] == 0x80) | ||
243 | vlen += 2; /* Indefinite length - there should be an EOC */ | ||
244 | |||
245 | x509 = x509_cert_parse(value, vlen); | ||
246 | if (IS_ERR(x509)) | ||
247 | return PTR_ERR(x509); | ||
248 | |||
249 | pr_debug("Got cert for %s\n", x509->subject); | ||
250 | pr_debug("- fingerprint %s\n", x509->fingerprint); | ||
251 | |||
252 | x509->index = ++ctx->x509_index; | ||
253 | *ctx->ppcerts = x509; | ||
254 | ctx->ppcerts = &x509->next; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * Save the certificate list | ||
260 | */ | ||
261 | int pkcs7_note_certificate_list(void *context, size_t hdrlen, | ||
262 | unsigned char tag, | ||
263 | const void *value, size_t vlen) | ||
264 | { | ||
265 | struct pkcs7_parse_context *ctx = context; | ||
266 | |||
267 | pr_devel("Got cert list (%02x)\n", tag); | ||
268 | |||
269 | *ctx->ppcerts = ctx->msg->certs; | ||
270 | ctx->msg->certs = ctx->certs; | ||
271 | ctx->certs = NULL; | ||
272 | ctx->ppcerts = &ctx->certs; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * Extract the data from the message and store that and its content type OID in | ||
278 | * the context. | ||
279 | */ | ||
280 | int pkcs7_note_data(void *context, size_t hdrlen, | ||
281 | unsigned char tag, | ||
282 | const void *value, size_t vlen) | ||
283 | { | ||
284 | struct pkcs7_parse_context *ctx = context; | ||
285 | |||
286 | pr_debug("Got data\n"); | ||
287 | |||
288 | ctx->msg->data = value; | ||
289 | ctx->msg->data_len = vlen; | ||
290 | ctx->msg->data_hdrlen = hdrlen; | ||
291 | ctx->msg->data_type = ctx->last_oid; | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Parse authenticated attributes | ||
297 | */ | ||
298 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, | ||
299 | unsigned char tag, | ||
300 | const void *value, size_t vlen) | ||
301 | { | ||
302 | struct pkcs7_parse_context *ctx = context; | ||
303 | |||
304 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | ||
305 | |||
306 | switch (ctx->last_oid) { | ||
307 | case OID_messageDigest: | ||
308 | if (tag != ASN1_OTS) | ||
309 | return -EBADMSG; | ||
310 | ctx->sinfo->msgdigest = value; | ||
311 | ctx->sinfo->msgdigest_len = vlen; | ||
312 | return 0; | ||
313 | default: | ||
314 | return 0; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Note the set of auth attributes for digestion purposes [RFC2315 9.3] | ||
320 | */ | ||
321 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, | ||
322 | unsigned char tag, | ||
323 | const void *value, size_t vlen) | ||
324 | { | ||
325 | struct pkcs7_parse_context *ctx = context; | ||
326 | |||
327 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ | ||
328 | ctx->sinfo->authattrs = value - (hdrlen - 1); | ||
329 | ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Note the issuing certificate serial number | ||
335 | */ | ||
336 | int pkcs7_sig_note_serial(void *context, size_t hdrlen, | ||
337 | unsigned char tag, | ||
338 | const void *value, size_t vlen) | ||
339 | { | ||
340 | struct pkcs7_parse_context *ctx = context; | ||
341 | ctx->sinfo->raw_serial = value; | ||
342 | ctx->sinfo->raw_serial_size = vlen; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Note the issuer's name | ||
348 | */ | ||
349 | int pkcs7_sig_note_issuer(void *context, size_t hdrlen, | ||
350 | unsigned char tag, | ||
351 | const void *value, size_t vlen) | ||
352 | { | ||
353 | struct pkcs7_parse_context *ctx = context; | ||
354 | ctx->sinfo->raw_issuer = value; | ||
355 | ctx->sinfo->raw_issuer_size = vlen; | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Note the signature data | ||
361 | */ | ||
362 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, | ||
363 | unsigned char tag, | ||
364 | const void *value, size_t vlen) | ||
365 | { | ||
366 | struct pkcs7_parse_context *ctx = context; | ||
367 | MPI mpi; | ||
368 | |||
369 | BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA); | ||
370 | |||
371 | mpi = mpi_read_raw_data(value, vlen); | ||
372 | if (!mpi) | ||
373 | return -ENOMEM; | ||
374 | |||
375 | ctx->sinfo->sig.mpi[0] = mpi; | ||
376 | ctx->sinfo->sig.nr_mpi = 1; | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | * Note a signature information block | ||
382 | */ | ||
383 | int pkcs7_note_signed_info(void *context, size_t hdrlen, | ||
384 | unsigned char tag, | ||
385 | const void *value, size_t vlen) | ||
386 | { | ||
387 | struct pkcs7_parse_context *ctx = context; | ||
388 | |||
389 | ctx->sinfo->index = ++ctx->sinfo_index; | ||
390 | *ctx->ppsinfo = ctx->sinfo; | ||
391 | ctx->ppsinfo = &ctx->sinfo->next; | ||
392 | ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); | ||
393 | if (!ctx->sinfo) | ||
394 | return -ENOMEM; | ||
395 | return 0; | ||
396 | } | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h new file mode 100644 index 000000000000..d25f4d15370f --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* PKCS#7 crypto data parser internal definitions | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/oid_registry.h> | ||
13 | #include <crypto/pkcs7.h> | ||
14 | #include "x509_parser.h" | ||
15 | |||
16 | #define kenter(FMT, ...) \ | ||
17 | pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) | ||
18 | #define kleave(FMT, ...) \ | ||
19 | pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | ||
20 | |||
21 | struct pkcs7_signed_info { | ||
22 | struct pkcs7_signed_info *next; | ||
23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ | ||
24 | unsigned index; | ||
25 | bool trusted; | ||
26 | |||
27 | /* Message digest - the digest of the Content Data (or NULL) */ | ||
28 | const void *msgdigest; | ||
29 | unsigned msgdigest_len; | ||
30 | |||
31 | /* Authenticated Attribute data (or NULL) */ | ||
32 | unsigned authattrs_len; | ||
33 | const void *authattrs; | ||
34 | |||
35 | /* Issuing cert serial number and issuer's name */ | ||
36 | const void *raw_serial; | ||
37 | unsigned raw_serial_size; | ||
38 | unsigned raw_issuer_size; | ||
39 | const void *raw_issuer; | ||
40 | |||
41 | /* Message signature. | ||
42 | * | ||
43 | * This contains the generated digest of _either_ the Content Data or | ||
44 | * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of | ||
45 | * the attributes contains the digest of the the Content Data within | ||
46 | * it. | ||
47 | */ | ||
48 | struct public_key_signature sig; | ||
49 | }; | ||
50 | |||
51 | struct pkcs7_message { | ||
52 | struct x509_certificate *certs; /* Certificate list */ | ||
53 | struct x509_certificate *crl; /* Revocation list */ | ||
54 | struct pkcs7_signed_info *signed_infos; | ||
55 | |||
56 | /* Content Data (or NULL) */ | ||
57 | enum OID data_type; /* Type of Data */ | ||
58 | size_t data_len; /* Length of Data */ | ||
59 | size_t data_hdrlen; /* Length of Data ASN.1 header */ | ||
60 | const void *data; /* Content Data (or 0) */ | ||
61 | }; | ||
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c new file mode 100644 index 000000000000..e666eb011a85 --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* Validate the trust chain of a PKCS#7 message. | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/asn1.h> | ||
18 | #include <linux/key.h> | ||
19 | #include <keys/asymmetric-type.h> | ||
20 | #include "public_key.h" | ||
21 | #include "pkcs7_parser.h" | ||
22 | |||
23 | /** | ||
24 | * Check the trust on one PKCS#7 SignedInfo block. | ||
25 | */ | ||
26 | int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | ||
27 | struct pkcs7_signed_info *sinfo, | ||
28 | struct key *trust_keyring) | ||
29 | { | ||
30 | struct public_key_signature *sig = &sinfo->sig; | ||
31 | struct x509_certificate *x509, *last = NULL, *p; | ||
32 | struct key *key; | ||
33 | bool trusted; | ||
34 | int ret; | ||
35 | |||
36 | kenter(",%u,", sinfo->index); | ||
37 | |||
38 | for (x509 = sinfo->signer; x509; x509 = x509->signer) { | ||
39 | if (x509->seen) { | ||
40 | if (x509->verified) { | ||
41 | trusted = x509->trusted; | ||
42 | goto verified; | ||
43 | } | ||
44 | kleave(" = -ENOKEY [cached]"); | ||
45 | return -ENOKEY; | ||
46 | } | ||
47 | x509->seen = true; | ||
48 | |||
49 | /* Look to see if this certificate is present in the trusted | ||
50 | * keys. | ||
51 | */ | ||
52 | key = x509_request_asymmetric_key(trust_keyring, x509->subject, | ||
53 | x509->fingerprint); | ||
54 | if (!IS_ERR(key)) | ||
55 | /* One of the X.509 certificates in the PKCS#7 message | ||
56 | * is apparently the same as one we already trust. | ||
57 | * Verify that the trusted variant can also validate | ||
58 | * the signature on the descendant. | ||
59 | */ | ||
60 | goto matched; | ||
61 | if (key == ERR_PTR(-ENOMEM)) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | /* Self-signed certificates form roots of their own, and if we | ||
65 | * don't know them, then we can't accept them. | ||
66 | */ | ||
67 | if (x509->next == x509) { | ||
68 | kleave(" = -ENOKEY [unknown self-signed]"); | ||
69 | return -ENOKEY; | ||
70 | } | ||
71 | |||
72 | might_sleep(); | ||
73 | last = x509; | ||
74 | sig = &last->sig; | ||
75 | } | ||
76 | |||
77 | /* No match - see if the root certificate has a signer amongst the | ||
78 | * trusted keys. | ||
79 | */ | ||
80 | if (!last || !last->issuer || !last->authority) { | ||
81 | kleave(" = -ENOKEY [no backref]"); | ||
82 | return -ENOKEY; | ||
83 | } | ||
84 | |||
85 | key = x509_request_asymmetric_key(trust_keyring, last->issuer, | ||
86 | last->authority); | ||
87 | if (IS_ERR(key)) | ||
88 | return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; | ||
89 | x509 = last; | ||
90 | |||
91 | matched: | ||
92 | ret = verify_signature(key, sig); | ||
93 | trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); | ||
94 | key_put(key); | ||
95 | if (ret < 0) { | ||
96 | if (ret == -ENOMEM) | ||
97 | return ret; | ||
98 | kleave(" = -EKEYREJECTED [verify %d]", ret); | ||
99 | return -EKEYREJECTED; | ||
100 | } | ||
101 | |||
102 | verified: | ||
103 | x509->verified = true; | ||
104 | for (p = sinfo->signer; p != x509; p = p->signer) { | ||
105 | p->verified = true; | ||
106 | p->trusted = trusted; | ||
107 | } | ||
108 | sinfo->trusted = trusted; | ||
109 | kleave(" = 0"); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * pkcs7_validate_trust - Validate PKCS#7 trust chain | ||
115 | * @pkcs7: The PKCS#7 certificate to validate | ||
116 | * @trust_keyring: Signing certificates to use as starting points | ||
117 | * @_trusted: Set to true if trustworth, false otherwise | ||
118 | * | ||
119 | * Validate that the certificate chain inside the PKCS#7 message intersects | ||
120 | * keys we already know and trust. | ||
121 | * | ||
122 | * Returns, in order of descending priority: | ||
123 | * | ||
124 | * (*) -EKEYREJECTED if a signature failed to match for which we have a valid | ||
125 | * key, or: | ||
126 | * | ||
127 | * (*) 0 if at least one signature chain intersects with the keys in the trust | ||
128 | * keyring, or: | ||
129 | * | ||
130 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a | ||
131 | * chain. | ||
132 | * | ||
133 | * (*) -ENOKEY if we couldn't find a match for any of the signature chains in | ||
134 | * the message. | ||
135 | * | ||
136 | * May also return -ENOMEM. | ||
137 | */ | ||
138 | int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | ||
139 | struct key *trust_keyring, | ||
140 | bool *_trusted) | ||
141 | { | ||
142 | struct pkcs7_signed_info *sinfo; | ||
143 | struct x509_certificate *p; | ||
144 | int cached_ret = 0, ret; | ||
145 | |||
146 | for (p = pkcs7->certs; p; p = p->next) | ||
147 | p->seen = false; | ||
148 | |||
149 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | ||
150 | ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); | ||
151 | if (ret < 0) { | ||
152 | if (ret == -ENOPKG) { | ||
153 | cached_ret = -ENOPKG; | ||
154 | } else if (ret == -ENOKEY) { | ||
155 | if (cached_ret == 0) | ||
156 | cached_ret = -ENOKEY; | ||
157 | } else { | ||
158 | return ret; | ||
159 | } | ||
160 | } | ||
161 | *_trusted |= sinfo->trusted; | ||
162 | } | ||
163 | |||
164 | return cached_ret; | ||
165 | } | ||
166 | EXPORT_SYMBOL_GPL(pkcs7_validate_trust); | ||
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c new file mode 100644 index 000000000000..c62cf8006e1f --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
@@ -0,0 +1,321 @@ | |||
1 | /* Verify the signature on a PKCS#7 message. | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PKCS7: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/asn1.h> | ||
18 | #include <crypto/hash.h> | ||
19 | #include "public_key.h" | ||
20 | #include "pkcs7_parser.h" | ||
21 | |||
22 | /* | ||
23 | * Digest the relevant parts of the PKCS#7 data | ||
24 | */ | ||
25 | static int pkcs7_digest(struct pkcs7_message *pkcs7, | ||
26 | struct pkcs7_signed_info *sinfo) | ||
27 | { | ||
28 | struct crypto_shash *tfm; | ||
29 | struct shash_desc *desc; | ||
30 | size_t digest_size, desc_size; | ||
31 | void *digest; | ||
32 | int ret; | ||
33 | |||
34 | kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo); | ||
35 | |||
36 | if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST || | ||
37 | !hash_algo_name[sinfo->sig.pkey_hash_algo]) | ||
38 | return -ENOPKG; | ||
39 | |||
40 | /* Allocate the hashing algorithm we're going to need and find out how | ||
41 | * big the hash operational data will be. | ||
42 | */ | ||
43 | tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo], | ||
44 | 0, 0); | ||
45 | if (IS_ERR(tfm)) | ||
46 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | ||
47 | |||
48 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
49 | sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm); | ||
50 | |||
51 | ret = -ENOMEM; | ||
52 | digest = kzalloc(digest_size + desc_size, GFP_KERNEL); | ||
53 | if (!digest) | ||
54 | goto error_no_desc; | ||
55 | |||
56 | desc = digest + digest_size; | ||
57 | desc->tfm = tfm; | ||
58 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
59 | |||
60 | /* Digest the message [RFC2315 9.3] */ | ||
61 | ret = crypto_shash_init(desc); | ||
62 | if (ret < 0) | ||
63 | goto error; | ||
64 | ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest); | ||
65 | if (ret < 0) | ||
66 | goto error; | ||
67 | pr_devel("MsgDigest = [%*ph]\n", 8, digest); | ||
68 | |||
69 | /* However, if there are authenticated attributes, there must be a | ||
70 | * message digest attribute amongst them which corresponds to the | ||
71 | * digest we just calculated. | ||
72 | */ | ||
73 | if (sinfo->msgdigest) { | ||
74 | u8 tag; | ||
75 | |||
76 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | ||
77 | pr_debug("Sig %u: Invalid digest size (%u)\n", | ||
78 | sinfo->index, sinfo->msgdigest_len); | ||
79 | ret = -EBADMSG; | ||
80 | goto error; | ||
81 | } | ||
82 | |||
83 | if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) { | ||
84 | pr_debug("Sig %u: Message digest doesn't match\n", | ||
85 | sinfo->index); | ||
86 | ret = -EKEYREJECTED; | ||
87 | goto error; | ||
88 | } | ||
89 | |||
90 | /* We then calculate anew, using the authenticated attributes | ||
91 | * as the contents of the digest instead. Note that we need to | ||
92 | * convert the attributes from a CONT.0 into a SET before we | ||
93 | * hash it. | ||
94 | */ | ||
95 | memset(digest, 0, sinfo->sig.digest_size); | ||
96 | |||
97 | ret = crypto_shash_init(desc); | ||
98 | if (ret < 0) | ||
99 | goto error; | ||
100 | tag = ASN1_CONS_BIT | ASN1_SET; | ||
101 | ret = crypto_shash_update(desc, &tag, 1); | ||
102 | if (ret < 0) | ||
103 | goto error; | ||
104 | ret = crypto_shash_finup(desc, sinfo->authattrs, | ||
105 | sinfo->authattrs_len, digest); | ||
106 | if (ret < 0) | ||
107 | goto error; | ||
108 | pr_devel("AADigest = [%*ph]\n", 8, digest); | ||
109 | } | ||
110 | |||
111 | sinfo->sig.digest = digest; | ||
112 | digest = NULL; | ||
113 | |||
114 | error: | ||
115 | kfree(digest); | ||
116 | error_no_desc: | ||
117 | crypto_free_shash(tfm); | ||
118 | kleave(" = %d", ret); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7 | ||
124 | * uses the issuer's name and the issuing certificate serial number for | ||
125 | * matching purposes. These must match the certificate issuer's name (not | ||
126 | * subject's name) and the certificate serial number [RFC 2315 6.7]. | ||
127 | */ | ||
128 | static int pkcs7_find_key(struct pkcs7_message *pkcs7, | ||
129 | struct pkcs7_signed_info *sinfo) | ||
130 | { | ||
131 | struct x509_certificate *x509; | ||
132 | unsigned certix = 1; | ||
133 | |||
134 | kenter("%u,%u,%u", | ||
135 | sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size); | ||
136 | |||
137 | for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) { | ||
138 | /* I'm _assuming_ that the generator of the PKCS#7 message will | ||
139 | * encode the fields from the X.509 cert in the same way in the | ||
140 | * PKCS#7 message - but I can't be 100% sure of that. It's | ||
141 | * possible this will need element-by-element comparison. | ||
142 | */ | ||
143 | if (x509->raw_serial_size != sinfo->raw_serial_size || | ||
144 | memcmp(x509->raw_serial, sinfo->raw_serial, | ||
145 | sinfo->raw_serial_size) != 0) | ||
146 | continue; | ||
147 | pr_devel("Sig %u: Found cert serial match X.509[%u]\n", | ||
148 | sinfo->index, certix); | ||
149 | |||
150 | if (x509->raw_issuer_size != sinfo->raw_issuer_size || | ||
151 | memcmp(x509->raw_issuer, sinfo->raw_issuer, | ||
152 | sinfo->raw_issuer_size) != 0) { | ||
153 | pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n", | ||
154 | sinfo->index); | ||
155 | continue; | ||
156 | } | ||
157 | |||
158 | if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) { | ||
159 | pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n", | ||
160 | sinfo->index); | ||
161 | continue; | ||
162 | } | ||
163 | |||
164 | sinfo->signer = x509; | ||
165 | return 0; | ||
166 | } | ||
167 | pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n", | ||
168 | sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial); | ||
169 | return -ENOKEY; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Verify the internal certificate chain as best we can. | ||
174 | */ | ||
175 | static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | ||
176 | struct pkcs7_signed_info *sinfo) | ||
177 | { | ||
178 | struct x509_certificate *x509 = sinfo->signer, *p; | ||
179 | int ret; | ||
180 | |||
181 | kenter(""); | ||
182 | |||
183 | for (p = pkcs7->certs; p; p = p->next) | ||
184 | p->seen = false; | ||
185 | |||
186 | for (;;) { | ||
187 | pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint); | ||
188 | x509->seen = true; | ||
189 | ret = x509_get_sig_params(x509); | ||
190 | if (ret < 0) | ||
191 | return ret; | ||
192 | |||
193 | pr_debug("- issuer %s\n", x509->issuer); | ||
194 | if (x509->authority) | ||
195 | pr_debug("- authkeyid %s\n", x509->authority); | ||
196 | |||
197 | if (!x509->authority || | ||
198 | strcmp(x509->subject, x509->issuer) == 0) { | ||
199 | /* If there's no authority certificate specified, then | ||
200 | * the certificate must be self-signed and is the root | ||
201 | * of the chain. Likewise if the cert is its own | ||
202 | * authority. | ||
203 | */ | ||
204 | pr_debug("- no auth?\n"); | ||
205 | if (x509->raw_subject_size != x509->raw_issuer_size || | ||
206 | memcmp(x509->raw_subject, x509->raw_issuer, | ||
207 | x509->raw_issuer_size) != 0) | ||
208 | return 0; | ||
209 | |||
210 | ret = x509_check_signature(x509->pub, x509); | ||
211 | if (ret < 0) | ||
212 | return ret; | ||
213 | x509->signer = x509; | ||
214 | pr_debug("- self-signed\n"); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | /* Look through the X.509 certificates in the PKCS#7 message's | ||
219 | * list to see if the next one is there. | ||
220 | */ | ||
221 | pr_debug("- want %s\n", x509->authority); | ||
222 | for (p = pkcs7->certs; p; p = p->next) { | ||
223 | pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint); | ||
224 | if (p->raw_subject_size == x509->raw_issuer_size && | ||
225 | strcmp(p->fingerprint, x509->authority) == 0 && | ||
226 | memcmp(p->raw_subject, x509->raw_issuer, | ||
227 | x509->raw_issuer_size) == 0) | ||
228 | goto found_issuer; | ||
229 | } | ||
230 | |||
231 | /* We didn't find the root of this chain */ | ||
232 | pr_debug("- top\n"); | ||
233 | return 0; | ||
234 | |||
235 | found_issuer: | ||
236 | pr_debug("- issuer %s\n", p->subject); | ||
237 | if (p->seen) { | ||
238 | pr_warn("Sig %u: X.509 chain contains loop\n", | ||
239 | sinfo->index); | ||
240 | return 0; | ||
241 | } | ||
242 | ret = x509_check_signature(p->pub, x509); | ||
243 | if (ret < 0) | ||
244 | return ret; | ||
245 | x509->signer = p; | ||
246 | if (x509 == p) { | ||
247 | pr_debug("- self-signed\n"); | ||
248 | return 0; | ||
249 | } | ||
250 | x509 = p; | ||
251 | might_sleep(); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Verify one signed information block from a PKCS#7 message. | ||
257 | */ | ||
258 | static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | ||
259 | struct pkcs7_signed_info *sinfo) | ||
260 | { | ||
261 | int ret; | ||
262 | |||
263 | kenter(",%u", sinfo->index); | ||
264 | |||
265 | /* First of all, digest the data in the PKCS#7 message and the | ||
266 | * signed information block | ||
267 | */ | ||
268 | ret = pkcs7_digest(pkcs7, sinfo); | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | |||
272 | /* Find the key for the signature */ | ||
273 | ret = pkcs7_find_key(pkcs7, sinfo); | ||
274 | if (ret < 0) | ||
275 | return ret; | ||
276 | |||
277 | pr_devel("Using X.509[%u] for sig %u\n", | ||
278 | sinfo->signer->index, sinfo->index); | ||
279 | |||
280 | /* Verify the PKCS#7 binary against the key */ | ||
281 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | ||
282 | if (ret < 0) | ||
283 | return ret; | ||
284 | |||
285 | pr_devel("Verified signature %u\n", sinfo->index); | ||
286 | |||
287 | /* Verify the internal certificate chain */ | ||
288 | return pkcs7_verify_sig_chain(pkcs7, sinfo); | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * pkcs7_verify - Verify a PKCS#7 message | ||
293 | * @pkcs7: The PKCS#7 message to be verified | ||
294 | */ | ||
295 | int pkcs7_verify(struct pkcs7_message *pkcs7) | ||
296 | { | ||
297 | struct pkcs7_signed_info *sinfo; | ||
298 | struct x509_certificate *x509; | ||
299 | int ret, n; | ||
300 | |||
301 | kenter(""); | ||
302 | |||
303 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | ||
304 | ret = x509_get_sig_params(x509); | ||
305 | if (ret < 0) | ||
306 | return ret; | ||
307 | pr_debug("X.509[%u] %s\n", n, x509->authority); | ||
308 | } | ||
309 | |||
310 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | ||
311 | ret = pkcs7_verify_one(pkcs7, sinfo); | ||
312 | if (ret < 0) { | ||
313 | kleave(" = %d", ret); | ||
314 | return ret; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | kleave(" = 0"); | ||
319 | return 0; | ||
320 | } | ||
321 | EXPORT_SYMBOL_GPL(pkcs7_verify); | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c new file mode 100644 index 000000000000..79175e6ea0b2 --- /dev/null +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
@@ -0,0 +1,457 @@ | |||
1 | /* Parse a signed PE binary | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "PEFILE: "fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/pe.h> | ||
18 | #include <linux/asn1.h> | ||
19 | #include <crypto/pkcs7.h> | ||
20 | #include <crypto/hash.h> | ||
21 | #include "verify_pefile.h" | ||
22 | |||
23 | /* | ||
24 | * Parse a PE binary. | ||
25 | */ | ||
26 | static int pefile_parse_binary(const void *pebuf, unsigned int pelen, | ||
27 | struct pefile_context *ctx) | ||
28 | { | ||
29 | const struct mz_hdr *mz = pebuf; | ||
30 | const struct pe_hdr *pe; | ||
31 | const struct pe32_opt_hdr *pe32; | ||
32 | const struct pe32plus_opt_hdr *pe64; | ||
33 | const struct data_directory *ddir; | ||
34 | const struct data_dirent *dde; | ||
35 | const struct section_header *secs, *sec; | ||
36 | size_t cursor, datalen = pelen; | ||
37 | |||
38 | kenter(""); | ||
39 | |||
40 | #define chkaddr(base, x, s) \ | ||
41 | do { \ | ||
42 | if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \ | ||
43 | return -ELIBBAD; \ | ||
44 | } while (0) | ||
45 | |||
46 | chkaddr(0, 0, sizeof(*mz)); | ||
47 | if (mz->magic != MZ_MAGIC) | ||
48 | return -ELIBBAD; | ||
49 | cursor = sizeof(*mz); | ||
50 | |||
51 | chkaddr(cursor, mz->peaddr, sizeof(*pe)); | ||
52 | pe = pebuf + mz->peaddr; | ||
53 | if (pe->magic != PE_MAGIC) | ||
54 | return -ELIBBAD; | ||
55 | cursor = mz->peaddr + sizeof(*pe); | ||
56 | |||
57 | chkaddr(0, cursor, sizeof(pe32->magic)); | ||
58 | pe32 = pebuf + cursor; | ||
59 | pe64 = pebuf + cursor; | ||
60 | |||
61 | switch (pe32->magic) { | ||
62 | case PE_OPT_MAGIC_PE32: | ||
63 | chkaddr(0, cursor, sizeof(*pe32)); | ||
64 | ctx->image_checksum_offset = | ||
65 | (unsigned long)&pe32->csum - (unsigned long)pebuf; | ||
66 | ctx->header_size = pe32->header_size; | ||
67 | cursor += sizeof(*pe32); | ||
68 | ctx->n_data_dirents = pe32->data_dirs; | ||
69 | break; | ||
70 | |||
71 | case PE_OPT_MAGIC_PE32PLUS: | ||
72 | chkaddr(0, cursor, sizeof(*pe64)); | ||
73 | ctx->image_checksum_offset = | ||
74 | (unsigned long)&pe64->csum - (unsigned long)pebuf; | ||
75 | ctx->header_size = pe64->header_size; | ||
76 | cursor += sizeof(*pe64); | ||
77 | ctx->n_data_dirents = pe64->data_dirs; | ||
78 | break; | ||
79 | |||
80 | default: | ||
81 | pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic); | ||
82 | return -ELIBBAD; | ||
83 | } | ||
84 | |||
85 | pr_debug("checksum @ %x\n", ctx->image_checksum_offset); | ||
86 | pr_debug("header size = %x\n", ctx->header_size); | ||
87 | |||
88 | if (cursor >= ctx->header_size || ctx->header_size >= datalen) | ||
89 | return -ELIBBAD; | ||
90 | |||
91 | if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde)) | ||
92 | return -ELIBBAD; | ||
93 | |||
94 | ddir = pebuf + cursor; | ||
95 | cursor += sizeof(*dde) * ctx->n_data_dirents; | ||
96 | |||
97 | ctx->cert_dirent_offset = | ||
98 | (unsigned long)&ddir->certs - (unsigned long)pebuf; | ||
99 | ctx->certs_size = ddir->certs.size; | ||
100 | |||
101 | if (!ddir->certs.virtual_address || !ddir->certs.size) { | ||
102 | pr_debug("Unsigned PE binary\n"); | ||
103 | return -EKEYREJECTED; | ||
104 | } | ||
105 | |||
106 | chkaddr(ctx->header_size, ddir->certs.virtual_address, | ||
107 | ddir->certs.size); | ||
108 | ctx->sig_offset = ddir->certs.virtual_address; | ||
109 | ctx->sig_len = ddir->certs.size; | ||
110 | pr_debug("cert = %x @%x [%*ph]\n", | ||
111 | ctx->sig_len, ctx->sig_offset, | ||
112 | ctx->sig_len, pebuf + ctx->sig_offset); | ||
113 | |||
114 | ctx->n_sections = pe->sections; | ||
115 | if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec)) | ||
116 | return -ELIBBAD; | ||
117 | ctx->secs = secs = pebuf + cursor; | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Check and strip the PE wrapper from around the signature and check that the | ||
124 | * remnant looks something like PKCS#7. | ||
125 | */ | ||
126 | static int pefile_strip_sig_wrapper(const void *pebuf, | ||
127 | struct pefile_context *ctx) | ||
128 | { | ||
129 | struct win_certificate wrapper; | ||
130 | const u8 *pkcs7; | ||
131 | |||
132 | if (ctx->sig_len < sizeof(wrapper)) { | ||
133 | pr_debug("Signature wrapper too short\n"); | ||
134 | return -ELIBBAD; | ||
135 | } | ||
136 | |||
137 | memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper)); | ||
138 | pr_debug("sig wrapper = { %x, %x, %x }\n", | ||
139 | wrapper.length, wrapper.revision, wrapper.cert_type); | ||
140 | |||
141 | /* Both pesign and sbsign round up the length of certificate table | ||
142 | * (in optional header data directories) to 8 byte alignment. | ||
143 | */ | ||
144 | if (round_up(wrapper.length, 8) != ctx->sig_len) { | ||
145 | pr_debug("Signature wrapper len wrong\n"); | ||
146 | return -ELIBBAD; | ||
147 | } | ||
148 | if (wrapper.revision != WIN_CERT_REVISION_2_0) { | ||
149 | pr_debug("Signature is not revision 2.0\n"); | ||
150 | return -ENOTSUPP; | ||
151 | } | ||
152 | if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) { | ||
153 | pr_debug("Signature certificate type is not PKCS\n"); | ||
154 | return -ENOTSUPP; | ||
155 | } | ||
156 | |||
157 | /* Looks like actual pkcs signature length is in wrapper->length. | ||
158 | * size obtained from data dir entries lists the total size of | ||
159 | * certificate table which is also aligned to octawrod boundary. | ||
160 | * | ||
161 | * So set signature length field appropriately. | ||
162 | */ | ||
163 | ctx->sig_len = wrapper.length; | ||
164 | ctx->sig_offset += sizeof(wrapper); | ||
165 | ctx->sig_len -= sizeof(wrapper); | ||
166 | if (ctx->sig_len == 0) { | ||
167 | pr_debug("Signature data missing\n"); | ||
168 | return -EKEYREJECTED; | ||
169 | } | ||
170 | |||
171 | /* What's left should a PKCS#7 cert */ | ||
172 | pkcs7 = pebuf + ctx->sig_offset; | ||
173 | if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) { | ||
174 | if (pkcs7[1] == 0x82 && | ||
175 | pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) && | ||
176 | pkcs7[3] == ((ctx->sig_len - 4) & 0xff)) | ||
177 | return 0; | ||
178 | if (pkcs7[1] == 0x80) | ||
179 | return 0; | ||
180 | if (pkcs7[1] > 0x82) | ||
181 | return -EMSGSIZE; | ||
182 | } | ||
183 | |||
184 | pr_debug("Signature data not PKCS#7\n"); | ||
185 | return -ELIBBAD; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Compare two sections for canonicalisation. | ||
190 | */ | ||
191 | static int pefile_compare_shdrs(const void *a, const void *b) | ||
192 | { | ||
193 | const struct section_header *shdra = a; | ||
194 | const struct section_header *shdrb = b; | ||
195 | int rc; | ||
196 | |||
197 | if (shdra->data_addr > shdrb->data_addr) | ||
198 | return 1; | ||
199 | if (shdrb->data_addr > shdra->data_addr) | ||
200 | return -1; | ||
201 | |||
202 | if (shdra->virtual_address > shdrb->virtual_address) | ||
203 | return 1; | ||
204 | if (shdrb->virtual_address > shdra->virtual_address) | ||
205 | return -1; | ||
206 | |||
207 | rc = strcmp(shdra->name, shdrb->name); | ||
208 | if (rc != 0) | ||
209 | return rc; | ||
210 | |||
211 | if (shdra->virtual_size > shdrb->virtual_size) | ||
212 | return 1; | ||
213 | if (shdrb->virtual_size > shdra->virtual_size) | ||
214 | return -1; | ||
215 | |||
216 | if (shdra->raw_data_size > shdrb->raw_data_size) | ||
217 | return 1; | ||
218 | if (shdrb->raw_data_size > shdra->raw_data_size) | ||
219 | return -1; | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Load the contents of the PE binary into the digest, leaving out the image | ||
226 | * checksum and the certificate data block. | ||
227 | */ | ||
228 | static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen, | ||
229 | struct pefile_context *ctx, | ||
230 | struct shash_desc *desc) | ||
231 | { | ||
232 | unsigned *canon, tmp, loop, i, hashed_bytes; | ||
233 | int ret; | ||
234 | |||
235 | /* Digest the header and data directory, but leave out the image | ||
236 | * checksum and the data dirent for the signature. | ||
237 | */ | ||
238 | ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset); | ||
239 | if (ret < 0) | ||
240 | return ret; | ||
241 | |||
242 | tmp = ctx->image_checksum_offset + sizeof(uint32_t); | ||
243 | ret = crypto_shash_update(desc, pebuf + tmp, | ||
244 | ctx->cert_dirent_offset - tmp); | ||
245 | if (ret < 0) | ||
246 | return ret; | ||
247 | |||
248 | tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent); | ||
249 | ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp); | ||
250 | if (ret < 0) | ||
251 | return ret; | ||
252 | |||
253 | canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL); | ||
254 | if (!canon) | ||
255 | return -ENOMEM; | ||
256 | |||
257 | /* We have to canonicalise the section table, so we perform an | ||
258 | * insertion sort. | ||
259 | */ | ||
260 | canon[0] = 0; | ||
261 | for (loop = 1; loop < ctx->n_sections; loop++) { | ||
262 | for (i = 0; i < loop; i++) { | ||
263 | if (pefile_compare_shdrs(&ctx->secs[canon[i]], | ||
264 | &ctx->secs[loop]) > 0) { | ||
265 | memmove(&canon[i + 1], &canon[i], | ||
266 | (loop - i) * sizeof(canon[0])); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | canon[i] = loop; | ||
271 | } | ||
272 | |||
273 | hashed_bytes = ctx->header_size; | ||
274 | for (loop = 0; loop < ctx->n_sections; loop++) { | ||
275 | i = canon[loop]; | ||
276 | if (ctx->secs[i].raw_data_size == 0) | ||
277 | continue; | ||
278 | ret = crypto_shash_update(desc, | ||
279 | pebuf + ctx->secs[i].data_addr, | ||
280 | ctx->secs[i].raw_data_size); | ||
281 | if (ret < 0) { | ||
282 | kfree(canon); | ||
283 | return ret; | ||
284 | } | ||
285 | hashed_bytes += ctx->secs[i].raw_data_size; | ||
286 | } | ||
287 | kfree(canon); | ||
288 | |||
289 | if (pelen > hashed_bytes) { | ||
290 | tmp = hashed_bytes + ctx->certs_size; | ||
291 | ret = crypto_shash_update(desc, | ||
292 | pebuf + hashed_bytes, | ||
293 | pelen - tmp); | ||
294 | if (ret < 0) | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * Digest the contents of the PE binary, leaving out the image checksum and the | ||
303 | * certificate data block. | ||
304 | */ | ||
305 | static int pefile_digest_pe(const void *pebuf, unsigned int pelen, | ||
306 | struct pefile_context *ctx) | ||
307 | { | ||
308 | struct crypto_shash *tfm; | ||
309 | struct shash_desc *desc; | ||
310 | size_t digest_size, desc_size; | ||
311 | void *digest; | ||
312 | int ret; | ||
313 | |||
314 | kenter(",%u", ctx->digest_algo); | ||
315 | |||
316 | /* Allocate the hashing algorithm we're going to need and find out how | ||
317 | * big the hash operational data will be. | ||
318 | */ | ||
319 | tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0); | ||
320 | if (IS_ERR(tfm)) | ||
321 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | ||
322 | |||
323 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
324 | digest_size = crypto_shash_digestsize(tfm); | ||
325 | |||
326 | if (digest_size != ctx->digest_len) { | ||
327 | pr_debug("Digest size mismatch (%zx != %x)\n", | ||
328 | digest_size, ctx->digest_len); | ||
329 | ret = -EBADMSG; | ||
330 | goto error_no_desc; | ||
331 | } | ||
332 | pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size); | ||
333 | |||
334 | ret = -ENOMEM; | ||
335 | desc = kzalloc(desc_size + digest_size, GFP_KERNEL); | ||
336 | if (!desc) | ||
337 | goto error_no_desc; | ||
338 | |||
339 | desc->tfm = tfm; | ||
340 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
341 | ret = crypto_shash_init(desc); | ||
342 | if (ret < 0) | ||
343 | goto error; | ||
344 | |||
345 | ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc); | ||
346 | if (ret < 0) | ||
347 | goto error; | ||
348 | |||
349 | digest = (void *)desc + desc_size; | ||
350 | ret = crypto_shash_final(desc, digest); | ||
351 | if (ret < 0) | ||
352 | goto error; | ||
353 | |||
354 | pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest); | ||
355 | |||
356 | /* Check that the PE file digest matches that in the MSCODE part of the | ||
357 | * PKCS#7 certificate. | ||
358 | */ | ||
359 | if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) { | ||
360 | pr_debug("Digest mismatch\n"); | ||
361 | ret = -EKEYREJECTED; | ||
362 | } else { | ||
363 | pr_debug("The digests match!\n"); | ||
364 | } | ||
365 | |||
366 | error: | ||
367 | kfree(desc); | ||
368 | error_no_desc: | ||
369 | crypto_free_shash(tfm); | ||
370 | kleave(" = %d", ret); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * verify_pefile_signature - Verify the signature on a PE binary image | ||
376 | * @pebuf: Buffer containing the PE binary image | ||
377 | * @pelen: Length of the binary image | ||
378 | * @trust_keyring: Signing certificates to use as starting points | ||
379 | * @_trusted: Set to true if trustworth, false otherwise | ||
380 | * | ||
381 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | ||
382 | * binary image intersects keys we already know and trust. | ||
383 | * | ||
384 | * Returns, in order of descending priority: | ||
385 | * | ||
386 | * (*) -ELIBBAD if the image cannot be parsed, or: | ||
387 | * | ||
388 | * (*) -EKEYREJECTED if a signature failed to match for which we have a valid | ||
389 | * key, or: | ||
390 | * | ||
391 | * (*) 0 if at least one signature chain intersects with the keys in the trust | ||
392 | * keyring, or: | ||
393 | * | ||
394 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a | ||
395 | * chain. | ||
396 | * | ||
397 | * (*) -ENOKEY if we couldn't find a match for any of the signature chains in | ||
398 | * the message. | ||
399 | * | ||
400 | * May also return -ENOMEM. | ||
401 | */ | ||
402 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
403 | struct key *trusted_keyring, bool *_trusted) | ||
404 | { | ||
405 | struct pkcs7_message *pkcs7; | ||
406 | struct pefile_context ctx; | ||
407 | const void *data; | ||
408 | size_t datalen; | ||
409 | int ret; | ||
410 | |||
411 | kenter(""); | ||
412 | |||
413 | memset(&ctx, 0, sizeof(ctx)); | ||
414 | ret = pefile_parse_binary(pebuf, pelen, &ctx); | ||
415 | if (ret < 0) | ||
416 | return ret; | ||
417 | |||
418 | ret = pefile_strip_sig_wrapper(pebuf, &ctx); | ||
419 | if (ret < 0) | ||
420 | return ret; | ||
421 | |||
422 | pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len); | ||
423 | if (IS_ERR(pkcs7)) | ||
424 | return PTR_ERR(pkcs7); | ||
425 | ctx.pkcs7 = pkcs7; | ||
426 | |||
427 | ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false); | ||
428 | if (ret < 0 || datalen == 0) { | ||
429 | pr_devel("PKCS#7 message does not contain data\n"); | ||
430 | ret = -EBADMSG; | ||
431 | goto error; | ||
432 | } | ||
433 | |||
434 | ret = mscode_parse(&ctx); | ||
435 | if (ret < 0) | ||
436 | goto error; | ||
437 | |||
438 | pr_debug("Digest: %u [%*ph]\n", | ||
439 | ctx.digest_len, ctx.digest_len, ctx.digest); | ||
440 | |||
441 | /* Generate the digest and check against the PKCS7 certificate | ||
442 | * contents. | ||
443 | */ | ||
444 | ret = pefile_digest_pe(pebuf, pelen, &ctx); | ||
445 | if (ret < 0) | ||
446 | goto error; | ||
447 | |||
448 | ret = pkcs7_verify(pkcs7); | ||
449 | if (ret < 0) | ||
450 | goto error; | ||
451 | |||
452 | ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); | ||
453 | |||
454 | error: | ||
455 | pkcs7_free_message(ctx.pkcs7); | ||
456 | return ret; | ||
457 | } | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h new file mode 100644 index 000000000000..55d5f7ebc45a --- /dev/null +++ b/crypto/asymmetric_keys/verify_pefile.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* PE Binary parser bits | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/verify_pefile.h> | ||
13 | #include <crypto/pkcs7.h> | ||
14 | #include <crypto/hash_info.h> | ||
15 | |||
16 | struct pefile_context { | ||
17 | unsigned header_size; | ||
18 | unsigned image_checksum_offset; | ||
19 | unsigned cert_dirent_offset; | ||
20 | unsigned n_data_dirents; | ||
21 | unsigned n_sections; | ||
22 | unsigned certs_size; | ||
23 | unsigned sig_offset; | ||
24 | unsigned sig_len; | ||
25 | const struct section_header *secs; | ||
26 | struct pkcs7_message *pkcs7; | ||
27 | |||
28 | /* PKCS#7 MS Individual Code Signing content */ | ||
29 | const void *digest; /* Digest */ | ||
30 | unsigned digest_len; /* Digest length */ | ||
31 | enum hash_algo digest_algo; /* Digest algorithm */ | ||
32 | }; | ||
33 | |||
34 | #define kenter(FMT, ...) \ | ||
35 | pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) | ||
36 | #define kleave(FMT, ...) \ | ||
37 | pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | ||
38 | |||
39 | /* | ||
40 | * mscode_parser.c | ||
41 | */ | ||
42 | extern int mscode_parse(struct pefile_context *ctx); | ||
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1 index bf32b3dff088..aae0cde414e2 100644 --- a/crypto/asymmetric_keys/x509.asn1 +++ b/crypto/asymmetric_keys/x509.asn1 | |||
@@ -6,7 +6,7 @@ Certificate ::= SEQUENCE { | |||
6 | 6 | ||
7 | TBSCertificate ::= SEQUENCE { | 7 | TBSCertificate ::= SEQUENCE { |
8 | version [ 0 ] Version DEFAULT, | 8 | version [ 0 ] Version DEFAULT, |
9 | serialNumber CertificateSerialNumber, | 9 | serialNumber CertificateSerialNumber ({ x509_note_serial }), |
10 | signature AlgorithmIdentifier ({ x509_note_pkey_algo }), | 10 | signature AlgorithmIdentifier ({ x509_note_pkey_algo }), |
11 | issuer Name ({ x509_note_issuer }), | 11 | issuer Name ({ x509_note_issuer }), |
12 | validity Validity, | 12 | validity Validity, |
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 29893162497c..ac72348c186a 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #define pr_fmt(fmt) "X.509: "fmt | 12 | #define pr_fmt(fmt) "X.509: "fmt |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/export.h> | ||
14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
15 | #include <linux/err.h> | 16 | #include <linux/err.h> |
16 | #include <linux/oid_registry.h> | 17 | #include <linux/oid_registry.h> |
@@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert) | |||
52 | kfree(cert); | 53 | kfree(cert); |
53 | } | 54 | } |
54 | } | 55 | } |
56 | EXPORT_SYMBOL_GPL(x509_free_certificate); | ||
55 | 57 | ||
56 | /* | 58 | /* |
57 | * Parse an X.509 certificate | 59 | * Parse an X.509 certificate |
@@ -97,6 +99,7 @@ error_no_ctx: | |||
97 | error_no_cert: | 99 | error_no_cert: |
98 | return ERR_PTR(ret); | 100 | return ERR_PTR(ret); |
99 | } | 101 | } |
102 | EXPORT_SYMBOL_GPL(x509_cert_parse); | ||
100 | 103 | ||
101 | /* | 104 | /* |
102 | * Note an OID when we find one for later processing when we know how | 105 | * Note an OID when we find one for later processing when we know how |
@@ -211,6 +214,19 @@ int x509_note_signature(void *context, size_t hdrlen, | |||
211 | } | 214 | } |
212 | 215 | ||
213 | /* | 216 | /* |
217 | * Note the certificate serial number | ||
218 | */ | ||
219 | int x509_note_serial(void *context, size_t hdrlen, | ||
220 | unsigned char tag, | ||
221 | const void *value, size_t vlen) | ||
222 | { | ||
223 | struct x509_parse_context *ctx = context; | ||
224 | ctx->cert->raw_serial = value; | ||
225 | ctx->cert->raw_serial_size = vlen; | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | /* | ||
214 | * Note some of the name segments from which we'll fabricate a name. | 230 | * Note some of the name segments from which we'll fabricate a name. |
215 | */ | 231 | */ |
216 | int x509_extract_name_segment(void *context, size_t hdrlen, | 232 | int x509_extract_name_segment(void *context, size_t hdrlen, |
@@ -322,6 +338,8 @@ int x509_note_issuer(void *context, size_t hdrlen, | |||
322 | const void *value, size_t vlen) | 338 | const void *value, size_t vlen) |
323 | { | 339 | { |
324 | struct x509_parse_context *ctx = context; | 340 | struct x509_parse_context *ctx = context; |
341 | ctx->cert->raw_issuer = value; | ||
342 | ctx->cert->raw_issuer_size = vlen; | ||
325 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); | 343 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); |
326 | } | 344 | } |
327 | 345 | ||
@@ -330,6 +348,8 @@ int x509_note_subject(void *context, size_t hdrlen, | |||
330 | const void *value, size_t vlen) | 348 | const void *value, size_t vlen) |
331 | { | 349 | { |
332 | struct x509_parse_context *ctx = context; | 350 | struct x509_parse_context *ctx = context; |
351 | ctx->cert->raw_subject = value; | ||
352 | ctx->cert->raw_subject_size = vlen; | ||
333 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); | 353 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); |
334 | } | 354 | } |
335 | 355 | ||
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 87d9cc26f630..1b76f207c1f3 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
@@ -14,7 +14,9 @@ | |||
14 | 14 | ||
15 | struct x509_certificate { | 15 | struct x509_certificate { |
16 | struct x509_certificate *next; | 16 | struct x509_certificate *next; |
17 | struct x509_certificate *signer; /* Certificate that signed this one */ | ||
17 | struct public_key *pub; /* Public key details */ | 18 | struct public_key *pub; /* Public key details */ |
19 | struct public_key_signature sig; /* Signature parameters */ | ||
18 | char *issuer; /* Name of certificate issuer */ | 20 | char *issuer; /* Name of certificate issuer */ |
19 | char *subject; /* Name of certificate subject */ | 21 | char *subject; /* Name of certificate subject */ |
20 | char *fingerprint; /* Key fingerprint as hex */ | 22 | char *fingerprint; /* Key fingerprint as hex */ |
@@ -25,7 +27,16 @@ struct x509_certificate { | |||
25 | unsigned tbs_size; /* Size of signed data */ | 27 | unsigned tbs_size; /* Size of signed data */ |
26 | unsigned raw_sig_size; /* Size of sigature */ | 28 | unsigned raw_sig_size; /* Size of sigature */ |
27 | const void *raw_sig; /* Signature data */ | 29 | const void *raw_sig; /* Signature data */ |
28 | struct public_key_signature sig; /* Signature parameters */ | 30 | const void *raw_serial; /* Raw serial number in ASN.1 */ |
31 | unsigned raw_serial_size; | ||
32 | unsigned raw_issuer_size; | ||
33 | const void *raw_issuer; /* Raw issuer name in ASN.1 */ | ||
34 | const void *raw_subject; /* Raw subject name in ASN.1 */ | ||
35 | unsigned raw_subject_size; | ||
36 | unsigned index; | ||
37 | bool seen; /* Infinite recursion prevention */ | ||
38 | bool verified; | ||
39 | bool trusted; | ||
29 | }; | 40 | }; |
30 | 41 | ||
31 | /* | 42 | /* |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 382ef0d2ff2e..f3d62307e6ee 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -18,11 +18,86 @@ | |||
18 | #include <linux/asn1_decoder.h> | 18 | #include <linux/asn1_decoder.h> |
19 | #include <keys/asymmetric-subtype.h> | 19 | #include <keys/asymmetric-subtype.h> |
20 | #include <keys/asymmetric-parser.h> | 20 | #include <keys/asymmetric-parser.h> |
21 | #include <keys/system_keyring.h> | ||
21 | #include <crypto/hash.h> | 22 | #include <crypto/hash.h> |
22 | #include "asymmetric_keys.h" | 23 | #include "asymmetric_keys.h" |
23 | #include "public_key.h" | 24 | #include "public_key.h" |
24 | #include "x509_parser.h" | 25 | #include "x509_parser.h" |
25 | 26 | ||
27 | static bool use_builtin_keys; | ||
28 | static char *ca_keyid; | ||
29 | |||
30 | #ifndef MODULE | ||
31 | static int __init ca_keys_setup(char *str) | ||
32 | { | ||
33 | if (!str) /* default system keyring */ | ||
34 | return 1; | ||
35 | |||
36 | if (strncmp(str, "id:", 3) == 0) | ||
37 | ca_keyid = str; /* owner key 'id:xxxxxx' */ | ||
38 | else if (strcmp(str, "builtin") == 0) | ||
39 | use_builtin_keys = true; | ||
40 | |||
41 | return 1; | ||
42 | } | ||
43 | __setup("ca_keys=", ca_keys_setup); | ||
44 | #endif | ||
45 | |||
46 | /** | ||
47 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | ||
48 | * @keyring: The keys to search. | ||
49 | * @subject: The name of the subject to whom the key belongs. | ||
50 | * @key_id: The subject key ID as a hex string. | ||
51 | * | ||
52 | * Find a key in the given keyring by subject name and key ID. These might, | ||
53 | * for instance, be the issuer name and the authority key ID of an X.509 | ||
54 | * certificate that needs to be verified. | ||
55 | */ | ||
56 | struct key *x509_request_asymmetric_key(struct key *keyring, | ||
57 | const char *subject, | ||
58 | const char *key_id) | ||
59 | { | ||
60 | key_ref_t key; | ||
61 | size_t subject_len = strlen(subject), key_id_len = strlen(key_id); | ||
62 | char *id; | ||
63 | |||
64 | /* Construct an identifier "<subjname>:<keyid>". */ | ||
65 | id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL); | ||
66 | if (!id) | ||
67 | return ERR_PTR(-ENOMEM); | ||
68 | |||
69 | memcpy(id, subject, subject_len); | ||
70 | id[subject_len + 0] = ':'; | ||
71 | id[subject_len + 1] = ' '; | ||
72 | memcpy(id + subject_len + 2, key_id, key_id_len); | ||
73 | id[subject_len + 2 + key_id_len] = 0; | ||
74 | |||
75 | pr_debug("Look up: \"%s\"\n", id); | ||
76 | |||
77 | key = keyring_search(make_key_ref(keyring, 1), | ||
78 | &key_type_asymmetric, id); | ||
79 | if (IS_ERR(key)) | ||
80 | pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key)); | ||
81 | kfree(id); | ||
82 | |||
83 | if (IS_ERR(key)) { | ||
84 | switch (PTR_ERR(key)) { | ||
85 | /* Hide some search errors */ | ||
86 | case -EACCES: | ||
87 | case -ENOTDIR: | ||
88 | case -EAGAIN: | ||
89 | return ERR_PTR(-ENOKEY); | ||
90 | default: | ||
91 | return ERR_CAST(key); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | pr_devel("<==%s() = 0 [%x]\n", __func__, | ||
96 | key_serial(key_ref_to_ptr(key))); | ||
97 | return key_ref_to_ptr(key); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | ||
100 | |||
26 | /* | 101 | /* |
27 | * Set up the signature parameters in an X.509 certificate. This involves | 102 | * Set up the signature parameters in an X.509 certificate. This involves |
28 | * digesting the signed data and extracting the signature. | 103 | * digesting the signed data and extracting the signature. |
@@ -103,6 +178,38 @@ int x509_check_signature(const struct public_key *pub, | |||
103 | EXPORT_SYMBOL_GPL(x509_check_signature); | 178 | EXPORT_SYMBOL_GPL(x509_check_signature); |
104 | 179 | ||
105 | /* | 180 | /* |
181 | * Check the new certificate against the ones in the trust keyring. If one of | ||
182 | * those is the signing key and validates the new certificate, then mark the | ||
183 | * new certificate as being trusted. | ||
184 | * | ||
185 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | ||
186 | * find a matching parent certificate in the trusted list and an error if there | ||
187 | * is a matching certificate but the signature check fails. | ||
188 | */ | ||
189 | static int x509_validate_trust(struct x509_certificate *cert, | ||
190 | struct key *trust_keyring) | ||
191 | { | ||
192 | struct key *key; | ||
193 | int ret = 1; | ||
194 | |||
195 | if (!trust_keyring) | ||
196 | return -EOPNOTSUPP; | ||
197 | |||
198 | if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid)) | ||
199 | return -EPERM; | ||
200 | |||
201 | key = x509_request_asymmetric_key(trust_keyring, | ||
202 | cert->issuer, cert->authority); | ||
203 | if (!IS_ERR(key)) { | ||
204 | if (!use_builtin_keys | ||
205 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | ||
206 | ret = x509_check_signature(key->payload.data, cert); | ||
207 | key_put(key); | ||
208 | } | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | /* | ||
106 | * Attempt to parse a data blob for a key as an X509 certificate. | 213 | * Attempt to parse a data blob for a key as an X509 certificate. |
107 | */ | 214 | */ |
108 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 215 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
@@ -155,9 +262,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
155 | /* Check the signature on the key if it appears to be self-signed */ | 262 | /* Check the signature on the key if it appears to be self-signed */ |
156 | if (!cert->authority || | 263 | if (!cert->authority || |
157 | strcmp(cert->fingerprint, cert->authority) == 0) { | 264 | strcmp(cert->fingerprint, cert->authority) == 0) { |
158 | ret = x509_check_signature(cert->pub, cert); | 265 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
159 | if (ret < 0) | 266 | if (ret < 0) |
160 | goto error_free_cert; | 267 | goto error_free_cert; |
268 | } else if (!prep->trusted) { | ||
269 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | ||
270 | if (!ret) | ||
271 | prep->trusted = 1; | ||
161 | } | 272 | } |
162 | 273 | ||
163 | /* Propose a description */ | 274 | /* Propose a description */ |
@@ -177,7 +288,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
177 | __module_get(public_key_subtype.owner); | 288 | __module_get(public_key_subtype.owner); |
178 | prep->type_data[0] = &public_key_subtype; | 289 | prep->type_data[0] = &public_key_subtype; |
179 | prep->type_data[1] = cert->fingerprint; | 290 | prep->type_data[1] = cert->fingerprint; |
180 | prep->payload = cert->pub; | 291 | prep->payload[0] = cert->pub; |
181 | prep->description = desc; | 292 | prep->description = desc; |
182 | prep->quotalen = 100; | 293 | prep->quotalen = 100; |
183 | 294 | ||
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index da77791793f1..bf424305f3dc 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/suspend.h> | 28 | #include <linux/suspend.h> |
29 | #include <linux/syscore_ops.h> | 29 | #include <linux/syscore_ops.h> |
30 | #include <linux/reboot.h> | 30 | #include <linux/reboot.h> |
31 | #include <linux/security.h> | ||
31 | 32 | ||
32 | #include <generated/utsrelease.h> | 33 | #include <generated/utsrelease.h> |
33 | 34 | ||
@@ -303,12 +304,17 @@ static int fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf) | |||
303 | if (rc != size) { | 304 | if (rc != size) { |
304 | if (rc > 0) | 305 | if (rc > 0) |
305 | rc = -EIO; | 306 | rc = -EIO; |
306 | vfree(buf); | 307 | goto fail; |
307 | return rc; | ||
308 | } | 308 | } |
309 | rc = security_kernel_fw_from_file(file, buf, size); | ||
310 | if (rc) | ||
311 | goto fail; | ||
309 | fw_buf->data = buf; | 312 | fw_buf->data = buf; |
310 | fw_buf->size = size; | 313 | fw_buf->size = size; |
311 | return 0; | 314 | return 0; |
315 | fail: | ||
316 | vfree(buf); | ||
317 | return rc; | ||
312 | } | 318 | } |
313 | 319 | ||
314 | static int fw_get_filesystem_firmware(struct device *device, | 320 | static int fw_get_filesystem_firmware(struct device *device, |
@@ -612,6 +618,7 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
612 | { | 618 | { |
613 | struct firmware_priv *fw_priv = to_firmware_priv(dev); | 619 | struct firmware_priv *fw_priv = to_firmware_priv(dev); |
614 | struct firmware_buf *fw_buf; | 620 | struct firmware_buf *fw_buf; |
621 | ssize_t written = count; | ||
615 | int loading = simple_strtol(buf, NULL, 10); | 622 | int loading = simple_strtol(buf, NULL, 10); |
616 | int i; | 623 | int i; |
617 | 624 | ||
@@ -635,6 +642,8 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
635 | break; | 642 | break; |
636 | case 0: | 643 | case 0: |
637 | if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { | 644 | if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { |
645 | int rc; | ||
646 | |||
638 | set_bit(FW_STATUS_DONE, &fw_buf->status); | 647 | set_bit(FW_STATUS_DONE, &fw_buf->status); |
639 | clear_bit(FW_STATUS_LOADING, &fw_buf->status); | 648 | clear_bit(FW_STATUS_LOADING, &fw_buf->status); |
640 | 649 | ||
@@ -644,10 +653,23 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
644 | * see the mapped 'buf->data' once the loading | 653 | * see the mapped 'buf->data' once the loading |
645 | * is completed. | 654 | * is completed. |
646 | * */ | 655 | * */ |
647 | if (fw_map_pages_buf(fw_buf)) | 656 | rc = fw_map_pages_buf(fw_buf); |
657 | if (rc) | ||
648 | dev_err(dev, "%s: map pages failed\n", | 658 | dev_err(dev, "%s: map pages failed\n", |
649 | __func__); | 659 | __func__); |
660 | else | ||
661 | rc = security_kernel_fw_from_file(NULL, | ||
662 | fw_buf->data, fw_buf->size); | ||
663 | |||
664 | /* | ||
665 | * Same logic as fw_load_abort, only the DONE bit | ||
666 | * is ignored and we set ABORT only on failure. | ||
667 | */ | ||
650 | list_del_init(&fw_buf->pending_list); | 668 | list_del_init(&fw_buf->pending_list); |
669 | if (rc) { | ||
670 | set_bit(FW_STATUS_ABORT, &fw_buf->status); | ||
671 | written = rc; | ||
672 | } | ||
651 | complete_all(&fw_buf->completion); | 673 | complete_all(&fw_buf->completion); |
652 | break; | 674 | break; |
653 | } | 675 | } |
@@ -661,7 +683,7 @@ static ssize_t firmware_loading_store(struct device *dev, | |||
661 | } | 683 | } |
662 | out: | 684 | out: |
663 | mutex_unlock(&fw_lock); | 685 | mutex_unlock(&fw_lock); |
664 | return count; | 686 | return written; |
665 | } | 687 | } |
666 | 688 | ||
667 | static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); | 689 | static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); |
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 62e10fd1e1cb..6af17002a115 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c | |||
@@ -491,11 +491,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) | |||
491 | int tpm_get_timeouts(struct tpm_chip *chip) | 491 | int tpm_get_timeouts(struct tpm_chip *chip) |
492 | { | 492 | { |
493 | struct tpm_cmd_t tpm_cmd; | 493 | struct tpm_cmd_t tpm_cmd; |
494 | struct timeout_t *timeout_cap; | 494 | unsigned long new_timeout[4]; |
495 | unsigned long old_timeout[4]; | ||
495 | struct duration_t *duration_cap; | 496 | struct duration_t *duration_cap; |
496 | ssize_t rc; | 497 | ssize_t rc; |
497 | u32 timeout; | ||
498 | unsigned int scale = 1; | ||
499 | 498 | ||
500 | tpm_cmd.header.in = tpm_getcap_header; | 499 | tpm_cmd.header.in = tpm_getcap_header; |
501 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 500 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
@@ -529,25 +528,46 @@ int tpm_get_timeouts(struct tpm_chip *chip) | |||
529 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) | 528 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) |
530 | return -EINVAL; | 529 | return -EINVAL; |
531 | 530 | ||
532 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; | 531 | old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); |
533 | /* Don't overwrite default if value is 0 */ | 532 | old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); |
534 | timeout = be32_to_cpu(timeout_cap->a); | 533 | old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); |
535 | if (timeout && timeout < 1000) { | 534 | old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); |
536 | /* timeouts in msec rather usec */ | 535 | memcpy(new_timeout, old_timeout, sizeof(new_timeout)); |
537 | scale = 1000; | 536 | |
538 | chip->vendor.timeout_adjusted = true; | 537 | /* |
538 | * Provide ability for vendor overrides of timeout values in case | ||
539 | * of misreporting. | ||
540 | */ | ||
541 | if (chip->ops->update_timeouts != NULL) | ||
542 | chip->vendor.timeout_adjusted = | ||
543 | chip->ops->update_timeouts(chip, new_timeout); | ||
544 | |||
545 | if (!chip->vendor.timeout_adjusted) { | ||
546 | /* Don't overwrite default if value is 0 */ | ||
547 | if (new_timeout[0] != 0 && new_timeout[0] < 1000) { | ||
548 | int i; | ||
549 | |||
550 | /* timeouts in msec rather usec */ | ||
551 | for (i = 0; i != ARRAY_SIZE(new_timeout); i++) | ||
552 | new_timeout[i] *= 1000; | ||
553 | chip->vendor.timeout_adjusted = true; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | /* Report adjusted timeouts */ | ||
558 | if (chip->vendor.timeout_adjusted) { | ||
559 | dev_info(chip->dev, | ||
560 | HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", | ||
561 | old_timeout[0], new_timeout[0], | ||
562 | old_timeout[1], new_timeout[1], | ||
563 | old_timeout[2], new_timeout[2], | ||
564 | old_timeout[3], new_timeout[3]); | ||
539 | } | 565 | } |
540 | if (timeout) | 566 | |
541 | chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale); | 567 | chip->vendor.timeout_a = usecs_to_jiffies(new_timeout[0]); |
542 | timeout = be32_to_cpu(timeout_cap->b); | 568 | chip->vendor.timeout_b = usecs_to_jiffies(new_timeout[1]); |
543 | if (timeout) | 569 | chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]); |
544 | chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale); | 570 | chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]); |
545 | timeout = be32_to_cpu(timeout_cap->c); | ||
546 | if (timeout) | ||
547 | chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale); | ||
548 | timeout = be32_to_cpu(timeout_cap->d); | ||
549 | if (timeout) | ||
550 | chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale); | ||
551 | 571 | ||
552 | duration: | 572 | duration: |
553 | tpm_cmd.header.in = tpm_getcap_header; | 573 | tpm_cmd.header.in = tpm_getcap_header; |
@@ -991,13 +1011,13 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) | |||
991 | int err, total = 0, retries = 5; | 1011 | int err, total = 0, retries = 5; |
992 | u8 *dest = out; | 1012 | u8 *dest = out; |
993 | 1013 | ||
1014 | if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) | ||
1015 | return -EINVAL; | ||
1016 | |||
994 | chip = tpm_chip_find_get(chip_num); | 1017 | chip = tpm_chip_find_get(chip_num); |
995 | if (chip == NULL) | 1018 | if (chip == NULL) |
996 | return -ENODEV; | 1019 | return -ENODEV; |
997 | 1020 | ||
998 | if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) | ||
999 | return -EINVAL; | ||
1000 | |||
1001 | do { | 1021 | do { |
1002 | tpm_cmd.header.in = tpm_getrandom_header; | 1022 | tpm_cmd.header.in = tpm_getrandom_header; |
1003 | tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); | 1023 | 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) | |||
1016 | num_bytes -= recd; | 1036 | num_bytes -= recd; |
1017 | } while (retries-- && total < max); | 1037 | } while (retries-- && total < max); |
1018 | 1038 | ||
1039 | tpm_chip_put(chip); | ||
1019 | return total ? total : -EIO; | 1040 | return total ? total : -EIO; |
1020 | } | 1041 | } |
1021 | EXPORT_SYMBOL_GPL(tpm_get_random); | 1042 | EXPORT_SYMBOL_GPL(tpm_get_random); |
@@ -1095,7 +1116,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1095 | goto del_misc; | 1116 | goto del_misc; |
1096 | 1117 | ||
1097 | if (tpm_add_ppi(&dev->kobj)) | 1118 | if (tpm_add_ppi(&dev->kobj)) |
1098 | goto del_misc; | 1119 | goto del_sysfs; |
1099 | 1120 | ||
1100 | chip->bios_dir = tpm_bios_log_setup(chip->devname); | 1121 | chip->bios_dir = tpm_bios_log_setup(chip->devname); |
1101 | 1122 | ||
@@ -1106,6 +1127,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1106 | 1127 | ||
1107 | return chip; | 1128 | return chip; |
1108 | 1129 | ||
1130 | del_sysfs: | ||
1131 | tpm_sysfs_del_device(chip); | ||
1109 | del_misc: | 1132 | del_misc: |
1110 | tpm_dev_del_device(chip); | 1133 | tpm_dev_del_device(chip); |
1111 | put_device: | 1134 | put_device: |
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 59f7cb28260b..3a56a131586c 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c | |||
@@ -235,7 +235,6 @@ static int tpm_bios_measurements_release(struct inode *inode, | |||
235 | static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) | 235 | static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) |
236 | { | 236 | { |
237 | int len = 0; | 237 | int len = 0; |
238 | int i; | ||
239 | char *eventname; | 238 | char *eventname; |
240 | struct tcpa_event *event = v; | 239 | struct tcpa_event *event = v; |
241 | unsigned char *event_entry = | 240 | unsigned char *event_entry = |
@@ -251,8 +250,7 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) | |||
251 | seq_printf(m, "%2d ", event->pcr_index); | 250 | seq_printf(m, "%2d ", event->pcr_index); |
252 | 251 | ||
253 | /* 2nd: SHA1 */ | 252 | /* 2nd: SHA1 */ |
254 | for (i = 0; i < 20; i++) | 253 | seq_printf(m, "%20phN", event->pcr_value); |
255 | seq_printf(m, "%02x", event->pcr_value[i]); | ||
256 | 254 | ||
257 | /* 3rd: event type identifier */ | 255 | /* 3rd: event type identifier */ |
258 | seq_printf(m, " %02x", event->event_type); | 256 | seq_printf(m, " %02x", event->event_type); |
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 3b7bf2162898..4669e3713428 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/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) | |||
714 | } | 714 | } |
715 | 715 | ||
716 | tpm_get_timeouts(chip); | 716 | tpm_get_timeouts(chip); |
717 | tpm_do_selftest(chip); | ||
717 | 718 | ||
718 | dev_info(chip->dev, "TPM I2C Initialized\n"); | 719 | dev_info(chip->dev, "TPM I2C Initialized\n"); |
719 | return 0; | 720 | return 0; |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index a9ed2270c25d..2c46734b266d 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -373,6 +373,36 @@ out_err: | |||
373 | return rc; | 373 | return rc; |
374 | } | 374 | } |
375 | 375 | ||
376 | struct tis_vendor_timeout_override { | ||
377 | u32 did_vid; | ||
378 | unsigned long timeout_us[4]; | ||
379 | }; | ||
380 | |||
381 | static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = { | ||
382 | /* Atmel 3204 */ | ||
383 | { 0x32041114, { (TIS_SHORT_TIMEOUT*1000), (TIS_LONG_TIMEOUT*1000), | ||
384 | (TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } }, | ||
385 | }; | ||
386 | |||
387 | static bool tpm_tis_update_timeouts(struct tpm_chip *chip, | ||
388 | unsigned long *timeout_cap) | ||
389 | { | ||
390 | int i; | ||
391 | u32 did_vid; | ||
392 | |||
393 | did_vid = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); | ||
394 | |||
395 | for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) { | ||
396 | if (vendor_timeout_overrides[i].did_vid != did_vid) | ||
397 | continue; | ||
398 | memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us, | ||
399 | sizeof(vendor_timeout_overrides[i].timeout_us)); | ||
400 | return true; | ||
401 | } | ||
402 | |||
403 | return false; | ||
404 | } | ||
405 | |||
376 | /* | 406 | /* |
377 | * Early probing for iTPM with STS_DATA_EXPECT flaw. | 407 | * Early probing for iTPM with STS_DATA_EXPECT flaw. |
378 | * Try sending command without itpm flag set and if that | 408 | * Try sending command without itpm flag set and if that |
@@ -437,6 +467,7 @@ static const struct tpm_class_ops tpm_tis = { | |||
437 | .recv = tpm_tis_recv, | 467 | .recv = tpm_tis_recv, |
438 | .send = tpm_tis_send, | 468 | .send = tpm_tis_send, |
439 | .cancel = tpm_tis_ready, | 469 | .cancel = tpm_tis_ready, |
470 | .update_timeouts = tpm_tis_update_timeouts, | ||
440 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 471 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
441 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 472 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
442 | .req_canceled = tpm_tis_req_canceled, | 473 | .req_canceled = tpm_tis_req_canceled, |
@@ -1216,7 +1216,7 @@ EXPORT_SYMBOL(install_exec_creds); | |||
1216 | /* | 1216 | /* |
1217 | * determine how safe it is to execute the proposed program | 1217 | * determine how safe it is to execute the proposed program |
1218 | * - the caller must hold ->cred_guard_mutex to protect against | 1218 | * - the caller must hold ->cred_guard_mutex to protect against |
1219 | * PTRACE_ATTACH | 1219 | * PTRACE_ATTACH or seccomp thread-sync |
1220 | */ | 1220 | */ |
1221 | static void check_unsafe_exec(struct linux_binprm *bprm) | 1221 | static void check_unsafe_exec(struct linux_binprm *bprm) |
1222 | { | 1222 | { |
@@ -1234,7 +1234,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm) | |||
1234 | * This isn't strictly necessary, but it makes it harder for LSMs to | 1234 | * This isn't strictly necessary, but it makes it harder for LSMs to |
1235 | * mess up. | 1235 | * mess up. |
1236 | */ | 1236 | */ |
1237 | if (current->no_new_privs) | 1237 | if (task_no_new_privs(current)) |
1238 | bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; | 1238 | bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; |
1239 | 1239 | ||
1240 | t = p; | 1240 | t = p; |
@@ -1272,7 +1272,7 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
1272 | bprm->cred->egid = current_egid(); | 1272 | bprm->cred->egid = current_egid(); |
1273 | 1273 | ||
1274 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && | 1274 | if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && |
1275 | !current->no_new_privs && | 1275 | !task_no_new_privs(current) && |
1276 | kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) && | 1276 | kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) && |
1277 | kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) { | 1277 | kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) { |
1278 | /* Set-uid? */ | 1278 | /* Set-uid? */ |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 567983d2c0eb..7dd55b745c4d 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen) | |||
174 | 174 | ||
175 | static struct key_type key_type_id_resolver = { | 175 | static struct key_type key_type_id_resolver = { |
176 | .name = "id_resolver", | 176 | .name = "id_resolver", |
177 | .instantiate = user_instantiate, | 177 | .preparse = user_preparse, |
178 | .free_preparse = user_free_preparse, | ||
179 | .instantiate = generic_key_instantiate, | ||
178 | .match = user_match, | 180 | .match = user_match, |
179 | .revoke = user_revoke, | 181 | .revoke = user_revoke, |
180 | .destroy = user_destroy, | 182 | .destroy = user_destroy, |
@@ -282,6 +284,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen, | |||
282 | desc, "", 0, idmap); | 284 | desc, "", 0, idmap); |
283 | mutex_unlock(&idmap->idmap_mutex); | 285 | mutex_unlock(&idmap->idmap_mutex); |
284 | } | 286 | } |
287 | if (!IS_ERR(rkey)) | ||
288 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
285 | 289 | ||
286 | kfree(desc); | 290 | kfree(desc); |
287 | return rkey; | 291 | return rkey; |
@@ -394,7 +398,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = { | |||
394 | 398 | ||
395 | static struct key_type key_type_id_resolver_legacy = { | 399 | static struct key_type key_type_id_resolver_legacy = { |
396 | .name = "id_legacy", | 400 | .name = "id_legacy", |
397 | .instantiate = user_instantiate, | 401 | .preparse = user_preparse, |
402 | .free_preparse = user_free_preparse, | ||
403 | .instantiate = generic_key_instantiate, | ||
398 | .match = user_match, | 404 | .match = user_match, |
399 | .revoke = user_revoke, | 405 | .revoke = user_revoke, |
400 | .destroy = user_destroy, | 406 | .destroy = user_destroy, |
diff --git a/fs/proc/array.c b/fs/proc/array.c index d7f9199217bb..cd3653e4f35c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -297,15 +297,11 @@ static void render_cap_t(struct seq_file *m, const char *header, | |||
297 | seq_puts(m, header); | 297 | seq_puts(m, header); |
298 | CAP_FOR_EACH_U32(__capi) { | 298 | CAP_FOR_EACH_U32(__capi) { |
299 | seq_printf(m, "%08x", | 299 | seq_printf(m, "%08x", |
300 | a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]); | 300 | a->cap[CAP_LAST_U32 - __capi]); |
301 | } | 301 | } |
302 | seq_putc(m, '\n'); | 302 | seq_putc(m, '\n'); |
303 | } | 303 | } |
304 | 304 | ||
305 | /* Remove non-existent capabilities */ | ||
306 | #define NORM_CAPS(v) (v.cap[CAP_TO_INDEX(CAP_LAST_CAP)] &= \ | ||
307 | CAP_TO_MASK(CAP_LAST_CAP + 1) - 1) | ||
308 | |||
309 | static inline void task_cap(struct seq_file *m, struct task_struct *p) | 305 | static inline void task_cap(struct seq_file *m, struct task_struct *p) |
310 | { | 306 | { |
311 | const struct cred *cred; | 307 | const struct cred *cred; |
@@ -319,11 +315,6 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p) | |||
319 | cap_bset = cred->cap_bset; | 315 | cap_bset = cred->cap_bset; |
320 | rcu_read_unlock(); | 316 | rcu_read_unlock(); |
321 | 317 | ||
322 | NORM_CAPS(cap_inheritable); | ||
323 | NORM_CAPS(cap_permitted); | ||
324 | NORM_CAPS(cap_effective); | ||
325 | NORM_CAPS(cap_bset); | ||
326 | |||
327 | render_cap_t(m, "CapInh:\t", &cap_inheritable); | 318 | render_cap_t(m, "CapInh:\t", &cap_inheritable); |
328 | render_cap_t(m, "CapPrm:\t", &cap_permitted); | 319 | render_cap_t(m, "CapPrm:\t", &cap_permitted); |
329 | render_cap_t(m, "CapEff:\t", &cap_effective); | 320 | render_cap_t(m, "CapEff:\t", &cap_effective); |
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h new file mode 100644 index 000000000000..691c79172a26 --- /dev/null +++ b/include/crypto/pkcs7.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* PKCS#7 crypto data parser | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | struct key; | ||
13 | struct pkcs7_message; | ||
14 | |||
15 | /* | ||
16 | * pkcs7_parser.c | ||
17 | */ | ||
18 | extern struct pkcs7_message *pkcs7_parse_message(const void *data, | ||
19 | size_t datalen); | ||
20 | extern void pkcs7_free_message(struct pkcs7_message *pkcs7); | ||
21 | |||
22 | extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, | ||
23 | const void **_data, size_t *_datalen, | ||
24 | bool want_wrapper); | ||
25 | |||
26 | /* | ||
27 | * pkcs7_trust.c | ||
28 | */ | ||
29 | extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | ||
30 | struct key *trust_keyring, | ||
31 | bool *_trusted); | ||
32 | |||
33 | /* | ||
34 | * pkcs7_verify.c | ||
35 | */ | ||
36 | extern int pkcs7_verify(struct pkcs7_message *pkcs7); | ||
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index fc09732613ad..0d164c6af539 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h | |||
@@ -98,4 +98,8 @@ struct key; | |||
98 | extern int verify_signature(const struct key *key, | 98 | extern int verify_signature(const struct key *key, |
99 | const struct public_key_signature *sig); | 99 | const struct public_key_signature *sig); |
100 | 100 | ||
101 | extern struct key *x509_request_asymmetric_key(struct key *keyring, | ||
102 | const char *issuer, | ||
103 | const char *key_id); | ||
104 | |||
101 | #endif /* _LINUX_PUBLIC_KEY_H */ | 105 | #endif /* _LINUX_PUBLIC_KEY_H */ |
diff --git a/include/keys/big_key-type.h b/include/keys/big_key-type.h index d69bc8af3292..e0970a578188 100644 --- a/include/keys/big_key-type.h +++ b/include/keys/big_key-type.h | |||
@@ -16,7 +16,8 @@ | |||
16 | 16 | ||
17 | extern struct key_type key_type_big_key; | 17 | extern struct key_type key_type_big_key; |
18 | 18 | ||
19 | extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | 19 | extern int big_key_preparse(struct key_preparsed_payload *prep); |
20 | extern void big_key_free_preparse(struct key_preparsed_payload *prep); | ||
20 | extern void big_key_revoke(struct key *key); | 21 | extern void big_key_revoke(struct key *key); |
21 | extern void big_key_destroy(struct key *key); | 22 | extern void big_key_destroy(struct key *key); |
22 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); | 23 | extern void big_key_describe(const struct key *big_key, struct seq_file *m); |
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 8dabc399bd1d..72665eb80692 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h | |||
@@ -17,7 +17,15 @@ | |||
17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
18 | 18 | ||
19 | extern struct key *system_trusted_keyring; | 19 | extern struct key *system_trusted_keyring; |
20 | 20 | static inline struct key *get_system_trusted_keyring(void) | |
21 | { | ||
22 | return system_trusted_keyring; | ||
23 | } | ||
24 | #else | ||
25 | static inline struct key *get_system_trusted_keyring(void) | ||
26 | { | ||
27 | return NULL; | ||
28 | } | ||
21 | #endif | 29 | #endif |
22 | 30 | ||
23 | #endif /* _KEYS_SYSTEM_KEYRING_H */ | 31 | #endif /* _KEYS_SYSTEM_KEYRING_H */ |
diff --git a/include/keys/user-type.h b/include/keys/user-type.h index 5e452c84f1e6..3ab1873a4bfa 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h | |||
@@ -37,7 +37,8 @@ extern struct key_type key_type_logon; | |||
37 | 37 | ||
38 | struct key_preparsed_payload; | 38 | struct key_preparsed_payload; |
39 | 39 | ||
40 | extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep); | 40 | extern int user_preparse(struct key_preparsed_payload *prep); |
41 | extern void user_free_preparse(struct key_preparsed_payload *prep); | ||
41 | extern int user_update(struct key *key, struct key_preparsed_payload *prep); | 42 | extern int user_update(struct key *key, struct key_preparsed_payload *prep); |
42 | extern int user_match(const struct key *key, const void *criterion); | 43 | extern int user_match(const struct key *key, const void *criterion); |
43 | extern void user_revoke(struct key *key); | 44 | extern void user_revoke(struct key *key); |
diff --git a/include/linux/capability.h b/include/linux/capability.h index 84b13ad67c1c..aa93e5ef594c 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -78,8 +78,11 @@ extern const kernel_cap_t __cap_init_eff_set; | |||
78 | # error Fix up hand-coded capability macro initializers | 78 | # error Fix up hand-coded capability macro initializers |
79 | #else /* HAND-CODED capability initializers */ | 79 | #else /* HAND-CODED capability initializers */ |
80 | 80 | ||
81 | #define CAP_LAST_U32 ((_KERNEL_CAPABILITY_U32S) - 1) | ||
82 | #define CAP_LAST_U32_VALID_MASK (CAP_TO_MASK(CAP_LAST_CAP + 1) -1) | ||
83 | |||
81 | # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) | 84 | # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) |
82 | # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }}) | 85 | # define CAP_FULL_SET ((kernel_cap_t){{ ~0, CAP_LAST_U32_VALID_MASK }}) |
83 | # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ | 86 | # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ |
84 | | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ | 87 | | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ |
85 | CAP_FS_MASK_B1 } }) | 88 | CAP_FS_MASK_B1 } }) |
diff --git a/include/linux/ima.h b/include/linux/ima.h index 1b7f268cddce..7cf5e9b32550 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
@@ -19,6 +19,7 @@ extern int ima_file_check(struct file *file, int mask); | |||
19 | extern void ima_file_free(struct file *file); | 19 | extern void ima_file_free(struct file *file); |
20 | extern int ima_file_mmap(struct file *file, unsigned long prot); | 20 | extern int ima_file_mmap(struct file *file, unsigned long prot); |
21 | extern int ima_module_check(struct file *file); | 21 | extern int ima_module_check(struct file *file); |
22 | extern int ima_fw_from_file(struct file *file, char *buf, size_t size); | ||
22 | 23 | ||
23 | #else | 24 | #else |
24 | static inline int ima_bprm_check(struct linux_binprm *bprm) | 25 | static inline int ima_bprm_check(struct linux_binprm *bprm) |
@@ -46,6 +47,11 @@ static inline int ima_module_check(struct file *file) | |||
46 | return 0; | 47 | return 0; |
47 | } | 48 | } |
48 | 49 | ||
50 | static inline int ima_fw_from_file(struct file *file, char *buf, size_t size) | ||
51 | { | ||
52 | return 0; | ||
53 | } | ||
54 | |||
49 | #endif /* CONFIG_IMA */ | 55 | #endif /* CONFIG_IMA */ |
50 | 56 | ||
51 | #ifdef CONFIG_IMA_APPRAISE | 57 | #ifdef CONFIG_IMA_APPRAISE |
diff --git a/include/linux/key-type.h b/include/linux/key-type.h index a74c3a84dfdd..44792ee649de 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h | |||
@@ -41,10 +41,11 @@ struct key_construction { | |||
41 | struct key_preparsed_payload { | 41 | struct key_preparsed_payload { |
42 | char *description; /* Proposed key description (or NULL) */ | 42 | char *description; /* Proposed key description (or NULL) */ |
43 | void *type_data[2]; /* Private key-type data */ | 43 | void *type_data[2]; /* Private key-type data */ |
44 | void *payload; /* Proposed payload */ | 44 | void *payload[2]; /* Proposed payload */ |
45 | const void *data; /* Raw data */ | 45 | const void *data; /* Raw data */ |
46 | size_t datalen; /* Raw datalen */ | 46 | size_t datalen; /* Raw datalen */ |
47 | size_t quotalen; /* Quota length for proposed payload */ | 47 | size_t quotalen; /* Quota length for proposed payload */ |
48 | time_t expiry; /* Expiry time of key */ | ||
48 | bool trusted; /* True if key is trusted */ | 49 | bool trusted; /* True if key is trusted */ |
49 | }; | 50 | }; |
50 | 51 | ||
@@ -159,5 +160,7 @@ static inline int key_negate_and_link(struct key *key, | |||
159 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); | 160 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); |
160 | } | 161 | } |
161 | 162 | ||
163 | extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep); | ||
164 | |||
162 | #endif /* CONFIG_KEYS */ | 165 | #endif /* CONFIG_KEYS */ |
163 | #endif /* _LINUX_KEY_TYPE_H */ | 166 | #endif /* _LINUX_KEY_TYPE_H */ |
diff --git a/include/linux/key.h b/include/linux/key.h index 017b0826642f..e1d4715f3222 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -170,6 +170,8 @@ struct key { | |||
170 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ | 170 | #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ |
171 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ | 171 | #define KEY_FLAG_TRUSTED 8 /* set if key is trusted */ |
172 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ | 172 | #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */ |
173 | #define KEY_FLAG_BUILTIN 10 /* set if key is builtin */ | ||
174 | #define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */ | ||
173 | 175 | ||
174 | /* the key type and key description string | 176 | /* the key type and key description string |
175 | * - the desc is used to match a key against search criteria | 177 | * - the desc is used to match a key against search criteria |
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 6926db724258..c2bbf672b84e 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h | |||
@@ -52,9 +52,15 @@ enum OID { | |||
52 | OID_md4, /* 1.2.840.113549.2.4 */ | 52 | OID_md4, /* 1.2.840.113549.2.4 */ |
53 | OID_md5, /* 1.2.840.113549.2.5 */ | 53 | OID_md5, /* 1.2.840.113549.2.5 */ |
54 | 54 | ||
55 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | 55 | /* Microsoft Authenticode & Software Publishing */ |
56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ | ||
57 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ | ||
58 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ | ||
56 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ | 59 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ |
60 | |||
61 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | ||
57 | OID_sha1, /* 1.3.14.3.2.26 */ | 62 | OID_sha1, /* 1.3.14.3.2.26 */ |
63 | OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ | ||
58 | 64 | ||
59 | /* Distinguished Name attribute IDs [RFC 2256] */ | 65 | /* Distinguished Name attribute IDs [RFC 2256] */ |
60 | OID_commonName, /* 2.5.4.3 */ | 66 | OID_commonName, /* 2.5.4.3 */ |
diff --git a/include/linux/pe.h b/include/linux/pe.h new file mode 100644 index 000000000000..e170b95e763b --- /dev/null +++ b/include/linux/pe.h | |||
@@ -0,0 +1,448 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Red Hat, Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | * Author(s): Peter Jones <pjones@redhat.com> | ||
18 | */ | ||
19 | #ifndef __LINUX_PE_H | ||
20 | #define __LINUX_PE_H | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | |||
24 | #define MZ_MAGIC 0x5a4d /* "MZ" */ | ||
25 | |||
26 | struct mz_hdr { | ||
27 | uint16_t magic; /* MZ_MAGIC */ | ||
28 | uint16_t lbsize; /* size of last used block */ | ||
29 | uint16_t blocks; /* pages in file, 0x3 */ | ||
30 | uint16_t relocs; /* relocations */ | ||
31 | uint16_t hdrsize; /* header size in "paragraphs" */ | ||
32 | uint16_t min_extra_pps; /* .bss */ | ||
33 | uint16_t max_extra_pps; /* runtime limit for the arena size */ | ||
34 | uint16_t ss; /* relative stack segment */ | ||
35 | uint16_t sp; /* initial %sp register */ | ||
36 | uint16_t checksum; /* word checksum */ | ||
37 | uint16_t ip; /* initial %ip register */ | ||
38 | uint16_t cs; /* initial %cs relative to load segment */ | ||
39 | uint16_t reloc_table_offset; /* offset of the first relocation */ | ||
40 | uint16_t overlay_num; /* overlay number. set to 0. */ | ||
41 | uint16_t reserved0[4]; /* reserved */ | ||
42 | uint16_t oem_id; /* oem identifier */ | ||
43 | uint16_t oem_info; /* oem specific */ | ||
44 | uint16_t reserved1[10]; /* reserved */ | ||
45 | uint32_t peaddr; /* address of pe header */ | ||
46 | char message[64]; /* message to print */ | ||
47 | }; | ||
48 | |||
49 | struct mz_reloc { | ||
50 | uint16_t offset; | ||
51 | uint16_t segment; | ||
52 | }; | ||
53 | |||
54 | #define PE_MAGIC 0x00004550 /* "PE\0\0" */ | ||
55 | #define PE_OPT_MAGIC_PE32 0x010b | ||
56 | #define PE_OPT_MAGIC_PE32_ROM 0x0107 | ||
57 | #define PE_OPT_MAGIC_PE32PLUS 0x020b | ||
58 | |||
59 | /* machine type */ | ||
60 | #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 | ||
61 | #define IMAGE_FILE_MACHINE_AM33 0x01d3 | ||
62 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 | ||
63 | #define IMAGE_FILE_MACHINE_ARM 0x01c0 | ||
64 | #define IMAGE_FILE_MACHINE_ARMV7 0x01c4 | ||
65 | #define IMAGE_FILE_MACHINE_EBC 0x0ebc | ||
66 | #define IMAGE_FILE_MACHINE_I386 0x014c | ||
67 | #define IMAGE_FILE_MACHINE_IA64 0x0200 | ||
68 | #define IMAGE_FILE_MACHINE_M32R 0x9041 | ||
69 | #define IMAGE_FILE_MACHINE_MIPS16 0x0266 | ||
70 | #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 | ||
71 | #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 | ||
72 | #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 | ||
73 | #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 | ||
74 | #define IMAGE_FILE_MACHINE_R4000 0x0166 | ||
75 | #define IMAGE_FILE_MACHINE_SH3 0x01a2 | ||
76 | #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 | ||
77 | #define IMAGE_FILE_MACHINE_SH3E 0x01a4 | ||
78 | #define IMAGE_FILE_MACHINE_SH4 0x01a6 | ||
79 | #define IMAGE_FILE_MACHINE_SH5 0x01a8 | ||
80 | #define IMAGE_FILE_MACHINE_THUMB 0x01c2 | ||
81 | #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 | ||
82 | |||
83 | /* flags */ | ||
84 | #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 | ||
85 | #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 | ||
86 | #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 | ||
87 | #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 | ||
88 | #define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 | ||
89 | #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 | ||
90 | #define IMAGE_FILE_16BIT_MACHINE 0x0040 | ||
91 | #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 | ||
92 | #define IMAGE_FILE_32BIT_MACHINE 0x0100 | ||
93 | #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 | ||
94 | #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 | ||
95 | #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 | ||
96 | #define IMAGE_FILE_SYSTEM 0x1000 | ||
97 | #define IMAGE_FILE_DLL 0x2000 | ||
98 | #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 | ||
99 | #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 | ||
100 | |||
101 | struct pe_hdr { | ||
102 | uint32_t magic; /* PE magic */ | ||
103 | uint16_t machine; /* machine type */ | ||
104 | uint16_t sections; /* number of sections */ | ||
105 | uint32_t timestamp; /* time_t */ | ||
106 | uint32_t symbol_table; /* symbol table offset */ | ||
107 | uint32_t symbols; /* number of symbols */ | ||
108 | uint16_t opt_hdr_size; /* size of optional header */ | ||
109 | uint16_t flags; /* flags */ | ||
110 | }; | ||
111 | |||
112 | #define IMAGE_FILE_OPT_ROM_MAGIC 0x107 | ||
113 | #define IMAGE_FILE_OPT_PE32_MAGIC 0x10b | ||
114 | #define IMAGE_FILE_OPT_PE32_PLUS_MAGIC 0x20b | ||
115 | |||
116 | #define IMAGE_SUBSYSTEM_UNKNOWN 0 | ||
117 | #define IMAGE_SUBSYSTEM_NATIVE 1 | ||
118 | #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 | ||
119 | #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 | ||
120 | #define IMAGE_SUBSYSTEM_POSIX_CUI 7 | ||
121 | #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 | ||
122 | #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 | ||
123 | #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 | ||
124 | #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 | ||
125 | #define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 | ||
126 | #define IMAGE_SUBSYSTEM_XBOX 14 | ||
127 | |||
128 | #define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040 | ||
129 | #define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080 | ||
130 | #define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100 | ||
131 | #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 | ||
132 | #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 | ||
133 | #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 | ||
134 | #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 | ||
135 | #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 | ||
136 | |||
137 | /* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't | ||
138 | * work right. vomit. */ | ||
139 | struct pe32_opt_hdr { | ||
140 | /* "standard" header */ | ||
141 | uint16_t magic; /* file type */ | ||
142 | uint8_t ld_major; /* linker major version */ | ||
143 | uint8_t ld_minor; /* linker minor version */ | ||
144 | uint32_t text_size; /* size of text section(s) */ | ||
145 | uint32_t data_size; /* size of data section(s) */ | ||
146 | uint32_t bss_size; /* size of bss section(s) */ | ||
147 | uint32_t entry_point; /* file offset of entry point */ | ||
148 | uint32_t code_base; /* relative code addr in ram */ | ||
149 | uint32_t data_base; /* relative data addr in ram */ | ||
150 | /* "windows" header */ | ||
151 | uint32_t image_base; /* preferred load address */ | ||
152 | uint32_t section_align; /* alignment in bytes */ | ||
153 | uint32_t file_align; /* file alignment in bytes */ | ||
154 | uint16_t os_major; /* major OS version */ | ||
155 | uint16_t os_minor; /* minor OS version */ | ||
156 | uint16_t image_major; /* major image version */ | ||
157 | uint16_t image_minor; /* minor image version */ | ||
158 | uint16_t subsys_major; /* major subsystem version */ | ||
159 | uint16_t subsys_minor; /* minor subsystem version */ | ||
160 | uint32_t win32_version; /* reserved, must be 0 */ | ||
161 | uint32_t image_size; /* image size */ | ||
162 | uint32_t header_size; /* header size rounded up to | ||
163 | file_align */ | ||
164 | uint32_t csum; /* checksum */ | ||
165 | uint16_t subsys; /* subsystem */ | ||
166 | uint16_t dll_flags; /* more flags! */ | ||
167 | uint32_t stack_size_req;/* amt of stack requested */ | ||
168 | uint32_t stack_size; /* amt of stack required */ | ||
169 | uint32_t heap_size_req; /* amt of heap requested */ | ||
170 | uint32_t heap_size; /* amt of heap required */ | ||
171 | uint32_t loader_flags; /* reserved, must be 0 */ | ||
172 | uint32_t data_dirs; /* number of data dir entries */ | ||
173 | }; | ||
174 | |||
175 | struct pe32plus_opt_hdr { | ||
176 | uint16_t magic; /* file type */ | ||
177 | uint8_t ld_major; /* linker major version */ | ||
178 | uint8_t ld_minor; /* linker minor version */ | ||
179 | uint32_t text_size; /* size of text section(s) */ | ||
180 | uint32_t data_size; /* size of data section(s) */ | ||
181 | uint32_t bss_size; /* size of bss section(s) */ | ||
182 | uint32_t entry_point; /* file offset of entry point */ | ||
183 | uint32_t code_base; /* relative code addr in ram */ | ||
184 | /* "windows" header */ | ||
185 | uint64_t image_base; /* preferred load address */ | ||
186 | uint32_t section_align; /* alignment in bytes */ | ||
187 | uint32_t file_align; /* file alignment in bytes */ | ||
188 | uint16_t os_major; /* major OS version */ | ||
189 | uint16_t os_minor; /* minor OS version */ | ||
190 | uint16_t image_major; /* major image version */ | ||
191 | uint16_t image_minor; /* minor image version */ | ||
192 | uint16_t subsys_major; /* major subsystem version */ | ||
193 | uint16_t subsys_minor; /* minor subsystem version */ | ||
194 | uint32_t win32_version; /* reserved, must be 0 */ | ||
195 | uint32_t image_size; /* image size */ | ||
196 | uint32_t header_size; /* header size rounded up to | ||
197 | file_align */ | ||
198 | uint32_t csum; /* checksum */ | ||
199 | uint16_t subsys; /* subsystem */ | ||
200 | uint16_t dll_flags; /* more flags! */ | ||
201 | uint64_t stack_size_req;/* amt of stack requested */ | ||
202 | uint64_t stack_size; /* amt of stack required */ | ||
203 | uint64_t heap_size_req; /* amt of heap requested */ | ||
204 | uint64_t heap_size; /* amt of heap required */ | ||
205 | uint32_t loader_flags; /* reserved, must be 0 */ | ||
206 | uint32_t data_dirs; /* number of data dir entries */ | ||
207 | }; | ||
208 | |||
209 | struct data_dirent { | ||
210 | uint32_t virtual_address; /* relative to load address */ | ||
211 | uint32_t size; | ||
212 | }; | ||
213 | |||
214 | struct data_directory { | ||
215 | struct data_dirent exports; /* .edata */ | ||
216 | struct data_dirent imports; /* .idata */ | ||
217 | struct data_dirent resources; /* .rsrc */ | ||
218 | struct data_dirent exceptions; /* .pdata */ | ||
219 | struct data_dirent certs; /* certs */ | ||
220 | struct data_dirent base_relocations; /* .reloc */ | ||
221 | struct data_dirent debug; /* .debug */ | ||
222 | struct data_dirent arch; /* reservered */ | ||
223 | struct data_dirent global_ptr; /* global pointer reg. Size=0 */ | ||
224 | struct data_dirent tls; /* .tls */ | ||
225 | struct data_dirent load_config; /* load configuration structure */ | ||
226 | struct data_dirent bound_imports; /* no idea */ | ||
227 | struct data_dirent import_addrs; /* import address table */ | ||
228 | struct data_dirent delay_imports; /* delay-load import table */ | ||
229 | struct data_dirent clr_runtime_hdr; /* .cor (object only) */ | ||
230 | struct data_dirent reserved; | ||
231 | }; | ||
232 | |||
233 | struct section_header { | ||
234 | char name[8]; /* name or "/12\0" string tbl offset */ | ||
235 | uint32_t virtual_size; /* size of loaded section in ram */ | ||
236 | uint32_t virtual_address; /* relative virtual address */ | ||
237 | uint32_t raw_data_size; /* size of the section */ | ||
238 | uint32_t data_addr; /* file pointer to first page of sec */ | ||
239 | uint32_t relocs; /* file pointer to relocation entries */ | ||
240 | uint32_t line_numbers; /* line numbers! */ | ||
241 | uint16_t num_relocs; /* number of relocations */ | ||
242 | uint16_t num_lin_numbers; /* srsly. */ | ||
243 | uint32_t flags; | ||
244 | }; | ||
245 | |||
246 | /* they actually defined 0x00000000 as well, but I think we'll skip that one. */ | ||
247 | #define IMAGE_SCN_RESERVED_0 0x00000001 | ||
248 | #define IMAGE_SCN_RESERVED_1 0x00000002 | ||
249 | #define IMAGE_SCN_RESERVED_2 0x00000004 | ||
250 | #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* don't pad - obsolete */ | ||
251 | #define IMAGE_SCN_RESERVED_3 0x00000010 | ||
252 | #define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */ | ||
253 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */ | ||
254 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */ | ||
255 | #define IMAGE_SCN_LNK_OTHER 0x00000100 /* reserved */ | ||
256 | #define IMAGE_SCN_LNK_INFO 0x00000200 /* .drectve comments */ | ||
257 | #define IMAGE_SCN_RESERVED_4 0x00000400 | ||
258 | #define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/ | ||
259 | #define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */ | ||
260 | #define IMAGE_SCN_RESERVED_5 0x00002000 /* spec omits this */ | ||
261 | #define IMAGE_SCN_RESERVED_6 0x00004000 /* spec omits this */ | ||
262 | #define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data */ | ||
263 | /* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */ | ||
264 | #define IMAGE_SCN_MEM_PURGEABLE 0x00010000 /* reserved for "future" use */ | ||
265 | #define IMAGE_SCN_16BIT 0x00020000 /* reserved for "future" use */ | ||
266 | #define IMAGE_SCN_LOCKED 0x00040000 /* reserved for "future" use */ | ||
267 | #define IMAGE_SCN_PRELOAD 0x00080000 /* reserved for "future" use */ | ||
268 | /* and here they just stuck a 1-byte integer in the middle of a bitfield */ | ||
269 | #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* it does what it says on the box */ | ||
270 | #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 | ||
271 | #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 | ||
272 | #define IMAGE_SCN_ALIGN_8BYTES 0x00400000 | ||
273 | #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 | ||
274 | #define IMAGE_SCN_ALIGN_32BYTES 0x00600000 | ||
275 | #define IMAGE_SCN_ALIGN_64BYTES 0x00700000 | ||
276 | #define IMAGE_SCN_ALIGN_128BYTES 0x00800000 | ||
277 | #define IMAGE_SCN_ALIGN_256BYTES 0x00900000 | ||
278 | #define IMAGE_SCN_ALIGN_512BYTES 0x00a00000 | ||
279 | #define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000 | ||
280 | #define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000 | ||
281 | #define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000 | ||
282 | #define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000 | ||
283 | #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */ | ||
284 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */ | ||
285 | #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */ | ||
286 | #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */ | ||
287 | #define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */ | ||
288 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */ | ||
289 | #define IMAGE_SCN_MEM_READ 0x40000000 /* readable */ | ||
290 | #define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */ | ||
291 | |||
292 | enum x64_coff_reloc_type { | ||
293 | IMAGE_REL_AMD64_ABSOLUTE = 0, | ||
294 | IMAGE_REL_AMD64_ADDR64, | ||
295 | IMAGE_REL_AMD64_ADDR32, | ||
296 | IMAGE_REL_AMD64_ADDR32N, | ||
297 | IMAGE_REL_AMD64_REL32, | ||
298 | IMAGE_REL_AMD64_REL32_1, | ||
299 | IMAGE_REL_AMD64_REL32_2, | ||
300 | IMAGE_REL_AMD64_REL32_3, | ||
301 | IMAGE_REL_AMD64_REL32_4, | ||
302 | IMAGE_REL_AMD64_REL32_5, | ||
303 | IMAGE_REL_AMD64_SECTION, | ||
304 | IMAGE_REL_AMD64_SECREL, | ||
305 | IMAGE_REL_AMD64_SECREL7, | ||
306 | IMAGE_REL_AMD64_TOKEN, | ||
307 | IMAGE_REL_AMD64_SREL32, | ||
308 | IMAGE_REL_AMD64_PAIR, | ||
309 | IMAGE_REL_AMD64_SSPAN32, | ||
310 | }; | ||
311 | |||
312 | enum arm_coff_reloc_type { | ||
313 | IMAGE_REL_ARM_ABSOLUTE, | ||
314 | IMAGE_REL_ARM_ADDR32, | ||
315 | IMAGE_REL_ARM_ADDR32N, | ||
316 | IMAGE_REL_ARM_BRANCH2, | ||
317 | IMAGE_REL_ARM_BRANCH1, | ||
318 | IMAGE_REL_ARM_SECTION, | ||
319 | IMAGE_REL_ARM_SECREL, | ||
320 | }; | ||
321 | |||
322 | enum sh_coff_reloc_type { | ||
323 | IMAGE_REL_SH3_ABSOLUTE, | ||
324 | IMAGE_REL_SH3_DIRECT16, | ||
325 | IMAGE_REL_SH3_DIRECT32, | ||
326 | IMAGE_REL_SH3_DIRECT8, | ||
327 | IMAGE_REL_SH3_DIRECT8_WORD, | ||
328 | IMAGE_REL_SH3_DIRECT8_LONG, | ||
329 | IMAGE_REL_SH3_DIRECT4, | ||
330 | IMAGE_REL_SH3_DIRECT4_WORD, | ||
331 | IMAGE_REL_SH3_DIRECT4_LONG, | ||
332 | IMAGE_REL_SH3_PCREL8_WORD, | ||
333 | IMAGE_REL_SH3_PCREL8_LONG, | ||
334 | IMAGE_REL_SH3_PCREL12_WORD, | ||
335 | IMAGE_REL_SH3_STARTOF_SECTION, | ||
336 | IMAGE_REL_SH3_SIZEOF_SECTION, | ||
337 | IMAGE_REL_SH3_SECTION, | ||
338 | IMAGE_REL_SH3_SECREL, | ||
339 | IMAGE_REL_SH3_DIRECT32_NB, | ||
340 | IMAGE_REL_SH3_GPREL4_LONG, | ||
341 | IMAGE_REL_SH3_TOKEN, | ||
342 | IMAGE_REL_SHM_PCRELPT, | ||
343 | IMAGE_REL_SHM_REFLO, | ||
344 | IMAGE_REL_SHM_REFHALF, | ||
345 | IMAGE_REL_SHM_RELLO, | ||
346 | IMAGE_REL_SHM_RELHALF, | ||
347 | IMAGE_REL_SHM_PAIR, | ||
348 | IMAGE_REL_SHM_NOMODE, | ||
349 | }; | ||
350 | |||
351 | enum ppc_coff_reloc_type { | ||
352 | IMAGE_REL_PPC_ABSOLUTE, | ||
353 | IMAGE_REL_PPC_ADDR64, | ||
354 | IMAGE_REL_PPC_ADDR32, | ||
355 | IMAGE_REL_PPC_ADDR24, | ||
356 | IMAGE_REL_PPC_ADDR16, | ||
357 | IMAGE_REL_PPC_ADDR14, | ||
358 | IMAGE_REL_PPC_REL24, | ||
359 | IMAGE_REL_PPC_REL14, | ||
360 | IMAGE_REL_PPC_ADDR32N, | ||
361 | IMAGE_REL_PPC_SECREL, | ||
362 | IMAGE_REL_PPC_SECTION, | ||
363 | IMAGE_REL_PPC_SECREL16, | ||
364 | IMAGE_REL_PPC_REFHI, | ||
365 | IMAGE_REL_PPC_REFLO, | ||
366 | IMAGE_REL_PPC_PAIR, | ||
367 | IMAGE_REL_PPC_SECRELLO, | ||
368 | IMAGE_REL_PPC_GPREL, | ||
369 | IMAGE_REL_PPC_TOKEN, | ||
370 | }; | ||
371 | |||
372 | enum x86_coff_reloc_type { | ||
373 | IMAGE_REL_I386_ABSOLUTE, | ||
374 | IMAGE_REL_I386_DIR16, | ||
375 | IMAGE_REL_I386_REL16, | ||
376 | IMAGE_REL_I386_DIR32, | ||
377 | IMAGE_REL_I386_DIR32NB, | ||
378 | IMAGE_REL_I386_SEG12, | ||
379 | IMAGE_REL_I386_SECTION, | ||
380 | IMAGE_REL_I386_SECREL, | ||
381 | IMAGE_REL_I386_TOKEN, | ||
382 | IMAGE_REL_I386_SECREL7, | ||
383 | IMAGE_REL_I386_REL32, | ||
384 | }; | ||
385 | |||
386 | enum ia64_coff_reloc_type { | ||
387 | IMAGE_REL_IA64_ABSOLUTE, | ||
388 | IMAGE_REL_IA64_IMM14, | ||
389 | IMAGE_REL_IA64_IMM22, | ||
390 | IMAGE_REL_IA64_IMM64, | ||
391 | IMAGE_REL_IA64_DIR32, | ||
392 | IMAGE_REL_IA64_DIR64, | ||
393 | IMAGE_REL_IA64_PCREL21B, | ||
394 | IMAGE_REL_IA64_PCREL21M, | ||
395 | IMAGE_REL_IA64_PCREL21F, | ||
396 | IMAGE_REL_IA64_GPREL22, | ||
397 | IMAGE_REL_IA64_LTOFF22, | ||
398 | IMAGE_REL_IA64_SECTION, | ||
399 | IMAGE_REL_IA64_SECREL22, | ||
400 | IMAGE_REL_IA64_SECREL64I, | ||
401 | IMAGE_REL_IA64_SECREL32, | ||
402 | IMAGE_REL_IA64_DIR32NB, | ||
403 | IMAGE_REL_IA64_SREL14, | ||
404 | IMAGE_REL_IA64_SREL22, | ||
405 | IMAGE_REL_IA64_SREL32, | ||
406 | IMAGE_REL_IA64_UREL32, | ||
407 | IMAGE_REL_IA64_PCREL60X, | ||
408 | IMAGE_REL_IA64_PCREL60B, | ||
409 | IMAGE_REL_IA64_PCREL60F, | ||
410 | IMAGE_REL_IA64_PCREL60I, | ||
411 | IMAGE_REL_IA64_PCREL60M, | ||
412 | IMAGE_REL_IA64_IMMGPREL6, | ||
413 | IMAGE_REL_IA64_TOKEN, | ||
414 | IMAGE_REL_IA64_GPREL32, | ||
415 | IMAGE_REL_IA64_ADDEND, | ||
416 | }; | ||
417 | |||
418 | struct coff_reloc { | ||
419 | uint32_t virtual_address; | ||
420 | uint32_t symbol_table_index; | ||
421 | union { | ||
422 | enum x64_coff_reloc_type x64_type; | ||
423 | enum arm_coff_reloc_type arm_type; | ||
424 | enum sh_coff_reloc_type sh_type; | ||
425 | enum ppc_coff_reloc_type ppc_type; | ||
426 | enum x86_coff_reloc_type x86_type; | ||
427 | enum ia64_coff_reloc_type ia64_type; | ||
428 | uint16_t data; | ||
429 | }; | ||
430 | }; | ||
431 | |||
432 | /* | ||
433 | * Definitions for the contents of the certs data block | ||
434 | */ | ||
435 | #define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 | ||
436 | #define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0 | ||
437 | #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 | ||
438 | |||
439 | #define WIN_CERT_REVISION_1_0 0x0100 | ||
440 | #define WIN_CERT_REVISION_2_0 0x0200 | ||
441 | |||
442 | struct win_certificate { | ||
443 | uint32_t length; | ||
444 | uint16_t revision; | ||
445 | uint16_t cert_type; | ||
446 | }; | ||
447 | |||
448 | #endif /* __LINUX_PE_H */ | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 66124d63371a..7c19d552dc3f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1304,13 +1304,12 @@ struct task_struct { | |||
1304 | * execve */ | 1304 | * execve */ |
1305 | unsigned in_iowait:1; | 1305 | unsigned in_iowait:1; |
1306 | 1306 | ||
1307 | /* task may not gain privileges */ | ||
1308 | unsigned no_new_privs:1; | ||
1309 | |||
1310 | /* Revert to default priority/policy when forking */ | 1307 | /* Revert to default priority/policy when forking */ |
1311 | unsigned sched_reset_on_fork:1; | 1308 | unsigned sched_reset_on_fork:1; |
1312 | unsigned sched_contributes_to_load:1; | 1309 | unsigned sched_contributes_to_load:1; |
1313 | 1310 | ||
1311 | unsigned long atomic_flags; /* Flags needing atomic access. */ | ||
1312 | |||
1314 | pid_t pid; | 1313 | pid_t pid; |
1315 | pid_t tgid; | 1314 | pid_t tgid; |
1316 | 1315 | ||
@@ -1962,6 +1961,19 @@ static inline void memalloc_noio_restore(unsigned int flags) | |||
1962 | current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; | 1961 | current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; |
1963 | } | 1962 | } |
1964 | 1963 | ||
1964 | /* Per-process atomic flags. */ | ||
1965 | #define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */ | ||
1966 | |||
1967 | static inline bool task_no_new_privs(struct task_struct *p) | ||
1968 | { | ||
1969 | return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); | ||
1970 | } | ||
1971 | |||
1972 | static inline void task_set_no_new_privs(struct task_struct *p) | ||
1973 | { | ||
1974 | set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags); | ||
1975 | } | ||
1976 | |||
1965 | /* | 1977 | /* |
1966 | * task->jobctl flags | 1978 | * task->jobctl flags |
1967 | */ | 1979 | */ |
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 4054b0994071..5d586a45a319 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
@@ -3,6 +3,8 @@ | |||
3 | 3 | ||
4 | #include <uapi/linux/seccomp.h> | 4 | #include <uapi/linux/seccomp.h> |
5 | 5 | ||
6 | #define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC) | ||
7 | |||
6 | #ifdef CONFIG_SECCOMP | 8 | #ifdef CONFIG_SECCOMP |
7 | 9 | ||
8 | #include <linux/thread_info.h> | 10 | #include <linux/thread_info.h> |
@@ -14,11 +16,11 @@ struct seccomp_filter; | |||
14 | * | 16 | * |
15 | * @mode: indicates one of the valid values above for controlled | 17 | * @mode: indicates one of the valid values above for controlled |
16 | * system calls available to a process. | 18 | * system calls available to a process. |
17 | * @filter: The metadata and ruleset for determining what system calls | 19 | * @filter: must always point to a valid seccomp-filter or NULL as it is |
18 | * are allowed for a task. | 20 | * accessed without locking during system call entry. |
19 | * | 21 | * |
20 | * @filter must only be accessed from the context of current as there | 22 | * @filter must only be accessed from the context of current as there |
21 | * is no locking. | 23 | * is no read locking. |
22 | */ | 24 | */ |
23 | struct seccomp { | 25 | struct seccomp { |
24 | int mode; | 26 | int mode; |
diff --git a/include/linux/security.h b/include/linux/security.h index 9c6b9722ff48..623f90e5f38d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -702,6 +702,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
702 | * @inode points to the inode to use as a reference. | 702 | * @inode points to the inode to use as a reference. |
703 | * The current task must be the one that nominated @inode. | 703 | * The current task must be the one that nominated @inode. |
704 | * Return 0 if successful. | 704 | * Return 0 if successful. |
705 | * @kernel_fw_from_file: | ||
706 | * Load firmware from userspace (not called for built-in firmware). | ||
707 | * @file contains the file structure pointing to the file containing | ||
708 | * the firmware to load. This argument will be NULL if the firmware | ||
709 | * was loaded via the uevent-triggered blob-based interface exposed | ||
710 | * by CONFIG_FW_LOADER_USER_HELPER. | ||
711 | * @buf pointer to buffer containing firmware contents. | ||
712 | * @size length of the firmware contents. | ||
713 | * Return 0 if permission is granted. | ||
705 | * @kernel_module_request: | 714 | * @kernel_module_request: |
706 | * Ability to trigger the kernel to automatically upcall to userspace for | 715 | * Ability to trigger the kernel to automatically upcall to userspace for |
707 | * userspace to load a kernel module with the given name. | 716 | * userspace to load a kernel module with the given name. |
@@ -1565,6 +1574,7 @@ struct security_operations { | |||
1565 | void (*cred_transfer)(struct cred *new, const struct cred *old); | 1574 | void (*cred_transfer)(struct cred *new, const struct cred *old); |
1566 | int (*kernel_act_as)(struct cred *new, u32 secid); | 1575 | int (*kernel_act_as)(struct cred *new, u32 secid); |
1567 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); | 1576 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); |
1577 | int (*kernel_fw_from_file)(struct file *file, char *buf, size_t size); | ||
1568 | int (*kernel_module_request)(char *kmod_name); | 1578 | int (*kernel_module_request)(char *kmod_name); |
1569 | int (*kernel_module_from_file)(struct file *file); | 1579 | int (*kernel_module_from_file)(struct file *file); |
1570 | int (*task_fix_setuid) (struct cred *new, const struct cred *old, | 1580 | 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); | |||
1837 | void security_transfer_creds(struct cred *new, const struct cred *old); | 1847 | void security_transfer_creds(struct cred *new, const struct cred *old); |
1838 | int security_kernel_act_as(struct cred *new, u32 secid); | 1848 | int security_kernel_act_as(struct cred *new, u32 secid); |
1839 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); | 1849 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); |
1850 | int security_kernel_fw_from_file(struct file *file, char *buf, size_t size); | ||
1840 | int security_kernel_module_request(char *kmod_name); | 1851 | int security_kernel_module_request(char *kmod_name); |
1841 | int security_kernel_module_from_file(struct file *file); | 1852 | int security_kernel_module_from_file(struct file *file); |
1842 | int security_task_fix_setuid(struct cred *new, const struct cred *old, | 1853 | 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, | |||
2363 | return 0; | 2374 | return 0; |
2364 | } | 2375 | } |
2365 | 2376 | ||
2377 | static inline int security_kernel_fw_from_file(struct file *file, | ||
2378 | char *buf, size_t size) | ||
2379 | { | ||
2380 | return 0; | ||
2381 | } | ||
2382 | |||
2366 | static inline int security_kernel_module_request(char *kmod_name) | 2383 | static inline int security_kernel_module_request(char *kmod_name) |
2367 | { | 2384 | { |
2368 | return 0; | 2385 | return 0; |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index b0881a0ed322..1713977ee26f 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -866,4 +866,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid, | |||
866 | asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, | 866 | asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, |
867 | unsigned long idx1, unsigned long idx2); | 867 | unsigned long idx1, unsigned long idx2); |
868 | asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); | 868 | asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); |
869 | asmlinkage long sys_seccomp(unsigned int op, unsigned int flags, | ||
870 | const char __user *uargs); | ||
869 | #endif | 871 | #endif |
diff --git a/include/linux/tpm.h b/include/linux/tpm.h index fff1d0976f80..8350c538b486 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h | |||
@@ -39,6 +39,9 @@ struct tpm_class_ops { | |||
39 | int (*send) (struct tpm_chip *chip, u8 *buf, size_t len); | 39 | int (*send) (struct tpm_chip *chip, u8 *buf, size_t len); |
40 | void (*cancel) (struct tpm_chip *chip); | 40 | void (*cancel) (struct tpm_chip *chip); |
41 | u8 (*status) (struct tpm_chip *chip); | 41 | u8 (*status) (struct tpm_chip *chip); |
42 | bool (*update_timeouts)(struct tpm_chip *chip, | ||
43 | unsigned long *timeout_cap); | ||
44 | |||
42 | }; | 45 | }; |
43 | 46 | ||
44 | #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) | 47 | #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) |
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h new file mode 100644 index 000000000000..ac34819214f9 --- /dev/null +++ b/include/linux/verify_pefile.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* Signed PE file verification | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _LINUX_VERIFY_PEFILE_H | ||
13 | #define _LINUX_VERIFY_PEFILE_H | ||
14 | |||
15 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | ||
16 | struct key *trusted_keyring, bool *_trusted); | ||
17 | |||
18 | #endif /* _LINUX_VERIFY_PEFILE_H */ | ||
diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 4fe018c48ed9..a4fc39bb3e4f 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h | |||
@@ -139,7 +139,7 @@ struct netlbl_lsm_cache { | |||
139 | }; | 139 | }; |
140 | 140 | ||
141 | /** | 141 | /** |
142 | * struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap | 142 | * struct netlbl_lsm_catmap - NetLabel LSM secattr category bitmap |
143 | * @startbit: the value of the lowest order bit in the bitmap | 143 | * @startbit: the value of the lowest order bit in the bitmap |
144 | * @bitmap: the category bitmap | 144 | * @bitmap: the category bitmap |
145 | * @next: pointer to the next bitmap "node" or NULL | 145 | * @next: pointer to the next bitmap "node" or NULL |
@@ -162,10 +162,10 @@ struct netlbl_lsm_cache { | |||
162 | #define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \ | 162 | #define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \ |
163 | NETLBL_CATMAP_MAPCNT) | 163 | NETLBL_CATMAP_MAPCNT) |
164 | #define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01 | 164 | #define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01 |
165 | struct netlbl_lsm_secattr_catmap { | 165 | struct netlbl_lsm_catmap { |
166 | u32 startbit; | 166 | u32 startbit; |
167 | NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; | 167 | NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; |
168 | struct netlbl_lsm_secattr_catmap *next; | 168 | struct netlbl_lsm_catmap *next; |
169 | }; | 169 | }; |
170 | 170 | ||
171 | /** | 171 | /** |
@@ -209,7 +209,7 @@ struct netlbl_lsm_secattr { | |||
209 | struct netlbl_lsm_cache *cache; | 209 | struct netlbl_lsm_cache *cache; |
210 | struct { | 210 | struct { |
211 | struct { | 211 | struct { |
212 | struct netlbl_lsm_secattr_catmap *cat; | 212 | struct netlbl_lsm_catmap *cat; |
213 | u32 lvl; | 213 | u32 lvl; |
214 | } mls; | 214 | } mls; |
215 | u32 secid; | 215 | u32 secid; |
@@ -258,7 +258,7 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) | |||
258 | } | 258 | } |
259 | 259 | ||
260 | /** | 260 | /** |
261 | * netlbl_secattr_catmap_alloc - Allocate a LSM secattr catmap | 261 | * netlbl_catmap_alloc - Allocate a LSM secattr catmap |
262 | * @flags: memory allocation flags | 262 | * @flags: memory allocation flags |
263 | * | 263 | * |
264 | * Description: | 264 | * Description: |
@@ -266,30 +266,28 @@ static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) | |||
266 | * on failure. | 266 | * on failure. |
267 | * | 267 | * |
268 | */ | 268 | */ |
269 | static inline struct netlbl_lsm_secattr_catmap *netlbl_secattr_catmap_alloc( | 269 | static inline struct netlbl_lsm_catmap *netlbl_catmap_alloc(gfp_t flags) |
270 | gfp_t flags) | ||
271 | { | 270 | { |
272 | return kzalloc(sizeof(struct netlbl_lsm_secattr_catmap), flags); | 271 | return kzalloc(sizeof(struct netlbl_lsm_catmap), flags); |
273 | } | 272 | } |
274 | 273 | ||
275 | /** | 274 | /** |
276 | * netlbl_secattr_catmap_free - Free a LSM secattr catmap | 275 | * netlbl_catmap_free - Free a LSM secattr catmap |
277 | * @catmap: the category bitmap | 276 | * @catmap: the category bitmap |
278 | * | 277 | * |
279 | * Description: | 278 | * Description: |
280 | * Free a LSM secattr catmap. | 279 | * Free a LSM secattr catmap. |
281 | * | 280 | * |
282 | */ | 281 | */ |
283 | static inline void netlbl_secattr_catmap_free( | 282 | static inline void netlbl_catmap_free(struct netlbl_lsm_catmap *catmap) |
284 | struct netlbl_lsm_secattr_catmap *catmap) | ||
285 | { | 283 | { |
286 | struct netlbl_lsm_secattr_catmap *iter; | 284 | struct netlbl_lsm_catmap *iter; |
287 | 285 | ||
288 | do { | 286 | while (catmap) { |
289 | iter = catmap; | 287 | iter = catmap; |
290 | catmap = catmap->next; | 288 | catmap = catmap->next; |
291 | kfree(iter); | 289 | kfree(iter); |
292 | } while (catmap); | 290 | } |
293 | } | 291 | } |
294 | 292 | ||
295 | /** | 293 | /** |
@@ -321,7 +319,7 @@ static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) | |||
321 | if (secattr->flags & NETLBL_SECATTR_CACHE) | 319 | if (secattr->flags & NETLBL_SECATTR_CACHE) |
322 | netlbl_secattr_cache_free(secattr->cache); | 320 | netlbl_secattr_cache_free(secattr->cache); |
323 | if (secattr->flags & NETLBL_SECATTR_MLS_CAT) | 321 | if (secattr->flags & NETLBL_SECATTR_MLS_CAT) |
324 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 322 | netlbl_catmap_free(secattr->attr.mls.cat); |
325 | } | 323 | } |
326 | 324 | ||
327 | /** | 325 | /** |
@@ -390,17 +388,22 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, | |||
390 | /* | 388 | /* |
391 | * LSM security attribute operations | 389 | * LSM security attribute operations |
392 | */ | 390 | */ |
393 | int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, | 391 | int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset); |
394 | u32 offset); | 392 | int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset); |
395 | int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, | 393 | int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, |
396 | u32 offset); | 394 | u32 *offset, |
397 | int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, | 395 | unsigned long *bitmap); |
398 | u32 bit, | 396 | int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, |
399 | gfp_t flags); | 397 | u32 bit, |
400 | int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | 398 | gfp_t flags); |
401 | u32 start, | 399 | int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, |
402 | u32 end, | 400 | u32 start, |
403 | gfp_t flags); | 401 | u32 end, |
402 | gfp_t flags); | ||
403 | int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, | ||
404 | u32 offset, | ||
405 | unsigned long bitmap, | ||
406 | gfp_t flags); | ||
404 | 407 | ||
405 | /* | 408 | /* |
406 | * LSM protocol operations (NetLabel LSM/kernel API) | 409 | * LSM protocol operations (NetLabel LSM/kernel API) |
@@ -492,30 +495,39 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi, | |||
492 | { | 495 | { |
493 | return -ENOSYS; | 496 | return -ENOSYS; |
494 | } | 497 | } |
495 | static inline int netlbl_secattr_catmap_walk( | 498 | static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, |
496 | struct netlbl_lsm_secattr_catmap *catmap, | 499 | u32 offset) |
497 | u32 offset) | ||
498 | { | 500 | { |
499 | return -ENOENT; | 501 | return -ENOENT; |
500 | } | 502 | } |
501 | static inline int netlbl_secattr_catmap_walk_rng( | 503 | static inline int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, |
502 | struct netlbl_lsm_secattr_catmap *catmap, | 504 | u32 offset) |
503 | u32 offset) | ||
504 | { | 505 | { |
505 | return -ENOENT; | 506 | return -ENOENT; |
506 | } | 507 | } |
507 | static inline int netlbl_secattr_catmap_setbit( | 508 | static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, |
508 | struct netlbl_lsm_secattr_catmap *catmap, | 509 | u32 *offset, |
509 | u32 bit, | 510 | unsigned long *bitmap) |
510 | gfp_t flags) | ||
511 | { | 511 | { |
512 | return 0; | 512 | return 0; |
513 | } | 513 | } |
514 | static inline int netlbl_secattr_catmap_setrng( | 514 | static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, |
515 | struct netlbl_lsm_secattr_catmap *catmap, | 515 | u32 bit, |
516 | u32 start, | 516 | gfp_t flags) |
517 | u32 end, | 517 | { |
518 | gfp_t flags) | 518 | return 0; |
519 | } | ||
520 | static inline int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, | ||
521 | u32 start, | ||
522 | u32 end, | ||
523 | gfp_t flags) | ||
524 | { | ||
525 | return 0; | ||
526 | } | ||
527 | static int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, | ||
528 | u32 offset, | ||
529 | unsigned long bitmap, | ||
530 | gfp_t flags) | ||
519 | { | 531 | { |
520 | return 0; | 532 | return 0; |
521 | } | 533 | } |
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 333640608087..65acbf0e2867 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h | |||
@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr) | |||
699 | __SYSCALL(__NR_sched_getattr, sys_sched_getattr) | 699 | __SYSCALL(__NR_sched_getattr, sys_sched_getattr) |
700 | #define __NR_renameat2 276 | 700 | #define __NR_renameat2 276 |
701 | __SYSCALL(__NR_renameat2, sys_renameat2) | 701 | __SYSCALL(__NR_renameat2, sys_renameat2) |
702 | #define __NR_seccomp 277 | ||
703 | __SYSCALL(__NR_seccomp, sys_seccomp) | ||
702 | 704 | ||
703 | #undef __NR_syscalls | 705 | #undef __NR_syscalls |
704 | #define __NR_syscalls 277 | 706 | #define __NR_syscalls 278 |
705 | 707 | ||
706 | /* | 708 | /* |
707 | * All syscalls below here should go away really, | 709 | * All syscalls below here should go away really, |
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index ac2dc9f72973..0f238a43ff1e 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h | |||
@@ -10,6 +10,13 @@ | |||
10 | #define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ | 10 | #define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ |
11 | #define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ | 11 | #define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ |
12 | 12 | ||
13 | /* Valid operations for seccomp syscall. */ | ||
14 | #define SECCOMP_SET_MODE_STRICT 0 | ||
15 | #define SECCOMP_SET_MODE_FILTER 1 | ||
16 | |||
17 | /* Valid flags for SECCOMP_SET_MODE_FILTER */ | ||
18 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | ||
19 | |||
13 | /* | 20 | /* |
14 | * All BPF programs must return a 32-bit value. | 21 | * All BPF programs must return a 32-bit value. |
15 | * The bottom 16-bits are for optional return data. | 22 | * The bottom 16-bits are for optional return data. |
diff --git a/kernel/audit.c b/kernel/audit.c index 3ef2e0e797e8..ba2ff5a5c600 100644 --- a/kernel/audit.c +++ b/kernel/audit.c | |||
@@ -1677,7 +1677,7 @@ void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) | |||
1677 | audit_log_format(ab, " %s=", prefix); | 1677 | audit_log_format(ab, " %s=", prefix); |
1678 | CAP_FOR_EACH_U32(i) { | 1678 | CAP_FOR_EACH_U32(i) { |
1679 | audit_log_format(ab, "%08x", | 1679 | audit_log_format(ab, "%08x", |
1680 | cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]); | 1680 | cap->cap[CAP_LAST_U32 - i]); |
1681 | } | 1681 | } |
1682 | } | 1682 | } |
1683 | 1683 | ||
diff --git a/kernel/capability.c b/kernel/capability.c index a5cf13c018ce..989f5bfc57dc 100644 --- a/kernel/capability.c +++ b/kernel/capability.c | |||
@@ -258,6 +258,10 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) | |||
258 | i++; | 258 | i++; |
259 | } | 259 | } |
260 | 260 | ||
261 | effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
262 | permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
263 | inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
264 | |||
261 | new = prepare_creds(); | 265 | new = prepare_creds(); |
262 | if (!new) | 266 | if (!new) |
263 | return -ENOMEM; | 267 | return -ENOMEM; |
diff --git a/kernel/fork.c b/kernel/fork.c index 5f1bf3bebb4f..fbd3497b221f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -315,6 +315,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) | |||
315 | goto free_ti; | 315 | goto free_ti; |
316 | 316 | ||
317 | tsk->stack = ti; | 317 | tsk->stack = ti; |
318 | #ifdef CONFIG_SECCOMP | ||
319 | /* | ||
320 | * We must handle setting up seccomp filters once we're under | ||
321 | * the sighand lock in case orig has changed between now and | ||
322 | * then. Until then, filter must be NULL to avoid messing up | ||
323 | * the usage counts on the error path calling free_task. | ||
324 | */ | ||
325 | tsk->seccomp.filter = NULL; | ||
326 | #endif | ||
318 | 327 | ||
319 | setup_thread_stack(tsk, orig); | 328 | setup_thread_stack(tsk, orig); |
320 | clear_user_return_notifier(tsk); | 329 | clear_user_return_notifier(tsk); |
@@ -1081,6 +1090,39 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) | |||
1081 | return 0; | 1090 | return 0; |
1082 | } | 1091 | } |
1083 | 1092 | ||
1093 | static void copy_seccomp(struct task_struct *p) | ||
1094 | { | ||
1095 | #ifdef CONFIG_SECCOMP | ||
1096 | /* | ||
1097 | * Must be called with sighand->lock held, which is common to | ||
1098 | * all threads in the group. Holding cred_guard_mutex is not | ||
1099 | * needed because this new task is not yet running and cannot | ||
1100 | * be racing exec. | ||
1101 | */ | ||
1102 | BUG_ON(!spin_is_locked(¤t->sighand->siglock)); | ||
1103 | |||
1104 | /* Ref-count the new filter user, and assign it. */ | ||
1105 | get_seccomp_filter(current); | ||
1106 | p->seccomp = current->seccomp; | ||
1107 | |||
1108 | /* | ||
1109 | * Explicitly enable no_new_privs here in case it got set | ||
1110 | * between the task_struct being duplicated and holding the | ||
1111 | * sighand lock. The seccomp state and nnp must be in sync. | ||
1112 | */ | ||
1113 | if (task_no_new_privs(current)) | ||
1114 | task_set_no_new_privs(p); | ||
1115 | |||
1116 | /* | ||
1117 | * If the parent gained a seccomp mode after copying thread | ||
1118 | * flags and between before we held the sighand lock, we have | ||
1119 | * to manually enable the seccomp thread flag here. | ||
1120 | */ | ||
1121 | if (p->seccomp.mode != SECCOMP_MODE_DISABLED) | ||
1122 | set_tsk_thread_flag(p, TIF_SECCOMP); | ||
1123 | #endif | ||
1124 | } | ||
1125 | |||
1084 | SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) | 1126 | SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) |
1085 | { | 1127 | { |
1086 | current->clear_child_tid = tidptr; | 1128 | current->clear_child_tid = tidptr; |
@@ -1195,7 +1237,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1195 | goto fork_out; | 1237 | goto fork_out; |
1196 | 1238 | ||
1197 | ftrace_graph_init_task(p); | 1239 | ftrace_graph_init_task(p); |
1198 | get_seccomp_filter(p); | ||
1199 | 1240 | ||
1200 | rt_mutex_init_task(p); | 1241 | rt_mutex_init_task(p); |
1201 | 1242 | ||
@@ -1435,6 +1476,12 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1435 | spin_lock(¤t->sighand->siglock); | 1476 | spin_lock(¤t->sighand->siglock); |
1436 | 1477 | ||
1437 | /* | 1478 | /* |
1479 | * Copy seccomp details explicitly here, in case they were changed | ||
1480 | * before holding sighand lock. | ||
1481 | */ | ||
1482 | copy_seccomp(p); | ||
1483 | |||
1484 | /* | ||
1438 | * Process group and session signals need to be delivered to just the | 1485 | * Process group and session signals need to be delivered to just the |
1439 | * parent before the fork or both the parent and the child after the | 1486 | * parent before the fork or both the parent and the child after the |
1440 | * fork. Restart if a signal comes in before we add the new process to | 1487 | * fork. Restart if a signal comes in before we add the new process to |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 301bbc24739c..74f460179171 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -18,15 +18,17 @@ | |||
18 | #include <linux/compat.h> | 18 | #include <linux/compat.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/seccomp.h> | 20 | #include <linux/seccomp.h> |
21 | #include <linux/slab.h> | ||
22 | #include <linux/syscalls.h> | ||
21 | 23 | ||
22 | /* #define SECCOMP_DEBUG 1 */ | 24 | /* #define SECCOMP_DEBUG 1 */ |
23 | 25 | ||
24 | #ifdef CONFIG_SECCOMP_FILTER | 26 | #ifdef CONFIG_SECCOMP_FILTER |
25 | #include <asm/syscall.h> | 27 | #include <asm/syscall.h> |
26 | #include <linux/filter.h> | 28 | #include <linux/filter.h> |
29 | #include <linux/pid.h> | ||
27 | #include <linux/ptrace.h> | 30 | #include <linux/ptrace.h> |
28 | #include <linux/security.h> | 31 | #include <linux/security.h> |
29 | #include <linux/slab.h> | ||
30 | #include <linux/tracehook.h> | 32 | #include <linux/tracehook.h> |
31 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
32 | 34 | ||
@@ -172,21 +174,24 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) | |||
172 | */ | 174 | */ |
173 | static u32 seccomp_run_filters(int syscall) | 175 | static u32 seccomp_run_filters(int syscall) |
174 | { | 176 | { |
175 | struct seccomp_filter *f; | 177 | struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter); |
176 | struct seccomp_data sd; | 178 | struct seccomp_data sd; |
177 | u32 ret = SECCOMP_RET_ALLOW; | 179 | u32 ret = SECCOMP_RET_ALLOW; |
178 | 180 | ||
179 | /* Ensure unexpected behavior doesn't result in failing open. */ | 181 | /* Ensure unexpected behavior doesn't result in failing open. */ |
180 | if (WARN_ON(current->seccomp.filter == NULL)) | 182 | if (unlikely(WARN_ON(f == NULL))) |
181 | return SECCOMP_RET_KILL; | 183 | return SECCOMP_RET_KILL; |
182 | 184 | ||
185 | /* Make sure cross-thread synced filter points somewhere sane. */ | ||
186 | smp_read_barrier_depends(); | ||
187 | |||
183 | populate_seccomp_data(&sd); | 188 | populate_seccomp_data(&sd); |
184 | 189 | ||
185 | /* | 190 | /* |
186 | * All filters in the list are evaluated and the lowest BPF return | 191 | * All filters in the list are evaluated and the lowest BPF return |
187 | * value always takes priority (ignoring the DATA). | 192 | * value always takes priority (ignoring the DATA). |
188 | */ | 193 | */ |
189 | for (f = current->seccomp.filter; f; f = f->prev) { | 194 | for (; f; f = f->prev) { |
190 | u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); | 195 | u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); |
191 | 196 | ||
192 | if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) | 197 | if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) |
@@ -194,29 +199,159 @@ static u32 seccomp_run_filters(int syscall) | |||
194 | } | 199 | } |
195 | return ret; | 200 | return ret; |
196 | } | 201 | } |
202 | #endif /* CONFIG_SECCOMP_FILTER */ | ||
203 | |||
204 | static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode) | ||
205 | { | ||
206 | BUG_ON(!spin_is_locked(¤t->sighand->siglock)); | ||
207 | |||
208 | if (current->seccomp.mode && current->seccomp.mode != seccomp_mode) | ||
209 | return false; | ||
210 | |||
211 | return true; | ||
212 | } | ||
213 | |||
214 | static inline void seccomp_assign_mode(struct task_struct *task, | ||
215 | unsigned long seccomp_mode) | ||
216 | { | ||
217 | BUG_ON(!spin_is_locked(&task->sighand->siglock)); | ||
218 | |||
219 | task->seccomp.mode = seccomp_mode; | ||
220 | /* | ||
221 | * Make sure TIF_SECCOMP cannot be set before the mode (and | ||
222 | * filter) is set. | ||
223 | */ | ||
224 | smp_mb__before_atomic(); | ||
225 | set_tsk_thread_flag(task, TIF_SECCOMP); | ||
226 | } | ||
227 | |||
228 | #ifdef CONFIG_SECCOMP_FILTER | ||
229 | /* Returns 1 if the parent is an ancestor of the child. */ | ||
230 | static int is_ancestor(struct seccomp_filter *parent, | ||
231 | struct seccomp_filter *child) | ||
232 | { | ||
233 | /* NULL is the root ancestor. */ | ||
234 | if (parent == NULL) | ||
235 | return 1; | ||
236 | for (; child; child = child->prev) | ||
237 | if (child == parent) | ||
238 | return 1; | ||
239 | return 0; | ||
240 | } | ||
197 | 241 | ||
198 | /** | 242 | /** |
199 | * seccomp_attach_filter: Attaches a seccomp filter to current. | 243 | * seccomp_can_sync_threads: checks if all threads can be synchronized |
244 | * | ||
245 | * Expects sighand and cred_guard_mutex locks to be held. | ||
246 | * | ||
247 | * Returns 0 on success, -ve on error, or the pid of a thread which was | ||
248 | * either not in the correct seccomp mode or it did not have an ancestral | ||
249 | * seccomp filter. | ||
250 | */ | ||
251 | static inline pid_t seccomp_can_sync_threads(void) | ||
252 | { | ||
253 | struct task_struct *thread, *caller; | ||
254 | |||
255 | BUG_ON(!mutex_is_locked(¤t->signal->cred_guard_mutex)); | ||
256 | BUG_ON(!spin_is_locked(¤t->sighand->siglock)); | ||
257 | |||
258 | /* Validate all threads being eligible for synchronization. */ | ||
259 | caller = current; | ||
260 | for_each_thread(caller, thread) { | ||
261 | pid_t failed; | ||
262 | |||
263 | /* Skip current, since it is initiating the sync. */ | ||
264 | if (thread == caller) | ||
265 | continue; | ||
266 | |||
267 | if (thread->seccomp.mode == SECCOMP_MODE_DISABLED || | ||
268 | (thread->seccomp.mode == SECCOMP_MODE_FILTER && | ||
269 | is_ancestor(thread->seccomp.filter, | ||
270 | caller->seccomp.filter))) | ||
271 | continue; | ||
272 | |||
273 | /* Return the first thread that cannot be synchronized. */ | ||
274 | failed = task_pid_vnr(thread); | ||
275 | /* If the pid cannot be resolved, then return -ESRCH */ | ||
276 | if (unlikely(WARN_ON(failed == 0))) | ||
277 | failed = -ESRCH; | ||
278 | return failed; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * seccomp_sync_threads: sets all threads to use current's filter | ||
286 | * | ||
287 | * Expects sighand and cred_guard_mutex locks to be held, and for | ||
288 | * seccomp_can_sync_threads() to have returned success already | ||
289 | * without dropping the locks. | ||
290 | * | ||
291 | */ | ||
292 | static inline void seccomp_sync_threads(void) | ||
293 | { | ||
294 | struct task_struct *thread, *caller; | ||
295 | |||
296 | BUG_ON(!mutex_is_locked(¤t->signal->cred_guard_mutex)); | ||
297 | BUG_ON(!spin_is_locked(¤t->sighand->siglock)); | ||
298 | |||
299 | /* Synchronize all threads. */ | ||
300 | caller = current; | ||
301 | for_each_thread(caller, thread) { | ||
302 | /* Skip current, since it needs no changes. */ | ||
303 | if (thread == caller) | ||
304 | continue; | ||
305 | |||
306 | /* Get a task reference for the new leaf node. */ | ||
307 | get_seccomp_filter(caller); | ||
308 | /* | ||
309 | * Drop the task reference to the shared ancestor since | ||
310 | * current's path will hold a reference. (This also | ||
311 | * allows a put before the assignment.) | ||
312 | */ | ||
313 | put_seccomp_filter(thread); | ||
314 | smp_store_release(&thread->seccomp.filter, | ||
315 | caller->seccomp.filter); | ||
316 | /* | ||
317 | * Opt the other thread into seccomp if needed. | ||
318 | * As threads are considered to be trust-realm | ||
319 | * equivalent (see ptrace_may_access), it is safe to | ||
320 | * allow one thread to transition the other. | ||
321 | */ | ||
322 | if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) { | ||
323 | /* | ||
324 | * Don't let an unprivileged task work around | ||
325 | * the no_new_privs restriction by creating | ||
326 | * a thread that sets it up, enters seccomp, | ||
327 | * then dies. | ||
328 | */ | ||
329 | if (task_no_new_privs(caller)) | ||
330 | task_set_no_new_privs(thread); | ||
331 | |||
332 | seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * seccomp_prepare_filter: Prepares a seccomp filter for use. | ||
200 | * @fprog: BPF program to install | 339 | * @fprog: BPF program to install |
201 | * | 340 | * |
202 | * Returns 0 on success or an errno on failure. | 341 | * Returns filter on success or an ERR_PTR on failure. |
203 | */ | 342 | */ |
204 | static long seccomp_attach_filter(struct sock_fprog *fprog) | 343 | static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) |
205 | { | 344 | { |
206 | struct seccomp_filter *filter; | 345 | struct seccomp_filter *filter; |
207 | unsigned long fp_size = fprog->len * sizeof(struct sock_filter); | 346 | unsigned long fp_size; |
208 | unsigned long total_insns = fprog->len; | ||
209 | struct sock_filter *fp; | 347 | struct sock_filter *fp; |
210 | int new_len; | 348 | int new_len; |
211 | long ret; | 349 | long ret; |
212 | 350 | ||
213 | if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) | 351 | if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) |
214 | return -EINVAL; | 352 | return ERR_PTR(-EINVAL); |
215 | 353 | BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter)); | |
216 | for (filter = current->seccomp.filter; filter; filter = filter->prev) | 354 | fp_size = fprog->len * sizeof(struct sock_filter); |
217 | total_insns += filter->prog->len + 4; /* include a 4 instr penalty */ | ||
218 | if (total_insns > MAX_INSNS_PER_PATH) | ||
219 | return -ENOMEM; | ||
220 | 355 | ||
221 | /* | 356 | /* |
222 | * Installing a seccomp filter requires that the task has | 357 | * Installing a seccomp filter requires that the task has |
@@ -224,14 +359,14 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) | |||
224 | * This avoids scenarios where unprivileged tasks can affect the | 359 | * This avoids scenarios where unprivileged tasks can affect the |
225 | * behavior of privileged children. | 360 | * behavior of privileged children. |
226 | */ | 361 | */ |
227 | if (!current->no_new_privs && | 362 | if (!task_no_new_privs(current) && |
228 | security_capable_noaudit(current_cred(), current_user_ns(), | 363 | security_capable_noaudit(current_cred(), current_user_ns(), |
229 | CAP_SYS_ADMIN) != 0) | 364 | CAP_SYS_ADMIN) != 0) |
230 | return -EACCES; | 365 | return ERR_PTR(-EACCES); |
231 | 366 | ||
232 | fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); | 367 | fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); |
233 | if (!fp) | 368 | if (!fp) |
234 | return -ENOMEM; | 369 | return ERR_PTR(-ENOMEM); |
235 | 370 | ||
236 | /* Copy the instructions from fprog. */ | 371 | /* Copy the instructions from fprog. */ |
237 | ret = -EFAULT; | 372 | ret = -EFAULT; |
@@ -275,13 +410,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) | |||
275 | 410 | ||
276 | sk_filter_select_runtime(filter->prog); | 411 | sk_filter_select_runtime(filter->prog); |
277 | 412 | ||
278 | /* | 413 | return filter; |
279 | * If there is an existing filter, make it the prev and don't drop its | ||
280 | * task reference. | ||
281 | */ | ||
282 | filter->prev = current->seccomp.filter; | ||
283 | current->seccomp.filter = filter; | ||
284 | return 0; | ||
285 | 414 | ||
286 | free_filter_prog: | 415 | free_filter_prog: |
287 | kfree(filter->prog); | 416 | kfree(filter->prog); |
@@ -289,19 +418,20 @@ free_filter: | |||
289 | kfree(filter); | 418 | kfree(filter); |
290 | free_prog: | 419 | free_prog: |
291 | kfree(fp); | 420 | kfree(fp); |
292 | return ret; | 421 | return ERR_PTR(ret); |
293 | } | 422 | } |
294 | 423 | ||
295 | /** | 424 | /** |
296 | * seccomp_attach_user_filter - attaches a user-supplied sock_fprog | 425 | * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog |
297 | * @user_filter: pointer to the user data containing a sock_fprog. | 426 | * @user_filter: pointer to the user data containing a sock_fprog. |
298 | * | 427 | * |
299 | * Returns 0 on success and non-zero otherwise. | 428 | * Returns 0 on success and non-zero otherwise. |
300 | */ | 429 | */ |
301 | static long seccomp_attach_user_filter(char __user *user_filter) | 430 | static struct seccomp_filter * |
431 | seccomp_prepare_user_filter(const char __user *user_filter) | ||
302 | { | 432 | { |
303 | struct sock_fprog fprog; | 433 | struct sock_fprog fprog; |
304 | long ret = -EFAULT; | 434 | struct seccomp_filter *filter = ERR_PTR(-EFAULT); |
305 | 435 | ||
306 | #ifdef CONFIG_COMPAT | 436 | #ifdef CONFIG_COMPAT |
307 | if (is_compat_task()) { | 437 | if (is_compat_task()) { |
@@ -314,9 +444,56 @@ static long seccomp_attach_user_filter(char __user *user_filter) | |||
314 | #endif | 444 | #endif |
315 | if (copy_from_user(&fprog, user_filter, sizeof(fprog))) | 445 | if (copy_from_user(&fprog, user_filter, sizeof(fprog))) |
316 | goto out; | 446 | goto out; |
317 | ret = seccomp_attach_filter(&fprog); | 447 | filter = seccomp_prepare_filter(&fprog); |
318 | out: | 448 | out: |
319 | return ret; | 449 | return filter; |
450 | } | ||
451 | |||
452 | /** | ||
453 | * seccomp_attach_filter: validate and attach filter | ||
454 | * @flags: flags to change filter behavior | ||
455 | * @filter: seccomp filter to add to the current process | ||
456 | * | ||
457 | * Caller must be holding current->sighand->siglock lock. | ||
458 | * | ||
459 | * Returns 0 on success, -ve on error. | ||
460 | */ | ||
461 | static long seccomp_attach_filter(unsigned int flags, | ||
462 | struct seccomp_filter *filter) | ||
463 | { | ||
464 | unsigned long total_insns; | ||
465 | struct seccomp_filter *walker; | ||
466 | |||
467 | BUG_ON(!spin_is_locked(¤t->sighand->siglock)); | ||
468 | |||
469 | /* Validate resulting filter length. */ | ||
470 | total_insns = filter->prog->len; | ||
471 | for (walker = current->seccomp.filter; walker; walker = walker->prev) | ||
472 | total_insns += walker->prog->len + 4; /* 4 instr penalty */ | ||
473 | if (total_insns > MAX_INSNS_PER_PATH) | ||
474 | return -ENOMEM; | ||
475 | |||
476 | /* If thread sync has been requested, check that it is possible. */ | ||
477 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) { | ||
478 | int ret; | ||
479 | |||
480 | ret = seccomp_can_sync_threads(); | ||
481 | if (ret) | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * If there is an existing filter, make it the prev and don't drop its | ||
487 | * task reference. | ||
488 | */ | ||
489 | filter->prev = current->seccomp.filter; | ||
490 | current->seccomp.filter = filter; | ||
491 | |||
492 | /* Now that the new filter is in place, synchronize to all threads. */ | ||
493 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) | ||
494 | seccomp_sync_threads(); | ||
495 | |||
496 | return 0; | ||
320 | } | 497 | } |
321 | 498 | ||
322 | /* get_seccomp_filter - increments the reference count of the filter on @tsk */ | 499 | /* get_seccomp_filter - increments the reference count of the filter on @tsk */ |
@@ -329,6 +506,14 @@ void get_seccomp_filter(struct task_struct *tsk) | |||
329 | atomic_inc(&orig->usage); | 506 | atomic_inc(&orig->usage); |
330 | } | 507 | } |
331 | 508 | ||
509 | static inline void seccomp_filter_free(struct seccomp_filter *filter) | ||
510 | { | ||
511 | if (filter) { | ||
512 | sk_filter_free(filter->prog); | ||
513 | kfree(filter); | ||
514 | } | ||
515 | } | ||
516 | |||
332 | /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ | 517 | /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ |
333 | void put_seccomp_filter(struct task_struct *tsk) | 518 | void put_seccomp_filter(struct task_struct *tsk) |
334 | { | 519 | { |
@@ -337,8 +522,7 @@ void put_seccomp_filter(struct task_struct *tsk) | |||
337 | while (orig && atomic_dec_and_test(&orig->usage)) { | 522 | while (orig && atomic_dec_and_test(&orig->usage)) { |
338 | struct seccomp_filter *freeme = orig; | 523 | struct seccomp_filter *freeme = orig; |
339 | orig = orig->prev; | 524 | orig = orig->prev; |
340 | sk_filter_free(freeme->prog); | 525 | seccomp_filter_free(freeme); |
341 | kfree(freeme); | ||
342 | } | 526 | } |
343 | } | 527 | } |
344 | 528 | ||
@@ -382,12 +566,17 @@ static int mode1_syscalls_32[] = { | |||
382 | 566 | ||
383 | int __secure_computing(int this_syscall) | 567 | int __secure_computing(int this_syscall) |
384 | { | 568 | { |
385 | int mode = current->seccomp.mode; | ||
386 | int exit_sig = 0; | 569 | int exit_sig = 0; |
387 | int *syscall; | 570 | int *syscall; |
388 | u32 ret; | 571 | u32 ret; |
389 | 572 | ||
390 | switch (mode) { | 573 | /* |
574 | * Make sure that any changes to mode from another thread have | ||
575 | * been seen after TIF_SECCOMP was seen. | ||
576 | */ | ||
577 | rmb(); | ||
578 | |||
579 | switch (current->seccomp.mode) { | ||
391 | case SECCOMP_MODE_STRICT: | 580 | case SECCOMP_MODE_STRICT: |
392 | syscall = mode1_syscalls; | 581 | syscall = mode1_syscalls; |
393 | #ifdef CONFIG_COMPAT | 582 | #ifdef CONFIG_COMPAT |
@@ -473,47 +662,152 @@ long prctl_get_seccomp(void) | |||
473 | } | 662 | } |
474 | 663 | ||
475 | /** | 664 | /** |
476 | * prctl_set_seccomp: configures current->seccomp.mode | 665 | * seccomp_set_mode_strict: internal function for setting strict seccomp |
477 | * @seccomp_mode: requested mode to use | ||
478 | * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER | ||
479 | * | 666 | * |
480 | * This function may be called repeatedly with a @seccomp_mode of | 667 | * Once current->seccomp.mode is non-zero, it may not be changed. |
481 | * SECCOMP_MODE_FILTER to install additional filters. Every filter | 668 | * |
482 | * successfully installed will be evaluated (in reverse order) for each system | 669 | * Returns 0 on success or -EINVAL on failure. |
483 | * call the task makes. | 670 | */ |
671 | static long seccomp_set_mode_strict(void) | ||
672 | { | ||
673 | const unsigned long seccomp_mode = SECCOMP_MODE_STRICT; | ||
674 | long ret = -EINVAL; | ||
675 | |||
676 | spin_lock_irq(¤t->sighand->siglock); | ||
677 | |||
678 | if (!seccomp_may_assign_mode(seccomp_mode)) | ||
679 | goto out; | ||
680 | |||
681 | #ifdef TIF_NOTSC | ||
682 | disable_TSC(); | ||
683 | #endif | ||
684 | seccomp_assign_mode(current, seccomp_mode); | ||
685 | ret = 0; | ||
686 | |||
687 | out: | ||
688 | spin_unlock_irq(¤t->sighand->siglock); | ||
689 | |||
690 | return ret; | ||
691 | } | ||
692 | |||
693 | #ifdef CONFIG_SECCOMP_FILTER | ||
694 | /** | ||
695 | * seccomp_set_mode_filter: internal function for setting seccomp filter | ||
696 | * @flags: flags to change filter behavior | ||
697 | * @filter: struct sock_fprog containing filter | ||
698 | * | ||
699 | * This function may be called repeatedly to install additional filters. | ||
700 | * Every filter successfully installed will be evaluated (in reverse order) | ||
701 | * for each system call the task makes. | ||
484 | * | 702 | * |
485 | * Once current->seccomp.mode is non-zero, it may not be changed. | 703 | * Once current->seccomp.mode is non-zero, it may not be changed. |
486 | * | 704 | * |
487 | * Returns 0 on success or -EINVAL on failure. | 705 | * Returns 0 on success or -EINVAL on failure. |
488 | */ | 706 | */ |
489 | long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) | 707 | static long seccomp_set_mode_filter(unsigned int flags, |
708 | const char __user *filter) | ||
490 | { | 709 | { |
710 | const unsigned long seccomp_mode = SECCOMP_MODE_FILTER; | ||
711 | struct seccomp_filter *prepared = NULL; | ||
491 | long ret = -EINVAL; | 712 | long ret = -EINVAL; |
492 | 713 | ||
493 | if (current->seccomp.mode && | 714 | /* Validate flags. */ |
494 | current->seccomp.mode != seccomp_mode) | 715 | if (flags & ~SECCOMP_FILTER_FLAG_MASK) |
716 | return -EINVAL; | ||
717 | |||
718 | /* Prepare the new filter before holding any locks. */ | ||
719 | prepared = seccomp_prepare_user_filter(filter); | ||
720 | if (IS_ERR(prepared)) | ||
721 | return PTR_ERR(prepared); | ||
722 | |||
723 | /* | ||
724 | * Make sure we cannot change seccomp or nnp state via TSYNC | ||
725 | * while another thread is in the middle of calling exec. | ||
726 | */ | ||
727 | if (flags & SECCOMP_FILTER_FLAG_TSYNC && | ||
728 | mutex_lock_killable(¤t->signal->cred_guard_mutex)) | ||
729 | goto out_free; | ||
730 | |||
731 | spin_lock_irq(¤t->sighand->siglock); | ||
732 | |||
733 | if (!seccomp_may_assign_mode(seccomp_mode)) | ||
734 | goto out; | ||
735 | |||
736 | ret = seccomp_attach_filter(flags, prepared); | ||
737 | if (ret) | ||
495 | goto out; | 738 | goto out; |
739 | /* Do not free the successfully attached filter. */ | ||
740 | prepared = NULL; | ||
741 | |||
742 | seccomp_assign_mode(current, seccomp_mode); | ||
743 | out: | ||
744 | spin_unlock_irq(¤t->sighand->siglock); | ||
745 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) | ||
746 | mutex_unlock(¤t->signal->cred_guard_mutex); | ||
747 | out_free: | ||
748 | seccomp_filter_free(prepared); | ||
749 | return ret; | ||
750 | } | ||
751 | #else | ||
752 | static inline long seccomp_set_mode_filter(unsigned int flags, | ||
753 | const char __user *filter) | ||
754 | { | ||
755 | return -EINVAL; | ||
756 | } | ||
757 | #endif | ||
758 | |||
759 | /* Common entry point for both prctl and syscall. */ | ||
760 | static long do_seccomp(unsigned int op, unsigned int flags, | ||
761 | const char __user *uargs) | ||
762 | { | ||
763 | switch (op) { | ||
764 | case SECCOMP_SET_MODE_STRICT: | ||
765 | if (flags != 0 || uargs != NULL) | ||
766 | return -EINVAL; | ||
767 | return seccomp_set_mode_strict(); | ||
768 | case SECCOMP_SET_MODE_FILTER: | ||
769 | return seccomp_set_mode_filter(flags, uargs); | ||
770 | default: | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags, | ||
776 | const char __user *, uargs) | ||
777 | { | ||
778 | return do_seccomp(op, flags, uargs); | ||
779 | } | ||
780 | |||
781 | /** | ||
782 | * prctl_set_seccomp: configures current->seccomp.mode | ||
783 | * @seccomp_mode: requested mode to use | ||
784 | * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER | ||
785 | * | ||
786 | * Returns 0 on success or -EINVAL on failure. | ||
787 | */ | ||
788 | long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) | ||
789 | { | ||
790 | unsigned int op; | ||
791 | char __user *uargs; | ||
496 | 792 | ||
497 | switch (seccomp_mode) { | 793 | switch (seccomp_mode) { |
498 | case SECCOMP_MODE_STRICT: | 794 | case SECCOMP_MODE_STRICT: |
499 | ret = 0; | 795 | op = SECCOMP_SET_MODE_STRICT; |
500 | #ifdef TIF_NOTSC | 796 | /* |
501 | disable_TSC(); | 797 | * Setting strict mode through prctl always ignored filter, |
502 | #endif | 798 | * so make sure it is always NULL here to pass the internal |
799 | * check in do_seccomp(). | ||
800 | */ | ||
801 | uargs = NULL; | ||
503 | break; | 802 | break; |
504 | #ifdef CONFIG_SECCOMP_FILTER | ||
505 | case SECCOMP_MODE_FILTER: | 803 | case SECCOMP_MODE_FILTER: |
506 | ret = seccomp_attach_user_filter(filter); | 804 | op = SECCOMP_SET_MODE_FILTER; |
507 | if (ret) | 805 | uargs = filter; |
508 | goto out; | ||
509 | break; | 806 | break; |
510 | #endif | ||
511 | default: | 807 | default: |
512 | goto out; | 808 | return -EINVAL; |
513 | } | 809 | } |
514 | 810 | ||
515 | current->seccomp.mode = seccomp_mode; | 811 | /* prctl interface doesn't have flags, so they are always zero. */ |
516 | set_thread_flag(TIF_SECCOMP); | 812 | return do_seccomp(op, 0, uargs); |
517 | out: | ||
518 | return ret; | ||
519 | } | 813 | } |
diff --git a/kernel/sys.c b/kernel/sys.c index 66a751ebf9d9..ce8129192a26 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1990,12 +1990,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1990 | if (arg2 != 1 || arg3 || arg4 || arg5) | 1990 | if (arg2 != 1 || arg3 || arg4 || arg5) |
1991 | return -EINVAL; | 1991 | return -EINVAL; |
1992 | 1992 | ||
1993 | current->no_new_privs = 1; | 1993 | task_set_no_new_privs(current); |
1994 | break; | 1994 | break; |
1995 | case PR_GET_NO_NEW_PRIVS: | 1995 | case PR_GET_NO_NEW_PRIVS: |
1996 | if (arg2 || arg3 || arg4 || arg5) | 1996 | if (arg2 || arg3 || arg4 || arg5) |
1997 | return -EINVAL; | 1997 | return -EINVAL; |
1998 | return current->no_new_privs ? 1 : 0; | 1998 | return task_no_new_privs(current) ? 1 : 0; |
1999 | case PR_GET_THP_DISABLE: | 1999 | case PR_GET_THP_DISABLE: |
2000 | if (arg2 || arg3 || arg4 || arg5) | 2000 | if (arg2 || arg3 || arg4 || arg5) |
2001 | return -EINVAL; | 2001 | return -EINVAL; |
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 36441b51b5df..2904a2105914 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at); | |||
213 | 213 | ||
214 | /* compare kernel pointers */ | 214 | /* compare kernel pointers */ |
215 | cond_syscall(sys_kcmp); | 215 | cond_syscall(sys_kcmp); |
216 | |||
217 | /* operate on Secure Computing state */ | ||
218 | cond_syscall(sys_seccomp); | ||
diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c index 52ebc70263f4..875f64e8935b 100644 --- a/kernel/system_keyring.c +++ b/kernel/system_keyring.c | |||
@@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void) | |||
89 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", | 89 | pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", |
90 | PTR_ERR(key)); | 90 | PTR_ERR(key)); |
91 | } else { | 91 | } else { |
92 | set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags); | ||
92 | pr_notice("Loaded X.509 cert '%s'\n", | 93 | pr_notice("Loaded X.509 cert '%s'\n", |
93 | key_ref_to_ptr(key)->description); | 94 | key_ref_to_ptr(key)->description); |
94 | key_ref_put(key); | 95 | key_ref_put(key); |
diff --git a/lib/Kconfig b/lib/Kconfig index 334f7722a999..a8a775730c09 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -451,7 +451,8 @@ config MPILIB | |||
451 | 451 | ||
452 | config SIGNATURE | 452 | config SIGNATURE |
453 | tristate | 453 | tristate |
454 | depends on KEYS && CRYPTO | 454 | depends on KEYS |
455 | select CRYPTO | ||
455 | select CRYPTO_SHA1 | 456 | select CRYPTO_SHA1 |
456 | select MPILIB | 457 | select MPILIB |
457 | help | 458 | help |
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 6e7a236525b6..ffeba8f9dda9 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/key-type.h> | 8 | #include <linux/key-type.h> |
9 | 9 | ||
10 | #include <keys/ceph-type.h> | 10 | #include <keys/ceph-type.h> |
11 | #include <keys/user-type.h> | ||
11 | #include <linux/ceph/decode.h> | 12 | #include <linux/ceph/decode.h> |
12 | #include "crypto.h" | 13 | #include "crypto.h" |
13 | 14 | ||
@@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |||
423 | } | 424 | } |
424 | } | 425 | } |
425 | 426 | ||
426 | static int ceph_key_instantiate(struct key *key, | 427 | static int ceph_key_preparse(struct key_preparsed_payload *prep) |
427 | struct key_preparsed_payload *prep) | ||
428 | { | 428 | { |
429 | struct ceph_crypto_key *ckey; | 429 | struct ceph_crypto_key *ckey; |
430 | size_t datalen = prep->datalen; | 430 | size_t datalen = prep->datalen; |
@@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key, | |||
435 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 435 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
436 | goto err; | 436 | goto err; |
437 | 437 | ||
438 | ret = key_payload_reserve(key, datalen); | ||
439 | if (ret < 0) | ||
440 | goto err; | ||
441 | |||
442 | ret = -ENOMEM; | 438 | ret = -ENOMEM; |
443 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); | 439 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); |
444 | if (!ckey) | 440 | if (!ckey) |
@@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key, | |||
450 | if (ret < 0) | 446 | if (ret < 0) |
451 | goto err_ckey; | 447 | goto err_ckey; |
452 | 448 | ||
453 | key->payload.data = ckey; | 449 | prep->payload[0] = ckey; |
450 | prep->quotalen = datalen; | ||
454 | return 0; | 451 | return 0; |
455 | 452 | ||
456 | err_ckey: | 453 | err_ckey: |
@@ -459,12 +456,15 @@ err: | |||
459 | return ret; | 456 | return ret; |
460 | } | 457 | } |
461 | 458 | ||
462 | static int ceph_key_match(const struct key *key, const void *description) | 459 | static void ceph_key_free_preparse(struct key_preparsed_payload *prep) |
463 | { | 460 | { |
464 | return strcmp(key->description, description) == 0; | 461 | struct ceph_crypto_key *ckey = prep->payload[0]; |
462 | ceph_crypto_key_destroy(ckey); | ||
463 | kfree(ckey); | ||
465 | } | 464 | } |
466 | 465 | ||
467 | static void ceph_key_destroy(struct key *key) { | 466 | static void ceph_key_destroy(struct key *key) |
467 | { | ||
468 | struct ceph_crypto_key *ckey = key->payload.data; | 468 | struct ceph_crypto_key *ckey = key->payload.data; |
469 | 469 | ||
470 | ceph_crypto_key_destroy(ckey); | 470 | ceph_crypto_key_destroy(ckey); |
@@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) { | |||
473 | 473 | ||
474 | struct key_type key_type_ceph = { | 474 | struct key_type key_type_ceph = { |
475 | .name = "ceph", | 475 | .name = "ceph", |
476 | .instantiate = ceph_key_instantiate, | 476 | .preparse = ceph_key_preparse, |
477 | .match = ceph_key_match, | 477 | .free_preparse = ceph_key_free_preparse, |
478 | .instantiate = generic_key_instantiate, | ||
479 | .match = user_match, | ||
478 | .destroy = ceph_key_destroy, | 480 | .destroy = ceph_key_destroy, |
479 | }; | 481 | }; |
480 | 482 | ||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index bf8584339048..f380b2c58178 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
@@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache; | |||
46 | #define DNS_ERRORNO_OPTION "dnserror" | 46 | #define DNS_ERRORNO_OPTION "dnserror" |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Instantiate a user defined key for dns_resolver. | 49 | * Preparse instantiation data for a dns_resolver key. |
50 | * | 50 | * |
51 | * The data must be a NUL-terminated string, with the NUL char accounted in | 51 | * The data must be a NUL-terminated string, with the NUL char accounted in |
52 | * datalen. | 52 | * datalen. |
@@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache; | |||
58 | * "ip1,ip2,...#foo=bar" | 58 | * "ip1,ip2,...#foo=bar" |
59 | */ | 59 | */ |
60 | static int | 60 | static int |
61 | dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | 61 | dns_resolver_preparse(struct key_preparsed_payload *prep) |
62 | { | 62 | { |
63 | struct user_key_payload *upayload; | 63 | struct user_key_payload *upayload; |
64 | unsigned long derrno; | 64 | unsigned long derrno; |
65 | int ret; | 65 | int ret; |
66 | size_t datalen = prep->datalen, result_len = 0; | 66 | int datalen = prep->datalen, result_len = 0; |
67 | const char *data = prep->data, *end, *opt; | 67 | const char *data = prep->data, *end, *opt; |
68 | 68 | ||
69 | kenter("%%%d,%s,'%*.*s',%zu", | 69 | kenter("'%*.*s',%u", datalen, datalen, data, datalen); |
70 | key->serial, key->description, | ||
71 | (int)datalen, (int)datalen, data, datalen); | ||
72 | 70 | ||
73 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') | 71 | if (datalen <= 1 || !data || data[datalen - 1] != '\0') |
74 | return -EINVAL; | 72 | return -EINVAL; |
@@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
95 | opt_len = next_opt - opt; | 93 | opt_len = next_opt - opt; |
96 | if (!opt_len) { | 94 | if (!opt_len) { |
97 | printk(KERN_WARNING | 95 | printk(KERN_WARNING |
98 | "Empty option to dns_resolver key %d\n", | 96 | "Empty option to dns_resolver key\n"); |
99 | key->serial); | ||
100 | return -EINVAL; | 97 | return -EINVAL; |
101 | } | 98 | } |
102 | 99 | ||
@@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
125 | goto bad_option_value; | 122 | goto bad_option_value; |
126 | 123 | ||
127 | kdebug("dns error no. = %lu", derrno); | 124 | kdebug("dns error no. = %lu", derrno); |
128 | key->type_data.x[0] = -derrno; | 125 | prep->type_data[0] = ERR_PTR(-derrno); |
129 | continue; | 126 | continue; |
130 | } | 127 | } |
131 | 128 | ||
132 | bad_option_value: | 129 | bad_option_value: |
133 | printk(KERN_WARNING | 130 | printk(KERN_WARNING |
134 | "Option '%*.*s' to dns_resolver key %d:" | 131 | "Option '%*.*s' to dns_resolver key:" |
135 | " bad/missing value\n", | 132 | " bad/missing value\n", |
136 | opt_nlen, opt_nlen, opt, key->serial); | 133 | opt_nlen, opt_nlen, opt); |
137 | return -EINVAL; | 134 | return -EINVAL; |
138 | } while (opt = next_opt + 1, opt < end); | 135 | } while (opt = next_opt + 1, opt < end); |
139 | } | 136 | } |
140 | 137 | ||
141 | /* don't cache the result if we're caching an error saying there's no | 138 | /* don't cache the result if we're caching an error saying there's no |
142 | * result */ | 139 | * result */ |
143 | if (key->type_data.x[0]) { | 140 | if (prep->type_data[0]) { |
144 | kleave(" = 0 [h_error %ld]", key->type_data.x[0]); | 141 | kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0])); |
145 | return 0; | 142 | return 0; |
146 | } | 143 | } |
147 | 144 | ||
148 | kdebug("store result"); | 145 | kdebug("store result"); |
149 | ret = key_payload_reserve(key, result_len); | 146 | prep->quotalen = result_len; |
150 | if (ret < 0) | ||
151 | return -EINVAL; | ||
152 | 147 | ||
153 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); | 148 | upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL); |
154 | if (!upayload) { | 149 | if (!upayload) { |
@@ -159,13 +154,23 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
159 | upayload->datalen = result_len; | 154 | upayload->datalen = result_len; |
160 | memcpy(upayload->data, data, result_len); | 155 | memcpy(upayload->data, data, result_len); |
161 | upayload->data[result_len] = '\0'; | 156 | upayload->data[result_len] = '\0'; |
162 | rcu_assign_pointer(key->payload.data, upayload); | ||
163 | 157 | ||
158 | prep->payload[0] = upayload; | ||
164 | kleave(" = 0"); | 159 | kleave(" = 0"); |
165 | return 0; | 160 | return 0; |
166 | } | 161 | } |
167 | 162 | ||
168 | /* | 163 | /* |
164 | * Clean up the preparse data | ||
165 | */ | ||
166 | static void dns_resolver_free_preparse(struct key_preparsed_payload *prep) | ||
167 | { | ||
168 | pr_devel("==>%s()\n", __func__); | ||
169 | |||
170 | kfree(prep->payload[0]); | ||
171 | } | ||
172 | |||
173 | /* | ||
169 | * The description is of the form "[<type>:]<domain_name>" | 174 | * The description is of the form "[<type>:]<domain_name>" |
170 | * | 175 | * |
171 | * The domain name may be a simple name or an absolute domain name (which | 176 | * The domain name may be a simple name or an absolute domain name (which |
@@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key, | |||
234 | 239 | ||
235 | struct key_type key_type_dns_resolver = { | 240 | struct key_type key_type_dns_resolver = { |
236 | .name = "dns_resolver", | 241 | .name = "dns_resolver", |
237 | .instantiate = dns_resolver_instantiate, | 242 | .preparse = dns_resolver_preparse, |
243 | .free_preparse = dns_resolver_free_preparse, | ||
244 | .instantiate = generic_key_instantiate, | ||
238 | .match = dns_resolver_match, | 245 | .match = dns_resolver_match, |
239 | .revoke = user_revoke, | 246 | .revoke = user_revoke, |
240 | .destroy = user_destroy, | 247 | .destroy = user_destroy, |
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index dd8696a3dbec..39d2c39bdf87 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c | |||
@@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen, | |||
129 | } | 129 | } |
130 | 130 | ||
131 | down_read(&rkey->sem); | 131 | down_read(&rkey->sem); |
132 | set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); | ||
132 | rkey->perm |= KEY_USR_VIEW; | 133 | rkey->perm |= KEY_USR_VIEW; |
133 | 134 | ||
134 | ret = key_validate(rkey); | 135 | ret = key_validate(rkey); |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 69e77c8ff285..05b708bbdb0d 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -890,8 +890,8 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, | |||
890 | } | 890 | } |
891 | 891 | ||
892 | for (;;) { | 892 | for (;;) { |
893 | host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, | 893 | host_spot = netlbl_catmap_walk(secattr->attr.mls.cat, |
894 | host_spot + 1); | 894 | host_spot + 1); |
895 | if (host_spot < 0) | 895 | if (host_spot < 0) |
896 | break; | 896 | break; |
897 | 897 | ||
@@ -973,7 +973,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, | |||
973 | return -EPERM; | 973 | return -EPERM; |
974 | break; | 974 | break; |
975 | } | 975 | } |
976 | ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat, | 976 | ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, |
977 | host_spot, | 977 | host_spot, |
978 | GFP_ATOMIC); | 978 | GFP_ATOMIC); |
979 | if (ret_val != 0) | 979 | if (ret_val != 0) |
@@ -1039,8 +1039,7 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, | |||
1039 | u32 cat_iter = 0; | 1039 | u32 cat_iter = 0; |
1040 | 1040 | ||
1041 | for (;;) { | 1041 | for (;;) { |
1042 | cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, | 1042 | cat = netlbl_catmap_walk(secattr->attr.mls.cat, cat + 1); |
1043 | cat + 1); | ||
1044 | if (cat < 0) | 1043 | if (cat < 0) |
1045 | break; | 1044 | break; |
1046 | if ((cat_iter + 2) > net_cat_len) | 1045 | 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, | |||
1075 | u32 iter; | 1074 | u32 iter; |
1076 | 1075 | ||
1077 | for (iter = 0; iter < net_cat_len; iter += 2) { | 1076 | for (iter = 0; iter < net_cat_len; iter += 2) { |
1078 | ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat, | 1077 | ret_val = netlbl_catmap_setbit(&secattr->attr.mls.cat, |
1079 | get_unaligned_be16(&net_cat[iter]), | 1078 | get_unaligned_be16(&net_cat[iter]), |
1080 | GFP_ATOMIC); | 1079 | GFP_ATOMIC); |
1081 | if (ret_val != 0) | 1080 | if (ret_val != 0) |
1082 | return ret_val; | 1081 | return ret_val; |
1083 | } | 1082 | } |
@@ -1155,8 +1154,7 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, | |||
1155 | return -ENOSPC; | 1154 | return -ENOSPC; |
1156 | 1155 | ||
1157 | for (;;) { | 1156 | for (;;) { |
1158 | iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat, | 1157 | iter = netlbl_catmap_walk(secattr->attr.mls.cat, iter + 1); |
1159 | iter + 1); | ||
1160 | if (iter < 0) | 1158 | if (iter < 0) |
1161 | break; | 1159 | break; |
1162 | cat_size += (iter == 0 ? 0 : sizeof(u16)); | 1160 | 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, | |||
1164 | return -ENOSPC; | 1162 | return -ENOSPC; |
1165 | array[array_cnt++] = iter; | 1163 | array[array_cnt++] = iter; |
1166 | 1164 | ||
1167 | iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat, | 1165 | iter = netlbl_catmap_walkrng(secattr->attr.mls.cat, iter); |
1168 | iter); | ||
1169 | if (iter < 0) | 1166 | if (iter < 0) |
1170 | return -EFAULT; | 1167 | return -EFAULT; |
1171 | cat_size += sizeof(u16); | 1168 | cat_size += sizeof(u16); |
@@ -1217,10 +1214,10 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, | |||
1217 | else | 1214 | else |
1218 | cat_low = 0; | 1215 | cat_low = 0; |
1219 | 1216 | ||
1220 | ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat, | 1217 | ret_val = netlbl_catmap_setrng(&secattr->attr.mls.cat, |
1221 | cat_low, | 1218 | cat_low, |
1222 | cat_high, | 1219 | cat_high, |
1223 | GFP_ATOMIC); | 1220 | GFP_ATOMIC); |
1224 | if (ret_val != 0) | 1221 | if (ret_val != 0) |
1225 | return ret_val; | 1222 | return ret_val; |
1226 | } | 1223 | } |
@@ -1335,16 +1332,12 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, | |||
1335 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1332 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
1336 | 1333 | ||
1337 | if (tag_len > 4) { | 1334 | if (tag_len > 4) { |
1338 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1339 | if (secattr->attr.mls.cat == NULL) | ||
1340 | return -ENOMEM; | ||
1341 | |||
1342 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, | 1335 | ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, |
1343 | &tag[4], | 1336 | &tag[4], |
1344 | tag_len - 4, | 1337 | tag_len - 4, |
1345 | secattr); | 1338 | secattr); |
1346 | if (ret_val != 0) { | 1339 | if (ret_val != 0) { |
1347 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 1340 | netlbl_catmap_free(secattr->attr.mls.cat); |
1348 | return ret_val; | 1341 | return ret_val; |
1349 | } | 1342 | } |
1350 | 1343 | ||
@@ -1430,16 +1423,12 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, | |||
1430 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1423 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
1431 | 1424 | ||
1432 | if (tag_len > 4) { | 1425 | if (tag_len > 4) { |
1433 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1434 | if (secattr->attr.mls.cat == NULL) | ||
1435 | return -ENOMEM; | ||
1436 | |||
1437 | ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, | 1426 | ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, |
1438 | &tag[4], | 1427 | &tag[4], |
1439 | tag_len - 4, | 1428 | tag_len - 4, |
1440 | secattr); | 1429 | secattr); |
1441 | if (ret_val != 0) { | 1430 | if (ret_val != 0) { |
1442 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 1431 | netlbl_catmap_free(secattr->attr.mls.cat); |
1443 | return ret_val; | 1432 | return ret_val; |
1444 | } | 1433 | } |
1445 | 1434 | ||
@@ -1524,16 +1513,12 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, | |||
1524 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; | 1513 | secattr->flags |= NETLBL_SECATTR_MLS_LVL; |
1525 | 1514 | ||
1526 | if (tag_len > 4) { | 1515 | if (tag_len > 4) { |
1527 | secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1528 | if (secattr->attr.mls.cat == NULL) | ||
1529 | return -ENOMEM; | ||
1530 | |||
1531 | ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, | 1516 | ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, |
1532 | &tag[4], | 1517 | &tag[4], |
1533 | tag_len - 4, | 1518 | tag_len - 4, |
1534 | secattr); | 1519 | secattr); |
1535 | if (ret_val != 0) { | 1520 | if (ret_val != 0) { |
1536 | netlbl_secattr_catmap_free(secattr->attr.mls.cat); | 1521 | netlbl_catmap_free(secattr->attr.mls.cat); |
1537 | return ret_val; | 1522 | return ret_val; |
1538 | } | 1523 | } |
1539 | 1524 | ||
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 3045a964f39c..05ea4a4cc0ac 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c | |||
@@ -405,8 +405,72 @@ out_entry: | |||
405 | * Security Attribute Functions | 405 | * Security Attribute Functions |
406 | */ | 406 | */ |
407 | 407 | ||
408 | #define _CM_F_NONE 0x00000000 | ||
409 | #define _CM_F_ALLOC 0x00000001 | ||
410 | #define _CM_F_WALK 0x00000002 | ||
411 | |||
408 | /** | 412 | /** |
409 | * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit | 413 | * _netlbl_catmap_getnode - Get a individual node from a catmap |
414 | * @catmap: pointer to the category bitmap | ||
415 | * @offset: the requested offset | ||
416 | * @cm_flags: catmap flags, see _CM_F_* | ||
417 | * @gfp_flags: memory allocation flags | ||
418 | * | ||
419 | * Description: | ||
420 | * Iterate through the catmap looking for the node associated with @offset. | ||
421 | * If the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node, | ||
422 | * one will be created and inserted into the catmap. If the _CM_F_WALK flag is | ||
423 | * set in @cm_flags and there is no associated node, the next highest node will | ||
424 | * be returned. Returns a pointer to the node on success, NULL on failure. | ||
425 | * | ||
426 | */ | ||
427 | static struct netlbl_lsm_catmap *_netlbl_catmap_getnode( | ||
428 | struct netlbl_lsm_catmap **catmap, | ||
429 | u32 offset, | ||
430 | unsigned int cm_flags, | ||
431 | gfp_t gfp_flags) | ||
432 | { | ||
433 | struct netlbl_lsm_catmap *iter = *catmap; | ||
434 | struct netlbl_lsm_catmap *prev = NULL; | ||
435 | |||
436 | if (iter == NULL) | ||
437 | goto catmap_getnode_alloc; | ||
438 | if (offset < iter->startbit) | ||
439 | goto catmap_getnode_walk; | ||
440 | while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
441 | prev = iter; | ||
442 | iter = iter->next; | ||
443 | } | ||
444 | if (iter == NULL || offset < iter->startbit) | ||
445 | goto catmap_getnode_walk; | ||
446 | |||
447 | return iter; | ||
448 | |||
449 | catmap_getnode_walk: | ||
450 | if (cm_flags & _CM_F_WALK) | ||
451 | return iter; | ||
452 | catmap_getnode_alloc: | ||
453 | if (!(cm_flags & _CM_F_ALLOC)) | ||
454 | return NULL; | ||
455 | |||
456 | iter = netlbl_catmap_alloc(gfp_flags); | ||
457 | if (iter == NULL) | ||
458 | return NULL; | ||
459 | iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1); | ||
460 | |||
461 | if (prev == NULL) { | ||
462 | iter->next = *catmap; | ||
463 | *catmap = iter; | ||
464 | } else { | ||
465 | iter->next = prev->next; | ||
466 | prev->next = iter; | ||
467 | } | ||
468 | |||
469 | return iter; | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * netlbl_catmap_walk - Walk a LSM secattr catmap looking for a bit | ||
410 | * @catmap: the category bitmap | 474 | * @catmap: the category bitmap |
411 | * @offset: the offset to start searching at, in bits | 475 | * @offset: the offset to start searching at, in bits |
412 | * | 476 | * |
@@ -415,54 +479,51 @@ out_entry: | |||
415 | * returns the spot of the first set bit or -ENOENT if no bits are set. | 479 | * returns the spot of the first set bit or -ENOENT if no bits are set. |
416 | * | 480 | * |
417 | */ | 481 | */ |
418 | int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, | 482 | int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset) |
419 | u32 offset) | ||
420 | { | 483 | { |
421 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 484 | struct netlbl_lsm_catmap *iter = catmap; |
422 | u32 node_idx; | 485 | u32 idx; |
423 | u32 node_bit; | 486 | u32 bit; |
424 | NETLBL_CATMAP_MAPTYPE bitmap; | 487 | NETLBL_CATMAP_MAPTYPE bitmap; |
425 | 488 | ||
489 | iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); | ||
490 | if (iter == NULL) | ||
491 | return -ENOENT; | ||
426 | if (offset > iter->startbit) { | 492 | if (offset > iter->startbit) { |
427 | while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | 493 | offset -= iter->startbit; |
428 | iter = iter->next; | 494 | idx = offset / NETLBL_CATMAP_MAPSIZE; |
429 | if (iter == NULL) | 495 | bit = offset % NETLBL_CATMAP_MAPSIZE; |
430 | return -ENOENT; | ||
431 | } | ||
432 | node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
433 | node_bit = offset - iter->startbit - | ||
434 | (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
435 | } else { | 496 | } else { |
436 | node_idx = 0; | 497 | idx = 0; |
437 | node_bit = 0; | 498 | bit = 0; |
438 | } | 499 | } |
439 | bitmap = iter->bitmap[node_idx] >> node_bit; | 500 | bitmap = iter->bitmap[idx] >> bit; |
440 | 501 | ||
441 | for (;;) { | 502 | for (;;) { |
442 | if (bitmap != 0) { | 503 | if (bitmap != 0) { |
443 | while ((bitmap & NETLBL_CATMAP_BIT) == 0) { | 504 | while ((bitmap & NETLBL_CATMAP_BIT) == 0) { |
444 | bitmap >>= 1; | 505 | bitmap >>= 1; |
445 | node_bit++; | 506 | bit++; |
446 | } | 507 | } |
447 | return iter->startbit + | 508 | return iter->startbit + |
448 | (NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit; | 509 | (NETLBL_CATMAP_MAPSIZE * idx) + bit; |
449 | } | 510 | } |
450 | if (++node_idx >= NETLBL_CATMAP_MAPCNT) { | 511 | if (++idx >= NETLBL_CATMAP_MAPCNT) { |
451 | if (iter->next != NULL) { | 512 | if (iter->next != NULL) { |
452 | iter = iter->next; | 513 | iter = iter->next; |
453 | node_idx = 0; | 514 | idx = 0; |
454 | } else | 515 | } else |
455 | return -ENOENT; | 516 | return -ENOENT; |
456 | } | 517 | } |
457 | bitmap = iter->bitmap[node_idx]; | 518 | bitmap = iter->bitmap[idx]; |
458 | node_bit = 0; | 519 | bit = 0; |
459 | } | 520 | } |
460 | 521 | ||
461 | return -ENOENT; | 522 | return -ENOENT; |
462 | } | 523 | } |
463 | 524 | ||
464 | /** | 525 | /** |
465 | * netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits | 526 | * netlbl_catmap_walkrng - Find the end of a string of set bits |
466 | * @catmap: the category bitmap | 527 | * @catmap: the category bitmap |
467 | * @offset: the offset to start searching at, in bits | 528 | * @offset: the offset to start searching at, in bits |
468 | * | 529 | * |
@@ -472,57 +533,105 @@ int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap, | |||
472 | * the end of the bitmap. | 533 | * the end of the bitmap. |
473 | * | 534 | * |
474 | */ | 535 | */ |
475 | int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, | 536 | int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset) |
476 | u32 offset) | ||
477 | { | 537 | { |
478 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 538 | struct netlbl_lsm_catmap *iter; |
479 | u32 node_idx; | 539 | struct netlbl_lsm_catmap *prev = NULL; |
480 | u32 node_bit; | 540 | u32 idx; |
541 | u32 bit; | ||
481 | NETLBL_CATMAP_MAPTYPE bitmask; | 542 | NETLBL_CATMAP_MAPTYPE bitmask; |
482 | NETLBL_CATMAP_MAPTYPE bitmap; | 543 | NETLBL_CATMAP_MAPTYPE bitmap; |
483 | 544 | ||
545 | iter = _netlbl_catmap_getnode(&catmap, offset, _CM_F_WALK, 0); | ||
546 | if (iter == NULL) | ||
547 | return -ENOENT; | ||
484 | if (offset > iter->startbit) { | 548 | if (offset > iter->startbit) { |
485 | while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | 549 | offset -= iter->startbit; |
486 | iter = iter->next; | 550 | idx = offset / NETLBL_CATMAP_MAPSIZE; |
487 | if (iter == NULL) | 551 | bit = offset % NETLBL_CATMAP_MAPSIZE; |
488 | return -ENOENT; | ||
489 | } | ||
490 | node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | ||
491 | node_bit = offset - iter->startbit - | ||
492 | (NETLBL_CATMAP_MAPSIZE * node_idx); | ||
493 | } else { | 552 | } else { |
494 | node_idx = 0; | 553 | idx = 0; |
495 | node_bit = 0; | 554 | bit = 0; |
496 | } | 555 | } |
497 | bitmask = NETLBL_CATMAP_BIT << node_bit; | 556 | bitmask = NETLBL_CATMAP_BIT << bit; |
498 | 557 | ||
499 | for (;;) { | 558 | for (;;) { |
500 | bitmap = iter->bitmap[node_idx]; | 559 | bitmap = iter->bitmap[idx]; |
501 | while (bitmask != 0 && (bitmap & bitmask) != 0) { | 560 | while (bitmask != 0 && (bitmap & bitmask) != 0) { |
502 | bitmask <<= 1; | 561 | bitmask <<= 1; |
503 | node_bit++; | 562 | bit++; |
504 | } | 563 | } |
505 | 564 | ||
506 | if (bitmask != 0) | 565 | if (prev && idx == 0 && bit == 0) |
566 | return prev->startbit + NETLBL_CATMAP_SIZE - 1; | ||
567 | else if (bitmask != 0) | ||
507 | return iter->startbit + | 568 | return iter->startbit + |
508 | (NETLBL_CATMAP_MAPSIZE * node_idx) + | 569 | (NETLBL_CATMAP_MAPSIZE * idx) + bit - 1; |
509 | node_bit - 1; | 570 | else if (++idx >= NETLBL_CATMAP_MAPCNT) { |
510 | else if (++node_idx >= NETLBL_CATMAP_MAPCNT) { | ||
511 | if (iter->next == NULL) | 571 | if (iter->next == NULL) |
512 | return iter->startbit + NETLBL_CATMAP_SIZE - 1; | 572 | return iter->startbit + NETLBL_CATMAP_SIZE - 1; |
573 | prev = iter; | ||
513 | iter = iter->next; | 574 | iter = iter->next; |
514 | node_idx = 0; | 575 | idx = 0; |
515 | } | 576 | } |
516 | bitmask = NETLBL_CATMAP_BIT; | 577 | bitmask = NETLBL_CATMAP_BIT; |
517 | node_bit = 0; | 578 | bit = 0; |
518 | } | 579 | } |
519 | 580 | ||
520 | return -ENOENT; | 581 | return -ENOENT; |
521 | } | 582 | } |
522 | 583 | ||
523 | /** | 584 | /** |
524 | * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap | 585 | * netlbl_catmap_getlong - Export an unsigned long bitmap |
525 | * @catmap: the category bitmap | 586 | * @catmap: pointer to the category bitmap |
587 | * @offset: pointer to the requested offset | ||
588 | * @bitmap: the exported bitmap | ||
589 | * | ||
590 | * Description: | ||
591 | * Export a bitmap with an offset greater than or equal to @offset and return | ||
592 | * it in @bitmap. The @offset must be aligned to an unsigned long and will be | ||
593 | * updated on return if different from what was requested; if the catmap is | ||
594 | * empty at the requested offset and beyond, the @offset is set to (u32)-1. | ||
595 | * Returns zero on sucess, negative values on failure. | ||
596 | * | ||
597 | */ | ||
598 | int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, | ||
599 | u32 *offset, | ||
600 | unsigned long *bitmap) | ||
601 | { | ||
602 | struct netlbl_lsm_catmap *iter; | ||
603 | u32 off = *offset; | ||
604 | u32 idx; | ||
605 | |||
606 | /* only allow aligned offsets */ | ||
607 | if ((off & (BITS_PER_LONG - 1)) != 0) | ||
608 | return -EINVAL; | ||
609 | |||
610 | if (off < catmap->startbit) { | ||
611 | off = catmap->startbit; | ||
612 | *offset = off; | ||
613 | } | ||
614 | iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0); | ||
615 | if (iter == NULL) { | ||
616 | *offset = (u32)-1; | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | if (off < iter->startbit) { | ||
621 | off = iter->startbit; | ||
622 | *offset = off; | ||
623 | } else | ||
624 | off -= iter->startbit; | ||
625 | |||
626 | idx = off / NETLBL_CATMAP_MAPSIZE; | ||
627 | *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | /** | ||
633 | * netlbl_catmap_setbit - Set a bit in a LSM secattr catmap | ||
634 | * @catmap: pointer to the category bitmap | ||
526 | * @bit: the bit to set | 635 | * @bit: the bit to set |
527 | * @flags: memory allocation flags | 636 | * @flags: memory allocation flags |
528 | * | 637 | * |
@@ -531,36 +640,27 @@ int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap, | |||
531 | * negative values on failure. | 640 | * negative values on failure. |
532 | * | 641 | * |
533 | */ | 642 | */ |
534 | int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, | 643 | int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, |
535 | u32 bit, | 644 | u32 bit, |
536 | gfp_t flags) | 645 | gfp_t flags) |
537 | { | 646 | { |
538 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 647 | struct netlbl_lsm_catmap *iter; |
539 | u32 node_bit; | 648 | u32 idx; |
540 | u32 node_idx; | ||
541 | 649 | ||
542 | while (iter->next != NULL && | 650 | iter = _netlbl_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags); |
543 | bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) | 651 | if (iter == NULL) |
544 | iter = iter->next; | 652 | return -ENOMEM; |
545 | if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) { | ||
546 | iter->next = netlbl_secattr_catmap_alloc(flags); | ||
547 | if (iter->next == NULL) | ||
548 | return -ENOMEM; | ||
549 | iter = iter->next; | ||
550 | iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1); | ||
551 | } | ||
552 | 653 | ||
553 | /* gcc always rounds to zero when doing integer division */ | 654 | bit -= iter->startbit; |
554 | node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE; | 655 | idx = bit / NETLBL_CATMAP_MAPSIZE; |
555 | node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); | 656 | iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE); |
556 | iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit; | ||
557 | 657 | ||
558 | return 0; | 658 | return 0; |
559 | } | 659 | } |
560 | 660 | ||
561 | /** | 661 | /** |
562 | * netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap | 662 | * netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap |
563 | * @catmap: the category bitmap | 663 | * @catmap: pointer to the category bitmap |
564 | * @start: the starting bit | 664 | * @start: the starting bit |
565 | * @end: the last bit in the string | 665 | * @end: the last bit in the string |
566 | * @flags: memory allocation flags | 666 | * @flags: memory allocation flags |
@@ -570,36 +670,63 @@ int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap, | |||
570 | * on success, negative values on failure. | 670 | * on success, negative values on failure. |
571 | * | 671 | * |
572 | */ | 672 | */ |
573 | int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, | 673 | int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, |
574 | u32 start, | 674 | u32 start, |
575 | u32 end, | 675 | u32 end, |
576 | gfp_t flags) | 676 | gfp_t flags) |
577 | { | 677 | { |
578 | int ret_val = 0; | 678 | int rc = 0; |
579 | struct netlbl_lsm_secattr_catmap *iter = catmap; | 679 | u32 spot = start; |
580 | u32 iter_max_spot; | 680 | |
581 | u32 spot; | 681 | while (rc == 0 && spot <= end) { |
582 | 682 | if (((spot & (BITS_PER_LONG - 1)) != 0) && | |
583 | /* XXX - This could probably be made a bit faster by combining writes | 683 | ((end - spot) > BITS_PER_LONG)) { |
584 | * to the catmap instead of setting a single bit each time, but for | 684 | rc = netlbl_catmap_setlong(catmap, |
585 | * right now skipping to the start of the range in the catmap should | 685 | spot, |
586 | * be a nice improvement over calling the individual setbit function | 686 | (unsigned long)-1, |
587 | * repeatedly from a loop. */ | 687 | flags); |
588 | 688 | spot += BITS_PER_LONG; | |
589 | while (iter->next != NULL && | 689 | } else |
590 | start >= (iter->startbit + NETLBL_CATMAP_SIZE)) | 690 | rc = netlbl_catmap_setbit(catmap, spot++, flags); |
591 | iter = iter->next; | ||
592 | iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; | ||
593 | |||
594 | for (spot = start; spot <= end && ret_val == 0; spot++) { | ||
595 | if (spot >= iter_max_spot && iter->next != NULL) { | ||
596 | iter = iter->next; | ||
597 | iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE; | ||
598 | } | ||
599 | ret_val = netlbl_secattr_catmap_setbit(iter, spot, flags); | ||
600 | } | 691 | } |
601 | 692 | ||
602 | return ret_val; | 693 | return rc; |
694 | } | ||
695 | |||
696 | /** | ||
697 | * netlbl_catmap_setlong - Import an unsigned long bitmap | ||
698 | * @catmap: pointer to the category bitmap | ||
699 | * @offset: offset to the start of the imported bitmap | ||
700 | * @bitmap: the bitmap to import | ||
701 | * @flags: memory allocation flags | ||
702 | * | ||
703 | * Description: | ||
704 | * Import the bitmap specified in @bitmap into @catmap, using the offset | ||
705 | * in @offset. The offset must be aligned to an unsigned long. Returns zero | ||
706 | * on success, negative values on failure. | ||
707 | * | ||
708 | */ | ||
709 | int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, | ||
710 | u32 offset, | ||
711 | unsigned long bitmap, | ||
712 | gfp_t flags) | ||
713 | { | ||
714 | struct netlbl_lsm_catmap *iter; | ||
715 | u32 idx; | ||
716 | |||
717 | /* only allow aligned offsets */ | ||
718 | if ((offset & (BITS_PER_LONG - 1)) != 0) | ||
719 | return -EINVAL; | ||
720 | |||
721 | iter = _netlbl_catmap_getnode(catmap, offset, _CM_F_ALLOC, flags); | ||
722 | if (iter == NULL) | ||
723 | return -ENOMEM; | ||
724 | |||
725 | offset -= iter->startbit; | ||
726 | idx = offset / NETLBL_CATMAP_MAPSIZE; | ||
727 | iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE); | ||
728 | |||
729 | return 0; | ||
603 | } | 730 | } |
604 | 731 | ||
605 | /* | 732 | /* |
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 0ad080790a32..3907add75932 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c | |||
@@ -26,8 +26,10 @@ | |||
26 | #include "ar-internal.h" | 26 | #include "ar-internal.h" |
27 | 27 | ||
28 | static int rxrpc_vet_description_s(const char *); | 28 | static int rxrpc_vet_description_s(const char *); |
29 | static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *); | 29 | static int rxrpc_preparse(struct key_preparsed_payload *); |
30 | static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *); | 30 | static int rxrpc_preparse_s(struct key_preparsed_payload *); |
31 | static void rxrpc_free_preparse(struct key_preparsed_payload *); | ||
32 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *); | ||
31 | static void rxrpc_destroy(struct key *); | 33 | static void rxrpc_destroy(struct key *); |
32 | static void rxrpc_destroy_s(struct key *); | 34 | static void rxrpc_destroy_s(struct key *); |
33 | static void rxrpc_describe(const struct key *, struct seq_file *); | 35 | 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); | |||
39 | */ | 41 | */ |
40 | struct key_type key_type_rxrpc = { | 42 | struct key_type key_type_rxrpc = { |
41 | .name = "rxrpc", | 43 | .name = "rxrpc", |
42 | .instantiate = rxrpc_instantiate, | 44 | .preparse = rxrpc_preparse, |
45 | .free_preparse = rxrpc_free_preparse, | ||
46 | .instantiate = generic_key_instantiate, | ||
43 | .match = user_match, | 47 | .match = user_match, |
44 | .destroy = rxrpc_destroy, | 48 | .destroy = rxrpc_destroy, |
45 | .describe = rxrpc_describe, | 49 | .describe = rxrpc_describe, |
@@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc); | |||
54 | struct key_type key_type_rxrpc_s = { | 58 | struct key_type key_type_rxrpc_s = { |
55 | .name = "rxrpc_s", | 59 | .name = "rxrpc_s", |
56 | .vet_description = rxrpc_vet_description_s, | 60 | .vet_description = rxrpc_vet_description_s, |
57 | .instantiate = rxrpc_instantiate_s, | 61 | .preparse = rxrpc_preparse_s, |
62 | .free_preparse = rxrpc_free_preparse_s, | ||
63 | .instantiate = generic_key_instantiate, | ||
58 | .match = user_match, | 64 | .match = user_match, |
59 | .destroy = rxrpc_destroy_s, | 65 | .destroy = rxrpc_destroy_s, |
60 | .describe = rxrpc_describe, | 66 | .describe = rxrpc_describe, |
@@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc) | |||
81 | * parse an RxKAD type XDR format token | 87 | * parse an RxKAD type XDR format token |
82 | * - the caller guarantees we have at least 4 words | 88 | * - the caller guarantees we have at least 4 words |
83 | */ | 89 | */ |
84 | static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | 90 | static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep, |
85 | unsigned int toklen) | 91 | size_t datalen, |
92 | const __be32 *xdr, unsigned int toklen) | ||
86 | { | 93 | { |
87 | struct rxrpc_key_token *token, **pptoken; | 94 | struct rxrpc_key_token *token, **pptoken; |
88 | size_t plen; | 95 | size_t plen; |
89 | u32 tktlen; | 96 | u32 tktlen; |
90 | int ret; | ||
91 | 97 | ||
92 | _enter(",{%x,%x,%x,%x},%u", | 98 | _enter(",{%x,%x,%x,%x},%u", |
93 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 99 | 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, | |||
103 | return -EKEYREJECTED; | 109 | return -EKEYREJECTED; |
104 | 110 | ||
105 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; | 111 | plen = sizeof(*token) + sizeof(*token->kad) + tktlen; |
106 | ret = key_payload_reserve(key, key->datalen + plen); | 112 | prep->quotalen = datalen + plen; |
107 | if (ret < 0) | ||
108 | return ret; | ||
109 | 113 | ||
110 | plen -= sizeof(*token); | 114 | plen -= sizeof(*token); |
111 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 115 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
@@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, | |||
146 | token->kad->ticket[6], token->kad->ticket[7]); | 150 | token->kad->ticket[6], token->kad->ticket[7]); |
147 | 151 | ||
148 | /* count the number of tokens attached */ | 152 | /* count the number of tokens attached */ |
149 | key->type_data.x[0]++; | 153 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
150 | 154 | ||
151 | /* attach the data */ | 155 | /* attach the data */ |
152 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 156 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
153 | *pptoken; | 157 | *pptoken; |
154 | pptoken = &(*pptoken)->next) | 158 | pptoken = &(*pptoken)->next) |
155 | continue; | 159 | continue; |
156 | *pptoken = token; | 160 | *pptoken = token; |
157 | if (token->kad->expiry < key->expiry) | 161 | if (token->kad->expiry < prep->expiry) |
158 | key->expiry = token->kad->expiry; | 162 | prep->expiry = token->kad->expiry; |
159 | 163 | ||
160 | _leave(" = 0"); | 164 | _leave(" = 0"); |
161 | return 0; | 165 | return 0; |
@@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, | |||
418 | * parse an RxK5 type XDR format token | 422 | * parse an RxK5 type XDR format token |
419 | * - the caller guarantees we have at least 4 words | 423 | * - the caller guarantees we have at least 4 words |
420 | */ | 424 | */ |
421 | static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | 425 | static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep, |
422 | unsigned int toklen) | 426 | size_t datalen, |
427 | const __be32 *xdr, unsigned int toklen) | ||
423 | { | 428 | { |
424 | struct rxrpc_key_token *token, **pptoken; | 429 | struct rxrpc_key_token *token, **pptoken; |
425 | struct rxk5_key *rxk5; | 430 | struct rxk5_key *rxk5; |
@@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
432 | 437 | ||
433 | /* reserve some payload space for this subkey - the length of the token | 438 | /* reserve some payload space for this subkey - the length of the token |
434 | * is a reasonable approximation */ | 439 | * is a reasonable approximation */ |
435 | ret = key_payload_reserve(key, key->datalen + toklen); | 440 | prep->quotalen = datalen + toklen; |
436 | if (ret < 0) | ||
437 | return ret; | ||
438 | 441 | ||
439 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 442 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
440 | if (!token) | 443 | if (!token) |
@@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, | |||
520 | if (toklen != 0) | 523 | if (toklen != 0) |
521 | goto inval; | 524 | goto inval; |
522 | 525 | ||
523 | /* attach the payload to the key */ | 526 | /* attach the payload */ |
524 | for (pptoken = (struct rxrpc_key_token **)&key->payload.data; | 527 | for (pptoken = (struct rxrpc_key_token **)&prep->payload[0]; |
525 | *pptoken; | 528 | *pptoken; |
526 | pptoken = &(*pptoken)->next) | 529 | pptoken = &(*pptoken)->next) |
527 | continue; | 530 | continue; |
528 | *pptoken = token; | 531 | *pptoken = token; |
529 | if (token->kad->expiry < key->expiry) | 532 | if (token->kad->expiry < prep->expiry) |
530 | key->expiry = token->kad->expiry; | 533 | prep->expiry = token->kad->expiry; |
531 | 534 | ||
532 | _leave(" = 0"); | 535 | _leave(" = 0"); |
533 | return 0; | 536 | return 0; |
@@ -545,16 +548,17 @@ error: | |||
545 | * attempt to parse the data as the XDR format | 548 | * attempt to parse the data as the XDR format |
546 | * - the caller guarantees we have more than 7 words | 549 | * - the caller guarantees we have more than 7 words |
547 | */ | 550 | */ |
548 | static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen) | 551 | static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep) |
549 | { | 552 | { |
550 | const __be32 *xdr = data, *token; | 553 | const __be32 *xdr = prep->data, *token; |
551 | const char *cp; | 554 | const char *cp; |
552 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; | 555 | unsigned int len, tmp, loop, ntoken, toklen, sec_ix; |
556 | size_t datalen = prep->datalen; | ||
553 | int ret; | 557 | int ret; |
554 | 558 | ||
555 | _enter(",{%x,%x,%x,%x},%zu", | 559 | _enter(",{%x,%x,%x,%x},%zu", |
556 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), | 560 | ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), |
557 | datalen); | 561 | prep->datalen); |
558 | 562 | ||
559 | if (datalen > AFSTOKEN_LENGTH_MAX) | 563 | if (datalen > AFSTOKEN_LENGTH_MAX) |
560 | goto not_xdr; | 564 | goto not_xdr; |
@@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal | |||
635 | 639 | ||
636 | switch (sec_ix) { | 640 | switch (sec_ix) { |
637 | case RXRPC_SECURITY_RXKAD: | 641 | case RXRPC_SECURITY_RXKAD: |
638 | ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen); | 642 | ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen); |
639 | if (ret != 0) | 643 | if (ret != 0) |
640 | goto error; | 644 | goto error; |
641 | break; | 645 | break; |
642 | 646 | ||
643 | case RXRPC_SECURITY_RXK5: | 647 | case RXRPC_SECURITY_RXK5: |
644 | ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen); | 648 | ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen); |
645 | if (ret != 0) | 649 | if (ret != 0) |
646 | goto error; | 650 | goto error; |
647 | break; | 651 | break; |
@@ -665,8 +669,9 @@ error: | |||
665 | } | 669 | } |
666 | 670 | ||
667 | /* | 671 | /* |
668 | * instantiate an rxrpc defined key | 672 | * Preparse an rxrpc defined key. |
669 | * data should be of the form: | 673 | * |
674 | * Data should be of the form: | ||
670 | * OFFSET LEN CONTENT | 675 | * OFFSET LEN CONTENT |
671 | * 0 4 key interface version number | 676 | * 0 4 key interface version number |
672 | * 4 2 security index (type) | 677 | * 4 2 security index (type) |
@@ -678,7 +683,7 @@ error: | |||
678 | * | 683 | * |
679 | * if no data is provided, then a no-security key is made | 684 | * if no data is provided, then a no-security key is made |
680 | */ | 685 | */ |
681 | static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep) | 686 | static int rxrpc_preparse(struct key_preparsed_payload *prep) |
682 | { | 687 | { |
683 | const struct rxrpc_key_data_v1 *v1; | 688 | const struct rxrpc_key_data_v1 *v1; |
684 | struct rxrpc_key_token *token, **pp; | 689 | struct rxrpc_key_token *token, **pp; |
@@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
686 | u32 kver; | 691 | u32 kver; |
687 | int ret; | 692 | int ret; |
688 | 693 | ||
689 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 694 | _enter("%zu", prep->datalen); |
690 | 695 | ||
691 | /* handle a no-security key */ | 696 | /* handle a no-security key */ |
692 | if (!prep->data && prep->datalen == 0) | 697 | if (!prep->data && prep->datalen == 0) |
@@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
694 | 699 | ||
695 | /* determine if the XDR payload format is being used */ | 700 | /* determine if the XDR payload format is being used */ |
696 | if (prep->datalen > 7 * 4) { | 701 | if (prep->datalen > 7 * 4) { |
697 | ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen); | 702 | ret = rxrpc_preparse_xdr(prep); |
698 | if (ret != -EPROTO) | 703 | if (ret != -EPROTO) |
699 | return ret; | 704 | return ret; |
700 | } | 705 | } |
@@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
743 | goto error; | 748 | goto error; |
744 | 749 | ||
745 | plen = sizeof(*token->kad) + v1->ticket_length; | 750 | plen = sizeof(*token->kad) + v1->ticket_length; |
746 | ret = key_payload_reserve(key, plen + sizeof(*token)); | 751 | prep->quotalen = plen + sizeof(*token); |
747 | if (ret < 0) | ||
748 | goto error; | ||
749 | 752 | ||
750 | ret = -ENOMEM; | 753 | ret = -ENOMEM; |
751 | token = kzalloc(sizeof(*token), GFP_KERNEL); | 754 | token = kzalloc(sizeof(*token), GFP_KERNEL); |
@@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep | |||
762 | memcpy(&token->kad->session_key, &v1->session_key, 8); | 765 | memcpy(&token->kad->session_key, &v1->session_key, 8); |
763 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); | 766 | memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length); |
764 | 767 | ||
765 | /* attach the data */ | 768 | /* count the number of tokens attached */ |
766 | key->type_data.x[0]++; | 769 | prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1); |
767 | 770 | ||
768 | pp = (struct rxrpc_key_token **)&key->payload.data; | 771 | /* attach the data */ |
772 | pp = (struct rxrpc_key_token **)&prep->payload[0]; | ||
769 | while (*pp) | 773 | while (*pp) |
770 | pp = &(*pp)->next; | 774 | pp = &(*pp)->next; |
771 | *pp = token; | 775 | *pp = token; |
772 | if (token->kad->expiry < key->expiry) | 776 | if (token->kad->expiry < prep->expiry) |
773 | key->expiry = token->kad->expiry; | 777 | prep->expiry = token->kad->expiry; |
774 | token = NULL; | 778 | token = NULL; |
775 | ret = 0; | 779 | ret = 0; |
776 | 780 | ||
@@ -781,20 +785,55 @@ error: | |||
781 | } | 785 | } |
782 | 786 | ||
783 | /* | 787 | /* |
784 | * instantiate a server secret key | 788 | * Free token list. |
785 | * data should be a pointer to the 8-byte secret key | ||
786 | */ | 789 | */ |
787 | static int rxrpc_instantiate_s(struct key *key, | 790 | static void rxrpc_free_token_list(struct rxrpc_key_token *token) |
788 | struct key_preparsed_payload *prep) | 791 | { |
792 | struct rxrpc_key_token *next; | ||
793 | |||
794 | for (; token; token = next) { | ||
795 | next = token->next; | ||
796 | switch (token->security_index) { | ||
797 | case RXRPC_SECURITY_RXKAD: | ||
798 | kfree(token->kad); | ||
799 | break; | ||
800 | case RXRPC_SECURITY_RXK5: | ||
801 | if (token->k5) | ||
802 | rxrpc_rxk5_free(token->k5); | ||
803 | break; | ||
804 | default: | ||
805 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
806 | token->security_index); | ||
807 | BUG(); | ||
808 | } | ||
809 | |||
810 | kfree(token); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | /* | ||
815 | * Clean up preparse data. | ||
816 | */ | ||
817 | static void rxrpc_free_preparse(struct key_preparsed_payload *prep) | ||
818 | { | ||
819 | rxrpc_free_token_list(prep->payload[0]); | ||
820 | } | ||
821 | |||
822 | /* | ||
823 | * Preparse a server secret key. | ||
824 | * | ||
825 | * The data should be the 8-byte secret key. | ||
826 | */ | ||
827 | static int rxrpc_preparse_s(struct key_preparsed_payload *prep) | ||
789 | { | 828 | { |
790 | struct crypto_blkcipher *ci; | 829 | struct crypto_blkcipher *ci; |
791 | 830 | ||
792 | _enter("{%x},,%zu", key_serial(key), prep->datalen); | 831 | _enter("%zu", prep->datalen); |
793 | 832 | ||
794 | if (prep->datalen != 8) | 833 | if (prep->datalen != 8) |
795 | return -EINVAL; | 834 | return -EINVAL; |
796 | 835 | ||
797 | memcpy(&key->type_data, prep->data, 8); | 836 | memcpy(&prep->type_data, prep->data, 8); |
798 | 837 | ||
799 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); | 838 | ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC); |
800 | if (IS_ERR(ci)) { | 839 | if (IS_ERR(ci)) { |
@@ -805,36 +844,26 @@ static int rxrpc_instantiate_s(struct key *key, | |||
805 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) | 844 | if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0) |
806 | BUG(); | 845 | BUG(); |
807 | 846 | ||
808 | key->payload.data = ci; | 847 | prep->payload[0] = ci; |
809 | _leave(" = 0"); | 848 | _leave(" = 0"); |
810 | return 0; | 849 | return 0; |
811 | } | 850 | } |
812 | 851 | ||
813 | /* | 852 | /* |
853 | * Clean up preparse data. | ||
854 | */ | ||
855 | static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep) | ||
856 | { | ||
857 | if (prep->payload[0]) | ||
858 | crypto_free_blkcipher(prep->payload[0]); | ||
859 | } | ||
860 | |||
861 | /* | ||
814 | * dispose of the data dangling from the corpse of a rxrpc key | 862 | * dispose of the data dangling from the corpse of a rxrpc key |
815 | */ | 863 | */ |
816 | static void rxrpc_destroy(struct key *key) | 864 | static void rxrpc_destroy(struct key *key) |
817 | { | 865 | { |
818 | struct rxrpc_key_token *token; | 866 | rxrpc_free_token_list(key->payload.data); |
819 | |||
820 | while ((token = key->payload.data)) { | ||
821 | key->payload.data = token->next; | ||
822 | switch (token->security_index) { | ||
823 | case RXRPC_SECURITY_RXKAD: | ||
824 | kfree(token->kad); | ||
825 | break; | ||
826 | case RXRPC_SECURITY_RXK5: | ||
827 | if (token->k5) | ||
828 | rxrpc_rxk5_free(token->k5); | ||
829 | break; | ||
830 | default: | ||
831 | printk(KERN_ERR "Unknown token type %x on rxrpc key\n", | ||
832 | token->security_index); | ||
833 | BUG(); | ||
834 | } | ||
835 | |||
836 | kfree(token); | ||
837 | } | ||
838 | } | 867 | } |
839 | 868 | ||
840 | /* | 869 | /* |
diff --git a/scripts/selinux/genheaders/Makefile b/scripts/selinux/genheaders/Makefile index 417b165008ee..1d1ac51359e3 100644 --- a/scripts/selinux/genheaders/Makefile +++ b/scripts/selinux/genheaders/Makefile | |||
@@ -2,4 +2,3 @@ hostprogs-y := genheaders | |||
2 | HOST_EXTRACFLAGS += -Isecurity/selinux/include | 2 | HOST_EXTRACFLAGS += -Isecurity/selinux/include |
3 | 3 | ||
4 | always := $(hostprogs-y) | 4 | always := $(hostprogs-y) |
5 | clean-files := $(hostprogs-y) | ||
diff --git a/scripts/selinux/mdp/Makefile b/scripts/selinux/mdp/Makefile index eb365b333441..dba7eff69a00 100644 --- a/scripts/selinux/mdp/Makefile +++ b/scripts/selinux/mdp/Makefile | |||
@@ -2,4 +2,4 @@ hostprogs-y := mdp | |||
2 | HOST_EXTRACFLAGS += -Isecurity/selinux/include | 2 | HOST_EXTRACFLAGS += -Isecurity/selinux/include |
3 | 3 | ||
4 | always := $(hostprogs-y) | 4 | always := $(hostprogs-y) |
5 | clean-files := $(hostprogs-y) policy.* file_contexts | 5 | clean-files := policy.* file_contexts |
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 452567d3a08e..d97cba3e3849 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) | |||
621 | * There is no exception for unconfined as change_hat is not | 621 | * There is no exception for unconfined as change_hat is not |
622 | * available. | 622 | * available. |
623 | */ | 623 | */ |
624 | if (current->no_new_privs) | 624 | if (task_no_new_privs(current)) |
625 | return -EPERM; | 625 | return -EPERM; |
626 | 626 | ||
627 | /* released below */ | 627 | /* released below */ |
@@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, | |||
776 | * no_new_privs is set because this aways results in a reduction | 776 | * no_new_privs is set because this aways results in a reduction |
777 | * of permissions. | 777 | * of permissions. |
778 | */ | 778 | */ |
779 | if (current->no_new_privs && !unconfined(profile)) { | 779 | if (task_no_new_privs(current) && !unconfined(profile)) { |
780 | put_cred(cred); | 780 | put_cred(cred); |
781 | return -EPERM; | 781 | return -EPERM; |
782 | } | 782 | } |
diff --git a/security/capability.c b/security/capability.c index e76373de3129..a74fde6a7468 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -401,6 +401,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
401 | return 0; | 401 | return 0; |
402 | } | 402 | } |
403 | 403 | ||
404 | static int cap_kernel_fw_from_file(struct file *file, char *buf, size_t size) | ||
405 | { | ||
406 | return 0; | ||
407 | } | ||
408 | |||
404 | static int cap_kernel_module_request(char *kmod_name) | 409 | static int cap_kernel_module_request(char *kmod_name) |
405 | { | 410 | { |
406 | return 0; | 411 | return 0; |
@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
1015 | set_to_cap_if_null(ops, cred_transfer); | 1020 | set_to_cap_if_null(ops, cred_transfer); |
1016 | set_to_cap_if_null(ops, kernel_act_as); | 1021 | set_to_cap_if_null(ops, kernel_act_as); |
1017 | set_to_cap_if_null(ops, kernel_create_files_as); | 1022 | set_to_cap_if_null(ops, kernel_create_files_as); |
1023 | set_to_cap_if_null(ops, kernel_fw_from_file); | ||
1018 | set_to_cap_if_null(ops, kernel_module_request); | 1024 | set_to_cap_if_null(ops, kernel_module_request); |
1019 | set_to_cap_if_null(ops, kernel_module_from_file); | 1025 | set_to_cap_if_null(ops, kernel_module_from_file); |
1020 | set_to_cap_if_null(ops, task_fix_setuid); | 1026 | set_to_cap_if_null(ops, task_fix_setuid); |
diff --git a/security/commoncap.c b/security/commoncap.c index b9d613e0ef14..bab0611afc1e 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -421,6 +421,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data | |||
421 | cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); | 421 | cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); |
422 | } | 422 | } |
423 | 423 | ||
424 | cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
425 | cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
426 | |||
424 | return 0; | 427 | return 0; |
425 | } | 428 | } |
426 | 429 | ||
@@ -822,15 +825,20 @@ int cap_task_setnice(struct task_struct *p, int nice) | |||
822 | * Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from | 825 | * Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from |
823 | * the current task's bounding set. Returns 0 on success, -ve on error. | 826 | * the current task's bounding set. Returns 0 on success, -ve on error. |
824 | */ | 827 | */ |
825 | static long cap_prctl_drop(struct cred *new, unsigned long cap) | 828 | static int cap_prctl_drop(unsigned long cap) |
826 | { | 829 | { |
830 | struct cred *new; | ||
831 | |||
827 | if (!ns_capable(current_user_ns(), CAP_SETPCAP)) | 832 | if (!ns_capable(current_user_ns(), CAP_SETPCAP)) |
828 | return -EPERM; | 833 | return -EPERM; |
829 | if (!cap_valid(cap)) | 834 | if (!cap_valid(cap)) |
830 | return -EINVAL; | 835 | return -EINVAL; |
831 | 836 | ||
837 | new = prepare_creds(); | ||
838 | if (!new) | ||
839 | return -ENOMEM; | ||
832 | cap_lower(new->cap_bset, cap); | 840 | cap_lower(new->cap_bset, cap); |
833 | return 0; | 841 | return commit_creds(new); |
834 | } | 842 | } |
835 | 843 | ||
836 | /** | 844 | /** |
@@ -848,26 +856,17 @@ static long cap_prctl_drop(struct cred *new, unsigned long cap) | |||
848 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 856 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
849 | unsigned long arg4, unsigned long arg5) | 857 | unsigned long arg4, unsigned long arg5) |
850 | { | 858 | { |
859 | const struct cred *old = current_cred(); | ||
851 | struct cred *new; | 860 | struct cred *new; |
852 | long error = 0; | ||
853 | |||
854 | new = prepare_creds(); | ||
855 | if (!new) | ||
856 | return -ENOMEM; | ||
857 | 861 | ||
858 | switch (option) { | 862 | switch (option) { |
859 | case PR_CAPBSET_READ: | 863 | case PR_CAPBSET_READ: |
860 | error = -EINVAL; | ||
861 | if (!cap_valid(arg2)) | 864 | if (!cap_valid(arg2)) |
862 | goto error; | 865 | return -EINVAL; |
863 | error = !!cap_raised(new->cap_bset, arg2); | 866 | return !!cap_raised(old->cap_bset, arg2); |
864 | goto no_change; | ||
865 | 867 | ||
866 | case PR_CAPBSET_DROP: | 868 | case PR_CAPBSET_DROP: |
867 | error = cap_prctl_drop(new, arg2); | 869 | return cap_prctl_drop(arg2); |
868 | if (error < 0) | ||
869 | goto error; | ||
870 | goto changed; | ||
871 | 870 | ||
872 | /* | 871 | /* |
873 | * The next four prctl's remain to assist with transitioning a | 872 | * 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, | |||
889 | * capability-based-privilege environment. | 888 | * capability-based-privilege environment. |
890 | */ | 889 | */ |
891 | case PR_SET_SECUREBITS: | 890 | case PR_SET_SECUREBITS: |
892 | error = -EPERM; | 891 | if ((((old->securebits & SECURE_ALL_LOCKS) >> 1) |
893 | if ((((new->securebits & SECURE_ALL_LOCKS) >> 1) | 892 | & (old->securebits ^ arg2)) /*[1]*/ |
894 | & (new->securebits ^ arg2)) /*[1]*/ | 893 | || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
895 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | ||
896 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 894 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
897 | || (cap_capable(current_cred(), | 895 | || (cap_capable(current_cred(), |
898 | current_cred()->user_ns, CAP_SETPCAP, | 896 | current_cred()->user_ns, CAP_SETPCAP, |
@@ -906,46 +904,39 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
906 | */ | 904 | */ |
907 | ) | 905 | ) |
908 | /* cannot change a locked bit */ | 906 | /* cannot change a locked bit */ |
909 | goto error; | 907 | return -EPERM; |
908 | |||
909 | new = prepare_creds(); | ||
910 | if (!new) | ||
911 | return -ENOMEM; | ||
910 | new->securebits = arg2; | 912 | new->securebits = arg2; |
911 | goto changed; | 913 | return commit_creds(new); |
912 | 914 | ||
913 | case PR_GET_SECUREBITS: | 915 | case PR_GET_SECUREBITS: |
914 | error = new->securebits; | 916 | return old->securebits; |
915 | goto no_change; | ||
916 | 917 | ||
917 | case PR_GET_KEEPCAPS: | 918 | case PR_GET_KEEPCAPS: |
918 | if (issecure(SECURE_KEEP_CAPS)) | 919 | return !!issecure(SECURE_KEEP_CAPS); |
919 | error = 1; | ||
920 | goto no_change; | ||
921 | 920 | ||
922 | case PR_SET_KEEPCAPS: | 921 | case PR_SET_KEEPCAPS: |
923 | error = -EINVAL; | ||
924 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ | 922 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ |
925 | goto error; | 923 | return -EINVAL; |
926 | error = -EPERM; | ||
927 | if (issecure(SECURE_KEEP_CAPS_LOCKED)) | 924 | if (issecure(SECURE_KEEP_CAPS_LOCKED)) |
928 | goto error; | 925 | return -EPERM; |
926 | |||
927 | new = prepare_creds(); | ||
928 | if (!new) | ||
929 | return -ENOMEM; | ||
929 | if (arg2) | 930 | if (arg2) |
930 | new->securebits |= issecure_mask(SECURE_KEEP_CAPS); | 931 | new->securebits |= issecure_mask(SECURE_KEEP_CAPS); |
931 | else | 932 | else |
932 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); | 933 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
933 | goto changed; | 934 | return commit_creds(new); |
934 | 935 | ||
935 | default: | 936 | default: |
936 | /* No functionality available - continue with default */ | 937 | /* No functionality available - continue with default */ |
937 | error = -ENOSYS; | 938 | return -ENOSYS; |
938 | goto error; | ||
939 | } | 939 | } |
940 | |||
941 | /* Functionality provided */ | ||
942 | changed: | ||
943 | return commit_creds(new); | ||
944 | |||
945 | no_change: | ||
946 | error: | ||
947 | abort_creds(new); | ||
948 | return error; | ||
949 | } | 940 | } |
950 | 941 | ||
951 | /** | 942 | /** |
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index b4af4ebc5be2..8d4fbff8b87c 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
@@ -13,7 +13,9 @@ | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
14 | 14 | ||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/sched.h> | ||
16 | #include <linux/rbtree.h> | 17 | #include <linux/rbtree.h> |
18 | #include <linux/cred.h> | ||
17 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
18 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
19 | 21 | ||
@@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; | |||
24 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { | 26 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { |
25 | "_evm", | 27 | "_evm", |
26 | "_module", | 28 | "_module", |
29 | #ifndef CONFIG_IMA_TRUSTED_KEYRING | ||
27 | "_ima", | 30 | "_ima", |
31 | #else | ||
32 | ".ima", | ||
33 | #endif | ||
28 | }; | 34 | }; |
29 | 35 | ||
30 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 36 | 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, | |||
56 | 62 | ||
57 | return -EOPNOTSUPP; | 63 | return -EOPNOTSUPP; |
58 | } | 64 | } |
65 | |||
66 | int integrity_init_keyring(const unsigned int id) | ||
67 | { | ||
68 | const struct cred *cred = current_cred(); | ||
69 | int err = 0; | ||
70 | |||
71 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), | ||
72 | KGIDT_INIT(0), cred, | ||
73 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
74 | KEY_USR_VIEW | KEY_USR_READ | | ||
75 | KEY_USR_WRITE | KEY_USR_SEARCH), | ||
76 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | ||
77 | if (!IS_ERR(keyring[id])) | ||
78 | set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); | ||
79 | else { | ||
80 | err = PTR_ERR(keyring[id]); | ||
81 | pr_info("Can't allocate %s keyring (%d)\n", | ||
82 | keyring_name[id], err); | ||
83 | keyring[id] = NULL; | ||
84 | } | ||
85 | return err; | ||
86 | } | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 81a27971d884..08758fbd496f 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -123,3 +123,13 @@ config IMA_APPRAISE | |||
123 | For more information on integrity appraisal refer to: | 123 | For more information on integrity appraisal refer to: |
124 | <http://linux-ima.sourceforge.net> | 124 | <http://linux-ima.sourceforge.net> |
125 | If unsure, say N. | 125 | If unsure, say N. |
126 | |||
127 | config IMA_TRUSTED_KEYRING | ||
128 | bool "Require all keys on the .ima keyring be signed" | ||
129 | depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING | ||
130 | depends on INTEGRITY_ASYMMETRIC_KEYS | ||
131 | select KEYS_DEBUG_PROC_KEYS | ||
132 | default y | ||
133 | help | ||
134 | This option requires that all keys added to the .ima | ||
135 | keyring be signed by a key on the system trusted keyring. | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index f79fa8be203c..57da4bd7ba0c 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -158,7 +158,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); | |||
158 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 158 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
159 | 159 | ||
160 | /* IMA policy related functions */ | 160 | /* IMA policy related functions */ |
161 | enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR }; | 161 | enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR }; |
162 | 162 | ||
163 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | 163 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
164 | int flags); | 164 | int flags); |
@@ -171,6 +171,7 @@ void ima_delete_rules(void); | |||
171 | #define IMA_APPRAISE_ENFORCE 0x01 | 171 | #define IMA_APPRAISE_ENFORCE 0x01 |
172 | #define IMA_APPRAISE_FIX 0x02 | 172 | #define IMA_APPRAISE_FIX 0x02 |
173 | #define IMA_APPRAISE_MODULES 0x04 | 173 | #define IMA_APPRAISE_MODULES 0x04 |
174 | #define IMA_APPRAISE_FIRMWARE 0x08 | ||
174 | 175 | ||
175 | #ifdef CONFIG_IMA_APPRAISE | 176 | #ifdef CONFIG_IMA_APPRAISE |
176 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 177 | 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, | |||
249 | return -EINVAL; | 250 | return -EINVAL; |
250 | } | 251 | } |
251 | #endif /* CONFIG_IMA_LSM_RULES */ | 252 | #endif /* CONFIG_IMA_LSM_RULES */ |
253 | |||
254 | #ifdef CONFIG_IMA_TRUSTED_KEYRING | ||
255 | static inline int ima_init_keyring(const unsigned int id) | ||
256 | { | ||
257 | return integrity_init_keyring(id); | ||
258 | } | ||
259 | #else | ||
260 | static inline int ima_init_keyring(const unsigned int id) | ||
261 | { | ||
262 | return 0; | ||
263 | } | ||
264 | #endif /* CONFIG_IMA_TRUSTED_KEYRING */ | ||
252 | #endif | 265 | #endif |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index d3113d4aaa3c..86bfd5c5df85 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -75,6 +75,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | |||
75 | return iint->ima_bprm_status; | 75 | return iint->ima_bprm_status; |
76 | case MODULE_CHECK: | 76 | case MODULE_CHECK: |
77 | return iint->ima_module_status; | 77 | return iint->ima_module_status; |
78 | case FIRMWARE_CHECK: | ||
79 | return iint->ima_firmware_status; | ||
78 | case FILE_CHECK: | 80 | case FILE_CHECK: |
79 | default: | 81 | default: |
80 | return iint->ima_file_status; | 82 | return iint->ima_file_status; |
@@ -94,6 +96,9 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, | |||
94 | case MODULE_CHECK: | 96 | case MODULE_CHECK: |
95 | iint->ima_module_status = status; | 97 | iint->ima_module_status = status; |
96 | break; | 98 | break; |
99 | case FIRMWARE_CHECK: | ||
100 | iint->ima_firmware_status = status; | ||
101 | break; | ||
97 | case FILE_CHECK: | 102 | case FILE_CHECK: |
98 | default: | 103 | default: |
99 | iint->ima_file_status = status; | 104 | iint->ima_file_status = status; |
@@ -113,6 +118,9 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
113 | case MODULE_CHECK: | 118 | case MODULE_CHECK: |
114 | iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); | 119 | iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); |
115 | break; | 120 | break; |
121 | case FIRMWARE_CHECK: | ||
122 | iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED); | ||
123 | break; | ||
116 | case FILE_CHECK: | 124 | case FILE_CHECK: |
117 | default: | 125 | default: |
118 | iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); | 126 | iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); |
@@ -214,7 +222,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
214 | hash_start = 1; | 222 | hash_start = 1; |
215 | case IMA_XATTR_DIGEST: | 223 | case IMA_XATTR_DIGEST: |
216 | if (iint->flags & IMA_DIGSIG_REQUIRED) { | 224 | if (iint->flags & IMA_DIGSIG_REQUIRED) { |
217 | cause = "IMA signature required"; | 225 | cause = "IMA-signature-required"; |
218 | status = INTEGRITY_FAIL; | 226 | status = INTEGRITY_FAIL; |
219 | break; | 227 | break; |
220 | } | 228 | } |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index ccd0ac8fa9a0..0bd732843fe7 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/ratelimit.h> | ||
19 | #include <linux/file.h> | 21 | #include <linux/file.h> |
20 | #include <linux/crypto.h> | 22 | #include <linux/crypto.h> |
21 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
@@ -25,7 +27,45 @@ | |||
25 | #include <crypto/hash_info.h> | 27 | #include <crypto/hash_info.h> |
26 | #include "ima.h" | 28 | #include "ima.h" |
27 | 29 | ||
30 | struct ahash_completion { | ||
31 | struct completion completion; | ||
32 | int err; | ||
33 | }; | ||
34 | |||
35 | /* minimum file size for ahash use */ | ||
36 | static unsigned long ima_ahash_minsize; | ||
37 | module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); | ||
38 | MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use"); | ||
39 | |||
40 | /* default is 0 - 1 page. */ | ||
41 | static int ima_maxorder; | ||
42 | static unsigned int ima_bufsize = PAGE_SIZE; | ||
43 | |||
44 | static int param_set_bufsize(const char *val, const struct kernel_param *kp) | ||
45 | { | ||
46 | unsigned long long size; | ||
47 | int order; | ||
48 | |||
49 | size = memparse(val, NULL); | ||
50 | order = get_order(size); | ||
51 | if (order >= MAX_ORDER) | ||
52 | return -EINVAL; | ||
53 | ima_maxorder = order; | ||
54 | ima_bufsize = PAGE_SIZE << order; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static struct kernel_param_ops param_ops_bufsize = { | ||
59 | .set = param_set_bufsize, | ||
60 | .get = param_get_uint, | ||
61 | }; | ||
62 | #define param_check_bufsize(name, p) __param_check(name, p, unsigned int) | ||
63 | |||
64 | module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644); | ||
65 | MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size"); | ||
66 | |||
28 | static struct crypto_shash *ima_shash_tfm; | 67 | static struct crypto_shash *ima_shash_tfm; |
68 | static struct crypto_ahash *ima_ahash_tfm; | ||
29 | 69 | ||
30 | /** | 70 | /** |
31 | * ima_kernel_read - read file content | 71 | * ima_kernel_read - read file content |
@@ -93,9 +133,246 @@ static void ima_free_tfm(struct crypto_shash *tfm) | |||
93 | crypto_free_shash(tfm); | 133 | crypto_free_shash(tfm); |
94 | } | 134 | } |
95 | 135 | ||
96 | /* | 136 | /** |
97 | * Calculate the MD5/SHA1 file digest | 137 | * ima_alloc_pages() - Allocate contiguous pages. |
138 | * @max_size: Maximum amount of memory to allocate. | ||
139 | * @allocated_size: Returned size of actual allocation. | ||
140 | * @last_warn: Should the min_size allocation warn or not. | ||
141 | * | ||
142 | * Tries to do opportunistic allocation for memory first trying to allocate | ||
143 | * max_size amount of memory and then splitting that until zero order is | ||
144 | * reached. Allocation is tried without generating allocation warnings unless | ||
145 | * last_warn is set. Last_warn set affects only last allocation of zero order. | ||
146 | * | ||
147 | * By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL) | ||
148 | * | ||
149 | * Return pointer to allocated memory, or NULL on failure. | ||
150 | */ | ||
151 | static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size, | ||
152 | int last_warn) | ||
153 | { | ||
154 | void *ptr; | ||
155 | int order = ima_maxorder; | ||
156 | gfp_t gfp_mask = __GFP_WAIT | __GFP_NOWARN | __GFP_NORETRY; | ||
157 | |||
158 | if (order) | ||
159 | order = min(get_order(max_size), order); | ||
160 | |||
161 | for (; order; order--) { | ||
162 | ptr = (void *)__get_free_pages(gfp_mask, order); | ||
163 | if (ptr) { | ||
164 | *allocated_size = PAGE_SIZE << order; | ||
165 | return ptr; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | /* order is zero - one page */ | ||
170 | |||
171 | gfp_mask = GFP_KERNEL; | ||
172 | |||
173 | if (!last_warn) | ||
174 | gfp_mask |= __GFP_NOWARN; | ||
175 | |||
176 | ptr = (void *)__get_free_pages(gfp_mask, 0); | ||
177 | if (ptr) { | ||
178 | *allocated_size = PAGE_SIZE; | ||
179 | return ptr; | ||
180 | } | ||
181 | |||
182 | *allocated_size = 0; | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * ima_free_pages() - Free pages allocated by ima_alloc_pages(). | ||
188 | * @ptr: Pointer to allocated pages. | ||
189 | * @size: Size of allocated buffer. | ||
98 | */ | 190 | */ |
191 | static void ima_free_pages(void *ptr, size_t size) | ||
192 | { | ||
193 | if (!ptr) | ||
194 | return; | ||
195 | free_pages((unsigned long)ptr, get_order(size)); | ||
196 | } | ||
197 | |||
198 | static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo) | ||
199 | { | ||
200 | struct crypto_ahash *tfm = ima_ahash_tfm; | ||
201 | int rc; | ||
202 | |||
203 | if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) { | ||
204 | tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0); | ||
205 | if (!IS_ERR(tfm)) { | ||
206 | if (algo == ima_hash_algo) | ||
207 | ima_ahash_tfm = tfm; | ||
208 | } else { | ||
209 | rc = PTR_ERR(tfm); | ||
210 | pr_err("Can not allocate %s (reason: %d)\n", | ||
211 | hash_algo_name[algo], rc); | ||
212 | } | ||
213 | } | ||
214 | return tfm; | ||
215 | } | ||
216 | |||
217 | static void ima_free_atfm(struct crypto_ahash *tfm) | ||
218 | { | ||
219 | if (tfm != ima_ahash_tfm) | ||
220 | crypto_free_ahash(tfm); | ||
221 | } | ||
222 | |||
223 | static void ahash_complete(struct crypto_async_request *req, int err) | ||
224 | { | ||
225 | struct ahash_completion *res = req->data; | ||
226 | |||
227 | if (err == -EINPROGRESS) | ||
228 | return; | ||
229 | res->err = err; | ||
230 | complete(&res->completion); | ||
231 | } | ||
232 | |||
233 | static int ahash_wait(int err, struct ahash_completion *res) | ||
234 | { | ||
235 | switch (err) { | ||
236 | case 0: | ||
237 | break; | ||
238 | case -EINPROGRESS: | ||
239 | case -EBUSY: | ||
240 | wait_for_completion(&res->completion); | ||
241 | reinit_completion(&res->completion); | ||
242 | err = res->err; | ||
243 | /* fall through */ | ||
244 | default: | ||
245 | pr_crit_ratelimited("ahash calculation failed: err: %d\n", err); | ||
246 | } | ||
247 | |||
248 | return err; | ||
249 | } | ||
250 | |||
251 | static int ima_calc_file_hash_atfm(struct file *file, | ||
252 | struct ima_digest_data *hash, | ||
253 | struct crypto_ahash *tfm) | ||
254 | { | ||
255 | loff_t i_size, offset; | ||
256 | char *rbuf[2] = { NULL, }; | ||
257 | int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0; | ||
258 | struct ahash_request *req; | ||
259 | struct scatterlist sg[1]; | ||
260 | struct ahash_completion res; | ||
261 | size_t rbuf_size[2]; | ||
262 | |||
263 | hash->length = crypto_ahash_digestsize(tfm); | ||
264 | |||
265 | req = ahash_request_alloc(tfm, GFP_KERNEL); | ||
266 | if (!req) | ||
267 | return -ENOMEM; | ||
268 | |||
269 | init_completion(&res.completion); | ||
270 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | ||
271 | CRYPTO_TFM_REQ_MAY_SLEEP, | ||
272 | ahash_complete, &res); | ||
273 | |||
274 | rc = ahash_wait(crypto_ahash_init(req), &res); | ||
275 | if (rc) | ||
276 | goto out1; | ||
277 | |||
278 | i_size = i_size_read(file_inode(file)); | ||
279 | |||
280 | if (i_size == 0) | ||
281 | goto out2; | ||
282 | |||
283 | /* | ||
284 | * Try to allocate maximum size of memory. | ||
285 | * Fail if even a single page cannot be allocated. | ||
286 | */ | ||
287 | rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1); | ||
288 | if (!rbuf[0]) { | ||
289 | rc = -ENOMEM; | ||
290 | goto out1; | ||
291 | } | ||
292 | |||
293 | /* Only allocate one buffer if that is enough. */ | ||
294 | if (i_size > rbuf_size[0]) { | ||
295 | /* | ||
296 | * Try to allocate secondary buffer. If that fails fallback to | ||
297 | * using single buffering. Use previous memory allocation size | ||
298 | * as baseline for possible allocation size. | ||
299 | */ | ||
300 | rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0], | ||
301 | &rbuf_size[1], 0); | ||
302 | } | ||
303 | |||
304 | if (!(file->f_mode & FMODE_READ)) { | ||
305 | file->f_mode |= FMODE_READ; | ||
306 | read = 1; | ||
307 | } | ||
308 | |||
309 | for (offset = 0; offset < i_size; offset += rbuf_len) { | ||
310 | if (!rbuf[1] && offset) { | ||
311 | /* Not using two buffers, and it is not the first | ||
312 | * read/request, wait for the completion of the | ||
313 | * previous ahash_update() request. | ||
314 | */ | ||
315 | rc = ahash_wait(ahash_rc, &res); | ||
316 | if (rc) | ||
317 | goto out3; | ||
318 | } | ||
319 | /* read buffer */ | ||
320 | rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); | ||
321 | rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len); | ||
322 | if (rc != rbuf_len) | ||
323 | goto out3; | ||
324 | |||
325 | if (rbuf[1] && offset) { | ||
326 | /* Using two buffers, and it is not the first | ||
327 | * read/request, wait for the completion of the | ||
328 | * previous ahash_update() request. | ||
329 | */ | ||
330 | rc = ahash_wait(ahash_rc, &res); | ||
331 | if (rc) | ||
332 | goto out3; | ||
333 | } | ||
334 | |||
335 | sg_init_one(&sg[0], rbuf[active], rbuf_len); | ||
336 | ahash_request_set_crypt(req, sg, NULL, rbuf_len); | ||
337 | |||
338 | ahash_rc = crypto_ahash_update(req); | ||
339 | |||
340 | if (rbuf[1]) | ||
341 | active = !active; /* swap buffers, if we use two */ | ||
342 | } | ||
343 | /* wait for the last update request to complete */ | ||
344 | rc = ahash_wait(ahash_rc, &res); | ||
345 | out3: | ||
346 | if (read) | ||
347 | file->f_mode &= ~FMODE_READ; | ||
348 | ima_free_pages(rbuf[0], rbuf_size[0]); | ||
349 | ima_free_pages(rbuf[1], rbuf_size[1]); | ||
350 | out2: | ||
351 | if (!rc) { | ||
352 | ahash_request_set_crypt(req, NULL, hash->digest, 0); | ||
353 | rc = ahash_wait(crypto_ahash_final(req), &res); | ||
354 | } | ||
355 | out1: | ||
356 | ahash_request_free(req); | ||
357 | return rc; | ||
358 | } | ||
359 | |||
360 | static int ima_calc_file_ahash(struct file *file, struct ima_digest_data *hash) | ||
361 | { | ||
362 | struct crypto_ahash *tfm; | ||
363 | int rc; | ||
364 | |||
365 | tfm = ima_alloc_atfm(hash->algo); | ||
366 | if (IS_ERR(tfm)) | ||
367 | return PTR_ERR(tfm); | ||
368 | |||
369 | rc = ima_calc_file_hash_atfm(file, hash, tfm); | ||
370 | |||
371 | ima_free_atfm(tfm); | ||
372 | |||
373 | return rc; | ||
374 | } | ||
375 | |||
99 | static int ima_calc_file_hash_tfm(struct file *file, | 376 | static int ima_calc_file_hash_tfm(struct file *file, |
100 | struct ima_digest_data *hash, | 377 | struct ima_digest_data *hash, |
101 | struct crypto_shash *tfm) | 378 | struct crypto_shash *tfm) |
@@ -156,7 +433,7 @@ out: | |||
156 | return rc; | 433 | return rc; |
157 | } | 434 | } |
158 | 435 | ||
159 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | 436 | static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash) |
160 | { | 437 | { |
161 | struct crypto_shash *tfm; | 438 | struct crypto_shash *tfm; |
162 | int rc; | 439 | int rc; |
@@ -173,6 +450,35 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | |||
173 | } | 450 | } |
174 | 451 | ||
175 | /* | 452 | /* |
453 | * ima_calc_file_hash - calculate file hash | ||
454 | * | ||
455 | * Asynchronous hash (ahash) allows using HW acceleration for calculating | ||
456 | * a hash. ahash performance varies for different data sizes on different | ||
457 | * crypto accelerators. shash performance might be better for smaller files. | ||
458 | * The 'ima.ahash_minsize' module parameter allows specifying the best | ||
459 | * minimum file size for using ahash on the system. | ||
460 | * | ||
461 | * If the ima.ahash_minsize parameter is not specified, this function uses | ||
462 | * shash for the hash calculation. If ahash fails, it falls back to using | ||
463 | * shash. | ||
464 | */ | ||
465 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | ||
466 | { | ||
467 | loff_t i_size; | ||
468 | int rc; | ||
469 | |||
470 | i_size = i_size_read(file_inode(file)); | ||
471 | |||
472 | if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { | ||
473 | rc = ima_calc_file_ahash(file, hash); | ||
474 | if (!rc) | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | return ima_calc_file_shash(file, hash); | ||
479 | } | ||
480 | |||
481 | /* | ||
176 | * Calculate the hash of template data | 482 | * Calculate the hash of template data |
177 | */ | 483 | */ |
178 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | 484 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 09baa335ebc7..2917f980bf30 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -88,8 +88,6 @@ static void ima_rdwr_violation_check(struct file *file) | |||
88 | if (!S_ISREG(inode->i_mode) || !ima_initialized) | 88 | if (!S_ISREG(inode->i_mode) || !ima_initialized) |
89 | return; | 89 | return; |
90 | 90 | ||
91 | mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ | ||
92 | |||
93 | if (mode & FMODE_WRITE) { | 91 | if (mode & FMODE_WRITE) { |
94 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { | 92 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { |
95 | struct integrity_iint_cache *iint; | 93 | struct integrity_iint_cache *iint; |
@@ -104,8 +102,6 @@ static void ima_rdwr_violation_check(struct file *file) | |||
104 | send_writers = true; | 102 | send_writers = true; |
105 | } | 103 | } |
106 | 104 | ||
107 | mutex_unlock(&inode->i_mutex); | ||
108 | |||
109 | if (!send_tomtou && !send_writers) | 105 | if (!send_tomtou && !send_writers) |
110 | return; | 106 | return; |
111 | 107 | ||
@@ -163,7 +159,7 @@ static int process_measurement(struct file *file, const char *filename, | |||
163 | { | 159 | { |
164 | struct inode *inode = file_inode(file); | 160 | struct inode *inode = file_inode(file); |
165 | struct integrity_iint_cache *iint; | 161 | struct integrity_iint_cache *iint; |
166 | struct ima_template_desc *template_desc = ima_template_desc_current(); | 162 | struct ima_template_desc *template_desc; |
167 | char *pathbuf = NULL; | 163 | char *pathbuf = NULL; |
168 | const char *pathname = NULL; | 164 | const char *pathname = NULL; |
169 | int rc = -ENOMEM, action, must_appraise, _func; | 165 | int rc = -ENOMEM, action, must_appraise, _func; |
@@ -207,6 +203,7 @@ static int process_measurement(struct file *file, const char *filename, | |||
207 | goto out_digsig; | 203 | goto out_digsig; |
208 | } | 204 | } |
209 | 205 | ||
206 | template_desc = ima_template_desc_current(); | ||
210 | if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) { | 207 | if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) { |
211 | if (action & IMA_APPRAISE_SUBMASK) | 208 | if (action & IMA_APPRAISE_SUBMASK) |
212 | xattr_ptr = &xattr_value; | 209 | xattr_ptr = &xattr_value; |
@@ -322,14 +319,31 @@ int ima_module_check(struct file *file) | |||
322 | return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK); | 319 | return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK); |
323 | } | 320 | } |
324 | 321 | ||
322 | int ima_fw_from_file(struct file *file, char *buf, size_t size) | ||
323 | { | ||
324 | if (!file) { | ||
325 | if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && | ||
326 | (ima_appraise & IMA_APPRAISE_ENFORCE)) | ||
327 | return -EACCES; /* INTEGRITY_UNKNOWN */ | ||
328 | return 0; | ||
329 | } | ||
330 | return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK); | ||
331 | } | ||
332 | |||
325 | static int __init init_ima(void) | 333 | static int __init init_ima(void) |
326 | { | 334 | { |
327 | int error; | 335 | int error; |
328 | 336 | ||
329 | hash_setup(CONFIG_IMA_DEFAULT_HASH); | 337 | hash_setup(CONFIG_IMA_DEFAULT_HASH); |
330 | error = ima_init(); | 338 | error = ima_init(); |
331 | if (!error) | 339 | if (error) |
332 | ima_initialized = 1; | 340 | goto out; |
341 | |||
342 | error = ima_init_keyring(INTEGRITY_KEYRING_IMA); | ||
343 | if (error) | ||
344 | goto out; | ||
345 | ima_initialized = 1; | ||
346 | out: | ||
333 | return error; | 347 | return error; |
334 | } | 348 | } |
335 | 349 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 40a7488f6721..07099a8bc283 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -84,6 +84,7 @@ static struct ima_rule_entry default_rules[] = { | |||
84 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, | 84 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, |
85 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 85 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
86 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, | 86 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
87 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, | ||
87 | }; | 88 | }; |
88 | 89 | ||
89 | static struct ima_rule_entry default_appraise_rules[] = { | 90 | static struct ima_rule_entry default_appraise_rules[] = { |
@@ -241,6 +242,8 @@ static int get_subaction(struct ima_rule_entry *rule, int func) | |||
241 | return IMA_BPRM_APPRAISE; | 242 | return IMA_BPRM_APPRAISE; |
242 | case MODULE_CHECK: | 243 | case MODULE_CHECK: |
243 | return IMA_MODULE_APPRAISE; | 244 | return IMA_MODULE_APPRAISE; |
245 | case FIRMWARE_CHECK: | ||
246 | return IMA_FIRMWARE_APPRAISE; | ||
244 | case FILE_CHECK: | 247 | case FILE_CHECK: |
245 | default: | 248 | default: |
246 | return IMA_FILE_APPRAISE; | 249 | return IMA_FILE_APPRAISE; |
@@ -332,7 +335,7 @@ void __init ima_init_policy(void) | |||
332 | void ima_update_policy(void) | 335 | void ima_update_policy(void) |
333 | { | 336 | { |
334 | static const char op[] = "policy_update"; | 337 | static const char op[] = "policy_update"; |
335 | const char *cause = "already exists"; | 338 | const char *cause = "already-exists"; |
336 | int result = 1; | 339 | int result = 1; |
337 | int audit_info = 0; | 340 | int audit_info = 0; |
338 | 341 | ||
@@ -486,6 +489,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
486 | entry->func = FILE_CHECK; | 489 | entry->func = FILE_CHECK; |
487 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) | 490 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) |
488 | entry->func = MODULE_CHECK; | 491 | entry->func = MODULE_CHECK; |
492 | else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) | ||
493 | entry->func = FIRMWARE_CHECK; | ||
489 | else if ((strcmp(args[0].from, "FILE_MMAP") == 0) | 494 | else if ((strcmp(args[0].from, "FILE_MMAP") == 0) |
490 | || (strcmp(args[0].from, "MMAP_CHECK") == 0)) | 495 | || (strcmp(args[0].from, "MMAP_CHECK") == 0)) |
491 | entry->func = MMAP_CHECK; | 496 | entry->func = MMAP_CHECK; |
@@ -636,6 +641,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
636 | result = -EINVAL; | 641 | result = -EINVAL; |
637 | else if (entry->func == MODULE_CHECK) | 642 | else if (entry->func == MODULE_CHECK) |
638 | ima_appraise |= IMA_APPRAISE_MODULES; | 643 | ima_appraise |= IMA_APPRAISE_MODULES; |
644 | else if (entry->func == FIRMWARE_CHECK) | ||
645 | ima_appraise |= IMA_APPRAISE_FIRMWARE; | ||
639 | audit_log_format(ab, "res=%d", !result); | 646 | audit_log_format(ab, "res=%d", !result); |
640 | audit_log_end(ab); | 647 | audit_log_end(ab); |
641 | return result; | 648 | return result; |
@@ -659,7 +666,7 @@ ssize_t ima_parse_add_rule(char *rule) | |||
659 | /* Prevent installed policy from changing */ | 666 | /* Prevent installed policy from changing */ |
660 | if (ima_rules != &ima_default_rules) { | 667 | if (ima_rules != &ima_default_rules) { |
661 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 668 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
662 | NULL, op, "already exists", | 669 | NULL, op, "already-exists", |
663 | -EACCES, audit_info); | 670 | -EACCES, audit_info); |
664 | return -EACCES; | 671 | return -EACCES; |
665 | } | 672 | } |
@@ -685,7 +692,7 @@ ssize_t ima_parse_add_rule(char *rule) | |||
685 | if (result) { | 692 | if (result) { |
686 | kfree(entry); | 693 | kfree(entry); |
687 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 694 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
688 | NULL, op, "invalid policy", result, | 695 | NULL, op, "invalid-policy", result, |
689 | audit_info); | 696 | audit_info); |
690 | return result; | 697 | return result; |
691 | } | 698 | } |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 33c0a70f6b15..19b8e314ca96 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -46,10 +46,14 @@ | |||
46 | #define IMA_BPRM_APPRAISED 0x00002000 | 46 | #define IMA_BPRM_APPRAISED 0x00002000 |
47 | #define IMA_MODULE_APPRAISE 0x00004000 | 47 | #define IMA_MODULE_APPRAISE 0x00004000 |
48 | #define IMA_MODULE_APPRAISED 0x00008000 | 48 | #define IMA_MODULE_APPRAISED 0x00008000 |
49 | #define IMA_FIRMWARE_APPRAISE 0x00010000 | ||
50 | #define IMA_FIRMWARE_APPRAISED 0x00020000 | ||
49 | #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ | 51 | #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ |
50 | IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE) | 52 | IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \ |
53 | IMA_FIRMWARE_APPRAISE) | ||
51 | #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ | 54 | #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ |
52 | IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED) | 55 | IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \ |
56 | IMA_FIRMWARE_APPRAISED) | ||
53 | 57 | ||
54 | enum evm_ima_xattr_type { | 58 | enum evm_ima_xattr_type { |
55 | IMA_XATTR_DIGEST = 0x01, | 59 | IMA_XATTR_DIGEST = 0x01, |
@@ -104,6 +108,7 @@ struct integrity_iint_cache { | |||
104 | enum integrity_status ima_mmap_status:4; | 108 | enum integrity_status ima_mmap_status:4; |
105 | enum integrity_status ima_bprm_status:4; | 109 | enum integrity_status ima_bprm_status:4; |
106 | enum integrity_status ima_module_status:4; | 110 | enum integrity_status ima_module_status:4; |
111 | enum integrity_status ima_firmware_status:4; | ||
107 | enum integrity_status evm_status:4; | 112 | enum integrity_status evm_status:4; |
108 | struct ima_digest_data *ima_hash; | 113 | struct ima_digest_data *ima_hash; |
109 | }; | 114 | }; |
@@ -124,6 +129,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
124 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 129 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
125 | const char *digest, int digestlen); | 130 | const char *digest, int digestlen); |
126 | 131 | ||
132 | int integrity_init_keyring(const unsigned int id); | ||
127 | #else | 133 | #else |
128 | 134 | ||
129 | static inline int integrity_digsig_verify(const unsigned int id, | 135 | static inline int integrity_digsig_verify(const unsigned int id, |
@@ -133,6 +139,10 @@ static inline int integrity_digsig_verify(const unsigned int id, | |||
133 | return -EOPNOTSUPP; | 139 | return -EOPNOTSUPP; |
134 | } | 140 | } |
135 | 141 | ||
142 | static inline int integrity_init_keyring(const unsigned int id) | ||
143 | { | ||
144 | return 0; | ||
145 | } | ||
136 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ | 146 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ |
137 | 147 | ||
138 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | 148 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 8137b27d641d..c2f91a0cf889 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
@@ -34,7 +34,9 @@ MODULE_LICENSE("GPL"); | |||
34 | struct key_type key_type_big_key = { | 34 | struct key_type key_type_big_key = { |
35 | .name = "big_key", | 35 | .name = "big_key", |
36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
37 | .instantiate = big_key_instantiate, | 37 | .preparse = big_key_preparse, |
38 | .free_preparse = big_key_free_preparse, | ||
39 | .instantiate = generic_key_instantiate, | ||
38 | .match = user_match, | 40 | .match = user_match, |
39 | .revoke = big_key_revoke, | 41 | .revoke = big_key_revoke, |
40 | .destroy = big_key_destroy, | 42 | .destroy = big_key_destroy, |
@@ -43,11 +45,11 @@ struct key_type key_type_big_key = { | |||
43 | }; | 45 | }; |
44 | 46 | ||
45 | /* | 47 | /* |
46 | * Instantiate a big key | 48 | * Preparse a big key |
47 | */ | 49 | */ |
48 | int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | 50 | int big_key_preparse(struct key_preparsed_payload *prep) |
49 | { | 51 | { |
50 | struct path *path = (struct path *)&key->payload.data2; | 52 | struct path *path = (struct path *)&prep->payload; |
51 | struct file *file; | 53 | struct file *file; |
52 | ssize_t written; | 54 | ssize_t written; |
53 | size_t datalen = prep->datalen; | 55 | size_t datalen = prep->datalen; |
@@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
58 | goto error; | 60 | goto error; |
59 | 61 | ||
60 | /* Set an arbitrary quota */ | 62 | /* Set an arbitrary quota */ |
61 | ret = key_payload_reserve(key, 16); | 63 | prep->quotalen = 16; |
62 | if (ret < 0) | ||
63 | goto error; | ||
64 | 64 | ||
65 | key->type_data.x[1] = datalen; | 65 | prep->type_data[1] = (void *)(unsigned long)datalen; |
66 | 66 | ||
67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
68 | /* Create a shmem file to store the data in. This will permit the data | 68 | /* 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) | |||
73 | file = shmem_kernel_file_setup("", datalen, 0); | 73 | file = shmem_kernel_file_setup("", datalen, 0); |
74 | if (IS_ERR(file)) { | 74 | if (IS_ERR(file)) { |
75 | ret = PTR_ERR(file); | 75 | ret = PTR_ERR(file); |
76 | goto err_quota; | 76 | goto error; |
77 | } | 77 | } |
78 | 78 | ||
79 | written = kernel_write(file, prep->data, prep->datalen, 0); | 79 | written = kernel_write(file, prep->data, prep->datalen, 0); |
@@ -93,24 +93,33 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
93 | } else { | 93 | } else { |
94 | /* Just store the data in a buffer */ | 94 | /* Just store the data in a buffer */ |
95 | void *data = kmalloc(datalen, GFP_KERNEL); | 95 | void *data = kmalloc(datalen, GFP_KERNEL); |
96 | if (!data) { | 96 | if (!data) |
97 | ret = -ENOMEM; | 97 | return -ENOMEM; |
98 | goto err_quota; | ||
99 | } | ||
100 | 98 | ||
101 | key->payload.data = memcpy(data, prep->data, prep->datalen); | 99 | prep->payload[0] = memcpy(data, prep->data, prep->datalen); |
102 | } | 100 | } |
103 | return 0; | 101 | return 0; |
104 | 102 | ||
105 | err_fput: | 103 | err_fput: |
106 | fput(file); | 104 | fput(file); |
107 | err_quota: | ||
108 | key_payload_reserve(key, 0); | ||
109 | error: | 105 | error: |
110 | return ret; | 106 | return ret; |
111 | } | 107 | } |
112 | 108 | ||
113 | /* | 109 | /* |
110 | * Clear preparsement. | ||
111 | */ | ||
112 | void big_key_free_preparse(struct key_preparsed_payload *prep) | ||
113 | { | ||
114 | if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { | ||
115 | struct path *path = (struct path *)&prep->payload; | ||
116 | path_put(path); | ||
117 | } else { | ||
118 | kfree(prep->payload[0]); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /* | ||
114 | * dispose of the links from a revoked keyring | 123 | * dispose of the links from a revoked keyring |
115 | * - called with the key sem write-locked | 124 | * - called with the key sem write-locked |
116 | */ | 125 | */ |
diff --git a/security/keys/key.c b/security/keys/key.c index 2048a110e7f1..b90a68c4e2c4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key, | |||
437 | /* disable the authorisation key */ | 437 | /* disable the authorisation key */ |
438 | if (authkey) | 438 | if (authkey) |
439 | key_revoke(authkey); | 439 | key_revoke(authkey); |
440 | |||
441 | if (prep->expiry != TIME_T_MAX) { | ||
442 | key->expiry = prep->expiry; | ||
443 | key_schedule_gc(prep->expiry + key_gc_delay); | ||
444 | } | ||
440 | } | 445 | } |
441 | } | 446 | } |
442 | 447 | ||
@@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key, | |||
479 | prep.data = data; | 484 | prep.data = data; |
480 | prep.datalen = datalen; | 485 | prep.datalen = datalen; |
481 | prep.quotalen = key->type->def_datalen; | 486 | prep.quotalen = key->type->def_datalen; |
487 | prep.expiry = TIME_T_MAX; | ||
482 | if (key->type->preparse) { | 488 | if (key->type->preparse) { |
483 | ret = key->type->preparse(&prep); | 489 | ret = key->type->preparse(&prep); |
484 | if (ret < 0) | 490 | if (ret < 0) |
@@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key, | |||
488 | if (keyring) { | 494 | if (keyring) { |
489 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 495 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
490 | if (ret < 0) | 496 | if (ret < 0) |
491 | goto error_free_preparse; | 497 | goto error; |
492 | } | 498 | } |
493 | 499 | ||
494 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); | 500 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); |
@@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key, | |||
496 | if (keyring) | 502 | if (keyring) |
497 | __key_link_end(keyring, &key->index_key, edit); | 503 | __key_link_end(keyring, &key->index_key, edit); |
498 | 504 | ||
499 | error_free_preparse: | 505 | error: |
500 | if (key->type->preparse) | 506 | if (key->type->preparse) |
501 | key->type->free_preparse(&prep); | 507 | key->type->free_preparse(&prep); |
502 | error: | ||
503 | return ret; | 508 | return ret; |
504 | } | 509 | } |
505 | 510 | ||
@@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
811 | prep.datalen = plen; | 816 | prep.datalen = plen; |
812 | prep.quotalen = index_key.type->def_datalen; | 817 | prep.quotalen = index_key.type->def_datalen; |
813 | prep.trusted = flags & KEY_ALLOC_TRUSTED; | 818 | prep.trusted = flags & KEY_ALLOC_TRUSTED; |
819 | prep.expiry = TIME_T_MAX; | ||
814 | if (index_key.type->preparse) { | 820 | if (index_key.type->preparse) { |
815 | ret = index_key.type->preparse(&prep); | 821 | ret = index_key.type->preparse(&prep); |
816 | if (ret < 0) { | 822 | if (ret < 0) { |
817 | key_ref = ERR_PTR(ret); | 823 | key_ref = ERR_PTR(ret); |
818 | goto error_put_type; | 824 | goto error_free_prep; |
819 | } | 825 | } |
820 | if (!index_key.description) | 826 | if (!index_key.description) |
821 | index_key.description = prep.description; | 827 | index_key.description = prep.description; |
@@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
941 | prep.data = payload; | 947 | prep.data = payload; |
942 | prep.datalen = plen; | 948 | prep.datalen = plen; |
943 | prep.quotalen = key->type->def_datalen; | 949 | prep.quotalen = key->type->def_datalen; |
950 | prep.expiry = TIME_T_MAX; | ||
944 | if (key->type->preparse) { | 951 | if (key->type->preparse) { |
945 | ret = key->type->preparse(&prep); | 952 | ret = key->type->preparse(&prep); |
946 | if (ret < 0) | 953 | if (ret < 0) |
@@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
956 | 963 | ||
957 | up_write(&key->sem); | 964 | up_write(&key->sem); |
958 | 965 | ||
966 | error: | ||
959 | if (key->type->preparse) | 967 | if (key->type->preparse) |
960 | key->type->free_preparse(&prep); | 968 | key->type->free_preparse(&prep); |
961 | error: | ||
962 | return ret; | 969 | return ret; |
963 | } | 970 | } |
964 | EXPORT_SYMBOL(key_update); | 971 | EXPORT_SYMBOL(key_update); |
@@ -1024,6 +1031,38 @@ void key_invalidate(struct key *key) | |||
1024 | EXPORT_SYMBOL(key_invalidate); | 1031 | EXPORT_SYMBOL(key_invalidate); |
1025 | 1032 | ||
1026 | /** | 1033 | /** |
1034 | * generic_key_instantiate - Simple instantiation of a key from preparsed data | ||
1035 | * @key: The key to be instantiated | ||
1036 | * @prep: The preparsed data to load. | ||
1037 | * | ||
1038 | * Instantiate a key from preparsed data. We assume we can just copy the data | ||
1039 | * in directly and clear the old pointers. | ||
1040 | * | ||
1041 | * This can be pointed to directly by the key type instantiate op pointer. | ||
1042 | */ | ||
1043 | int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
1044 | { | ||
1045 | int ret; | ||
1046 | |||
1047 | pr_devel("==>%s()\n", __func__); | ||
1048 | |||
1049 | ret = key_payload_reserve(key, prep->quotalen); | ||
1050 | if (ret == 0) { | ||
1051 | key->type_data.p[0] = prep->type_data[0]; | ||
1052 | key->type_data.p[1] = prep->type_data[1]; | ||
1053 | rcu_assign_keypointer(key, prep->payload[0]); | ||
1054 | key->payload.data2[1] = prep->payload[1]; | ||
1055 | prep->type_data[0] = NULL; | ||
1056 | prep->type_data[1] = NULL; | ||
1057 | prep->payload[0] = NULL; | ||
1058 | prep->payload[1] = NULL; | ||
1059 | } | ||
1060 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
1061 | return ret; | ||
1062 | } | ||
1063 | EXPORT_SYMBOL(generic_key_instantiate); | ||
1064 | |||
1065 | /** | ||
1027 | * register_key_type - Register a type of key. | 1066 | * register_key_type - Register a type of key. |
1028 | * @ktype: The new key type. | 1067 | * @ktype: The new key type. |
1029 | * | 1068 | * |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cd5bd0cef25d..e26f860e5f2e 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type, | |||
37 | return ret; | 37 | return ret; |
38 | if (ret == 0 || ret >= len) | 38 | if (ret == 0 || ret >= len) |
39 | return -EINVAL; | 39 | return -EINVAL; |
40 | if (type[0] == '.') | ||
41 | return -EPERM; | ||
42 | type[len - 1] = '\0'; | 40 | type[len - 1] = '\0'; |
43 | return 0; | 41 | return 0; |
44 | } | 42 | } |
@@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
86 | if (!*description) { | 84 | if (!*description) { |
87 | kfree(description); | 85 | kfree(description); |
88 | description = NULL; | 86 | description = NULL; |
87 | } else if ((description[0] == '.') && | ||
88 | (strncmp(type, "keyring", 7) == 0)) { | ||
89 | ret = -EPERM; | ||
90 | goto error2; | ||
89 | } | 91 | } |
90 | } | 92 | } |
91 | 93 | ||
@@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id) | |||
404 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); | 406 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); |
405 | if (IS_ERR(key_ref)) { | 407 | if (IS_ERR(key_ref)) { |
406 | ret = PTR_ERR(key_ref); | 408 | ret = PTR_ERR(key_ref); |
409 | |||
410 | /* Root is permitted to invalidate certain special keys */ | ||
411 | if (capable(CAP_SYS_ADMIN)) { | ||
412 | key_ref = lookup_user_key(id, 0, 0); | ||
413 | if (IS_ERR(key_ref)) | ||
414 | goto error; | ||
415 | if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, | ||
416 | &key_ref_to_ptr(key_ref)->flags)) | ||
417 | goto invalidate; | ||
418 | goto error_put; | ||
419 | } | ||
420 | |||
407 | goto error; | 421 | goto error; |
408 | } | 422 | } |
409 | 423 | ||
424 | invalidate: | ||
410 | key_invalidate(key_ref_to_ptr(key_ref)); | 425 | key_invalidate(key_ref_to_ptr(key_ref)); |
411 | ret = 0; | 426 | ret = 0; |
412 | 427 | error_put: | |
413 | key_ref_put(key_ref); | 428 | key_ref_put(key_ref); |
414 | error: | 429 | error: |
415 | kleave(" = %ld", ret); | 430 | kleave(" = %ld", ret); |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 9cf2575f0d97..8314a7d2104d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc) | |||
73 | * can be treated as ordinary keys in addition to having their own special | 73 | * can be treated as ordinary keys in addition to having their own special |
74 | * operations. | 74 | * operations. |
75 | */ | 75 | */ |
76 | static int keyring_preparse(struct key_preparsed_payload *prep); | ||
77 | static void keyring_free_preparse(struct key_preparsed_payload *prep); | ||
76 | static int keyring_instantiate(struct key *keyring, | 78 | static int keyring_instantiate(struct key *keyring, |
77 | struct key_preparsed_payload *prep); | 79 | struct key_preparsed_payload *prep); |
78 | static void keyring_revoke(struct key *keyring); | 80 | static void keyring_revoke(struct key *keyring); |
@@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring, | |||
84 | struct key_type key_type_keyring = { | 86 | struct key_type key_type_keyring = { |
85 | .name = "keyring", | 87 | .name = "keyring", |
86 | .def_datalen = 0, | 88 | .def_datalen = 0, |
89 | .preparse = keyring_preparse, | ||
90 | .free_preparse = keyring_free_preparse, | ||
87 | .instantiate = keyring_instantiate, | 91 | .instantiate = keyring_instantiate, |
88 | .match = user_match, | 92 | .match = user_match, |
89 | .revoke = keyring_revoke, | 93 | .revoke = keyring_revoke, |
@@ -123,6 +127,21 @@ static void keyring_publish_name(struct key *keyring) | |||
123 | } | 127 | } |
124 | 128 | ||
125 | /* | 129 | /* |
130 | * Preparse a keyring payload | ||
131 | */ | ||
132 | static int keyring_preparse(struct key_preparsed_payload *prep) | ||
133 | { | ||
134 | return prep->datalen != 0 ? -EINVAL : 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Free a preparse of a user defined key payload | ||
139 | */ | ||
140 | static void keyring_free_preparse(struct key_preparsed_payload *prep) | ||
141 | { | ||
142 | } | ||
143 | |||
144 | /* | ||
126 | * Initialise a keyring. | 145 | * Initialise a keyring. |
127 | * | 146 | * |
128 | * Returns 0 on success, -EINVAL if given any data. | 147 | * Returns 0 on success, -EINVAL if given any data. |
@@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring) | |||
130 | static int keyring_instantiate(struct key *keyring, | 149 | static int keyring_instantiate(struct key *keyring, |
131 | struct key_preparsed_payload *prep) | 150 | struct key_preparsed_payload *prep) |
132 | { | 151 | { |
133 | int ret; | 152 | assoc_array_init(&keyring->keys); |
134 | 153 | /* make the keyring available by name if it has one */ | |
135 | ret = -EINVAL; | 154 | keyring_publish_name(keyring); |
136 | if (prep->datalen == 0) { | 155 | return 0; |
137 | assoc_array_init(&keyring->keys); | ||
138 | /* make the keyring available by name if it has one */ | ||
139 | keyring_publish_name(keyring); | ||
140 | ret = 0; | ||
141 | } | ||
142 | |||
143 | return ret; | ||
144 | } | 156 | } |
145 | 157 | ||
146 | /* | 158 | /* |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 7495a93b4b90..842e6f410d50 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "internal.h" | 20 | #include "internal.h" |
21 | #include <keys/user-type.h> | 21 | #include <keys/user-type.h> |
22 | 22 | ||
23 | static int request_key_auth_preparse(struct key_preparsed_payload *); | ||
24 | static void request_key_auth_free_preparse(struct key_preparsed_payload *); | ||
23 | static int request_key_auth_instantiate(struct key *, | 25 | static int request_key_auth_instantiate(struct key *, |
24 | struct key_preparsed_payload *); | 26 | struct key_preparsed_payload *); |
25 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 27 | 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); | |||
33 | struct key_type key_type_request_key_auth = { | 35 | struct key_type key_type_request_key_auth = { |
34 | .name = ".request_key_auth", | 36 | .name = ".request_key_auth", |
35 | .def_datalen = sizeof(struct request_key_auth), | 37 | .def_datalen = sizeof(struct request_key_auth), |
38 | .preparse = request_key_auth_preparse, | ||
39 | .free_preparse = request_key_auth_free_preparse, | ||
36 | .instantiate = request_key_auth_instantiate, | 40 | .instantiate = request_key_auth_instantiate, |
37 | .describe = request_key_auth_describe, | 41 | .describe = request_key_auth_describe, |
38 | .revoke = request_key_auth_revoke, | 42 | .revoke = request_key_auth_revoke, |
@@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = { | |||
40 | .read = request_key_auth_read, | 44 | .read = request_key_auth_read, |
41 | }; | 45 | }; |
42 | 46 | ||
47 | int request_key_auth_preparse(struct key_preparsed_payload *prep) | ||
48 | { | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | void request_key_auth_free_preparse(struct key_preparsed_payload *prep) | ||
53 | { | ||
54 | } | ||
55 | |||
43 | /* | 56 | /* |
44 | * Instantiate a request-key authorisation key. | 57 | * Instantiate a request-key authorisation key. |
45 | */ | 58 | */ |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index faa2caeb593f..eee340011f2b 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
@@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc); | |||
27 | struct key_type key_type_user = { | 27 | struct key_type key_type_user = { |
28 | .name = "user", | 28 | .name = "user", |
29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
30 | .instantiate = user_instantiate, | 30 | .preparse = user_preparse, |
31 | .free_preparse = user_free_preparse, | ||
32 | .instantiate = generic_key_instantiate, | ||
31 | .update = user_update, | 33 | .update = user_update, |
32 | .match = user_match, | 34 | .match = user_match, |
33 | .revoke = user_revoke, | 35 | .revoke = user_revoke, |
@@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user); | |||
47 | struct key_type key_type_logon = { | 49 | struct key_type key_type_logon = { |
48 | .name = "logon", | 50 | .name = "logon", |
49 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 51 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
50 | .instantiate = user_instantiate, | 52 | .preparse = user_preparse, |
53 | .free_preparse = user_free_preparse, | ||
54 | .instantiate = generic_key_instantiate, | ||
51 | .update = user_update, | 55 | .update = user_update, |
52 | .match = user_match, | 56 | .match = user_match, |
53 | .revoke = user_revoke, | 57 | .revoke = user_revoke, |
@@ -58,38 +62,37 @@ struct key_type key_type_logon = { | |||
58 | EXPORT_SYMBOL_GPL(key_type_logon); | 62 | EXPORT_SYMBOL_GPL(key_type_logon); |
59 | 63 | ||
60 | /* | 64 | /* |
61 | * instantiate a user defined key | 65 | * Preparse a user defined key payload |
62 | */ | 66 | */ |
63 | int user_instantiate(struct key *key, struct key_preparsed_payload *prep) | 67 | int user_preparse(struct key_preparsed_payload *prep) |
64 | { | 68 | { |
65 | struct user_key_payload *upayload; | 69 | struct user_key_payload *upayload; |
66 | size_t datalen = prep->datalen; | 70 | size_t datalen = prep->datalen; |
67 | int ret; | ||
68 | 71 | ||
69 | ret = -EINVAL; | ||
70 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 72 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
71 | goto error; | 73 | return -EINVAL; |
72 | |||
73 | ret = key_payload_reserve(key, datalen); | ||
74 | if (ret < 0) | ||
75 | goto error; | ||
76 | 74 | ||
77 | ret = -ENOMEM; | ||
78 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | 75 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
79 | if (!upayload) | 76 | if (!upayload) |
80 | goto error; | 77 | return -ENOMEM; |
81 | 78 | ||
82 | /* attach the data */ | 79 | /* attach the data */ |
80 | prep->quotalen = datalen; | ||
81 | prep->payload[0] = upayload; | ||
83 | upayload->datalen = datalen; | 82 | upayload->datalen = datalen; |
84 | memcpy(upayload->data, prep->data, datalen); | 83 | memcpy(upayload->data, prep->data, datalen); |
85 | rcu_assign_keypointer(key, upayload); | 84 | return 0; |
86 | ret = 0; | ||
87 | |||
88 | error: | ||
89 | return ret; | ||
90 | } | 85 | } |
86 | EXPORT_SYMBOL_GPL(user_preparse); | ||
91 | 87 | ||
92 | EXPORT_SYMBOL_GPL(user_instantiate); | 88 | /* |
89 | * Free a preparse of a user defined key payload | ||
90 | */ | ||
91 | void user_free_preparse(struct key_preparsed_payload *prep) | ||
92 | { | ||
93 | kfree(prep->payload[0]); | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(user_free_preparse); | ||
93 | 96 | ||
94 | /* | 97 | /* |
95 | * update a user defined key | 98 | * update a user defined key |
diff --git a/security/security.c b/security/security.c index 31614e9e96e5..e41b1a8d7644 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -845,6 +845,17 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
845 | return security_ops->kernel_create_files_as(new, inode); | 845 | return security_ops->kernel_create_files_as(new, inode); |
846 | } | 846 | } |
847 | 847 | ||
848 | int security_kernel_fw_from_file(struct file *file, char *buf, size_t size) | ||
849 | { | ||
850 | int ret; | ||
851 | |||
852 | ret = security_ops->kernel_fw_from_file(file, buf, size); | ||
853 | if (ret) | ||
854 | return ret; | ||
855 | return ima_fw_from_file(file, buf, size); | ||
856 | } | ||
857 | EXPORT_SYMBOL_GPL(security_kernel_fw_from_file); | ||
858 | |||
848 | int security_kernel_module_request(char *kmod_name) | 859 | int security_kernel_module_request(char *kmod_name) |
849 | { | 860 | { |
850 | return security_ops->kernel_module_request(kmod_name); | 861 | return security_ops->kernel_module_request(kmod_name); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 83d06db34d03..b0e940497e23 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -161,6 +161,17 @@ static int selinux_peerlbl_enabled(void) | |||
161 | return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled()); | 161 | return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled()); |
162 | } | 162 | } |
163 | 163 | ||
164 | static int selinux_netcache_avc_callback(u32 event) | ||
165 | { | ||
166 | if (event == AVC_CALLBACK_RESET) { | ||
167 | sel_netif_flush(); | ||
168 | sel_netnode_flush(); | ||
169 | sel_netport_flush(); | ||
170 | synchronize_net(); | ||
171 | } | ||
172 | return 0; | ||
173 | } | ||
174 | |||
164 | /* | 175 | /* |
165 | * initialise the security for the init task | 176 | * initialise the security for the init task |
166 | */ | 177 | */ |
@@ -5993,6 +6004,9 @@ static __init int selinux_init(void) | |||
5993 | if (register_security(&selinux_ops)) | 6004 | if (register_security(&selinux_ops)) |
5994 | panic("SELinux: Unable to register with kernel.\n"); | 6005 | panic("SELinux: Unable to register with kernel.\n"); |
5995 | 6006 | ||
6007 | if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) | ||
6008 | panic("SELinux: Unable to register AVC netcache callback\n"); | ||
6009 | |||
5996 | if (selinux_enforcing) | 6010 | if (selinux_enforcing) |
5997 | printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); | 6011 | printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); |
5998 | else | 6012 | else |
diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h index 43d507242b42..57c6eae81eac 100644 --- a/security/selinux/include/netif.h +++ b/security/selinux/include/netif.h | |||
@@ -17,6 +17,8 @@ | |||
17 | #ifndef _SELINUX_NETIF_H_ | 17 | #ifndef _SELINUX_NETIF_H_ |
18 | #define _SELINUX_NETIF_H_ | 18 | #define _SELINUX_NETIF_H_ |
19 | 19 | ||
20 | void sel_netif_flush(void); | ||
21 | |||
20 | int sel_netif_sid(int ifindex, u32 *sid); | 22 | int sel_netif_sid(int ifindex, u32 *sid); |
21 | 23 | ||
22 | #endif /* _SELINUX_NETIF_H_ */ | 24 | #endif /* _SELINUX_NETIF_H_ */ |
diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h index df7a5ed6c694..937668dd3024 100644 --- a/security/selinux/include/netnode.h +++ b/security/selinux/include/netnode.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #ifndef _SELINUX_NETNODE_H | 27 | #ifndef _SELINUX_NETNODE_H |
28 | #define _SELINUX_NETNODE_H | 28 | #define _SELINUX_NETNODE_H |
29 | 29 | ||
30 | void sel_netnode_flush(void); | ||
31 | |||
30 | int sel_netnode_sid(void *addr, u16 family, u32 *sid); | 32 | int sel_netnode_sid(void *addr, u16 family, u32 *sid); |
31 | 33 | ||
32 | #endif | 34 | #endif |
diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h index 4d965b83d735..d1ce896b2cb0 100644 --- a/security/selinux/include/netport.h +++ b/security/selinux/include/netport.h | |||
@@ -26,6 +26,8 @@ | |||
26 | #ifndef _SELINUX_NETPORT_H | 26 | #ifndef _SELINUX_NETPORT_H |
27 | #define _SELINUX_NETPORT_H | 27 | #define _SELINUX_NETPORT_H |
28 | 28 | ||
29 | void sel_netport_flush(void); | ||
30 | |||
29 | int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); | 31 | int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); |
30 | 32 | ||
31 | #endif | 33 | #endif |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ce7852cf526b..d1e0b239b602 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #ifndef _SELINUX_SECURITY_H_ | 8 | #ifndef _SELINUX_SECURITY_H_ |
9 | #define _SELINUX_SECURITY_H_ | 9 | #define _SELINUX_SECURITY_H_ |
10 | 10 | ||
11 | #include <linux/compiler.h> | ||
11 | #include <linux/dcache.h> | 12 | #include <linux/dcache.h> |
12 | #include <linux/magic.h> | 13 | #include <linux/magic.h> |
13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
@@ -220,7 +221,7 @@ struct selinux_kernel_status { | |||
220 | /* | 221 | /* |
221 | * The version > 0 supports above members. | 222 | * The version > 0 supports above members. |
222 | */ | 223 | */ |
223 | } __attribute__((packed)); | 224 | } __packed; |
224 | 225 | ||
225 | extern void selinux_status_update_setenforce(int enforcing); | 226 | extern void selinux_status_update_setenforce(int enforcing); |
226 | extern void selinux_status_update_policyload(int seqno); | 227 | extern void selinux_status_update_policyload(int seqno); |
diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 694e9e43855f..3c3de4ca0ebc 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c | |||
@@ -240,7 +240,7 @@ static void sel_netif_kill(int ifindex) | |||
240 | * Remove all entries from the network interface table. | 240 | * Remove all entries from the network interface table. |
241 | * | 241 | * |
242 | */ | 242 | */ |
243 | static void sel_netif_flush(void) | 243 | void sel_netif_flush(void) |
244 | { | 244 | { |
245 | int idx; | 245 | int idx; |
246 | struct sel_netif *netif; | 246 | struct sel_netif *netif; |
@@ -252,15 +252,6 @@ static void sel_netif_flush(void) | |||
252 | spin_unlock_bh(&sel_netif_lock); | 252 | spin_unlock_bh(&sel_netif_lock); |
253 | } | 253 | } |
254 | 254 | ||
255 | static int sel_netif_avc_callback(u32 event) | ||
256 | { | ||
257 | if (event == AVC_CALLBACK_RESET) { | ||
258 | sel_netif_flush(); | ||
259 | synchronize_net(); | ||
260 | } | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int sel_netif_netdev_notifier_handler(struct notifier_block *this, | 255 | static int sel_netif_netdev_notifier_handler(struct notifier_block *this, |
265 | unsigned long event, void *ptr) | 256 | unsigned long event, void *ptr) |
266 | { | 257 | { |
@@ -291,10 +282,6 @@ static __init int sel_netif_init(void) | |||
291 | 282 | ||
292 | register_netdevice_notifier(&sel_netif_netdev_notifier); | 283 | register_netdevice_notifier(&sel_netif_netdev_notifier); |
293 | 284 | ||
294 | err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET); | ||
295 | if (err) | ||
296 | panic("avc_add_callback() failed, error %d\n", err); | ||
297 | |||
298 | return err; | 285 | return err; |
299 | } | 286 | } |
300 | 287 | ||
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 03a72c32afd7..ddf315260839 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -283,7 +283,7 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid) | |||
283 | * Remove all entries from the network address table. | 283 | * Remove all entries from the network address table. |
284 | * | 284 | * |
285 | */ | 285 | */ |
286 | static void sel_netnode_flush(void) | 286 | void sel_netnode_flush(void) |
287 | { | 287 | { |
288 | unsigned int idx; | 288 | unsigned int idx; |
289 | struct sel_netnode *node, *node_tmp; | 289 | struct sel_netnode *node, *node_tmp; |
@@ -300,15 +300,6 @@ static void sel_netnode_flush(void) | |||
300 | spin_unlock_bh(&sel_netnode_lock); | 300 | spin_unlock_bh(&sel_netnode_lock); |
301 | } | 301 | } |
302 | 302 | ||
303 | static int sel_netnode_avc_callback(u32 event) | ||
304 | { | ||
305 | if (event == AVC_CALLBACK_RESET) { | ||
306 | sel_netnode_flush(); | ||
307 | synchronize_net(); | ||
308 | } | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static __init int sel_netnode_init(void) | 303 | static __init int sel_netnode_init(void) |
313 | { | 304 | { |
314 | int iter; | 305 | int iter; |
@@ -322,10 +313,6 @@ static __init int sel_netnode_init(void) | |||
322 | sel_netnode_hash[iter].size = 0; | 313 | sel_netnode_hash[iter].size = 0; |
323 | } | 314 | } |
324 | 315 | ||
325 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET); | ||
326 | if (ret != 0) | ||
327 | panic("avc_add_callback() failed, error %d\n", ret); | ||
328 | |||
329 | return ret; | 316 | return ret; |
330 | } | 317 | } |
331 | 318 | ||
diff --git a/security/selinux/netport.c b/security/selinux/netport.c index d35379781c2c..73ac6784d091 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c | |||
@@ -217,7 +217,7 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) | |||
217 | * Remove all entries from the network address table. | 217 | * Remove all entries from the network address table. |
218 | * | 218 | * |
219 | */ | 219 | */ |
220 | static void sel_netport_flush(void) | 220 | void sel_netport_flush(void) |
221 | { | 221 | { |
222 | unsigned int idx; | 222 | unsigned int idx; |
223 | struct sel_netport *port, *port_tmp; | 223 | struct sel_netport *port, *port_tmp; |
@@ -234,15 +234,6 @@ static void sel_netport_flush(void) | |||
234 | spin_unlock_bh(&sel_netport_lock); | 234 | spin_unlock_bh(&sel_netport_lock); |
235 | } | 235 | } |
236 | 236 | ||
237 | static int sel_netport_avc_callback(u32 event) | ||
238 | { | ||
239 | if (event == AVC_CALLBACK_RESET) { | ||
240 | sel_netport_flush(); | ||
241 | synchronize_net(); | ||
242 | } | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static __init int sel_netport_init(void) | 237 | static __init int sel_netport_init(void) |
247 | { | 238 | { |
248 | int iter; | 239 | int iter; |
@@ -256,10 +247,6 @@ static __init int sel_netport_init(void) | |||
256 | sel_netport_hash[iter].size = 0; | 247 | sel_netport_hash[iter].size = 0; |
257 | } | 248 | } |
258 | 249 | ||
259 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET); | ||
260 | if (ret != 0) | ||
261 | panic("avc_add_callback() failed, error %d\n", ret); | ||
262 | |||
263 | return ret; | 250 | return ret; |
264 | } | 251 | } |
265 | 252 | ||
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 377d148e7157..62c6773be0b7 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -402,19 +402,14 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) | |||
402 | int rc; | 402 | int rc; |
403 | struct cond_expr *expr = NULL, *last = NULL; | 403 | struct cond_expr *expr = NULL, *last = NULL; |
404 | 404 | ||
405 | rc = next_entry(buf, fp, sizeof(u32)); | 405 | rc = next_entry(buf, fp, sizeof(u32) * 2); |
406 | if (rc) | 406 | if (rc) |
407 | return rc; | 407 | goto err; |
408 | 408 | ||
409 | node->cur_state = le32_to_cpu(buf[0]); | 409 | node->cur_state = le32_to_cpu(buf[0]); |
410 | 410 | ||
411 | len = 0; | ||
412 | rc = next_entry(buf, fp, sizeof(u32)); | ||
413 | if (rc) | ||
414 | return rc; | ||
415 | |||
416 | /* expr */ | 411 | /* expr */ |
417 | len = le32_to_cpu(buf[0]); | 412 | len = le32_to_cpu(buf[1]); |
418 | 413 | ||
419 | for (i = 0; i < len; i++) { | 414 | for (i = 0; i < len; i++) { |
420 | rc = next_entry(buf, fp, sizeof(u32) * 2); | 415 | rc = next_entry(buf, fp, sizeof(u32) * 2); |
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 820313a04d49..afe6a269ec17 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
@@ -86,51 +86,36 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) | |||
86 | * | 86 | * |
87 | */ | 87 | */ |
88 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 88 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
89 | struct netlbl_lsm_secattr_catmap **catmap) | 89 | struct netlbl_lsm_catmap **catmap) |
90 | { | 90 | { |
91 | struct ebitmap_node *e_iter = ebmap->node; | 91 | struct ebitmap_node *e_iter = ebmap->node; |
92 | struct netlbl_lsm_secattr_catmap *c_iter; | 92 | unsigned long e_map; |
93 | u32 cmap_idx, cmap_sft; | 93 | u32 offset; |
94 | int i; | 94 | unsigned int iter; |
95 | 95 | int rc; | |
96 | /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, | ||
97 | * however, it is not always compatible with an array of unsigned long | ||
98 | * in ebitmap_node. | ||
99 | * In addition, you should pay attention the following implementation | ||
100 | * assumes unsigned long has a width equal with or less than 64-bit. | ||
101 | */ | ||
102 | 96 | ||
103 | if (e_iter == NULL) { | 97 | if (e_iter == NULL) { |
104 | *catmap = NULL; | 98 | *catmap = NULL; |
105 | return 0; | 99 | return 0; |
106 | } | 100 | } |
107 | 101 | ||
108 | c_iter = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | 102 | if (*catmap != NULL) |
109 | if (c_iter == NULL) | 103 | netlbl_catmap_free(*catmap); |
110 | return -ENOMEM; | 104 | *catmap = NULL; |
111 | *catmap = c_iter; | ||
112 | c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); | ||
113 | 105 | ||
114 | while (e_iter) { | 106 | while (e_iter) { |
115 | for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { | 107 | offset = e_iter->startbit; |
116 | unsigned int delta, e_startbit, c_endbit; | 108 | for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) { |
117 | 109 | e_map = e_iter->maps[iter]; | |
118 | e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE; | 110 | if (e_map != 0) { |
119 | c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE; | 111 | rc = netlbl_catmap_setlong(catmap, |
120 | if (e_startbit >= c_endbit) { | 112 | offset, |
121 | c_iter->next | 113 | e_map, |
122 | = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | 114 | GFP_ATOMIC); |
123 | if (c_iter->next == NULL) | 115 | if (rc != 0) |
124 | goto netlbl_export_failure; | 116 | goto netlbl_export_failure; |
125 | c_iter = c_iter->next; | ||
126 | c_iter->startbit | ||
127 | = e_startbit & ~(NETLBL_CATMAP_SIZE - 1); | ||
128 | } | 117 | } |
129 | delta = e_startbit - c_iter->startbit; | 118 | offset += EBITMAP_UNIT_SIZE; |
130 | cmap_idx = delta / NETLBL_CATMAP_MAPSIZE; | ||
131 | cmap_sft = delta % NETLBL_CATMAP_MAPSIZE; | ||
132 | c_iter->bitmap[cmap_idx] | ||
133 | |= e_iter->maps[i] << cmap_sft; | ||
134 | } | 119 | } |
135 | e_iter = e_iter->next; | 120 | e_iter = e_iter->next; |
136 | } | 121 | } |
@@ -138,7 +123,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, | |||
138 | return 0; | 123 | return 0; |
139 | 124 | ||
140 | netlbl_export_failure: | 125 | netlbl_export_failure: |
141 | netlbl_secattr_catmap_free(*catmap); | 126 | netlbl_catmap_free(*catmap); |
142 | return -ENOMEM; | 127 | return -ENOMEM; |
143 | } | 128 | } |
144 | 129 | ||
@@ -153,58 +138,44 @@ netlbl_export_failure: | |||
153 | * | 138 | * |
154 | */ | 139 | */ |
155 | int ebitmap_netlbl_import(struct ebitmap *ebmap, | 140 | int ebitmap_netlbl_import(struct ebitmap *ebmap, |
156 | struct netlbl_lsm_secattr_catmap *catmap) | 141 | struct netlbl_lsm_catmap *catmap) |
157 | { | 142 | { |
143 | int rc; | ||
158 | struct ebitmap_node *e_iter = NULL; | 144 | struct ebitmap_node *e_iter = NULL; |
159 | struct ebitmap_node *emap_prev = NULL; | 145 | struct ebitmap_node *e_prev = NULL; |
160 | struct netlbl_lsm_secattr_catmap *c_iter = catmap; | 146 | u32 offset = 0, idx; |
161 | u32 c_idx, c_pos, e_idx, e_sft; | 147 | unsigned long bitmap; |
162 | 148 | ||
163 | /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, | 149 | for (;;) { |
164 | * however, it is not always compatible with an array of unsigned long | 150 | rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); |
165 | * in ebitmap_node. | 151 | if (rc < 0) |
166 | * In addition, you should pay attention the following implementation | 152 | goto netlbl_import_failure; |
167 | * assumes unsigned long has a width equal with or less than 64-bit. | 153 | if (offset == (u32)-1) |
168 | */ | 154 | return 0; |
169 | |||
170 | do { | ||
171 | for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { | ||
172 | unsigned int delta; | ||
173 | u64 map = c_iter->bitmap[c_idx]; | ||
174 | |||
175 | if (!map) | ||
176 | continue; | ||
177 | 155 | ||
178 | c_pos = c_iter->startbit | 156 | if (e_iter == NULL || |
179 | + c_idx * NETLBL_CATMAP_MAPSIZE; | 157 | offset >= e_iter->startbit + EBITMAP_SIZE) { |
180 | if (!e_iter | 158 | e_prev = e_iter; |
181 | || c_pos >= e_iter->startbit + EBITMAP_SIZE) { | 159 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); |
182 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); | 160 | if (e_iter == NULL) |
183 | if (!e_iter) | 161 | goto netlbl_import_failure; |
184 | goto netlbl_import_failure; | 162 | e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); |
185 | e_iter->startbit | 163 | if (e_prev == NULL) |
186 | = c_pos - (c_pos % EBITMAP_SIZE); | 164 | ebmap->node = e_iter; |
187 | if (emap_prev == NULL) | 165 | else |
188 | ebmap->node = e_iter; | 166 | e_prev->next = e_iter; |
189 | else | 167 | ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; |
190 | emap_prev->next = e_iter; | ||
191 | emap_prev = e_iter; | ||
192 | } | ||
193 | delta = c_pos - e_iter->startbit; | ||
194 | e_idx = delta / EBITMAP_UNIT_SIZE; | ||
195 | e_sft = delta % EBITMAP_UNIT_SIZE; | ||
196 | while (map) { | ||
197 | e_iter->maps[e_idx++] |= map & (-1UL); | ||
198 | map = EBITMAP_SHIFT_UNIT_SIZE(map); | ||
199 | } | ||
200 | } | 168 | } |
201 | c_iter = c_iter->next; | ||
202 | } while (c_iter); | ||
203 | if (e_iter != NULL) | ||
204 | ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; | ||
205 | else | ||
206 | ebitmap_destroy(ebmap); | ||
207 | 169 | ||
170 | /* offset will always be aligned to an unsigned long */ | ||
171 | idx = EBITMAP_NODE_INDEX(e_iter, offset); | ||
172 | e_iter->maps[idx] = bitmap; | ||
173 | |||
174 | /* next */ | ||
175 | offset += EBITMAP_UNIT_SIZE; | ||
176 | } | ||
177 | |||
178 | /* NOTE: we should never reach this return */ | ||
208 | return 0; | 179 | return 0; |
209 | 180 | ||
210 | netlbl_import_failure: | 181 | netlbl_import_failure: |
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 712c8a7b8e8b..9637b8c71085 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
@@ -132,17 +132,17 @@ int ebitmap_write(struct ebitmap *e, void *fp); | |||
132 | 132 | ||
133 | #ifdef CONFIG_NETLABEL | 133 | #ifdef CONFIG_NETLABEL |
134 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 134 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
135 | struct netlbl_lsm_secattr_catmap **catmap); | 135 | struct netlbl_lsm_catmap **catmap); |
136 | int ebitmap_netlbl_import(struct ebitmap *ebmap, | 136 | int ebitmap_netlbl_import(struct ebitmap *ebmap, |
137 | struct netlbl_lsm_secattr_catmap *catmap); | 137 | struct netlbl_lsm_catmap *catmap); |
138 | #else | 138 | #else |
139 | static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, | 139 | static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, |
140 | struct netlbl_lsm_secattr_catmap **catmap) | 140 | struct netlbl_lsm_catmap **catmap) |
141 | { | 141 | { |
142 | return -ENOMEM; | 142 | return -ENOMEM; |
143 | } | 143 | } |
144 | static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, | 144 | static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, |
145 | struct netlbl_lsm_secattr_catmap *catmap) | 145 | struct netlbl_lsm_catmap *catmap) |
146 | { | 146 | { |
147 | return -ENOMEM; | 147 | return -ENOMEM; |
148 | } | 148 | } |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 9c5cdc2caaef..bc2a586f095c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -1080,6 +1080,26 @@ out: | |||
1080 | * binary representation file. | 1080 | * binary representation file. |
1081 | */ | 1081 | */ |
1082 | 1082 | ||
1083 | static int str_read(char **strp, gfp_t flags, void *fp, u32 len) | ||
1084 | { | ||
1085 | int rc; | ||
1086 | char *str; | ||
1087 | |||
1088 | str = kmalloc(len + 1, flags); | ||
1089 | if (!str) | ||
1090 | return -ENOMEM; | ||
1091 | |||
1092 | /* it's expected the caller should free the str */ | ||
1093 | *strp = str; | ||
1094 | |||
1095 | rc = next_entry(str, fp, len); | ||
1096 | if (rc) | ||
1097 | return rc; | ||
1098 | |||
1099 | str[len] = '\0'; | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1083 | static int perm_read(struct policydb *p, struct hashtab *h, void *fp) | 1103 | static int perm_read(struct policydb *p, struct hashtab *h, void *fp) |
1084 | { | 1104 | { |
1085 | char *key = NULL; | 1105 | char *key = NULL; |
@@ -1100,15 +1120,9 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1100 | len = le32_to_cpu(buf[0]); | 1120 | len = le32_to_cpu(buf[0]); |
1101 | perdatum->value = le32_to_cpu(buf[1]); | 1121 | perdatum->value = le32_to_cpu(buf[1]); |
1102 | 1122 | ||
1103 | rc = -ENOMEM; | 1123 | rc = str_read(&key, GFP_KERNEL, fp, len); |
1104 | key = kmalloc(len + 1, GFP_KERNEL); | ||
1105 | if (!key) | ||
1106 | goto bad; | ||
1107 | |||
1108 | rc = next_entry(key, fp, len); | ||
1109 | if (rc) | 1124 | if (rc) |
1110 | goto bad; | 1125 | goto bad; |
1111 | key[len] = '\0'; | ||
1112 | 1126 | ||
1113 | rc = hashtab_insert(h, key, perdatum); | 1127 | rc = hashtab_insert(h, key, perdatum); |
1114 | if (rc) | 1128 | if (rc) |
@@ -1146,15 +1160,9 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1146 | comdatum->permissions.nprim = le32_to_cpu(buf[2]); | 1160 | comdatum->permissions.nprim = le32_to_cpu(buf[2]); |
1147 | nel = le32_to_cpu(buf[3]); | 1161 | nel = le32_to_cpu(buf[3]); |
1148 | 1162 | ||
1149 | rc = -ENOMEM; | 1163 | rc = str_read(&key, GFP_KERNEL, fp, len); |
1150 | key = kmalloc(len + 1, GFP_KERNEL); | ||
1151 | if (!key) | ||
1152 | goto bad; | ||
1153 | |||
1154 | rc = next_entry(key, fp, len); | ||
1155 | if (rc) | 1164 | if (rc) |
1156 | goto bad; | 1165 | goto bad; |
1157 | key[len] = '\0'; | ||
1158 | 1166 | ||
1159 | for (i = 0; i < nel; i++) { | 1167 | for (i = 0; i < nel; i++) { |
1160 | rc = perm_read(p, comdatum->permissions.table, fp); | 1168 | rc = perm_read(p, comdatum->permissions.table, fp); |
@@ -1321,25 +1329,14 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1321 | 1329 | ||
1322 | ncons = le32_to_cpu(buf[5]); | 1330 | ncons = le32_to_cpu(buf[5]); |
1323 | 1331 | ||
1324 | rc = -ENOMEM; | 1332 | rc = str_read(&key, GFP_KERNEL, fp, len); |
1325 | key = kmalloc(len + 1, GFP_KERNEL); | ||
1326 | if (!key) | ||
1327 | goto bad; | ||
1328 | |||
1329 | rc = next_entry(key, fp, len); | ||
1330 | if (rc) | 1333 | if (rc) |
1331 | goto bad; | 1334 | goto bad; |
1332 | key[len] = '\0'; | ||
1333 | 1335 | ||
1334 | if (len2) { | 1336 | if (len2) { |
1335 | rc = -ENOMEM; | 1337 | rc = str_read(&cladatum->comkey, GFP_KERNEL, fp, len2); |
1336 | cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); | ||
1337 | if (!cladatum->comkey) | ||
1338 | goto bad; | ||
1339 | rc = next_entry(cladatum->comkey, fp, len2); | ||
1340 | if (rc) | 1338 | if (rc) |
1341 | goto bad; | 1339 | goto bad; |
1342 | cladatum->comkey[len2] = '\0'; | ||
1343 | 1340 | ||
1344 | rc = -EINVAL; | 1341 | rc = -EINVAL; |
1345 | cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); | 1342 | cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); |
@@ -1422,15 +1419,9 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1422 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 1419 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
1423 | role->bounds = le32_to_cpu(buf[2]); | 1420 | role->bounds = le32_to_cpu(buf[2]); |
1424 | 1421 | ||
1425 | rc = -ENOMEM; | 1422 | rc = str_read(&key, GFP_KERNEL, fp, len); |
1426 | key = kmalloc(len + 1, GFP_KERNEL); | ||
1427 | if (!key) | ||
1428 | goto bad; | ||
1429 | |||
1430 | rc = next_entry(key, fp, len); | ||
1431 | if (rc) | 1423 | if (rc) |
1432 | goto bad; | 1424 | goto bad; |
1433 | key[len] = '\0'; | ||
1434 | 1425 | ||
1435 | rc = ebitmap_read(&role->dominates, fp); | 1426 | rc = ebitmap_read(&role->dominates, fp); |
1436 | if (rc) | 1427 | if (rc) |
@@ -1495,14 +1486,9 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1495 | typdatum->primary = le32_to_cpu(buf[2]); | 1486 | typdatum->primary = le32_to_cpu(buf[2]); |
1496 | } | 1487 | } |
1497 | 1488 | ||
1498 | rc = -ENOMEM; | 1489 | rc = str_read(&key, GFP_KERNEL, fp, len); |
1499 | key = kmalloc(len + 1, GFP_KERNEL); | ||
1500 | if (!key) | ||
1501 | goto bad; | ||
1502 | rc = next_entry(key, fp, len); | ||
1503 | if (rc) | 1490 | if (rc) |
1504 | goto bad; | 1491 | goto bad; |
1505 | key[len] = '\0'; | ||
1506 | 1492 | ||
1507 | rc = hashtab_insert(h, key, typdatum); | 1493 | rc = hashtab_insert(h, key, typdatum); |
1508 | if (rc) | 1494 | if (rc) |
@@ -1565,14 +1551,9 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1565 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 1551 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
1566 | usrdatum->bounds = le32_to_cpu(buf[2]); | 1552 | usrdatum->bounds = le32_to_cpu(buf[2]); |
1567 | 1553 | ||
1568 | rc = -ENOMEM; | 1554 | rc = str_read(&key, GFP_KERNEL, fp, len); |
1569 | key = kmalloc(len + 1, GFP_KERNEL); | ||
1570 | if (!key) | ||
1571 | goto bad; | ||
1572 | rc = next_entry(key, fp, len); | ||
1573 | if (rc) | 1555 | if (rc) |
1574 | goto bad; | 1556 | goto bad; |
1575 | key[len] = '\0'; | ||
1576 | 1557 | ||
1577 | rc = ebitmap_read(&usrdatum->roles, fp); | 1558 | rc = ebitmap_read(&usrdatum->roles, fp); |
1578 | if (rc) | 1559 | if (rc) |
@@ -1616,14 +1597,9 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1616 | len = le32_to_cpu(buf[0]); | 1597 | len = le32_to_cpu(buf[0]); |
1617 | levdatum->isalias = le32_to_cpu(buf[1]); | 1598 | levdatum->isalias = le32_to_cpu(buf[1]); |
1618 | 1599 | ||
1619 | rc = -ENOMEM; | 1600 | rc = str_read(&key, GFP_ATOMIC, fp, len); |
1620 | key = kmalloc(len + 1, GFP_ATOMIC); | ||
1621 | if (!key) | ||
1622 | goto bad; | ||
1623 | rc = next_entry(key, fp, len); | ||
1624 | if (rc) | 1601 | if (rc) |
1625 | goto bad; | 1602 | goto bad; |
1626 | key[len] = '\0'; | ||
1627 | 1603 | ||
1628 | rc = -ENOMEM; | 1604 | rc = -ENOMEM; |
1629 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); | 1605 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); |
@@ -1664,14 +1640,9 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1664 | catdatum->value = le32_to_cpu(buf[1]); | 1640 | catdatum->value = le32_to_cpu(buf[1]); |
1665 | catdatum->isalias = le32_to_cpu(buf[2]); | 1641 | catdatum->isalias = le32_to_cpu(buf[2]); |
1666 | 1642 | ||
1667 | rc = -ENOMEM; | 1643 | rc = str_read(&key, GFP_ATOMIC, fp, len); |
1668 | key = kmalloc(len + 1, GFP_ATOMIC); | ||
1669 | if (!key) | ||
1670 | goto bad; | ||
1671 | rc = next_entry(key, fp, len); | ||
1672 | if (rc) | 1644 | if (rc) |
1673 | goto bad; | 1645 | goto bad; |
1674 | key[len] = '\0'; | ||
1675 | 1646 | ||
1676 | rc = hashtab_insert(h, key, catdatum); | 1647 | rc = hashtab_insert(h, key, catdatum); |
1677 | if (rc) | 1648 | if (rc) |
@@ -1968,18 +1939,12 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
1968 | goto out; | 1939 | goto out; |
1969 | len = le32_to_cpu(buf[0]); | 1940 | len = le32_to_cpu(buf[0]); |
1970 | 1941 | ||
1971 | rc = -ENOMEM; | ||
1972 | name = kmalloc(len + 1, GFP_KERNEL); | ||
1973 | if (!name) | ||
1974 | goto out; | ||
1975 | |||
1976 | ft->name = name; | ||
1977 | |||
1978 | /* path component string */ | 1942 | /* path component string */ |
1979 | rc = next_entry(name, fp, len); | 1943 | rc = str_read(&name, GFP_KERNEL, fp, len); |
1980 | if (rc) | 1944 | if (rc) |
1981 | goto out; | 1945 | goto out; |
1982 | name[len] = 0; | 1946 | |
1947 | ft->name = name; | ||
1983 | 1948 | ||
1984 | rc = next_entry(buf, fp, sizeof(u32) * 4); | 1949 | rc = next_entry(buf, fp, sizeof(u32) * 4); |
1985 | if (rc) | 1950 | if (rc) |
@@ -2045,17 +2010,10 @@ static int genfs_read(struct policydb *p, void *fp) | |||
2045 | if (!newgenfs) | 2010 | if (!newgenfs) |
2046 | goto out; | 2011 | goto out; |
2047 | 2012 | ||
2048 | rc = -ENOMEM; | 2013 | rc = str_read(&newgenfs->fstype, GFP_KERNEL, fp, len); |
2049 | newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL); | ||
2050 | if (!newgenfs->fstype) | ||
2051 | goto out; | ||
2052 | |||
2053 | rc = next_entry(newgenfs->fstype, fp, len); | ||
2054 | if (rc) | 2014 | if (rc) |
2055 | goto out; | 2015 | goto out; |
2056 | 2016 | ||
2057 | newgenfs->fstype[len] = 0; | ||
2058 | |||
2059 | for (genfs_p = NULL, genfs = p->genfs; genfs; | 2017 | for (genfs_p = NULL, genfs = p->genfs; genfs; |
2060 | genfs_p = genfs, genfs = genfs->next) { | 2018 | genfs_p = genfs, genfs = genfs->next) { |
2061 | rc = -EINVAL; | 2019 | rc = -EINVAL; |
@@ -2091,15 +2049,9 @@ static int genfs_read(struct policydb *p, void *fp) | |||
2091 | if (!newc) | 2049 | if (!newc) |
2092 | goto out; | 2050 | goto out; |
2093 | 2051 | ||
2094 | rc = -ENOMEM; | 2052 | rc = str_read(&newc->u.name, GFP_KERNEL, fp, len); |
2095 | newc->u.name = kmalloc(len + 1, GFP_KERNEL); | ||
2096 | if (!newc->u.name) | ||
2097 | goto out; | ||
2098 | |||
2099 | rc = next_entry(newc->u.name, fp, len); | ||
2100 | if (rc) | 2053 | if (rc) |
2101 | goto out; | 2054 | goto out; |
2102 | newc->u.name[len] = 0; | ||
2103 | 2055 | ||
2104 | rc = next_entry(buf, fp, sizeof(u32)); | 2056 | rc = next_entry(buf, fp, sizeof(u32)); |
2105 | if (rc) | 2057 | if (rc) |
@@ -2189,16 +2141,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
2189 | goto out; | 2141 | goto out; |
2190 | len = le32_to_cpu(buf[0]); | 2142 | len = le32_to_cpu(buf[0]); |
2191 | 2143 | ||
2192 | rc = -ENOMEM; | 2144 | rc = str_read(&c->u.name, GFP_KERNEL, fp, len); |
2193 | c->u.name = kmalloc(len + 1, GFP_KERNEL); | ||
2194 | if (!c->u.name) | ||
2195 | goto out; | ||
2196 | |||
2197 | rc = next_entry(c->u.name, fp, len); | ||
2198 | if (rc) | 2145 | if (rc) |
2199 | goto out; | 2146 | goto out; |
2200 | 2147 | ||
2201 | c->u.name[len] = 0; | ||
2202 | rc = context_read_and_validate(&c->context[0], p, fp); | 2148 | rc = context_read_and_validate(&c->context[0], p, fp); |
2203 | if (rc) | 2149 | if (rc) |
2204 | goto out; | 2150 | goto out; |
@@ -2240,16 +2186,11 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
2240 | if (c->v.behavior > SECURITY_FS_USE_MAX) | 2186 | if (c->v.behavior > SECURITY_FS_USE_MAX) |
2241 | goto out; | 2187 | goto out; |
2242 | 2188 | ||
2243 | rc = -ENOMEM; | ||
2244 | len = le32_to_cpu(buf[1]); | 2189 | len = le32_to_cpu(buf[1]); |
2245 | c->u.name = kmalloc(len + 1, GFP_KERNEL); | 2190 | rc = str_read(&c->u.name, GFP_KERNEL, fp, len); |
2246 | if (!c->u.name) | ||
2247 | goto out; | ||
2248 | |||
2249 | rc = next_entry(c->u.name, fp, len); | ||
2250 | if (rc) | 2191 | if (rc) |
2251 | goto out; | 2192 | goto out; |
2252 | c->u.name[len] = 0; | 2193 | |
2253 | rc = context_read_and_validate(&c->context[0], p, fp); | 2194 | rc = context_read_and_validate(&c->context[0], p, fp); |
2254 | if (rc) | 2195 | if (rc) |
2255 | goto out; | 2196 | goto out; |
@@ -2608,7 +2549,7 @@ static int mls_write_range_helper(struct mls_range *r, void *fp) | |||
2608 | if (!eq) | 2549 | if (!eq) |
2609 | buf[2] = cpu_to_le32(r->level[1].sens); | 2550 | buf[2] = cpu_to_le32(r->level[1].sens); |
2610 | 2551 | ||
2611 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | 2552 | BUG_ON(items > ARRAY_SIZE(buf)); |
2612 | 2553 | ||
2613 | rc = put_entry(buf, sizeof(u32), items, fp); | 2554 | rc = put_entry(buf, sizeof(u32), items, fp); |
2614 | if (rc) | 2555 | if (rc) |
@@ -2990,7 +2931,7 @@ static int role_write(void *vkey, void *datum, void *ptr) | |||
2990 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 2931 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
2991 | buf[items++] = cpu_to_le32(role->bounds); | 2932 | buf[items++] = cpu_to_le32(role->bounds); |
2992 | 2933 | ||
2993 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | 2934 | BUG_ON(items > ARRAY_SIZE(buf)); |
2994 | 2935 | ||
2995 | rc = put_entry(buf, sizeof(u32), items, fp); | 2936 | rc = put_entry(buf, sizeof(u32), items, fp); |
2996 | if (rc) | 2937 | if (rc) |
@@ -3040,7 +2981,7 @@ static int type_write(void *vkey, void *datum, void *ptr) | |||
3040 | } else { | 2981 | } else { |
3041 | buf[items++] = cpu_to_le32(typdatum->primary); | 2982 | buf[items++] = cpu_to_le32(typdatum->primary); |
3042 | } | 2983 | } |
3043 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | 2984 | BUG_ON(items > ARRAY_SIZE(buf)); |
3044 | rc = put_entry(buf, sizeof(u32), items, fp); | 2985 | rc = put_entry(buf, sizeof(u32), items, fp); |
3045 | if (rc) | 2986 | if (rc) |
3046 | return rc; | 2987 | return rc; |
@@ -3069,7 +3010,7 @@ static int user_write(void *vkey, void *datum, void *ptr) | |||
3069 | buf[items++] = cpu_to_le32(usrdatum->value); | 3010 | buf[items++] = cpu_to_le32(usrdatum->value); |
3070 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 3011 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
3071 | buf[items++] = cpu_to_le32(usrdatum->bounds); | 3012 | buf[items++] = cpu_to_le32(usrdatum->bounds); |
3072 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | 3013 | BUG_ON(items > ARRAY_SIZE(buf)); |
3073 | rc = put_entry(buf, sizeof(u32), items, fp); | 3014 | rc = put_entry(buf, sizeof(u32), items, fp); |
3074 | if (rc) | 3015 | if (rc) |
3075 | return rc; | 3016 | return rc; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4bca49414a40..2aa9d172dc7e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2277,7 +2277,7 @@ out: | |||
2277 | } | 2277 | } |
2278 | 2278 | ||
2279 | /** | 2279 | /** |
2280 | * security_genfs_sid - Obtain a SID for a file in a filesystem | 2280 | * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem |
2281 | * @fstype: filesystem type | 2281 | * @fstype: filesystem type |
2282 | * @path: path from root of mount | 2282 | * @path: path from root of mount |
2283 | * @sclass: file security class | 2283 | * @sclass: file security class |
@@ -2286,11 +2286,13 @@ out: | |||
2286 | * Obtain a SID to use for a file in a filesystem that | 2286 | * Obtain a SID to use for a file in a filesystem that |
2287 | * cannot support xattr or use a fixed labeling behavior like | 2287 | * cannot support xattr or use a fixed labeling behavior like |
2288 | * transition SIDs or task SIDs. | 2288 | * transition SIDs or task SIDs. |
2289 | * | ||
2290 | * The caller must acquire the policy_rwlock before calling this function. | ||
2289 | */ | 2291 | */ |
2290 | int security_genfs_sid(const char *fstype, | 2292 | static inline int __security_genfs_sid(const char *fstype, |
2291 | char *path, | 2293 | char *path, |
2292 | u16 orig_sclass, | 2294 | u16 orig_sclass, |
2293 | u32 *sid) | 2295 | u32 *sid) |
2294 | { | 2296 | { |
2295 | int len; | 2297 | int len; |
2296 | u16 sclass; | 2298 | u16 sclass; |
@@ -2301,8 +2303,6 @@ int security_genfs_sid(const char *fstype, | |||
2301 | while (path[0] == '/' && path[1] == '/') | 2303 | while (path[0] == '/' && path[1] == '/') |
2302 | path++; | 2304 | path++; |
2303 | 2305 | ||
2304 | read_lock(&policy_rwlock); | ||
2305 | |||
2306 | sclass = unmap_class(orig_sclass); | 2306 | sclass = unmap_class(orig_sclass); |
2307 | *sid = SECINITSID_UNLABELED; | 2307 | *sid = SECINITSID_UNLABELED; |
2308 | 2308 | ||
@@ -2336,11 +2336,33 @@ int security_genfs_sid(const char *fstype, | |||
2336 | *sid = c->sid[0]; | 2336 | *sid = c->sid[0]; |
2337 | rc = 0; | 2337 | rc = 0; |
2338 | out: | 2338 | out: |
2339 | read_unlock(&policy_rwlock); | ||
2340 | return rc; | 2339 | return rc; |
2341 | } | 2340 | } |
2342 | 2341 | ||
2343 | /** | 2342 | /** |
2343 | * security_genfs_sid - Obtain a SID for a file in a filesystem | ||
2344 | * @fstype: filesystem type | ||
2345 | * @path: path from root of mount | ||
2346 | * @sclass: file security class | ||
2347 | * @sid: SID for path | ||
2348 | * | ||
2349 | * Acquire policy_rwlock before calling __security_genfs_sid() and release | ||
2350 | * it afterward. | ||
2351 | */ | ||
2352 | int security_genfs_sid(const char *fstype, | ||
2353 | char *path, | ||
2354 | u16 orig_sclass, | ||
2355 | u32 *sid) | ||
2356 | { | ||
2357 | int retval; | ||
2358 | |||
2359 | read_lock(&policy_rwlock); | ||
2360 | retval = __security_genfs_sid(fstype, path, orig_sclass, sid); | ||
2361 | read_unlock(&policy_rwlock); | ||
2362 | return retval; | ||
2363 | } | ||
2364 | |||
2365 | /** | ||
2344 | * security_fs_use - Determine how to handle labeling for a filesystem. | 2366 | * security_fs_use - Determine how to handle labeling for a filesystem. |
2345 | * @sb: superblock in question | 2367 | * @sb: superblock in question |
2346 | */ | 2368 | */ |
@@ -2370,7 +2392,8 @@ int security_fs_use(struct super_block *sb) | |||
2370 | } | 2392 | } |
2371 | sbsec->sid = c->sid[0]; | 2393 | sbsec->sid = c->sid[0]; |
2372 | } else { | 2394 | } else { |
2373 | rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid); | 2395 | rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR, |
2396 | &sbsec->sid); | ||
2374 | if (rc) { | 2397 | if (rc) { |
2375 | sbsec->behavior = SECURITY_FS_USE_NONE; | 2398 | sbsec->behavior = SECURITY_FS_USE_NONE; |
2376 | rc = 0; | 2399 | rc = 0; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index c062e9467b62..f97d0842e621 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -457,19 +457,16 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, | |||
457 | 457 | ||
458 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | 458 | sap->flags |= NETLBL_SECATTR_MLS_CAT; |
459 | sap->attr.mls.lvl = level; | 459 | sap->attr.mls.lvl = level; |
460 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | 460 | sap->attr.mls.cat = NULL; |
461 | if (!sap->attr.mls.cat) | ||
462 | return -ENOMEM; | ||
463 | sap->attr.mls.cat->startbit = 0; | ||
464 | 461 | ||
465 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) | 462 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) |
466 | for (m = 0x80; m != 0; m >>= 1, cat++) { | 463 | for (m = 0x80; m != 0; m >>= 1, cat++) { |
467 | if ((m & *cp) == 0) | 464 | if ((m & *cp) == 0) |
468 | continue; | 465 | continue; |
469 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | 466 | rc = netlbl_catmap_setbit(&sap->attr.mls.cat, |
470 | cat, GFP_ATOMIC); | 467 | cat, GFP_ATOMIC); |
471 | if (rc < 0) { | 468 | if (rc < 0) { |
472 | netlbl_secattr_catmap_free(sap->attr.mls.cat); | 469 | netlbl_catmap_free(sap->attr.mls.cat); |
473 | return rc; | 470 | return rc; |
474 | } | 471 | } |
475 | } | 472 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index f2c30801ce41..e6ab307ce86e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -3209,9 +3209,9 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
3209 | break; | 3209 | break; |
3210 | } | 3210 | } |
3211 | for (acat = -1, kcat = -1; acat == kcat; ) { | 3211 | for (acat = -1, kcat = -1; acat == kcat; ) { |
3212 | acat = netlbl_secattr_catmap_walk( | 3212 | acat = netlbl_catmap_walk(sap->attr.mls.cat, |
3213 | sap->attr.mls.cat, acat + 1); | 3213 | acat + 1); |
3214 | kcat = netlbl_secattr_catmap_walk( | 3214 | kcat = netlbl_catmap_walk( |
3215 | skp->smk_netlabel.attr.mls.cat, | 3215 | skp->smk_netlabel.attr.mls.cat, |
3216 | kcat + 1); | 3216 | kcat + 1); |
3217 | if (acat < 0 || kcat < 0) | 3217 | if (acat < 0 || kcat < 0) |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 32b248820840..3c720ff10591 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -787,7 +787,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
787 | struct list_head *list = v; | 787 | struct list_head *list = v; |
788 | struct smack_known *skp = | 788 | struct smack_known *skp = |
789 | list_entry(list, struct smack_known, list); | 789 | list_entry(list, struct smack_known, list); |
790 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | 790 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
791 | char sep = '/'; | 791 | char sep = '/'; |
792 | int i; | 792 | int i; |
793 | 793 | ||
@@ -804,8 +804,8 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
804 | 804 | ||
805 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | 805 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
806 | 806 | ||
807 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | 807 | for (i = netlbl_catmap_walk(cmp, 0); i >= 0; |
808 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | 808 | i = netlbl_catmap_walk(cmp, i + 1)) { |
809 | seq_printf(s, "%c%d", sep, i); | 809 | seq_printf(s, "%c%d", sep, i); |
810 | sep = ','; | 810 | sep = ','; |
811 | } | 811 | } |
@@ -926,7 +926,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, | |||
926 | 926 | ||
927 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); | 927 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); |
928 | if (rc >= 0) { | 928 | if (rc >= 0) { |
929 | netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); | 929 | netlbl_catmap_free(skp->smk_netlabel.attr.mls.cat); |
930 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; | 930 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; |
931 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; | 931 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; |
932 | rc = count; | 932 | rc = count; |
@@ -976,14 +976,14 @@ static int cipso2_seq_show(struct seq_file *s, void *v) | |||
976 | struct list_head *list = v; | 976 | struct list_head *list = v; |
977 | struct smack_known *skp = | 977 | struct smack_known *skp = |
978 | list_entry(list, struct smack_known, list); | 978 | list_entry(list, struct smack_known, list); |
979 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | 979 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
980 | char sep = '/'; | 980 | char sep = '/'; |
981 | int i; | 981 | int i; |
982 | 982 | ||
983 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | 983 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
984 | 984 | ||
985 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | 985 | for (i = netlbl_catmap_walk(cmp, 0); i >= 0; |
986 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | 986 | i = netlbl_catmap_walk(cmp, i + 1)) { |
987 | seq_printf(s, "%c%d", sep, i); | 987 | seq_printf(s, "%c%d", sep, i); |
988 | sep = ','; | 988 | sep = ','; |
989 | } | 989 | } |