brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · 3a39e16 Raw
800 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  pkey device driver4 *5 *  Copyright IBM Corp. 2017, 20236 *7 *  Author(s): Harald Freudenberger8 */9 10#define KMSG_COMPONENT "pkey"11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt12 13#include <linux/init.h>14#include <linux/miscdevice.h>15#include <linux/slab.h>16 17#include "zcrypt_api.h"18#include "zcrypt_ccamisc.h"19 20#include "pkey_base.h"21 22/*23 * Helper functions24 */25static int key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,26		       const u8 *key, size_t keylen,27		       u8 *protkey, u32 *protkeylen, u32 *protkeytype)28{29	int rc;30 31	/* try the direct way */32	rc = pkey_handler_key_to_protkey(apqns, nr_apqns,33					 key, keylen,34					 protkey, protkeylen,35					 protkeytype);36 37	/* if this did not work, try the slowpath way */38	if (rc == -ENODEV) {39		rc = pkey_handler_slowpath_key_to_protkey(apqns, nr_apqns,40							  key, keylen,41							  protkey, protkeylen,42							  protkeytype);43		if (rc)44			rc = -ENODEV;45	}46 47	pr_debug("rc=%d\n", rc);48	return rc;49}50 51/*52 * In-Kernel function: Transform a key blob (of any type) into a protected key53 */54int pkey_key2protkey(const u8 *key, u32 keylen,55		     u8 *protkey, u32 *protkeylen, u32 *protkeytype)56{57	int rc;58 59	rc = key2protkey(NULL, 0, key, keylen,60			 protkey, protkeylen, protkeytype);61	if (rc == -ENODEV) {62		pkey_handler_request_modules();63		rc = key2protkey(NULL, 0, key, keylen,64				 protkey, protkeylen, protkeytype);65	}66 67	return rc;68}69EXPORT_SYMBOL(pkey_key2protkey);70 71/*72 * Ioctl functions73 */74 75static void *_copy_key_from_user(void __user *ukey, size_t keylen)76{77	if (!ukey || keylen < MINKEYBLOBBUFSIZE || keylen > KEYBLOBBUFSIZE)78		return ERR_PTR(-EINVAL);79 80	return memdup_user(ukey, keylen);81}82 83static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns)84{85	if (!uapqns || nr_apqns == 0)86		return NULL;87 88	return memdup_user(uapqns, nr_apqns * sizeof(struct pkey_apqn));89}90 91static int pkey_ioctl_genseck(struct pkey_genseck __user *ugs)92{93	struct pkey_genseck kgs;94	struct pkey_apqn apqn;95	u32 keybuflen;96	int rc;97 98	if (copy_from_user(&kgs, ugs, sizeof(kgs)))99		return -EFAULT;100 101	apqn.card = kgs.cardnr;102	apqn.domain = kgs.domain;103	keybuflen = sizeof(kgs.seckey.seckey);104	rc = pkey_handler_gen_key(&apqn, 1,105				  kgs.keytype, PKEY_TYPE_CCA_DATA, 0, 0,106				  kgs.seckey.seckey, &keybuflen, NULL);107	pr_debug("gen_key()=%d\n", rc);108	if (!rc && copy_to_user(ugs, &kgs, sizeof(kgs)))109		rc = -EFAULT;110	memzero_explicit(&kgs, sizeof(kgs));111 112	return rc;113}114 115static int pkey_ioctl_clr2seck(struct pkey_clr2seck __user *ucs)116{117	struct pkey_clr2seck kcs;118	struct pkey_apqn apqn;119	u32 keybuflen;120	int rc;121 122	if (copy_from_user(&kcs, ucs, sizeof(kcs)))123		return -EFAULT;124 125	apqn.card = kcs.cardnr;126	apqn.domain = kcs.domain;127	keybuflen = sizeof(kcs.seckey.seckey);128	rc = pkey_handler_clr_to_key(&apqn, 1,129				     kcs.keytype, PKEY_TYPE_CCA_DATA, 0, 0,130				     kcs.clrkey.clrkey,131				     pkey_keytype_aes_to_size(kcs.keytype),132				     kcs.seckey.seckey, &keybuflen, NULL);133	pr_debug("clr_to_key()=%d\n", rc);134	if (!rc && copy_to_user(ucs, &kcs, sizeof(kcs)))135		rc = -EFAULT;136	memzero_explicit(&kcs, sizeof(kcs));137 138	return rc;139}140 141static int pkey_ioctl_sec2protk(struct pkey_sec2protk __user *usp)142{143	struct pkey_sec2protk ksp;144	struct pkey_apqn apqn;145	int rc;146 147	if (copy_from_user(&ksp, usp, sizeof(ksp)))148		return -EFAULT;149 150	apqn.card = ksp.cardnr;151	apqn.domain = ksp.domain;152	ksp.protkey.len = sizeof(ksp.protkey.protkey);153	rc = pkey_handler_key_to_protkey(&apqn, 1,154					 ksp.seckey.seckey,155					 sizeof(ksp.seckey.seckey),156					 ksp.protkey.protkey,157					 &ksp.protkey.len, &ksp.protkey.type);158	pr_debug("key_to_protkey()=%d\n", rc);159	if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))160		rc = -EFAULT;161	memzero_explicit(&ksp, sizeof(ksp));162 163	return rc;164}165 166static int pkey_ioctl_clr2protk(struct pkey_clr2protk __user *ucp)167{168	struct pkey_clr2protk kcp;169	struct clearkeytoken *t;170	u32 keylen;171	u8 *tmpbuf;172	int rc;173 174	if (copy_from_user(&kcp, ucp, sizeof(kcp)))175		return -EFAULT;176 177	/* build a 'clear key token' from the clear key value */178	keylen = pkey_keytype_aes_to_size(kcp.keytype);179	if (!keylen) {180		PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",181			     __func__, kcp.keytype);182		memzero_explicit(&kcp, sizeof(kcp));183		return -EINVAL;184	}185	tmpbuf = kzalloc(sizeof(*t) + keylen, GFP_KERNEL);186	if (!tmpbuf) {187		memzero_explicit(&kcp, sizeof(kcp));188		return -ENOMEM;189	}190	t = (struct clearkeytoken *)tmpbuf;191	t->type = TOKTYPE_NON_CCA;192	t->version = TOKVER_CLEAR_KEY;193	t->keytype = (keylen - 8) >> 3;194	t->len = keylen;195	memcpy(t->clearkey, kcp.clrkey.clrkey, keylen);196	kcp.protkey.len = sizeof(kcp.protkey.protkey);197 198	rc = key2protkey(NULL, 0,199			 tmpbuf, sizeof(*t) + keylen,200			 kcp.protkey.protkey,201			 &kcp.protkey.len, &kcp.protkey.type);202	pr_debug("key2protkey()=%d\n", rc);203 204	kfree_sensitive(tmpbuf);205 206	if (!rc && copy_to_user(ucp, &kcp, sizeof(kcp)))207		rc = -EFAULT;208	memzero_explicit(&kcp, sizeof(kcp));209 210	return rc;211}212 213static int pkey_ioctl_findcard(struct pkey_findcard __user *ufc)214{215	struct pkey_findcard kfc;216	struct pkey_apqn *apqns;217	size_t nr_apqns;218	int rc;219 220	if (copy_from_user(&kfc, ufc, sizeof(kfc)))221		return -EFAULT;222 223	nr_apqns = MAXAPQNSINLIST;224	apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn), GFP_KERNEL);225	if (!apqns)226		return -ENOMEM;227 228	rc = pkey_handler_apqns_for_key(kfc.seckey.seckey,229					sizeof(kfc.seckey.seckey),230					PKEY_FLAGS_MATCH_CUR_MKVP,231					apqns, &nr_apqns);232	if (rc == -ENODEV)233		rc = pkey_handler_apqns_for_key(kfc.seckey.seckey,234						sizeof(kfc.seckey.seckey),235						PKEY_FLAGS_MATCH_ALT_MKVP,236						apqns, &nr_apqns);237	pr_debug("apqns_for_key()=%d\n", rc);238	if (rc) {239		kfree(apqns);240		return rc;241	}242	kfc.cardnr = apqns[0].card;243	kfc.domain = apqns[0].domain;244	kfree(apqns);245	if (copy_to_user(ufc, &kfc, sizeof(kfc)))246		return -EFAULT;247 248	return 0;249}250 251static int pkey_ioctl_skey2pkey(struct pkey_skey2pkey __user *usp)252{253	struct pkey_skey2pkey ksp;254	int rc;255 256	if (copy_from_user(&ksp, usp, sizeof(ksp)))257		return -EFAULT;258 259	ksp.protkey.len = sizeof(ksp.protkey.protkey);260	rc = pkey_handler_key_to_protkey(NULL, 0,261					 ksp.seckey.seckey,262					 sizeof(ksp.seckey.seckey),263					 ksp.protkey.protkey,264					 &ksp.protkey.len,265					 &ksp.protkey.type);266	pr_debug("key_to_protkey()=%d\n", rc);267	if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))268		rc = -EFAULT;269	memzero_explicit(&ksp, sizeof(ksp));270 271	return rc;272}273 274static int pkey_ioctl_verifykey(struct pkey_verifykey __user *uvk)275{276	u32 keytype, keybitsize, flags;277	struct pkey_verifykey kvk;278	int rc;279 280	if (copy_from_user(&kvk, uvk, sizeof(kvk)))281		return -EFAULT;282 283	kvk.cardnr = 0xFFFF;284	kvk.domain = 0xFFFF;285	rc = pkey_handler_verify_key(kvk.seckey.seckey,286				     sizeof(kvk.seckey.seckey),287				     &kvk.cardnr, &kvk.domain,288				     &keytype, &keybitsize, &flags);289	pr_debug("verify_key()=%d\n", rc);290	if (!rc && keytype != PKEY_TYPE_CCA_DATA)291		rc = -EINVAL;292	kvk.attributes = PKEY_VERIFY_ATTR_AES;293	kvk.keysize = (u16)keybitsize;294	if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)295		kvk.attributes |= PKEY_VERIFY_ATTR_OLD_MKVP;296	if (!rc && copy_to_user(uvk, &kvk, sizeof(kvk)))297		rc = -EFAULT;298	memzero_explicit(&kvk, sizeof(kvk));299 300	return rc;301}302 303static int pkey_ioctl_genprotk(struct pkey_genprotk __user *ugp)304{305	struct pkey_genprotk kgp;306	int rc;307 308	if (copy_from_user(&kgp, ugp, sizeof(kgp)))309		return -EFAULT;310 311	kgp.protkey.len = sizeof(kgp.protkey.protkey);312	rc = pkey_handler_gen_key(NULL, 0, kgp.keytype,313				  PKEY_TYPE_PROTKEY, 0, 0,314				  kgp.protkey.protkey, &kgp.protkey.len,315				  &kgp.protkey.type);316	pr_debug("gen_key()=%d\n", rc);317	if (!rc && copy_to_user(ugp, &kgp, sizeof(kgp)))318		rc = -EFAULT;319	memzero_explicit(&kgp, sizeof(kgp));320 321	return rc;322}323 324static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp)325{326	struct pkey_verifyprotk kvp;327	struct protaeskeytoken *t;328	u32 keytype;329	u8 *tmpbuf;330	int rc;331 332	if (copy_from_user(&kvp, uvp, sizeof(kvp)))333		return -EFAULT;334 335	keytype = pkey_aes_bitsize_to_keytype(8 * kvp.protkey.len);336	if (!keytype) {337		PKEY_DBF_ERR("%s unknown/unsupported protkey length %u\n",338			     __func__, kvp.protkey.len);339		memzero_explicit(&kvp, sizeof(kvp));340		return -EINVAL;341	}342 343	/* build a 'protected key token' from the raw protected key */344	tmpbuf = kzalloc(sizeof(*t), GFP_KERNEL);345	if (!tmpbuf) {346		memzero_explicit(&kvp, sizeof(kvp));347		return -ENOMEM;348	}349	t = (struct protaeskeytoken *)tmpbuf;350	t->type = TOKTYPE_NON_CCA;351	t->version = TOKVER_PROTECTED_KEY;352	t->keytype = keytype;353	t->len = kvp.protkey.len;354	memcpy(t->protkey, kvp.protkey.protkey, kvp.protkey.len);355 356	rc = pkey_handler_verify_key(tmpbuf, sizeof(*t),357				     NULL, NULL, NULL, NULL, NULL);358	pr_debug("verify_key()=%d\n", rc);359 360	kfree_sensitive(tmpbuf);361	memzero_explicit(&kvp, sizeof(kvp));362 363	return rc;364}365 366static int pkey_ioctl_kblob2protk(struct pkey_kblob2pkey __user *utp)367{368	struct pkey_kblob2pkey ktp;369	u8 *kkey;370	int rc;371 372	if (copy_from_user(&ktp, utp, sizeof(ktp)))373		return -EFAULT;374	kkey = _copy_key_from_user(ktp.key, ktp.keylen);375	if (IS_ERR(kkey))376		return PTR_ERR(kkey);377	ktp.protkey.len = sizeof(ktp.protkey.protkey);378	rc = key2protkey(NULL, 0, kkey, ktp.keylen,379			 ktp.protkey.protkey, &ktp.protkey.len,380			 &ktp.protkey.type);381	pr_debug("key2protkey()=%d\n", rc);382	kfree_sensitive(kkey);383	if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))384		rc = -EFAULT;385	memzero_explicit(&ktp, sizeof(ktp));386 387	return rc;388}389 390static int pkey_ioctl_genseck2(struct pkey_genseck2 __user *ugs)391{392	u32 klen = KEYBLOBBUFSIZE;393	struct pkey_genseck2 kgs;394	struct pkey_apqn *apqns;395	u8 *kkey;396	int rc;397	u32 u;398 399	if (copy_from_user(&kgs, ugs, sizeof(kgs)))400		return -EFAULT;401	u = pkey_aes_bitsize_to_keytype(kgs.size);402	if (!u) {403		PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",404			     __func__, kgs.size);405		return -EINVAL;406	}407	apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries);408	if (IS_ERR(apqns))409		return PTR_ERR(apqns);410	kkey = kzalloc(klen, GFP_KERNEL);411	if (!kkey) {412		kfree(apqns);413		return -ENOMEM;414	}415	rc = pkey_handler_gen_key(apqns, kgs.apqn_entries,416				  u, kgs.type, kgs.size, kgs.keygenflags,417				  kkey, &klen, NULL);418	pr_debug("gen_key()=%d\n", rc);419	kfree(apqns);420	if (rc) {421		kfree_sensitive(kkey);422		return rc;423	}424	if (kgs.key) {425		if (kgs.keylen < klen) {426			kfree_sensitive(kkey);427			return -EINVAL;428		}429		if (copy_to_user(kgs.key, kkey, klen)) {430			kfree_sensitive(kkey);431			return -EFAULT;432		}433	}434	kgs.keylen = klen;435	if (copy_to_user(ugs, &kgs, sizeof(kgs)))436		rc = -EFAULT;437	kfree_sensitive(kkey);438 439	return rc;440}441 442static int pkey_ioctl_clr2seck2(struct pkey_clr2seck2 __user *ucs)443{444	u32 klen = KEYBLOBBUFSIZE;445	struct pkey_clr2seck2 kcs;446	struct pkey_apqn *apqns;447	u8 *kkey;448	int rc;449	u32 u;450 451	if (copy_from_user(&kcs, ucs, sizeof(kcs)))452		return -EFAULT;453	u = pkey_aes_bitsize_to_keytype(kcs.size);454	if (!u) {455		PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",456			     __func__, kcs.size);457		memzero_explicit(&kcs, sizeof(kcs));458		return -EINVAL;459	}460	apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries);461	if (IS_ERR(apqns)) {462		memzero_explicit(&kcs, sizeof(kcs));463		return PTR_ERR(apqns);464	}465	kkey = kzalloc(klen, GFP_KERNEL);466	if (!kkey) {467		kfree(apqns);468		memzero_explicit(&kcs, sizeof(kcs));469		return -ENOMEM;470	}471	rc = pkey_handler_clr_to_key(apqns, kcs.apqn_entries,472				     u, kcs.type, kcs.size, kcs.keygenflags,473				     kcs.clrkey.clrkey, kcs.size / 8,474				     kkey, &klen, NULL);475	pr_debug("clr_to_key()=%d\n", rc);476	kfree(apqns);477	if (rc) {478		kfree_sensitive(kkey);479		memzero_explicit(&kcs, sizeof(kcs));480		return rc;481	}482	if (kcs.key) {483		if (kcs.keylen < klen) {484			kfree_sensitive(kkey);485			memzero_explicit(&kcs, sizeof(kcs));486			return -EINVAL;487		}488		if (copy_to_user(kcs.key, kkey, klen)) {489			kfree_sensitive(kkey);490			memzero_explicit(&kcs, sizeof(kcs));491			return -EFAULT;492		}493	}494	kcs.keylen = klen;495	if (copy_to_user(ucs, &kcs, sizeof(kcs)))496		rc = -EFAULT;497	memzero_explicit(&kcs, sizeof(kcs));498	kfree_sensitive(kkey);499 500	return rc;501}502 503static int pkey_ioctl_verifykey2(struct pkey_verifykey2 __user *uvk)504{505	struct pkey_verifykey2 kvk;506	u8 *kkey;507	int rc;508 509	if (copy_from_user(&kvk, uvk, sizeof(kvk)))510		return -EFAULT;511	kkey = _copy_key_from_user(kvk.key, kvk.keylen);512	if (IS_ERR(kkey))513		return PTR_ERR(kkey);514 515	rc = pkey_handler_verify_key(kkey, kvk.keylen,516				     &kvk.cardnr, &kvk.domain,517				     &kvk.type, &kvk.size, &kvk.flags);518	pr_debug("verify_key()=%d\n", rc);519 520	kfree_sensitive(kkey);521	if (!rc && copy_to_user(uvk, &kvk, sizeof(kvk)))522		return -EFAULT;523 524	return rc;525}526 527static int pkey_ioctl_kblob2protk2(struct pkey_kblob2pkey2 __user *utp)528{529	struct pkey_apqn *apqns = NULL;530	struct pkey_kblob2pkey2 ktp;531	u8 *kkey;532	int rc;533 534	if (copy_from_user(&ktp, utp, sizeof(ktp)))535		return -EFAULT;536	apqns = _copy_apqns_from_user(ktp.apqns, ktp.apqn_entries);537	if (IS_ERR(apqns))538		return PTR_ERR(apqns);539	kkey = _copy_key_from_user(ktp.key, ktp.keylen);540	if (IS_ERR(kkey)) {541		kfree(apqns);542		return PTR_ERR(kkey);543	}544	ktp.protkey.len = sizeof(ktp.protkey.protkey);545	rc = key2protkey(apqns, ktp.apqn_entries, kkey, ktp.keylen,546			 ktp.protkey.protkey, &ktp.protkey.len,547			 &ktp.protkey.type);548	pr_debug("key2protkey()=%d\n", rc);549	kfree(apqns);550	kfree_sensitive(kkey);551	if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))552		rc = -EFAULT;553	memzero_explicit(&ktp, sizeof(ktp));554 555	return rc;556}557 558static int pkey_ioctl_apqns4k(struct pkey_apqns4key __user *uak)559{560	struct pkey_apqn *apqns = NULL;561	struct pkey_apqns4key kak;562	size_t nr_apqns, len;563	u8 *kkey;564	int rc;565 566	if (copy_from_user(&kak, uak, sizeof(kak)))567		return -EFAULT;568	nr_apqns = kak.apqn_entries;569	if (nr_apqns) {570		apqns = kmalloc_array(nr_apqns,571				      sizeof(struct pkey_apqn),572				      GFP_KERNEL);573		if (!apqns)574			return -ENOMEM;575	}576	kkey = _copy_key_from_user(kak.key, kak.keylen);577	if (IS_ERR(kkey)) {578		kfree(apqns);579		return PTR_ERR(kkey);580	}581	rc = pkey_handler_apqns_for_key(kkey, kak.keylen, kak.flags,582					apqns, &nr_apqns);583	pr_debug("apqns_for_key()=%d\n", rc);584	kfree_sensitive(kkey);585	if (rc && rc != -ENOSPC) {586		kfree(apqns);587		return rc;588	}589	if (!rc && kak.apqns) {590		if (nr_apqns > kak.apqn_entries) {591			kfree(apqns);592			return -EINVAL;593		}594		len = nr_apqns * sizeof(struct pkey_apqn);595		if (len) {596			if (copy_to_user(kak.apqns, apqns, len)) {597				kfree(apqns);598				return -EFAULT;599			}600		}601	}602	kak.apqn_entries = nr_apqns;603	if (copy_to_user(uak, &kak, sizeof(kak)))604		rc = -EFAULT;605	kfree(apqns);606 607	return rc;608}609 610static int pkey_ioctl_apqns4kt(struct pkey_apqns4keytype __user *uat)611{612	struct pkey_apqn *apqns = NULL;613	struct pkey_apqns4keytype kat;614	size_t nr_apqns, len;615	int rc;616 617	if (copy_from_user(&kat, uat, sizeof(kat)))618		return -EFAULT;619	nr_apqns = kat.apqn_entries;620	if (nr_apqns) {621		apqns = kmalloc_array(nr_apqns,622				      sizeof(struct pkey_apqn),623				      GFP_KERNEL);624		if (!apqns)625			return -ENOMEM;626	}627	rc = pkey_handler_apqns_for_keytype(kat.type,628					    kat.cur_mkvp, kat.alt_mkvp,629					    kat.flags, apqns, &nr_apqns);630	pr_debug("apqns_for_keytype()=%d\n", rc);631	if (rc && rc != -ENOSPC) {632		kfree(apqns);633		return rc;634	}635	if (!rc && kat.apqns) {636		if (nr_apqns > kat.apqn_entries) {637			kfree(apqns);638			return -EINVAL;639		}640		len = nr_apqns * sizeof(struct pkey_apqn);641		if (len) {642			if (copy_to_user(kat.apqns, apqns, len)) {643				kfree(apqns);644				return -EFAULT;645			}646		}647	}648	kat.apqn_entries = nr_apqns;649	if (copy_to_user(uat, &kat, sizeof(kat)))650		rc = -EFAULT;651	kfree(apqns);652 653	return rc;654}655 656static int pkey_ioctl_kblob2protk3(struct pkey_kblob2pkey3 __user *utp)657{658	u32 protkeylen = PROTKEYBLOBBUFSIZE;659	struct pkey_apqn *apqns = NULL;660	struct pkey_kblob2pkey3 ktp;661	u8 *kkey, *protkey;662	int rc;663 664	if (copy_from_user(&ktp, utp, sizeof(ktp)))665		return -EFAULT;666	apqns = _copy_apqns_from_user(ktp.apqns, ktp.apqn_entries);667	if (IS_ERR(apqns))668		return PTR_ERR(apqns);669	kkey = _copy_key_from_user(ktp.key, ktp.keylen);670	if (IS_ERR(kkey)) {671		kfree(apqns);672		return PTR_ERR(kkey);673	}674	protkey = kmalloc(protkeylen, GFP_KERNEL);675	if (!protkey) {676		kfree(apqns);677		kfree_sensitive(kkey);678		return -ENOMEM;679	}680	rc = key2protkey(apqns, ktp.apqn_entries, kkey, ktp.keylen,681			 protkey, &protkeylen, &ktp.pkeytype);682	pr_debug("key2protkey()=%d\n", rc);683	kfree(apqns);684	kfree_sensitive(kkey);685	if (rc) {686		kfree_sensitive(protkey);687		return rc;688	}689	if (ktp.pkey && ktp.pkeylen) {690		if (protkeylen > ktp.pkeylen) {691			kfree_sensitive(protkey);692			return -EINVAL;693		}694		if (copy_to_user(ktp.pkey, protkey, protkeylen)) {695			kfree_sensitive(protkey);696			return -EFAULT;697		}698	}699	kfree_sensitive(protkey);700	ktp.pkeylen = protkeylen;701	if (copy_to_user(utp, &ktp, sizeof(ktp)))702		return -EFAULT;703 704	return 0;705}706 707static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,708				unsigned long arg)709{710	int rc;711 712	switch (cmd) {713	case PKEY_GENSECK:714		rc = pkey_ioctl_genseck((struct pkey_genseck __user *)arg);715		break;716	case PKEY_CLR2SECK:717		rc = pkey_ioctl_clr2seck((struct pkey_clr2seck __user *)arg);718		break;719	case PKEY_SEC2PROTK:720		rc = pkey_ioctl_sec2protk((struct pkey_sec2protk __user *)arg);721		break;722	case PKEY_CLR2PROTK:723		rc = pkey_ioctl_clr2protk((struct pkey_clr2protk __user *)arg);724		break;725	case PKEY_FINDCARD:726		rc = pkey_ioctl_findcard((struct pkey_findcard __user *)arg);727		break;728	case PKEY_SKEY2PKEY:729		rc = pkey_ioctl_skey2pkey((struct pkey_skey2pkey __user *)arg);730		break;731	case PKEY_VERIFYKEY:732		rc = pkey_ioctl_verifykey((struct pkey_verifykey __user *)arg);733		break;734	case PKEY_GENPROTK:735		rc = pkey_ioctl_genprotk((struct pkey_genprotk __user *)arg);736		break;737	case PKEY_VERIFYPROTK:738		rc = pkey_ioctl_verifyprotk((struct pkey_verifyprotk __user *)arg);739		break;740	case PKEY_KBLOB2PROTK:741		rc = pkey_ioctl_kblob2protk((struct pkey_kblob2pkey __user *)arg);742		break;743	case PKEY_GENSECK2:744		rc = pkey_ioctl_genseck2((struct pkey_genseck2 __user *)arg);745		break;746	case PKEY_CLR2SECK2:747		rc = pkey_ioctl_clr2seck2((struct pkey_clr2seck2 __user *)arg);748		break;749	case PKEY_VERIFYKEY2:750		rc = pkey_ioctl_verifykey2((struct pkey_verifykey2 __user *)arg);751		break;752	case PKEY_KBLOB2PROTK2:753		rc = pkey_ioctl_kblob2protk2((struct pkey_kblob2pkey2 __user *)arg);754		break;755	case PKEY_APQNS4K:756		rc = pkey_ioctl_apqns4k((struct pkey_apqns4key __user *)arg);757		break;758	case PKEY_APQNS4KT:759		rc = pkey_ioctl_apqns4kt((struct pkey_apqns4keytype __user *)arg);760		break;761	case PKEY_KBLOB2PROTK3:762		rc = pkey_ioctl_kblob2protk3((struct pkey_kblob2pkey3 __user *)arg);763		break;764	default:765		/* unknown/unsupported ioctl cmd */766		return -ENOTTY;767	}768 769	return rc;770}771 772/*773 * File io operations774 */775 776static const struct file_operations pkey_fops = {777	.owner		= THIS_MODULE,778	.open		= nonseekable_open,779	.unlocked_ioctl = pkey_unlocked_ioctl,780};781 782static struct miscdevice pkey_dev = {783	.name	= "pkey",784	.minor	= MISC_DYNAMIC_MINOR,785	.mode	= 0666,786	.fops	= &pkey_fops,787	.groups = pkey_attr_groups,788};789 790int __init pkey_api_init(void)791{792	/* register as a misc device */793	return misc_register(&pkey_dev);794}795 796void __exit pkey_api_exit(void)797{798	misc_deregister(&pkey_dev);799}800