mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 11:03:43 +02:00
s390 updates for 6.16 merge window
- Large rework of the protected key crypto code to allow for asynchronous handling without memory allocation - Speed up system call entry/exit path by re-implementing lazy ASCE handling - Add module autoload support for the diag288_wdt watchdog device driver - Get rid of s390 specific strcpy() and strncpy() implementations, and switch all remaining users to strscpy() when possible - Various other small fixes and improvements -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEECMNfWEw3SLnmiLkZIg7DeRspbsIFAmgwuaIACgkQIg7DeRsp bsJ+xA//VTVWo15XHqX6xuJOSGSjwE7BbyA2RBNoIK+qH2PqCRvwvJU+QUcmjiKF v+GHOL5GGypKneEVjHCB4xTlKeBPt61yf9/dmTbE4K8KD/3olpHcC6BY62VJiet1 hDd6Tx9JT3TmjiTV+BanJ5KdiioUxc7jjJ2etMpQkCsHwAZlBtJ+yK+P/IoSI2kP 80hhNPHvlBadd36ke+Ell95TJBoxhQkKPX/u8ryIKybCvUf4ybsoEaYSPJv8/2I8 G4IqhTQ0Ft5BcO0g2gcfkpU+8HUtrqhjIDDDhy2h42wuWXsE2Jn3/PieNJUybtwA QdsAcN7P85a1TX2L7e4cEM9LEeIk15syZ8mUDKl6H69UHz4M8VNjMO8XfPpFD2ml 5xCPp7D+RcvUkdnjmz0jLx18mgrF9xjTTqrhYwcP2PWtANvf2m602ElEUlIWuRpI Mew/wgCfSdqKsYEbPenvfT+XTd62+hMdo3U3dwZ6OZlKwVXNTk5EUXe3UgMDkKdO 37OmAh5N2DcYwtPtL9vtl1CLguVJD+FXRnB/veHLCg25+OO/G4IrobySOjI7K0m7 C48Z5lUjxVJiRjKe35XXwBjuEaN+/TctK1kH3RfCDQGvBGBNoPyvC+L4kOprsbce 1Lnc7/pFCKdP5y90sJMomMdJCyP5BHKiJvHHWTr8maeslfxd9Vw= =lFqh -----END PGP SIGNATURE----- Merge tag 's390-6.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux Pull s390 updates from Heiko Carstens: - Large rework of the protected key crypto code to allow for asynchronous handling without memory allocation - Speed up system call entry/exit path by re-implementing lazy ASCE handling - Add module autoload support for the diag288_wdt watchdog device driver - Get rid of s390 specific strcpy() and strncpy() implementations, and switch all remaining users to strscpy() when possible - Various other small fixes and improvements * tag 's390-6.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (51 commits) s390/pci: Serialize device addition and removal s390/pci: Allow re-add of a reserved but not yet removed device s390/pci: Prevent self deletion in disable_slot() s390/pci: Remove redundant bus removal and disable from zpci_release_device() s390/crypto: Extend protected key conversion retry loop s390/pci: Fix __pcilg_mio_inuser() inline assembly s390/ptrace: Always inline regs_get_kernel_stack_nth() and regs_get_register() s390/thread_info: Cleanup header includes s390/extmem: Add workaround for DCSS unload diag s390/crypto: Rework protected key AES for true asynch support s390/cpacf: Rework cpacf_pcc() to return condition code s390/mm: Fix potential use-after-free in __crst_table_upgrade() s390/mm: Add mmap_assert_write_locked() check to crst_table_upgrade() s390/string: Remove strcpy() implementation s390/con3270: Use strscpy() instead of strcpy() s390/boot: Use strspcy() instead of strcpy() s390: Simple strcpy() to strscpy() conversions s390/pkey/crypto: Introduce xflags param for pkey in-kernel API s390/pkey: Provide and pass xflags within pkey and zcrypt layers s390/uv: Remove uv_get_secret_metadata function ...
This commit is contained in:
commit
d8cb068359
|
|
@ -146,6 +146,7 @@ config S390
|
|||
select ARCH_WANTS_NO_INSTR
|
||||
select ARCH_WANT_DEFAULT_BPF_JIT
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
|
||||
select ARCH_WANT_KERNEL_PMD_MKWRITE
|
||||
select ARCH_WANT_LD_ORPHAN_WARN
|
||||
select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ void setup_boot_command_line(void)
|
|||
if (has_ebcdic_char(parmarea.command_line))
|
||||
EBCASC(parmarea.command_line, COMMAND_LINE_SIZE);
|
||||
/* copy arch command line */
|
||||
strcpy(early_command_line, strim(parmarea.command_line));
|
||||
strscpy(early_command_line, strim(parmarea.command_line));
|
||||
|
||||
/* append IPL PARM data to the boot command line */
|
||||
if (!is_prot_virt_guest() && ipl_block_valid)
|
||||
|
|
@ -253,7 +253,8 @@ void parse_boot_command_line(void)
|
|||
int rc;
|
||||
|
||||
__kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE);
|
||||
args = strcpy(command_line_buf, early_command_line);
|
||||
strscpy(command_line_buf, early_command_line);
|
||||
args = command_line_buf;
|
||||
while (*args) {
|
||||
args = next_arg(args, ¶m, &val);
|
||||
|
||||
|
|
@ -309,7 +310,7 @@ void parse_boot_command_line(void)
|
|||
if (!strcmp(param, "bootdebug")) {
|
||||
bootdebug = true;
|
||||
if (val)
|
||||
strncpy(bootdebug_filter, val, sizeof(bootdebug_filter) - 1);
|
||||
strscpy(bootdebug_filter, val);
|
||||
}
|
||||
if (!strcmp(param, "quiet"))
|
||||
boot_console_loglevel = CONSOLE_LOGLEVEL_QUIET;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ static void boot_rb_add(const char *str, size_t len)
|
|||
/* store strings separated by '\0' */
|
||||
if (len + 1 > avail)
|
||||
boot_rb_off = 0;
|
||||
strcpy(boot_rb + boot_rb_off, str);
|
||||
avail = sizeof(boot_rb) - boot_rb_off - 1;
|
||||
strscpy(boot_rb + boot_rb_off, str, avail);
|
||||
boot_rb_off += len + 1;
|
||||
}
|
||||
|
||||
|
|
@ -158,10 +159,10 @@ static noinline char *strsym(char *buf, void *ip)
|
|||
|
||||
p = findsym((unsigned long)ip, &off, &len);
|
||||
if (p) {
|
||||
strncpy(buf, p, MAX_SYMLEN);
|
||||
strscpy(buf, p, MAX_SYMLEN);
|
||||
/* reserve 15 bytes for offset/len in symbol+0x1234/0x1234 */
|
||||
p = buf + strnlen(buf, MAX_SYMLEN - 15);
|
||||
strcpy(p, "+0x");
|
||||
strscpy(p, "+0x", MAX_SYMLEN - (p - buf));
|
||||
as_hex(p + 3, off, 0);
|
||||
strcat(p, "/0x");
|
||||
as_hex(p + strlen(p), len, 0);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <asm/boot_data.h>
|
||||
#include <asm/extmem.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/diag288.h>
|
||||
#include <asm/maccess.h>
|
||||
#include <asm/machine.h>
|
||||
#include <asm/sysinfo.h>
|
||||
|
|
@ -71,6 +72,20 @@ static void detect_machine_type(void)
|
|||
set_machine_feature(MFEATURE_VM);
|
||||
}
|
||||
|
||||
static void detect_diag288(void)
|
||||
{
|
||||
/* "BEGIN" in EBCDIC character set */
|
||||
static const char cmd[] = "\xc2\xc5\xc7\xc9\xd5";
|
||||
unsigned long action, len;
|
||||
|
||||
action = machine_is_vm() ? (unsigned long)cmd : LPARWDT_RESTART;
|
||||
len = machine_is_vm() ? sizeof(cmd) : 0;
|
||||
if (__diag288(WDT_FUNC_INIT, MIN_INTERVAL, action, len))
|
||||
return;
|
||||
__diag288(WDT_FUNC_CANCEL, 0, 0, 0);
|
||||
set_machine_feature(MFEATURE_DIAG288);
|
||||
}
|
||||
|
||||
static void detect_diag9c(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
|
@ -519,6 +534,8 @@ void startup_kernel(void)
|
|||
detect_facilities();
|
||||
detect_diag9c();
|
||||
detect_machine_type();
|
||||
/* detect_diag288() needs machine type */
|
||||
detect_diag288();
|
||||
cmma_init();
|
||||
sanitize_prot_virt_host();
|
||||
max_physmem_end = detect_max_physmem_end();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,18 @@ int strncmp(const char *cs, const char *ct, size_t count)
|
|||
return 0;
|
||||
}
|
||||
|
||||
ssize_t sized_strscpy(char *dst, const char *src, size_t count)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (count == 0)
|
||||
return -E2BIG;
|
||||
len = strnlen(src, count - 1);
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
return src[len] ? -E2BIG : len;
|
||||
}
|
||||
|
||||
void *memset64(uint64_t *s, uint64_t v, size_t count)
|
||||
{
|
||||
uint64_t *xs = s;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
36
arch/s390/include/asm/asce.h
Normal file
36
arch/s390/include/asm/asce.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_S390_ASCE_H
|
||||
#define _ASM_S390_ASCE_H
|
||||
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/ctlreg.h>
|
||||
|
||||
static inline bool enable_sacf_uaccess(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (test_thread_flag(TIF_ASCE_PRIMARY))
|
||||
return true;
|
||||
local_irq_save(flags);
|
||||
local_ctl_load(1, &get_lowcore()->kernel_asce);
|
||||
set_thread_flag(TIF_ASCE_PRIMARY);
|
||||
local_irq_restore(flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void disable_sacf_uaccess(bool previous)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (previous)
|
||||
return;
|
||||
local_irq_save(flags);
|
||||
local_ctl_load(1, &get_lowcore()->user_asce);
|
||||
clear_thread_flag(TIF_ASCE_PRIMARY);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#endif /* _ASM_S390_ASCE_H */
|
||||
|
|
@ -649,18 +649,30 @@ static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len,
|
|||
* instruction
|
||||
* @func: the function code passed to PCC; see CPACF_KM_xxx defines
|
||||
* @param: address of parameter block; see POP for details on each func
|
||||
*
|
||||
* Returns the condition code, this is
|
||||
* 0 - cc code 0 (normal completion)
|
||||
* 1 - cc code 1 (protected key wkvp mismatch or src operand out of range)
|
||||
* 2 - cc code 2 (something invalid, scalar multiply infinity, ...)
|
||||
* Condition code 3 (partial completion) is handled within the asm code
|
||||
* and never returned.
|
||||
*/
|
||||
static inline void cpacf_pcc(unsigned long func, void *param)
|
||||
static inline int cpacf_pcc(unsigned long func, void *param)
|
||||
{
|
||||
int cc;
|
||||
|
||||
asm volatile(
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
:
|
||||
CC_IPM(cc)
|
||||
: CC_OUT(cc, cc)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
[opc] "i" (CPACF_PCC)
|
||||
: "cc", "memory", "0", "1");
|
||||
: CC_CLOBBER_LIST("memory", "0", "1"));
|
||||
|
||||
return CC_TRANSFORM(cc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ enum {
|
|||
S390_CPU_FEATURE_MSA,
|
||||
S390_CPU_FEATURE_VXRS,
|
||||
S390_CPU_FEATURE_UV,
|
||||
S390_CPU_FEATURE_D288,
|
||||
MAX_CPU_FEATURES
|
||||
};
|
||||
|
||||
|
|
|
|||
41
arch/s390/include/asm/diag288.h
Normal file
41
arch/s390/include/asm/diag288.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_S390_DIAG288_H
|
||||
#define _ASM_S390_DIAG288_H
|
||||
|
||||
#include <asm/asm-extable.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#define MIN_INTERVAL 15 /* Minimal time supported by diag288 */
|
||||
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
|
||||
|
||||
#define WDT_DEFAULT_TIMEOUT 30
|
||||
|
||||
/* Function codes - init, change, cancel */
|
||||
#define WDT_FUNC_INIT 0
|
||||
#define WDT_FUNC_CHANGE 1
|
||||
#define WDT_FUNC_CANCEL 2
|
||||
#define WDT_FUNC_CONCEAL 0x80000000
|
||||
|
||||
/* Action codes for LPAR watchdog */
|
||||
#define LPARWDT_RESTART 0
|
||||
|
||||
static inline int __diag288(unsigned int func, unsigned int timeout,
|
||||
unsigned long action, unsigned int len)
|
||||
{
|
||||
union register_pair r1 = { .even = func, .odd = timeout, };
|
||||
union register_pair r3 = { .even = action, .odd = len, };
|
||||
int rc = -EINVAL;
|
||||
|
||||
asm volatile(
|
||||
" diag %[r1],%[r3],0x288\n"
|
||||
"0: lhi %[rc],0\n"
|
||||
"1:"
|
||||
EX_TABLE(0b, 1b)
|
||||
: [rc] "+d" (rc)
|
||||
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
|
||||
: "cc", "memory");
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* _ASM_S390_DIAG288_H */
|
||||
|
|
@ -13,9 +13,11 @@
|
|||
static uaccess_kmsan_or_inline int \
|
||||
__futex_atomic_##name(int oparg, int *old, u32 __user *uaddr) \
|
||||
{ \
|
||||
bool sacf_flag; \
|
||||
int rc, new; \
|
||||
\
|
||||
instrument_copy_from_user_before(old, uaddr, sizeof(*old)); \
|
||||
sacf_flag = enable_sacf_uaccess(); \
|
||||
asm_inline volatile( \
|
||||
" sacf 256\n" \
|
||||
"0: l %[old],%[uaddr]\n" \
|
||||
|
|
@ -32,6 +34,7 @@ __futex_atomic_##name(int oparg, int *old, u32 __user *uaddr) \
|
|||
[new] "=&d" (new), [uaddr] "+Q" (*uaddr) \
|
||||
: [oparg] "d" (oparg) \
|
||||
: "cc"); \
|
||||
disable_sacf_uaccess(sacf_flag); \
|
||||
if (!rc) \
|
||||
instrument_copy_from_user_after(old, uaddr, sizeof(*old), 0); \
|
||||
return rc; \
|
||||
|
|
@ -75,9 +78,11 @@ int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|||
static uaccess_kmsan_or_inline
|
||||
int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval)
|
||||
{
|
||||
bool sacf_flag;
|
||||
int rc;
|
||||
|
||||
instrument_copy_from_user_before(uval, uaddr, sizeof(*uval));
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile(
|
||||
" sacf 256\n"
|
||||
"0: cs %[old],%[new],%[uaddr]\n"
|
||||
|
|
@ -88,6 +93,7 @@ int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32
|
|||
: [rc] "=d" (rc), [old] "+d" (oldval), [uaddr] "+Q" (*uaddr)
|
||||
: [new] "d" (newval)
|
||||
: "cc", "memory");
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*uval = oldval;
|
||||
instrument_copy_from_user_after(uval, uaddr, sizeof(*uval), 0);
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#define MFEATURE_VM 7
|
||||
#define MFEATURE_KVM 8
|
||||
#define MFEATURE_LPAR 9
|
||||
#define MFEATURE_DIAG288 10
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/mm_types.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/ctlreg.h>
|
||||
#include <asm/asce.h>
|
||||
#include <asm-generic/mm_hooks.h>
|
||||
|
||||
#define init_new_context init_new_context
|
||||
|
|
@ -77,7 +78,8 @@ static inline void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *
|
|||
else
|
||||
get_lowcore()->user_asce.val = next->context.asce;
|
||||
cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
|
||||
/* Clear previous user-ASCE from CR7 */
|
||||
/* Clear previous user-ASCE from CR1 and CR7 */
|
||||
local_ctl_load(1, &s390_invalid_asce);
|
||||
local_ctl_load(7, &s390_invalid_asce);
|
||||
if (prev != next)
|
||||
cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
|
||||
|
|
@ -99,6 +101,7 @@ static inline void finish_arch_post_lock_switch(void)
|
|||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct mm_struct *mm = tsk->mm;
|
||||
unsigned long flags;
|
||||
|
||||
if (mm) {
|
||||
preempt_disable();
|
||||
|
|
@ -108,15 +111,25 @@ static inline void finish_arch_post_lock_switch(void)
|
|||
__tlb_flush_mm_lazy(mm);
|
||||
preempt_enable();
|
||||
}
|
||||
local_irq_save(flags);
|
||||
if (test_thread_flag(TIF_ASCE_PRIMARY))
|
||||
local_ctl_load(1, &get_lowcore()->kernel_asce);
|
||||
else
|
||||
local_ctl_load(1, &get_lowcore()->user_asce);
|
||||
local_ctl_load(7, &get_lowcore()->user_asce);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#define activate_mm activate_mm
|
||||
static inline void activate_mm(struct mm_struct *prev,
|
||||
struct mm_struct *next)
|
||||
{
|
||||
switch_mm(prev, next, current);
|
||||
switch_mm_irqs_off(prev, next, current);
|
||||
cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
|
||||
if (test_thread_flag(TIF_ASCE_PRIMARY))
|
||||
local_ctl_load(1, &get_lowcore()->kernel_asce);
|
||||
else
|
||||
local_ctl_load(1, &get_lowcore()->user_asce);
|
||||
local_ctl_load(7, &get_lowcore()->user_asce);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,22 @@
|
|||
* @param key pointer to a buffer containing the key blob
|
||||
* @param keylen size of the key blob in bytes
|
||||
* @param protkey pointer to buffer receiving the protected key
|
||||
* @param xflags additional execution flags (see PKEY_XFLAG_* definitions below)
|
||||
* As of now the only supported flag is PKEY_XFLAG_NOMEMALLOC.
|
||||
* @return 0 on success, negative errno value on failure
|
||||
*/
|
||||
int pkey_key2protkey(const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags);
|
||||
|
||||
/*
|
||||
* If this flag is given in the xflags parameter, the pkey implementation
|
||||
* is not allowed to allocate memory but instead should fall back to use
|
||||
* preallocated memory or simple fail with -ENOMEM.
|
||||
* This flag is for protected key derive within a cipher or similar
|
||||
* which must not allocate memory which would cause io operations - see
|
||||
* also the CRYPTO_ALG_ALLOCATES_MEMORY flag in crypto.h.
|
||||
*/
|
||||
#define PKEY_XFLAG_NOMEMALLOC 0x0001
|
||||
|
||||
#endif /* _KAPI_PKEY_H */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <linux/bits.h>
|
||||
#include <uapi/asm/ptrace.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/tpi.h>
|
||||
|
||||
#define PIF_SYSCALL 0 /* inside a system call */
|
||||
|
|
@ -126,7 +127,6 @@ struct pt_regs {
|
|||
struct tpi_info tpi_info;
|
||||
};
|
||||
unsigned long flags;
|
||||
unsigned long cr1;
|
||||
unsigned long last_break;
|
||||
};
|
||||
|
||||
|
|
@ -229,8 +229,44 @@ static inline void instruction_pointer_set(struct pt_regs *regs,
|
|||
|
||||
int regs_query_register_offset(const char *name);
|
||||
const char *regs_query_register_name(unsigned int offset);
|
||||
unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset);
|
||||
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n);
|
||||
|
||||
static __always_inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return regs->gprs[15];
|
||||
}
|
||||
|
||||
static __always_inline unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset)
|
||||
{
|
||||
if (offset >= NUM_GPRS)
|
||||
return 0;
|
||||
return regs->gprs[offset];
|
||||
}
|
||||
|
||||
static __always_inline int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
|
||||
{
|
||||
unsigned long ksp = kernel_stack_pointer(regs);
|
||||
|
||||
return (addr & ~(THREAD_SIZE - 1)) == (ksp & ~(THREAD_SIZE - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* regs_get_kernel_stack_nth() - get Nth entry of the stack
|
||||
* @regs:pt_regs which contains kernel stack pointer.
|
||||
* @n:stack entry number.
|
||||
*
|
||||
* regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
|
||||
* is specifined by @regs. If the @n th entry is NOT in the kernel stack,
|
||||
* this returns 0.
|
||||
*/
|
||||
static __always_inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
addr = kernel_stack_pointer(regs) + n * sizeof(long);
|
||||
if (!regs_within_kernel_stack(regs, addr))
|
||||
return 0;
|
||||
return READ_ONCE_NOCHECK(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* regs_get_kernel_argument() - get Nth function argument in kernel
|
||||
|
|
@ -251,11 +287,6 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
|
|||
return regs_get_kernel_stack_nth(regs, argoffset + n);
|
||||
}
|
||||
|
||||
static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
|
||||
{
|
||||
return regs->gprs[15];
|
||||
}
|
||||
|
||||
static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
|
||||
{
|
||||
regs->gprs[2] = rc;
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ void *memmove(void *dest, const void *src, size_t n);
|
|||
#define __HAVE_ARCH_MEMSCAN /* inline & arch function */
|
||||
#define __HAVE_ARCH_STRCAT /* inline & arch function */
|
||||
#define __HAVE_ARCH_STRCMP /* arch function */
|
||||
#define __HAVE_ARCH_STRCPY /* inline & arch function */
|
||||
#define __HAVE_ARCH_STRLCAT /* arch function */
|
||||
#define __HAVE_ARCH_STRLEN /* inline & arch function */
|
||||
#define __HAVE_ARCH_STRNCAT /* arch function */
|
||||
#define __HAVE_ARCH_STRNCPY /* arch function */
|
||||
#define __HAVE_ARCH_STRNLEN /* inline & arch function */
|
||||
#define __HAVE_ARCH_STRSTR /* arch function */
|
||||
#define __HAVE_ARCH_MEMSET16 /* arch function */
|
||||
|
|
@ -42,7 +40,6 @@ int memcmp(const void *s1, const void *s2, size_t n);
|
|||
int strcmp(const char *s1, const char *s2);
|
||||
size_t strlcat(char *dest, const char *src, size_t n);
|
||||
char *strncat(char *dest, const char *src, size_t n);
|
||||
char *strncpy(char *dest, const char *src, size_t n);
|
||||
char *strstr(const char *s1, const char *s2);
|
||||
#endif /* !defined(CONFIG_KASAN) && !defined(CONFIG_KMSAN) */
|
||||
|
||||
|
|
@ -155,22 +152,6 @@ static inline char *strcat(char *dst, const char *src)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef __HAVE_ARCH_STRCPY
|
||||
static inline char *strcpy(char *dst, const char *src)
|
||||
{
|
||||
char *ret = dst;
|
||||
|
||||
asm volatile(
|
||||
" lghi 0,0\n"
|
||||
"0: mvst %[dst],%[src]\n"
|
||||
" jo 0b"
|
||||
: [dst] "+&a" (dst), [src] "+&a" (src)
|
||||
:
|
||||
: "cc", "memory", "0");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__HAVE_ARCH_STRLEN) || (defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__))
|
||||
static inline size_t __no_sanitize_prefix_strfunc(strlen)(const char *s)
|
||||
{
|
||||
|
|
@ -208,7 +189,6 @@ static inline size_t strnlen(const char * s, size_t n)
|
|||
void *memchr(const void * s, int c, size_t n);
|
||||
void *memscan(void *s, int c, size_t n);
|
||||
char *strcat(char *dst, const char *src);
|
||||
char *strcpy(char *dst, const char *src);
|
||||
size_t strlen(const char *s);
|
||||
size_t strnlen(const char * s, size_t n);
|
||||
#endif /* !IN_ARCH_STRING_C */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#define _ASM_THREAD_INFO_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <vdso/page.h>
|
||||
|
||||
/*
|
||||
* General size of kernel stacks
|
||||
|
|
@ -24,8 +25,6 @@
|
|||
#define STACK_INIT_OFFSET (THREAD_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/*
|
||||
* low level task data that entry.S needs immediate access to
|
||||
|
|
@ -64,6 +63,7 @@ void arch_setup_new_exec(void);
|
|||
#define TIF_NEED_RESCHED_LAZY 3 /* lazy rescheduling needed */
|
||||
#define TIF_UPROBE 4 /* breakpointed or single-stepping */
|
||||
#define TIF_PATCH_PENDING 5 /* pending live patching update */
|
||||
#define TIF_ASCE_PRIMARY 6 /* primary asce is kernel asce */
|
||||
#define TIF_NOTIFY_SIGNAL 7 /* signal notifications exist */
|
||||
#define TIF_GUARDED_STORAGE 8 /* load guarded storage control block */
|
||||
#define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */
|
||||
|
|
@ -85,6 +85,7 @@ void arch_setup_new_exec(void);
|
|||
#define _TIF_NEED_RESCHED_LAZY BIT(TIF_NEED_RESCHED_LAZY)
|
||||
#define _TIF_UPROBE BIT(TIF_UPROBE)
|
||||
#define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING)
|
||||
#define _TIF_ASCE_PRIMARY BIT(TIF_ASCE_PRIMARY)
|
||||
#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL)
|
||||
#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE)
|
||||
#define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <asm/extable.h>
|
||||
#include <asm/facility.h>
|
||||
#include <asm-generic/access_ok.h>
|
||||
#include <asm/asce.h>
|
||||
#include <linux/instrumented.h>
|
||||
|
||||
void debug_user_asce(int exit);
|
||||
|
|
@ -478,6 +479,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
__uint128_t old, __uint128_t new,
|
||||
unsigned long key, int size)
|
||||
{
|
||||
bool sacf_flag;
|
||||
int rc = 0;
|
||||
|
||||
switch (size) {
|
||||
|
|
@ -490,6 +492,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
_old = ((unsigned int)old & 0xff) << shift;
|
||||
_new = ((unsigned int)new & 0xff) << shift;
|
||||
mask = ~(0xff << shift);
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile(
|
||||
" spka 0(%[key])\n"
|
||||
" sacf 256\n"
|
||||
|
|
@ -524,6 +527,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
[default_key] "J" (PAGE_DEFAULT_KEY),
|
||||
[max_loops] "J" (CMPXCHG_USER_KEY_MAX_LOOPS)
|
||||
: "memory", "cc");
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*(unsigned char *)uval = prev >> shift;
|
||||
if (!count)
|
||||
rc = -EAGAIN;
|
||||
|
|
@ -538,6 +542,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
_old = ((unsigned int)old & 0xffff) << shift;
|
||||
_new = ((unsigned int)new & 0xffff) << shift;
|
||||
mask = ~(0xffff << shift);
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile(
|
||||
" spka 0(%[key])\n"
|
||||
" sacf 256\n"
|
||||
|
|
@ -572,6 +577,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
[default_key] "J" (PAGE_DEFAULT_KEY),
|
||||
[max_loops] "J" (CMPXCHG_USER_KEY_MAX_LOOPS)
|
||||
: "memory", "cc");
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*(unsigned short *)uval = prev >> shift;
|
||||
if (!count)
|
||||
rc = -EAGAIN;
|
||||
|
|
@ -580,6 +586,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
case 4: {
|
||||
unsigned int prev = old;
|
||||
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile(
|
||||
" spka 0(%[key])\n"
|
||||
" sacf 256\n"
|
||||
|
|
@ -595,12 +602,14 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
[key] "a" (key << 4),
|
||||
[default_key] "J" (PAGE_DEFAULT_KEY)
|
||||
: "memory", "cc");
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*(unsigned int *)uval = prev;
|
||||
return rc;
|
||||
}
|
||||
case 8: {
|
||||
unsigned long prev = old;
|
||||
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile(
|
||||
" spka 0(%[key])\n"
|
||||
" sacf 256\n"
|
||||
|
|
@ -616,12 +625,14 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
[key] "a" (key << 4),
|
||||
[default_key] "J" (PAGE_DEFAULT_KEY)
|
||||
: "memory", "cc");
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*(unsigned long *)uval = prev;
|
||||
return rc;
|
||||
}
|
||||
case 16: {
|
||||
__uint128_t prev = old;
|
||||
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile(
|
||||
" spka 0(%[key])\n"
|
||||
" sacf 256\n"
|
||||
|
|
@ -637,6 +648,7 @@ static __always_inline int __cmpxchg_user_key(unsigned long address, void *uval,
|
|||
[key] "a" (key << 4),
|
||||
[default_key] "J" (PAGE_DEFAULT_KEY)
|
||||
: "memory", "cc");
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*(__uint128_t *)uval = prev;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -616,8 +616,9 @@ static inline int uv_remove_shared(unsigned long addr)
|
|||
return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
|
||||
}
|
||||
|
||||
int uv_get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
struct uv_secret_list_item_hdr *secret);
|
||||
int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
struct uv_secret_list *list,
|
||||
struct uv_secret_list_item_hdr *secret);
|
||||
int uv_retrieve_secret(u16 secret_idx, u8 *buf, size_t buf_size);
|
||||
|
||||
extern int prot_virt_host;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ int main(void)
|
|||
OFFSET(__PT_ORIG_GPR2, pt_regs, orig_gpr2);
|
||||
OFFSET(__PT_INT_CODE, pt_regs, int_code);
|
||||
OFFSET(__PT_FLAGS, pt_regs, flags);
|
||||
OFFSET(__PT_CR1, pt_regs, cr1);
|
||||
OFFSET(__PT_LAST_BREAK, pt_regs, last_break);
|
||||
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
|
||||
BLANK();
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ static void cert_store_key_describe(const struct key *key, struct seq_file *m)
|
|||
* First 64 bytes of the key description is key name in EBCDIC CP 500.
|
||||
* Convert it to ASCII for displaying in /proc/keys.
|
||||
*/
|
||||
strscpy(ascii, key->description, sizeof(ascii));
|
||||
strscpy(ascii, key->description);
|
||||
EBCASC_500(ascii, VC_NAME_LEN_BYTES);
|
||||
seq_puts(m, ascii);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/bug.h>
|
||||
#include <asm/machine.h>
|
||||
#include <asm/elf.h>
|
||||
|
||||
enum {
|
||||
TYPE_HWCAP,
|
||||
TYPE_FACILITY,
|
||||
TYPE_MACHINE,
|
||||
};
|
||||
|
||||
struct s390_cpu_feature {
|
||||
|
|
@ -21,6 +23,7 @@ static struct s390_cpu_feature s390_cpu_features[MAX_CPU_FEATURES] = {
|
|||
[S390_CPU_FEATURE_MSA] = {.type = TYPE_HWCAP, .num = HWCAP_NR_MSA},
|
||||
[S390_CPU_FEATURE_VXRS] = {.type = TYPE_HWCAP, .num = HWCAP_NR_VXRS},
|
||||
[S390_CPU_FEATURE_UV] = {.type = TYPE_FACILITY, .num = 158},
|
||||
[S390_CPU_FEATURE_D288] = {.type = TYPE_MACHINE, .num = MFEATURE_DIAG288},
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -38,6 +41,8 @@ int cpu_have_feature(unsigned int num)
|
|||
return !!(elf_hwcap & BIT(feature->num));
|
||||
case TYPE_FACILITY:
|
||||
return test_facility(feature->num);
|
||||
case TYPE_MACHINE:
|
||||
return test_machine_feature(feature->num);
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ static void *nt_prpsinfo(void *ptr)
|
|||
|
||||
memset(&prpsinfo, 0, sizeof(prpsinfo));
|
||||
prpsinfo.pr_sname = 'R';
|
||||
strcpy(prpsinfo.pr_fname, "vmlinux");
|
||||
strscpy(prpsinfo.pr_fname, "vmlinux");
|
||||
return nt_init(ptr, PRPSINFO, prpsinfo);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ static debug_info_t *debug_info_alloc(const char *name, int pages_per_area,
|
|||
rc->level = level;
|
||||
rc->buf_size = buf_size;
|
||||
rc->entry_size = sizeof(debug_entry_t) + buf_size;
|
||||
strscpy(rc->name, name, sizeof(rc->name));
|
||||
strscpy(rc->name, name);
|
||||
memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
|
||||
memset(rc->debugfs_entries, 0, DEBUG_MAX_VIEWS * sizeof(struct dentry *));
|
||||
refcount_set(&(rc->ref_count), 0);
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ _LPP_OFFSET = __LC_LPP
|
|||
.macro SIEEXIT sie_control,lowcore
|
||||
lg %r9,\sie_control # get control block pointer
|
||||
ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE
|
||||
lctlg %c1,%c1,__LC_KERNEL_ASCE(\lowcore) # load primary asce
|
||||
lctlg %c1,%c1,__LC_USER_ASCE(\lowcore) # load primary asce
|
||||
lg %r9,__LC_CURRENT(\lowcore)
|
||||
mvi __TI_sie(%r9),0
|
||||
larl %r9,sie_exit # skip forward to sie_exit
|
||||
|
|
@ -208,7 +208,7 @@ SYM_FUNC_START(__sie64a)
|
|||
lg %r14,__SF_SIE_CONTROL(%r15) # get control block pointer
|
||||
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
|
||||
GET_LC %r14
|
||||
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r14) # load primary asce
|
||||
lctlg %c1,%c1,__LC_USER_ASCE(%r14) # load primary asce
|
||||
lg %r14,__LC_CURRENT(%r14)
|
||||
mvi __TI_sie(%r14),0
|
||||
SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL)
|
||||
|
|
@ -240,7 +240,6 @@ SYM_CODE_START(system_call)
|
|||
lghi %r14,0
|
||||
.Lsysc_per:
|
||||
STBEAR __LC_LAST_BREAK(%r13)
|
||||
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13)
|
||||
lg %r15,__LC_KERNEL_STACK(%r13)
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
stmg %r0,%r7,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
|
||||
|
|
@ -261,7 +260,6 @@ SYM_CODE_START(system_call)
|
|||
lgr %r3,%r14
|
||||
brasl %r14,__do_syscall
|
||||
STACKLEAK_ERASE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE(%r13)
|
||||
mvc __LC_RETURN_PSW(16,%r13),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
|
||||
BPON
|
||||
LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15)
|
||||
|
|
@ -278,7 +276,6 @@ SYM_CODE_START(ret_from_fork)
|
|||
brasl %r14,__ret_from_fork
|
||||
STACKLEAK_ERASE
|
||||
GET_LC %r13
|
||||
lctlg %c1,%c1,__LC_USER_ASCE(%r13)
|
||||
mvc __LC_RETURN_PSW(16,%r13),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
|
||||
BPON
|
||||
LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15)
|
||||
|
|
@ -299,10 +296,7 @@ SYM_CODE_START(pgm_check_handler)
|
|||
lmg %r8,%r9,__LC_PGM_OLD_PSW(%r13)
|
||||
xgr %r10,%r10
|
||||
tmhh %r8,0x0001 # coming from user space?
|
||||
jno .Lpgm_skip_asce
|
||||
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13)
|
||||
j 3f # -> fault in user space
|
||||
.Lpgm_skip_asce:
|
||||
jo 3f # -> fault in user space
|
||||
#if IS_ENABLED(CONFIG_KVM)
|
||||
lg %r11,__LC_CURRENT(%r13)
|
||||
tm __TI_sie(%r11),0xff
|
||||
|
|
@ -340,7 +334,6 @@ SYM_CODE_START(pgm_check_handler)
|
|||
tmhh %r8,0x0001 # returning to user space?
|
||||
jno .Lpgm_exit_kernel
|
||||
STACKLEAK_ERASE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE(%r13)
|
||||
BPON
|
||||
stpt __LC_EXIT_TIMER(%r13)
|
||||
.Lpgm_exit_kernel:
|
||||
|
|
@ -384,8 +377,7 @@ SYM_CODE_START(\name)
|
|||
#endif
|
||||
0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
j 2f
|
||||
1: lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13)
|
||||
lg %r15,__LC_KERNEL_STACK(%r13)
|
||||
1: lg %r15,__LC_KERNEL_STACK(%r13)
|
||||
2: xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
stmg %r0,%r7,__PT_R0(%r11)
|
||||
|
|
@ -408,7 +400,6 @@ SYM_CODE_START(\name)
|
|||
tmhh %r8,0x0001 # returning to user ?
|
||||
jno 2f
|
||||
STACKLEAK_ERASE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE(%r13)
|
||||
BPON
|
||||
stpt __LC_EXIT_TIMER(%r13)
|
||||
2: LBEAR __PT_LAST_BREAK(%r11)
|
||||
|
|
@ -476,8 +467,6 @@ SYM_CODE_START(mcck_int_handler)
|
|||
.Lmcck_user:
|
||||
lg %r15,__LC_MCCK_STACK(%r13)
|
||||
la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
stctg %c1,%c1,__PT_CR1(%r11)
|
||||
lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13)
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
lay %r14,__LC_GPREGS_SAVE_AREA(%r13)
|
||||
mvc __PT_R0(128,%r11),0(%r14)
|
||||
|
|
@ -495,7 +484,6 @@ SYM_CODE_START(mcck_int_handler)
|
|||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
lgr %r2,%r11 # pass pointer to pt_regs
|
||||
brasl %r14,s390_do_machine_check
|
||||
lctlg %c1,%c1,__PT_CR1(%r11)
|
||||
lmg %r0,%r10,__PT_R0(%r11)
|
||||
mvc __LC_RETURN_MCCK_PSW(16,%r13),__PT_PSW(%r11) # move return PSW
|
||||
tm __LC_RETURN_MCCK_PSW+1(%r13),0x01 # returning to user ?
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
|
|||
{ \
|
||||
if (len >= sizeof(_value)) \
|
||||
return -E2BIG; \
|
||||
len = strscpy(_value, buf, sizeof(_value)); \
|
||||
len = strscpy(_value, buf); \
|
||||
if ((ssize_t)len < 0) \
|
||||
return len; \
|
||||
strim(_value); \
|
||||
|
|
@ -2249,26 +2249,28 @@ static int __init s390_ipl_init(void)
|
|||
|
||||
__initcall(s390_ipl_init);
|
||||
|
||||
static void __init strncpy_skip_quote(char *dst, char *src, int n)
|
||||
static void __init strscpy_skip_quote(char *dst, char *src, int n)
|
||||
{
|
||||
int sx, dx;
|
||||
|
||||
dx = 0;
|
||||
for (sx = 0; src[sx] != 0; sx++) {
|
||||
if (!n)
|
||||
return;
|
||||
for (sx = 0, dx = 0; src[sx]; sx++) {
|
||||
if (src[sx] == '"')
|
||||
continue;
|
||||
dst[dx++] = src[sx];
|
||||
if (dx >= n)
|
||||
dst[dx] = src[sx];
|
||||
if (dx + 1 == n)
|
||||
break;
|
||||
dx++;
|
||||
}
|
||||
dst[dx] = '\0';
|
||||
}
|
||||
|
||||
static int __init vmcmd_on_reboot_setup(char *str)
|
||||
{
|
||||
if (!machine_is_vm())
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_reboot, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_reboot[VMCMD_MAX_SIZE] = 0;
|
||||
strscpy_skip_quote(vmcmd_on_reboot, str, sizeof(vmcmd_on_reboot));
|
||||
on_reboot_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2278,8 +2280,7 @@ static int __init vmcmd_on_panic_setup(char *str)
|
|||
{
|
||||
if (!machine_is_vm())
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_panic, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_panic[VMCMD_MAX_SIZE] = 0;
|
||||
strscpy_skip_quote(vmcmd_on_panic, str, sizeof(vmcmd_on_panic));
|
||||
on_panic_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2289,8 +2290,7 @@ static int __init vmcmd_on_halt_setup(char *str)
|
|||
{
|
||||
if (!machine_is_vm())
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_halt, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_halt[VMCMD_MAX_SIZE] = 0;
|
||||
strscpy_skip_quote(vmcmd_on_halt, str, sizeof(vmcmd_on_halt));
|
||||
on_halt_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -2300,8 +2300,7 @@ static int __init vmcmd_on_poff_setup(char *str)
|
|||
{
|
||||
if (!machine_is_vm())
|
||||
return 1;
|
||||
strncpy_skip_quote(vmcmd_on_poff, str, VMCMD_MAX_SIZE);
|
||||
vmcmd_on_poff[VMCMD_MAX_SIZE] = 0;
|
||||
strscpy_skip_quote(vmcmd_on_poff, str, sizeof(vmcmd_on_poff));
|
||||
on_poff_trigger.action = &vmcmd_action;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -290,8 +290,8 @@ CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_NO_SPECIAL, 0x00f4);
|
|||
CPUMF_EVENT_ATTR(cf_z15, TX_C_TABORT_SPECIAL, 0x00f5);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_ACCESS, 0x00f7);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CYCLES, 0x00fc);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CC, 0x00108);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CCFINISH, 0x00109);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CC, 0x0108);
|
||||
CPUMF_EVENT_ATTR(cf_z15, DFLT_CCFINISH, 0x0109);
|
||||
CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_ONE_THR_ACTIVE, 0x01c0);
|
||||
CPUMF_EVENT_ATTR(cf_z15, MT_DIAG_CYCLES_TWO_THR_ACTIVE, 0x01c1);
|
||||
CPUMF_EVENT_ATTR(cf_z16, L1D_RO_EXCL_WRITES, 0x0080);
|
||||
|
|
|
|||
|
|
@ -268,35 +268,35 @@ static int __init setup_elf_platform(void)
|
|||
add_device_randomness(&cpu_id, sizeof(cpu_id));
|
||||
switch (cpu_id.machine) {
|
||||
default: /* Use "z10" as default. */
|
||||
strcpy(elf_platform, "z10");
|
||||
strscpy(elf_platform, "z10");
|
||||
break;
|
||||
case 0x2817:
|
||||
case 0x2818:
|
||||
strcpy(elf_platform, "z196");
|
||||
strscpy(elf_platform, "z196");
|
||||
break;
|
||||
case 0x2827:
|
||||
case 0x2828:
|
||||
strcpy(elf_platform, "zEC12");
|
||||
strscpy(elf_platform, "zEC12");
|
||||
break;
|
||||
case 0x2964:
|
||||
case 0x2965:
|
||||
strcpy(elf_platform, "z13");
|
||||
strscpy(elf_platform, "z13");
|
||||
break;
|
||||
case 0x3906:
|
||||
case 0x3907:
|
||||
strcpy(elf_platform, "z14");
|
||||
strscpy(elf_platform, "z14");
|
||||
break;
|
||||
case 0x8561:
|
||||
case 0x8562:
|
||||
strcpy(elf_platform, "z15");
|
||||
strscpy(elf_platform, "z15");
|
||||
break;
|
||||
case 0x3931:
|
||||
case 0x3932:
|
||||
strcpy(elf_platform, "z16");
|
||||
strscpy(elf_platform, "z16");
|
||||
break;
|
||||
case 0x9175:
|
||||
case 0x9176:
|
||||
strcpy(elf_platform, "z17");
|
||||
strscpy(elf_platform, "z17");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1524,13 +1524,6 @@ static const char *gpr_names[NUM_GPRS] = {
|
|||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
};
|
||||
|
||||
unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset)
|
||||
{
|
||||
if (offset >= NUM_GPRS)
|
||||
return 0;
|
||||
return regs->gprs[offset];
|
||||
}
|
||||
|
||||
int regs_query_register_offset(const char *name)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
|
@ -1550,29 +1543,3 @@ const char *regs_query_register_name(unsigned int offset)
|
|||
return NULL;
|
||||
return gpr_names[offset];
|
||||
}
|
||||
|
||||
static int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
|
||||
{
|
||||
unsigned long ksp = kernel_stack_pointer(regs);
|
||||
|
||||
return (addr & ~(THREAD_SIZE - 1)) == (ksp & ~(THREAD_SIZE - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* regs_get_kernel_stack_nth() - get Nth entry of the stack
|
||||
* @regs:pt_regs which contains kernel stack pointer.
|
||||
* @n:stack entry number.
|
||||
*
|
||||
* regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
|
||||
* is specifined by @regs. If the @n th entry is NOT in the kernel stack,
|
||||
* this returns 0.
|
||||
*/
|
||||
unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
addr = kernel_stack_pointer(regs) + n * sizeof(long);
|
||||
if (!regs_within_kernel_stack(regs, addr))
|
||||
return 0;
|
||||
return READ_ONCE_NOCHECK(addr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
|
|||
abs_lc = get_abs_lowcore();
|
||||
memcpy(lc->cregs_save_area, abs_lc->cregs_save_area, sizeof(lc->cregs_save_area));
|
||||
put_abs_lowcore(abs_lc);
|
||||
lc->cregs_save_area[1] = lc->kernel_asce;
|
||||
lc->cregs_save_area[1] = lc->user_asce;
|
||||
lc->cregs_save_area[7] = lc->user_asce;
|
||||
save_access_regs((unsigned int *) lc->access_regs_save_area);
|
||||
arch_spin_lock_setup(cpu);
|
||||
|
|
|
|||
|
|
@ -782,7 +782,12 @@ static int __init uv_sysfs_init(void)
|
|||
device_initcall(uv_sysfs_init);
|
||||
|
||||
/*
|
||||
* Find the secret with the secret_id in the provided list.
|
||||
* Locate a secret in the list by its id.
|
||||
* @secret_id: search pattern.
|
||||
* @list: ephemeral buffer space
|
||||
* @secret: output data, containing the secret's metadata.
|
||||
*
|
||||
* Search for a secret with the given secret_id in the Ultravisor secret store.
|
||||
*
|
||||
* Context: might sleep.
|
||||
*/
|
||||
|
|
@ -803,12 +808,15 @@ static int find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN],
|
|||
|
||||
/*
|
||||
* Do the actual search for `uv_get_secret_metadata`.
|
||||
* @secret_id: search pattern.
|
||||
* @list: ephemeral buffer space
|
||||
* @secret: output data, containing the secret's metadata.
|
||||
*
|
||||
* Context: might sleep.
|
||||
*/
|
||||
static int find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
struct uv_secret_list *list,
|
||||
struct uv_secret_list_item_hdr *secret)
|
||||
int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
struct uv_secret_list *list,
|
||||
struct uv_secret_list_item_hdr *secret)
|
||||
{
|
||||
u16 start_idx = 0;
|
||||
u16 list_rc;
|
||||
|
|
@ -830,36 +838,7 @@ static int find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
|||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* uv_get_secret_metadata() - get secret metadata for a given secret id.
|
||||
* @secret_id: search pattern.
|
||||
* @secret: output data, containing the secret's metadata.
|
||||
*
|
||||
* Search for a secret with the given secret_id in the Ultravisor secret store.
|
||||
*
|
||||
* Context: might sleep.
|
||||
*
|
||||
* Return:
|
||||
* * %0: - Found entry; secret->idx and secret->type are valid.
|
||||
* * %ENOENT - No entry found.
|
||||
* * %ENODEV: - Not supported: UV not available or command not available.
|
||||
* * %EIO: - Other unexpected UV error.
|
||||
*/
|
||||
int uv_get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
struct uv_secret_list_item_hdr *secret)
|
||||
{
|
||||
struct uv_secret_list *buf;
|
||||
int rc;
|
||||
|
||||
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
rc = find_secret(secret_id, buf, secret);
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uv_get_secret_metadata);
|
||||
EXPORT_SYMBOL_GPL(uv_find_secret);
|
||||
|
||||
/**
|
||||
* uv_retrieve_secret() - get the secret value for the secret index.
|
||||
|
|
|
|||
|
|
@ -77,50 +77,6 @@ size_t strnlen(const char *s, size_t n)
|
|||
EXPORT_SYMBOL(strnlen);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* strcpy - Copy a %NUL terminated string
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
*
|
||||
* returns a pointer to @dest
|
||||
*/
|
||||
#ifdef __HAVE_ARCH_STRCPY
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
char *ret = dest;
|
||||
|
||||
asm volatile(
|
||||
" lghi 0,0\n"
|
||||
"0: mvst %[dest],%[src]\n"
|
||||
" jo 0b\n"
|
||||
: [dest] "+&a" (dest), [src] "+&a" (src)
|
||||
:
|
||||
: "cc", "memory", "0");
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(strcpy);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* strncpy - Copy a length-limited, %NUL-terminated string
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @n: The maximum number of bytes to copy
|
||||
*
|
||||
* The result is not %NUL-terminated if the source exceeds
|
||||
* @n bytes.
|
||||
*/
|
||||
#ifdef __HAVE_ARCH_STRNCPY
|
||||
char *strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
size_t len = __strnend(src, n) - src;
|
||||
memset(dest + len, 0, n - len);
|
||||
memcpy(dest, src, len);
|
||||
return dest;
|
||||
}
|
||||
EXPORT_SYMBOL(strncpy);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* strcat - Append one %NUL-terminated string to another
|
||||
* @dest: The string to be appended to
|
||||
|
|
@ -181,9 +137,6 @@ EXPORT_SYMBOL(strlcat);
|
|||
* @n: The maximum numbers of bytes to copy
|
||||
*
|
||||
* returns a pointer to @dest
|
||||
*
|
||||
* Note that in contrast to strncpy, strncat ensures the result is
|
||||
* terminated.
|
||||
*/
|
||||
#ifdef __HAVE_ARCH_STRNCAT
|
||||
char *strncat(char *dest, const char *src, size_t n)
|
||||
|
|
|
|||
|
|
@ -17,17 +17,18 @@
|
|||
#ifdef CONFIG_DEBUG_ENTRY
|
||||
void debug_user_asce(int exit)
|
||||
{
|
||||
struct lowcore *lc = get_lowcore();
|
||||
struct ctlreg cr1, cr7;
|
||||
|
||||
local_ctl_store(1, &cr1);
|
||||
local_ctl_store(7, &cr7);
|
||||
if (cr1.val == get_lowcore()->kernel_asce.val && cr7.val == get_lowcore()->user_asce.val)
|
||||
if (cr1.val == lc->user_asce.val && cr7.val == lc->user_asce.val)
|
||||
return;
|
||||
panic("incorrect ASCE on kernel %s\n"
|
||||
"cr1: %016lx cr7: %016lx\n"
|
||||
"kernel: %016lx user: %016lx\n",
|
||||
exit ? "exit" : "entry", cr1.val, cr7.val,
|
||||
get_lowcore()->kernel_asce.val, get_lowcore()->user_asce.val);
|
||||
lc->kernel_asce.val, lc->user_asce.val);
|
||||
}
|
||||
#endif /*CONFIG_DEBUG_ENTRY */
|
||||
|
||||
|
|
|
|||
|
|
@ -530,6 +530,14 @@ segment_modify_shared (char *name, int do_nonshared)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void __dcss_diag_purge_on_cpu_0(void *data)
|
||||
{
|
||||
struct dcss_segment *seg = (struct dcss_segment *)data;
|
||||
unsigned long dummy;
|
||||
|
||||
dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrease the use count of a DCSS segment and remove
|
||||
* it from the address space if nobody is using it
|
||||
|
|
@ -538,7 +546,6 @@ segment_modify_shared (char *name, int do_nonshared)
|
|||
void
|
||||
segment_unload(char *name)
|
||||
{
|
||||
unsigned long dummy;
|
||||
struct dcss_segment *seg;
|
||||
|
||||
if (!machine_is_vm())
|
||||
|
|
@ -556,7 +563,14 @@ segment_unload(char *name)
|
|||
kfree(seg->res);
|
||||
vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
|
||||
list_del(&seg->list);
|
||||
dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy);
|
||||
/*
|
||||
* Workaround for z/VM issue, where calling the DCSS unload diag on
|
||||
* a non-IPL CPU would cause bogus sclp maximum memory detection on
|
||||
* next IPL.
|
||||
* IPL CPU 0 cannot be set offline, so the dcss_diag() call can
|
||||
* directly be scheduled to that CPU.
|
||||
*/
|
||||
smp_call_function_single(0, __dcss_diag_purge_on_cpu_0, seg, 1);
|
||||
kfree(seg);
|
||||
out_unlock:
|
||||
mutex_unlock(&dcss_lock);
|
||||
|
|
|
|||
|
|
@ -38,11 +38,15 @@ void crst_table_free(struct mm_struct *mm, unsigned long *table)
|
|||
static void __crst_table_upgrade(void *arg)
|
||||
{
|
||||
struct mm_struct *mm = arg;
|
||||
struct ctlreg asce;
|
||||
|
||||
/* change all active ASCEs to avoid the creation of new TLBs */
|
||||
if (current->active_mm == mm) {
|
||||
get_lowcore()->user_asce.val = mm->context.asce;
|
||||
local_ctl_load(7, &get_lowcore()->user_asce);
|
||||
asce.val = mm->context.asce;
|
||||
get_lowcore()->user_asce = asce;
|
||||
local_ctl_load(7, &asce);
|
||||
if (!test_thread_flag(TIF_ASCE_PRIMARY))
|
||||
local_ctl_load(1, &asce);
|
||||
}
|
||||
__tlb_flush_local();
|
||||
}
|
||||
|
|
@ -52,6 +56,8 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long end)
|
|||
unsigned long *pgd = NULL, *p4d = NULL, *__pgd;
|
||||
unsigned long asce_limit = mm->context.asce_limit;
|
||||
|
||||
mmap_assert_write_locked(mm);
|
||||
|
||||
/* upgrade should only happen from 3 to 4, 3 to 5, or 4 to 5 levels */
|
||||
VM_BUG_ON(asce_limit < _REGION2_SIZE);
|
||||
|
||||
|
|
@ -75,13 +81,6 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long end)
|
|||
|
||||
spin_lock_bh(&mm->page_table_lock);
|
||||
|
||||
/*
|
||||
* This routine gets called with mmap_lock lock held and there is
|
||||
* no reason to optimize for the case of otherwise. However, if
|
||||
* that would ever change, the below check will let us know.
|
||||
*/
|
||||
VM_BUG_ON(asce_limit != mm->context.asce_limit);
|
||||
|
||||
if (p4d) {
|
||||
__pgd = (unsigned long *) mm->pgd;
|
||||
p4d_populate(mm, (p4d_t *) p4d, (pud_t *) __pgd);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
/* list of all detected zpci devices */
|
||||
static LIST_HEAD(zpci_list);
|
||||
static DEFINE_SPINLOCK(zpci_list_lock);
|
||||
static DEFINE_MUTEX(zpci_add_remove_lock);
|
||||
|
||||
static DECLARE_BITMAP(zpci_domain, ZPCI_DOMAIN_BITMAP_SIZE);
|
||||
static DEFINE_SPINLOCK(zpci_domain_lock);
|
||||
|
|
@ -70,6 +71,15 @@ EXPORT_SYMBOL_GPL(zpci_aipb);
|
|||
struct airq_iv *zpci_aif_sbv;
|
||||
EXPORT_SYMBOL_GPL(zpci_aif_sbv);
|
||||
|
||||
void zpci_zdev_put(struct zpci_dev *zdev)
|
||||
{
|
||||
if (!zdev)
|
||||
return;
|
||||
mutex_lock(&zpci_add_remove_lock);
|
||||
kref_put_lock(&zdev->kref, zpci_release_device, &zpci_list_lock);
|
||||
mutex_unlock(&zpci_add_remove_lock);
|
||||
}
|
||||
|
||||
struct zpci_dev *get_zdev_by_fid(u32 fid)
|
||||
{
|
||||
struct zpci_dev *tmp, *zdev = NULL;
|
||||
|
|
@ -837,6 +847,7 @@ int zpci_add_device(struct zpci_dev *zdev)
|
|||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&zpci_add_remove_lock);
|
||||
zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", zdev->fid, zdev->fh, zdev->state);
|
||||
rc = zpci_init_iommu(zdev);
|
||||
if (rc)
|
||||
|
|
@ -850,12 +861,14 @@ int zpci_add_device(struct zpci_dev *zdev)
|
|||
spin_lock(&zpci_list_lock);
|
||||
list_add_tail(&zdev->entry, &zpci_list);
|
||||
spin_unlock(&zpci_list_lock);
|
||||
mutex_unlock(&zpci_add_remove_lock);
|
||||
return 0;
|
||||
|
||||
error_destroy_iommu:
|
||||
zpci_destroy_iommu(zdev);
|
||||
error:
|
||||
zpci_dbg(0, "add fid:%x, rc:%d\n", zdev->fid, rc);
|
||||
mutex_unlock(&zpci_add_remove_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -925,21 +938,20 @@ int zpci_deconfigure_device(struct zpci_dev *zdev)
|
|||
* @zdev: the zpci_dev that was reserved
|
||||
*
|
||||
* Handle the case that a given zPCI function was reserved by another system.
|
||||
* After a call to this function the zpci_dev can not be found via
|
||||
* get_zdev_by_fid() anymore but may still be accessible via existing
|
||||
* references though it will not be functional anymore.
|
||||
*/
|
||||
void zpci_device_reserved(struct zpci_dev *zdev)
|
||||
{
|
||||
/*
|
||||
* Remove device from zpci_list as it is going away. This also
|
||||
* makes sure we ignore subsequent zPCI events for this device.
|
||||
*/
|
||||
spin_lock(&zpci_list_lock);
|
||||
list_del(&zdev->entry);
|
||||
spin_unlock(&zpci_list_lock);
|
||||
lockdep_assert_held(&zdev->state_lock);
|
||||
/* We may declare the device reserved multiple times */
|
||||
if (zdev->state == ZPCI_FN_STATE_RESERVED)
|
||||
return;
|
||||
zdev->state = ZPCI_FN_STATE_RESERVED;
|
||||
zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
|
||||
/*
|
||||
* The underlying device is gone. Allow the zdev to be freed
|
||||
* as soon as all other references are gone by accounting for
|
||||
* the removal as a dropped reference.
|
||||
*/
|
||||
zpci_zdev_put(zdev);
|
||||
}
|
||||
|
||||
|
|
@ -947,13 +959,14 @@ void zpci_release_device(struct kref *kref)
|
|||
{
|
||||
struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
|
||||
|
||||
lockdep_assert_held(&zpci_add_remove_lock);
|
||||
WARN_ON(zdev->state != ZPCI_FN_STATE_RESERVED);
|
||||
|
||||
if (zdev->zbus->bus)
|
||||
zpci_bus_remove_device(zdev, false);
|
||||
|
||||
if (zdev_enabled(zdev))
|
||||
zpci_disable_device(zdev);
|
||||
/*
|
||||
* We already hold zpci_list_lock thanks to kref_put_lock().
|
||||
* This makes sure no new reference can be taken from the list.
|
||||
*/
|
||||
list_del(&zdev->entry);
|
||||
spin_unlock(&zpci_list_lock);
|
||||
|
||||
if (zdev->has_hp_slot)
|
||||
zpci_exit_slot(zdev);
|
||||
|
|
|
|||
|
|
@ -21,11 +21,8 @@ int zpci_bus_scan_device(struct zpci_dev *zdev);
|
|||
void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);
|
||||
|
||||
void zpci_release_device(struct kref *kref);
|
||||
static inline void zpci_zdev_put(struct zpci_dev *zdev)
|
||||
{
|
||||
if (zdev)
|
||||
kref_put(&zdev->kref, zpci_release_device);
|
||||
}
|
||||
|
||||
void zpci_zdev_put(struct zpci_dev *zdev);
|
||||
|
||||
static inline void zpci_zdev_get(struct zpci_dev *zdev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -335,6 +335,22 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
|
|||
zdev->state = ZPCI_FN_STATE_STANDBY;
|
||||
}
|
||||
|
||||
static void zpci_event_reappear(struct zpci_dev *zdev)
|
||||
{
|
||||
lockdep_assert_held(&zdev->state_lock);
|
||||
/*
|
||||
* The zdev is in the reserved state. This means that it was presumed to
|
||||
* go away but there are still undropped references. Now, the platform
|
||||
* announced its availability again. Bring back the lingering zdev
|
||||
* to standby. This is safe because we hold a temporary reference
|
||||
* now so that it won't go away. Account for the re-appearance of the
|
||||
* underlying device by incrementing the reference count.
|
||||
*/
|
||||
zdev->state = ZPCI_FN_STATE_STANDBY;
|
||||
zpci_zdev_get(zdev);
|
||||
zpci_dbg(1, "rea fid:%x, fh:%x\n", zdev->fid, zdev->fh);
|
||||
}
|
||||
|
||||
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||
{
|
||||
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
|
||||
|
|
@ -358,8 +374,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
if (zdev->state == ZPCI_FN_STATE_RESERVED)
|
||||
zpci_event_reappear(zdev);
|
||||
/* the configuration request may be stale */
|
||||
if (zdev->state != ZPCI_FN_STATE_STANDBY)
|
||||
else if (zdev->state != ZPCI_FN_STATE_STANDBY)
|
||||
break;
|
||||
zdev->state = ZPCI_FN_STATE_CONFIGURED;
|
||||
}
|
||||
|
|
@ -375,6 +393,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
if (zdev->state == ZPCI_FN_STATE_RESERVED)
|
||||
zpci_event_reappear(zdev);
|
||||
zpci_update_fh(zdev, ccdf->fh);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ static inline int __pcistb_mio_inuser(
|
|||
u64 len, u8 *status)
|
||||
{
|
||||
int cc, exception;
|
||||
bool sacf_flag;
|
||||
|
||||
exception = 1;
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile (
|
||||
" sacf 256\n"
|
||||
"0: .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[src]\n"
|
||||
|
|
@ -44,6 +46,7 @@ static inline int __pcistb_mio_inuser(
|
|||
: CC_OUT(cc, cc), [len] "+d" (len), [exc] "+d" (exception)
|
||||
: [ioaddr] "a" (ioaddr), [src] "Q" (*((u8 __force *)src))
|
||||
: CC_CLOBBER_LIST("memory"));
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*status = len >> 24 & 0xff;
|
||||
return exception ? -ENXIO : CC_TRANSFORM(cc);
|
||||
}
|
||||
|
|
@ -54,6 +57,7 @@ static inline int __pcistg_mio_inuser(
|
|||
{
|
||||
union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen};
|
||||
int cc, exception;
|
||||
bool sacf_flag;
|
||||
u64 val = 0;
|
||||
u64 cnt = ulen;
|
||||
u8 tmp;
|
||||
|
|
@ -64,6 +68,7 @@ static inline int __pcistg_mio_inuser(
|
|||
* address space. pcistg then uses the user mappings.
|
||||
*/
|
||||
exception = 1;
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile (
|
||||
" sacf 256\n"
|
||||
"0: llgc %[tmp],0(%[src])\n"
|
||||
|
|
@ -81,6 +86,7 @@ static inline int __pcistg_mio_inuser(
|
|||
CC_OUT(cc, cc), [ioaddr_len] "+&d" (ioaddr_len.pair)
|
||||
:
|
||||
: CC_CLOBBER_LIST("memory"));
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
*status = ioaddr_len.odd >> 24 & 0xff;
|
||||
|
||||
cc = exception ? -ENXIO : CC_TRANSFORM(cc);
|
||||
|
|
@ -204,6 +210,7 @@ static inline int __pcilg_mio_inuser(
|
|||
u64 ulen, u8 *status)
|
||||
{
|
||||
union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen};
|
||||
bool sacf_flag;
|
||||
u64 cnt = ulen;
|
||||
int shift = ulen * 8;
|
||||
int cc, exception;
|
||||
|
|
@ -215,6 +222,7 @@ static inline int __pcilg_mio_inuser(
|
|||
* user address @dst
|
||||
*/
|
||||
exception = 1;
|
||||
sacf_flag = enable_sacf_uaccess();
|
||||
asm_inline volatile (
|
||||
" sacf 256\n"
|
||||
"0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n"
|
||||
|
|
@ -236,10 +244,10 @@ static inline int __pcilg_mio_inuser(
|
|||
: [ioaddr_len] "+&d" (ioaddr_len.pair), [exc] "+d" (exception),
|
||||
CC_OUT(cc, cc), [val] "=d" (val),
|
||||
[dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp),
|
||||
[shift] "+d" (shift)
|
||||
[shift] "+a" (shift)
|
||||
:
|
||||
: CC_CLOBBER_LIST("memory"));
|
||||
|
||||
disable_sacf_uaccess(sacf_flag);
|
||||
cc = exception ? -ENXIO : CC_TRANSFORM(cc);
|
||||
/* did we write everything to the user space buffer? */
|
||||
if (!cc && cnt != 0)
|
||||
|
|
|
|||
|
|
@ -65,9 +65,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
|||
|
||||
rc = zpci_deconfigure_device(zdev);
|
||||
out:
|
||||
mutex_unlock(&zdev->state_lock);
|
||||
if (pdev)
|
||||
pci_dev_put(pdev);
|
||||
mutex_unlock(&zdev->state_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ dcssblk_load_segment(char *name, struct segment_info **seg_info)
|
|||
if (*seg_info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy((*seg_info)->segment_name, name);
|
||||
strscpy((*seg_info)->segment_name, name);
|
||||
|
||||
/* load the segment */
|
||||
rc = segment_load(name, SEGMENT_SHARED,
|
||||
|
|
@ -612,7 +612,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
|
|||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
strcpy(dev_info->segment_name, local_buf);
|
||||
strscpy(dev_info->segment_name, local_buf);
|
||||
dev_info->segment_type = seg_info->segment_type;
|
||||
INIT_LIST_HEAD(&dev_info->seg_list);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ struct tty3270 {
|
|||
|
||||
/* Input stuff. */
|
||||
char *prompt; /* Output string for input area. */
|
||||
size_t prompt_sz; /* Size of output string. */
|
||||
char *input; /* Input string for read request. */
|
||||
struct raw3270_request *read; /* Single read request. */
|
||||
struct raw3270_request *kreset; /* Single keyboard reset request. */
|
||||
|
|
@ -206,7 +207,7 @@ static int tty3270_input_size(int cols)
|
|||
|
||||
static void tty3270_update_prompt(struct tty3270 *tp, char *input)
|
||||
{
|
||||
strcpy(tp->prompt, input);
|
||||
strscpy(tp->prompt, input, tp->prompt_sz);
|
||||
tp->update_flags |= TTY_UPDATE_INPUT;
|
||||
tty3270_set_timer(tp, 1);
|
||||
}
|
||||
|
|
@ -971,6 +972,7 @@ static void tty3270_resize(struct raw3270_view *view,
|
|||
char *old_input, *new_input;
|
||||
struct tty_struct *tty;
|
||||
struct winsize ws;
|
||||
size_t prompt_sz;
|
||||
int new_allocated, old_allocated = tp->allocated_lines;
|
||||
|
||||
if (old_model == new_model &&
|
||||
|
|
@ -982,10 +984,11 @@ static void tty3270_resize(struct raw3270_view *view,
|
|||
return;
|
||||
}
|
||||
|
||||
new_input = kzalloc(tty3270_input_size(new_cols), GFP_KERNEL | GFP_DMA);
|
||||
prompt_sz = tty3270_input_size(new_cols);
|
||||
new_input = kzalloc(prompt_sz, GFP_KERNEL | GFP_DMA);
|
||||
if (!new_input)
|
||||
return;
|
||||
new_prompt = kzalloc(tty3270_input_size(new_cols), GFP_KERNEL);
|
||||
new_prompt = kzalloc(prompt_sz, GFP_KERNEL);
|
||||
if (!new_prompt)
|
||||
goto out_input;
|
||||
screen = tty3270_alloc_screen(tp, new_rows, new_cols, &new_allocated);
|
||||
|
|
@ -1010,6 +1013,7 @@ static void tty3270_resize(struct raw3270_view *view,
|
|||
old_rcl_lines = tp->rcl_lines;
|
||||
tp->input = new_input;
|
||||
tp->prompt = new_prompt;
|
||||
tp->prompt_sz = prompt_sz;
|
||||
tp->rcl_lines = new_rcl_lines;
|
||||
tp->rcl_read_index = 0;
|
||||
tp->rcl_write_index = 0;
|
||||
|
|
@ -1096,6 +1100,7 @@ static int
|
|||
tty3270_create_view(int index, struct tty3270 **newtp)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
size_t prompt_sz;
|
||||
int rc;
|
||||
|
||||
if (tty3270_max_index < index + 1)
|
||||
|
|
@ -1125,17 +1130,19 @@ tty3270_create_view(int index, struct tty3270 **newtp)
|
|||
goto out_free_screen;
|
||||
}
|
||||
|
||||
tp->input = kzalloc(tty3270_input_size(tp->view.cols), GFP_KERNEL | GFP_DMA);
|
||||
prompt_sz = tty3270_input_size(tp->view.cols);
|
||||
tp->input = kzalloc(prompt_sz, GFP_KERNEL | GFP_DMA);
|
||||
if (!tp->input) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_converted_line;
|
||||
}
|
||||
|
||||
tp->prompt = kzalloc(tty3270_input_size(tp->view.cols), GFP_KERNEL);
|
||||
tp->prompt = kzalloc(prompt_sz, GFP_KERNEL);
|
||||
if (!tp->prompt) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_input;
|
||||
}
|
||||
tp->prompt_sz = prompt_sz;
|
||||
|
||||
tp->rcl_lines = tty3270_alloc_recall(tp->view.cols);
|
||||
if (!tp->rcl_lines) {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
|
|||
goto out;
|
||||
}
|
||||
|
||||
len = strscpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
|
||||
len = strscpy(ldfpl->fident, ftp->fname);
|
||||
if (len < 0) {
|
||||
len = -EINVAL;
|
||||
goto out_free;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <asm/uv.h>
|
||||
#include <asm/chsc.h>
|
||||
#include <linux/mempool.h>
|
||||
|
||||
#include "ap_bus.h"
|
||||
#include "ap_debug.h"
|
||||
|
|
@ -102,6 +103,27 @@ static struct ap_config_info *const ap_qci_info_old = &qci[1];
|
|||
*/
|
||||
debug_info_t *ap_dbf_info;
|
||||
|
||||
/*
|
||||
* There is a need for a do-not-allocate-memory path through the AP bus
|
||||
* layer. The pkey layer may be triggered via the in-kernel interface from
|
||||
* a protected key crypto algorithm (namely PAES) to convert a secure key
|
||||
* into a protected key. This happens in a workqueue context, so sleeping
|
||||
* is allowed but memory allocations causing IO operations are not permitted.
|
||||
* To accomplish this, an AP message memory pool with pre-allocated space
|
||||
* is established. When ap_init_apmsg() with use_mempool set to true is
|
||||
* called, instead of kmalloc() the ap message buffer is allocated from
|
||||
* the ap_msg_pool. This pool only holds a limited amount of buffers:
|
||||
* ap_msg_pool_min_items with the item size AP_DEFAULT_MAX_MSG_SIZE and
|
||||
* exactly one of these items (if available) is returned if ap_init_apmsg()
|
||||
* with the use_mempool arg set to true is called. When this pool is exhausted
|
||||
* and use_mempool is set true, ap_init_apmsg() returns -ENOMEM without
|
||||
* any attempt to allocate memory and the caller has to deal with that.
|
||||
*/
|
||||
static mempool_t *ap_msg_pool;
|
||||
static unsigned int ap_msg_pool_min_items = 8;
|
||||
module_param_named(msgpool_min_items, ap_msg_pool_min_items, uint, 0440);
|
||||
MODULE_PARM_DESC(msgpool_min_items, "AP message pool minimal items");
|
||||
|
||||
/*
|
||||
* AP bus rescan related things.
|
||||
*/
|
||||
|
|
@ -547,6 +569,48 @@ static void ap_poll_thread_stop(void)
|
|||
#define is_card_dev(x) ((x)->parent == ap_root_device)
|
||||
#define is_queue_dev(x) ((x)->parent != ap_root_device)
|
||||
|
||||
/*
|
||||
* ap_init_apmsg() - Initialize ap_message.
|
||||
*/
|
||||
int ap_init_apmsg(struct ap_message *ap_msg, u32 flags)
|
||||
{
|
||||
unsigned int maxmsgsize;
|
||||
|
||||
memset(ap_msg, 0, sizeof(*ap_msg));
|
||||
ap_msg->flags = flags;
|
||||
|
||||
if (flags & AP_MSG_FLAG_MEMPOOL) {
|
||||
ap_msg->msg = mempool_alloc_preallocated(ap_msg_pool);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
maxmsgsize = atomic_read(&ap_max_msg_size);
|
||||
ap_msg->msg = kmalloc(maxmsgsize, GFP_KERNEL);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
ap_msg->bufsize = maxmsgsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ap_init_apmsg);
|
||||
|
||||
/*
|
||||
* ap_release_apmsg() - Release ap_message.
|
||||
*/
|
||||
void ap_release_apmsg(struct ap_message *ap_msg)
|
||||
{
|
||||
if (ap_msg->flags & AP_MSG_FLAG_MEMPOOL) {
|
||||
memzero_explicit(ap_msg->msg, ap_msg->bufsize);
|
||||
mempool_free(ap_msg->msg, ap_msg_pool);
|
||||
} else {
|
||||
kfree_sensitive(ap_msg->msg);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ap_release_apmsg);
|
||||
|
||||
/**
|
||||
* ap_bus_match()
|
||||
* @dev: Pointer to device
|
||||
|
|
@ -2431,6 +2495,14 @@ static int __init ap_module_init(void)
|
|||
/* init ap_queue hashtable */
|
||||
hash_init(ap_queues);
|
||||
|
||||
/* create ap msg buffer memory pool */
|
||||
ap_msg_pool = mempool_create_kmalloc_pool(ap_msg_pool_min_items,
|
||||
AP_DEFAULT_MAX_MSG_SIZE);
|
||||
if (!ap_msg_pool) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* set up the AP permissions (ioctls, ap and aq masks) */
|
||||
ap_perms_init();
|
||||
|
||||
|
|
@ -2477,6 +2549,7 @@ static int __init ap_module_init(void)
|
|||
out_bus:
|
||||
bus_unregister(&ap_bus_type);
|
||||
out:
|
||||
mempool_destroy(ap_msg_pool);
|
||||
ap_debug_exit();
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -2487,6 +2560,7 @@ static void __exit ap_module_exit(void)
|
|||
ap_irq_exit();
|
||||
root_device_unregister(ap_root_device);
|
||||
bus_unregister(&ap_bus_type);
|
||||
mempool_destroy(ap_msg_pool);
|
||||
ap_debug_exit();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,11 @@ struct ap_queue {
|
|||
|
||||
typedef enum ap_sm_wait (ap_func_t)(struct ap_queue *queue);
|
||||
|
||||
struct ap_response_type {
|
||||
struct completion work;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct ap_message {
|
||||
struct list_head list; /* Request queueing. */
|
||||
unsigned long psmid; /* Message id. */
|
||||
|
|
@ -222,7 +227,7 @@ struct ap_message {
|
|||
size_t bufsize; /* allocated msg buffer size */
|
||||
u16 flags; /* Flags, see AP_MSG_FLAG_xxx */
|
||||
int rc; /* Return code for this message */
|
||||
void *private; /* ap driver private pointer. */
|
||||
struct ap_response_type response;
|
||||
/* receive is called from tasklet context */
|
||||
void (*receive)(struct ap_queue *, struct ap_message *,
|
||||
struct ap_message *);
|
||||
|
|
@ -231,27 +236,10 @@ struct ap_message {
|
|||
#define AP_MSG_FLAG_SPECIAL 0x0001 /* flag msg as 'special' with NQAP */
|
||||
#define AP_MSG_FLAG_USAGE 0x0002 /* CCA, EP11: usage (no admin) msg */
|
||||
#define AP_MSG_FLAG_ADMIN 0x0004 /* CCA, EP11: admin (=control) msg */
|
||||
#define AP_MSG_FLAG_MEMPOOL 0x0008 /* ap msg buffer allocated via mempool */
|
||||
|
||||
/**
|
||||
* ap_init_message() - Initialize ap_message.
|
||||
* Initialize a message before using. Otherwise this might result in
|
||||
* unexpected behaviour.
|
||||
*/
|
||||
static inline void ap_init_message(struct ap_message *ap_msg)
|
||||
{
|
||||
memset(ap_msg, 0, sizeof(*ap_msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* ap_release_message() - Release ap_message.
|
||||
* Releases all memory used internal within the ap_message struct
|
||||
* Currently this is the message and private field.
|
||||
*/
|
||||
static inline void ap_release_message(struct ap_message *ap_msg)
|
||||
{
|
||||
kfree_sensitive(ap_msg->msg);
|
||||
kfree_sensitive(ap_msg->private);
|
||||
}
|
||||
int ap_init_apmsg(struct ap_message *ap_msg, u32 flags);
|
||||
void ap_release_apmsg(struct ap_message *ap_msg);
|
||||
|
||||
enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event);
|
||||
enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
*/
|
||||
static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
const u8 *key, size_t keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
|
@ -32,14 +33,14 @@ static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
rc = pkey_handler_key_to_protkey(apqns, nr_apqns,
|
||||
key, keylen,
|
||||
protkey, protkeylen,
|
||||
protkeytype);
|
||||
protkeytype, xflags);
|
||||
|
||||
/* if this did not work, try the slowpath way */
|
||||
if (rc == -ENODEV) {
|
||||
rc = pkey_handler_slowpath_key_to_protkey(apqns, nr_apqns,
|
||||
key, keylen,
|
||||
protkey, protkeylen,
|
||||
protkeytype);
|
||||
protkeytype, xflags);
|
||||
if (rc)
|
||||
rc = -ENODEV;
|
||||
}
|
||||
|
|
@ -52,16 +53,16 @@ static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
* In-Kernel function: Transform a key blob (of any type) into a protected key
|
||||
*/
|
||||
int pkey_key2protkey(const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = key2protkey(NULL, 0, key, keylen,
|
||||
protkey, protkeylen, protkeytype);
|
||||
protkey, protkeylen, protkeytype, xflags);
|
||||
if (rc == -ENODEV) {
|
||||
pkey_handler_request_modules();
|
||||
rc = key2protkey(NULL, 0, key, keylen,
|
||||
protkey, protkeylen, protkeytype);
|
||||
protkey, protkeylen, protkeytype, xflags);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
@ -103,7 +104,7 @@ static int pkey_ioctl_genseck(struct pkey_genseck __user *ugs)
|
|||
keybuflen = sizeof(kgs.seckey.seckey);
|
||||
rc = pkey_handler_gen_key(&apqn, 1,
|
||||
kgs.keytype, PKEY_TYPE_CCA_DATA, 0, 0,
|
||||
kgs.seckey.seckey, &keybuflen, NULL);
|
||||
kgs.seckey.seckey, &keybuflen, NULL, 0);
|
||||
pr_debug("gen_key()=%d\n", rc);
|
||||
if (!rc && copy_to_user(ugs, &kgs, sizeof(kgs)))
|
||||
rc = -EFAULT;
|
||||
|
|
@ -129,7 +130,7 @@ static int pkey_ioctl_clr2seck(struct pkey_clr2seck __user *ucs)
|
|||
kcs.keytype, PKEY_TYPE_CCA_DATA, 0, 0,
|
||||
kcs.clrkey.clrkey,
|
||||
pkey_keytype_aes_to_size(kcs.keytype),
|
||||
kcs.seckey.seckey, &keybuflen, NULL);
|
||||
kcs.seckey.seckey, &keybuflen, NULL, 0);
|
||||
pr_debug("clr_to_key()=%d\n", rc);
|
||||
if (!rc && copy_to_user(ucs, &kcs, sizeof(kcs)))
|
||||
rc = -EFAULT;
|
||||
|
|
@ -154,7 +155,8 @@ static int pkey_ioctl_sec2protk(struct pkey_sec2protk __user *usp)
|
|||
ksp.seckey.seckey,
|
||||
sizeof(ksp.seckey.seckey),
|
||||
ksp.protkey.protkey,
|
||||
&ksp.protkey.len, &ksp.protkey.type);
|
||||
&ksp.protkey.len, &ksp.protkey.type,
|
||||
0);
|
||||
pr_debug("key_to_protkey()=%d\n", rc);
|
||||
if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||
rc = -EFAULT;
|
||||
|
|
@ -198,7 +200,7 @@ static int pkey_ioctl_clr2protk(struct pkey_clr2protk __user *ucp)
|
|||
rc = key2protkey(NULL, 0,
|
||||
tmpbuf, sizeof(*t) + keylen,
|
||||
kcp.protkey.protkey,
|
||||
&kcp.protkey.len, &kcp.protkey.type);
|
||||
&kcp.protkey.len, &kcp.protkey.type, 0);
|
||||
pr_debug("key2protkey()=%d\n", rc);
|
||||
|
||||
kfree_sensitive(tmpbuf);
|
||||
|
|
@ -228,12 +230,12 @@ static int pkey_ioctl_findcard(struct pkey_findcard __user *ufc)
|
|||
rc = pkey_handler_apqns_for_key(kfc.seckey.seckey,
|
||||
sizeof(kfc.seckey.seckey),
|
||||
PKEY_FLAGS_MATCH_CUR_MKVP,
|
||||
apqns, &nr_apqns);
|
||||
apqns, &nr_apqns, 0);
|
||||
if (rc == -ENODEV)
|
||||
rc = pkey_handler_apqns_for_key(kfc.seckey.seckey,
|
||||
sizeof(kfc.seckey.seckey),
|
||||
PKEY_FLAGS_MATCH_ALT_MKVP,
|
||||
apqns, &nr_apqns);
|
||||
apqns, &nr_apqns, 0);
|
||||
pr_debug("apqns_for_key()=%d\n", rc);
|
||||
if (rc) {
|
||||
kfree(apqns);
|
||||
|
|
@ -262,7 +264,7 @@ static int pkey_ioctl_skey2pkey(struct pkey_skey2pkey __user *usp)
|
|||
sizeof(ksp.seckey.seckey),
|
||||
ksp.protkey.protkey,
|
||||
&ksp.protkey.len,
|
||||
&ksp.protkey.type);
|
||||
&ksp.protkey.type, 0);
|
||||
pr_debug("key_to_protkey()=%d\n", rc);
|
||||
if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||
rc = -EFAULT;
|
||||
|
|
@ -285,7 +287,7 @@ static int pkey_ioctl_verifykey(struct pkey_verifykey __user *uvk)
|
|||
rc = pkey_handler_verify_key(kvk.seckey.seckey,
|
||||
sizeof(kvk.seckey.seckey),
|
||||
&kvk.cardnr, &kvk.domain,
|
||||
&keytype, &keybitsize, &flags);
|
||||
&keytype, &keybitsize, &flags, 0);
|
||||
pr_debug("verify_key()=%d\n", rc);
|
||||
if (!rc && keytype != PKEY_TYPE_CCA_DATA)
|
||||
rc = -EINVAL;
|
||||
|
|
@ -312,7 +314,7 @@ static int pkey_ioctl_genprotk(struct pkey_genprotk __user *ugp)
|
|||
rc = pkey_handler_gen_key(NULL, 0, kgp.keytype,
|
||||
PKEY_TYPE_PROTKEY, 0, 0,
|
||||
kgp.protkey.protkey, &kgp.protkey.len,
|
||||
&kgp.protkey.type);
|
||||
&kgp.protkey.type, 0);
|
||||
pr_debug("gen_key()=%d\n", rc);
|
||||
if (!rc && copy_to_user(ugp, &kgp, sizeof(kgp)))
|
||||
rc = -EFAULT;
|
||||
|
|
@ -354,7 +356,7 @@ static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp)
|
|||
memcpy(t->protkey, kvp.protkey.protkey, kvp.protkey.len);
|
||||
|
||||
rc = pkey_handler_verify_key(tmpbuf, sizeof(*t),
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL, NULL, 0);
|
||||
pr_debug("verify_key()=%d\n", rc);
|
||||
|
||||
kfree_sensitive(tmpbuf);
|
||||
|
|
@ -377,7 +379,7 @@ static int pkey_ioctl_kblob2protk(struct pkey_kblob2pkey __user *utp)
|
|||
ktp.protkey.len = sizeof(ktp.protkey.protkey);
|
||||
rc = key2protkey(NULL, 0, kkey, ktp.keylen,
|
||||
ktp.protkey.protkey, &ktp.protkey.len,
|
||||
&ktp.protkey.type);
|
||||
&ktp.protkey.type, 0);
|
||||
pr_debug("key2protkey()=%d\n", rc);
|
||||
kfree_sensitive(kkey);
|
||||
if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
|
|
@ -414,7 +416,7 @@ static int pkey_ioctl_genseck2(struct pkey_genseck2 __user *ugs)
|
|||
}
|
||||
rc = pkey_handler_gen_key(apqns, kgs.apqn_entries,
|
||||
u, kgs.type, kgs.size, kgs.keygenflags,
|
||||
kkey, &klen, NULL);
|
||||
kkey, &klen, NULL, 0);
|
||||
pr_debug("gen_key()=%d\n", rc);
|
||||
kfree(apqns);
|
||||
if (rc) {
|
||||
|
|
@ -471,7 +473,7 @@ static int pkey_ioctl_clr2seck2(struct pkey_clr2seck2 __user *ucs)
|
|||
rc = pkey_handler_clr_to_key(apqns, kcs.apqn_entries,
|
||||
u, kcs.type, kcs.size, kcs.keygenflags,
|
||||
kcs.clrkey.clrkey, kcs.size / 8,
|
||||
kkey, &klen, NULL);
|
||||
kkey, &klen, NULL, 0);
|
||||
pr_debug("clr_to_key()=%d\n", rc);
|
||||
kfree(apqns);
|
||||
if (rc) {
|
||||
|
|
@ -514,7 +516,7 @@ static int pkey_ioctl_verifykey2(struct pkey_verifykey2 __user *uvk)
|
|||
|
||||
rc = pkey_handler_verify_key(kkey, kvk.keylen,
|
||||
&kvk.cardnr, &kvk.domain,
|
||||
&kvk.type, &kvk.size, &kvk.flags);
|
||||
&kvk.type, &kvk.size, &kvk.flags, 0);
|
||||
pr_debug("verify_key()=%d\n", rc);
|
||||
|
||||
kfree_sensitive(kkey);
|
||||
|
|
@ -544,7 +546,7 @@ static int pkey_ioctl_kblob2protk2(struct pkey_kblob2pkey2 __user *utp)
|
|||
ktp.protkey.len = sizeof(ktp.protkey.protkey);
|
||||
rc = key2protkey(apqns, ktp.apqn_entries, kkey, ktp.keylen,
|
||||
ktp.protkey.protkey, &ktp.protkey.len,
|
||||
&ktp.protkey.type);
|
||||
&ktp.protkey.type, 0);
|
||||
pr_debug("key2protkey()=%d\n", rc);
|
||||
kfree(apqns);
|
||||
kfree_sensitive(kkey);
|
||||
|
|
@ -579,7 +581,7 @@ static int pkey_ioctl_apqns4k(struct pkey_apqns4key __user *uak)
|
|||
return PTR_ERR(kkey);
|
||||
}
|
||||
rc = pkey_handler_apqns_for_key(kkey, kak.keylen, kak.flags,
|
||||
apqns, &nr_apqns);
|
||||
apqns, &nr_apqns, 0);
|
||||
pr_debug("apqns_for_key()=%d\n", rc);
|
||||
kfree_sensitive(kkey);
|
||||
if (rc && rc != -ENOSPC) {
|
||||
|
|
@ -626,7 +628,7 @@ static int pkey_ioctl_apqns4kt(struct pkey_apqns4keytype __user *uat)
|
|||
}
|
||||
rc = pkey_handler_apqns_for_keytype(kat.type,
|
||||
kat.cur_mkvp, kat.alt_mkvp,
|
||||
kat.flags, apqns, &nr_apqns);
|
||||
kat.flags, apqns, &nr_apqns, 0);
|
||||
pr_debug("apqns_for_keytype()=%d\n", rc);
|
||||
if (rc && rc != -ENOSPC) {
|
||||
kfree(apqns);
|
||||
|
|
@ -678,7 +680,7 @@ static int pkey_ioctl_kblob2protk3(struct pkey_kblob2pkey3 __user *utp)
|
|||
return -ENOMEM;
|
||||
}
|
||||
rc = key2protkey(apqns, ktp.apqn_entries, kkey, ktp.keylen,
|
||||
protkey, &protkeylen, &ktp.pkeytype);
|
||||
protkey, &protkeylen, &ktp.pkeytype, 0);
|
||||
pr_debug("key2protkey()=%d\n", rc);
|
||||
kfree(apqns);
|
||||
kfree_sensitive(kkey);
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ EXPORT_SYMBOL(pkey_handler_put);
|
|||
|
||||
int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h;
|
||||
int rc = -ENODEV;
|
||||
|
|
@ -159,7 +160,7 @@ int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (h && h->key_to_protkey) {
|
||||
rc = h->key_to_protkey(apqns, nr_apqns, key, keylen,
|
||||
protkey, protkeylen,
|
||||
protkeytype);
|
||||
protkeytype, xflags);
|
||||
}
|
||||
pkey_handler_put(h);
|
||||
|
||||
|
|
@ -177,7 +178,7 @@ int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
|
|||
size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype)
|
||||
u32 *protkeytype, u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h, *htmp[10];
|
||||
int i, n = 0, rc = -ENODEV;
|
||||
|
|
@ -199,7 +200,7 @@ int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
|
|||
rc = h->slowpath_key_to_protkey(apqns, nr_apqns,
|
||||
key, keylen,
|
||||
protkey, protkeylen,
|
||||
protkeytype);
|
||||
protkeytype, xflags);
|
||||
module_put(h->module);
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +211,7 @@ EXPORT_SYMBOL(pkey_handler_slowpath_key_to_protkey);
|
|||
int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 keysubtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h;
|
||||
int rc = -ENODEV;
|
||||
|
|
@ -219,7 +220,7 @@ int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (h && h->gen_key) {
|
||||
rc = h->gen_key(apqns, nr_apqns, keytype, keysubtype,
|
||||
keybitsize, flags,
|
||||
keybuf, keybuflen, keyinfo);
|
||||
keybuf, keybuflen, keyinfo, xflags);
|
||||
}
|
||||
pkey_handler_put(h);
|
||||
|
||||
|
|
@ -231,7 +232,8 @@ int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
u32 keytype, u32 keysubtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
const u8 *clrkey, u32 clrkeylen,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo,
|
||||
u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h;
|
||||
int rc = -ENODEV;
|
||||
|
|
@ -240,7 +242,7 @@ int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (h && h->clr_to_key) {
|
||||
rc = h->clr_to_key(apqns, nr_apqns, keytype, keysubtype,
|
||||
keybitsize, flags, clrkey, clrkeylen,
|
||||
keybuf, keybuflen, keyinfo);
|
||||
keybuf, keybuflen, keyinfo, xflags);
|
||||
}
|
||||
pkey_handler_put(h);
|
||||
|
||||
|
|
@ -250,7 +252,8 @@ EXPORT_SYMBOL(pkey_handler_clr_to_key);
|
|||
|
||||
int pkey_handler_verify_key(const u8 *key, u32 keylen,
|
||||
u16 *card, u16 *dom,
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags)
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags,
|
||||
u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h;
|
||||
int rc = -ENODEV;
|
||||
|
|
@ -258,7 +261,7 @@ int pkey_handler_verify_key(const u8 *key, u32 keylen,
|
|||
h = pkey_handler_get_keybased(key, keylen);
|
||||
if (h && h->verify_key) {
|
||||
rc = h->verify_key(key, keylen, card, dom,
|
||||
keytype, keybitsize, flags);
|
||||
keytype, keybitsize, flags, xflags);
|
||||
}
|
||||
pkey_handler_put(h);
|
||||
|
||||
|
|
@ -267,14 +270,16 @@ int pkey_handler_verify_key(const u8 *key, u32 keylen,
|
|||
EXPORT_SYMBOL(pkey_handler_verify_key);
|
||||
|
||||
int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns)
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h;
|
||||
int rc = -ENODEV;
|
||||
|
||||
h = pkey_handler_get_keybased(key, keylen);
|
||||
if (h && h->apqns_for_key)
|
||||
rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns);
|
||||
rc = h->apqns_for_key(key, keylen, flags, apqns, nr_apqns,
|
||||
xflags);
|
||||
pkey_handler_put(h);
|
||||
|
||||
return rc;
|
||||
|
|
@ -283,7 +288,8 @@ EXPORT_SYMBOL(pkey_handler_apqns_for_key);
|
|||
|
||||
int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype,
|
||||
u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns)
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 xflags)
|
||||
{
|
||||
const struct pkey_handler *h;
|
||||
int rc = -ENODEV;
|
||||
|
|
@ -292,7 +298,7 @@ int pkey_handler_apqns_for_keytype(enum pkey_key_type keysubtype,
|
|||
if (h && h->apqns_for_keytype) {
|
||||
rc = h->apqns_for_keytype(keysubtype,
|
||||
cur_mkvp, alt_mkvp, flags,
|
||||
apqns, nr_apqns);
|
||||
apqns, nr_apqns, xflags);
|
||||
}
|
||||
pkey_handler_put(h);
|
||||
|
||||
|
|
|
|||
|
|
@ -159,29 +159,33 @@ struct pkey_handler {
|
|||
bool (*is_supported_keytype)(enum pkey_key_type);
|
||||
int (*key_to_protkey)(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags);
|
||||
int (*slowpath_key_to_protkey)(const struct pkey_apqn *apqns,
|
||||
size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype);
|
||||
u32 *protkeytype, u32 xflags);
|
||||
int (*gen_key)(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 keysubtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo);
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags);
|
||||
int (*clr_to_key)(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 keysubtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
const u8 *clrkey, u32 clrkeylen,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo);
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags);
|
||||
int (*verify_key)(const u8 *key, u32 keylen,
|
||||
u16 *card, u16 *dom,
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags);
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags,
|
||||
u32 xflags);
|
||||
int (*apqns_for_key)(const u8 *key, u32 keylen, u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns);
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 xflags);
|
||||
int (*apqns_for_keytype)(enum pkey_key_type ktype,
|
||||
u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns);
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 xflags);
|
||||
/* used internal by pkey base */
|
||||
struct list_head list;
|
||||
};
|
||||
|
|
@ -199,29 +203,34 @@ void pkey_handler_put(const struct pkey_handler *handler);
|
|||
|
||||
int pkey_handler_key_to_protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags);
|
||||
int pkey_handler_slowpath_key_to_protkey(const struct pkey_apqn *apqns,
|
||||
size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype);
|
||||
u32 *protkeytype, u32 xflags);
|
||||
int pkey_handler_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 keysubtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo);
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo, u32 xflags);
|
||||
int pkey_handler_clr_to_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 keysubtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
const u8 *clrkey, u32 clrkeylen,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo);
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo,
|
||||
u32 xflags);
|
||||
int pkey_handler_verify_key(const u8 *key, u32 keylen,
|
||||
u16 *card, u16 *dom,
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags);
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags,
|
||||
u32 xflags);
|
||||
int pkey_handler_apqns_for_key(const u8 *key, u32 keylen, u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns);
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 xflags);
|
||||
int pkey_handler_apqns_for_keytype(enum pkey_key_type ktype,
|
||||
u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns);
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 xflags);
|
||||
|
||||
/*
|
||||
* Unconditional try to load all handler modules
|
||||
|
|
|
|||
|
|
@ -70,12 +70,15 @@ static bool is_cca_keytype(enum pkey_key_type key_type)
|
|||
}
|
||||
|
||||
static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns)
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns, u32 pflags)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
u32 _nr_apqns, *_apqns = NULL;
|
||||
u32 _apqns[MAXAPQNSINLIST], _nr_apqns = ARRAY_SIZE(_apqns);
|
||||
u32 xflags;
|
||||
int rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
if (!flags)
|
||||
flags = PKEY_FLAGS_MATCH_CUR_MKVP | PKEY_FLAGS_MATCH_ALT_MKVP;
|
||||
|
||||
|
|
@ -107,9 +110,9 @@ static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
|||
/* unknown CCA internal token type */
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, AES_MK_SET,
|
||||
cur_mkvp, old_mkvp, 1);
|
||||
cur_mkvp, old_mkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -126,9 +129,9 @@ static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
|||
/* unknown CCA internal 2 token type */
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, APKA_MK_SET,
|
||||
cur_mkvp, old_mkvp, 1);
|
||||
cur_mkvp, old_mkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -147,18 +150,21 @@ static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
|||
*nr_apqns = _nr_apqns;
|
||||
|
||||
out:
|
||||
kfree(_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cca_apqns4type(enum pkey_key_type ktype,
|
||||
u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns)
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns,
|
||||
u32 pflags)
|
||||
{
|
||||
u32 _nr_apqns, *_apqns = NULL;
|
||||
u32 _apqns[MAXAPQNSINLIST], _nr_apqns = ARRAY_SIZE(_apqns);
|
||||
u32 xflags;
|
||||
int rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
zcrypt_wait_api_operational();
|
||||
|
||||
if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {
|
||||
|
|
@ -171,9 +177,9 @@ static int cca_apqns4type(enum pkey_key_type ktype,
|
|||
old_mkvp = *((u64 *)alt_mkvp);
|
||||
if (ktype == PKEY_TYPE_CCA_CIPHER)
|
||||
minhwtype = ZCRYPT_CEX6;
|
||||
rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, AES_MK_SET,
|
||||
cur_mkvp, old_mkvp, 1);
|
||||
cur_mkvp, old_mkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -184,9 +190,9 @@ static int cca_apqns4type(enum pkey_key_type ktype,
|
|||
cur_mkvp = *((u64 *)cur_mkvp);
|
||||
if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
|
||||
old_mkvp = *((u64 *)alt_mkvp);
|
||||
rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
rc = cca_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, APKA_MK_SET,
|
||||
cur_mkvp, old_mkvp, 1);
|
||||
cur_mkvp, old_mkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -205,19 +211,22 @@ static int cca_apqns4type(enum pkey_key_type ktype,
|
|||
*nr_apqns = _nr_apqns;
|
||||
|
||||
out:
|
||||
kfree(_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 pflags)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
struct pkey_apqn *local_apqns = NULL;
|
||||
struct pkey_apqn _apqns[MAXAPQNSINLIST];
|
||||
u32 xflags;
|
||||
int i, rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
if (keylen < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -253,14 +262,10 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (!apqns || (nr_apqns == 1 &&
|
||||
apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
|
||||
nr_apqns = MAXAPQNSINLIST;
|
||||
local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
|
||||
GFP_KERNEL);
|
||||
if (!local_apqns)
|
||||
return -ENOMEM;
|
||||
rc = cca_apqns4key(key, keylen, 0, local_apqns, &nr_apqns);
|
||||
rc = cca_apqns4key(key, keylen, 0, _apqns, &nr_apqns, pflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
apqns = local_apqns;
|
||||
apqns = _apqns;
|
||||
}
|
||||
|
||||
for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
|
||||
|
|
@ -268,16 +273,16 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
hdr->version == TOKVER_CCA_AES) {
|
||||
rc = cca_sec2protkey(apqns[i].card, apqns[i].domain,
|
||||
key, protkey,
|
||||
protkeylen, protkeytype);
|
||||
protkeylen, protkeytype, xflags);
|
||||
} else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
|
||||
hdr->version == TOKVER_CCA_VLSC) {
|
||||
rc = cca_cipher2protkey(apqns[i].card, apqns[i].domain,
|
||||
key, protkey,
|
||||
protkeylen, protkeytype);
|
||||
protkeylen, protkeytype, xflags);
|
||||
} else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
|
||||
rc = cca_ecc2protkey(apqns[i].card, apqns[i].domain,
|
||||
key, protkey,
|
||||
protkeylen, protkeytype);
|
||||
protkeylen, protkeytype, xflags);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
|
|
@ -285,7 +290,6 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
}
|
||||
|
||||
out:
|
||||
kfree(local_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -302,10 +306,13 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
static int cca_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 subtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo, u32 pflags)
|
||||
{
|
||||
struct pkey_apqn *local_apqns = NULL;
|
||||
struct pkey_apqn _apqns[MAXAPQNSINLIST];
|
||||
int i, len, rc;
|
||||
u32 xflags;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
/* check keytype, subtype, keybitsize */
|
||||
switch (keytype) {
|
||||
|
|
@ -340,32 +347,27 @@ static int cca_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (!apqns || (nr_apqns == 1 &&
|
||||
apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
|
||||
nr_apqns = MAXAPQNSINLIST;
|
||||
local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
|
||||
GFP_KERNEL);
|
||||
if (!local_apqns)
|
||||
return -ENOMEM;
|
||||
rc = cca_apqns4type(subtype, NULL, NULL, 0,
|
||||
local_apqns, &nr_apqns);
|
||||
_apqns, &nr_apqns, pflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
apqns = local_apqns;
|
||||
apqns = _apqns;
|
||||
}
|
||||
|
||||
for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
|
||||
if (subtype == PKEY_TYPE_CCA_CIPHER) {
|
||||
rc = cca_gencipherkey(apqns[i].card, apqns[i].domain,
|
||||
keybitsize, flags,
|
||||
keybuf, keybuflen);
|
||||
keybuf, keybuflen, xflags);
|
||||
} else {
|
||||
/* PKEY_TYPE_CCA_DATA */
|
||||
rc = cca_genseckey(apqns[i].card, apqns[i].domain,
|
||||
keybitsize, keybuf);
|
||||
keybitsize, keybuf, xflags);
|
||||
*keybuflen = (rc ? 0 : SECKEYBLOBSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(local_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -383,10 +385,13 @@ static int cca_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
u32 keytype, u32 subtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
const u8 *clrkey, u32 clrkeylen,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo, u32 pflags)
|
||||
{
|
||||
struct pkey_apqn *local_apqns = NULL;
|
||||
struct pkey_apqn _apqns[MAXAPQNSINLIST];
|
||||
int i, len, rc;
|
||||
u32 xflags;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
/* check keytype, subtype, clrkeylen, keybitsize */
|
||||
switch (keytype) {
|
||||
|
|
@ -426,44 +431,42 @@ static int cca_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (!apqns || (nr_apqns == 1 &&
|
||||
apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
|
||||
nr_apqns = MAXAPQNSINLIST;
|
||||
local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
|
||||
GFP_KERNEL);
|
||||
if (!local_apqns)
|
||||
return -ENOMEM;
|
||||
rc = cca_apqns4type(subtype, NULL, NULL, 0,
|
||||
local_apqns, &nr_apqns);
|
||||
_apqns, &nr_apqns, pflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
apqns = local_apqns;
|
||||
apqns = _apqns;
|
||||
}
|
||||
|
||||
for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
|
||||
if (subtype == PKEY_TYPE_CCA_CIPHER) {
|
||||
rc = cca_clr2cipherkey(apqns[i].card, apqns[i].domain,
|
||||
keybitsize, flags, clrkey,
|
||||
keybuf, keybuflen);
|
||||
keybuf, keybuflen, xflags);
|
||||
} else {
|
||||
/* PKEY_TYPE_CCA_DATA */
|
||||
rc = cca_clr2seckey(apqns[i].card, apqns[i].domain,
|
||||
keybitsize, clrkey, keybuf);
|
||||
keybitsize, clrkey, keybuf, xflags);
|
||||
*keybuflen = (rc ? 0 : SECKEYBLOBSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(local_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cca_verifykey(const u8 *key, u32 keylen,
|
||||
u16 *card, u16 *dom,
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags)
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags, u32 pflags)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
u32 nr_apqns, *apqns = NULL;
|
||||
u32 apqns[MAXAPQNSINLIST], nr_apqns = ARRAY_SIZE(apqns);
|
||||
u32 xflags;
|
||||
int rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
if (keylen < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -478,15 +481,16 @@ static int cca_verifykey(const u8 *key, u32 keylen,
|
|||
goto out;
|
||||
*keytype = PKEY_TYPE_CCA_DATA;
|
||||
*keybitsize = t->bitsize;
|
||||
rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
|
||||
rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
|
||||
ZCRYPT_CEX3C, AES_MK_SET,
|
||||
t->mkvp, 0, 1);
|
||||
t->mkvp, 0, xflags);
|
||||
if (!rc)
|
||||
*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
|
||||
if (rc == -ENODEV) {
|
||||
rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
|
||||
nr_apqns = ARRAY_SIZE(apqns);
|
||||
rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
|
||||
ZCRYPT_CEX3C, AES_MK_SET,
|
||||
0, t->mkvp, 1);
|
||||
0, t->mkvp, xflags);
|
||||
if (!rc)
|
||||
*flags = PKEY_FLAGS_MATCH_ALT_MKVP;
|
||||
}
|
||||
|
|
@ -511,15 +515,16 @@ static int cca_verifykey(const u8 *key, u32 keylen,
|
|||
*keybitsize = PKEY_SIZE_AES_192;
|
||||
else if (!t->plfver && t->wpllen == 640)
|
||||
*keybitsize = PKEY_SIZE_AES_256;
|
||||
rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
|
||||
rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
|
||||
ZCRYPT_CEX6, AES_MK_SET,
|
||||
t->mkvp0, 0, 1);
|
||||
t->mkvp0, 0, xflags);
|
||||
if (!rc)
|
||||
*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
|
||||
if (rc == -ENODEV) {
|
||||
rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,
|
||||
nr_apqns = ARRAY_SIZE(apqns);
|
||||
rc = cca_findcard2(apqns, &nr_apqns, *card, *dom,
|
||||
ZCRYPT_CEX6, AES_MK_SET,
|
||||
0, t->mkvp0, 1);
|
||||
0, t->mkvp0, xflags);
|
||||
if (!rc)
|
||||
*flags = PKEY_FLAGS_MATCH_ALT_MKVP;
|
||||
}
|
||||
|
|
@ -535,7 +540,6 @@ static int cca_verifykey(const u8 *key, u32 keylen,
|
|||
}
|
||||
|
||||
out:
|
||||
kfree(apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -551,12 +555,12 @@ static int cca_slowpath_key2protkey(const struct pkey_apqn *apqns,
|
|||
size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype)
|
||||
u32 *protkeytype, u32 pflags)
|
||||
{
|
||||
const struct keytoken_header *hdr = (const struct keytoken_header *)key;
|
||||
const struct clearkeytoken *t = (const struct clearkeytoken *)key;
|
||||
u8 tmpbuf[SECKEYBLOBSIZE]; /* 64 bytes */
|
||||
u32 tmplen, keysize = 0;
|
||||
u8 *tmpbuf;
|
||||
int i, rc;
|
||||
|
||||
if (keylen < sizeof(*hdr))
|
||||
|
|
@ -568,26 +572,20 @@ static int cca_slowpath_key2protkey(const struct pkey_apqn *apqns,
|
|||
if (!keysize || t->len != keysize)
|
||||
return -EINVAL;
|
||||
|
||||
/* alloc tmp key buffer */
|
||||
tmpbuf = kmalloc(SECKEYBLOBSIZE, GFP_ATOMIC);
|
||||
if (!tmpbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* try two times in case of failure */
|
||||
for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
|
||||
tmplen = SECKEYBLOBSIZE;
|
||||
rc = cca_clr2key(NULL, 0, t->keytype, PKEY_TYPE_CCA_DATA,
|
||||
8 * keysize, 0, t->clearkey, t->len,
|
||||
tmpbuf, &tmplen, NULL);
|
||||
tmpbuf, &tmplen, NULL, pflags);
|
||||
pr_debug("cca_clr2key()=%d\n", rc);
|
||||
if (rc)
|
||||
continue;
|
||||
rc = cca_key2protkey(NULL, 0, tmpbuf, tmplen,
|
||||
protkey, protkeylen, protkeytype);
|
||||
protkey, protkeylen, protkeytype, pflags);
|
||||
pr_debug("cca_key2protkey()=%d\n", rc);
|
||||
}
|
||||
|
||||
kfree(tmpbuf);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,12 +70,15 @@ static bool is_ep11_keytype(enum pkey_key_type key_type)
|
|||
}
|
||||
|
||||
static int ep11_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns)
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns, u32 pflags)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
u32 _nr_apqns, *_apqns = NULL;
|
||||
u32 _apqns[MAXAPQNSINLIST], _nr_apqns = ARRAY_SIZE(_apqns);
|
||||
u32 xflags;
|
||||
int rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
if (!flags)
|
||||
flags = PKEY_FLAGS_MATCH_CUR_MKVP;
|
||||
|
||||
|
|
@ -98,8 +101,8 @@ static int ep11_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
|||
minhwtype = ZCRYPT_CEX7;
|
||||
api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
|
||||
}
|
||||
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, api, kb->wkvp);
|
||||
rc = ep11_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, api, kb->wkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -115,8 +118,8 @@ static int ep11_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
|||
minhwtype = ZCRYPT_CEX7;
|
||||
api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
|
||||
}
|
||||
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, api, kb->wkvp);
|
||||
rc = ep11_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
minhwtype, api, kb->wkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -135,18 +138,20 @@ static int ep11_apqns4key(const u8 *key, u32 keylen, u32 flags,
|
|||
*nr_apqns = _nr_apqns;
|
||||
|
||||
out:
|
||||
kfree(_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ep11_apqns4type(enum pkey_key_type ktype,
|
||||
u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns)
|
||||
struct pkey_apqn *apqns, size_t *nr_apqns, u32 pflags)
|
||||
{
|
||||
u32 _nr_apqns, *_apqns = NULL;
|
||||
u32 _apqns[MAXAPQNSINLIST], _nr_apqns = ARRAY_SIZE(_apqns);
|
||||
u32 xflags;
|
||||
int rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
zcrypt_wait_api_operational();
|
||||
|
||||
if (ktype == PKEY_TYPE_EP11 ||
|
||||
|
|
@ -158,8 +163,8 @@ static int ep11_apqns4type(enum pkey_key_type ktype,
|
|||
if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
|
||||
wkvp = cur_mkvp;
|
||||
api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
|
||||
rc = ep11_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, api, wkvp);
|
||||
rc = ep11_findcard2(_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
|
||||
ZCRYPT_CEX7, api, wkvp, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -178,19 +183,22 @@ static int ep11_apqns4type(enum pkey_key_type ktype,
|
|||
*nr_apqns = _nr_apqns;
|
||||
|
||||
out:
|
||||
kfree(_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ep11_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 pflags)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
struct pkey_apqn *local_apqns = NULL;
|
||||
struct pkey_apqn _apqns[MAXAPQNSINLIST];
|
||||
u32 xflags;
|
||||
int i, rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
if (keylen < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -225,14 +233,10 @@ static int ep11_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (!apqns || (nr_apqns == 1 &&
|
||||
apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
|
||||
nr_apqns = MAXAPQNSINLIST;
|
||||
local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
|
||||
GFP_KERNEL);
|
||||
if (!local_apqns)
|
||||
return -ENOMEM;
|
||||
rc = ep11_apqns4key(key, keylen, 0, local_apqns, &nr_apqns);
|
||||
rc = ep11_apqns4key(key, keylen, 0, _apqns, &nr_apqns, pflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
apqns = local_apqns;
|
||||
apqns = _apqns;
|
||||
}
|
||||
|
||||
for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
|
||||
|
|
@ -241,19 +245,19 @@ static int ep11_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) {
|
||||
rc = ep11_kblob2protkey(apqns[i].card, apqns[i].domain,
|
||||
key, hdr->len, protkey,
|
||||
protkeylen, protkeytype);
|
||||
protkeylen, protkeytype, xflags);
|
||||
} else if (hdr->type == TOKTYPE_NON_CCA &&
|
||||
hdr->version == TOKVER_EP11_ECC_WITH_HEADER &&
|
||||
is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) {
|
||||
rc = ep11_kblob2protkey(apqns[i].card, apqns[i].domain,
|
||||
key, hdr->len, protkey,
|
||||
protkeylen, protkeytype);
|
||||
protkeylen, protkeytype, xflags);
|
||||
} else if (hdr->type == TOKTYPE_NON_CCA &&
|
||||
hdr->version == TOKVER_EP11_AES &&
|
||||
is_ep11_keyblob(key)) {
|
||||
rc = ep11_kblob2protkey(apqns[i].card, apqns[i].domain,
|
||||
key, hdr->len, protkey,
|
||||
protkeylen, protkeytype);
|
||||
protkeylen, protkeytype, xflags);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
|
|
@ -261,7 +265,6 @@ static int ep11_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
}
|
||||
|
||||
out:
|
||||
kfree(local_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -278,10 +281,13 @@ static int ep11_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
static int ep11_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
u32 keytype, u32 subtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo, u32 pflags)
|
||||
{
|
||||
struct pkey_apqn *local_apqns = NULL;
|
||||
struct pkey_apqn _apqns[MAXAPQNSINLIST];
|
||||
int i, len, rc;
|
||||
u32 xflags;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
/* check keytype, subtype, keybitsize */
|
||||
switch (keytype) {
|
||||
|
|
@ -316,25 +322,20 @@ static int ep11_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (!apqns || (nr_apqns == 1 &&
|
||||
apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
|
||||
nr_apqns = MAXAPQNSINLIST;
|
||||
local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
|
||||
GFP_KERNEL);
|
||||
if (!local_apqns)
|
||||
return -ENOMEM;
|
||||
rc = ep11_apqns4type(subtype, NULL, NULL, 0,
|
||||
local_apqns, &nr_apqns);
|
||||
_apqns, &nr_apqns, pflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
apqns = local_apqns;
|
||||
apqns = _apqns;
|
||||
}
|
||||
|
||||
for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
|
||||
rc = ep11_genaeskey(apqns[i].card, apqns[i].domain,
|
||||
keybitsize, flags,
|
||||
keybuf, keybuflen, subtype);
|
||||
keybuf, keybuflen, subtype, xflags);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(local_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -352,10 +353,13 @@ static int ep11_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
u32 keytype, u32 subtype,
|
||||
u32 keybitsize, u32 flags,
|
||||
const u8 *clrkey, u32 clrkeylen,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *_keyinfo, u32 pflags)
|
||||
{
|
||||
struct pkey_apqn *local_apqns = NULL;
|
||||
struct pkey_apqn _apqns[MAXAPQNSINLIST];
|
||||
int i, len, rc;
|
||||
u32 xflags;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
/* check keytype, subtype, clrkeylen, keybitsize */
|
||||
switch (keytype) {
|
||||
|
|
@ -395,37 +399,35 @@ static int ep11_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,
|
|||
if (!apqns || (nr_apqns == 1 &&
|
||||
apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {
|
||||
nr_apqns = MAXAPQNSINLIST;
|
||||
local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),
|
||||
GFP_KERNEL);
|
||||
if (!local_apqns)
|
||||
return -ENOMEM;
|
||||
rc = ep11_apqns4type(subtype, NULL, NULL, 0,
|
||||
local_apqns, &nr_apqns);
|
||||
_apqns, &nr_apqns, pflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
apqns = local_apqns;
|
||||
apqns = _apqns;
|
||||
}
|
||||
|
||||
for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {
|
||||
rc = ep11_clr2keyblob(apqns[i].card, apqns[i].domain,
|
||||
keybitsize, flags, clrkey,
|
||||
keybuf, keybuflen, subtype);
|
||||
keybuf, keybuflen, subtype, xflags);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(local_apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ep11_verifykey(const u8 *key, u32 keylen,
|
||||
u16 *card, u16 *dom,
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags)
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags, u32 pflags)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
u32 nr_apqns, *apqns = NULL;
|
||||
u32 apqns[MAXAPQNSINLIST], nr_apqns = ARRAY_SIZE(apqns);
|
||||
u32 xflags;
|
||||
int rc;
|
||||
|
||||
xflags = pflags & PKEY_XFLAG_NOMEMALLOC ? ZCRYPT_XFLAG_NOMEMALLOC : 0;
|
||||
|
||||
if (keylen < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -443,9 +445,9 @@ static int ep11_verifykey(const u8 *key, u32 keylen,
|
|||
*keybitsize = kb->head.bitlen;
|
||||
|
||||
api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
|
||||
rc = ep11_findcard2(&apqns, &nr_apqns, *card, *dom,
|
||||
rc = ep11_findcard2(apqns, &nr_apqns, *card, *dom,
|
||||
ZCRYPT_CEX7, api,
|
||||
ep11_kb_wkvp(key, keylen));
|
||||
ep11_kb_wkvp(key, keylen), xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -467,9 +469,9 @@ static int ep11_verifykey(const u8 *key, u32 keylen,
|
|||
*keybitsize = kh->bitlen;
|
||||
|
||||
api = ap_is_se_guest() ? EP11_API_V6 : EP11_API_V4;
|
||||
rc = ep11_findcard2(&apqns, &nr_apqns, *card, *dom,
|
||||
rc = ep11_findcard2(apqns, &nr_apqns, *card, *dom,
|
||||
ZCRYPT_CEX7, api,
|
||||
ep11_kb_wkvp(key, keylen));
|
||||
ep11_kb_wkvp(key, keylen), xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -484,7 +486,6 @@ static int ep11_verifykey(const u8 *key, u32 keylen,
|
|||
}
|
||||
|
||||
out:
|
||||
kfree(apqns);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -500,12 +501,12 @@ static int ep11_slowpath_key2protkey(const struct pkey_apqn *apqns,
|
|||
size_t nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype)
|
||||
u32 *protkeytype, u32 pflags)
|
||||
{
|
||||
const struct keytoken_header *hdr = (const struct keytoken_header *)key;
|
||||
const struct clearkeytoken *t = (const struct clearkeytoken *)key;
|
||||
u8 tmpbuf[MAXEP11AESKEYBLOBSIZE]; /* 336 bytes */
|
||||
u32 tmplen, keysize = 0;
|
||||
u8 *tmpbuf;
|
||||
int i, rc;
|
||||
|
||||
if (keylen < sizeof(*hdr))
|
||||
|
|
@ -517,26 +518,20 @@ static int ep11_slowpath_key2protkey(const struct pkey_apqn *apqns,
|
|||
if (!keysize || t->len != keysize)
|
||||
return -EINVAL;
|
||||
|
||||
/* alloc tmp key buffer */
|
||||
tmpbuf = kmalloc(MAXEP11AESKEYBLOBSIZE, GFP_ATOMIC);
|
||||
if (!tmpbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* try two times in case of failure */
|
||||
for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {
|
||||
tmplen = MAXEP11AESKEYBLOBSIZE;
|
||||
rc = ep11_clr2key(NULL, 0, t->keytype, PKEY_TYPE_EP11,
|
||||
8 * keysize, 0, t->clearkey, t->len,
|
||||
tmpbuf, &tmplen, NULL);
|
||||
tmpbuf, &tmplen, NULL, pflags);
|
||||
pr_debug("ep11_clr2key()=%d\n", rc);
|
||||
if (rc)
|
||||
continue;
|
||||
rc = ep11_key2protkey(NULL, 0, tmpbuf, tmplen,
|
||||
protkey, protkeylen, protkeytype);
|
||||
protkey, protkeylen, protkeytype, pflags);
|
||||
pr_debug("ep11_key2protkey()=%d\n", rc);
|
||||
}
|
||||
|
||||
kfree(tmpbuf);
|
||||
pr_debug("rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -406,7 +406,8 @@ static int pckmo_verify_key(const u8 *key, u32 keylen)
|
|||
static int pkey_pckmo_key2protkey(const struct pkey_apqn *_apqns,
|
||||
size_t _nr_apqns,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *keyinfo)
|
||||
u8 *protkey, u32 *protkeylen, u32 *keyinfo,
|
||||
u32 _xflags __always_unused)
|
||||
{
|
||||
return pckmo_key2protkey(key, keylen,
|
||||
protkey, protkeylen, keyinfo);
|
||||
|
|
@ -415,7 +416,8 @@ static int pkey_pckmo_key2protkey(const struct pkey_apqn *_apqns,
|
|||
static int pkey_pckmo_gen_key(const struct pkey_apqn *_apqns, size_t _nr_apqns,
|
||||
u32 keytype, u32 keysubtype,
|
||||
u32 _keybitsize, u32 _flags,
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo)
|
||||
u8 *keybuf, u32 *keybuflen, u32 *keyinfo,
|
||||
u32 _xflags __always_unused)
|
||||
{
|
||||
return pckmo_gen_protkey(keytype, keysubtype,
|
||||
keybuf, keybuflen, keyinfo);
|
||||
|
|
@ -423,7 +425,8 @@ static int pkey_pckmo_gen_key(const struct pkey_apqn *_apqns, size_t _nr_apqns,
|
|||
|
||||
static int pkey_pckmo_verifykey(const u8 *key, u32 keylen,
|
||||
u16 *_card, u16 *_dom,
|
||||
u32 *_keytype, u32 *_keybitsize, u32 *_flags)
|
||||
u32 *_keytype, u32 *_keybitsize,
|
||||
u32 *_flags, u32 _xflags __always_unused)
|
||||
{
|
||||
return pckmo_verify_key(key, keylen);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ static int sys_pkey_handler_gen_key(u32 keytype, u32 keysubtype,
|
|||
rc = pkey_handler_gen_key(NULL, 0,
|
||||
keytype, keysubtype,
|
||||
keybitsize, flags,
|
||||
keybuf, keybuflen, keyinfo);
|
||||
keybuf, keybuflen, keyinfo, 0);
|
||||
if (rc == -ENODEV) {
|
||||
pkey_handler_request_modules();
|
||||
rc = pkey_handler_gen_key(NULL, 0,
|
||||
keytype, keysubtype,
|
||||
keybitsize, flags,
|
||||
keybuf, keybuflen, keyinfo);
|
||||
keybuf, keybuflen, keyinfo, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@ MODULE_LICENSE("GPL");
|
|||
MODULE_AUTHOR("IBM Corporation");
|
||||
MODULE_DESCRIPTION("s390 protected key UV handler");
|
||||
|
||||
/*
|
||||
* One pre-allocated uv_secret_list for use with uv_find_secret()
|
||||
*/
|
||||
static struct uv_secret_list *uv_list;
|
||||
static DEFINE_MUTEX(uv_list_mutex);
|
||||
|
||||
/*
|
||||
* UV secret token struct and defines.
|
||||
*/
|
||||
|
|
@ -85,13 +91,26 @@ static bool is_uv_keytype(enum pkey_key_type keytype)
|
|||
}
|
||||
}
|
||||
|
||||
static int get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
struct uv_secret_list_item_hdr *secret)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&uv_list_mutex);
|
||||
memset(uv_list, 0, sizeof(*uv_list));
|
||||
rc = uv_find_secret(secret_id, uv_list, secret);
|
||||
mutex_unlock(&uv_list_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int retrieve_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
u16 *secret_type, u8 *buf, u32 *buflen)
|
||||
{
|
||||
struct uv_secret_list_item_hdr secret_meta_data;
|
||||
int rc;
|
||||
|
||||
rc = uv_get_secret_metadata(secret_id, &secret_meta_data);
|
||||
rc = get_secret_metadata(secret_id, &secret_meta_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -172,7 +191,8 @@ static int uv_get_size_and_type(u16 secret_type, u32 *pkeysize, u32 *pkeytype)
|
|||
static int uv_key2protkey(const struct pkey_apqn *_apqns __always_unused,
|
||||
size_t _nr_apqns __always_unused,
|
||||
const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *keyinfo)
|
||||
u8 *protkey, u32 *protkeylen, u32 *keyinfo,
|
||||
u32 _xflags __always_unused)
|
||||
{
|
||||
struct uvsecrettoken *t = (struct uvsecrettoken *)key;
|
||||
u32 pkeysize, pkeytype;
|
||||
|
|
@ -214,7 +234,8 @@ static int uv_key2protkey(const struct pkey_apqn *_apqns __always_unused,
|
|||
static int uv_verifykey(const u8 *key, u32 keylen,
|
||||
u16 *_card __always_unused,
|
||||
u16 *_dom __always_unused,
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags)
|
||||
u32 *keytype, u32 *keybitsize, u32 *flags,
|
||||
u32 xflags __always_unused)
|
||||
{
|
||||
struct uvsecrettoken *t = (struct uvsecrettoken *)key;
|
||||
struct uv_secret_list_item_hdr secret_meta_data;
|
||||
|
|
@ -225,7 +246,7 @@ static int uv_verifykey(const u8 *key, u32 keylen,
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = uv_get_secret_metadata(t->secret_id, &secret_meta_data);
|
||||
rc = get_secret_metadata(t->secret_id, &secret_meta_data);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
|
|
@ -263,13 +284,23 @@ static struct pkey_handler uv_handler = {
|
|||
*/
|
||||
static int __init pkey_uv_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!is_prot_virt_guest())
|
||||
return -ENODEV;
|
||||
|
||||
if (!test_bit_inv(BIT_UVC_CMD_RETR_SECRET, uv_info.inst_calls_list))
|
||||
return -ENODEV;
|
||||
|
||||
return pkey_handler_register(&uv_handler);
|
||||
uv_list = kmalloc(sizeof(*uv_list), GFP_KERNEL);
|
||||
if (!uv_list)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = pkey_handler_register(&uv_handler);
|
||||
if (rc)
|
||||
kfree(uv_list);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -278,6 +309,9 @@ static int __init pkey_uv_init(void)
|
|||
static void __exit pkey_uv_exit(void)
|
||||
{
|
||||
pkey_handler_unregister(&uv_handler);
|
||||
mutex_lock(&uv_list_mutex);
|
||||
kvfree(uv_list);
|
||||
mutex_unlock(&uv_list_mutex);
|
||||
}
|
||||
|
||||
module_cpu_feature_match(S390_CPU_FEATURE_UV, pkey_uv_init);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \
|
|||
"Copyright IBM Corp. 2001, 2012");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
unsigned int zcrypt_mempool_threshold = 5;
|
||||
module_param_named(mempool_threshold, zcrypt_mempool_threshold, uint, 0440);
|
||||
MODULE_PARM_DESC(mempool_threshold, "CCA and EP11 request/reply mempool minimal items (min: 1)");
|
||||
|
||||
/*
|
||||
* zcrypt tracepoint functions
|
||||
*/
|
||||
|
|
@ -642,16 +646,17 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
|
|||
struct zcrypt_queue *zq, *pref_zq;
|
||||
struct ap_message ap_msg;
|
||||
unsigned int wgt = 0, pref_wgt = 0;
|
||||
unsigned int func_code;
|
||||
int cpen, qpen, qid = 0, rc = -ENODEV;
|
||||
unsigned int func_code = 0;
|
||||
int cpen, qpen, qid = 0, rc;
|
||||
struct module *mod;
|
||||
|
||||
trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO);
|
||||
|
||||
ap_init_message(&ap_msg);
|
||||
rc = ap_init_apmsg(&ap_msg, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (mex->outputdatalength < mex->inputdatalength) {
|
||||
func_code = 0;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -728,7 +733,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
|
|||
spin_unlock(&zcrypt_list_lock);
|
||||
|
||||
out:
|
||||
ap_release_message(&ap_msg);
|
||||
ap_release_apmsg(&ap_msg);
|
||||
if (tr) {
|
||||
tr->last_rc = rc;
|
||||
tr->last_qid = qid;
|
||||
|
|
@ -746,16 +751,17 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
|
|||
struct zcrypt_queue *zq, *pref_zq;
|
||||
struct ap_message ap_msg;
|
||||
unsigned int wgt = 0, pref_wgt = 0;
|
||||
unsigned int func_code;
|
||||
int cpen, qpen, qid = 0, rc = -ENODEV;
|
||||
unsigned int func_code = 0;
|
||||
int cpen, qpen, qid = 0, rc;
|
||||
struct module *mod;
|
||||
|
||||
trace_s390_zcrypt_req(crt, TP_ICARSACRT);
|
||||
|
||||
ap_init_message(&ap_msg);
|
||||
rc = ap_init_apmsg(&ap_msg, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (crt->outputdatalength < crt->inputdatalength) {
|
||||
func_code = 0;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -832,7 +838,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
|
|||
spin_unlock(&zcrypt_list_lock);
|
||||
|
||||
out:
|
||||
ap_release_message(&ap_msg);
|
||||
ap_release_apmsg(&ap_msg);
|
||||
if (tr) {
|
||||
tr->last_rc = rc;
|
||||
tr->last_qid = qid;
|
||||
|
|
@ -842,23 +848,28 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
|
||||
static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
|
||||
struct zcrypt_track *tr,
|
||||
struct ica_xcRB *xcrb)
|
||||
{
|
||||
bool userspace = xflags & ZCRYPT_XFLAG_USERSPACE;
|
||||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
struct ap_message ap_msg;
|
||||
unsigned int wgt = 0, pref_wgt = 0;
|
||||
unsigned int func_code;
|
||||
unsigned int func_code = 0;
|
||||
unsigned short *domain, tdom;
|
||||
int cpen, qpen, qid = 0, rc = -ENODEV;
|
||||
int cpen, qpen, qid = 0, rc;
|
||||
struct module *mod;
|
||||
|
||||
trace_s390_zcrypt_req(xcrb, TB_ZSECSENDCPRB);
|
||||
|
||||
xcrb->status = 0;
|
||||
ap_init_message(&ap_msg);
|
||||
|
||||
rc = ap_init_apmsg(&ap_msg, xflags & ZCRYPT_XFLAG_NOMEMALLOC ?
|
||||
AP_MSG_FLAG_MEMPOOL : 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = prep_cca_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
|
||||
if (rc)
|
||||
|
|
@ -962,7 +973,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
|
|||
spin_unlock(&zcrypt_list_lock);
|
||||
|
||||
out:
|
||||
ap_release_message(&ap_msg);
|
||||
ap_release_apmsg(&ap_msg);
|
||||
if (tr) {
|
||||
tr->last_rc = rc;
|
||||
tr->last_qid = qid;
|
||||
|
|
@ -972,7 +983,7 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
|
|||
return rc;
|
||||
}
|
||||
|
||||
long zcrypt_send_cprb(struct ica_xcRB *xcrb)
|
||||
long zcrypt_send_cprb(struct ica_xcRB *xcrb, u32 xflags)
|
||||
{
|
||||
struct zcrypt_track tr;
|
||||
int rc;
|
||||
|
|
@ -980,13 +991,13 @@ long zcrypt_send_cprb(struct ica_xcRB *xcrb)
|
|||
memset(&tr, 0, sizeof(tr));
|
||||
|
||||
do {
|
||||
rc = _zcrypt_send_cprb(false, &ap_perms, &tr, xcrb);
|
||||
rc = _zcrypt_send_cprb(xflags, &ap_perms, &tr, xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
|
||||
/* on ENODEV failure: retry once again after a requested rescan */
|
||||
if (rc == -ENODEV && zcrypt_process_rescan())
|
||||
do {
|
||||
rc = _zcrypt_send_cprb(false, &ap_perms, &tr, xcrb);
|
||||
rc = _zcrypt_send_cprb(xflags, &ap_perms, &tr, xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
|
||||
rc = -EIO;
|
||||
|
|
@ -1024,50 +1035,50 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
|
|||
return false;
|
||||
}
|
||||
|
||||
static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
|
||||
static long _zcrypt_send_ep11_cprb(u32 xflags, struct ap_perms *perms,
|
||||
struct zcrypt_track *tr,
|
||||
struct ep11_urb *xcrb)
|
||||
{
|
||||
bool userspace = xflags & ZCRYPT_XFLAG_USERSPACE;
|
||||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
struct ep11_target_dev *targets;
|
||||
struct ep11_target_dev *targets = NULL;
|
||||
unsigned short target_num;
|
||||
unsigned int wgt = 0, pref_wgt = 0;
|
||||
unsigned int func_code, domain;
|
||||
unsigned int func_code = 0, domain;
|
||||
struct ap_message ap_msg;
|
||||
int cpen, qpen, qid = 0, rc = -ENODEV;
|
||||
int cpen, qpen, qid = 0, rc;
|
||||
struct module *mod;
|
||||
|
||||
trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB);
|
||||
|
||||
ap_init_message(&ap_msg);
|
||||
rc = ap_init_apmsg(&ap_msg, xflags & ZCRYPT_XFLAG_NOMEMALLOC ?
|
||||
AP_MSG_FLAG_MEMPOOL : 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
target_num = (unsigned short)xcrb->targets_num;
|
||||
|
||||
/* empty list indicates autoselect (all available targets) */
|
||||
targets = NULL;
|
||||
rc = -ENOMEM;
|
||||
if (target_num != 0) {
|
||||
struct ep11_target_dev __user *uptr;
|
||||
|
||||
targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL);
|
||||
if (!targets) {
|
||||
func_code = 0;
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uptr = (struct ep11_target_dev __force __user *)xcrb->targets;
|
||||
if (z_copy_from_user(userspace, targets, uptr,
|
||||
target_num * sizeof(*targets))) {
|
||||
func_code = 0;
|
||||
rc = -EFAULT;
|
||||
goto out_free;
|
||||
if (userspace) {
|
||||
targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL);
|
||||
if (!targets)
|
||||
goto out;
|
||||
if (copy_from_user(targets, xcrb->targets,
|
||||
target_num * sizeof(*targets))) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
targets = (struct ep11_target_dev __force __kernel *)xcrb->targets;
|
||||
}
|
||||
}
|
||||
|
||||
rc = prep_ep11_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
goto out;
|
||||
print_hex_dump_debug("ep11req: ", DUMP_PREFIX_ADDRESS, 16, 1,
|
||||
ap_msg.msg, ap_msg.len, false);
|
||||
|
||||
|
|
@ -1075,11 +1086,11 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
|
|||
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
|
||||
if (!test_bit_inv(domain, perms->adm)) {
|
||||
rc = -ENODEV;
|
||||
goto out_free;
|
||||
goto out;
|
||||
}
|
||||
} else if ((ap_msg.flags & AP_MSG_FLAG_USAGE) == 0) {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out_free;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1147,7 +1158,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
|
|||
pr_debug("no match for address ff.ffff => ENODEV\n");
|
||||
}
|
||||
rc = -ENODEV;
|
||||
goto out_free;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qid = pref_zq->queue->qid;
|
||||
|
|
@ -1161,10 +1172,10 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
|
|||
zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
|
||||
spin_unlock(&zcrypt_list_lock);
|
||||
|
||||
out_free:
|
||||
kfree(targets);
|
||||
out:
|
||||
ap_release_message(&ap_msg);
|
||||
if (userspace)
|
||||
kfree(targets);
|
||||
ap_release_apmsg(&ap_msg);
|
||||
if (tr) {
|
||||
tr->last_rc = rc;
|
||||
tr->last_qid = qid;
|
||||
|
|
@ -1174,7 +1185,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
|
|||
return rc;
|
||||
}
|
||||
|
||||
long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
||||
long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb, u32 xflags)
|
||||
{
|
||||
struct zcrypt_track tr;
|
||||
int rc;
|
||||
|
|
@ -1182,13 +1193,13 @@ long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
|||
memset(&tr, 0, sizeof(tr));
|
||||
|
||||
do {
|
||||
rc = _zcrypt_send_ep11_cprb(false, &ap_perms, &tr, xcrb);
|
||||
rc = _zcrypt_send_ep11_cprb(xflags, &ap_perms, &tr, xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
|
||||
/* on ENODEV failure: retry once again after a requested rescan */
|
||||
if (rc == -ENODEV && zcrypt_process_rescan())
|
||||
do {
|
||||
rc = _zcrypt_send_ep11_cprb(false, &ap_perms, &tr, xcrb);
|
||||
rc = _zcrypt_send_ep11_cprb(xflags, &ap_perms, &tr, xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
|
||||
rc = -EIO;
|
||||
|
|
@ -1204,7 +1215,7 @@ static long zcrypt_rng(char *buffer)
|
|||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
unsigned int wgt = 0, pref_wgt = 0;
|
||||
unsigned int func_code;
|
||||
unsigned int func_code = 0;
|
||||
struct ap_message ap_msg;
|
||||
unsigned int domain;
|
||||
int qid = 0, rc = -ENODEV;
|
||||
|
|
@ -1212,7 +1223,9 @@ static long zcrypt_rng(char *buffer)
|
|||
|
||||
trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB);
|
||||
|
||||
ap_init_message(&ap_msg);
|
||||
rc = ap_init_apmsg(&ap_msg, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = prep_rng_ap_msg(&ap_msg, &func_code, &domain);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
|
@ -1258,7 +1271,7 @@ static long zcrypt_rng(char *buffer)
|
|||
spin_unlock(&zcrypt_list_lock);
|
||||
|
||||
out:
|
||||
ap_release_message(&ap_msg);
|
||||
ap_release_apmsg(&ap_msg);
|
||||
trace_s390_zcrypt_rep(buffer, func_code, rc,
|
||||
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
|
||||
return rc;
|
||||
|
|
@ -1291,19 +1304,25 @@ static void zcrypt_device_status_mask(struct zcrypt_device_status *devstatus)
|
|||
spin_unlock(&zcrypt_list_lock);
|
||||
}
|
||||
|
||||
void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus)
|
||||
void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus,
|
||||
int maxcard, int maxqueue)
|
||||
{
|
||||
struct zcrypt_card *zc;
|
||||
struct zcrypt_queue *zq;
|
||||
struct zcrypt_device_status_ext *stat;
|
||||
int card, queue;
|
||||
|
||||
maxcard = min_t(int, maxcard, MAX_ZDEV_CARDIDS_EXT);
|
||||
maxqueue = min_t(int, maxqueue, MAX_ZDEV_DOMAINS_EXT);
|
||||
|
||||
spin_lock(&zcrypt_list_lock);
|
||||
for_each_zcrypt_card(zc) {
|
||||
for_each_zcrypt_queue(zq, zc) {
|
||||
card = AP_QID_CARD(zq->queue->qid);
|
||||
queue = AP_QID_QUEUE(zq->queue->qid);
|
||||
stat = &devstatus[card * AP_DOMAINS + queue];
|
||||
if (card >= maxcard || queue >= maxqueue)
|
||||
continue;
|
||||
stat = &devstatus[card * maxqueue + queue];
|
||||
stat->hwtype = zc->card->ap_dev.device_type;
|
||||
stat->functions = zc->card->hwinfo.fac >> 26;
|
||||
stat->qid = zq->queue->qid;
|
||||
|
|
@ -1523,6 +1542,7 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
|
|||
int rc;
|
||||
struct ica_xcRB xcrb;
|
||||
struct zcrypt_track tr;
|
||||
u32 xflags = ZCRYPT_XFLAG_USERSPACE;
|
||||
struct ica_xcRB __user *uxcrb = (void __user *)arg;
|
||||
|
||||
memset(&tr, 0, sizeof(tr));
|
||||
|
|
@ -1530,13 +1550,13 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
|
|||
return -EFAULT;
|
||||
|
||||
do {
|
||||
rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
|
||||
rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
|
||||
/* on ENODEV failure: retry once again after a requested rescan */
|
||||
if (rc == -ENODEV && zcrypt_process_rescan())
|
||||
do {
|
||||
rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb);
|
||||
rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
|
||||
rc = -EIO;
|
||||
|
|
@ -1553,6 +1573,7 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
|
|||
int rc;
|
||||
struct ep11_urb xcrb;
|
||||
struct zcrypt_track tr;
|
||||
u32 xflags = ZCRYPT_XFLAG_USERSPACE;
|
||||
struct ep11_urb __user *uxcrb = (void __user *)arg;
|
||||
|
||||
memset(&tr, 0, sizeof(tr));
|
||||
|
|
@ -1560,13 +1581,13 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
|
|||
return -EFAULT;
|
||||
|
||||
do {
|
||||
rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
|
||||
rc = _zcrypt_send_ep11_cprb(xflags, perms, &tr, &xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
|
||||
/* on ENODEV failure: retry once again after a requested rescan */
|
||||
if (rc == -ENODEV && zcrypt_process_rescan())
|
||||
do {
|
||||
rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
|
||||
rc = _zcrypt_send_ep11_cprb(xflags, perms, &tr, &xcrb);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
|
||||
rc = -EIO;
|
||||
|
|
@ -1607,7 +1628,9 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
zcrypt_device_status_mask_ext(device_status,
|
||||
MAX_ZDEV_CARDIDS_EXT,
|
||||
MAX_ZDEV_DOMAINS_EXT);
|
||||
if (copy_to_user((char __user *)arg, device_status,
|
||||
total_size))
|
||||
rc = -EFAULT;
|
||||
|
|
@ -1827,6 +1850,7 @@ static long trans_xcrb32(struct ap_perms *perms, struct file *filp,
|
|||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct compat_ica_xcrb __user *uxcrb32 = compat_ptr(arg);
|
||||
u32 xflags = ZCRYPT_XFLAG_USERSPACE;
|
||||
struct compat_ica_xcrb xcrb32;
|
||||
struct zcrypt_track tr;
|
||||
struct ica_xcRB xcrb64;
|
||||
|
|
@ -1856,13 +1880,13 @@ static long trans_xcrb32(struct ap_perms *perms, struct file *filp,
|
|||
xcrb64.priority_window = xcrb32.priority_window;
|
||||
xcrb64.status = xcrb32.status;
|
||||
do {
|
||||
rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
|
||||
rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb64);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
|
||||
/* on ENODEV failure: retry once again after a requested rescan */
|
||||
if (rc == -ENODEV && zcrypt_process_rescan())
|
||||
do {
|
||||
rc = _zcrypt_send_cprb(true, perms, &tr, &xcrb64);
|
||||
rc = _zcrypt_send_cprb(xflags, perms, &tr, &xcrb64);
|
||||
} while (rc == -EAGAIN && ++tr.again_counter < TRACK_AGAIN_MAX);
|
||||
if (rc == -EAGAIN && tr.again_counter >= TRACK_AGAIN_MAX)
|
||||
rc = -EIO;
|
||||
|
|
@ -2132,13 +2156,27 @@ int __init zcrypt_api_init(void)
|
|||
{
|
||||
int rc;
|
||||
|
||||
/* make sure the mempool threshold is >= 1 */
|
||||
if (zcrypt_mempool_threshold < 1) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = zcrypt_debug_init();
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = zcdn_init();
|
||||
if (rc)
|
||||
goto out;
|
||||
goto out_zcdn_init_failed;
|
||||
|
||||
rc = zcrypt_ccamisc_init();
|
||||
if (rc)
|
||||
goto out_ccamisc_init_failed;
|
||||
|
||||
rc = zcrypt_ep11misc_init();
|
||||
if (rc)
|
||||
goto out_ep11misc_init_failed;
|
||||
|
||||
/* Register the request sprayer. */
|
||||
rc = misc_register(&zcrypt_misc_device);
|
||||
|
|
@ -2151,7 +2189,12 @@ int __init zcrypt_api_init(void)
|
|||
return 0;
|
||||
|
||||
out_misc_register_failed:
|
||||
zcrypt_ep11misc_exit();
|
||||
out_ep11misc_init_failed:
|
||||
zcrypt_ccamisc_exit();
|
||||
out_ccamisc_init_failed:
|
||||
zcdn_exit();
|
||||
out_zcdn_init_failed:
|
||||
zcrypt_debug_exit();
|
||||
out:
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ struct zcrypt_track {
|
|||
#define TRACK_AGAIN_CARD_WEIGHT_PENALTY 1000
|
||||
#define TRACK_AGAIN_QUEUE_WEIGHT_PENALTY 10000
|
||||
|
||||
/*
|
||||
* xflags - to be used with zcrypt_send_cprb() and
|
||||
* zcrypt_send_ep11_cprb() for the xflags parameter.
|
||||
*/
|
||||
#define ZCRYPT_XFLAG_USERSPACE 0x0001 /* data ptrs address userspace */
|
||||
#define ZCRYPT_XFLAG_NOMEMALLOC 0x0002 /* do not allocate memory via kmalloc */
|
||||
|
||||
struct zcrypt_ops {
|
||||
long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *,
|
||||
struct ap_message *);
|
||||
|
|
@ -132,6 +139,8 @@ extern atomic_t zcrypt_rescan_req;
|
|||
extern spinlock_t zcrypt_list_lock;
|
||||
extern struct list_head zcrypt_card_list;
|
||||
|
||||
extern unsigned int zcrypt_mempool_threshold;
|
||||
|
||||
#define for_each_zcrypt_card(_zc) \
|
||||
list_for_each_entry(_zc, &zcrypt_card_list, list)
|
||||
|
||||
|
|
@ -161,9 +170,10 @@ void zcrypt_msgtype_unregister(struct zcrypt_ops *);
|
|||
struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int);
|
||||
int zcrypt_api_init(void);
|
||||
void zcrypt_api_exit(void);
|
||||
long zcrypt_send_cprb(struct ica_xcRB *xcRB);
|
||||
long zcrypt_send_ep11_cprb(struct ep11_urb *urb);
|
||||
void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus);
|
||||
long zcrypt_send_cprb(struct ica_xcRB *xcRB, u32 xflags);
|
||||
long zcrypt_send_ep11_cprb(struct ep11_urb *urb, u32 xflags);
|
||||
void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus,
|
||||
int maxcard, int maxqueue);
|
||||
int zcrypt_device_status_ext(int card, int queue,
|
||||
struct zcrypt_device_status_ext *devstatus);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/random.h>
|
||||
|
|
@ -29,16 +30,31 @@
|
|||
/* Size of vardata block used for some of the cca requests/replies */
|
||||
#define VARDATASIZE 4096
|
||||
|
||||
struct cca_info_list_entry {
|
||||
struct list_head list;
|
||||
u16 cardnr;
|
||||
u16 domain;
|
||||
struct cca_info info;
|
||||
};
|
||||
/*
|
||||
* Cprb memory pool held for urgent cases where no memory
|
||||
* can be allocated via kmalloc. This pool is only used
|
||||
* when alloc_and_prep_cprbmem() is called with the xflag
|
||||
* ZCRYPT_XFLAG_NOMEMALLOC. The cprb memory needs to hold
|
||||
* space for request AND reply!
|
||||
*/
|
||||
#define CPRB_MEMPOOL_ITEM_SIZE (16 * 1024)
|
||||
static mempool_t *cprb_mempool;
|
||||
|
||||
/* a list with cca_info_list_entry entries */
|
||||
static LIST_HEAD(cca_info_list);
|
||||
static DEFINE_SPINLOCK(cca_info_list_lock);
|
||||
/*
|
||||
* This is a pre-allocated memory for the device status array
|
||||
* used within the findcard() functions. It is currently
|
||||
* 128 * 128 * 4 bytes = 64 KB big. Usage of this memory is
|
||||
* controlled via dev_status_mem_mutex. Needs adaption if more
|
||||
* than 128 cards or domains to be are supported.
|
||||
*/
|
||||
#define ZCRYPT_DEV_STATUS_CARD_MAX 128
|
||||
#define ZCRYPT_DEV_STATUS_QUEUE_MAX 128
|
||||
#define ZCRYPT_DEV_STATUS_ENTRIES (ZCRYPT_DEV_STATUS_CARD_MAX * \
|
||||
ZCRYPT_DEV_STATUS_QUEUE_MAX)
|
||||
#define ZCRYPT_DEV_STATUS_EXT_SIZE (ZCRYPT_DEV_STATUS_ENTRIES * \
|
||||
sizeof(struct zcrypt_device_status_ext))
|
||||
static void *dev_status_mem;
|
||||
static DEFINE_MUTEX(dev_status_mem_mutex);
|
||||
|
||||
/*
|
||||
* Simple check if the token is a valid CCA secure AES data key
|
||||
|
|
@ -219,19 +235,27 @@ EXPORT_SYMBOL(cca_check_sececckeytoken);
|
|||
static int alloc_and_prep_cprbmem(size_t paramblen,
|
||||
u8 **p_cprb_mem,
|
||||
struct CPRBX **p_req_cprb,
|
||||
struct CPRBX **p_rep_cprb)
|
||||
struct CPRBX **p_rep_cprb,
|
||||
u32 xflags)
|
||||
{
|
||||
u8 *cprbmem;
|
||||
u8 *cprbmem = NULL;
|
||||
size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen;
|
||||
size_t len = 2 * cprbplusparamblen;
|
||||
struct CPRBX *preqcblk, *prepcblk;
|
||||
|
||||
/*
|
||||
* allocate consecutive memory for request CPRB, request param
|
||||
* block, reply CPRB and reply param block
|
||||
*/
|
||||
cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL);
|
||||
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
|
||||
if (len <= CPRB_MEMPOOL_ITEM_SIZE)
|
||||
cprbmem = mempool_alloc_preallocated(cprb_mempool);
|
||||
} else {
|
||||
cprbmem = kmalloc(len, GFP_KERNEL);
|
||||
}
|
||||
if (!cprbmem)
|
||||
return -ENOMEM;
|
||||
memset(cprbmem, 0, len);
|
||||
|
||||
preqcblk = (struct CPRBX *)cprbmem;
|
||||
prepcblk = (struct CPRBX *)(cprbmem + cprbplusparamblen);
|
||||
|
|
@ -261,11 +285,15 @@ static int alloc_and_prep_cprbmem(size_t paramblen,
|
|||
* with zeros before freeing (useful if there was some
|
||||
* clear key material in there).
|
||||
*/
|
||||
static void free_cprbmem(void *mem, size_t paramblen, int scrub)
|
||||
static void free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)
|
||||
{
|
||||
if (scrub)
|
||||
if (mem && scrub)
|
||||
memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));
|
||||
kfree(mem);
|
||||
|
||||
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
|
||||
mempool_free(mem, cprb_mempool);
|
||||
else
|
||||
kfree(mem);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -290,7 +318,7 @@ static inline void prep_xcrb(struct ica_xcRB *pxcrb,
|
|||
* Generate (random) CCA AES DATA secure key.
|
||||
*/
|
||||
int cca_genseckey(u16 cardnr, u16 domain,
|
||||
u32 keybitsize, u8 *seckey)
|
||||
u32 keybitsize, u8 *seckey, u32 xflags)
|
||||
{
|
||||
int i, rc, keysize;
|
||||
int seckeysize;
|
||||
|
|
@ -332,7 +360,8 @@ int cca_genseckey(u16 cardnr, u16 domain,
|
|||
} __packed * prepparm;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -379,7 +408,7 @@ int cca_genseckey(u16 cardnr, u16 domain,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -424,7 +453,7 @@ int cca_genseckey(u16 cardnr, u16 domain,
|
|||
memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE);
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 0);
|
||||
free_cprbmem(mem, PARMBSIZE, false, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_genseckey);
|
||||
|
|
@ -433,7 +462,7 @@ EXPORT_SYMBOL(cca_genseckey);
|
|||
* Generate an CCA AES DATA secure key with given key value.
|
||||
*/
|
||||
int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
|
||||
const u8 *clrkey, u8 *seckey)
|
||||
const u8 *clrkey, u8 *seckey, u32 xflags)
|
||||
{
|
||||
int rc, keysize, seckeysize;
|
||||
u8 *mem, *ptr;
|
||||
|
|
@ -473,7 +502,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
|
|||
} __packed * prepparm;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -517,7 +547,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -563,7 +593,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
|
|||
memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE);
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 1);
|
||||
free_cprbmem(mem, PARMBSIZE, true, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_clr2seckey);
|
||||
|
|
@ -573,7 +603,7 @@ EXPORT_SYMBOL(cca_clr2seckey);
|
|||
*/
|
||||
int cca_sec2protkey(u16 cardnr, u16 domain,
|
||||
const u8 *seckey, u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype)
|
||||
u32 *protkeytype, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u8 *mem, *ptr;
|
||||
|
|
@ -619,7 +649,8 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
|
|||
} __packed * prepparm;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -644,7 +675,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -712,7 +743,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
|
|||
*protkeylen = prepparm->lv3.ckb.len;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 0);
|
||||
free_cprbmem(mem, PARMBSIZE, true, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_sec2protkey);
|
||||
|
|
@ -737,7 +768,7 @@ static const u8 aes_cipher_key_skeleton[] = {
|
|||
* Generate (random) CCA AES CIPHER secure key.
|
||||
*/
|
||||
int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, u32 *keybufsize)
|
||||
u8 *keybuf, u32 *keybufsize, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u8 *mem, *ptr;
|
||||
|
|
@ -813,7 +844,8 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
struct cipherkeytoken *t;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -872,7 +904,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -923,7 +955,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
*keybufsize = t->len;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 0);
|
||||
free_cprbmem(mem, PARMBSIZE, false, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_gencipherkey);
|
||||
|
|
@ -938,7 +970,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
|||
const u8 *clr_key_value,
|
||||
int clr_key_bit_size,
|
||||
u8 *key_token,
|
||||
int *key_token_size)
|
||||
int *key_token_size,
|
||||
u32 xflags)
|
||||
{
|
||||
int rc, n;
|
||||
u8 *mem, *ptr;
|
||||
|
|
@ -989,7 +1022,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
|||
int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1038,7 +1072,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -1077,7 +1111,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
|||
*key_token_size = t->len;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 0);
|
||||
free_cprbmem(mem, PARMBSIZE, false, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1085,23 +1119,31 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
|||
* Build CCA AES CIPHER secure key with a given clear key value.
|
||||
*/
|
||||
int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
|
||||
const u8 *clrkey, u8 *keybuf, u32 *keybufsize)
|
||||
const u8 *clrkey, u8 *keybuf, u32 *keybufsize, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u8 *token;
|
||||
void *mem;
|
||||
int tokensize;
|
||||
u8 exorbuf[32];
|
||||
u8 *token, exorbuf[32];
|
||||
struct cipherkeytoken *t;
|
||||
|
||||
/* fill exorbuf with random data */
|
||||
get_random_bytes(exorbuf, sizeof(exorbuf));
|
||||
|
||||
/* allocate space for the key token to build */
|
||||
token = kmalloc(MAXCCAVLSCTOKENSIZE, GFP_KERNEL);
|
||||
if (!token)
|
||||
/*
|
||||
* Allocate space for the key token to build.
|
||||
* Also we only need up to MAXCCAVLSCTOKENSIZE bytes for this
|
||||
* we use the already existing cprb mempool to solve this
|
||||
* short term memory requirement.
|
||||
*/
|
||||
mem = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
|
||||
mempool_alloc_preallocated(cprb_mempool) :
|
||||
mempool_alloc(cprb_mempool, GFP_KERNEL);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
|
||||
/* prepare the token with the key skeleton */
|
||||
token = (u8 *)mem;
|
||||
tokensize = SIZEOF_SKELETON;
|
||||
memcpy(token, aes_cipher_key_skeleton, tokensize);
|
||||
|
||||
|
|
@ -1120,28 +1162,28 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
|
|||
* 4/4 COMPLETE the secure cipher key import
|
||||
*/
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART",
|
||||
exorbuf, keybitsize, token, &tokensize);
|
||||
exorbuf, keybitsize, token, &tokensize, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
|
||||
clrkey, keybitsize, token, &tokensize);
|
||||
clrkey, keybitsize, token, &tokensize, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
|
||||
exorbuf, keybitsize, token, &tokensize);
|
||||
exorbuf, keybitsize, token, &tokensize, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL,
|
||||
NULL, keybitsize, token, &tokensize);
|
||||
NULL, keybitsize, token, &tokensize, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
|
|
@ -1158,7 +1200,7 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
|
|||
*keybufsize = tokensize;
|
||||
|
||||
out:
|
||||
kfree(token);
|
||||
mempool_free(mem, cprb_mempool);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_clr2cipherkey);
|
||||
|
|
@ -1167,7 +1209,8 @@ EXPORT_SYMBOL(cca_clr2cipherkey);
|
|||
* Derive proteced key from CCA AES cipher secure key.
|
||||
*/
|
||||
int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u8 *mem, *ptr;
|
||||
|
|
@ -1219,7 +1262,8 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
|
|||
int keytoklen = ((struct cipherkeytoken *)ckey)->len;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1249,7 +1293,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -1323,7 +1367,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
|
|||
*protkeylen = prepparm->vud.ckb.keylen;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 0);
|
||||
free_cprbmem(mem, PARMBSIZE, true, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_cipher2protkey);
|
||||
|
|
@ -1332,7 +1376,7 @@ EXPORT_SYMBOL(cca_cipher2protkey);
|
|||
* Derive protected key from CCA ECC secure private key.
|
||||
*/
|
||||
int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u8 *mem, *ptr;
|
||||
|
|
@ -1382,7 +1426,8 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
|||
int keylen = ((struct eccprivkeytoken *)key)->len;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1412,7 +1457,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -1470,7 +1515,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
|||
*protkeytype = PKEY_KEYTYPE_ECC;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, 0);
|
||||
free_cprbmem(mem, PARMBSIZE, true, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_ecc2protkey);
|
||||
|
|
@ -1481,7 +1526,8 @@ EXPORT_SYMBOL(cca_ecc2protkey);
|
|||
int cca_query_crypto_facility(u16 cardnr, u16 domain,
|
||||
const char *keyword,
|
||||
u8 *rarray, size_t *rarraylen,
|
||||
u8 *varray, size_t *varraylen)
|
||||
u8 *varray, size_t *varraylen,
|
||||
u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u16 len;
|
||||
|
|
@ -1505,7 +1551,8 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
|
|||
} __packed * prepparm;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk);
|
||||
rc = alloc_and_prep_cprbmem(parmbsize, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1526,7 +1573,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
|
|||
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
|
||||
|
||||
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
|
||||
rc = zcrypt_send_cprb(&xcrb);
|
||||
rc = zcrypt_send_cprb(&xcrb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -1573,94 +1620,21 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
|
|||
}
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, parmbsize, 0);
|
||||
free_cprbmem(mem, parmbsize, false, xflags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_query_crypto_facility);
|
||||
|
||||
static int cca_info_cache_fetch(u16 cardnr, u16 domain, struct cca_info *ci)
|
||||
{
|
||||
int rc = -ENOENT;
|
||||
struct cca_info_list_entry *ptr;
|
||||
|
||||
spin_lock_bh(&cca_info_list_lock);
|
||||
list_for_each_entry(ptr, &cca_info_list, list) {
|
||||
if (ptr->cardnr == cardnr && ptr->domain == domain) {
|
||||
memcpy(ci, &ptr->info, sizeof(*ci));
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&cca_info_list_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void cca_info_cache_update(u16 cardnr, u16 domain,
|
||||
const struct cca_info *ci)
|
||||
{
|
||||
int found = 0;
|
||||
struct cca_info_list_entry *ptr;
|
||||
|
||||
spin_lock_bh(&cca_info_list_lock);
|
||||
list_for_each_entry(ptr, &cca_info_list, list) {
|
||||
if (ptr->cardnr == cardnr &&
|
||||
ptr->domain == domain) {
|
||||
memcpy(&ptr->info, ci, sizeof(*ci));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC);
|
||||
if (!ptr) {
|
||||
spin_unlock_bh(&cca_info_list_lock);
|
||||
return;
|
||||
}
|
||||
ptr->cardnr = cardnr;
|
||||
ptr->domain = domain;
|
||||
memcpy(&ptr->info, ci, sizeof(*ci));
|
||||
list_add(&ptr->list, &cca_info_list);
|
||||
}
|
||||
spin_unlock_bh(&cca_info_list_lock);
|
||||
}
|
||||
|
||||
static void cca_info_cache_scrub(u16 cardnr, u16 domain)
|
||||
{
|
||||
struct cca_info_list_entry *ptr;
|
||||
|
||||
spin_lock_bh(&cca_info_list_lock);
|
||||
list_for_each_entry(ptr, &cca_info_list, list) {
|
||||
if (ptr->cardnr == cardnr &&
|
||||
ptr->domain == domain) {
|
||||
list_del(&ptr->list);
|
||||
kfree(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&cca_info_list_lock);
|
||||
}
|
||||
|
||||
static void __exit mkvp_cache_free(void)
|
||||
{
|
||||
struct cca_info_list_entry *ptr, *pnext;
|
||||
|
||||
spin_lock_bh(&cca_info_list_lock);
|
||||
list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) {
|
||||
list_del(&ptr->list);
|
||||
kfree(ptr);
|
||||
}
|
||||
spin_unlock_bh(&cca_info_list_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch cca_info values via query_crypto_facility from adapter.
|
||||
* Fetch cca_info values about a CCA queue via
|
||||
* query_crypto_facility from adapter.
|
||||
*/
|
||||
static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
|
||||
int cca_get_info(u16 cardnr, u16 domain, struct cca_info *ci, u32 xflags)
|
||||
{
|
||||
void *mem;
|
||||
int rc, found = 0;
|
||||
size_t rlen, vlen;
|
||||
u8 *rarray, *varray, *pg;
|
||||
u8 *rarray, *varray;
|
||||
struct zcrypt_device_status_ext devstat;
|
||||
|
||||
memset(ci, 0, sizeof(*ci));
|
||||
|
|
@ -1671,17 +1645,22 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
|
|||
return rc;
|
||||
ci->hwtype = devstat.hwtype;
|
||||
|
||||
/* prep page for rule array and var array use */
|
||||
pg = (u8 *)__get_free_page(GFP_KERNEL);
|
||||
if (!pg)
|
||||
/*
|
||||
* Prep memory for rule array and var array use.
|
||||
* Use the cprb mempool for this.
|
||||
*/
|
||||
mem = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
|
||||
mempool_alloc_preallocated(cprb_mempool) :
|
||||
mempool_alloc(cprb_mempool, GFP_KERNEL);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
rarray = pg;
|
||||
varray = pg + PAGE_SIZE / 2;
|
||||
rarray = (u8 *)mem;
|
||||
varray = (u8 *)mem + PAGE_SIZE / 2;
|
||||
rlen = vlen = PAGE_SIZE / 2;
|
||||
|
||||
/* QF for this card/domain */
|
||||
rc = cca_query_crypto_facility(cardnr, domain, "STATICSA",
|
||||
rarray, &rlen, varray, &vlen);
|
||||
rarray, &rlen, varray, &vlen, xflags);
|
||||
if (rc == 0 && rlen >= 10 * 8 && vlen >= 204) {
|
||||
memcpy(ci->serial, rarray, 8);
|
||||
ci->new_asym_mk_state = (char)rarray[4 * 8];
|
||||
|
|
@ -1708,7 +1687,7 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
|
|||
goto out;
|
||||
rlen = vlen = PAGE_SIZE / 2;
|
||||
rc = cca_query_crypto_facility(cardnr, domain, "STATICSB",
|
||||
rarray, &rlen, varray, &vlen);
|
||||
rarray, &rlen, varray, &vlen, xflags);
|
||||
if (rc == 0 && rlen >= 13 * 8 && vlen >= 240) {
|
||||
ci->new_apka_mk_state = (char)rarray[10 * 8];
|
||||
ci->cur_apka_mk_state = (char)rarray[11 * 8];
|
||||
|
|
@ -1723,177 +1702,32 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
|
|||
}
|
||||
|
||||
out:
|
||||
free_page((unsigned long)pg);
|
||||
mempool_free(mem, cprb_mempool);
|
||||
return found == 2 ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch cca information about a CCA queue.
|
||||
*/
|
||||
int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = cca_info_cache_fetch(card, dom, ci);
|
||||
if (rc || verify) {
|
||||
rc = fetch_cca_info(card, dom, ci);
|
||||
if (rc == 0)
|
||||
cca_info_cache_update(card, dom, ci);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_get_info);
|
||||
|
||||
/*
|
||||
* Search for a matching crypto card based on the
|
||||
* Master Key Verification Pattern given.
|
||||
*/
|
||||
static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain,
|
||||
int verify, int minhwtype)
|
||||
{
|
||||
struct zcrypt_device_status_ext *device_status;
|
||||
u16 card, dom;
|
||||
struct cca_info ci;
|
||||
int i, rc, oi = -1;
|
||||
|
||||
/* mkvp must not be zero, minhwtype needs to be >= 0 */
|
||||
if (mkvp == 0 || minhwtype < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* fetch status of all crypto cards */
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
|
||||
/* walk through all crypto cards */
|
||||
for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) {
|
||||
card = AP_QID_CARD(device_status[i].qid);
|
||||
dom = AP_QID_QUEUE(device_status[i].qid);
|
||||
if (device_status[i].online &&
|
||||
device_status[i].functions & 0x04) {
|
||||
/* enabled CCA card, check current mkvp from cache */
|
||||
if (cca_info_cache_fetch(card, dom, &ci) == 0 &&
|
||||
ci.hwtype >= minhwtype &&
|
||||
ci.cur_aes_mk_state == '2' &&
|
||||
ci.cur_aes_mkvp == mkvp) {
|
||||
if (!verify)
|
||||
break;
|
||||
/* verify: refresh card info */
|
||||
if (fetch_cca_info(card, dom, &ci) == 0) {
|
||||
cca_info_cache_update(card, dom, &ci);
|
||||
if (ci.hwtype >= minhwtype &&
|
||||
ci.cur_aes_mk_state == '2' &&
|
||||
ci.cur_aes_mkvp == mkvp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Card is offline and/or not a CCA card. */
|
||||
/* del mkvp entry from cache if it exists */
|
||||
cca_info_cache_scrub(card, dom);
|
||||
}
|
||||
}
|
||||
if (i >= MAX_ZDEV_ENTRIES_EXT) {
|
||||
/* nothing found, so this time without cache */
|
||||
for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) {
|
||||
if (!(device_status[i].online &&
|
||||
device_status[i].functions & 0x04))
|
||||
continue;
|
||||
card = AP_QID_CARD(device_status[i].qid);
|
||||
dom = AP_QID_QUEUE(device_status[i].qid);
|
||||
/* fresh fetch mkvp from adapter */
|
||||
if (fetch_cca_info(card, dom, &ci) == 0) {
|
||||
cca_info_cache_update(card, dom, &ci);
|
||||
if (ci.hwtype >= minhwtype &&
|
||||
ci.cur_aes_mk_state == '2' &&
|
||||
ci.cur_aes_mkvp == mkvp)
|
||||
break;
|
||||
if (ci.hwtype >= minhwtype &&
|
||||
ci.old_aes_mk_state == '2' &&
|
||||
ci.old_aes_mkvp == mkvp &&
|
||||
oi < 0)
|
||||
oi = i;
|
||||
}
|
||||
}
|
||||
if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) {
|
||||
/* old mkvp matched, use this card then */
|
||||
card = AP_QID_CARD(device_status[oi].qid);
|
||||
dom = AP_QID_QUEUE(device_status[oi].qid);
|
||||
}
|
||||
}
|
||||
if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) {
|
||||
if (pcardnr)
|
||||
*pcardnr = card;
|
||||
if (pdomain)
|
||||
*pdomain = dom;
|
||||
rc = (i < MAX_ZDEV_ENTRIES_EXT ? 0 : 1);
|
||||
} else {
|
||||
rc = -ENODEV;
|
||||
}
|
||||
|
||||
kvfree(device_status);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for a matching crypto card based on the Master Key
|
||||
* Verification Pattern provided inside a secure key token.
|
||||
*/
|
||||
int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify)
|
||||
{
|
||||
u64 mkvp;
|
||||
int minhwtype = 0;
|
||||
const struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
|
||||
if (hdr->type != TOKTYPE_CCA_INTERNAL)
|
||||
return -EINVAL;
|
||||
|
||||
switch (hdr->version) {
|
||||
case TOKVER_CCA_AES:
|
||||
mkvp = ((struct secaeskeytoken *)key)->mkvp;
|
||||
break;
|
||||
case TOKVER_CCA_VLSC:
|
||||
mkvp = ((struct cipherkeytoken *)key)->mkvp0;
|
||||
minhwtype = AP_DEVICE_TYPE_CEX6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return findcard(mkvp, pcardnr, pdomain, verify, minhwtype);
|
||||
}
|
||||
EXPORT_SYMBOL(cca_findcard);
|
||||
|
||||
int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int cca_findcard2(u32 *apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp,
|
||||
int verify)
|
||||
u32 xflags)
|
||||
{
|
||||
struct zcrypt_device_status_ext *device_status;
|
||||
u32 *_apqns = NULL, _nr_apqns = 0;
|
||||
int i, card, dom, curmatch, oldmatch, rc = 0;
|
||||
int i, card, dom, curmatch, oldmatch;
|
||||
struct cca_info ci;
|
||||
u32 _nr_apqns = 0;
|
||||
|
||||
/* fetch status of all crypto cards */
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
/* occupy the device status memory */
|
||||
mutex_lock(&dev_status_mem_mutex);
|
||||
memset(dev_status_mem, 0, ZCRYPT_DEV_STATUS_EXT_SIZE);
|
||||
device_status = (struct zcrypt_device_status_ext *)dev_status_mem;
|
||||
|
||||
/* allocate 1k space for up to 256 apqns */
|
||||
_apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL);
|
||||
if (!_apqns) {
|
||||
kvfree(device_status);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* fetch crypto device status into this struct */
|
||||
zcrypt_device_status_mask_ext(device_status,
|
||||
ZCRYPT_DEV_STATUS_CARD_MAX,
|
||||
ZCRYPT_DEV_STATUS_QUEUE_MAX);
|
||||
|
||||
/* walk through all the crypto apqnss */
|
||||
for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) {
|
||||
for (i = 0; i < ZCRYPT_DEV_STATUS_ENTRIES; i++) {
|
||||
card = AP_QID_CARD(device_status[i].qid);
|
||||
dom = AP_QID_QUEUE(device_status[i].qid);
|
||||
/* check online state */
|
||||
|
|
@ -1909,7 +1743,7 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
|||
if (domain != 0xFFFF && dom != domain)
|
||||
continue;
|
||||
/* get cca info on this apqn */
|
||||
if (cca_get_info(card, dom, &ci, verify))
|
||||
if (cca_get_info(card, dom, &ci, xflags))
|
||||
continue;
|
||||
/* current master key needs to be valid */
|
||||
if (mktype == AES_MK_SET && ci.cur_aes_mk_state != '2')
|
||||
|
|
@ -1939,27 +1773,41 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
|||
continue;
|
||||
}
|
||||
/* apqn passed all filtering criterons, add to the array */
|
||||
if (_nr_apqns < 256)
|
||||
_apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom);
|
||||
if (_nr_apqns < *nr_apqns)
|
||||
apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom);
|
||||
}
|
||||
|
||||
/* nothing found ? */
|
||||
if (!_nr_apqns) {
|
||||
kfree(_apqns);
|
||||
rc = -ENODEV;
|
||||
} else {
|
||||
/* no re-allocation, simple return the _apqns array */
|
||||
*apqns = _apqns;
|
||||
*nr_apqns = _nr_apqns;
|
||||
rc = 0;
|
||||
}
|
||||
*nr_apqns = _nr_apqns;
|
||||
|
||||
kvfree(device_status);
|
||||
return rc;
|
||||
/* release the device status memory */
|
||||
mutex_unlock(&dev_status_mem_mutex);
|
||||
|
||||
return _nr_apqns ? 0 : -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL(cca_findcard2);
|
||||
|
||||
void __exit zcrypt_ccamisc_exit(void)
|
||||
int __init zcrypt_ccamisc_init(void)
|
||||
{
|
||||
mkvp_cache_free();
|
||||
/* Pre-allocate a small memory pool for cca cprbs. */
|
||||
cprb_mempool = mempool_create_kmalloc_pool(zcrypt_mempool_threshold,
|
||||
CPRB_MEMPOOL_ITEM_SIZE);
|
||||
if (!cprb_mempool)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Pre-allocate one crypto status card struct used in findcard() */
|
||||
dev_status_mem = kvmalloc(ZCRYPT_DEV_STATUS_EXT_SIZE, GFP_KERNEL);
|
||||
if (!dev_status_mem) {
|
||||
mempool_destroy(cprb_mempool);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zcrypt_ccamisc_exit(void)
|
||||
{
|
||||
mutex_lock(&dev_status_mem_mutex);
|
||||
kvfree(dev_status_mem);
|
||||
mutex_unlock(&dev_status_mem_mutex);
|
||||
mempool_destroy(cprb_mempool);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,44 +160,47 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
|
|||
/*
|
||||
* Generate (random) CCA AES DATA secure key.
|
||||
*/
|
||||
int cca_genseckey(u16 cardnr, u16 domain, u32 keybitsize, u8 *seckey);
|
||||
int cca_genseckey(u16 cardnr, u16 domain, u32 keybitsize, u8 *seckey,
|
||||
u32 xflags);
|
||||
|
||||
/*
|
||||
* Generate CCA AES DATA secure key with given clear key value.
|
||||
*/
|
||||
int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
|
||||
const u8 *clrkey, u8 *seckey);
|
||||
const u8 *clrkey, u8 *seckey, u32 xflags);
|
||||
|
||||
/*
|
||||
* Derive proteced key from an CCA AES DATA secure key.
|
||||
*/
|
||||
int cca_sec2protkey(u16 cardnr, u16 domain,
|
||||
const u8 *seckey, u8 *protkey, u32 *protkeylen,
|
||||
u32 *protkeytype);
|
||||
u32 *protkeytype, u32 xflags);
|
||||
|
||||
/*
|
||||
* Generate (random) CCA AES CIPHER secure key.
|
||||
*/
|
||||
int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, u32 *keybufsize);
|
||||
u8 *keybuf, u32 *keybufsize, u32 xflags);
|
||||
|
||||
/*
|
||||
* Derive proteced key from CCA AES cipher secure key.
|
||||
*/
|
||||
int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags);
|
||||
|
||||
/*
|
||||
* Build CCA AES CIPHER secure key with a given clear key value.
|
||||
*/
|
||||
int cca_clr2cipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
const u8 *clrkey, u8 *keybuf, u32 *keybufsize);
|
||||
const u8 *clrkey, u8 *keybuf, u32 *keybufsize,
|
||||
u32 xflags);
|
||||
|
||||
/*
|
||||
* Derive proteced key from CCA ECC secure private key.
|
||||
*/
|
||||
int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype, u32 xflags);
|
||||
|
||||
/*
|
||||
* Query cryptographic facility from CCA adapter
|
||||
|
|
@ -205,16 +208,8 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
|||
int cca_query_crypto_facility(u16 cardnr, u16 domain,
|
||||
const char *keyword,
|
||||
u8 *rarray, size_t *rarraylen,
|
||||
u8 *varray, size_t *varraylen);
|
||||
|
||||
/*
|
||||
* Search for a matching crypto card based on the Master Key
|
||||
* Verification Pattern provided inside a secure key.
|
||||
* Works with CCA AES data and cipher keys.
|
||||
* Returns < 0 on failure, 0 if CURRENT MKVP matches and
|
||||
* 1 if OLD MKVP matches.
|
||||
*/
|
||||
int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify);
|
||||
u8 *varray, size_t *varraylen,
|
||||
u32 xflags);
|
||||
|
||||
/*
|
||||
* Build a list of cca apqns meeting the following constrains:
|
||||
|
|
@ -224,21 +219,16 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify);
|
|||
* - if minhwtype > 0 only apqns with hwtype >= minhwtype
|
||||
* - if cur_mkvp != 0 only apqns where cur_mkvp == mkvp
|
||||
* - if old_mkvp != 0 only apqns where old_mkvp == mkvp
|
||||
* - if verify is enabled and a cur_mkvp and/or old_mkvp
|
||||
* value is given, then refetch the cca_info and make sure the current
|
||||
* cur_mkvp or old_mkvp values of the apqn are used.
|
||||
* The mktype determines which set of master keys to use:
|
||||
* 0 = AES_MK_SET - AES MK set, 1 = APKA MK_SET - APKA MK set
|
||||
* The array of apqn entries is allocated with kmalloc and returned in *apqns;
|
||||
* the number of apqns stored into the list is returned in *nr_apqns. One apqn
|
||||
* entry is simple a 32 bit value with 16 bit cardnr and 16 bit domain nr and
|
||||
* may be casted to struct pkey_apqn. The return value is either 0 for success
|
||||
* or a negative errno value. If no apqn meeting the criteria is found,
|
||||
* -ENODEV is returned.
|
||||
* The caller should set *nr_apqns to the nr of elements available in *apqns.
|
||||
* On return *nr_apqns is then updated with the nr of apqns filled into *apqns.
|
||||
* The return value is either 0 for success or a negative errno value.
|
||||
* If no apqn meeting the criteria is found, -ENODEV is returned.
|
||||
*/
|
||||
int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int cca_findcard2(u32 *apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp,
|
||||
int verify);
|
||||
u32 xflags);
|
||||
|
||||
#define AES_MK_SET 0
|
||||
#define APKA_MK_SET 1
|
||||
|
|
@ -270,8 +260,9 @@ struct cca_info {
|
|||
/*
|
||||
* Fetch cca information about an CCA queue.
|
||||
*/
|
||||
int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify);
|
||||
int cca_get_info(u16 card, u16 dom, struct cca_info *ci, u32 xflags);
|
||||
|
||||
int zcrypt_ccamisc_init(void);
|
||||
void zcrypt_ccamisc_exit(void);
|
||||
|
||||
#endif /* _ZCRYPT_CCAMISC_H_ */
|
||||
|
|
|
|||
|
|
@ -79,14 +79,13 @@ static ssize_t cca_serialnr_show(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct zcrypt_card *zc = dev_get_drvdata(dev);
|
||||
struct cca_info ci;
|
||||
struct ap_card *ac = to_ap_card(dev);
|
||||
struct cca_info ci;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
if (ap_domain_index >= 0)
|
||||
cca_get_info(ac->id, ap_domain_index, &ci, zc->online);
|
||||
cca_get_info(ac->id, ap_domain_index, &ci, 0);
|
||||
|
||||
return sysfs_emit(buf, "%s\n", ci.serial);
|
||||
}
|
||||
|
|
@ -110,17 +109,17 @@ static ssize_t cca_mkvps_show(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct zcrypt_queue *zq = dev_get_drvdata(dev);
|
||||
int n = 0;
|
||||
struct cca_info ci;
|
||||
static const char * const cao_state[] = { "invalid", "valid" };
|
||||
static const char * const new_state[] = { "empty", "partial", "full" };
|
||||
static const char * const cao_state[] = { "invalid", "valid" };
|
||||
struct zcrypt_queue *zq = dev_get_drvdata(dev);
|
||||
struct cca_info ci;
|
||||
int n = 0;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
cca_get_info(AP_QID_CARD(zq->queue->qid),
|
||||
AP_QID_QUEUE(zq->queue->qid),
|
||||
&ci, zq->online);
|
||||
&ci, 0);
|
||||
|
||||
if (ci.new_aes_mk_state >= '1' && ci.new_aes_mk_state <= '3')
|
||||
n += sysfs_emit_at(buf, n, "AES NEW: %s 0x%016llx\n",
|
||||
|
|
@ -210,13 +209,12 @@ static ssize_t ep11_api_ordinalnr_show(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct zcrypt_card *zc = dev_get_drvdata(dev);
|
||||
struct ep11_card_info ci;
|
||||
struct ap_card *ac = to_ap_card(dev);
|
||||
struct ep11_card_info ci;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
ep11_get_card_info(ac->id, &ci, zc->online);
|
||||
ep11_get_card_info(ac->id, &ci, 0);
|
||||
|
||||
if (ci.API_ord_nr > 0)
|
||||
return sysfs_emit(buf, "%u\n", ci.API_ord_nr);
|
||||
|
|
@ -231,13 +229,12 @@ static ssize_t ep11_fw_version_show(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct zcrypt_card *zc = dev_get_drvdata(dev);
|
||||
struct ep11_card_info ci;
|
||||
struct ap_card *ac = to_ap_card(dev);
|
||||
struct ep11_card_info ci;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
ep11_get_card_info(ac->id, &ci, zc->online);
|
||||
ep11_get_card_info(ac->id, &ci, 0);
|
||||
|
||||
if (ci.FW_version > 0)
|
||||
return sysfs_emit(buf, "%d.%d\n",
|
||||
|
|
@ -254,13 +251,12 @@ static ssize_t ep11_serialnr_show(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct zcrypt_card *zc = dev_get_drvdata(dev);
|
||||
struct ep11_card_info ci;
|
||||
struct ap_card *ac = to_ap_card(dev);
|
||||
struct ep11_card_info ci;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
ep11_get_card_info(ac->id, &ci, zc->online);
|
||||
ep11_get_card_info(ac->id, &ci, 0);
|
||||
|
||||
if (ci.serial[0])
|
||||
return sysfs_emit(buf, "%16.16s\n", ci.serial);
|
||||
|
|
@ -291,14 +287,13 @@ static ssize_t ep11_card_op_modes_show(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct zcrypt_card *zc = dev_get_drvdata(dev);
|
||||
int i, n = 0;
|
||||
struct ep11_card_info ci;
|
||||
struct ap_card *ac = to_ap_card(dev);
|
||||
struct ep11_card_info ci;
|
||||
int i, n = 0;
|
||||
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
ep11_get_card_info(ac->id, &ci, zc->online);
|
||||
ep11_get_card_info(ac->id, &ci, 0);
|
||||
|
||||
for (i = 0; ep11_op_modes[i].mode_txt; i++) {
|
||||
if (ci.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) {
|
||||
|
|
@ -348,7 +343,7 @@ static ssize_t ep11_mkvps_show(struct device *dev,
|
|||
if (zq->online)
|
||||
ep11_get_domain_info(AP_QID_CARD(zq->queue->qid),
|
||||
AP_QID_QUEUE(zq->queue->qid),
|
||||
&di);
|
||||
&di, 0);
|
||||
|
||||
if (di.cur_wk_state == '0') {
|
||||
n = sysfs_emit(buf, "WK CUR: %s -\n",
|
||||
|
|
@ -395,7 +390,7 @@ static ssize_t ep11_queue_op_modes_show(struct device *dev,
|
|||
if (zq->online)
|
||||
ep11_get_domain_info(AP_QID_CARD(zq->queue->qid),
|
||||
AP_QID_QUEUE(zq->queue->qid),
|
||||
&di);
|
||||
&di, 0);
|
||||
|
||||
for (i = 0; ep11_op_modes[i].mode_txt; i++) {
|
||||
if (di.op_mode & (1ULL << ep11_op_modes[i].mode_bit)) {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@
|
|||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/zcrypt.h>
|
||||
#include <asm/pkey.h>
|
||||
#include <crypto/aes.h>
|
||||
|
|
@ -30,85 +31,29 @@
|
|||
static const u8 def_iv[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
|
||||
/* ep11 card info cache */
|
||||
struct card_list_entry {
|
||||
struct list_head list;
|
||||
u16 cardnr;
|
||||
struct ep11_card_info info;
|
||||
};
|
||||
static LIST_HEAD(card_list);
|
||||
static DEFINE_SPINLOCK(card_list_lock);
|
||||
/*
|
||||
* Cprb memory pool held for urgent cases where no memory
|
||||
* can be allocated via kmalloc. This pool is only used when
|
||||
* alloc_cprbmem() is called with the xflag ZCRYPT_XFLAG_NOMEMALLOC.
|
||||
*/
|
||||
#define CPRB_MEMPOOL_ITEM_SIZE (8 * 1024)
|
||||
static mempool_t *cprb_mempool;
|
||||
|
||||
static int card_cache_fetch(u16 cardnr, struct ep11_card_info *ci)
|
||||
{
|
||||
int rc = -ENOENT;
|
||||
struct card_list_entry *ptr;
|
||||
|
||||
spin_lock_bh(&card_list_lock);
|
||||
list_for_each_entry(ptr, &card_list, list) {
|
||||
if (ptr->cardnr == cardnr) {
|
||||
memcpy(ci, &ptr->info, sizeof(*ci));
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&card_list_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void card_cache_update(u16 cardnr, const struct ep11_card_info *ci)
|
||||
{
|
||||
int found = 0;
|
||||
struct card_list_entry *ptr;
|
||||
|
||||
spin_lock_bh(&card_list_lock);
|
||||
list_for_each_entry(ptr, &card_list, list) {
|
||||
if (ptr->cardnr == cardnr) {
|
||||
memcpy(&ptr->info, ci, sizeof(*ci));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC);
|
||||
if (!ptr) {
|
||||
spin_unlock_bh(&card_list_lock);
|
||||
return;
|
||||
}
|
||||
ptr->cardnr = cardnr;
|
||||
memcpy(&ptr->info, ci, sizeof(*ci));
|
||||
list_add(&ptr->list, &card_list);
|
||||
}
|
||||
spin_unlock_bh(&card_list_lock);
|
||||
}
|
||||
|
||||
static void card_cache_scrub(u16 cardnr)
|
||||
{
|
||||
struct card_list_entry *ptr;
|
||||
|
||||
spin_lock_bh(&card_list_lock);
|
||||
list_for_each_entry(ptr, &card_list, list) {
|
||||
if (ptr->cardnr == cardnr) {
|
||||
list_del(&ptr->list);
|
||||
kfree(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&card_list_lock);
|
||||
}
|
||||
|
||||
static void __exit card_cache_free(void)
|
||||
{
|
||||
struct card_list_entry *ptr, *pnext;
|
||||
|
||||
spin_lock_bh(&card_list_lock);
|
||||
list_for_each_entry_safe(ptr, pnext, &card_list, list) {
|
||||
list_del(&ptr->list);
|
||||
kfree(ptr);
|
||||
}
|
||||
spin_unlock_bh(&card_list_lock);
|
||||
}
|
||||
/*
|
||||
* This is a pre-allocated memory for the device status array
|
||||
* used within the ep11_findcard2() function. It is currently
|
||||
* 128 * 128 * 4 bytes = 64 KB big. Usage of this memory is
|
||||
* controlled via dev_status_mem_mutex. Needs adaption if more
|
||||
* than 128 cards or domains to be are supported.
|
||||
*/
|
||||
#define ZCRYPT_DEV_STATUS_CARD_MAX 128
|
||||
#define ZCRYPT_DEV_STATUS_QUEUE_MAX 128
|
||||
#define ZCRYPT_DEV_STATUS_ENTRIES (ZCRYPT_DEV_STATUS_CARD_MAX * \
|
||||
ZCRYPT_DEV_STATUS_QUEUE_MAX)
|
||||
#define ZCRYPT_DEV_STATUS_EXT_SIZE (ZCRYPT_DEV_STATUS_ENTRIES * \
|
||||
sizeof(struct zcrypt_device_status_ext))
|
||||
static void *dev_status_mem;
|
||||
static DEFINE_MUTEX(dev_status_mem_mutex);
|
||||
|
||||
static int ep11_kb_split(const u8 *kb, size_t kblen, u32 kbver,
|
||||
struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
|
||||
|
|
@ -411,14 +356,20 @@ EXPORT_SYMBOL(ep11_check_aes_key);
|
|||
/*
|
||||
* Allocate and prepare ep11 cprb plus additional payload.
|
||||
*/
|
||||
static inline struct ep11_cprb *alloc_cprb(size_t payload_len)
|
||||
static void *alloc_cprbmem(size_t payload_len, u32 xflags)
|
||||
{
|
||||
size_t len = sizeof(struct ep11_cprb) + payload_len;
|
||||
struct ep11_cprb *cprb;
|
||||
struct ep11_cprb *cprb = NULL;
|
||||
|
||||
cprb = kzalloc(len, GFP_KERNEL);
|
||||
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
|
||||
if (len <= CPRB_MEMPOOL_ITEM_SIZE)
|
||||
cprb = mempool_alloc_preallocated(cprb_mempool);
|
||||
} else {
|
||||
cprb = kmalloc(len, GFP_KERNEL);
|
||||
}
|
||||
if (!cprb)
|
||||
return NULL;
|
||||
memset(cprb, 0, len);
|
||||
|
||||
cprb->cprb_len = sizeof(struct ep11_cprb);
|
||||
cprb->cprb_ver_id = 0x04;
|
||||
|
|
@ -429,6 +380,20 @@ static inline struct ep11_cprb *alloc_cprb(size_t payload_len)
|
|||
return cprb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free ep11 cprb buffer space.
|
||||
*/
|
||||
static void free_cprbmem(void *mem, size_t payload_len, bool scrub, u32 xflags)
|
||||
{
|
||||
if (mem && scrub)
|
||||
memzero_explicit(mem, sizeof(struct ep11_cprb) + payload_len);
|
||||
|
||||
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
|
||||
mempool_free(mem, cprb_mempool);
|
||||
else
|
||||
kfree(mem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some helper functions related to ASN1 encoding.
|
||||
* Limited to length info <= 2 byte.
|
||||
|
|
@ -489,6 +454,7 @@ static inline void prep_urb(struct ep11_urb *u,
|
|||
struct ep11_cprb *req, size_t req_len,
|
||||
struct ep11_cprb *rep, size_t rep_len)
|
||||
{
|
||||
memset(u, 0, sizeof(*u));
|
||||
u->targets = (u8 __user *)t;
|
||||
u->targets_num = nt;
|
||||
u->req = (u8 __user *)req;
|
||||
|
|
@ -583,7 +549,7 @@ static int check_reply_cprb(const struct ep11_cprb *rep, const char *func)
|
|||
* Helper function which does an ep11 query with given query type.
|
||||
*/
|
||||
static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
||||
size_t buflen, u8 *buf)
|
||||
size_t buflen, u8 *buf, u32 xflags)
|
||||
{
|
||||
struct ep11_info_req_pl {
|
||||
struct pl_head head;
|
||||
|
|
@ -605,11 +571,11 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
|||
} __packed * rep_pl;
|
||||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
int api = EP11_API_V1, rc = -ENOMEM;
|
||||
|
||||
/* request cprb and payload */
|
||||
req = alloc_cprb(sizeof(struct ep11_info_req_pl));
|
||||
req = alloc_cprbmem(sizeof(struct ep11_info_req_pl), xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct ep11_info_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -621,22 +587,19 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
|||
req_pl->query_subtype_len = sizeof(u32);
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct ep11_info_rep_pl) + buflen);
|
||||
rep = alloc_cprbmem(sizeof(struct ep11_info_rep_pl) + buflen, xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct ep11_info_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = cardnr;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + sizeof(*req_pl),
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl) + buflen);
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -667,16 +630,15 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
|||
memcpy(buf, ((u8 *)rep_pl) + sizeof(*rep_pl), rep_pl->data_len);
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, 0, false, xflags);
|
||||
free_cprbmem(rep, 0, false, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide information about an EP11 card.
|
||||
*/
|
||||
int ep11_get_card_info(u16 card, struct ep11_card_info *info, int verify)
|
||||
int ep11_get_card_info(u16 card, struct ep11_card_info *info, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
struct ep11_module_query_info {
|
||||
|
|
@ -706,30 +668,26 @@ int ep11_get_card_info(u16 card, struct ep11_card_info *info, int verify)
|
|||
u32 max_CP_index;
|
||||
} __packed * pmqi = NULL;
|
||||
|
||||
rc = card_cache_fetch(card, info);
|
||||
if (rc || verify) {
|
||||
pmqi = kmalloc(sizeof(*pmqi), GFP_KERNEL);
|
||||
if (!pmqi)
|
||||
return -ENOMEM;
|
||||
rc = ep11_query_info(card, AUTOSEL_DOM,
|
||||
0x01 /* module info query */,
|
||||
sizeof(*pmqi), (u8 *)pmqi);
|
||||
if (rc) {
|
||||
if (rc == -ENODEV)
|
||||
card_cache_scrub(card);
|
||||
goto out;
|
||||
}
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->API_ord_nr = pmqi->API_ord_nr;
|
||||
info->FW_version =
|
||||
(pmqi->FW_major_vers << 8) + pmqi->FW_minor_vers;
|
||||
memcpy(info->serial, pmqi->serial, sizeof(info->serial));
|
||||
info->op_mode = pmqi->op_mode;
|
||||
card_cache_update(card, info);
|
||||
}
|
||||
/* use the cprb mempool to satisfy this short term mem alloc */
|
||||
pmqi = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
|
||||
mempool_alloc_preallocated(cprb_mempool) :
|
||||
mempool_alloc(cprb_mempool, GFP_KERNEL);
|
||||
if (!pmqi)
|
||||
return -ENOMEM;
|
||||
rc = ep11_query_info(card, AUTOSEL_DOM,
|
||||
0x01 /* module info query */,
|
||||
sizeof(*pmqi), (u8 *)pmqi, xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->API_ord_nr = pmqi->API_ord_nr;
|
||||
info->FW_version = (pmqi->FW_major_vers << 8) + pmqi->FW_minor_vers;
|
||||
memcpy(info->serial, pmqi->serial, sizeof(info->serial));
|
||||
info->op_mode = pmqi->op_mode;
|
||||
|
||||
out:
|
||||
kfree(pmqi);
|
||||
mempool_free(pmqi, cprb_mempool);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(ep11_get_card_info);
|
||||
|
|
@ -737,7 +695,8 @@ EXPORT_SYMBOL(ep11_get_card_info);
|
|||
/*
|
||||
* Provide information about a domain within an EP11 card.
|
||||
*/
|
||||
int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info)
|
||||
int ep11_get_domain_info(u16 card, u16 domain,
|
||||
struct ep11_domain_info *info, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
struct ep11_domain_query_info {
|
||||
|
|
@ -746,36 +705,32 @@ int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info)
|
|||
u8 new_WK_VP[32];
|
||||
u32 dom_flags;
|
||||
u64 op_mode;
|
||||
} __packed * p_dom_info;
|
||||
|
||||
p_dom_info = kmalloc(sizeof(*p_dom_info), GFP_KERNEL);
|
||||
if (!p_dom_info)
|
||||
return -ENOMEM;
|
||||
} __packed dom_query_info;
|
||||
|
||||
rc = ep11_query_info(card, domain, 0x03 /* domain info query */,
|
||||
sizeof(*p_dom_info), (u8 *)p_dom_info);
|
||||
sizeof(dom_query_info), (u8 *)&dom_query_info,
|
||||
xflags);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
info->cur_wk_state = '0';
|
||||
info->new_wk_state = '0';
|
||||
if (p_dom_info->dom_flags & 0x10 /* left imprint mode */) {
|
||||
if (p_dom_info->dom_flags & 0x02 /* cur wk valid */) {
|
||||
if (dom_query_info.dom_flags & 0x10 /* left imprint mode */) {
|
||||
if (dom_query_info.dom_flags & 0x02 /* cur wk valid */) {
|
||||
info->cur_wk_state = '1';
|
||||
memcpy(info->cur_wkvp, p_dom_info->cur_WK_VP, 32);
|
||||
memcpy(info->cur_wkvp, dom_query_info.cur_WK_VP, 32);
|
||||
}
|
||||
if (p_dom_info->dom_flags & 0x04 || /* new wk present */
|
||||
p_dom_info->dom_flags & 0x08 /* new wk committed */) {
|
||||
if (dom_query_info.dom_flags & 0x04 || /* new wk present */
|
||||
dom_query_info.dom_flags & 0x08 /* new wk committed */) {
|
||||
info->new_wk_state =
|
||||
p_dom_info->dom_flags & 0x08 ? '2' : '1';
|
||||
memcpy(info->new_wkvp, p_dom_info->new_WK_VP, 32);
|
||||
dom_query_info.dom_flags & 0x08 ? '2' : '1';
|
||||
memcpy(info->new_wkvp, dom_query_info.new_WK_VP, 32);
|
||||
}
|
||||
}
|
||||
info->op_mode = p_dom_info->op_mode;
|
||||
info->op_mode = dom_query_info.op_mode;
|
||||
|
||||
out:
|
||||
kfree(p_dom_info);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(ep11_get_domain_info);
|
||||
|
|
@ -788,7 +743,7 @@ EXPORT_SYMBOL(ep11_get_domain_info);
|
|||
|
||||
static int _ep11_genaeskey(u16 card, u16 domain,
|
||||
u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, size_t *keybufsize)
|
||||
u8 *keybuf, size_t *keybufsize, u32 xflags)
|
||||
{
|
||||
struct keygen_req_pl {
|
||||
struct pl_head head;
|
||||
|
|
@ -823,7 +778,7 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
size_t req_pl_size, pinblob_size = 0;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
int api, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
|
||||
|
|
@ -851,7 +806,7 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
pinblob_size = EP11_PINBLOB_V1_BYTES;
|
||||
}
|
||||
req_pl_size = sizeof(struct keygen_req_pl) + ASN1TAGLEN(pinblob_size);
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct keygen_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -877,22 +832,19 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
*p++ = pinblob_size;
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct keygen_rep_pl));
|
||||
rep = alloc_cprbmem(sizeof(struct keygen_rep_pl), xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct keygen_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl));
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -925,14 +877,13 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
*keybufsize = rep_pl->data_len;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, 0, false, xflags);
|
||||
free_cprbmem(rep, sizeof(struct keygen_rep_pl), true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, u32 *keybufsize, u32 keybufver)
|
||||
u8 *keybuf, u32 *keybufsize, u32 keybufver, u32 xflags)
|
||||
{
|
||||
struct ep11kblob_header *hdr;
|
||||
size_t hdr_size, pl_size;
|
||||
|
|
@ -953,7 +904,7 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
return rc;
|
||||
|
||||
rc = _ep11_genaeskey(card, domain, keybitsize, keygenflags,
|
||||
pl, &pl_size);
|
||||
pl, &pl_size, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -973,7 +924,8 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
u16 mode, u32 mech, const u8 *iv,
|
||||
const u8 *key, size_t keysize,
|
||||
const u8 *inbuf, size_t inbufsize,
|
||||
u8 *outbuf, size_t *outbufsize)
|
||||
u8 *outbuf, size_t *outbufsize,
|
||||
u32 xflags)
|
||||
{
|
||||
struct crypt_req_pl {
|
||||
struct pl_head head;
|
||||
|
|
@ -1000,8 +952,8 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
} __packed * rep_pl;
|
||||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
size_t req_pl_size, rep_pl_size;
|
||||
struct ep11_urb urb;
|
||||
size_t req_pl_size, rep_pl_size = 0;
|
||||
int n, api = EP11_API_V1, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
|
||||
|
|
@ -1012,7 +964,7 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
/* request cprb and payload */
|
||||
req_pl_size = sizeof(struct crypt_req_pl) + (iv ? 16 : 0)
|
||||
+ ASN1TAGLEN(keysize) + ASN1TAGLEN(inbufsize);
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct crypt_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -1034,22 +986,19 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
|
||||
/* reply cprb and payload, assume out data size <= in data size + 32 */
|
||||
rep_pl_size = sizeof(struct crypt_rep_pl) + ASN1TAGLEN(inbufsize + 32);
|
||||
rep = alloc_cprb(rep_pl_size);
|
||||
rep = alloc_cprbmem(rep_pl_size, xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct crypt_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + rep_pl_size);
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -1095,9 +1044,8 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
*outbufsize = n;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, req_pl_size, true, xflags);
|
||||
free_cprbmem(rep, rep_pl_size, true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1106,7 +1054,7 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
const u8 *enckey, size_t enckeysize,
|
||||
u32 mech, const u8 *iv,
|
||||
u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, size_t *keybufsize)
|
||||
u8 *keybuf, size_t *keybufsize, u32 xflags)
|
||||
{
|
||||
struct uw_req_pl {
|
||||
struct pl_head head;
|
||||
|
|
@ -1143,7 +1091,7 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
size_t req_pl_size, pinblob_size = 0;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
int api, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
|
||||
|
|
@ -1161,7 +1109,7 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
req_pl_size = sizeof(struct uw_req_pl) + (iv ? 16 : 0)
|
||||
+ ASN1TAGLEN(keksize) + ASN1TAGLEN(0)
|
||||
+ ASN1TAGLEN(pinblob_size) + ASN1TAGLEN(enckeysize);
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct uw_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -1197,22 +1145,19 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
p += asn1tag_write(p, 0x04, enckey, enckeysize);
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct uw_rep_pl));
|
||||
rep = alloc_cprbmem(sizeof(struct uw_rep_pl), xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct uw_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl));
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -1245,9 +1190,8 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
*keybufsize = rep_pl->data_len;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, req_pl_size, true, xflags);
|
||||
free_cprbmem(rep, sizeof(struct uw_rep_pl), true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1257,7 +1201,7 @@ static int ep11_unwrapkey(u16 card, u16 domain,
|
|||
u32 mech, const u8 *iv,
|
||||
u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, u32 *keybufsize,
|
||||
u8 keybufver)
|
||||
u8 keybufver, u32 xflags)
|
||||
{
|
||||
struct ep11kblob_header *hdr;
|
||||
size_t hdr_size, pl_size;
|
||||
|
|
@ -1271,7 +1215,7 @@ static int ep11_unwrapkey(u16 card, u16 domain,
|
|||
|
||||
rc = _ep11_unwrapkey(card, domain, kek, keksize, enckey, enckeysize,
|
||||
mech, iv, keybitsize, keygenflags,
|
||||
pl, &pl_size);
|
||||
pl, &pl_size, xflags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1290,7 +1234,7 @@ static int ep11_unwrapkey(u16 card, u16 domain,
|
|||
static int _ep11_wrapkey(u16 card, u16 domain,
|
||||
const u8 *key, size_t keysize,
|
||||
u32 mech, const u8 *iv,
|
||||
u8 *databuf, size_t *datasize)
|
||||
u8 *databuf, size_t *datasize, u32 xflags)
|
||||
{
|
||||
struct wk_req_pl {
|
||||
struct pl_head head;
|
||||
|
|
@ -1319,7 +1263,7 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
} __packed * rep_pl;
|
||||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
size_t req_pl_size;
|
||||
int api, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
|
|
@ -1327,7 +1271,7 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
/* request cprb and payload */
|
||||
req_pl_size = sizeof(struct wk_req_pl) + (iv ? 16 : 0)
|
||||
+ ASN1TAGLEN(keysize) + 4;
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
if (!mech || mech == 0x80060001)
|
||||
|
|
@ -1357,22 +1301,19 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
*p++ = 0;
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct wk_rep_pl));
|
||||
rep = alloc_cprbmem(sizeof(struct wk_rep_pl), xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct wk_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl));
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -1405,18 +1346,18 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
*datasize = rep_pl->data_len;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, req_pl_size, true, xflags);
|
||||
free_cprbmem(rep, sizeof(struct wk_rep_pl), true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
const u8 *clrkey, u8 *keybuf, u32 *keybufsize,
|
||||
u32 keytype)
|
||||
u32 keytype, u32 xflags)
|
||||
{
|
||||
int rc;
|
||||
u8 encbuf[64], *kek = NULL;
|
||||
void *mem;
|
||||
u8 encbuf[64], *kek;
|
||||
size_t clrkeylen, keklen, encbuflen = sizeof(encbuf);
|
||||
|
||||
if (keybitsize == 128 || keybitsize == 192 || keybitsize == 256) {
|
||||
|
|
@ -1427,18 +1368,24 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* allocate memory for the temp kek */
|
||||
/*
|
||||
* Allocate space for the temp kek.
|
||||
* Also we only need up to MAXEP11AESKEYBLOBSIZE bytes for this
|
||||
* we use the already existing cprb mempool to solve this
|
||||
* short term memory requirement.
|
||||
*/
|
||||
mem = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
|
||||
mempool_alloc_preallocated(cprb_mempool) :
|
||||
mempool_alloc(cprb_mempool, GFP_KERNEL);
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
kek = (u8 *)mem;
|
||||
keklen = MAXEP11AESKEYBLOBSIZE;
|
||||
kek = kmalloc(keklen, GFP_ATOMIC);
|
||||
if (!kek) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Step 1: generate AES 256 bit random kek key */
|
||||
rc = _ep11_genaeskey(card, domain, 256,
|
||||
0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
|
||||
kek, &keklen);
|
||||
kek, &keklen, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s generate kek key failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
|
|
@ -1447,7 +1394,7 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
|
||||
/* Step 2: encrypt clear key value with the kek key */
|
||||
rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen,
|
||||
clrkey, clrkeylen, encbuf, &encbuflen);
|
||||
clrkey, clrkeylen, encbuf, &encbuflen, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s encrypting key value with kek key failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
|
|
@ -1457,22 +1404,23 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
/* Step 3: import the encrypted key value as a new key */
|
||||
rc = ep11_unwrapkey(card, domain, kek, keklen,
|
||||
encbuf, encbuflen, 0, def_iv,
|
||||
keybitsize, 0, keybuf, keybufsize, keytype);
|
||||
keybitsize, 0, keybuf, keybufsize, keytype, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s importing key value as new key failed,, rc=%d\n",
|
||||
ZCRYPT_DBF_ERR("%s importing key value as new key failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(kek);
|
||||
mempool_free(mem, cprb_mempool);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(ep11_clr2keyblob);
|
||||
|
||||
int ep11_kblob2protkey(u16 card, u16 dom,
|
||||
const u8 *keyblob, u32 keybloblen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags)
|
||||
{
|
||||
struct ep11kblob_header *hdr;
|
||||
struct ep11keyblob *key;
|
||||
|
|
@ -1498,15 +1446,29 @@ int ep11_kblob2protkey(u16 card, u16 dom,
|
|||
}
|
||||
/* !!! hdr is no longer a valid header !!! */
|
||||
|
||||
/* alloc temp working buffer */
|
||||
/* need a temp working buffer */
|
||||
wkbuflen = (keylen + AES_BLOCK_SIZE) & (~(AES_BLOCK_SIZE - 1));
|
||||
wkbuf = kmalloc(wkbuflen, GFP_ATOMIC);
|
||||
if (!wkbuf)
|
||||
return -ENOMEM;
|
||||
if (wkbuflen > CPRB_MEMPOOL_ITEM_SIZE) {
|
||||
/* this should never happen */
|
||||
rc = -ENOMEM;
|
||||
ZCRYPT_DBF_WARN("%s wkbuflen %d > cprb mempool item size %d, rc=%d\n",
|
||||
__func__, (int)wkbuflen, CPRB_MEMPOOL_ITEM_SIZE, rc);
|
||||
return rc;
|
||||
}
|
||||
/* use the cprb mempool to satisfy this short term mem allocation */
|
||||
wkbuf = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
|
||||
mempool_alloc_preallocated(cprb_mempool) :
|
||||
mempool_alloc(cprb_mempool, GFP_ATOMIC);
|
||||
if (!wkbuf) {
|
||||
rc = -ENOMEM;
|
||||
ZCRYPT_DBF_WARN("%s allocating tmp buffer via cprb mempool failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* ep11 secure key -> protected key + info */
|
||||
rc = _ep11_wrapkey(card, dom, (u8 *)key, keylen,
|
||||
0, def_iv, wkbuf, &wkbuflen);
|
||||
0, def_iv, wkbuf, &wkbuflen, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s rewrapping ep11 key to pkey failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
|
|
@ -1573,37 +1535,32 @@ int ep11_kblob2protkey(u16 card, u16 dom,
|
|||
*protkeylen = wki->pkeysize;
|
||||
|
||||
out:
|
||||
kfree(wkbuf);
|
||||
mempool_free(wkbuf, cprb_mempool);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(ep11_kblob2protkey);
|
||||
|
||||
int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int minapi, const u8 *wkvp)
|
||||
int ep11_findcard2(u32 *apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int minapi, const u8 *wkvp, u32 xflags)
|
||||
{
|
||||
struct zcrypt_device_status_ext *device_status;
|
||||
u32 *_apqns = NULL, _nr_apqns = 0;
|
||||
int i, card, dom, rc = -ENOMEM;
|
||||
struct ep11_domain_info edi;
|
||||
struct ep11_card_info eci;
|
||||
u32 _nr_apqns = 0;
|
||||
int i, card, dom;
|
||||
|
||||
/* fetch status of all crypto cards */
|
||||
device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT,
|
||||
sizeof(struct zcrypt_device_status_ext),
|
||||
GFP_KERNEL);
|
||||
if (!device_status)
|
||||
return -ENOMEM;
|
||||
zcrypt_device_status_mask_ext(device_status);
|
||||
/* occupy the device status memory */
|
||||
mutex_lock(&dev_status_mem_mutex);
|
||||
memset(dev_status_mem, 0, ZCRYPT_DEV_STATUS_EXT_SIZE);
|
||||
device_status = (struct zcrypt_device_status_ext *)dev_status_mem;
|
||||
|
||||
/* allocate 1k space for up to 256 apqns */
|
||||
_apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL);
|
||||
if (!_apqns) {
|
||||
kvfree(device_status);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* fetch crypto device status into this struct */
|
||||
zcrypt_device_status_mask_ext(device_status,
|
||||
ZCRYPT_DEV_STATUS_CARD_MAX,
|
||||
ZCRYPT_DEV_STATUS_QUEUE_MAX);
|
||||
|
||||
/* walk through all the crypto apqnss */
|
||||
for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) {
|
||||
for (i = 0; i < ZCRYPT_DEV_STATUS_ENTRIES; i++) {
|
||||
card = AP_QID_CARD(device_status[i].qid);
|
||||
dom = AP_QID_QUEUE(device_status[i].qid);
|
||||
/* check online state */
|
||||
|
|
@ -1623,14 +1580,14 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
|||
continue;
|
||||
/* check min api version if given */
|
||||
if (minapi > 0) {
|
||||
if (ep11_get_card_info(card, &eci, 0))
|
||||
if (ep11_get_card_info(card, &eci, xflags))
|
||||
continue;
|
||||
if (minapi > eci.API_ord_nr)
|
||||
continue;
|
||||
}
|
||||
/* check wkvp if given */
|
||||
if (wkvp) {
|
||||
if (ep11_get_domain_info(card, dom, &edi))
|
||||
if (ep11_get_domain_info(card, dom, &edi, xflags))
|
||||
continue;
|
||||
if (edi.cur_wk_state != '1')
|
||||
continue;
|
||||
|
|
@ -1638,27 +1595,40 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
|||
continue;
|
||||
}
|
||||
/* apqn passed all filtering criterons, add to the array */
|
||||
if (_nr_apqns < 256)
|
||||
_apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom);
|
||||
if (_nr_apqns < *nr_apqns)
|
||||
apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom);
|
||||
}
|
||||
|
||||
/* nothing found ? */
|
||||
if (!_nr_apqns) {
|
||||
kfree(_apqns);
|
||||
rc = -ENODEV;
|
||||
} else {
|
||||
/* no re-allocation, simple return the _apqns array */
|
||||
*apqns = _apqns;
|
||||
*nr_apqns = _nr_apqns;
|
||||
rc = 0;
|
||||
}
|
||||
*nr_apqns = _nr_apqns;
|
||||
|
||||
kvfree(device_status);
|
||||
return rc;
|
||||
mutex_unlock(&dev_status_mem_mutex);
|
||||
|
||||
return _nr_apqns ? 0 : -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL(ep11_findcard2);
|
||||
|
||||
void __exit zcrypt_ep11misc_exit(void)
|
||||
int __init zcrypt_ep11misc_init(void)
|
||||
{
|
||||
card_cache_free();
|
||||
/* Pre-allocate a small memory pool for ep11 cprbs. */
|
||||
cprb_mempool = mempool_create_kmalloc_pool(2 * zcrypt_mempool_threshold,
|
||||
CPRB_MEMPOOL_ITEM_SIZE);
|
||||
if (!cprb_mempool)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Pre-allocate one crypto status card struct used in ep11_findcard2() */
|
||||
dev_status_mem = kvmalloc(ZCRYPT_DEV_STATUS_EXT_SIZE, GFP_KERNEL);
|
||||
if (!dev_status_mem) {
|
||||
mempool_destroy(cprb_mempool);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zcrypt_ep11misc_exit(void)
|
||||
{
|
||||
mutex_lock(&dev_status_mem_mutex);
|
||||
kvfree(dev_status_mem);
|
||||
mutex_unlock(&dev_status_mem_mutex);
|
||||
mempool_destroy(cprb_mempool);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,25 +104,26 @@ struct ep11_domain_info {
|
|||
/*
|
||||
* Provide information about an EP11 card.
|
||||
*/
|
||||
int ep11_get_card_info(u16 card, struct ep11_card_info *info, int verify);
|
||||
int ep11_get_card_info(u16 card, struct ep11_card_info *info, u32 xflags);
|
||||
|
||||
/*
|
||||
* Provide information about a domain within an EP11 card.
|
||||
*/
|
||||
int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info);
|
||||
int ep11_get_domain_info(u16 card, u16 domain,
|
||||
struct ep11_domain_info *info, u32 xflags);
|
||||
|
||||
/*
|
||||
* Generate (random) EP11 AES secure key.
|
||||
*/
|
||||
int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
u8 *keybuf, u32 *keybufsize, u32 keybufver);
|
||||
u8 *keybuf, u32 *keybufsize, u32 keybufver, u32 xflags);
|
||||
|
||||
/*
|
||||
* Generate EP11 AES secure key with given clear key value.
|
||||
*/
|
||||
int ep11_clr2keyblob(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
const u8 *clrkey, u8 *keybuf, u32 *keybufsize,
|
||||
u32 keytype);
|
||||
u32 keytype, u32 xflags);
|
||||
|
||||
/*
|
||||
* Build a list of ep11 apqns meeting the following constrains:
|
||||
|
|
@ -136,22 +137,22 @@ int ep11_clr2keyblob(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
* key for this domain. When a wkvp is given there will always be a re-fetch
|
||||
* of the domain info for the potential apqn - so this triggers an request
|
||||
* reply to each apqn eligible.
|
||||
* The array of apqn entries is allocated with kmalloc and returned in *apqns;
|
||||
* the number of apqns stored into the list is returned in *nr_apqns. One apqn
|
||||
* entry is simple a 32 bit value with 16 bit cardnr and 16 bit domain nr and
|
||||
* may be casted to struct pkey_apqn. The return value is either 0 for success
|
||||
* or a negative errno value. If no apqn meeting the criteria is found,
|
||||
* -ENODEV is returned.
|
||||
* The caller should set *nr_apqns to the nr of elements available in *apqns.
|
||||
* On return *nr_apqns is then updated with the nr of apqns filled into *apqns.
|
||||
* The return value is either 0 for success or a negative errno value.
|
||||
* If no apqn meeting the criteria is found, -ENODEV is returned.
|
||||
*/
|
||||
int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int minapi, const u8 *wkvp);
|
||||
int ep11_findcard2(u32 *apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
||||
int minhwtype, int minapi, const u8 *wkvp, u32 xflags);
|
||||
|
||||
/*
|
||||
* Derive proteced key from EP11 key blob (AES and ECC keys).
|
||||
*/
|
||||
int ep11_kblob2protkey(u16 card, u16 dom, const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype,
|
||||
u32 xflags);
|
||||
|
||||
int zcrypt_ep11misc_init(void);
|
||||
void zcrypt_ep11misc_exit(void);
|
||||
|
||||
#endif /* _ZCRYPT_EP11MISC_H_ */
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ static void zcrypt_msgtype50_receive(struct ap_queue *aq,
|
|||
msg->len = sizeof(error_reply);
|
||||
}
|
||||
out:
|
||||
complete((struct completion *)msg->private);
|
||||
complete(&msg->response.work);
|
||||
}
|
||||
|
||||
static atomic_t zcrypt_step = ATOMIC_INIT(0);
|
||||
|
|
@ -449,30 +449,30 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0);
|
|||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* CEXxA device to the request distributor
|
||||
* @mex: pointer to the modexpo request buffer
|
||||
* This function assumes that ap_msg has been initialized with
|
||||
* ap_init_apmsg() and thus a valid buffer with the size of
|
||||
* ap_msg->bufsize is available within ap_msg. Also the caller has
|
||||
* to make sure ap_release_apmsg() is always called even on failure.
|
||||
*/
|
||||
static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
|
||||
struct ica_rsa_modexpo *mex,
|
||||
struct ap_message *ap_msg)
|
||||
{
|
||||
struct completion work;
|
||||
int rc;
|
||||
|
||||
ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
|
||||
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
if (ap_msg->bufsize < MSGTYPE50_CRB3_MAX_MSG_SIZE)
|
||||
return -EMSGSIZE;
|
||||
ap_msg->receive = zcrypt_msgtype50_receive;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = &work;
|
||||
rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex);
|
||||
if (rc)
|
||||
goto out;
|
||||
init_completion(&work);
|
||||
init_completion(&ap_msg->response.work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = wait_for_completion_interruptible(&work);
|
||||
rc = wait_for_completion_interruptible(&ap_msg->response.work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
@ -485,7 +485,6 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
|
|||
}
|
||||
|
||||
out:
|
||||
ap_msg->private = NULL;
|
||||
if (rc)
|
||||
pr_debug("send me cprb at dev=%02x.%04x rc=%d\n",
|
||||
AP_QID_CARD(zq->queue->qid),
|
||||
|
|
@ -499,30 +498,30 @@ static long zcrypt_msgtype50_modexpo(struct zcrypt_queue *zq,
|
|||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* CEXxA device to the request distributor
|
||||
* @crt: pointer to the modexpoc_crt request buffer
|
||||
* This function assumes that ap_msg has been initialized with
|
||||
* ap_init_apmsg() and thus a valid buffer with the size of
|
||||
* ap_msg->bufsize is available within ap_msg. Also the caller has
|
||||
* to make sure ap_release_apmsg() is always called even on failure.
|
||||
*/
|
||||
static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
|
||||
struct ica_rsa_modexpo_crt *crt,
|
||||
struct ap_message *ap_msg)
|
||||
{
|
||||
struct completion work;
|
||||
int rc;
|
||||
|
||||
ap_msg->bufsize = MSGTYPE50_CRB3_MAX_MSG_SIZE;
|
||||
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
if (ap_msg->bufsize < MSGTYPE50_CRB3_MAX_MSG_SIZE)
|
||||
return -EMSGSIZE;
|
||||
ap_msg->receive = zcrypt_msgtype50_receive;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = &work;
|
||||
rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt);
|
||||
if (rc)
|
||||
goto out;
|
||||
init_completion(&work);
|
||||
init_completion(&ap_msg->response.work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = wait_for_completion_interruptible(&work);
|
||||
rc = wait_for_completion_interruptible(&ap_msg->response.work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
@ -535,7 +534,6 @@ static long zcrypt_msgtype50_modexpo_crt(struct zcrypt_queue *zq,
|
|||
}
|
||||
|
||||
out:
|
||||
ap_msg->private = NULL;
|
||||
if (rc)
|
||||
pr_debug("send crt cprb at dev=%02x.%04x rc=%d\n",
|
||||
AP_QID_CARD(zq->queue->qid),
|
||||
|
|
|
|||
|
|
@ -31,11 +31,6 @@
|
|||
|
||||
#define CEIL4(x) ((((x) + 3) / 4) * 4)
|
||||
|
||||
struct response_type {
|
||||
struct completion work;
|
||||
int type;
|
||||
};
|
||||
|
||||
#define CEXXC_RESPONSE_TYPE_ICA 0
|
||||
#define CEXXC_RESPONSE_TYPE_XCRB 1
|
||||
#define CEXXC_RESPONSE_TYPE_EP11 2
|
||||
|
|
@ -856,7 +851,7 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
|
|||
.type = TYPE82_RSP_CODE,
|
||||
.reply_code = REP82_ERROR_MACHINE_FAILURE,
|
||||
};
|
||||
struct response_type *resp_type = msg->private;
|
||||
struct ap_response_type *resp_type = &msg->response;
|
||||
struct type86x_reply *t86r;
|
||||
int len;
|
||||
|
||||
|
|
@ -920,7 +915,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
|
|||
.type = TYPE82_RSP_CODE,
|
||||
.reply_code = REP82_ERROR_MACHINE_FAILURE,
|
||||
};
|
||||
struct response_type *resp_type = msg->private;
|
||||
struct ap_response_type *resp_type = &msg->response;
|
||||
struct type86_ep11_reply *t86r;
|
||||
int len;
|
||||
|
||||
|
|
@ -967,9 +962,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
|
|||
struct ica_rsa_modexpo *mex,
|
||||
struct ap_message *ap_msg)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = CEXXC_RESPONSE_TYPE_ICA,
|
||||
};
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
int rc;
|
||||
|
||||
ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
|
|
@ -979,15 +972,15 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
|
|||
ap_msg->receive = zcrypt_msgtype6_receive;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = &resp_type;
|
||||
rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
init_completion(&resp_type.work);
|
||||
resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
|
||||
init_completion(&resp_type->work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
rc = wait_for_completion_interruptible(&resp_type.work);
|
||||
rc = wait_for_completion_interruptible(&resp_type->work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
@ -1001,7 +994,6 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
|
|||
|
||||
out_free:
|
||||
free_page((unsigned long)ap_msg->msg);
|
||||
ap_msg->private = NULL;
|
||||
ap_msg->msg = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1017,9 +1009,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
|
|||
struct ica_rsa_modexpo_crt *crt,
|
||||
struct ap_message *ap_msg)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = CEXXC_RESPONSE_TYPE_ICA,
|
||||
};
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
int rc;
|
||||
|
||||
ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
|
|
@ -1029,15 +1019,15 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
|
|||
ap_msg->receive = zcrypt_msgtype6_receive;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = &resp_type;
|
||||
rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
init_completion(&resp_type.work);
|
||||
resp_type->type = CEXXC_RESPONSE_TYPE_ICA;
|
||||
init_completion(&resp_type->work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
rc = wait_for_completion_interruptible(&resp_type.work);
|
||||
rc = wait_for_completion_interruptible(&resp_type->work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
@ -1051,7 +1041,6 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
|
|||
|
||||
out_free:
|
||||
free_page((unsigned long)ap_msg->msg);
|
||||
ap_msg->private = NULL;
|
||||
ap_msg->msg = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1061,28 +1050,21 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
|
|||
* Prepare a CCA AP msg: fetch the required data from userspace,
|
||||
* prepare the AP msg, fill some info into the ap_message struct,
|
||||
* extract some data from the CPRB and give back to the caller.
|
||||
* This function allocates memory and needs an ap_msg prepared
|
||||
* by the caller with ap_init_message(). Also the caller has to
|
||||
* make sure ap_release_message() is always called even on failure.
|
||||
* This function assumes that ap_msg has been initialized with
|
||||
* ap_init_apmsg() and thus a valid buffer with the size of
|
||||
* ap_msg->bufsize is available within ap_msg. Also the caller has
|
||||
* to make sure ap_release_apmsg() is always called even on failure.
|
||||
*/
|
||||
int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb,
|
||||
struct ap_message *ap_msg,
|
||||
unsigned int *func_code, unsigned short **dom)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = CEXXC_RESPONSE_TYPE_XCRB,
|
||||
};
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
|
||||
ap_msg->bufsize = atomic_read(&ap_max_msg_size);
|
||||
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
ap_msg->receive = zcrypt_msgtype6_receive;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
|
||||
if (!ap_msg->private)
|
||||
return -ENOMEM;
|
||||
resp_type->type = CEXXC_RESPONSE_TYPE_XCRB;
|
||||
return xcrb_msg_to_type6cprb_msgx(userspace, ap_msg, xcrb, func_code, dom);
|
||||
}
|
||||
|
||||
|
|
@ -1097,7 +1079,7 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
|
|||
struct ica_xcRB *xcrb,
|
||||
struct ap_message *ap_msg)
|
||||
{
|
||||
struct response_type *rtype = ap_msg->private;
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
struct {
|
||||
struct type6_hdr hdr;
|
||||
struct CPRBX cprbx;
|
||||
|
|
@ -1128,11 +1110,11 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
|
|||
msg->hdr.fromcardlen1 -= delta;
|
||||
}
|
||||
|
||||
init_completion(&rtype->work);
|
||||
init_completion(&resp_type->work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = wait_for_completion_interruptible(&rtype->work);
|
||||
rc = wait_for_completion_interruptible(&resp_type->work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
@ -1158,28 +1140,21 @@ static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq,
|
|||
* Prepare an EP11 AP msg: fetch the required data from userspace,
|
||||
* prepare the AP msg, fill some info into the ap_message struct,
|
||||
* extract some data from the CPRB and give back to the caller.
|
||||
* This function allocates memory and needs an ap_msg prepared
|
||||
* by the caller with ap_init_message(). Also the caller has to
|
||||
* make sure ap_release_message() is always called even on failure.
|
||||
* This function assumes that ap_msg has been initialized with
|
||||
* ap_init_apmsg() and thus a valid buffer with the size of
|
||||
* ap_msg->bufsize is available within ap_msg. Also the caller has
|
||||
* to make sure ap_release_apmsg() is always called even on failure.
|
||||
*/
|
||||
int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb,
|
||||
struct ap_message *ap_msg,
|
||||
unsigned int *func_code, unsigned int *domain)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = CEXXC_RESPONSE_TYPE_EP11,
|
||||
};
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
|
||||
ap_msg->bufsize = atomic_read(&ap_max_msg_size);
|
||||
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
ap_msg->receive = zcrypt_msgtype6_receive_ep11;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
|
||||
if (!ap_msg->private)
|
||||
return -ENOMEM;
|
||||
resp_type->type = CEXXC_RESPONSE_TYPE_EP11;
|
||||
return xcrb_msg_to_type6_ep11cprb_msgx(userspace, ap_msg, xcrb,
|
||||
func_code, domain);
|
||||
}
|
||||
|
|
@ -1197,7 +1172,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
|
|||
{
|
||||
int rc;
|
||||
unsigned int lfmt;
|
||||
struct response_type *rtype = ap_msg->private;
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
struct {
|
||||
struct type6_hdr hdr;
|
||||
struct ep11_cprb cprbx;
|
||||
|
|
@ -1251,11 +1226,11 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
|
|||
msg->hdr.fromcardlen1 = zq->reply.bufsize -
|
||||
sizeof(struct type86_hdr) - sizeof(struct type86_fmt2_ext);
|
||||
|
||||
init_completion(&rtype->work);
|
||||
init_completion(&resp_type->work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = wait_for_completion_interruptible(&rtype->work);
|
||||
rc = wait_for_completion_interruptible(&resp_type->work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
@ -1276,23 +1251,25 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare a CEXXC get random request ap message.
|
||||
* This function assumes that ap_msg has been initialized with
|
||||
* ap_init_apmsg() and thus a valid buffer with the size of
|
||||
* ap_max_msg_size is available within ap_msg. Also the caller has
|
||||
* to make sure ap_release_apmsg() is always called even on failure.
|
||||
*/
|
||||
int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code,
|
||||
unsigned int *domain)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = CEXXC_RESPONSE_TYPE_XCRB,
|
||||
};
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
|
||||
ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE;
|
||||
ap_msg->msg = kmalloc(ap_msg->bufsize, GFP_KERNEL);
|
||||
if (!ap_msg->msg)
|
||||
return -ENOMEM;
|
||||
if (ap_msg->bufsize < AP_DEFAULT_MAX_MSG_SIZE)
|
||||
return -EMSGSIZE;
|
||||
ap_msg->receive = zcrypt_msgtype6_receive;
|
||||
ap_msg->psmid = (((unsigned long)current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
|
||||
if (!ap_msg->private)
|
||||
return -ENOMEM;
|
||||
|
||||
resp_type->type = CEXXC_RESPONSE_TYPE_XCRB;
|
||||
|
||||
rng_type6cprb_msgx(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
|
||||
|
||||
|
|
@ -1319,16 +1296,16 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
|
|||
short int verb_length;
|
||||
short int key_length;
|
||||
} __packed * msg = ap_msg->msg;
|
||||
struct response_type *rtype = ap_msg->private;
|
||||
struct ap_response_type *resp_type = &ap_msg->response;
|
||||
int rc;
|
||||
|
||||
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
|
||||
|
||||
init_completion(&rtype->work);
|
||||
init_completion(&resp_type->work);
|
||||
rc = ap_queue_message(zq->queue, ap_msg);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = wait_for_completion_interruptible(&rtype->work);
|
||||
rc = wait_for_completion_interruptible(&resp_type->work);
|
||||
if (rc == 0) {
|
||||
rc = ap_msg->rc;
|
||||
if (rc == 0)
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ void ctcmpc_dumpit(char *buf, int len)
|
|||
ctcm_pr_debug(" %s (+%s) : %s [%s]\n",
|
||||
addr, boff, bhex, basc);
|
||||
dup = 0;
|
||||
strcpy(duphex, bhex);
|
||||
strscpy(duphex, bhex);
|
||||
} else
|
||||
dup++;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,26 +29,13 @@
|
|||
#include <linux/watchdog.h>
|
||||
#include <asm/machine.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/diag288.h>
|
||||
#include <asm/diag.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define MAX_CMDLEN 240
|
||||
#define DEFAULT_CMD "SYSTEM RESTART"
|
||||
|
||||
#define MIN_INTERVAL 15 /* Minimal time supported by diag88 */
|
||||
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
|
||||
|
||||
#define WDT_DEFAULT_TIMEOUT 30
|
||||
|
||||
/* Function codes - init, change, cancel */
|
||||
#define WDT_FUNC_INIT 0
|
||||
#define WDT_FUNC_CHANGE 1
|
||||
#define WDT_FUNC_CANCEL 2
|
||||
#define WDT_FUNC_CONCEAL 0x80000000
|
||||
|
||||
/* Action codes for LPAR watchdog */
|
||||
#define LPARWDT_RESTART 0
|
||||
|
||||
static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD;
|
||||
static bool conceal_on;
|
||||
static bool nowayout_info = WATCHDOG_NOWAYOUT;
|
||||
|
|
@ -75,22 +62,8 @@ static char *cmd_buf;
|
|||
static int diag288(unsigned int func, unsigned int timeout,
|
||||
unsigned long action, unsigned int len)
|
||||
{
|
||||
union register_pair r1 = { .even = func, .odd = timeout, };
|
||||
union register_pair r3 = { .even = action, .odd = len, };
|
||||
int err;
|
||||
|
||||
diag_stat_inc(DIAG_STAT_X288);
|
||||
|
||||
err = -EINVAL;
|
||||
asm volatile(
|
||||
" diag %[r1],%[r3],0x288\n"
|
||||
"0: la %[err],0\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b, 1b)
|
||||
: [err] "+d" (err)
|
||||
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
|
||||
: "cc", "memory");
|
||||
return err;
|
||||
return __diag288(func, timeout, action, len);
|
||||
}
|
||||
|
||||
static int diag288_str(unsigned int func, unsigned int timeout, char *cmd)
|
||||
|
|
@ -189,8 +162,6 @@ static struct watchdog_device wdt_dev = {
|
|||
|
||||
static int __init diag288_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
watchdog_set_nowayout(&wdt_dev, nowayout_info);
|
||||
|
||||
if (machine_is_vm()) {
|
||||
|
|
@ -199,24 +170,6 @@ static int __init diag288_init(void)
|
|||
pr_err("The watchdog cannot be initialized\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = diag288_str(WDT_FUNC_INIT, MIN_INTERVAL, "BEGIN");
|
||||
if (ret != 0) {
|
||||
pr_err("The watchdog cannot be initialized\n");
|
||||
kfree(cmd_buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (diag288(WDT_FUNC_INIT, WDT_DEFAULT_TIMEOUT,
|
||||
LPARWDT_RESTART, 0)) {
|
||||
pr_err("The watchdog cannot be initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (diag288(WDT_FUNC_CANCEL, 0, 0, 0)) {
|
||||
pr_err("The watchdog cannot be deactivated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return watchdog_register_device(&wdt_dev);
|
||||
|
|
@ -228,5 +181,5 @@ static void __exit diag288_exit(void)
|
|||
kfree(cmd_buf);
|
||||
}
|
||||
|
||||
module_init(diag288_init);
|
||||
module_cpu_feature_match(S390_CPU_FEATURE_D288, diag288_init);
|
||||
module_exit(diag288_exit);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user