From nobody Sun Feb 8 13:09:06 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 9AD1735CB88; Tue, 27 Jan 2026 14:53:04 +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=1769525586; cv=none; b=pAZ9glLw2G276i2FoqjStpL6G4sugslfZJGozUAzFWsFG8ZV16ir4I+eUciVwrVxaHP0P1pYTIMo3uQq9LKX0Uu7QXpWZ5sIXdUCzi2ijHGTG//f84Qba7dELEX1isx/rrbrhm5o1noS43boilG425SXl09sq32H8wXmrHsqyJg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769525586; c=relaxed/simple; bh=dmjp+2CMI6MH7K1MopbkaO5Ri8IoynfE18j1YzoEYxQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RDj9PBsyMwXK49xv/zxYWqGWNs8ZRDyuvDZZ1Lu62bbKRWIlES0wWAEkdaoN4gAZhkV0sTBMEAfWQj6efphxD4pf4R6xTYcmraKwUQoN53LiljGqCUPxcHfn7bxUPB3rM11hVV/hiuuT5c+VMWoaFnFY9G8yO/cL+8OFwxkajVU= 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=ffBkVM7E; 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="ffBkVM7E" 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 60R5SNNW005004; Tue, 27 Jan 2026 14:52:50 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=3JoSVGXgOOqDkL1Br tLuSCyouOoz4uH+xlIc0AifRIs=; b=ffBkVM7EJl9427/KfNu70hytzW0petgh9 Q55J/z/iY1FdgwYRlA2PgSfE/PUozasYrBXbsqZcROKXF5HCR85Ntpva429FBHgZ i2ZFeNMqvEIlFF+S8IgcyrWYTRPkfZdk+efHjGxmNEAOtB22f2AF2lU6YXNaZ0F8 K/tuftU9+fb2pOaODne6pLRDloTA53BokejMy1HrAHZgbeDx797BImrOscfFSzsk YTfc74UdOFEPKj+aw2V4Ooxh5pahF4TrDKdnMg9ZPUrloiLt/5+MatHSjuby4Xvj +rRm6tjG0MnL6uNVrpjkcUEKt0/Hip2A3jItid/+Oqeka1J7G/CGw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnk6x0mg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:50 +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 60REpw7b020033; Tue, 27 Jan 2026 14:52:49 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 4bvnk6x0md-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:49 +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 60R9ijMq018239; Tue, 27 Jan 2026 14:52:48 GMT Received: from smtprelay06.fra02v.mail.ibm.com ([9.218.2.230]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bwb41rs95-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:48 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay06.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60REqilA30015924 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 14:52:45 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C52EB20043; Tue, 27 Jan 2026 14:52:44 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 14FAC20040; Tue, 27 Jan 2026 14:52:41 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.210.108]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 14:52:40 +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 v5 1/6] pseries/plpks: fix kernel-doc comment inconsistencies Date: Tue, 27 Jan 2026 20:22:23 +0530 Message-ID: <20260127145228.48320-2-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260127145228.48320-1-ssrish@linux.ibm.com> References: <20260127145228.48320-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: EKsKd_FJSzRyzh5FYT7wZSYb6EnlJ2M3 X-Proofpoint-ORIG-GUID: rDfzJAB7AqM2ST11ct2iFk6N9N7AaKAH X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfX46dGf48MmZv5 LITZAyDLdE6O0nii4qjjQGxoVbQSh/39g/LX4A1+FlkSpCZ/J1vSdn2jqTzgjmzyCniZ/hCEnPX +juJZOvPb27bYE524rpwdxEy38+cvXML1hUGg1SoFa+zulhbBTNRFZ84MtvCy2vulNbSEb+LRyQ lel7QlHUknoRc4qH7f3ZNtBBxrjUO/R9S5dssj5tFf62DFix98eSpys493j6mSdiqwsKtJ2Yqb4 Y9MpL8Df2t5sqFvivbsQ+XJqqOE047Ph35u98wurHvjTm5BCKOaTjU0HM6e2ibWh7vsLqLxXPpL EdA5lIftbnPeNdtOkguizE4M+zL6PFGENNXag4cSPpRixMkjnnKukD/4BC/CBzkS8CCNwY32SfZ n6Yw8+DNuItYFI2INs9Vdv/YV/VCkTAYUco5wg27VZwuDTQEMs42ZlKJqWXEONaaWgO5X7J68tV vFY+w6brmFXDcLzrxmA== X-Authority-Analysis: v=2.4 cv=AMiVTGgp c=1 sm=1 tr=0 ts=6978d142 cx=c_pps a=aDMHemPKRhS1OARIsFnwRA==:117 a=aDMHemPKRhS1OARIsFnwRA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=_jD9v-G-JNOk7KggL9IA:9 a=tQW_-zY1P7yUjf7c:21 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 spamscore=0 phishscore=0 bulkscore=0 suspectscore=0 adultscore=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 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 Tested-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 13:09:06 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 8E74F35CBDF; Tue, 27 Jan 2026 14:53:07 +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=1769525589; cv=none; b=BLhgDv0j4o3MaXJDfUcQA+xyZrgBhmYfCAp9XTpo/mvYiZML8ZUFlFDskxracUcVmB+gaKlh3bFNH7OXecckTLUrVsX5WA/pA1KP7+nzgYZDQ74IXdNCeY/A0XMlAQ1c/GzfavCPszUvMNSkAhntXQlpF3HgdStudbXNrgHJXGE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769525589; c=relaxed/simple; bh=n96lxtGmFO8PCQ0oAyAKohxV6wC29k0MlSoCJIpHg5U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L057FcIqpAlU3LUa2flWi9XqHY7LTWXeuigXHs/S9/EBnPtYjQzGsnJ0elnbv65teqU4wJbA+CA33Z61YR3Bg9SfXRG/1/FAN2LshtnLKuZntCXgvz0wd3dbDXaWUPqjAXrHVyV8+xN94bMhQwyPsOAvq4NS7VP0q45+Cv7fejY= 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=qJGsqv+F; 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="qJGsqv+F" 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 60R7HbTo014420; Tue, 27 Jan 2026 14:52:55 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=cFktFtYyCo8QNn/+D MS3S9VXpGTnxROdndKTFBK85H8=; b=qJGsqv+FagNX7BS4+7g92C6Qy7faeQrEk O9K6ORk6gK06j3/019qgj7hocS2NrsjlPusHSBoZeI/NTpZl6rBaXiNAJcV+kKcQ MicPjgdR9MmrMemyUJyPNki7GXO7660olYAf+rBMYMzKkcwKVPtHCw3UJ2s2P15B 8ESYezV317K4gEKaB9/dyut2r79Px6iFDSoGedNJKkWlZ/K3Nbw9qBa4pnRzyr3X JjjT3/nN+TaJ2SG0Lw0CFQYbXYggIOy4aCUC68ZRRc7lqF6SZwFzgrHEMHVuka/w ZXTMhPt+x4t9vf9rXxI3YkEYxDhbRR/jP0LyYPIlA5adcmOebL4jA== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnrtdvwu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:54 +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 60REmJm4007621; Tue, 27 Jan 2026 14:52:54 GMT Received: from ppma21.wdc07v.mail.ibm.com (5b.69.3da9.ip4.static.sl-reverse.com [169.61.105.91]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnrtdvwr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:54 +0000 (GMT) Received: from pps.filterd (ppma21.wdc07v.mail.ibm.com [127.0.0.1]) by ppma21.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60RDxiXK019733; Tue, 27 Jan 2026 14:52:52 GMT Received: from smtprelay04.fra02v.mail.ibm.com ([9.218.2.228]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bw9dn11yc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:52 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay04.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60REqmNL15335838 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 14:52:48 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 925C120043; Tue, 27 Jan 2026 14:52:48 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3487420040; Tue, 27 Jan 2026 14:52:45 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.210.108]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 14:52:44 +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 v5 2/6] powerpc/pseries: move the PLPKS config inside its own sysfs directory Date: Tue, 27 Jan 2026 20:22:24 +0530 Message-ID: <20260127145228.48320-3-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260127145228.48320-1-ssrish@linux.ibm.com> References: <20260127145228.48320-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: XFUpgWJtWaYMUNZ2pGAkIrnGOkedQdTA X-Authority-Analysis: v=2.4 cv=Uptu9uwB c=1 sm=1 tr=0 ts=6978d146 cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=mWGr4ncSMiNchjaCnzgA:9 X-Proofpoint-ORIG-GUID: q0Al12uGyOxaDH1cj6Q14BTkVcwrz34W X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfXwUBAW0wHfMA/ OecT7GD/UZaiI9skQCQ8WEwVelTSxKY2N6psLHz5G6rmFynsAqQLK5Er0BnzNU6jPOvSIrsvV9O qZ7jzr5iUBJbeDz0yWAcweD8kTeoEqQRN3r8xMg2GB7eg8jdJ6jP8v1EvIAlyvfloUIElT1luee GBNbVI+ciritwZmp4Z4djqmcuaqxwKgbMulN4S0dICeYlNmntxOsTnuX+6tSoPBS1MsdwgK8LVn +S8m2XtVwzkC+XzpIOSjSWGcVsdxrG187jbA9JnXaKesstxUHZXNSeODfDjc3JZ6glFz1mK1n9m AMN7NYGwqTagpKOZug2bZfHPnVeQ0at+fmROEtKtmFPDF92cBfhALw2ewiFC7uNP46X4XC9b2bb eE6S8XTYsGLGPCKfWhMhIHaA7cudAmMW2yFKe4VAA35nAd1c3poMqtdkrKh6ELHNgS9pg+LiuHe Ai2OqqxIAAqvtcruhWg== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 priorityscore=1501 clxscore=1015 lowpriorityscore=0 phishscore=0 adultscore=0 impostorscore=0 bulkscore=0 spamscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 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 Tested-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 13:09:06 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 49EBA35CBB0; Tue, 27 Jan 2026 14:53:21 +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=1769525602; cv=none; b=EWZuzrsSsCZKCU8/pTVvWtYAeT3Iqlb2Kuo5aqAN4Jr62srje2Sf1l1WjIwgk9xBnNG/yHJqlys8rbJ4RVIXM/7RCS0US5m4hH9ev/EGXc+Gav15g5eo95HeIIDFDwcEnuWqZ8k4e9xUWLIJm2bn2PvPOk7j+I10hb+KnpvPCg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769525602; c=relaxed/simple; bh=7WJCWg5C8qW89dkLabIHd+gy9ZBPk21P/HFm+LlYKIM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Nfqk8TWKRELhAnGB0rTNruai/WGqEOBLwdOWSNcqkExYxUDK9U+p4X7MhcoKtC0Z0gLYl7Ik7ayiM/XgU0O0PQFXSe41kXj2auWVW9ub7B0v2bdpSGov7qchbrMvMmr9wkmMGLigN3m4iWys95e7FJHRzRnffY436aTGoUbtJhI= 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=U7DSf0yb; 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="U7DSf0yb" 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 60R2MIU6006601; Tue, 27 Jan 2026 14:52:58 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=xb5SJrpsUr6/RMJxx hVCuaDeY2htXoH3IpJC30FEMzw=; b=U7DSf0ybFPJ+SSWYb2MO1tAKrZihKnxeW 5YkX289hG90OCTfAaacGO7ttwT9YPN2TOChyFbKEKNdqHoIbGbL79H/U+mwC85I/ WVoQQ4PcHaVm33VyViG9KyCDnRsUwxmHuPmk8yYoubEdl+bEqVE4T+ZkpEBOWp/N gQgivbNNwdeDav3lzh7TGOniXPNNCeY6O/flYTVdHvTpukuRbWpVHrIgFScr70g8 gM8xAq8bbyqu3OW9aMlZf5ttSBLpcnfv9pTBZMSYE/Lcv1lr5IGpLc7M5bcp7vN1 BeUyLAOVcsKfcxI+qvJwmyG+6s81lJv0GSjjFRPxV3l7yvIbQJspw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvkgmmf92-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:58 +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 60REN4Zt012114; Tue, 27 Jan 2026 14:52:57 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 4bvkgmmf90-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:57 +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 60REgn1n023641; Tue, 27 Jan 2026 14:52:57 GMT Received: from smtprelay01.fra02v.mail.ibm.com ([9.218.2.227]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bwamjrus9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:52:56 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay01.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60REqrVJ48824610 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 14:52:53 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F06BC2004B; Tue, 27 Jan 2026 14:52:52 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1539D20040; Tue, 27 Jan 2026 14:52:49 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.210.108]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 14:52:48 +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 v5 3/6] pseries/plpks: expose PowerVM wrapping features via the sysfs Date: Tue, 27 Jan 2026 20:22:25 +0530 Message-ID: <20260127145228.48320-4-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260127145228.48320-1-ssrish@linux.ibm.com> References: <20260127145228.48320-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=Gr1PO01C c=1 sm=1 tr=0 ts=6978d14a 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-GUID: 1SNBvMGQx0hK2bnxD5iIb-_xVsLtDteo X-Proofpoint-ORIG-GUID: lRm3PORmYgCtaPKqaE5BtkZe3djJt-hN X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfX7m02MwOf8QnL vg/Smml79IGjKz0OihZDt2xLBD6TcVVLtDp0vGSFBTcrDCJQv+ri/UgxDIaTcEDMnZtf/B0wcdg +mUNk0LQu9fTGRWlFiM9PiRsCoyhnAtYuWNxrAVIiPWwuuGqcP8UyumKZlFU//yrin/qotunK8V LmhMaicAEkhqWx/BIKOl4RmqIT2ZgXAr1mzDkAGQvXdTvyVx0NvIUJPqM4yDSTXzJMUgo7LBFvW liwuVhpQPffcZA/dEVBJOJm43ImGKqQ4zzvxIhoLt8ROMeJPXq1h3lQMyttZwlM+195LrAdjJFz Pp1mN9M0u36Geyu2YvGSd/p78gT9AMqQmCunsGT2BcnWR0p8BARvmX5ruS7v8v7/l0g8iq+OGz/ VJY/kcMCT6MW3GUbCV9kzWVGTAIhLi+IOZfEUgByhhbuoO0IXeheWoQKi099ToSvYAUuRHIgmyD K3N0WzGr8iauabEZ7Og== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 clxscore=1015 lowpriorityscore=0 suspectscore=0 impostorscore=0 phishscore=0 malwarescore=0 adultscore=0 spamscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 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 Tested-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 13:09:06 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 CE5FD35DD12; Tue, 27 Jan 2026 14:53:24 +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=1769525607; cv=none; b=fBTy/4CLytcGdiK4V2KrN78IpwrdegEqPbMjETL55hYa4Jx/sja3Pd4gQ5iIKqS/wXH86d2NI+/C/W8nCoI/kNJLOndhKbmR06+vStSqSjBD3yvMCTvWktMa+OPKvSYyXtlgacmJBUmjAkilFiYgIoPlUOSNwhv1FRs8zwaJAYA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769525607; c=relaxed/simple; bh=y3ks8vciy7VCVy0nXBy8GhcqEKRxjBszZcFcig/SlP8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TLl7Yy3DG7p6AY03/jG/l3yCQjpnrFabG+duKIzShmiq6zs4KnNvLUUZuF6cTawLHfAyAX4SxdtgQJtfylIdS44Jk/WSRm7peH+n5jC6JUSCPqBWvecJQgsqiaKoxoKPKJru2HBkDynF3G7MTBjiGiL9l4Zq11soFO+4N0l2a2o= 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=CNM0sEXf; 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="CNM0sEXf" 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 60R8OYOo016222; Tue, 27 Jan 2026 14:53:02 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=9Fm0jSaawrywiM+j+ JokalnFc+ZmwEdF3JyuNbZO5uQ=; b=CNM0sEXfgjZD5tIqqLDPqq1RZe1zHlIjP jOVNG2eKT6y4yYa2utjyeOthJh5ugOZxu0eJWejRzMEexIrDbkjKwwFwLd2NRIoZ MefyAI0PdVYEBnySDYsi6BaZpooaLb7yabFrlmvjaCC9aaXMvz7SAcf2pV50xmqW x9Pe4od0ZKNYjdl1cBFF5dDXTWVy7kmRhozkmEfUjjXXKWfnQmJH3hlAhpOC7BKy fVnX33R53mqL4jLlEZDTzLpeMxdfOVTWpr4LF+FnWjt9ohMoJasdKhKh/fyL2OuM O7IgAnFTIfaydfxIQATXWnB6K+d5ObchtJuAS/p0F82AEJyB6fOYg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnr644fj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:02 +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 60REhpsP020393; Tue, 27 Jan 2026 14:53:01 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 4bvnr644fd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:01 +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 60RDBE3a031067; Tue, 27 Jan 2026 14:53:00 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bw8dsh4he-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:00 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60REquTo46989700 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 14:52:56 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9C67220043; Tue, 27 Jan 2026 14:52:56 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6CA1720040; Tue, 27 Jan 2026 14:52:53 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.210.108]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 14:52:53 +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 v5 4/6] pseries/plpks: add HCALLs for PowerVM Key Wrapping Module Date: Tue, 27 Jan 2026 20:22:26 +0530 Message-ID: <20260127145228.48320-5-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260127145228.48320-1-ssrish@linux.ibm.com> References: <20260127145228.48320-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: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfXzAQGl9mHYPId iWxsvAz/KVoADaEz8ZpAfuLpWywF70mElwHTepasMd/HSmMUYuIXXeAsIGlonebUH1v2unoZR6f UwEDtotUfRqpzSeAw90vdJwGmMvkOt4QjnBuL3w+W/tKsmYKEKcWgIb3sThmTwel8D2sB8pJe61 La/tZV4DkO38uz3BfXDnK/IIyzRSe27Ul5fBG7vXHVO/rR0XPoM2ujvigJRPv0Sl/07EOtJLeKj Dbi41aWovlZiZhfbTmnsxyPPzLc1Hw0Y/jK/UVJAp1Hc1V1aHk7qp/ZZCKlPg1YOwXL3EXUajTx K5p1/SCeOXMNsfW7Ccq3nqyBN04wnP8+yb8RkEdfDklqPNtIkLS0MzOEMHsXSaFIgWtpa+ynjUj 3zV1Izcnv4VH2mlsY0jyXM5wp8INhh6sauVTn2oXvaEkU2ar6EK6x0+46EJL3pqb3+4rDPETLpI Gw6+fwPBIlUY5Q6L9dg== X-Proofpoint-GUID: rXf7kBJpVpDe7ER1usz1NYs5q6P5weJ_ X-Proofpoint-ORIG-GUID: b0VZXbCFY5a4jrZWNjwDB6b7lLSWqF69 X-Authority-Analysis: v=2.4 cv=X+Vf6WTe c=1 sm=1 tr=0 ts=6978d14e cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=nO4dFLMeAchwtJrxA4IA:9 a=POYjf8jjcDEwoKyR:21 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 suspectscore=0 impostorscore=0 lowpriorityscore=0 clxscore=1015 spamscore=0 adultscore=0 malwarescore=0 bulkscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 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 Tested-by: Nayna Jain --- Documentation/arch/powerpc/papr_hcalls.rst | 43 +++ arch/powerpc/include/asm/plpks.h | 10 + arch/powerpc/platforms/pseries/plpks.c | 343 ++++++++++++++++++++- 3 files changed, 394 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..038ecf8f6d6b 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 @@ -19,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +66,7 @@ static u32 supportedpolicies; static u32 maxlargeobjectsize; static u64 signedupdatealgorithms; static u64 wrappingfeatures; +static bool wrapsupport; =20 struct plpks_auth { u8 version; @@ -283,6 +311,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 +643,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 +728,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 +825,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 +883,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 13:09:06 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 AE1BB35CBAC; Tue, 27 Jan 2026 14:53:21 +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=1769525603; cv=none; b=AaTZiyrjP3OZgsoF6jNnURQjJSWWenYkhJBipvKkwYj5te2M8AyJgK34oUQxzmo4B9llA5gjOaM5yF0sOw0vJqz8HswvB6x5Z/wDsMT0ZqvUwSQ1Q/de53Aishgv2zfuzogXBOXN3BWG4WXiV0eBF3jvzZZePhpInx7/mzrfAUU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769525603; c=relaxed/simple; bh=D93C373ERKE6CXC072YWdxWteWjBB9M2B93+pBAUWps=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZFFqee1lXPx1h2k5S8FotcY+mkEOcdgnYJWPX8ZpWpPiyaa5JreXNvmTJzTYbrpNs9Fdbzn9CAuM/xDkloE/LL8f8DDvR9VMvfglQHp68jTo60XbFTNNKuTXY1db0HGcko1HfPbnz2dbZpjSptkZznVH0c8m7pFaoSATkJAZDCM= 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=snDk7JvQ; 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="snDk7JvQ" 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 60R7SZG7002736; Tue, 27 Jan 2026 14:53:06 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=5hV8EzVyEZxFjbyqf Ov5mEfzEE6saTP9On08fm1vLoM=; b=snDk7JvQoAZ3i5ufYyFr26JI/l5qGWRXM hGoOlfTKuVZqls3K0zS5sS8zYDClB4EKt2SxVS470o/hO2pOTUbuXNoDkN2chCP6 BHC8gUx+vvQYOKa5HbMMcFSJxZBi0Z3p5mJv8OVFg3WGQRhvKY85XEm3WaHvw/gm j1Nr7TfgcTrwKA0P7jkCV6PR1ZJusuJivHOY3pJFRMocvxt7DayUxH+2OwhvZaA5 fWxg3BoR/q+Vx6JM7Rb+eZqMMHOxx5tOYOQakBF863NkvxlYtU8wobtOxxz5EJs+ WhepcKcVwcJnrZZNY6AGYaM529WLyD1KCB/DpYWwC1vhutW79SzJw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnr644fv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:06 +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 60REDNM3022668; Tue, 27 Jan 2026 14:53:05 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 4bvnr644fr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:05 +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 60RDnl4E026333; Tue, 27 Jan 2026 14:53:04 GMT Received: from smtprelay01.fra02v.mail.ibm.com ([9.218.2.227]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bw9wk8yta-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:04 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay01.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60REr0G962718376 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 14:53:00 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BC55A20043; Tue, 27 Jan 2026 14:53:00 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 245C120040; Tue, 27 Jan 2026 14:52:57 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.210.108]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 14:52:56 +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 v5 5/6] keys/trusted_keys: establish PKWM as a trusted source Date: Tue, 27 Jan 2026 20:22:27 +0530 Message-ID: <20260127145228.48320-6-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260127145228.48320-1-ssrish@linux.ibm.com> References: <20260127145228.48320-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: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfXw7c3D9waQSD6 lybGL+P7ENuUxDdcH31ZCh4NK4AjZY5Z5nGo5RIf3QWz8RO4JDQhNyDxKFcsuaux6M3WidJWE81 th4MtqFsnKH3u7dha04pjhGaRgp7ggN/g9TfRU9qfuSpH12JKORjyRgsOCu7Ax9bB7PzPB9cW7P Fs1GGv6ybC+4IMFSA9CKazqHEdRJvJJQgiiwp+NE/uA6lWTKJrvxVWt78KKIT9DgjwX7Qm9Xez1 1cKzb5ZplEieDaNYSFeVOdJ9xWVAf3xEwVIDvxNQ/te/77gHXF6G7hHXOL96Mft9/6PZ5uDJV6j wXYpez7aL9kdu3Hq6G6w91utetPWJTUkU/sVxpyhQLTjWXlax3G6Dcx7usXGaP7k0/rSxMsQvfu 1gJUAiJrQFfseGlH0rXhr9ItKOWzn8pk05l2XZTKG1jR8YQEibQrvJbnddgfTLycSbGWGu/Q2os Fn5CbC3f461xD78SwBQ== X-Proofpoint-GUID: T98r1wBsWCmUBipXkPAvR31vKe5fA-Cy X-Proofpoint-ORIG-GUID: fVfOpHyhrar9nxscYnnJyku55Odx4OSS X-Authority-Analysis: v=2.4 cv=X+Vf6WTe c=1 sm=1 tr=0 ts=6978d152 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-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 suspectscore=0 impostorscore=0 lowpriorityscore=0 clxscore=1015 spamscore=0 adultscore=0 malwarescore=0 bulkscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 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: Nayna Jain Reviewed-by: Jarkko Sakkinen Tested-by: Nayna Jain --- 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 67db88b04537..7ffa45b903d6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14014,6 +14014,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 13:09:06 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 6A8A735CBD2; Tue, 27 Jan 2026 14:53:23 +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=1769525604; cv=none; b=Of2fOj2CSwybA/o5DRkxPYCvXG0a9CHKf0sY8xGbEJqZZhmpWii6S3eTzp6wV/OcyRyig7j0FwMV09iEp0HFJ3cEmV6/ip3omgWbC/6WGKqS1rRsmQTNb91SL13ar2+nea5hgaNoG44uVDWz/QF/gRBDkgAIORYGdmLCyqDNLSk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769525604; c=relaxed/simple; bh=XCefpgXUxyNEKk/AXlmykIVBUmEW8jSfP/BPAzjGEUk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KChMuCpEMNgP37ZFay/rw5lAAkrWQbU3hBDg7+lA03w0RA34Sf9bNDZ9lTT7UOVFLb3uvGcl+PX4ii39EMh2cx2gTmN2Vn4q3tYnluDJGF74BK1q9jqnkBVYCLZtWm8wO2nw2CSpG1ByjJjA77lrefN9lrJG3dux7HmasRcV9aE= 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=aIIK/G6D; 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="aIIK/G6D" 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 60R7ARnZ014072; Tue, 27 Jan 2026 14:53:10 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=3AlJIuHueyJfodCUq PQr+cGMD8wjDvVNfPBSHGCosjo=; b=aIIK/G6D7xUQhPZveW4m6hEsthJMthQDr dnKuBMl7mIzu97ifjyAm0juOrlxGC9Xa5FeZTBznYyTG6JGKHmGxw+6/cG+oscp+ g8MsNpRBG+9ggvewJVnB0Te5ncPkAvxktuKMCG2GuWuWa5MFKAhg3lfcZKpBUAiy RIKFCN1MWfq9lZOdnNPXgPxVw2F5XGRUGql+mbss8IQowuwu/Avx5d0b87bL/UtJ 0sMre6oPIvVY0SSFeuVXNY2F5Pte2B9SYDDEXG+68oKW+ojG7H2jUFceecI8tbjZ CMiYlQORWgGOoOJ3PPQIUIXHrzF9SguEAFb04QiLW/kxmJOnZ2t5w== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnrtdvxv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:10 +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 60REr9mo016361; Tue, 27 Jan 2026 14:53:10 GMT Received: from ppma22.wdc07v.mail.ibm.com (5c.69.3da9.ip4.static.sl-reverse.com [169.61.105.92]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4bvnrtdvxr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:09 +0000 (GMT) Received: from pps.filterd (ppma22.wdc07v.mail.ibm.com [127.0.0.1]) by ppma22.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 60RD0rg9006737; Tue, 27 Jan 2026 14:53:08 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma22.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bw8sy94r8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 27 Jan 2026 14:53:08 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 60REr4Bq46268850 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 27 Jan 2026 14:53:04 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C46A32004B; Tue, 27 Jan 2026 14:53:04 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5D41220040; Tue, 27 Jan 2026 14:53:01 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.210.108]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 27 Jan 2026 14:53:00 +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 v5 6/6] docs: trusted-encryped: add PKWM as a new trust source Date: Tue, 27 Jan 2026 20:22:28 +0530 Message-ID: <20260127145228.48320-7-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260127145228.48320-1-ssrish@linux.ibm.com> References: <20260127145228.48320-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: eGqTO_9vNmTSjSLiqNmrGVdlw7BiDUz7 X-Authority-Analysis: v=2.4 cv=Uptu9uwB c=1 sm=1 tr=0 ts=6978d156 cx=c_pps a=5BHTudwdYE3Te8bg5FgnPg==:117 a=5BHTudwdYE3Te8bg5FgnPg==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=ULK339cd-4IVAxCgyX4A:9 X-Proofpoint-ORIG-GUID: JLSNF7j7hRtVaLT0RnF5jsQyLH2OEOz1 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI3MDEyMSBTYWx0ZWRfX4cUkFswFFsJu EuaOOor/xWO+QGKh/XDApT/ukR/Q/OobJEubvDEz0NlpBlY1EDYjTbV2Y17SCRsK/dMuGjMcSfE SIAEmmGwUweguFUDoNQ6YrA/qRWYLVjR3tym9hemdvEA+VJsVQNFbKMkwqjwil67QwCPmSPAzgJ hW1KLlP1v2MZky0QfrMITA6iEpFRzbAyRnhWMWFx1YxDAs3nllx0Fr99hAeforozwebeGupCfhV mZ2ZqQjosAn1r6qotjNkElrW7GHKcuIsAAx/MH7rykD9vEyAaZnxrbEO19pvUNbN9tnRkwojcMY BnS2vQeOfVt7lpx7FqnTF8YFGtYTa5cX2F5sEn0lv+wDoFExG9tyO6DiUVwed2EYo9ZKrF95tLt ms6AXg+yplXXQ3vjpOPzzcBVWD+qIQncc2cr+Q3ZqZR8N04ZY6bCeY4uCnwhzrCYYHbRwuRMvsL owgX1CA2Z5WKjk2ydJQ== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-27_03,2026-01-27_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 priorityscore=1501 clxscore=1015 lowpriorityscore=0 phishscore=0 adultscore=0 impostorscore=0 bulkscore=0 spamscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2601270121 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 Tested-by: Nayna Jain --- .../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 1058f2a6d6a8..aac15079b33d 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7790,6 +7790,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