From nobody Sat Feb 7 13:41:47 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 6F9F133ADA8; Sun, 1 Feb 2026 14:00:12 +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=1769954414; cv=none; b=M/zCR/DOzHxG+6biHpv+Qnrv06qLZiGG2XZ2liNIE5sAxPLMCW/IwiKaNwHUWATRfg42qCyAh8G9NfXR9DfcUqUjg6LejCLaMeBctkr5UOhFGEw9o+JFuCohrnytiLHN3PtvtGZEusE/Vavq4FOxlh+PZyda0/0NkbFUazfDemY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769954414; c=relaxed/simple; bh=h2rPnqdUjlC/2anIjbKI07xGV38lcrsncM4x8N/x+4s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WPhtjZPA9SrJX6Y9VkYhYQdSJIiVB3L7bbydoltfd9DGpG7UBF1NnIAgzsFtyXp16IMQbhfffiF7nxhm3aalUxuFfLfYS/Gec4PgrRKPE3nFv3u/zd6AS7xJVYkH6QYU3B0Jb0d2Ev3vH4MnKnZgYmuvYsZc/12fLlmPco0O/dw= 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=ksL6SpQj; 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="ksL6SpQj" 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 6119uCI6026510; Sun, 1 Feb 2026 13:59:44 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=1L34ePcbZI2PV75Rb gNaWlBUXbZOXn27dYGuhzId7PI=; b=ksL6SpQjp2AcDukLkqxA964l75LiGkUbY n6su4lKY/9Ak2huYql1RjvntMrlUY/YE7BQzIyAMfWwKC4U2LWYvo0OhhbYu87e3 9l55Dd4KX8D5UfiMwQtJswN7n/QFlb76CDu2mg4LnxyWOmT3stJCR6W2z5Mb51Mu wpZfo4sN41lQ27Ge1pSLv2krRL/OmjPIJy1WVvcH0RmJQi+LNqlQFuMylBIlJMcF 1MerOMsVgWnSI7ALyq3dJ0lTRQc/GuIn/eVAzFi0uut5UcEwT4dhTGMxllhzlh20 21PcK9nkEfPwwRYj45recTiccDdUDbQ6WnWaMTPKRekEMb97FxEVw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4c19dsvjax-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:44 +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 611Dxhvd011390; Sun, 1 Feb 2026 13:59:43 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 4c19dsvjav-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:43 +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 611775Vu029082; Sun, 1 Feb 2026 13:59:42 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4c1v2s1rcq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:42 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay03.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 611DxcZ141877908 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 1 Feb 2026 13:59:38 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B0F0320040; Sun, 1 Feb 2026 13:59:38 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 24E372004D; Sun, 1 Feb 2026 13:59:35 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.39]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sun, 1 Feb 2026 13:59:34 +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 v6 1/6] pseries/plpks: fix kernel-doc comment inconsistencies Date: Sun, 1 Feb 2026 19:29:25 +0530 Message-ID: <20260201135930.898721-2-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260201135930.898721-1-ssrish@linux.ibm.com> References: <20260201135930.898721-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: AW1haW4tMjYwMjAxMDEyMCBTYWx0ZWRfX+DzDngfJNrcF E7DMQvCWgBb1wjqCvLX/bYXUNKm41KfNPWWzbv8Ixa8dVl9CLZJn+41A4gM3Do9cRy8x4mzj4Gm vjP0P6jgMxugTBuRTS98bi7ZfKf+2D+Zvu1lK8f+YxNo4pVy+XEIk1xXbAHWn9L2twfapYhRhOc dRdOch1ePBQrXuU8d9PIdZWW7NyBU+65DApE2eoXTlE+numgE1aH37GPDx497FonrZ7pMGf12Wh XkJQkZ4YvcH8yCSdCcgRjb+0HXrnId3UiiD06X2Ci+soFVyZvnvGNdP/4d8LutI7bDD6dHavIcv a+YDtLM4x0hEqQ0W1jQ4Ie99YgGLFgqxviEm/voRJRtAscyHWFZUXNcVGZ1d7fAyzv9EkVLGx8r 8obpVDiQ2s9i5uhFWxBBnPw2hPzS3nWDjZg+kdj/mYoR8DSzRUE7t+mxnrGGotTKC9JREPzPnWd zgY6/ijzoCw3RpJKSmA== X-Proofpoint-GUID: dCFHSulLfy8bkHMubi1HAtJU8iWnQhQQ X-Proofpoint-ORIG-GUID: kgFF0d8KXjCrX_ggS2JfyNgDrrRX_2wL X-Authority-Analysis: v=2.4 cv=LesxKzfi c=1 sm=1 tr=0 ts=697f5c50 cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=HzLeVaNsDn8A: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-02-01_05,2026-01-30_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 impostorscore=0 spamscore=0 lowpriorityscore=0 clxscore=1015 adultscore=0 suspectscore=0 priorityscore=1501 phishscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2602010120 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 Sat Feb 7 13:41:47 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 741B6339B37; Sun, 1 Feb 2026 14:00:13 +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=1769954415; cv=none; b=exy570MocMFnK6GD4boOUVyAJsJbaCc2aH2g0da29tOLoxHCnUXSYVBPLgSGn4LaPV2iiUY0h4ZL835/j08pkh5S4XbSMbKthnr2d03TEvAf3FXVCHLIy6jujLhI62cVL1bfuS0lmCDn82s6jpl0m9y70v5OO9MNAz57BjUPI+g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769954415; c=relaxed/simple; bh=58z831xEZjotF1JqNM/2tMwZGDuce+3MSvtLQ6FXC4I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L29QvnQ1ygPFJZt1PU2IkckomD3T2lhSmRFSW64zQdUvYbp/NEklt0LibPe7X2ZzoGCkj6VyfnjRq2ZpbBifaeDIOUiMlh0V77CDpbhjlplkDrOaHuG0aDaPNcFryLb2vfPPvQmR4TaAfeYMiUHiy2vDjxN/3Rva5adize2/0GY= 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=I60oVpqP; 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="I60oVpqP" Received: from pps.filterd (m0356517.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 611BDi6w006540; Sun, 1 Feb 2026 13:59:48 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=PXEl5ntH2yB3D9QQh QxsIoEGl7c4wijnMH7IySeNjT8=; b=I60oVpqPux3+LXJKl22a5UjdeDfNwYl7a doOD2UiXNIeb3YOf35yJYeDlCMKtdDjMTVd6EfzpurN9sB7ZUJA9Knm1YG9dxOzJ 8mej892Xuk0HAQfFMrteoY6S53BM7Kt09QSHEuaxgjEn/GGU5ag3QX7u1dSPUDDH QLidRXqE/Xew41hNxR+tKvfE3CrVaHye1tXpe80UwB+6X3pJMz4XK+gu8Vvupvc5 861KQTuatYrTQ0oNMXi3OozbwpCeZ62OgXO8dIT97dynTuqejy8tuFUl4HBuSu4+ I0hQ7HzkD61Ii1SmH+ewvb7P/7r7nuUSGnbnHKVOSGsh+3bCzHC0Q== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4c19f64jxr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:48 +0000 (GMT) Received: from m0356517.ppops.net (m0356517.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 611DxlaA027339; Sun, 1 Feb 2026 13:59:48 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 4c19f64jxk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:47 +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 6118rYCD004422; Sun, 1 Feb 2026 13:59:46 GMT Received: from smtprelay06.fra02v.mail.ibm.com ([9.218.2.230]) by ppma23.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4c1wjjhh6q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:46 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay06.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 611Dxg3c19530030 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 1 Feb 2026 13:59:42 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7A81E20043; Sun, 1 Feb 2026 13:59:42 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 2118820040; Sun, 1 Feb 2026 13:59:39 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.39]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sun, 1 Feb 2026 13:59:38 +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 v6 2/6] powerpc/pseries: move the PLPKS config inside its own sysfs directory Date: Sun, 1 Feb 2026 19:29:26 +0530 Message-ID: <20260201135930.898721-3-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260201135930.898721-1-ssrish@linux.ibm.com> References: <20260201135930.898721-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: 4RE3I6p2rvjNGfRoKsWNFqxwvS9vaC8- X-Authority-Analysis: v=2.4 cv=drTWylg4 c=1 sm=1 tr=0 ts=697f5c54 cx=c_pps a=3Bg1Hr4SwmMryq2xdFQyZA==:117 a=3Bg1Hr4SwmMryq2xdFQyZA==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=mWGr4ncSMiNchjaCnzgA:9 X-Proofpoint-ORIG-GUID: leH-8NybOkIi7CiXPy2efX8duDAKW46o X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAxMDEyMCBTYWx0ZWRfXwNw3cDk74Ka3 IqltltVgAEq1r84356rzXdQus3IAHPrj+hT2Hpe2M6VIjPl2uA76PB1q+cJY+eMsWA2TvdqSjK3 ijvEa1cPCeojXTnPyhbJMP3Ky4hqpzmFviWAhf5k9fJzfWuPRNJbtl8th2vy1h63gx/gnhXnGOO x8zqE063QAP4QbCOSyjOyeS4K/tQh67eBcLBADE5iLH+l2qiBD8/P01dKnX4ZEhKf0Wi+OLdz/g ELDP4XL8aIuo0tByd0WYA6mrRKWG+yQVInT75xLB3xQmi4UEJgdVmKQhwKLeN60SrvxWcsQl5gF KaT2+BRhGVzOxikEZpzGwAfX5iDbqUNBm7d6VZ5bAWEi9T+5IJtJBwc+pyW0GTDepQ0ZbeT4Jgd NUTMzQBP/kZVBm05NXImZzTMrySNo6QpRDvj03X2WvtsQ6/J73MWY7xd6Nc09e8TG/+LIU8kmcF hYu/nqwMZkGkNfbhSdQ== 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-02-01_05,2026-01-30_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 clxscore=1015 spamscore=0 malwarescore=0 bulkscore=0 phishscore=0 adultscore=0 lowpriorityscore=0 impostorscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2602010120 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 Sat Feb 7 13:41:47 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 6F9632E5D17; Sun, 1 Feb 2026 14:00:12 +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=1769954413; cv=none; b=ENbzcm66lo86WRYU3lAOl+FV2w1Kh47GfREOKXxSwTVGdVt5mpUi4cXP0ZliOMMvsAwZJZIHKqd9+4xNlJQ70lWWNNtbBNHBXxlVqj7djgiM1PFJYiTlv5mpnNhfuQBOvLEXva5yLKh1Yerc/bXGYFTsALh1KDZpqRJ8/ei8brc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769954413; c=relaxed/simple; bh=Du2cjGPTlDTnng11xelZtqpcrNNhrTx1KQm3Icws5zw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sYRc4QLqTeMR5yVT5wEPtHythsTg9OLImoU+HDaJxdTci2rithN+ppnH7GspCabaOOKkLK3Hs63gxtG/yY5C911BvRRcejeoFilQEXSi++HwK4VwbkcC1+2Jmhfea1FuKpjGhI5nBzJ5jTKLZVjJlraBtxFAwx2bdqB52R8R/mE= 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=KciuktEV; 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="KciuktEV" 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 6118StHL011557; Sun, 1 Feb 2026 13:59:52 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=T/fT0/BGfn1xULqsM 4PIQIdo+lgTUq5URAy46hMilUg=; b=KciuktEVMi4Zu4XcaaFR+tLFxLClkSn9V LBdsBpG3qmsPxtyKabHJCQXb1DU1D1usayH/HvkurnY35AUqkD/gbef2B0+xPgCb +KKLdpKziyQ8MuPoOrECNVzllvGKYmHnkqnJzU/4W2sZCftXuf41I/3FqTB35d4m Mre/9kWJuJkY1UvhtqPyxGRchoQsDzaD97i4HfQBtiBZKjooh01mJ9MFkDVqNpLo ZaN2qRZcWwJRivj62IuTHhAahB8lFRZYyyIkg5f7esnIjL8GDrtU4K8CUdUvK4IE 6bb3E10GsinU3SR/bxWtajIcX9VLye70i1EC142Tu7kU139Nx6ODQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4c19dsvjb8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:52 +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 611DxpRN011471; Sun, 1 Feb 2026 13:59:51 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 4c19dsvjb6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:51 +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 6118ChPd025706; Sun, 1 Feb 2026 13:59:50 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4c1w2mhkpy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:50 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay03.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 611DxjPU48890156 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 1 Feb 2026 13:59:46 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DA6A520043; Sun, 1 Feb 2026 13:59:45 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C84F520040; Sun, 1 Feb 2026 13:59:42 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.39]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sun, 1 Feb 2026 13:59:42 +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 v6 3/6] pseries/plpks: expose PowerVM wrapping features via the sysfs Date: Sun, 1 Feb 2026 19:29:27 +0530 Message-ID: <20260201135930.898721-4-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260201135930.898721-1-ssrish@linux.ibm.com> References: <20260201135930.898721-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: AW1haW4tMjYwMjAxMDEyMCBTYWx0ZWRfXxCXjVh0+x3cI vhxzjEV3IEhZtjrVdijt7CUBzaR3kl2V7/Dilyk+gkd2gyLaxpkp1pvdSTQQpwZFrcfpqzbb7Aw /ht9gqwTbGiUj5QBGvmFdOcTFqQFBr5RHx7PqhCYR1GPKCBXlKlpRhP/qqw7Lh9EcPgWcTpG4Xq rYk0nt1LOZY/HfQBe7nMn+ni0WHHvDUuPaoOgCzC3AwpQyiq8n6tehZ5lHpeteXWEghWenvTz4E vMea1woM+5Kgyhi5Jk6rtlPhV9GzjOYr+UBemIRI+z/otPy+3JhJWcT4Hh2SU2GkcZxzitoCLbN XfC4tsrHN2MncaxnY3nwyS9IahAKVP8Oivxh4EMyyrHL2yWCmWqenV5XJ+zmdxxt7BbpMikXXnZ WFHz7p6DGQNbbwxG94y8z11GFi5DDvlYbk8dIMgNhtwvrkxVqYd+LotH7r07omAqqKyLm7U5631 n2t8toCoT6QY6x3mdQg== X-Proofpoint-GUID: ZmC9XgvoSrlBiHwEphV_pk6vMkrDBNvQ X-Proofpoint-ORIG-GUID: w7x1Tv0jsuaLc_dAG353t2RRitW8qirj X-Authority-Analysis: v=2.4 cv=LesxKzfi c=1 sm=1 tr=0 ts=697f5c58 cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=z7cUUKlKUSfJ7xv5IYMA:9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-02-01_05,2026-01-30_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 bulkscore=0 impostorscore=0 spamscore=0 lowpriorityscore=0 clxscore=1015 adultscore=0 suspectscore=0 priorityscore=1501 phishscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2602010120 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 Sat Feb 7 13:41:47 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 643E2350D47; Sun, 1 Feb 2026 14:00:15 +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=1769954417; cv=none; b=BKZmNUGm/pxa8g+sqb7o4+q9ITOvr0QOnZ1XrwtQ3P0HhxTJn4oK7/N4wQ5pvYhrD8VtiXdGBu/5FGfuC58eb3Ofo14gj2AKf1sSsmdnt3QBytoBcf9/In1Jrcv/DmLDrnBJdeJjmYYhuQlBVhLVl4NFngS7Dx2nL6OU3WBpKrc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769954417; c=relaxed/simple; bh=8Dn39dG5RGaSA53R1R+/K38BciWvPiVBuve0XCmCN2M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GNhIgRAmQGaxXSOP9rtG9NBLVEULaatSpxj0aIt+bxQCeLP+b541a1KscDmLA7hRVh74o7TB5vlEYi5kUVKTQMUNppN5kLH0ZVGd9eHVispGgQJ37hVDarycU/txlTiOigwKZ0bOVECQ3AhEtoCOpalZksk5mGYLhkgvmSgEBR4= 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=tQfu8y7+; 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="tQfu8y7+" Received: from pps.filterd (m0356517.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 611Cci4D019443; Sun, 1 Feb 2026 13:59:56 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=tQGrz+P5gwETbvhiO C/Xn6iVyhUnynE3XJHnX9wVo0w=; b=tQfu8y7+e19aBa17rHoXydNu9z8vRJgLp uWNo0Z3MCDOBu7qHo6auMa0HiBYMMAjvcySA2NtU9Izh51PRSWM4xdK+VkypAYOk Kpw4RVCeWz8EF/HwrvuoqA04mVMSEHZnSWcb9Wjuv+Pen4HczdIrPKJMsAVUL7IM +6pa0SNKJ7sWuzcKEpLUn4Mh5n8tse0TuFPcewlG8Mw+guuckH+QSjjymYoC29vZ WLphhzVzqD6fisgonK49Tabod56PlMUJbHVQWmkAfgceBEFrbJdCvuJZJ/+dEaBi +uUmikxN2eSAQ8Xk7q64VvkpDhpMPPqedREWMNJwDQg7vhvuFAnNg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4c19f64jxy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:55 +0000 (GMT) Received: from m0356517.ppops.net (m0356517.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 611DxtoK027557; Sun, 1 Feb 2026 13:59:55 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 4c19f64jxw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:55 +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 6118NDxf025743; Sun, 1 Feb 2026 13:59:54 GMT Received: from smtprelay06.fra02v.mail.ibm.com ([9.218.2.230]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4c1w2mhkq3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:53 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay06.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 611Dxnem6357426 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 1 Feb 2026 13:59:49 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9C6F420043; Sun, 1 Feb 2026 13:59:49 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3C94120040; Sun, 1 Feb 2026 13:59:46 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.39]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sun, 1 Feb 2026 13:59:46 +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 v6 4/6] pseries/plpks: add HCALLs for PowerVM Key Wrapping Module Date: Sun, 1 Feb 2026 19:29:28 +0530 Message-ID: <20260201135930.898721-5-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260201135930.898721-1-ssrish@linux.ibm.com> References: <20260201135930.898721-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: GeT0u4yS1_8H08HogLXWgM8P6UrUfoAK X-Authority-Analysis: v=2.4 cv=drTWylg4 c=1 sm=1 tr=0 ts=697f5c5c cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=nO4dFLMeAchwtJrxA4IA:9 a=POYjf8jjcDEwoKyR:21 X-Proofpoint-ORIG-GUID: dKSTxlzTq9mnF3jh5v48aGJtI-VnNoFB X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAxMDEyMCBTYWx0ZWRfX1UhNeq2NToX2 dl+nlMp49/w0DHHnh6KP1+AsfaaoRvxcGDzWPFWXwE/s9iZmK+Fz/LTNlXb7QqH5fd3lrRAU6kT Q5GwNGLQmKTq+RDXtX82XPivFUC09GCATZ7miOIpCjpAPKJv7sr06uP3eOsUgFM5yn8CwM1GT3b 1S4qi2Ix/owv0i15GP+g+wboSmnOVESvm+A7Tzm1cp52Plx3RO4yO6qT2d3/g1Q0s2x8yKsBHgb ob6w3qGmnI012zUWmWCDSKXgzGKipoC18H7ToE/JYX+1V9uWWN/dzPgqFVyepNxhBFosSX3eMby kGcNz5z5ZGgNLScKBAK/QipL/2cVxxkxv+5rc5stavBUUIOdi/OOwy3cs8OU7EUytcIOnzfg+OV lOvbQqRU9QO27rBQ784TGCuZAI/cnaQRcz9G+Hm1FnWa2JDKWmrLr2BtAIWIOgfj1jAuL4xRbXA dRglXJDs5N52mF1QVEA== 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-02-01_05,2026-01-30_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 clxscore=1015 spamscore=0 malwarescore=0 bulkscore=0 phishscore=0 adultscore=0 lowpriorityscore=0 impostorscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2602010120 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 | 344 ++++++++++++++++++++- 3 files changed, 395 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..23e4e2a922fc 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,310 @@ 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; +} +EXPORT_SYMBOL_GPL(plpks_wrapping_is_supported); + +/** + * 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 Sat Feb 7 13:41:47 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 3A4D733B96B; Sun, 1 Feb 2026 14:00:13 +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=1769954414; cv=none; b=JS4ka+oO3xNS2bTfSj1/GtKu1sIYDKoRW3TTYzl8qvXtpsBCQhg5bfNvuAXEpZJwbGc/XlNPTPn/l+YtBBPguEtlVRbbyeCuB35j5HRxkcMLem/X8Ws3d8vWnRzTKHBjvkReMR99VUsFWOqSVBBcE152lxeC5DsFOZYsi9rrDbA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769954414; c=relaxed/simple; bh=8GSCM9PTZmTDnOfw++1u4ef8KcGAb923KxDhQz2Xeec=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q9sXEGtB0pEQLjBFftiVUHz63WCKrKqubv1aIXsQJFZdUx8ZYAJ1I61P6vKwCT/+VfGRxCzu+bPr2gjQSzxyzTZ6TE0iEc1DUvOaJhZnAcfWyCes2gQPdxm3PWwE2oKK7oW3k248mqC6GrbhWVje/As73AXK/h+Ch43yCLtUFBs= 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=S8uC7eMP; 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="S8uC7eMP" Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 611804YK008775; Sun, 1 Feb 2026 13:59: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=JPX9D80ShV/Vh62aB WDxM9M6aEzJOTHR1/BpdkwVEEw=; b=S8uC7eMPegxckvofTXBZpHtxZeN05NUjn 9YxzvroqJbJMchuCfdkclRbIzo7ehKPY9uvwV5r+Nab7fUDiGl7phalDEz9r70Iq bHkKDfNBUT9SlDcqcUejBZ2aioLYs1zjvSvDvg4vS5PvFmgZWQohRByjZvhtScFf PXlGFpCzbdlIXJ5+jEL1YtgMVRLd75szIEIN+e7+Y0T97jQ1g8zYvwVDAXAsfR9T Ajk6H5J/HUIodeNARhA6Cm9PSmHzKx3s3tmAktAY6rRYx4hy6+b4SgE4Ungm4pBA ku1WxrUB14ZqmyEWn1Ym/36a+Zwocey3J8/8B1P8UyxhkJxKxvuow== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4c185gkt4s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:58 +0000 (GMT) Received: from m0353725.ppops.net (m0353725.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 611Dxv06000499; Sun, 1 Feb 2026 13:59:57 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 4c185gkt4q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:57 +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 61187s8T025696; Sun, 1 Feb 2026 13:59:57 GMT Received: from smtprelay04.fra02v.mail.ibm.com ([9.218.2.228]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4c1w2mhkq5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 13:59:56 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay04.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 611Dxr8d13697450 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 1 Feb 2026 13:59:53 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0F4F520043; Sun, 1 Feb 2026 13:59:53 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E837120040; Sun, 1 Feb 2026 13:59:49 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.39]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sun, 1 Feb 2026 13:59:49 +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 v6 5/6] keys/trusted_keys: establish PKWM as a trusted source Date: Sun, 1 Feb 2026 19:29:29 +0530 Message-ID: <20260201135930.898721-6-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260201135930.898721-1-ssrish@linux.ibm.com> References: <20260201135930.898721-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=UdxciaSN c=1 sm=1 tr=0 ts=697f5c5e cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=VwQbUJbxAAAA:8 a=6hcB66QTelQ3WYe9m3UA:9 X-Proofpoint-GUID: dvlZM0pJONVTpG8C-cyyAEqLVT6K_W1x X-Proofpoint-ORIG-GUID: t2eacskfmF420wyF_lXk8jsO-JzQi3QC X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAxMDEyMCBTYWx0ZWRfX0EwaMa03mfQF nR+oDv38Ly/JttSqzJwM2Xs78zgpDvr/9JcqNzuIjRMTK4LiRVAYlveX1CLO3wV2quPR1glSjOX xalQ/laBb/fSPc57Ei2bjX7w+iNgVyUqNefjmpIMmJHRZoNQhPP6cZOIOrU/8A3gsc5hHaYruIk PbAXOyzEtWwTUfMb9fVwIcN1x+9qowViDyzQWHlcpzDBvp6u9O/SzNxRklScvE1BJEpkfdvFsuH n7mAAfvw1YzW1fkO6y0QB2h0hF1XQaCktBLwWJqZOs6mJJ74qSX63XPzLRy49tRPloMd2GQZZKk JkUKBpDkwJWHmVr6vE8N8CZYkBAjsGiHJeicDZk6E4QunHYJrsBqZgcEdHxgX1WyLjtpCkVHxCz reyekBIH/8qn9R1f6ixSTdDIAGVMeV8T39osJLrEW07ukdMEoItUluDYOxRu2XXy+9nGjv7+QcD 0Abwt9EnlAgvK8fCdVA== 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-02-01_05,2026-01-30_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 impostorscore=0 lowpriorityscore=0 suspectscore=0 clxscore=1015 bulkscore=0 spamscore=0 phishscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2602010120 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 0efa8cc6775b..b037648e66fc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14013,6 +14013,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 Sat Feb 7 13:41:47 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 8882333CEB9; Sun, 1 Feb 2026 14:00:15 +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=1769954417; cv=none; b=UOb55LgmIQaazwWhfOF1J7C/j9oP3j3p2oS1U02vfyYGD03RMhsZeGrbz0WoM5FvaO+294XpOCE9KSN36AbutxrN8aZBdQVb6d6Wb0vQ80Yb8yzPWrK1wWtWRARjP9CVCaxScJCkoK/qbuuRM0UzjyFPs0oQyqLiwnFBoFA8liY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769954417; c=relaxed/simple; bh=XCefpgXUxyNEKk/AXlmykIVBUmEW8jSfP/BPAzjGEUk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bDtzRBAmeQ1e203K0hZfTNT5FClufQi1Gp1gDWgr2jk0Xnhuat7xgTzX5RfKH0PIgjZeK6+ENYasvAXIx5OPDw96QVEN5GKC8HF6ENKql3scjJFcHZUv2voa1U2rSUU+35TDYN3jqKlEAPwnw6m8rUwLfkCDwzK/U1V+P7HkGwg= 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=DgTYn2aq; 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="DgTYn2aq" 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 611AvakW006015; Sun, 1 Feb 2026 14:00: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=3AlJIuHueyJfodCUq PQr+cGMD8wjDvVNfPBSHGCosjo=; b=DgTYn2aqvWNFxtbgbqf/eul0lpRzK4kWi LomWABHSwpnLhQqk9QS0ntqJttnEUbn3LtCP86wSr4/AoOiStQ3B6NObiZ73S60s ANiD64cv+CUJSKyT8bR0NhcdbJr2ncaltt6hZeujFwVI8d0teIV5uX3I2J4WqUUT EzFzRHNeAKaBEPu+8GCcRphR98W4rSaiMY0b9XMaIVCxFFnEEr2AwPpJQlqAiqXv rhBB3S0l5+Xy0SpdXrwnv0b1yKXfEpXH10gJ3kdDpLOaWMnQ9Xmiy8OftF+YBMqu MYz1d4kkAmji8o7pPT1VR8xAoVrXaXyTHL6hNY1gxuvVXrr1zxsNg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4c175mkx5y-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 14:00:01 +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 611E01oY021627; Sun, 1 Feb 2026 14:00: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 4c175mkx5u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 14:00: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 61170cbT029108; Sun, 1 Feb 2026 14:00:00 GMT Received: from smtprelay06.fra02v.mail.ibm.com ([9.218.2.230]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4c1v2s1rd3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 01 Feb 2026 14:00:00 +0000 Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay06.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 611DxuLV19530040 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 1 Feb 2026 13:59:56 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8306A20043; Sun, 1 Feb 2026 13:59:56 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 728B120040; Sun, 1 Feb 2026 13:59:53 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.39.20.39]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Sun, 1 Feb 2026 13:59: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 v6 6/6] docs: trusted-encryped: add PKWM as a new trust source Date: Sun, 1 Feb 2026 19:29:30 +0530 Message-ID: <20260201135930.898721-7-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260201135930.898721-1-ssrish@linux.ibm.com> References: <20260201135930.898721-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-ORIG-GUID: Evg04QKxuVsarJqa7i2QNI9Y4fRtEMkb X-Authority-Analysis: v=2.4 cv=VcX6/Vp9 c=1 sm=1 tr=0 ts=697f5c61 cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=HzLeVaNsDn8A:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=ULK339cd-4IVAxCgyX4A:9 X-Proofpoint-GUID: d_3W2q5XZ5y6p6-HFy-5oJprXxLmYsF1 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjAxMDEyMCBTYWx0ZWRfX0J06/X323CG0 b+VW8LTBlJTEm4h6KBf1GeFq9oqzj13DG1zswjhuipqApsdx0hhWty+CMP5o8iTRXbGu0IKkzS1 gNL+g9Q8bWvu1dCeUzT9pdyuH7uMjAnA/Hi+HiqaMd+bHZCNQA9wI7JFsgblbmmnoFdlGDzSG4J reNdhTRM5JYspysBMgcxc94JxLWfinSGdtcRD+A0Z8JYTY5aDM2tV0/LGuoXa4GIKx+2lnu6jkI Uryln5s32N0j3UZKs8scYDE+AgmhvedDmR18FNZmh3sOsHQlL0M1iwspHmG/MVY8AVrSQj5t7Y6 dKDVuyhNeKI+B9ONhoj+JF8ItMlp2SR92DF056QSPFt/a7Gpc1OdX4ru/RORvq/L/hUCWVsTESe lyJaQPm9hJZBIPgalR6QX9YV49/9Q0deyXuofZ8SG5oSxBrA0b3fU0B1XlvTJPrUncbyITyBN+r R6RScvPIu6rPL91vMJg== 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-02-01_05,2026-01-30_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 spamscore=0 adultscore=0 bulkscore=0 phishscore=0 lowpriorityscore=0 impostorscore=0 clxscore=1015 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2601150000 definitions=main-2602010120 Content-Type: text/plain; charset="utf-8" From: Nayna Jain Update Documentation/security/keys/trusted-encrypted.rst and Documentation/ admin-guide/kernel-parameters.txt with PowerVM Key Wrapping Module (PKWM) as a new trust source Signed-off-by: Nayna Jain Signed-off-by: Srish Srinivasan Reviewed-by: Mimi Zohar --- .../admin-guide/kernel-parameters.txt | 1 + .../security/keys/trusted-encrypted.rst | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 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