From 98f368e9e2630a3ce3e80fb10fb2e02038cf9578 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 2 Jun 2016 23:43:21 -0500 Subject: kernel: Add noaudit variant of ns_capable() When checking the current cred for a capability in a specific user namespace, it isn't always desirable to have the LSMs audit the check. This patch adds a noaudit variant of ns_capable() for when those situations arise. The common logic between ns_capable() and the new ns_capable_noaudit() is moved into a single, shared function to keep duplicated code to a minimum and ease maintainability. Signed-off-by: Tyler Hicks Acked-by: Serge E. Hallyn Signed-off-by: James Morris --- include/linux/capability.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/capability.h b/include/linux/capability.h index 00690ff92edf..5f3c63dde2d5 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -206,6 +206,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, struct user_namespace *ns, int cap); extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); +extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); #else static inline bool has_capability(struct task_struct *t, int cap) { @@ -233,6 +234,10 @@ static inline bool ns_capable(struct user_namespace *ns, int cap) { return true; } +static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) +{ + return true; +} #endif /* CONFIG_MULTIUSER */ extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); -- cgit v1.2.3 From 2f275de5d1ed7269913ef9b4c64a13952c0a38e8 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 27 May 2016 12:57:02 -0700 Subject: seccomp: Add a seccomp_data parameter secure_computing() Currently, if arch code wants to supply seccomp_data directly to seccomp (which is generally much faster than having seccomp do it using the syscall_get_xyz() API), it has to use the two-phase seccomp hooks. Add it to the easy hooks, too. Cc: linux-arch@vger.kernel.org Signed-off-by: Andy Lutomirski Signed-off-by: Kees Cook --- arch/arm/kernel/ptrace.c | 2 +- arch/arm64/kernel/ptrace.c | 2 +- arch/mips/kernel/ptrace.c | 2 +- arch/parisc/kernel/ptrace.c | 2 +- arch/powerpc/kernel/ptrace.c | 2 +- arch/s390/kernel/ptrace.c | 2 +- arch/tile/kernel/ptrace.c | 2 +- arch/um/kernel/skas/syscall.c | 2 +- arch/x86/entry/vsyscall/vsyscall_64.c | 2 +- include/linux/seccomp.h | 8 ++++---- kernel/seccomp.c | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 4d9375814b53..1027d3b54541 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -934,7 +934,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno) /* Do the secure computing check first; failures should be fast. */ #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; #else /* XXX: remove this once OABI gets fixed */ diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 3f6cd5c5234f..6e2cf046615d 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -1247,7 +1247,7 @@ static void tracehook_report_syscall(struct pt_regs *regs, asmlinkage int syscall_trace_enter(struct pt_regs *regs) { /* Do the secure computing check first; failures should be fast. */ - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 0dcf69194473..c50af846ecf9 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -893,7 +893,7 @@ asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall) current_thread_info()->syscall = syscall; - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE) && diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index b5458b37fc5b..8edc47c0b98e 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -312,7 +312,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, long do_syscall_trace_enter(struct pt_regs *regs) { /* Do the secure computing check first. */ - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (test_thread_flag(TIF_SYSCALL_TRACE) && diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 30a03c03fe73..ed799e994773 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -1783,7 +1783,7 @@ static int do_seccomp(struct pt_regs *regs) * have already loaded -ENOSYS into r3, or seccomp has put * something else in r3 (via SECCOMP_RET_ERRNO/TRACE). */ - if (__secure_computing()) + if (__secure_computing(NULL)) return -1; /* diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 49b1c13bf6c9..c238e9958c2a 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -824,7 +824,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) long ret = 0; /* Do the secure computing check first. */ - if (secure_computing()) { + if (secure_computing(NULL)) { /* seccomp failures shouldn't expose any additional code. */ ret = -1; goto out; diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index 54e7b723db99..8c6d2f2fefa3 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c @@ -255,7 +255,7 @@ int do_syscall_trace_enter(struct pt_regs *regs) { u32 work = ACCESS_ONCE(current_thread_info()->flags); - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return -1; if (work & _TIF_SYSCALL_TRACE) { diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 48b0dcbd87be..9c5570f0f397 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -21,7 +21,7 @@ void handle_syscall(struct uml_pt_regs *r) PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS); /* Do the secure computing check first; failures should be fast. */ - if (secure_computing() == -1) + if (secure_computing(NULL) == -1) return; if (syscall_trace_enter(regs)) diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 174c2549939d..85acde5fa442 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -207,7 +207,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) */ regs->orig_ax = syscall_nr; regs->ax = -ENOSYS; - tmp = secure_computing(); + tmp = secure_computing(NULL); if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) { warn_bad_vsyscall(KERN_DEBUG, regs, "seccomp tried to change syscall nr or ip"); diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 2296e6b2f690..9eaa7b34d6da 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -28,11 +28,11 @@ struct seccomp { }; #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER -extern int __secure_computing(void); -static inline int secure_computing(void) +extern int __secure_computing(const struct seccomp_data *sd); +static inline int secure_computing(const struct seccomp_data *sd) { if (unlikely(test_thread_flag(TIF_SECCOMP))) - return __secure_computing(); + return __secure_computing(sd); return 0; } @@ -61,7 +61,7 @@ struct seccomp { }; struct seccomp_filter { }; #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER -static inline int secure_computing(void) { return 0; } +static inline int secure_computing(struct seccomp_data *sd) { return 0; } #else static inline void secure_computing_strict(int this_syscall) { return; } #endif diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 7002796f14a4..06816290a212 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -554,9 +554,9 @@ void secure_computing_strict(int this_syscall) BUG(); } #else -int __secure_computing(void) +int __secure_computing(const struct seccomp_data *sd) { - u32 phase1_result = seccomp_phase1(NULL); + u32 phase1_result = seccomp_phase1(sd); if (likely(phase1_result == SECCOMP_PHASE1_OK)) return 0; -- cgit v1.2.3 From 8112c4f140fa03f9ee68aad2cc79afa7df5418d3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 1 Jun 2016 16:02:17 -0700 Subject: seccomp: remove 2-phase API Since nothing is using the 2-phase API, and it adds more complexity than benefit, remove it. Signed-off-by: Kees Cook Cc: Andy Lutomirski --- include/linux/seccomp.h | 6 --- kernel/seccomp.c | 129 +++++++++++++++--------------------------------- 2 files changed, 41 insertions(+), 94 deletions(-) (limited to 'include/linux') diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 9eaa7b34d6da..ecc296c137cd 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -35,12 +35,6 @@ static inline int secure_computing(const struct seccomp_data *sd) return __secure_computing(sd); return 0; } - -#define SECCOMP_PHASE1_OK 0 -#define SECCOMP_PHASE1_SKIP 1 - -extern u32 seccomp_phase1(struct seccomp_data *sd); -int seccomp_phase2(u32 phase1_result); #else extern void secure_computing_strict(int this_syscall); #endif diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 06816290a212..14a37d71b612 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -173,7 +173,7 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) * * Returns valid seccomp BPF response codes. */ -static u32 seccomp_run_filters(struct seccomp_data *sd) +static u32 seccomp_run_filters(const struct seccomp_data *sd) { struct seccomp_data sd_local; u32 ret = SECCOMP_RET_ALLOW; @@ -554,20 +554,9 @@ void secure_computing_strict(int this_syscall) BUG(); } #else -int __secure_computing(const struct seccomp_data *sd) -{ - u32 phase1_result = seccomp_phase1(sd); - - if (likely(phase1_result == SECCOMP_PHASE1_OK)) - return 0; - else if (likely(phase1_result == SECCOMP_PHASE1_SKIP)) - return -1; - else - return seccomp_phase2(phase1_result); -} #ifdef CONFIG_SECCOMP_FILTER -static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) +static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) { u32 filter_ret, action; int data; @@ -599,10 +588,33 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) goto skip; case SECCOMP_RET_TRACE: - return filter_ret; /* Save the rest for phase 2. */ + /* ENOSYS these calls if there is no tracer attached. */ + if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { + syscall_set_return_value(current, + task_pt_regs(current), + -ENOSYS, 0); + goto skip; + } + + /* Allow the BPF to provide the event message */ + ptrace_event(PTRACE_EVENT_SECCOMP, data); + /* + * The delivery of a fatal signal during event + * notification may silently skip tracer notification. + * Terminating the task now avoids executing a system + * call that may not be intended. + */ + if (fatal_signal_pending(current)) + do_exit(SIGSYS); + /* Check if the tracer forced the syscall to be skipped. */ + this_syscall = syscall_get_nr(current, task_pt_regs(current)); + if (this_syscall < 0) + goto skip; + + return 0; case SECCOMP_RET_ALLOW: - return SECCOMP_PHASE1_OK; + return 0; case SECCOMP_RET_KILL: default: @@ -614,96 +626,37 @@ static u32 __seccomp_phase1_filter(int this_syscall, struct seccomp_data *sd) skip: audit_seccomp(this_syscall, 0, action); - return SECCOMP_PHASE1_SKIP; + return -1; +} +#else +static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd) +{ + BUG(); } #endif -/** - * seccomp_phase1() - run fast path seccomp checks on the current syscall - * @arg sd: The seccomp_data or NULL - * - * This only reads pt_regs via the syscall_xyz helpers. The only change - * it will make to pt_regs is via syscall_set_return_value, and it will - * only do that if it returns SECCOMP_PHASE1_SKIP. - * - * If sd is provided, it will not read pt_regs at all. - * - * It may also call do_exit or force a signal; these actions must be - * safe. - * - * If it returns SECCOMP_PHASE1_OK, the syscall passes checks and should - * be processed normally. - * - * If it returns SECCOMP_PHASE1_SKIP, then the syscall should not be - * invoked. In this case, seccomp_phase1 will have set the return value - * using syscall_set_return_value. - * - * If it returns anything else, then the return value should be passed - * to seccomp_phase2 from a context in which ptrace hooks are safe. - */ -u32 seccomp_phase1(struct seccomp_data *sd) +int __secure_computing(const struct seccomp_data *sd) { int mode = current->seccomp.mode; - int this_syscall = sd ? sd->nr : - syscall_get_nr(current, task_pt_regs(current)); + int this_syscall; if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) - return SECCOMP_PHASE1_OK; + return 0; + + this_syscall = sd ? sd->nr : + syscall_get_nr(current, task_pt_regs(current)); switch (mode) { case SECCOMP_MODE_STRICT: __secure_computing_strict(this_syscall); /* may call do_exit */ - return SECCOMP_PHASE1_OK; -#ifdef CONFIG_SECCOMP_FILTER + return 0; case SECCOMP_MODE_FILTER: - return __seccomp_phase1_filter(this_syscall, sd); -#endif + return __seccomp_filter(this_syscall, sd); default: BUG(); } } - -/** - * seccomp_phase2() - finish slow path seccomp work for the current syscall - * @phase1_result: The return value from seccomp_phase1() - * - * This must be called from a context in which ptrace hooks can be used. - * - * Returns 0 if the syscall should be processed or -1 to skip the syscall. - */ -int seccomp_phase2(u32 phase1_result) -{ - struct pt_regs *regs = task_pt_regs(current); - u32 action = phase1_result & SECCOMP_RET_ACTION; - int data = phase1_result & SECCOMP_RET_DATA; - - BUG_ON(action != SECCOMP_RET_TRACE); - - audit_seccomp(syscall_get_nr(current, regs), 0, action); - - /* Skip these calls if there is no tracer. */ - if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { - syscall_set_return_value(current, regs, - -ENOSYS, 0); - return -1; - } - - /* Allow the BPF to provide the event message */ - ptrace_event(PTRACE_EVENT_SECCOMP, data); - /* - * The delivery of a fatal signal during event - * notification may silently skip tracer notification. - * Terminating the task now avoids executing a system - * call that may not be intended. - */ - if (fatal_signal_pending(current)) - do_exit(SIGSYS); - if (syscall_get_nr(current, regs) < 0) - return -1; /* Explicit request to skip. */ - - return 0; -} #endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */ long prctl_get_seccomp(void) -- cgit v1.2.3 From 2c2b217a13ed11ff6d8f4583f9bee3a54e8f1034 Mon Sep 17 00:00:00 2001 From: Christophe RICARD Date: Sat, 13 Feb 2016 16:15:31 +0100 Subject: tpm/st33zp24: Extend Copyright headers Extend copyright header to 2016 Signed-off-by: Christophe Ricard Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/st33zp24/i2c.c | 2 +- drivers/char/tpm/st33zp24/spi.c | 2 +- drivers/char/tpm/st33zp24/st33zp24.c | 2 +- drivers/char/tpm/st33zp24/st33zp24.h | 2 +- include/linux/platform_data/st33zp24.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c index a05fbd8bddf0..a49b6f10836d 100644 --- a/drivers/char/tpm/st33zp24/i2c.c +++ b/drivers/char/tpm/st33zp24/i2c.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c index a2ef8ec4ba80..eb351ba48689 100644 --- a/drivers/char/tpm/st33zp24/spi.c +++ b/drivers/char/tpm/st33zp24/spi.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM SPI Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 8d626784cd8d..944d279f2402 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/char/tpm/st33zp24/st33zp24.h b/drivers/char/tpm/st33zp24/st33zp24.h index c207cebf67dd..bcbd5ffbdaa5 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.h +++ b/drivers/char/tpm/st33zp24/st33zp24.h @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM Linux driver for TPM ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/include/linux/platform_data/st33zp24.h b/include/linux/platform_data/st33zp24.h index 817dfdb37885..6f0fb6ebd7db 100644 --- a/include/linux/platform_data/st33zp24.h +++ b/include/linux/platform_data/st33zp24.h @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM Linux driver for TPM 1.2 ST33ZP24 - * Copyright (C) 2009 - 2015 STMicroelectronics + * Copyright (C) 2009 - 2016 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From cae8b441fc20812d7260dc3b45e05ee98fcfff1b Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 12 Jul 2016 11:41:49 -0600 Subject: tpm: Factor out common startup code The TCG standard startup sequence (get timeouts, tpm startup, etc) for TPM and TPM2 chips is being open coded in many drivers, move it into the core code. tpm_tis and tpm_crb are used as the basis for the core code implementation and the easy drivers are converted. In the process several small drivers bugs relating to error handling this flow are fixed. For now the flag TPM_OPS_AUTO_STARTUP is optional to allow a staged driver roll out, but ultimately all drivers should use this flow and the flag removed. Some drivers still do not implement the startup sequence at all and will need to be tested with it enabled. Signed-off-by: Jason Gunthorpe Tested-by: Andrew Zamansky Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/st33zp24/st33zp24.c | 4 +--- drivers/char/tpm/tpm-chip.c | 9 +++++++ drivers/char/tpm/tpm-interface.c | 27 +++++++++++++++++++++ drivers/char/tpm/tpm.h | 4 ++-- drivers/char/tpm/tpm2-cmd.c | 46 ++++++++++++++++++++++++++++++++---- drivers/char/tpm/tpm_crb.c | 10 +------- drivers/char/tpm/tpm_i2c_atmel.c | 6 +---- drivers/char/tpm/tpm_i2c_infineon.c | 4 +--- drivers/char/tpm/tpm_i2c_nuvoton.c | 7 +----- drivers/char/tpm/tpm_tis_core.c | 24 +------------------ drivers/char/tpm/tpm_vtpm_proxy.c | 9 +------ include/linux/tpm.h | 5 ++++ 12 files changed, 92 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index a7c99a284724..c2ee30451e41 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -505,6 +505,7 @@ static bool st33zp24_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops st33zp24_tpm = { + .flags = TPM_OPS_AUTO_STARTUP, .send = st33zp24_send, .recv = st33zp24_recv, .cancel = st33zp24_cancel, @@ -592,9 +593,6 @@ int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, tpm_gen_interrupt(chip); } - tpm_get_timeouts(chip); - tpm_do_selftest(chip); - return tpm_chip_register(chip); _tpm_clean_answer: dev_info(&chip->dev, "TPM initialization fail\n"); diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 5a2f0439ef47..e5950131bd90 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -354,6 +354,15 @@ int tpm_chip_register(struct tpm_chip *chip) { int rc; + if (chip->ops->flags & TPM_OPS_AUTO_STARTUP) { + if (chip->flags & TPM_CHIP_FLAG_TPM2) + rc = tpm2_auto_startup(chip); + else + rc = tpm1_auto_startup(chip); + if (rc) + return rc; + } + rc = tpm1_chip_register(chip); if (rc) return rc; diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 5e3c1b684859..1abe2d7a2610 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -843,6 +843,33 @@ int tpm_do_selftest(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm_do_selftest); +/** + * tpm1_auto_startup - Perform the standard automatic TPM initialization + * sequence + * @chip: TPM chip to use + * + * Returns 0 on success, < 0 in case of fatal error. + */ +int tpm1_auto_startup(struct tpm_chip *chip) +{ + int rc; + + rc = tpm_get_timeouts(chip); + if (rc) + goto out; + rc = tpm_do_selftest(chip); + if (rc) { + dev_err(&chip->dev, "TPM self test failed\n"); + goto out; + } + + return rc; +out: + if (rc > 0) + rc = -ENODEV; + return rc; +} + int tpm_send(u32 chip_num, void *cmd, size_t buflen) { struct tpm_chip *chip; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8890df205635..3e32d5bd2dc6 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -484,6 +484,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len, const char *desc); extern int tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); +int tpm1_auto_startup(struct tpm_chip *chip); extern int tpm_do_selftest(struct tpm_chip *); extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); extern int tpm_pm_suspend(struct device *); @@ -526,10 +527,9 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc); -extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); +int tpm2_auto_startup(struct tpm_chip *chip); extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); -extern int tpm2_do_selftest(struct tpm_chip *chip); extern int tpm2_gen_interrupt(struct tpm_chip *chip); extern int tpm2_probe(struct tpm_chip *chip); #endif diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index a88b31e7fe72..08c7e23ed535 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -728,7 +728,7 @@ static const struct tpm_input_header tpm2_startup_header = { * returned it remarks a POSIX error code. If a positive number is returned * it remarks a TPM error. */ -int tpm2_startup(struct tpm_chip *chip, u16 startup_type) +static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) { struct tpm2_cmd cmd; @@ -738,7 +738,6 @@ int tpm2_startup(struct tpm_chip *chip, u16 startup_type) return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "attempting to start the TPM"); } -EXPORT_SYMBOL_GPL(tpm2_startup); #define TPM2_SHUTDOWN_IN_SIZE \ (sizeof(struct tpm_input_header) + \ @@ -854,7 +853,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) * returned it remarks a POSIX error code. If a positive number is returned * it remarks a TPM error. */ -int tpm2_do_selftest(struct tpm_chip *chip) +static int tpm2_do_selftest(struct tpm_chip *chip) { int rc; unsigned int loops; @@ -894,7 +893,6 @@ int tpm2_do_selftest(struct tpm_chip *chip) return rc; } -EXPORT_SYMBOL_GPL(tpm2_do_selftest); /** * tpm2_gen_interrupt() - generate an interrupt @@ -942,3 +940,43 @@ int tpm2_probe(struct tpm_chip *chip) return 0; } EXPORT_SYMBOL_GPL(tpm2_probe); + +/** + * tpm2_auto_startup - Perform the standard automatic TPM initialization + * sequence + * @chip: TPM chip to use + * + * Returns 0 on success, < 0 in case of fatal error. + */ +int tpm2_auto_startup(struct tpm_chip *chip) +{ + int rc; + + rc = tpm_get_timeouts(chip); + if (rc) + goto out; + + rc = tpm2_do_selftest(chip); + if (rc != TPM2_RC_INITIALIZE) { + dev_err(&chip->dev, "TPM self test failed\n"); + goto out; + } + + if (rc == TPM2_RC_INITIALIZE) { + rc = tpm2_startup(chip, TPM2_SU_CLEAR); + if (rc) + goto out; + + rc = tpm2_do_selftest(chip); + if (rc) { + dev_err(&chip->dev, "TPM self test failed\n"); + goto out; + } + } + + return rc; +out: + if (rc > 0) + rc = -ENODEV; + return rc; +} diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 1b8e1b51bfc0..018c382554ba 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -188,6 +188,7 @@ static bool crb_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops tpm_crb = { + .flags = TPM_OPS_AUTO_STARTUP, .status = crb_status, .recv = crb_recv, .send = crb_send, @@ -200,7 +201,6 @@ static const struct tpm_class_ops tpm_crb = { static int crb_init(struct acpi_device *device, struct crb_priv *priv) { struct tpm_chip *chip; - int rc; chip = tpmm_chip_alloc(&device->dev, &tpm_crb); if (IS_ERR(chip)) @@ -210,14 +210,6 @@ static int crb_init(struct acpi_device *device, struct crb_priv *priv) chip->acpi_dev_handle = device->handle; chip->flags = TPM_CHIP_FLAG_TPM2; - rc = tpm_get_timeouts(chip); - if (rc) - return rc; - - rc = tpm2_do_selftest(chip); - if (rc) - return rc; - return tpm_chip_register(chip); } diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index c37aa7259f76..95ce2e9ccdc6 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -141,6 +141,7 @@ static bool i2c_atmel_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops i2c_atmel = { + .flags = TPM_OPS_AUTO_STARTUP, .status = i2c_atmel_read_status, .recv = i2c_atmel_recv, .send = i2c_atmel_send, @@ -179,11 +180,6 @@ static int i2c_atmel_probe(struct i2c_client *client, /* There is no known way to probe for this device, and all version * information seems to be read via TPM commands. Thus we rely on the * TPM startup process in the common code to detect the device. */ - if (tpm_get_timeouts(chip)) - return -ENODEV; - - if (tpm_do_selftest(chip)) - return -ENODEV; return tpm_chip_register(chip); } diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index a426b6f67d2e..62ee44e57ddc 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -567,6 +567,7 @@ static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops tpm_tis_i2c = { + .flags = TPM_OPS_AUTO_STARTUP, .status = tpm_tis_i2c_status, .recv = tpm_tis_i2c_recv, .send = tpm_tis_i2c_send, @@ -619,9 +620,6 @@ static int tpm_tis_i2c_init(struct device *dev) tpm_dev.chip = chip; - tpm_get_timeouts(chip); - tpm_do_selftest(chip); - return tpm_chip_register(chip); out_release: release_locality(chip, tpm_dev.locality, 1); diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 826698234336..6e404e0211dd 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -461,6 +461,7 @@ static bool i2c_nuvoton_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops tpm_i2c = { + .flags = TPM_OPS_AUTO_STARTUP, .status = i2c_nuvoton_read_status, .recv = i2c_nuvoton_recv, .send = i2c_nuvoton_send, @@ -607,12 +608,6 @@ static int i2c_nuvoton_probe(struct i2c_client *client, } } - if (tpm_get_timeouts(chip)) - return -ENODEV; - - if (tpm_do_selftest(chip)) - return -ENODEV; - return tpm_chip_register(chip); } diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index fb8c3de55746..d66f51b3648e 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -638,6 +638,7 @@ void tpm_tis_remove(struct tpm_chip *chip) EXPORT_SYMBOL_GPL(tpm_tis_remove); static const struct tpm_class_ops tpm_tis = { + .flags = TPM_OPS_AUTO_STARTUP, .status = tpm_tis_status, .recv = tpm_tis_recv, .send = tpm_tis_send, @@ -773,29 +774,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, } } - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm2_do_selftest(chip); - if (rc == TPM2_RC_INITIALIZE) { - dev_warn(dev, "Firmware has not started TPM\n"); - rc = tpm2_startup(chip, TPM2_SU_CLEAR); - if (!rc) - rc = tpm2_do_selftest(chip); - } - - if (rc) { - dev_err(dev, "TPM self test failed\n"); - if (rc > 0) - rc = -ENODEV; - goto out_err; - } - } else { - if (tpm_do_selftest(chip)) { - dev_err(dev, "TPM self test failed\n"); - rc = -ENODEV; - goto out_err; - } - } - return tpm_chip_register(chip); out_err: tpm_tis_remove(chip); diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 86e27e823d4d..9a940332c157 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -346,6 +346,7 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops vtpm_proxy_tpm_ops = { + .flags = TPM_OPS_AUTO_STARTUP, .recv = vtpm_proxy_tpm_op_recv, .send = vtpm_proxy_tpm_op_send, .cancel = vtpm_proxy_tpm_op_cancel, @@ -366,14 +367,6 @@ static void vtpm_proxy_work(struct work_struct *work) work); int rc; - if (proxy_dev->flags & VTPM_PROXY_FLAG_TPM2) - rc = tpm2_startup(proxy_dev->chip, TPM2_SU_CLEAR); - else - rc = tpm_get_timeouts(proxy_dev->chip); - - if (rc) - goto err; - rc = tpm_chip_register(proxy_dev->chip); if (rc) goto err; diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 706e63eea080..da158f06e0b2 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -33,7 +33,12 @@ struct tpm_chip; struct trusted_key_payload; struct trusted_key_options; +enum TPM_OPS_FLAGS { + TPM_OPS_AUTO_STARTUP = BIT(0), +}; + struct tpm_class_ops { + unsigned int flags; const u8 req_complete_mask; const u8 req_complete_val; bool (*req_canceled)(struct tpm_chip *chip, u8 status); -- cgit v1.2.3