From nobody Sun Feb 8 15:59:26 2026 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 72D933101DA; Thu, 15 Jan 2026 10:05:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471539; cv=none; b=dgoQnAHLk823L0CWaNgKRD5RB9r1jIFjuBG4GpDZwVY+lfS/EGtQqtlsTLU2bzmA5aPhpv3WzjQo2cnPtCQE8hP+qZbFpcme7iNHOuFIJnt5fclI2PD4t0HgubnexVSb9SYZ0kj1mz/xl3vsRc1WWDbOrBSriyuB4UjXQ//20VU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471539; c=relaxed/simple; bh=9/aOACvgpfwKH4Du31wucJqb2l0ngyiYIuD/ULhncVw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sdQDcTTPEcnPBFe1BuEVbHlf1X91meFWHjKIxRfI2GXBMVNghBFwfDhIYeHXUgXnCz7rjQLcKVdOtZDC+9kX6xNtmrjdTblExwSDk12C8XDON0P1MpMqeRZ+ywdFFOEmd7sqE187WKbTYk2eompE/WkfEqj3iNW8JKjXQ7f7SU4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=mRJMnPnX; arc=none smtp.client-ip=148.163.156.1 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="mRJMnPnX" Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60F8e203014465; Thu, 15 Jan 2026 10:05:18 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=zRuVMP8fy62QWWddd DjnySGr6oOB4PJyRbIstZEBTFU=; b=mRJMnPnXClg67FfikZge7cCwuZ3QC+Psd n44YiqSbZriOekDhslfjjntxhZZCXKXun6y/M9C4fBfwEFw3vUQoppmzYuOuFgMK 1o2NOmrrnGYeQYZ64o3JTegzM7kdad8R+jcp4XW/LTLedDxEhXZo7Etu77yZOx5z RCduFCFMDdkQ/ICQxQC2lKCHr7hIb1fpbrcB4j6kihBgoj3A45hZWTvACtS8gtr+ gPMMAFNfami8iPq8l6fbx4nqiFnB3bgePnH5CoV+hgmrpCvbRVSn7twJHSu9jTDU 0PeFsud6PTwMMz3B/SwRZlygffD68TInNxnjhHK1kBT3fUxD/jneg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkeeq5y0e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:17 +0000 (GMT) Received: from m0353729.ppops.net (m0353729.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60FA5HNF024017; Thu, 15 Jan 2026 10:05:17 GMT Received: from ppma12.dal12v.mail.ibm.com (dc.9e.1632.ip4.static.sl-reverse.com [50.22.158.220]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkeeq5y0b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:17 +0000 (GMT) Received: from pps.filterd (ppma12.dal12v.mail.ibm.com [127.0.0.1]) by ppma12.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60F7iFJW002505; Thu, 15 Jan 2026 10:05:16 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bm13sygyx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:15 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60FA5C4e43450738 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Jan 2026 10:05:12 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 48E582006A; Thu, 15 Jan 2026 10:05:12 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D24572004F; Thu, 15 Jan 2026 10:05:08 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.65]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 15 Jan 2026 10:05:08 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v4 1/6] pseries/plpks: fix kernel-doc comment inconsistencies Date: Thu, 15 Jan 2026 15:34:59 +0530 Message-ID: <20260115100504.488665-2-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115100504.488665-1-ssrish@linux.ibm.com> References: <20260115100504.488665-1-ssrish@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=DI6CIiNb c=1 sm=1 tr=0 ts=6968bbdd cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=_jD9v-G-JNOk7KggL9IA:9 a=tQW_-zY1P7yUjf7c:21 X-Proofpoint-GUID: KDyU6kMoYsJKEX__IZSYvTVXRk2e4eUe X-Proofpoint-ORIG-GUID: HYOAVPHwS7kfVjS1-4JY3mmnr6VbVOFN X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTE1MDA2OSBTYWx0ZWRfX38rucgwGeHpX pN/wYYMCkYQ00jeEvneUoKwT8lkLINPNI8tf9p0VOhKNxCM4FF6NcwtxNbcrHzbVnnPvMqKAj4G K5r7EowZCVT/P7Oyh1q38h4SEaeBc12lQEXKy9dA1uoU7nxirRX3w0PDQKjVGdgFgudtvjMgBBg 7hW3cbuIOhxiHqGzgnYchYIohnSJSEK6TtYqhNVMqskVTe8P96a/SIngzNpXt1x8v8hxWFRz5u+ Jy43DBNN/IvpX90Yq6UZlIzG+NZat/bw711exx33T2bfq8pH5VjoY5jLAH3aQUXUTKvfHKmKFXA F0uVH3Diejfa/cyqIqcTW7O4zalyTID80G29Giw8NdtmEA1GvekgIQUKO1rvDBVnwz34OBrtvDi jnhkPFkcgfocbIa3Ss+y6nhiNpKHtPkYjKTfU1SAkVDOHgNAJDZWf29ybM3SF+uvDOtSX73d8Cu O6mJzVydbpNZy7eNVgg== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-15_03,2026-01-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 adultscore=0 malwarescore=0 spamscore=0 suspectscore=0 phishscore=0 impostorscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601150069 Content-Type: text/plain; charset="utf-8" Fix issues with comments for all the applicable functions to be consistent with kernel-doc format. Move them before the function definition as opposed to the function prototype. Signed-off-by: Srish Srinivasan Reviewed-by: Nayna Jain --- arch/powerpc/include/asm/plpks.h | 77 ------ arch/powerpc/platforms/pseries/plpks.c | 328 ++++++++++++++++++++++++- 2 files changed, 318 insertions(+), 87 deletions(-) diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index 7a84069759b0..f303922bf622 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -67,122 +67,45 @@ struct plpks_var_name_list { struct plpks_var_name varlist[]; }; =20 -/** - * Updates the authenticated variable. It expects NULL as the component. - */ int plpks_signed_update_var(struct plpks_var *var, u64 flags); =20 -/** - * Writes the specified var and its data to PKS. - * Any caller of PKS driver should present a valid component type for - * their variable. - */ int plpks_write_var(struct plpks_var var); =20 -/** - * Removes the specified var and its data from PKS. - */ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname); =20 -/** - * Returns the data for the specified os variable. - * - * Caller must allocate a buffer in var->data with length in var->datalen. - * If no buffer is provided, var->datalen will be populated with the objec= t's - * size. - */ int plpks_read_os_var(struct plpks_var *var); =20 -/** - * Returns the data for the specified firmware variable. - * - * Caller must allocate a buffer in var->data with length in var->datalen. - * If no buffer is provided, var->datalen will be populated with the objec= t's - * size. - */ int plpks_read_fw_var(struct plpks_var *var); =20 -/** - * Returns the data for the specified bootloader variable. - * - * Caller must allocate a buffer in var->data with length in var->datalen. - * If no buffer is provided, var->datalen will be populated with the objec= t's - * size. - */ int plpks_read_bootloader_var(struct plpks_var *var); =20 -/** - * Returns if PKS is available on this LPAR. - */ bool plpks_is_available(void); =20 -/** - * Returns version of the Platform KeyStore. - */ u8 plpks_get_version(void); =20 -/** - * Returns hypervisor storage overhead per object, not including the size = of - * the object or label. Only valid for config version >=3D 2 - */ u16 plpks_get_objoverhead(void); =20 -/** - * Returns maximum password size. Must be >=3D 32 bytes - */ u16 plpks_get_maxpwsize(void); =20 -/** - * Returns maximum object size supported by Platform KeyStore. - */ u16 plpks_get_maxobjectsize(void); =20 -/** - * Returns maximum object label size supported by Platform KeyStore. - */ u16 plpks_get_maxobjectlabelsize(void); =20 -/** - * Returns total size of the configured Platform KeyStore. - */ u32 plpks_get_totalsize(void); =20 -/** - * Returns used space from the total size of the Platform KeyStore. - */ u32 plpks_get_usedspace(void); =20 -/** - * Returns bitmask of policies supported by the hypervisor. - */ u32 plpks_get_supportedpolicies(void); =20 -/** - * Returns maximum byte size of a single object supported by the hyperviso= r. - * Only valid for config version >=3D 3 - */ u32 plpks_get_maxlargeobjectsize(void); =20 -/** - * Returns bitmask of signature algorithms supported for signed updates. - * Only valid for config version >=3D 3 - */ u64 plpks_get_signedupdatealgorithms(void); =20 -/** - * Returns the length of the PLPKS password in bytes. - */ u16 plpks_get_passwordlen(void); =20 -/** - * Called in early init to retrieve and clear the PLPKS password from the = DT. - */ void plpks_early_init_devtree(void); =20 -/** - * Populates the FDT with the PLPKS password to prepare for kexec. - */ int plpks_populate_fdt(void *fdt); #else // CONFIG_PSERIES_PLPKS static inline bool plpks_is_available(void) { return false; } diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platform= s/pseries/plpks.c index b1667ed05f98..03722fabf9c3 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -312,40 +312,107 @@ static int _plpks_get_config(void) return rc; } =20 +/** + * plpks_get_version() - Get the version of the PLPKS config structure. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the PLPKS config structure version and saves it in a file local s= tatic + * version variable. + * + * Returns: On success the saved PLPKS config structure version is returne= d, 0 + * if not. + */ u8 plpks_get_version(void) { return version; } =20 +/** + * plpks_get_objoverhead() - Get the hypervisor storage overhead per objec= t. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the per object hypervisor storage overhead in bytes into the local + * static objoverhead variable, excluding the size of the object or the la= bel. + * This value can be treated as valid only when the PLPKS config structure + * version >=3D 2. + * + * Returns: If PLPKS config structure version >=3D 2 then the storage over= head is + * returned, 0 otherwise. + */ u16 plpks_get_objoverhead(void) { return objoverhead; } =20 +/** + * plpks_get_maxpwsize() - Get the maximum password size. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum password size and checks if it is 32 bytes at the lea= st + * before storing it in the local static maxpwsize variable. + * + * Returns: On success the maximum password size is returned, 0 if not. + */ u16 plpks_get_maxpwsize(void) { return maxpwsize; } =20 +/** + * plpks_get_maxobjectsize() - Get the maximum object size supported by the + * PLPKS. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum object size into the file local static maxobjsize var= iable. + * + * Returns: On success the maximum object size is returned, 0 if not. + */ u16 plpks_get_maxobjectsize(void) { return maxobjsize; } =20 +/** + * plpks_get_maxobjectlabelsize() - Get the maximum object label size supp= orted + * by the PLPKS. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum object label size into the local static maxobjlabelsi= ze + * variable. + * + * Returns: On success the maximum object label size is returned, 0 if not. + */ u16 plpks_get_maxobjectlabelsize(void) { return maxobjlabelsize; } =20 +/** + * plpks_get_totalsize() - Get the total size of the PLPKS that is configu= red. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the total size of the PLPKS that is configured for the LPAR into = the + * file local static totalsize variable. + * + * Returns: On success the total size of the PLPKS configured is returned,= 0 if + * not. + */ u32 plpks_get_totalsize(void) { return totalsize; } =20 +/** + * plpks_get_usedspace() - Get the used space from the total size of the P= LPKS. + * + * Invoke the H_PKS_GET_CONFIG HCALL to refresh the latest value for the u= sed + * space as this keeps changing with the creation and removal of objects i= n the + * PLPKS. + * + * Returns: On success the used space is returned, 0 if not. + */ u32 plpks_get_usedspace(void) { - // Unlike other config values, usedspace regularly changes as objects - // are updated, so we need to refresh. int rc =3D _plpks_get_config(); if (rc) { pr_err("Couldn't get config, rc: %d\n", rc); @@ -354,26 +421,84 @@ u32 plpks_get_usedspace(void) return usedspace; } =20 +/** + * plpks_get_supportedpolicies() - Get a bitmask of the policies supported= by + * the hypervisor. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads a bitmask of the policies supported by the hypervisor into the fi= le + * local static supportedpolicies variable. + * + * Returns: On success the bitmask of the policies supported by the hyperv= isor + * are returned, 0 if not. + */ u32 plpks_get_supportedpolicies(void) { return supportedpolicies; } =20 +/** + * plpks_get_maxlargeobjectsize() - Get the maximum object size supported = for + * PLPKS config structure version >=3D 3 + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum object size into the local static maxlargeobjectsize + * variable for PLPKS config structure version >=3D 3. This was introduced + * starting with PLPKS config structure version 3 to allow for objects of + * size >=3D 64K. + * + * Returns: If PLPKS config structure version >=3D 3 then the new maximum = object + * size is returned, 0 if not. + */ u32 plpks_get_maxlargeobjectsize(void) { return maxlargeobjectsize; } =20 +/** + * plpks_get_signedupdatealgorithms() - Get a bitmask of the signature + * algorithms supported for signed updates. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads a bitmask of the signature algorithms supported for signed update= s into + * the file local static signedupdatealgorithms variable. This is valid on= ly + * when the PLPKS config structure version >=3D 3. + * + * Returns: On success the bitmask of the signature algorithms supported f= or + * signed updates is returned, 0 if not. + */ u64 plpks_get_signedupdatealgorithms(void) { return signedupdatealgorithms; } =20 +/** + * plpks_get_passwordlen() - Get the length of the PLPKS password in bytes. + * + * The H_PKS_GEN_PASSWORD HCALL makes the hypervisor generate a random pas= sword + * for the specified consumer, apply that password to the PLPKS and return= it to + * the caller. In this process, the password length for the OS consumer is + * stored in the local static ospasswordlength variable. + * + * Returns: On success the password length for the OS consumer in bytes is + * returned, 0 if not. + */ u16 plpks_get_passwordlen(void) { return ospasswordlength; } =20 +/** + * plpks_is_available() - Get the PLPKS availability status for the LPAR. + * + * The availability of PLPKS is inferred based upon the successful executi= on of + * the H_PKS_GET_CONFIG HCALL provided the firmware supports this feature.= The + * H_PKS_GET_CONFIG HCALL reads the configuration and status information r= elated + * to the PLPKS. The configuration structure provides a version number to = inform + * the caller of the supported features. + * + * Returns: true is returned if PLPKS is available, false if not. + */ bool plpks_is_available(void) { int rc; @@ -425,6 +550,35 @@ static int plpks_confirm_object_flushed(struct label *= label, return pseries_status_to_err(rc); } =20 +/** + * plpks_signed_update_var() - Update the specified authenticated variable. + * @var: authenticated variable to be updated + * @flags: signed update request operation flags + * + * The H_PKS_SIGNED_UPDATE HCALL performs a signed update to an object in = the + * PLPKS. The object must have the signed update policy flag set. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid or unsupported policy declaration + * if invalid signed update flags + * if invalid input data parameter + * if invalid input data len parameter + * if invalid continue token parameter + * -EPERM if access is denied + * -ENOMEM if there is inadequate memory to perform the operation + * -EBUSY if unable to handle the request or long running operation + * initiated, retry later + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_signed_update_var(struct plpks_var *var, u64 flags) { unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] =3D {0}; @@ -481,6 +635,33 @@ int plpks_signed_update_var(struct plpks_var *var, u64= flags) return rc; } =20 +/** + * plpks_write_var() - Write the specified variable and its data to PLPKS. + * @var: variable to be written into the PLPKS + * + * The H_PKS_WRITE_OBJECT HCALL writes an object into the PLPKS. The calle= r must + * provide a valid component type for the variable, and the signed update = policy + * flag must not be set. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid or unsupported policy declaration + * if invalid input data parameter + * if invalid input data len parameter + * -EPERM if access is denied + * -ENOMEM if unable to store the requested object in the space available + * -EBUSY if unable to handle the request + * -EEXIST if the object label already exists + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_write_var(struct plpks_var var) { unsigned long retbuf[PLPAR_HCALL_BUFSIZE] =3D { 0 }; @@ -520,6 +701,30 @@ int plpks_write_var(struct plpks_var var) return rc; } =20 +/** + * plpks_remove_var() - Remove the specified variable and its data from PL= PKS. + * @component: metadata prefix in the object label metadata structure + * @varos: metadata OS flags in the object label metadata structure + * @vname: object label for the object that needs to be removed + * + * The H_PKS_REMOVE_OBJECT HCALL removes an object from the PLPKS. The rem= oval + * is independent of the policy bits that are set. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vnam= e) { unsigned long retbuf[PLPAR_HCALL_BUFSIZE] =3D { 0 }; @@ -619,21 +824,119 @@ static int plpks_read_var(u8 consumer, struct plpks_= var *var) return rc; } =20 +/** + * plpks_read_os_var() - Fetch the data for the specified variable that is + * owned by the OS consumer. + * @var: variable to be read from the PLPKS + * + * The consumer or the owner of the object is the os kernel. The + * H_PKS_READ_OBJECT HCALL reads an object from the PLPKS. The caller must + * allocate the buffer var->data and specify the length for this buffer in + * var->datalen. If no buffer is provided, var->datalen will be populated = with + * the requested object's size. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid output data parameter + * if invalid output data len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EFBIG if the requested object couldn't be + * stored in the buffer provided + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_read_os_var(struct plpks_var *var) { return plpks_read_var(PLPKS_OS_OWNER, var); } =20 +/** + * plpks_read_fw_var() - Fetch the data for the specified variable that is + * owned by the firmware consumer. + * @var: variable to be read from the PLPKS + * + * The consumer or the owner of the object is the firmware. The + * H_PKS_READ_OBJECT HCALL reads an object from the PLPKS. The caller must + * allocate the buffer var->data and specify the length for this buffer in + * var->datalen. If no buffer is provided, var->datalen will be populated = with + * the requested object's size. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid output data parameter + * if invalid output data len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EFBIG if the requested object couldn't be + * stored in the buffer provided + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_read_fw_var(struct plpks_var *var) { return plpks_read_var(PLPKS_FW_OWNER, var); } =20 +/** + * plpks_read_bootloader_var() - Fetch the data for the specified variable + * owned by the bootloader consumer. + * @var: variable to be read from the PLPKS + * + * The consumer or the owner of the object is the bootloader. The + * H_PKS_READ_OBJECT HCALL reads an object from the PLPKS. The caller must + * allocate the buffer var->data and specify the length for this buffer in + * var->datalen. If no buffer is provided, var->datalen will be populated = with + * the requested object's size. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid output data parameter + * if invalid output data len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EFBIG if the requested object couldn't be + * stored in the buffer provided + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_read_bootloader_var(struct plpks_var *var) { return plpks_read_var(PLPKS_BOOTLOADER_OWNER, var); } =20 +/** + * plpks_populate_fdt(): Populates the FDT with the PLPKS password to prep= are + * for kexec. + * @fdt: pointer to the device tree blob + * + * Upon confirming the existence of the chosen node, invoke fdt_setprop to + * populate the device tree with the PLPKS password in order to prepare for + * kexec. + * + * Returns: On success 0 is returned, a negative value if not. + */ int plpks_populate_fdt(void *fdt) { int chosen_offset =3D fdt_path_offset(fdt, "/chosen"); @@ -647,14 +950,19 @@ int plpks_populate_fdt(void *fdt) return fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw", ospassword, ospass= wordlength); } =20 -// Once a password is registered with the hypervisor it cannot be cleared = without -// rebooting the LPAR, so to keep using the PLPKS across kexec boots we ne= ed to -// recover the previous password from the FDT. -// -// There are a few challenges here. We don't want the password to be visi= ble to -// users, so we need to clear it from the FDT. This has to be done in ear= ly boot. -// Clearing it from the FDT would make the FDT's checksum invalid, so we h= ave to -// manually cause the checksum to be recalculated. +/** + * plpks_early_init_devtree() - Retrieves and clears the PLPKS password fr= om the + * DT in early init. + * + * Once a password is registered with the hypervisor it cannot be cleared + * without rebooting the LPAR, so to keep using the PLPKS across kexec boo= ts we + * need to recover the previous password from the FDT. + * + * There are a few challenges here. We don't want the password to be visi= ble to + * users, so we need to clear it from the FDT. This has to be done in ear= ly + * boot. Clearing it from the FDT would make the FDT's checksum invalid, s= o we + * have to manually cause the checksum to be recalculated. + */ void __init plpks_early_init_devtree(void) { void *fdt =3D initial_boot_params; --=20 2.47.3 From nobody Sun Feb 8 15:59:26 2026 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24247343208; Thu, 15 Jan 2026 10:05:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471543; cv=none; b=tj3LmufsyhGXhgORcgznhosXCU5sS5lvANtV3qv5K2N9Qpo7sQ5B7mY6FbrBLNaRHyX7I+MeqyflZi+HX0bj8KG1etgv+fy3pqwu6oDqTXomB2UZTGW/lp2yYSZyePH5oihl3boqUheECXfza/olV9G/uRwvLVkgy7ik/iObBdk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471543; c=relaxed/simple; bh=6G58g9crEgE57aep4YmCSRDvwVu4Es3NNVhZc8cDP7Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q13aHYJnYxdO8xab129LQlnFtrUh4E+MaQUhDQuAaf43Ay+U/aHZRhQAGuFTt+x0ItTyDIn7s0H2TI+T5wl+WghCWGidthSUs94YR3H7e+6hPa6wuDWxEJw3DwGWN/5ShIVmhodtXG1yvINfhEyn0h8F7FxF9euKd5j9DROJFxM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=DYPewoT+; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="DYPewoT+" Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60EKulS4012388; Thu, 15 Jan 2026 10:05:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=yc4kRWNOeDA46cfmO ijRYwTfYPM4pX1pzJgtVu4tPVs=; b=DYPewoT+6O1FKArjaPkJQp1FjAolanWi1 oiuST1dAwsm3ja/6Z6O0gtBinAlHNVLwykNq7k96MIXklDkwXBr7HCTLYLT0CD2V dElZtSkjflBwDyPRAffCQdxbk4LFC6OsfZd1v7AdsegWGVum3DXSfu1fErc+0XWA Jc3hrchAyR2dHowNE+znrqcevnoHqK25aBgiYhn7CAW1jHf3JfQ7bNIfb0Q4ta9V 7PZxwk9amliscmpvXGfY6PerONpJn1mkUF222BrUhp/fPJUU7PEBnOHReRxc39MM 4mMX+S9nV/UrhFzgav6KHzEjO+HyM55nU0nLOpefXGv5KypFryTdQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkedt5f7e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:21 +0000 (GMT) Received: from m0360072.ppops.net (m0360072.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60FA0SLE003167; Thu, 15 Jan 2026 10:05:20 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkedt5f7c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:20 +0000 (GMT) Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60F80olw025866; Thu, 15 Jan 2026 10:05:20 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bm2kkqbct-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:20 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60FA5Ge850266488 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Jan 2026 10:05:16 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0511C2004F; Thu, 15 Jan 2026 10:05:16 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B76352005A; Thu, 15 Jan 2026 10:05:12 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.65]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 15 Jan 2026 10:05:12 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v4 2/6] powerpc/pseries: move the PLPKS config inside its own sysfs directory Date: Thu, 15 Jan 2026 15:35:00 +0530 Message-ID: <20260115100504.488665-3-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115100504.488665-1-ssrish@linux.ibm.com> References: <20260115100504.488665-1-ssrish@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTE1MDA2OSBTYWx0ZWRfX4OWAFN/szGeI +2gTmB83ulRE5fn+ikkAcEhIGXqgV81YKMqM186se7QCn3fEmgnSuMdo92Ca2yk+191sn4QRPbO JIUj24kJ4/8BM/C7T4xe2fKAyk27Dwwemsghc25RUIjcrVsjF44VrZkZjPQ20M4dOGB/swJ4dpg z8Q9+vztFfmTlbusRP5DzfUeplz6pGTI34ziLrzXNl5JZAW06XhdVDzmkOb0ioj/M5pHEQU6Gs6 TmfueG70zDfh4mgS+2H2qu7PH8K0/i23WNJXHvpLGdx1QMRuReShXrt7hLgKVONEtvWsIWkcRvd cdmamE1XgO8i20OA4DqASyED3XHlsZhkPzqD9E7lWoUCQQ4bqsavJD67jmxuB58hUcVFWWLCrxj /lGc0dX77CzRS9vT7+jCzekdfGVJQX5ahVXsMHwhmmrGPifaX/AZKPKbA5NJXAVEA6vRAlW8dqk M/MuvUW03mWx/LF1T2A== X-Proofpoint-GUID: L34HcRkofm-QSP5s1nLybeww3ghDDaWe X-Authority-Analysis: v=2.4 cv=WLJyn3sR c=1 sm=1 tr=0 ts=6968bbe1 cx=c_pps a=3Bg1Hr4SwmMryq2xdFQyZA==:117 a=3Bg1Hr4SwmMryq2xdFQyZA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=mWGr4ncSMiNchjaCnzgA:9 X-Proofpoint-ORIG-GUID: NWSmFGAevClK3wgK40NR6qQFYX3Mu2rU X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-15_03,2026-01-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 adultscore=0 malwarescore=0 phishscore=0 suspectscore=0 priorityscore=1501 bulkscore=0 clxscore=1015 impostorscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601150069 Content-Type: text/plain; charset="utf-8" The /sys/firmware/secvar/config directory represents Power LPAR Platform KeyStore (PLPKS) configuration properties such as max_object_size, signed_ update_algorithms, supported_policies, total_size, used_space, and version. These attributes describe the PLPKS, and not the secure boot variables (secvars). Create /sys/firmware/plpks directory and move the PLPKS config inside this directory. For backwards compatibility, create a soft link from the secvar sysfs directory to this config and emit a warning stating that the older sysfs path has been deprecated. Separate out the plpks specific documentation from secvar. Signed-off-by: Srish Srinivasan Reviewed-by: Mimi Zohar Reviewed-by: Nayna Jain --- .../ABI/testing/sysfs-firmware-plpks | 50 ++++++++++ Documentation/ABI/testing/sysfs-secvar | 65 ------------- arch/powerpc/include/asm/plpks.h | 5 + arch/powerpc/include/asm/secvar.h | 1 - arch/powerpc/kernel/secvar-sysfs.c | 21 ++--- arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/plpks-secvar.c | 29 ------ arch/powerpc/platforms/pseries/plpks-sysfs.c | 94 +++++++++++++++++++ 8 files changed, 156 insertions(+), 111 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-firmware-plpks create mode 100644 arch/powerpc/platforms/pseries/plpks-sysfs.c diff --git a/Documentation/ABI/testing/sysfs-firmware-plpks b/Documentation= /ABI/testing/sysfs-firmware-plpks new file mode 100644 index 000000000000..af0353f34115 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-plpks @@ -0,0 +1,50 @@ +What: /sys/firmware/plpks/config +Date: February 2023 +Contact: Nayna Jain +Description: This optional directory contains read-only config attributes = as + defined by the PLPKS implementation. All data is in ASCII + format. + +What: /sys/firmware/plpks/config/version +Date: February 2023 +Contact: Nayna Jain +Description: Config version as reported by the hypervisor in ASCII decimal + format. + +What: /sys/firmware/plpks/config/max_object_size +Date: February 2023 +Contact: Nayna Jain +Description: Maximum allowed size of objects in the keystore in bytes, + represented in ASCII decimal format. + + This is not necessarily the same as the max size that can be + written to an update file as writes can contain more than + object data, you should use the size of the update file for + that purpose. + +What: /sys/firmware/plpks/config/total_size +Date: February 2023 +Contact: Nayna Jain +Description: Total size of the PLPKS in bytes, represented in ASCII decimal + format. + +What: /sys/firmware/plpks/config/used_space +Date: February 2023 +Contact: Nayna Jain +Description: Current space consumed by the key store, in bytes, represented + in ASCII decimal format. + +What: /sys/firmware/plpks/config/supported_policies +Date: February 2023 +Contact: Nayna Jain +Description: Bitmask of supported policy flags by the hypervisor, represen= ted + as an 8 byte hexadecimal ASCII string. Consult the hypervisor + documentation for what these flags are. + +What: /sys/firmware/plpks/config/signed_update_algorithms +Date: February 2023 +Contact: Nayna Jain +Description: Bitmask of flags indicating which algorithms the hypervisor + supports for signed update of objects, represented as a 16 byte + hexadecimal ASCII string. Consult the hypervisor documentation + for what these flags mean. diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/tes= ting/sysfs-secvar index 1016967a730f..c52a5fd15709 100644 --- a/Documentation/ABI/testing/sysfs-secvar +++ b/Documentation/ABI/testing/sysfs-secvar @@ -63,68 +63,3 @@ Contact: Nayna Jain Description: A write-only file that is used to submit the new value for the variable. The size of the file represents the maximum size of the variable data that can be written. - -What: /sys/firmware/secvar/config -Date: February 2023 -Contact: Nayna Jain -Description: This optional directory contains read-only config attributes = as - defined by the secure variable implementation. All data is in - ASCII format. The directory is only created if the backing - implementation provides variables to populate it, which at - present is only PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/version -Date: February 2023 -Contact: Nayna Jain -Description: Config version as reported by the hypervisor in ASCII decimal - format. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/max_object_size -Date: February 2023 -Contact: Nayna Jain -Description: Maximum allowed size of objects in the keystore in bytes, - represented in ASCII decimal format. - - This is not necessarily the same as the max size that can be - written to an update file as writes can contain more than - object data, you should use the size of the update file for - that purpose. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/total_size -Date: February 2023 -Contact: Nayna Jain -Description: Total size of the PLPKS in bytes, represented in ASCII decimal - format. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/used_space -Date: February 2023 -Contact: Nayna Jain -Description: Current space consumed by the key store, in bytes, represented - in ASCII decimal format. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/supported_policies -Date: February 2023 -Contact: Nayna Jain -Description: Bitmask of supported policy flags by the hypervisor, - represented as an 8 byte hexadecimal ASCII string. Consult the - hypervisor documentation for what these flags are. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/signed_update_algorithms -Date: February 2023 -Contact: Nayna Jain -Description: Bitmask of flags indicating which algorithms the hypervisor - supports for signed update of objects, represented as a 16 byte - hexadecimal ASCII string. Consult the hypervisor documentation - for what these flags mean. - - Currently only provided by PLPKS on the pseries platform. diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index f303922bf622..8829a13bfda0 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -13,6 +13,7 @@ =20 #include #include +#include =20 // Object policy flags from supported_policies #define PLPKS_OSSECBOOTAUDIT PPC_BIT32(1) // OS secure boot must be audit/= enforce @@ -107,11 +108,15 @@ u16 plpks_get_passwordlen(void); void plpks_early_init_devtree(void); =20 int plpks_populate_fdt(void *fdt); + +int plpks_config_create_softlink(struct kobject *from); #else // CONFIG_PSERIES_PLPKS static inline bool plpks_is_available(void) { return false; } static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); } static inline void plpks_early_init_devtree(void) { } static inline int plpks_populate_fdt(void *fdt) { BUILD_BUG(); } +static inline int plpks_config_create_softlink(struct kobject *from) + { return 0; } #endif // CONFIG_PSERIES_PLPKS =20 #endif // _ASM_POWERPC_PLPKS_H diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/s= ecvar.h index 4828e0ab7e3c..fd5006307f2a 100644 --- a/arch/powerpc/include/asm/secvar.h +++ b/arch/powerpc/include/asm/secvar.h @@ -20,7 +20,6 @@ struct secvar_operations { int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size); ssize_t (*format)(char *buf, size_t bufsize); int (*max_size)(u64 *max_size); - const struct attribute **config_attrs; =20 // NULL-terminated array of fixed variable names // Only used if get_next() isn't provided diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secva= r-sysfs.c index ec900bce0257..4111b21962eb 100644 --- a/arch/powerpc/kernel/secvar-sysfs.c +++ b/arch/powerpc/kernel/secvar-sysfs.c @@ -12,6 +12,7 @@ #include #include #include +#include =20 #define NAME_MAX_SIZE 1024 =20 @@ -145,19 +146,6 @@ static __init int update_kobj_size(void) return 0; } =20 -static __init int secvar_sysfs_config(struct kobject *kobj) -{ - struct attribute_group config_group =3D { - .name =3D "config", - .attrs =3D (struct attribute **)secvar_ops->config_attrs, - }; - - if (secvar_ops->config_attrs) - return sysfs_create_group(kobj, &config_group); - - return 0; -} - static __init int add_var(const char *name) { struct kobject *kobj; @@ -260,12 +248,15 @@ static __init int secvar_sysfs_init(void) goto err; } =20 - rc =3D secvar_sysfs_config(secvar_kobj); + rc =3D plpks_config_create_softlink(secvar_kobj); if (rc) { - pr_err("Failed to create config directory\n"); + pr_err("Failed to create softlink to PLPKS config directory"); goto err; } =20 + pr_info("/sys/firmware/secvar/config is now deprecated.\n"); + pr_info("Will be removed in future versions.\n"); + if (secvar_ops->get_next) rc =3D secvar_sysfs_load(); else diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platfor= ms/pseries/Makefile index 931ebaa474c8..3ced289a675b 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_PAPR_SCM) +=3D papr_scm.o obj-$(CONFIG_PPC_SPLPAR) +=3D vphn.o obj-$(CONFIG_PPC_SVM) +=3D svm.o obj-$(CONFIG_FA_DUMP) +=3D rtas-fadump.o -obj-$(CONFIG_PSERIES_PLPKS) +=3D plpks.o +obj-$(CONFIG_PSERIES_PLPKS) +=3D plpks.o plpks-sysfs.o obj-$(CONFIG_PPC_SECURE_BOOT) +=3D plpks-secvar.o obj-$(CONFIG_PSERIES_PLPKS_SED) +=3D plpks_sed_ops.o obj-$(CONFIG_SUSPEND) +=3D suspend.o diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/p= latforms/pseries/plpks-secvar.c index f9e9cc40c9d0..a50ff6943d80 100644 --- a/arch/powerpc/platforms/pseries/plpks-secvar.c +++ b/arch/powerpc/platforms/pseries/plpks-secvar.c @@ -20,33 +20,6 @@ #include #include =20 -// Config attributes for sysfs -#define PLPKS_CONFIG_ATTR(name, fmt, func) \ - static ssize_t name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ - char *buf) \ - { \ - return sysfs_emit(buf, fmt, func()); \ - } \ - static struct kobj_attribute attr_##name =3D __ATTR_RO(name) - -PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version); -PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize); -PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize); -PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace); -PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicie= s); -PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedu= pdatealgorithms); - -static const struct attribute *config_attrs[] =3D { - &attr_version.attr, - &attr_max_object_size.attr, - &attr_total_size.attr, - &attr_used_space.attr, - &attr_supported_policies.attr, - &attr_signed_update_algorithms.attr, - NULL, -}; - static u32 get_policy(const char *name) { if ((strcmp(name, "db") =3D=3D 0) || @@ -225,7 +198,6 @@ static const struct secvar_operations plpks_secvar_ops_= static =3D { .set =3D plpks_set_variable, .format =3D plpks_secvar_format, .max_size =3D plpks_max_size, - .config_attrs =3D config_attrs, .var_names =3D plpks_var_names_static, }; =20 @@ -234,7 +206,6 @@ static const struct secvar_operations plpks_secvar_ops_= dynamic =3D { .set =3D plpks_set_variable, .format =3D plpks_secvar_format, .max_size =3D plpks_max_size, - .config_attrs =3D config_attrs, .var_names =3D plpks_var_names_dynamic, }; =20 diff --git a/arch/powerpc/platforms/pseries/plpks-sysfs.c b/arch/powerpc/pl= atforms/pseries/plpks-sysfs.c new file mode 100644 index 000000000000..01d526185783 --- /dev/null +++ b/arch/powerpc/platforms/pseries/plpks-sysfs.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 IBM Corporation, Srish Srinivasan + * + * This code exposes PLPKS config to user via sysfs + */ + +#define pr_fmt(fmt) "plpks-sysfs: "fmt + +#include +#include +#include +#include +#include + +/* config attributes for sysfs */ +#define PLPKS_CONFIG_ATTR(name, fmt, func) \ + static ssize_t name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *buf) \ + { \ + return sysfs_emit(buf, fmt, func()); \ + } \ + static struct kobj_attribute attr_##name =3D __ATTR_RO(name) + +PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version); +PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize); +PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize); +PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace); +PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicie= s); +PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", + plpks_get_signedupdatealgorithms); + +static const struct attribute *config_attrs[] =3D { + &attr_version.attr, + &attr_max_object_size.attr, + &attr_total_size.attr, + &attr_used_space.attr, + &attr_supported_policies.attr, + &attr_signed_update_algorithms.attr, + NULL, +}; + +static struct kobject *plpks_kobj, *plpks_config_kobj; + +int plpks_config_create_softlink(struct kobject *from) +{ + if (!plpks_config_kobj) + return -EINVAL; + return sysfs_create_link(from, plpks_config_kobj, "config"); +} + +static __init int plpks_sysfs_config(struct kobject *kobj) +{ + struct attribute_group config_group =3D { + .name =3D NULL, + .attrs =3D (struct attribute **)config_attrs, + }; + + return sysfs_create_group(kobj, &config_group); +} + +static __init int plpks_sysfs_init(void) +{ + int rc; + + if (!plpks_is_available()) + return -ENODEV; + + plpks_kobj =3D kobject_create_and_add("plpks", firmware_kobj); + if (!plpks_kobj) { + pr_err("Failed to create plpks kobj\n"); + return -ENOMEM; + } + + plpks_config_kobj =3D kobject_create_and_add("config", plpks_kobj); + if (!plpks_config_kobj) { + pr_err("Failed to create plpks config kobj\n"); + kobject_put(plpks_kobj); + return -ENOMEM; + } + + rc =3D plpks_sysfs_config(plpks_config_kobj); + if (rc) { + pr_err("Failed to create attribute group for plpks config\n"); + kobject_put(plpks_config_kobj); + kobject_put(plpks_kobj); + return rc; + } + + return 0; +} + +machine_subsys_initcall(pseries, plpks_sysfs_init); --=20 2.47.3 From nobody Sun Feb 8 15:59:26 2026 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6342F13B7AE; Thu, 15 Jan 2026 10:05:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471540; cv=none; b=ehDCj7tos4QosuO/tcQK5OZPDDCR0+g9e1ref5b0x5c+ZXXq7OStXmOfuxAULV9/oY9cGKMplt5SoKPkrfstAVb8QPHEAPxw/SvgUSzykDHaEzHwFeRgGsfAALcNDy3K+wDYJ7fvRFTXHdr54vgyskoNJuewvCUq2MJmz3SWg54= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471540; c=relaxed/simple; bh=o+HNAoXe5dmj0ZXKdP/IxAcP+iQNOhjsPp/2eXaFA04=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LSkEOklKy/K1r1DerQMsafBs6H+gyaYQDXadsg3DXuafcfD8vqZoF2P9bMz3sspdsfj08vRZuZyP6x98oRezWOE1V4ey/AHFX+6F2GW6IfxES3WwWL7t4Glqkt20CyOB42GnIomiKl7OnJ9wUftVDVBemq0ezYg573hK6TubOqM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=kYTAEQBU; arc=none smtp.client-ip=148.163.156.1 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="kYTAEQBU" Received: from pps.filterd (m0360083.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60F9L1oc026309; Thu, 15 Jan 2026 10:05:25 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=E9q9MwLx+QxB8gPZo WTVfIF6m08d+i7ReyBrKfC6Vc8=; b=kYTAEQBUPxNFx8H43mN1u4tQene/B3Ya/ VFVSd3mtymJlc2tMM/cAHdITXvH9wWW8vc5nfL9vuG3Jze0yy3/HTdc01PTUYnrt AYBz1w686hFA3XTHue9TmBFLdvVEgyVUTzeSFcqN2yTMwN03bWUgmOCMHRLFjvCj YecZB1V6KCAvvTC8AS7qaFLRSNyL/WvRmog+6Ols//UE7nDhpO1Nt56g6pYArkHP X6a7XXb8Sla1OPXE9Ouz8DpzPK0tAYC3FfB236YiK4Yujqp4yciOvtiCcxiwFmCw oJQu1n+h1RjjPYPrpcR8t7QXEg+zeoBk4+DfmPmTWwpMK+fVA6Vlw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bpja4jgvq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:24 +0000 (GMT) Received: from m0360083.ppops.net (m0360083.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60FA5OKd029550; Thu, 15 Jan 2026 10:05:24 GMT Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bpja4jgvh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:24 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60F8aNSR030146; Thu, 15 Jan 2026 10:05:23 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bm3ajy4w6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:23 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60FA5JJR31261138 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Jan 2026 10:05:19 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 95D672004E; Thu, 15 Jan 2026 10:05:19 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5E43C2004F; Thu, 15 Jan 2026 10:05:16 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.65]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 15 Jan 2026 10:05:16 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v4 3/6] pseries/plpks: expose PowerVM wrapping features via the sysfs Date: Thu, 15 Jan 2026 15:35:01 +0530 Message-ID: <20260115100504.488665-4-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115100504.488665-1-ssrish@linux.ibm.com> References: <20260115100504.488665-1-ssrish@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTE1MDA2OSBTYWx0ZWRfXzsGInuXGaqNp vG6Gba+HBgaVn7fcYirKWgZ+aaLZxHO3zBImWxoxH+4DG56AS7qb9MA79vcgDug+4oLHI15XD9m nNCKbNKWPJFQ5RH2QpvzM+sABl+nzR6D2JLl93iS6FJxsb8e4jBsh0r8LGBP0xSu7yZiSOEmLEh cv1V9HsmTsZjbfO3dqbQmZi6Q4fB2tV1YtxRW6v7ki4MSzOxVbjUrjdIQoVaX8ptGCxZ/ED0K7v qYYhNaHGdsGnMhJamhOZx+e9uyvbLCqGbDXBx3qIkLtQTu8iYxeg20oVfkjAYicUxYG8cswMFDK L7LEQsvx/L2jfAmUVZGcU4qBEuKCmqVN+lEcXUVxRigBO1naSMHPMg1O9DbsARG5wzlEB/ki2gs UVjIVzmpq6XqYiFPvLA/RompRX0A787CV2pV6jLaao5yKP3chAtOVLQL1oLzF7verKSO7XTSzoc fHC0xpQKpsbJwb5X3fg== X-Proofpoint-ORIG-GUID: DJdQ-6_JF7FB7ujIPcaqkoOnT1WmUzlJ X-Proofpoint-GUID: 7__KPtyBQF2dw7reEONCjJG60qGMBn3_ X-Authority-Analysis: v=2.4 cv=U4afzOru c=1 sm=1 tr=0 ts=6968bbe4 cx=c_pps a=AfN7/Ok6k8XGzOShvHwTGQ==:117 a=AfN7/Ok6k8XGzOShvHwTGQ==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=z7cUUKlKUSfJ7xv5IYMA:9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-15_03,2026-01-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 adultscore=0 malwarescore=0 bulkscore=0 phishscore=0 suspectscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601150069 Content-Type: text/plain; charset="utf-8" Starting with Power11, PowerVM supports a new feature called "Key Wrapping" that protects user secrets by wrapping them using a hypervisor generated wrapping key. The status of this feature can be read by the H_PKS_GET_CONFIG HCALL. Expose the Power LPAR Platform KeyStore (PLPKS) wrapping features config via the sysfs file /sys/firmware/plpks/config/wrapping_features. Signed-off-by: Srish Srinivasan Reviewed-by: Nayna Jain --- .../ABI/testing/sysfs-firmware-plpks | 8 ++++++++ arch/powerpc/include/asm/hvcall.h | 4 +++- arch/powerpc/include/asm/plpks.h | 3 +++ arch/powerpc/platforms/pseries/plpks-sysfs.c | 2 ++ arch/powerpc/platforms/pseries/plpks.c | 20 +++++++++++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-firmware-plpks b/Documentation= /ABI/testing/sysfs-firmware-plpks index af0353f34115..cba061e4eee2 100644 --- a/Documentation/ABI/testing/sysfs-firmware-plpks +++ b/Documentation/ABI/testing/sysfs-firmware-plpks @@ -48,3 +48,11 @@ Description: Bitmask of flags indicating which algorithm= s the hypervisor supports for signed update of objects, represented as a 16 byte hexadecimal ASCII string. Consult the hypervisor documentation for what these flags mean. + +What: /sys/firmware/plpks/config/wrapping_features +Date: November 2025 +Contact: Srish Srinivasan +Description: Bitmask of the wrapping features indicating the wrapping + algorithms that are supported for the H_PKS_WRAP_OBJECT requests + , represented as a 8 byte hexadecimal ASCII string. Consult the + hypervisor documentation for what these flags mean. diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/h= vcall.h index 9aef16149d92..dff90a7d7f70 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -360,7 +360,9 @@ #define H_GUEST_RUN_VCPU 0x480 #define H_GUEST_COPY_MEMORY 0x484 #define H_GUEST_DELETE 0x488 -#define MAX_HCALL_OPCODE H_GUEST_DELETE +#define H_PKS_WRAP_OBJECT 0x490 +#define H_PKS_UNWRAP_OBJECT 0x494 +#define MAX_HCALL_OPCODE H_PKS_UNWRAP_OBJECT =20 /* Scope args for H_SCM_UNBIND_ALL */ #define H_UNBIND_SCOPE_ALL (0x1) diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index 8829a13bfda0..8f034588fdf7 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -23,6 +23,7 @@ #define PLPKS_IMMUTABLE PPC_BIT32(5) // Once written, object cannot be re= moved #define PLPKS_TRANSIENT PPC_BIT32(6) // Object does not persist through r= eboot #define PLPKS_SIGNEDUPDATE PPC_BIT32(7) // Object can only be modified by = signed updates +#define PLPKS_WRAPPINGKEY PPC_BIT32(8) // Object contains a wrapping key #define PLPKS_HVPROVISIONED PPC_BIT32(28) // Hypervisor has provisioned th= is object =20 // Signature algorithm flags from signed_update_algorithms @@ -103,6 +104,8 @@ u32 plpks_get_maxlargeobjectsize(void); =20 u64 plpks_get_signedupdatealgorithms(void); =20 +u64 plpks_get_wrappingfeatures(void); + u16 plpks_get_passwordlen(void); =20 void plpks_early_init_devtree(void); diff --git a/arch/powerpc/platforms/pseries/plpks-sysfs.c b/arch/powerpc/pl= atforms/pseries/plpks-sysfs.c index 01d526185783..c2ebcbb41ae3 100644 --- a/arch/powerpc/platforms/pseries/plpks-sysfs.c +++ b/arch/powerpc/platforms/pseries/plpks-sysfs.c @@ -30,6 +30,7 @@ PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace= ); PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicie= s); PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms); +PLPKS_CONFIG_ATTR(wrapping_features, "%016llx\n", plpks_get_wrappingfeatur= es); =20 static const struct attribute *config_attrs[] =3D { &attr_version.attr, @@ -38,6 +39,7 @@ static const struct attribute *config_attrs[] =3D { &attr_used_space.attr, &attr_supported_policies.attr, &attr_signed_update_algorithms.attr, + &attr_wrapping_features.attr, NULL, }; =20 diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platform= s/pseries/plpks.c index 03722fabf9c3..4a08f51537c8 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -38,6 +38,7 @@ static u32 usedspace; static u32 supportedpolicies; static u32 maxlargeobjectsize; static u64 signedupdatealgorithms; +static u64 wrappingfeatures; =20 struct plpks_auth { u8 version; @@ -248,6 +249,7 @@ static int _plpks_get_config(void) __be32 supportedpolicies; __be32 maxlargeobjectsize; __be64 signedupdatealgorithms; + __be64 wrappingfeatures; u8 rsvd1[476]; } __packed * config; size_t size; @@ -280,6 +282,7 @@ static int _plpks_get_config(void) supportedpolicies =3D be32_to_cpu(config->supportedpolicies); maxlargeobjectsize =3D be32_to_cpu(config->maxlargeobjectsize); signedupdatealgorithms =3D be64_to_cpu(config->signedupdatealgorithms); + wrappingfeatures =3D be64_to_cpu(config->wrappingfeatures); =20 // Validate that the numbers we get back match the requirements of the sp= ec if (maxpwsize < 32) { @@ -472,6 +475,23 @@ u64 plpks_get_signedupdatealgorithms(void) return signedupdatealgorithms; } =20 +/** + * plpks_get_wrappingfeatures() - Returns a bitmask of the wrapping featur= es + * supported by the hypervisor. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads a bitmask of the wrapping features supported by the hypervisor in= to the + * file local static wrappingfeatures variable. This is valid only when the + * PLPKS config structure version >=3D 3. + * + * Return: + * bitmask of the wrapping features supported by the hypervisor + */ +u64 plpks_get_wrappingfeatures(void) +{ + return wrappingfeatures; +} + /** * plpks_get_passwordlen() - Get the length of the PLPKS password in bytes. * --=20 2.47.3 From nobody Sun Feb 8 15:59:26 2026 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D566357705; Thu, 15 Jan 2026 10:05:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471548; cv=none; b=QGjzb/asFV4RB7bdpCKh8fvB+Ac3yRo+E8uXXzpx2e1ZKDz/FKHx22lE+j+jKk8bTbsoH0PBb/fFkDlZlKsfBR61K4V3GJeGI/lTvXVUhfaH979w3Ciptjt1lfkmLN7NrRtOyjJiXHGDqhD2YH35/rd790huyE4acdmpuQoZ068= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471548; c=relaxed/simple; bh=EO9Tig3LhbapD+MHuJBvhoq42q2dpqC+RXL2MlMDSuc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AEBkxy58aXS3I89naS9nYMtXJO3K6l3PH2Jj4ItJaOEuS7A397oBBLetN5vQ58z64h0VxGGU0yDCcy3+/i6WtWfkjM0DzBrvlb5jA+K3JDCn5i+ZvqoSWD70jqZA36sj/lJmePlGdKY4urMmkOM4V8zTCXu8I8CuUptNdqywYbo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=CHrGlnxW; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="CHrGlnxW" Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60F9JXK7020499; Thu, 15 Jan 2026 10:05:29 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=K+Od8GxrmnkejjBFN +JWdeN3Q1DWJCSa8u930e/Rdjc=; b=CHrGlnxWVkTvIu/bTkAVy1eOswusXGksv H6kIRw51VFidlDJvrvNket6yjWcrAi30YYhtQnvOJ5NsPkYPyN7KXgsKyf6jeHc9 quvf62fRLFGsB5eEmb+GPYkqNQqqJtvH0Nn4Y29jbWXAXY8kafZpxchcTCTYKQSm wnjwNs2NSawnND7VSOYYUNEFhLLr0vE7Z17IcnY/OAbOh+kMU/9MaFO9I66zZJgq uevmLhCMHZ+1wPyag+NJpOgBamWpKznqs/vwxyaqu89CoSdhhpB/3X1F58OHg4eX FoiXxkiJdRnlNkFkobJkbCbtXpXSMbylKHk0HZtEWTrSn9ntenYvw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkd6edhb9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:28 +0000 (GMT) Received: from m0353725.ppops.net (m0353725.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60FA2q5v028606; Thu, 15 Jan 2026 10:05:28 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkd6edhb6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:28 +0000 (GMT) Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60F82YfF025877; Thu, 15 Jan 2026 10:05:27 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bm2kkqbda-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:27 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60FA5NCv47186180 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Jan 2026 10:05:23 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5657720065; Thu, 15 Jan 2026 10:05:23 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 051A32005A; Thu, 15 Jan 2026 10:05:20 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.65]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 15 Jan 2026 10:05:19 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v4 4/6] pseries/plpks: add HCALLs for PowerVM Key Wrapping Module Date: Thu, 15 Jan 2026 15:35:02 +0530 Message-ID: <20260115100504.488665-5-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115100504.488665-1-ssrish@linux.ibm.com> References: <20260115100504.488665-1-ssrish@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: H_VQb4nYstbIJwAXyEe0TKx7JyHKjO-n X-Authority-Analysis: v=2.4 cv=LLxrgZW9 c=1 sm=1 tr=0 ts=6968bbe9 cx=c_pps a=3Bg1Hr4SwmMryq2xdFQyZA==:117 a=3Bg1Hr4SwmMryq2xdFQyZA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=nO4dFLMeAchwtJrxA4IA:9 a=POYjf8jjcDEwoKyR:21 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTE1MDA2OSBTYWx0ZWRfX7jc5eO+EQom/ LpVrIpQgDbjNzoBByfkAmdlL2C0Plb9pzqjTZe9JK05qQ2EiafsLxSz+hD8r5RrQy5t1/0vRqbT QrjH4/oe3T7SGhEaE1wKwvz+Rfc/2h72mKE1ZjvfQ+hexB6mJgT+Oc42ZR1Gk6VPLAHkFCk3hS9 Uci2uaGqXHVJnAHm1LeKKTVqQNmeUKKcCTmD70/iPbxd6FI+D1tBhjpxXJOKXjhqpVs67D8/XF0 rXftXIarrRE5mFaY27pBx5tRpdEyF+L7Tj1D8022g0Cwcp+nB+3kM396ZElRdV/5csskx+48bA7 bqNFcdu16R4vtI1soqcMcacH4g1Tdid5y0ar4wEEFwuhstbkBpZJq4XrEYmi2TXIQuGUbcbRnVr N6mcTeCIfr7AT+c5PQ1HC6wOgK3pLroZrE3yVl/Z4A3G4LU1od5V1Chg/CwHDBEa6xxSgDf5ytr 99oGjZzumNH5axKKLFg== X-Proofpoint-ORIG-GUID: -kFB2yBh3EKya2ZUThyta32k41Uf9Nyr X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-15_03,2026-01-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 suspectscore=0 clxscore=1015 spamscore=0 impostorscore=0 malwarescore=0 phishscore=0 adultscore=0 lowpriorityscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601150069 Content-Type: text/plain; charset="utf-8" The hypervisor generated wrapping key is an AES-GCM-256 symmetric key which is stored in a non-volatile, secure, and encrypted storage called the Power LPAR Platform KeyStore. It has policy based protections that prevent it from being read out or exposed to the user. Implement H_PKS_GEN_KEY, H_PKS_WRAP_OBJECT, and H_PKS_UNWRAP_OBJECT HCALLs to enable using the PowerVM Key Wrapping Module (PKWM) as a new trust source for trusted keys. Disallow H_PKS_READ_OBJECT, H_PKS_SIGNED_UPDATE, and H_PKS_WRITE_OBJECT for objects with the 'wrapping key' policy set. Capture the availability status for the H_PKS_WRAP_OBJECT interface. Signed-off-by: Srish Srinivasan Reviewed-by: Nayna Jain --- Documentation/arch/powerpc/papr_hcalls.rst | 43 +++ arch/powerpc/include/asm/plpks.h | 10 + arch/powerpc/platforms/pseries/plpks.c | 342 ++++++++++++++++++++- 3 files changed, 393 insertions(+), 2 deletions(-) diff --git a/Documentation/arch/powerpc/papr_hcalls.rst b/Documentation/arc= h/powerpc/papr_hcalls.rst index 805e1cb9bab9..14e39f095a1c 100644 --- a/Documentation/arch/powerpc/papr_hcalls.rst +++ b/Documentation/arch/powerpc/papr_hcalls.rst @@ -300,6 +300,49 @@ H_HTM supports setup, configuration, control and dumpi= ng of Hardware Trace Macro (HTM) function and its data. HTM buffer stores tracing data for func= tions like core instruction, core LLAT and nest. =20 +**H_PKS_GEN_KEY** + +| Input: authorization, objectlabel, objectlabellen, policy, out, outlen +| Out: *Hypervisor Generated Key, or None when the wrapping key policy is = set* +| Return Value: *H_SUCCESS, H_Function, H_State, H_R_State, H_Parameter, H= _P2, + H_P3, H_P4, H_P5, H_P6, H_Authority, H_Nomem, H_Busy, H_Re= source, + H_Aborted* + +H_PKS_GEN_KEY is used to have the hypervisor generate a new random key. +This key is stored as an object in the Power LPAR Platform KeyStore with +the provided object label. With the wrapping key policy set the key is only +visible to the hypervisor, while the key's label would still be visible to +the user. Generation of wrapping keys is supported only for a key size of +32 bytes. + +**H_PKS_WRAP_OBJECT** + +| Input: authorization, wrapkeylabel, wrapkeylabellen, objectwrapflags, in, +| inlen, out, outlen, continue-token +| Out: *continue-token, byte size of wrapped object, wrapped object* +| Return Value: *H_SUCCESS, H_Function, H_State, H_R_State, H_Parameter, H= _P2, + H_P3, H_P4, H_P5, H_P6, H_P7, H_P8, H_P9, H_Authority, H_I= nvalid_Key, + H_NOT_FOUND, H_Busy, H_LongBusy, H_Aborted* + +H_PKS_WRAP_OBJECT is used to wrap an object using a wrapping key stored in= the +Power LPAR Platform KeyStore and return the wrapped object to the caller. = The +caller provides a label to a wrapping key with the 'wrapping key' policy s= et, +which must have been previously created with H_PKS_GEN_KEY. The provided o= bject +is then encrypted with the wrapping key and additional metadata and the re= sult +is returned to the caller. + + +**H_PKS_UNWRAP_OBJECT** + +| Input: authorization, objectwrapflags, in, inlen, out, outlen, continue-= token +| Out: *continue-token, byte size of unwrapped object, unwrapped object* +| Return Value: *H_SUCCESS, H_Function, H_State, H_R_State, H_Parameter, H= _P2, + H_P3, H_P4, H_P5, H_P6, H_P7, H_Authority, H_Unsupported, = H_Bad_Data, + H_NOT_FOUND, H_Invalid_Key, H_Busy, H_LongBusy, H_Aborted* + +H_PKS_UNWRAP_OBJECT is used to unwrap an object that was previously warapp= ed with +H_PKS_WRAP_OBJECT. + References =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D .. [1] "Power Architecture Platform Reference" diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index 8f034588fdf7..e87f90e40d4e 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -113,6 +113,16 @@ void plpks_early_init_devtree(void); int plpks_populate_fdt(void *fdt); =20 int plpks_config_create_softlink(struct kobject *from); + +bool plpks_wrapping_is_supported(void); + +int plpks_gen_wrapping_key(void); + +int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags, + u8 **output_buf, u32 *output_len); + +int plpks_unwrap_object(u8 **input_buf, u32 input_len, + u8 **output_buf, u32 *output_len); #else // CONFIG_PSERIES_PLPKS static inline bool plpks_is_available(void) { return false; } static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); } diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platform= s/pseries/plpks.c index 4a08f51537c8..b97b7750f6a8 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -9,6 +9,32 @@ =20 #define pr_fmt(fmt) "plpks: " fmt =20 +#define PLPKS_WRAPKEY_COMPONENT "PLPKSWR" +#define PLPKS_WRAPKEY_NAME "default-wrapping-key" + +/* + * To 4K align the {input, output} buffers to the {UN}WRAP H_CALLs + */ +#define PLPKS_WRAPPING_BUF_ALIGN 4096 + +/* + * To ensure the output buffer's length is at least 1024 bytes greater + * than the input buffer's length during the WRAP H_CALL + */ +#define PLPKS_WRAPPING_BUF_DIFF 1024 + +#define PLPKS_WRAP_INTERFACE_BIT 3 +#define PLPKS_WRAPPING_KEY_LENGTH 32 + +#define WRAPFLAG_BE_BIT_SET(be_bit) \ + BIT_ULL(63 - (be_bit)) + +#define WRAPFLAG_BE_GENMASK(be_bit_hi, be_bit_lo) \ + GENMASK_ULL(63 - (be_bit_hi), 63 - (be_bit_lo)) + +#define WRAPFLAG_BE_FIELD_PREP(be_bit_hi, be_bit_lo, val) \ + FIELD_PREP(WRAPFLAG_BE_GENMASK(be_bit_hi, be_bit_lo), (val)) + #include #include #include @@ -39,6 +65,7 @@ static u32 supportedpolicies; static u32 maxlargeobjectsize; static u64 signedupdatealgorithms; static u64 wrappingfeatures; +static bool wrapsupport; =20 struct plpks_auth { u8 version; @@ -283,6 +310,7 @@ static int _plpks_get_config(void) maxlargeobjectsize =3D be32_to_cpu(config->maxlargeobjectsize); signedupdatealgorithms =3D be64_to_cpu(config->signedupdatealgorithms); wrappingfeatures =3D be64_to_cpu(config->wrappingfeatures); + wrapsupport =3D config->flags & PPC_BIT8(PLPKS_WRAP_INTERFACE_BIT); =20 // Validate that the numbers we get back match the requirements of the sp= ec if (maxpwsize < 32) { @@ -614,6 +642,9 @@ int plpks_signed_update_var(struct plpks_var *var, u64 = flags) if (!(var->policy & PLPKS_SIGNEDUPDATE)) return -EINVAL; =20 + if (var->policy & PLPKS_WRAPPINGKEY) + return -EINVAL; + // Signed updates need the component to be NULL. if (var->component) return -EINVAL; @@ -696,6 +727,9 @@ int plpks_write_var(struct plpks_var var) if (var.policy & PLPKS_SIGNEDUPDATE) return -EINVAL; =20 + if (var.policy & PLPKS_WRAPPINGKEY) + return -EINVAL; + auth =3D construct_auth(PLPKS_OS_OWNER); if (IS_ERR(auth)) return PTR_ERR(auth); @@ -790,6 +824,9 @@ static int plpks_read_var(u8 consumer, struct plpks_var= *var) if (var->namelen > PLPKS_MAX_NAME_SIZE) return -EINVAL; =20 + if (var->policy & PLPKS_WRAPPINGKEY) + return -EINVAL; + auth =3D construct_auth(consumer); if (IS_ERR(auth)) return PTR_ERR(auth); @@ -845,8 +882,309 @@ static int plpks_read_var(u8 consumer, struct plpks_v= ar *var) } =20 /** - * plpks_read_os_var() - Fetch the data for the specified variable that is - * owned by the OS consumer. + * plpks_wrapping_is_supported() - Get the H_PKS_WRAP_OBJECT interface + * availability status for the LPAR. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * sets bit 3 of the flags variable in the PLPKS config structure if the + * H_PKS_WRAP_OBJECT interface is supported. + * + * Returns: true if the H_PKS_WRAP_OBJECT interface is supported, false if= not. + */ +bool plpks_wrapping_is_supported(void) +{ + return wrapsupport; +} + +/** + * plpks_gen_wrapping_key() - Generate a new random key with the 'wrapping= key' + * policy set. + * + * The H_PKS_GEN_KEY HCALL makes the hypervisor generate a new random key = and + * store the key in a PLPKS object with the provided object label. With the + * 'wrapping key' policy set, only the label to the newly generated random= key + * would be visible to the user. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid or unsupported policy declaration + * if invalid output buffer parameter + * if invalid output buffer length parameter + * -EPERM if access is denied + * -ENOMEM if there is inadequate memory to perform this operation + * -EBUSY if unable to handle the request + * -EEXIST if the object label already exists + * + * Returns: On success 0 is returned, a negative errno if not. + */ +int plpks_gen_wrapping_key(void) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE] =3D { 0 }; + struct plpks_auth *auth; + struct label *label; + int rc =3D 0, pseries_status =3D 0; + struct plpks_var var =3D { + .name =3D PLPKS_WRAPKEY_NAME, + .namelen =3D strlen(var.name), + .policy =3D PLPKS_WRAPPINGKEY, + .os =3D PLPKS_VAR_LINUX, + .component =3D PLPKS_WRAPKEY_COMPONENT + }; + + auth =3D construct_auth(PLPKS_OS_OWNER); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + label =3D construct_label(var.component, var.os, var.name, var.namelen); + if (IS_ERR(label)) { + rc =3D PTR_ERR(label); + goto out; + } + + rc =3D plpar_hcall(H_PKS_GEN_KEY, retbuf, + virt_to_phys(auth), virt_to_phys(label), + label->size, var.policy, + NULL, PLPKS_WRAPPING_KEY_LENGTH); + + if (!rc) + rc =3D plpks_confirm_object_flushed(label, auth); + + pseries_status =3D rc; + rc =3D pseries_status_to_err(rc); + + if (rc && rc !=3D -EEXIST) { + pr_err("H_PKS_GEN_KEY failed. pseries_status=3D%d, rc=3D%d", + pseries_status, rc); + } else { + rc =3D 0; + } + + kfree(label); +out: + kfree(auth); + return rc; +} +EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key); + +/** + * plpks_wrap_object() - Wrap an object using the default wrapping key sto= red in + * the PLPKS. + * @input_buf: buffer containing the data to be wrapped + * @input_len: length of the input buffer + * @wrap_flags: object wrapping flags + * @output_buf: buffer to store the wrapped data + * @output_len: length of the output buffer + * + * The H_PKS_WRAP_OBJECT HCALL wraps an object using a wrapping key stored= in + * the PLPKS and returns the wrapped object to the caller. The caller prov= ides a + * label to the wrapping key with the 'wrapping key' policy set that must = have + * been previously created with the H_PKS_GEN_KEY HCALL. The provided obje= ct is + * then encrypted with the wrapping key and additional metadata and the re= sult + * is returned to the user. The metadata includes the wrapping algorithm a= nd the + * wrapping key name so those parameters are not required during unwrap. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid wrapping key label parameter + * if invalid wrapping key label length parameter + * if invalid or unsupported object wrapping flags + * if invalid input buffer parameter + * if invalid input buffer length parameter + * if invalid output buffer parameter + * if invalid output buffer length parameter + * if invalid continue token parameter + * if the wrapping key is not compatible with the wrapping + * algorithm + * -EPERM if access is denied + * -ENOENT if the requested wrapping key was not found + * -EBUSY if unable to handle the request or long running operation + * initiated, retry later. + * + * Returns: On success 0 is returned, a negative errno if not. + */ +int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags, + u8 **output_buf, u32 *output_len) +{ + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] =3D { 0 }; + struct plpks_auth *auth; + struct label *label; + u64 continuetoken =3D 0; + u64 objwrapflags =3D 0; + int rc =3D 0, pseries_status =3D 0; + bool sb_audit_or_enforce_bit =3D wrap_flags & BIT(0); + bool sb_enforce_bit =3D wrap_flags & BIT(1); + struct plpks_var var =3D { + .name =3D PLPKS_WRAPKEY_NAME, + .namelen =3D strlen(var.name), + .os =3D PLPKS_VAR_LINUX, + .component =3D PLPKS_WRAPKEY_COMPONENT + }; + + auth =3D construct_auth(PLPKS_OS_OWNER); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + label =3D construct_label(var.component, var.os, var.name, var.namelen); + if (IS_ERR(label)) { + rc =3D PTR_ERR(label); + goto out; + } + + /* Set the consumer password requirement bit. A must have. */ + objwrapflags |=3D WRAPFLAG_BE_BIT_SET(3); + + /* Set the wrapping algorithm bit. Just one algorithm option for now */ + objwrapflags |=3D WRAPFLAG_BE_FIELD_PREP(60, 63, 0x1); + + if (sb_audit_or_enforce_bit & sb_enforce_bit) { + pr_err("Cannot set both audit/enforce and enforce bits."); + rc =3D -EINVAL; + goto out_free_label; + } else if (sb_audit_or_enforce_bit) { + objwrapflags |=3D WRAPFLAG_BE_BIT_SET(1); + } else if (sb_enforce_bit) { + objwrapflags |=3D WRAPFLAG_BE_BIT_SET(2); + } + + *output_len =3D input_len + PLPKS_WRAPPING_BUF_DIFF; + + *output_buf =3D kzalloc(ALIGN(*output_len, PLPKS_WRAPPING_BUF_ALIGN), + GFP_KERNEL); + if (!(*output_buf)) { + pr_err("Output buffer allocation failed. Returning -ENOMEM."); + rc =3D -ENOMEM; + goto out_free_label; + } + + do { + rc =3D plpar_hcall9(H_PKS_WRAP_OBJECT, retbuf, + virt_to_phys(auth), virt_to_phys(label), + label->size, objwrapflags, + virt_to_phys(*input_buf), input_len, + virt_to_phys(*output_buf), *output_len, + continuetoken); + + continuetoken =3D retbuf[0]; + pseries_status =3D rc; + rc =3D pseries_status_to_err(rc); + } while (rc =3D=3D -EBUSY); + + if (rc) { + pr_err("H_PKS_WRAP_OBJECT failed. pseries_status=3D%d, rc=3D%d", + pseries_status, rc); + kfree(*output_buf); + *output_buf =3D NULL; + } else { + *output_len =3D retbuf[1]; + } + +out_free_label: + kfree(label); +out: + kfree(auth); + return rc; +} +EXPORT_SYMBOL_GPL(plpks_wrap_object); + +/** + * plpks_unwrap_object() - Unwrap an object using the default wrapping key + * stored in the PLPKS. + * @input_buf: buffer containing the data to be unwrapped + * @input_len: length of the input buffer + * @output_buf: buffer to store the unwrapped data + * @output_len: length of the output buffer + * + * The H_PKS_UNWRAP_OBJECT HCALL unwraps an object that was previously wra= pped + * using the H_PKS_WRAP_OBJECT HCALL. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid or unsupported object unwrapping flags + * if invalid input buffer parameter + * if invalid input buffer length parameter + * if invalid output buffer parameter + * if invalid output buffer length parameter + * if invalid continue token parameter + * if the wrapping key is not compatible with the wrapping + * algorithm + * if the wrapped object's format is not supported + * if the wrapped object is invalid + * -EPERM if access is denied + * -ENOENT if the wrapping key for the provided object was not found + * -EBUSY if unable to handle the request or long running operation + * initiated, retry later. + * + * Returns: On success 0 is returned, a negative errno if not. + */ +int plpks_unwrap_object(u8 **input_buf, u32 input_len, u8 **output_buf, + u32 *output_len) +{ + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] =3D { 0 }; + struct plpks_auth *auth; + u64 continuetoken =3D 0; + u64 objwrapflags =3D 0; + int rc =3D 0, pseries_status =3D 0; + + auth =3D construct_auth(PLPKS_OS_OWNER); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + *output_len =3D input_len - PLPKS_WRAPPING_BUF_DIFF; + *output_buf =3D kzalloc(ALIGN(*output_len, PLPKS_WRAPPING_BUF_ALIGN), + GFP_KERNEL); + if (!(*output_buf)) { + pr_err("Output buffer allocation failed. Returning -ENOMEM."); + rc =3D -ENOMEM; + goto out; + } + + do { + rc =3D plpar_hcall9(H_PKS_UNWRAP_OBJECT, retbuf, + virt_to_phys(auth), objwrapflags, + virt_to_phys(*input_buf), input_len, + virt_to_phys(*output_buf), *output_len, + continuetoken); + + continuetoken =3D retbuf[0]; + pseries_status =3D rc; + rc =3D pseries_status_to_err(rc); + } while (rc =3D=3D -EBUSY); + + if (rc) { + pr_err("H_PKS_UNWRAP_OBJECT failed. pseries_status=3D%d, rc=3D%d", + pseries_status, rc); + kfree(*output_buf); + *output_buf =3D NULL; + } else { + *output_len =3D retbuf[1]; + } + +out: + kfree(auth); + return rc; +} +EXPORT_SYMBOL_GPL(plpks_unwrap_object); + +/** + * plpks_read_os_var() - Fetch the data for the specified variable that is= owned + * by the OS consumer. * @var: variable to be read from the PLPKS * * The consumer or the owner of the object is the os kernel. The --=20 2.47.3 From nobody Sun Feb 8 15:59:26 2026 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 55C8935FF52; Thu, 15 Jan 2026 10:05:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471555; cv=none; b=KF/5bR+YLIXyueiP49GU8VDj++khbB2EHrl4mOoiLLE1avvdImKQFN+VqhxIyt6o6FM50P8TrVLJk0u1Uesju8afZ4rsCkzLKwwBqzoaQcd92nDi9Pv60Fp/746V0RO6Yxik91YW/SnQV/Q0Uq0Ue4v5TaEUqjSlZBCgY2zHmu0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471555; c=relaxed/simple; bh=OReRviVFNBNk1QzCUFlraQQfscmrF5+tQMqiszDaWhE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=p6HisV/iDcSxi+bnqStWM7YO5YERt/XDC7ZiKrbumhZWUgkSsx5HzbsUAvHY583JMCU1qTuPGdckwybHilptfc7N3p43W3OFnDwwcnK7m/Pshb2qfU5apghzG73jsBvMCDyKgqK9FI5tNyNTzQJeY7QTCT/8oD0qsxIeOE/SYGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=VWV6BWUy; arc=none smtp.client-ip=148.163.156.1 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="VWV6BWUy" Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60ENLTZZ007064; Thu, 15 Jan 2026 10:05:33 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=2xbeQU7Oy+tH2qRGT ZU1QMeJTjrIpjNe7YeAM/8IGwU=; b=VWV6BWUyopRW8jkMncPbDdg28dNcBCm1P ErYNiqgSY2tX+xYZq7TbCrLIN0Mv5jn9jl2TExG4m/sVMrd8OAkOtXfvIt7+TfV7 HeXsRkx3vbyGiweMd0K7aqtx8zI4Rfeew5Vx2NPrcAgmWqja1r5F/WE69bBeItHr +Rw12FtKadm52oXUA6iGWe1c5kCiAykSHxtsACw/mKZMs39HWUGQOKme8Vx5nh+u 48nmp1jSnESn74Tf/3ikNlqd/XqhSmPkMczNUJVttZKeD+IjeP2CicYYs75rcD42 KG5vAz7Ta4pdhogaCHlYjQy4NbSlavb90vCkJMkKjCfUwXAFkFGXg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkeeq5y13-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:32 +0000 (GMT) Received: from m0353729.ppops.net (m0353729.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60FA4ZPu022736; Thu, 15 Jan 2026 10:05:32 GMT Received: from ppma23.wdc07v.mail.ibm.com (5d.69.3da9.ip4.static.sl-reverse.com [169.61.105.93]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkeeq5y11-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:32 +0000 (GMT) Received: from pps.filterd (ppma23.wdc07v.mail.ibm.com [127.0.0.1]) by ppma23.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60F8GpfF025848; Thu, 15 Jan 2026 10:05:31 GMT Received: from smtprelay01.fra02v.mail.ibm.com ([9.218.2.227]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bm2kkqbdj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:31 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay01.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60FA5R2C61735262 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Jan 2026 10:05:27 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F064D2004E; Thu, 15 Jan 2026 10:05:26 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C5D022005A; Thu, 15 Jan 2026 10:05:23 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.65]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 15 Jan 2026 10:05:23 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v4 5/6] keys/trusted_keys: establish PKWM as a trusted source Date: Thu, 15 Jan 2026 15:35:03 +0530 Message-ID: <20260115100504.488665-6-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115100504.488665-1-ssrish@linux.ibm.com> References: <20260115100504.488665-1-ssrish@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=DI6CIiNb c=1 sm=1 tr=0 ts=6968bbec cx=c_pps a=3Bg1Hr4SwmMryq2xdFQyZA==:117 a=3Bg1Hr4SwmMryq2xdFQyZA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=VwQbUJbxAAAA:8 a=6hcB66QTelQ3WYe9m3UA:9 X-Proofpoint-GUID: NTVC_I3M2AG5ZLZjm4SxVjjuV9dudeea X-Proofpoint-ORIG-GUID: ZXgpX6gfj842tE04kMljlYgXVFXC-Eis X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTE1MDA2OSBTYWx0ZWRfX4kt+dDesR5db MJuZAHPyRm3+zMzrqljm8EOwbUcRJzX8zD28Dw/Fm+C83qhCo/FU1+2FKUMCqXANGA2C/HZ0rEO u1/9LBlaEQ1XTqBKYcAnKuSdidnmQ1WatqfzLgJzocNr4RhMm5xaYhfj7wySePmQg34lznmA+Bb E7CyCjC6Ag1UWgDkUSwJM6jIFUZysYn8fJg8ZZhdAcSp+A85GJok8vxuzWiVuIBbqgIy24V/Tn4 IFOEARBRGoxtz3SP4ReA6k6ivr34Kwg1z2xCC5TiG6W3IPEol802f2YaWOt8QELAAYlSY0L3czi L3kT09v7SVx7DME1HKFCjMbSwnHKphqva08z5zEo+850ypstZIhVGkRgBiH2QwRf3VRqgVdfili VdOdBCILcyxamimEGRC2t4tKC9NEnrpTmwCmi3qOZfZGGqRs7GmbuAh0ifTmjU4TqUrUuZoZh4L 6e8BgWaQg5AOGnobmnA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-15_03,2026-01-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 adultscore=0 malwarescore=0 spamscore=0 suspectscore=0 phishscore=0 impostorscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601150069 Content-Type: text/plain; charset="utf-8" The wrapping key does not exist by default and is generated by the hypervisor as a part of PKWM initialization. This key is then persisted by the hypervisor and is used to wrap trusted keys. These are variable length symmetric keys, which in the case of PowerVM Key Wrapping Module (PKWM) are generated using the kernel RNG. PKWM can be used as a trust source through the following example keyctl commands: keyctl add trusted my_trusted_key "new 32" @u Use the wrap_flags command option to set the secure boot requirement for the wrapping request through the following keyctl commands case1: no secure boot requirement. (default) keyctl usage: keyctl add trusted my_trusted_key "new 32" @u OR keyctl add trusted my_trusted_key "new 32 wrap_flags=3D0x00" @u case2: secure boot required to in either audit or enforce mode. set bit 0 keyctl usage: keyctl add trusted my_trusted_key "new 32 wrap_flags=3D0x01" = @u case3: secure boot required to be in enforce mode. set bit 1 keyctl usage: keyctl add trusted my_trusted_key "new 32 wrap_flags=3D0x02" = @u NOTE: -> Setting the secure boot requirement is NOT a must. -> Only either of the secure boot requirement options should be set. Not both. -> All the other bits are required to be not set. -> Set the kernel parameter trusted.source=3Dpkwm to choose PKWM as the backend for trusted keys implementation. -> CONFIG_PSERIES_PLPKS must be enabled to build PKWM. Add PKWM, which is a combination of IBM PowerVM and Power LPAR Platform KeyStore, as a new trust source for trusted keys. Signed-off-by: Srish Srinivasan Reviewed-by: Mimi Zohar Reviewed-by: Jarkko Sakkinen Reviewed-by: Nayna Jain --- This version introduces a private pointer for backend specific fields and related changes specific to the PKWM backend, but defers migrating the TPM fields to this new framework. That will be done independently of this patch series. MAINTAINERS | 9 + include/keys/trusted-type.h | 7 +- include/keys/trusted_pkwm.h | 33 ++++ security/keys/trusted-keys/Kconfig | 8 + security/keys/trusted-keys/Makefile | 2 + security/keys/trusted-keys/trusted_core.c | 6 +- security/keys/trusted-keys/trusted_pkwm.c | 190 ++++++++++++++++++++++ 7 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 include/keys/trusted_pkwm.h create mode 100644 security/keys/trusted-keys/trusted_pkwm.c diff --git a/MAINTAINERS b/MAINTAINERS index cf755238c429..c98f1811f836 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14008,6 +14008,15 @@ S: Supported F: include/keys/trusted_dcp.h F: security/keys/trusted-keys/trusted_dcp.c =20 +KEYS-TRUSTED-PLPKS +M: Srish Srinivasan +M: Nayna Jain +L: linux-integrity@vger.kernel.org +L: keyrings@vger.kernel.org +S: Supported +F: include/keys/trusted_pkwm.h +F: security/keys/trusted-keys/trusted_pkwm.c + KEYS-TRUSTED-TEE M: Sumit Garg L: linux-integrity@vger.kernel.org diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h index 4eb64548a74f..03527162613f 100644 --- a/include/keys/trusted-type.h +++ b/include/keys/trusted-type.h @@ -19,7 +19,11 @@ =20 #define MIN_KEY_SIZE 32 #define MAX_KEY_SIZE 128 -#define MAX_BLOB_SIZE 512 +#if IS_ENABLED(CONFIG_TRUSTED_KEYS_PKWM) +#define MAX_BLOB_SIZE 1152 +#else +#define MAX_BLOB_SIZE 512 +#endif #define MAX_PCRINFO_SIZE 64 #define MAX_DIGEST_SIZE 64 =20 @@ -46,6 +50,7 @@ struct trusted_key_options { uint32_t policydigest_len; unsigned char policydigest[MAX_DIGEST_SIZE]; uint32_t policyhandle; + void *private; }; =20 struct trusted_key_ops { diff --git a/include/keys/trusted_pkwm.h b/include/keys/trusted_pkwm.h new file mode 100644 index 000000000000..4035b9776394 --- /dev/null +++ b/include/keys/trusted_pkwm.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PKWM_TRUSTED_KEY_H +#define __PKWM_TRUSTED_KEY_H + +#include +#include +#include + +extern struct trusted_key_ops pkwm_trusted_key_ops; + +struct trusted_pkwm_options { + u16 wrap_flags; +}; + +static inline void dump_options(struct trusted_key_options *o) +{ + const struct trusted_pkwm_options *pkwm; + bool sb_audit_or_enforce_bit; + bool sb_enforce_bit; + + pkwm =3D o->private; + sb_audit_or_enforce_bit =3D pkwm->wrap_flags & BIT(0); + sb_enforce_bit =3D pkwm->wrap_flags & BIT(1); + + if (sb_audit_or_enforce_bit) + pr_debug("secure boot mode required: audit or enforce"); + else if (sb_enforce_bit) + pr_debug("secure boot mode required: enforce"); + else + pr_debug("secure boot mode required: disabled"); +} + +#endif diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-key= s/Kconfig index 204a68c1429d..9e00482d886a 100644 --- a/security/keys/trusted-keys/Kconfig +++ b/security/keys/trusted-keys/Kconfig @@ -46,6 +46,14 @@ config TRUSTED_KEYS_DCP help Enable use of NXP's DCP (Data Co-Processor) as trusted key backend. =20 +config TRUSTED_KEYS_PKWM + bool "PKWM-based trusted keys" + depends on PSERIES_PLPKS >=3D TRUSTED_KEYS + default y + select HAVE_TRUSTED_KEYS + help + Enable use of IBM PowerVM Key Wrapping Module (PKWM) as a trusted key b= ackend. + if !HAVE_TRUSTED_KEYS comment "No trust source selected!" endif diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-ke= ys/Makefile index f0f3b27f688b..5fc053a21dad 100644 --- a/security/keys/trusted-keys/Makefile +++ b/security/keys/trusted-keys/Makefile @@ -16,3 +16,5 @@ trusted-$(CONFIG_TRUSTED_KEYS_TEE) +=3D trusted_tee.o trusted-$(CONFIG_TRUSTED_KEYS_CAAM) +=3D trusted_caam.o =20 trusted-$(CONFIG_TRUSTED_KEYS_DCP) +=3D trusted_dcp.o + +trusted-$(CONFIG_TRUSTED_KEYS_PKWM) +=3D trusted_pkwm.o diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trus= ted-keys/trusted_core.c index b1680ee53f86..2d328de170e8 100644 --- a/security/keys/trusted-keys/trusted_core.c +++ b/security/keys/trusted-keys/trusted_core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ MODULE_PARM_DESC(rng, "Select trusted key RNG"); =20 static char *trusted_key_source; module_param_named(source, trusted_key_source, charp, 0); -MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam or dc= p)"); +MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam, dcp = or pkwm)"); =20 static const struct trusted_key_source trusted_key_sources[] =3D { #if defined(CONFIG_TRUSTED_KEYS_TPM) @@ -46,6 +47,9 @@ static const struct trusted_key_source trusted_key_source= s[] =3D { #if defined(CONFIG_TRUSTED_KEYS_DCP) { "dcp", &dcp_trusted_key_ops }, #endif +#if defined(CONFIG_TRUSTED_KEYS_PKWM) + { "pkwm", &pkwm_trusted_key_ops }, +#endif }; =20 DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->sea= l); diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trus= ted-keys/trusted_pkwm.c new file mode 100644 index 000000000000..4f391b77a907 --- /dev/null +++ b/security/keys/trusted-keys/trusted_pkwm.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 IBM Corporation, Srish Srinivasan + */ + +#include +#include +#include +#include +#include +#include + +enum { + Opt_err, + Opt_wrap_flags, +}; + +static const match_table_t key_tokens =3D { + {Opt_wrap_flags, "wrap_flags=3D%s"}, + {Opt_err, NULL} +}; + +static int getoptions(char *datablob, struct trusted_key_options *opt) +{ + substring_t args[MAX_OPT_ARGS]; + char *p =3D datablob; + int token; + int res; + u16 wrap_flags; + unsigned long token_mask =3D 0; + struct trusted_pkwm_options *pkwm; + + if (!datablob) + return 0; + + pkwm =3D opt->private; + + while ((p =3D strsep(&datablob, " \t"))) { + if (*p =3D=3D '\0' || *p =3D=3D ' ' || *p =3D=3D '\t') + continue; + + token =3D match_token(p, key_tokens, args); + if (test_and_set_bit(token, &token_mask)) + return -EINVAL; + + switch (token) { + case Opt_wrap_flags: + res =3D kstrtou16(args[0].from, 16, &wrap_flags); + if (res < 0 || wrap_flags > 2) + return -EINVAL; + pkwm->wrap_flags =3D wrap_flags; + break; + default: + return -EINVAL; + } + } + return 0; +} + +static struct trusted_key_options *trusted_options_alloc(void) +{ + struct trusted_key_options *options; + struct trusted_pkwm_options *pkwm; + + options =3D kzalloc(sizeof(*options), GFP_KERNEL); + + if (options) { + pkwm =3D kzalloc(sizeof(*pkwm), GFP_KERNEL); + + if (!pkwm) { + kfree_sensitive(options); + options =3D NULL; + } else { + options->private =3D pkwm; + } + } + + return options; +} + +static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob) +{ + struct trusted_key_options *options =3D NULL; + struct trusted_pkwm_options *pkwm =3D NULL; + u8 *input_buf, *output_buf; + u32 output_len, input_len; + int rc; + + options =3D trusted_options_alloc(); + + if (!options) + return -ENOMEM; + + rc =3D getoptions(datablob, options); + if (rc < 0) + goto out; + dump_options(options); + + input_len =3D p->key_len; + input_buf =3D kmalloc(ALIGN(input_len, 4096), GFP_KERNEL); + if (!input_buf) { + pr_err("Input buffer allocation failed. Returning -ENOMEM."); + rc =3D -ENOMEM; + goto out; + } + + memcpy(input_buf, p->key, p->key_len); + + pkwm =3D options->private; + + rc =3D plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags, + &output_buf, &output_len); + if (!rc) { + memcpy(p->blob, output_buf, output_len); + p->blob_len =3D output_len; + dump_payload(p); + } else { + pr_err("Wrapping of payload key failed: %d\n", rc); + } + + kfree(input_buf); + kfree(output_buf); + +out: + kfree_sensitive(options->private); + kfree_sensitive(options); + return rc; +} + +static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *databl= ob) +{ + u8 *input_buf, *output_buf; + u32 input_len, output_len; + int rc; + + input_len =3D p->blob_len; + input_buf =3D kmalloc(ALIGN(input_len, 4096), GFP_KERNEL); + if (!input_buf) { + pr_err("Input buffer allocation failed. Returning -ENOMEM."); + return -ENOMEM; + } + + memcpy(input_buf, p->blob, p->blob_len); + + rc =3D plpks_unwrap_object(&input_buf, input_len, &output_buf, + &output_len); + if (!rc) { + memcpy(p->key, output_buf, output_len); + p->key_len =3D output_len; + dump_payload(p); + } else { + pr_err("Unwrapping of payload failed: %d\n", rc); + } + + kfree(input_buf); + kfree(output_buf); + + return rc; +} + +static int trusted_pkwm_init(void) +{ + int ret; + + if (!plpks_wrapping_is_supported()) { + pr_err("H_PKS_WRAP_OBJECT interface not supported\n"); + return -ENODEV; + } + + ret =3D plpks_gen_wrapping_key(); + if (ret) { + pr_err("Failed to generate default wrapping key\n"); + return -EINVAL; + } + + return register_key_type(&key_type_trusted); +} + +static void trusted_pkwm_exit(void) +{ + unregister_key_type(&key_type_trusted); +} + +struct trusted_key_ops pkwm_trusted_key_ops =3D { + .migratable =3D 0, /* non-migratable */ + .init =3D trusted_pkwm_init, + .seal =3D trusted_pkwm_seal, + .unseal =3D trusted_pkwm_unseal, + .exit =3D trusted_pkwm_exit, +}; --=20 2.47.3 From nobody Sun Feb 8 15:59:26 2026 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 110B532E728; Thu, 15 Jan 2026 10:05:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471552; cv=none; b=DzkrvdS4Ex8i4gIEp7x8BS0hF0eHwUaCB/LCqb8JQtcOC/YErP4R0Gy1xlllu7/pBswD28alXzxRUh4VuYFYcTgDmnl9yVbI8uRjKGI/G7XCADCs0WO8JoY5VRNsdjq5zbYvxLHxuYi23EVFMqjHzJefJPzBwj8gRrWcDtNCXHQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768471552; c=relaxed/simple; bh=aqRdULq4kucJKLo7juH0QAnXYCAWo1Kzpfc6JBUoEtQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UoGSvn9lU3ja8jZbksBE22Cv7gZ9EKqBg7d9HzjShBVyzdprgXLS5kS2PRXVEI/UmGn7dSYey/HKAAuNJsdQ7+n3Ao/k9I1nCLQtMJfZWQgjTCv9+fm7v0ORCZ9I85EvKZOs3IbQ6a20IryWZSuG6oF/ocCf9F6drjgGegPyq3Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=KtwXDZCw; arc=none smtp.client-ip=148.163.158.5 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="KtwXDZCw" Received: from pps.filterd (m0356516.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 60EJVYA4021117; Thu, 15 Jan 2026 10:05:36 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=56BhBO+/eHWjmoR1c 5fXFEtI4KtKouXiVgC1S4fhn/U=; b=KtwXDZCwHY2uLltHX3I9FZtQ13bF0cNBr XEeWb9/JrN8p1Q3GXwy9EpBBGXww29F7q1+hC71p2gZx4JQWOBigCF73ifCd+BhX 91WkCD9qalFgGHnwBg+nrO9SH/kRoIYi4mes6Ebm49g8jaW6zsV9Y9IMSJV11o31 Vwt0ctoBaTERzjpdAfuoYpK5jS7oKuo3fa8iST6yHdzuTNx8gKYxOfNmr02o9Gxw 4LHAlAIVbV3QOG3jwJhufszHGpNj90Gr+PfRdzmEK8+rbtCtPjZm+mAPWwv/aNWg iHkqCvJ6weUF9FL+GH46rkDmeEuuyUwhaMZVoTOL0iYiU9z6Fdxlg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkc6hdmyp-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:36 +0000 (GMT) Received: from m0356516.ppops.net (m0356516.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 60FA02Dv032568; Thu, 15 Jan 2026 10:05:35 GMT Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bkc6hdmym-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:35 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60F9UrZC031294; Thu, 15 Jan 2026 10:05:34 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bm3t1y13d-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 15 Jan 2026 10:05:34 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60FA5Uow52232584 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 15 Jan 2026 10:05:31 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D64FE20065; Thu, 15 Jan 2026 10:05:30 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5311B2004E; Thu, 15 Jan 2026 10:05:27 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.65]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 15 Jan 2026 10:05:27 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v4 6/6] docs: trusted-encryped: add PKWM as a new trust source Date: Thu, 15 Jan 2026 15:35:04 +0530 Message-ID: <20260115100504.488665-7-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115100504.488665-1-ssrish@linux.ibm.com> References: <20260115100504.488665-1-ssrish@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: ZZTzovOmBRFF-Skx-OJQ3W6LCbNzmlt9 X-Proofpoint-ORIG-GUID: cPQT5v8ryDtZQNLmHA9AtQzwWRPHZoHk X-Authority-Analysis: v=2.4 cv=TaibdBQh c=1 sm=1 tr=0 ts=6968bbf0 cx=c_pps a=aDMHemPKRhS1OARIsFnwRA==:117 a=aDMHemPKRhS1OARIsFnwRA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=ULK339cd-4IVAxCgyX4A:9 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTE1MDA2OSBTYWx0ZWRfX53EA6qxhzXln KM+ff8pNI6BelJLMdYu5YRGIwA8jibvCk1zuYtp/mvHMqwr3gxdRaPutETFqv+C6o7j1yNGlNkI OgHNbZRPCBnkiUl3anY26p5N3VsAgEvwEIcbsi9+MGqNPhzYc11+eVkDnJoWG10W4dsMVdAPxvs cL9+8w2U5kXpFhX6XhGTcPQdqYooNJ+eySCuQKPpkY9NzjEJ/nIuxnV3MmA3lzgqiy8Kfo96NO0 G3fXCWjjEnLpt8uvuk2G95r1EIHnBFzzXTK9kNyGJvsdvfSnN3jv2GR6BBGDFQMB1F3rLg54zLq uKc/0gOdUhBacfPOPr5XEcKL8aPyxqP3dSn4yubO6V7OM3bO6ER5PHsatSnTr/pu2Cut69ZCfkM YHpnGjJ2dTu41Vl3V7641SKOFILfB5wCeicK1bDQiGAcyDnvvHgWK56jlP08Pspk/gpfsYTm78K DK7tDBCOTo9Au8TNvbw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-15_03,2026-01-14_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 phishscore=0 impostorscore=0 bulkscore=0 clxscore=1015 suspectscore=0 priorityscore=1501 malwarescore=0 lowpriorityscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601150069 Content-Type: text/plain; charset="utf-8" From: Nayna Jain Update Documentation/security/keys/trusted-encrypted.rst and Documentation/ admin-guide/kernel-parameters.txt with PowerVM Key Wrapping Module (PKWM) as a new trust source Signed-off-by: Nayna Jain Signed-off-by: Srish Srinivasan Reviewed-by: Mimi Zohar --- .../admin-guide/kernel-parameters.txt | 1 + .../security/keys/trusted-encrypted.rst | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index a8d0afde7f85..ccb9c2f502fb 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7755,6 +7755,7 @@ Kernel parameters - "tee" - "caam" - "dcp" + - "pkwm" If not specified then it defaults to iterating through the trust source list starting with TPM and assigns the first trust source as a backend which is initialized diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentat= ion/security/keys/trusted-encrypted.rst index eae6a36b1c9a..ddff7c7c2582 100644 --- a/Documentation/security/keys/trusted-encrypted.rst +++ b/Documentation/security/keys/trusted-encrypted.rst @@ -81,6 +81,14 @@ safe. and the UNIQUE key. Default is to use the UNIQUE key, but selecti= ng the OTP key can be done via a module parameter (dcp_use_otp_key). =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Rooted to a unique, per-LPAR key, which is derived from a system-= wide, + randomly generated LPAR root key. Both the per-LPAR keys and the = LPAR + root key are stored in hypervisor-owned secure memory at runtime, + and the LPAR root key is additionally persisted in secure locatio= ns + such as the processor SEEPROMs and encrypted NVRAM. + * Execution isolation =20 (1) TPM @@ -102,6 +110,14 @@ safe. environment. Only basic blob key encryption is executed there. The actual key sealing/unsealing is done on main processor/kernel= space. =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Fixed set of cryptographic operations done on on-chip hardware + cryptographic acceleration unit NX. Keys for wrapping and unwrapp= ing + are managed by PowerVM Platform KeyStore, which stores keys in an + isolated in-memory copy in secure hypervisor memory, as well as i= n a + persistent copy in hypervisor-encrypted NVRAM. + * Optional binding to platform integrity state =20 (1) TPM @@ -129,6 +145,11 @@ safe. Relies on Secure/Trusted boot process (called HAB by vendor) for platform integrity. =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Relies on secure and trusted boot process of IBM Power systems for + platform integrity. + * Interfaces and APIs =20 (1) TPM @@ -149,6 +170,11 @@ safe. Vendor-specific API that is implemented as part of the DCP crypto= driver in ``drivers/crypto/mxs-dcp.c``. =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Platform Keystore has well documented interfaces in PAPR document. + Refer to ``Documentation/arch/powerpc/papr_hcalls.rst`` + * Threat model =20 The strength and appropriateness of a particular trust source for a g= iven @@ -191,6 +217,10 @@ selected trust source: a dedicated hardware RNG that is independent from DCP which can be en= abled to back the kernel RNG. =20 + * PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore) + + The normal kernel random number generator is used to generate keys. + Users may override this by specifying ``trusted.rng=3Dkernel`` on the kern= el command-line to override the used RNG with the kernel's random number pool. =20 @@ -321,6 +351,26 @@ Usage:: specific to this DCP key-blob implementation. The key length for new keys= is always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits). =20 +Trusted Keys usage: PKWM +------------------------ + +Usage:: + + keyctl add trusted name "new keylen [options]" ring + keyctl add trusted name "load hex_blob" ring + keyctl print keyid + + options: + wrap_flags=3D ascii hex value of security policy requirement + 0x00: no secure boot requirement (default) + 0x01: require secure boot to be in either audit or + enforced mode + 0x02: require secure boot to be in enforced mode + +"keyctl print" returns an ASCII hex copy of the sealed key, which is in fo= rmat +specific to PKWM key-blob implementation. The key length for new keys is +always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits). + Encrypted Keys usage -------------------- =20 --=20 2.47.3