From nobody Sun Feb 8 15:59:17 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 4EFDD33A01E; Tue, 6 Jan 2026 15:06:14 +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=1767711976; cv=none; b=SESMCimQ0/kjZmcQDpybwBDiqVPhnDjyTDRgb1dv+mqkHlrUZvt9CSWPBSKXZBXup3hTHXV1amyUjj4KGxAZE1j9hVq9ExsSDFg/Fn0RN15I6Zof4ALJLeA78S47GxZRAFOi9xWH2GJR81p7+QXzqqqb89kijIUSEkbSNE0s16s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767711976; c=relaxed/simple; bh=9/aOACvgpfwKH4Du31wucJqb2l0ngyiYIuD/ULhncVw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=teCx0ll/NQYFYiNnA5vXYtMlAKIDYKSLgODzPkTCuXo6motE27pG/ua8PhoW9237+pAZU1ibwoa1pu6toZoMiRWt57mWmjM366aHC01ivxSlg3wjkREyfD1mitJxlaCg6n+xzkZqOFEGOFu0k2C6wmI8zZBuf4q3RwLBo7eJfhI= 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=bbD6ZG+h; 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="bbD6ZG+h" Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 6063AE9u014575; Tue, 6 Jan 2026 15:05:57 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=zRuVMP8fy62QWWddd DjnySGr6oOB4PJyRbIstZEBTFU=; b=bbD6ZG+hSx+0rdzSj3Q6IbYJzLNGjO2FH 4EwJreVZVZuE9cX8DXEsZX3NlOsfjAAmARUhmzGJMSWHI/VeP2Fhe4i1SdTv9/8k pWIx2iSpoLUniEx4Er8m1BfjLiumdQmKdg8y1I9Ozc0O7j3xwMe0dd3GGPhUk5vm ugI7Prd2xRUzsxA7l+eRTe+Q/Y+Ag9JT7hZ/FmY0TujuBoZo85pAlotOzfkHKpdX zilLkL94Q07UQhZhPCIMXKtqpZ2/IlExAW6vGu1zHdx5uJdKNDwN5Z06S17dt8kt 9uR0rqcBa9oAVatZJbiGghYuAOQ2Slj6eg+QXzrKxUMgRpZhjZBvg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4betrtkjjk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:05:57 +0000 (GMT) Received: from m0360072.ppops.net (m0360072.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 606F3NZt020947; Tue, 6 Jan 2026 15:05:57 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 4betrtkjjf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:05:57 +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 606CZtH7015233; Tue, 6 Jan 2026 15:05:56 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bfdesc596-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:05:56 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 606F5qjS43450630 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 6 Jan 2026 15:05:52 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 764B020040; Tue, 6 Jan 2026 15:05:52 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E77372004B; Tue, 6 Jan 2026 15:05:44 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.214.6]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 6 Jan 2026 15:05:44 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v3 1/6] pseries/plpks: fix kernel-doc comment inconsistencies Date: Tue, 6 Jan 2026 20:35:22 +0530 Message-ID: <20260106150527.446525-2-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260106150527.446525-1-ssrish@linux.ibm.com> References: <20260106150527.446525-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=aaJsXBot c=1 sm=1 tr=0 ts=695d24d5 cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=_jD9v-G-JNOk7KggL9IA:9 a=tQW_-zY1P7yUjf7c:21 X-Proofpoint-GUID: UnEb2qaETxrd47X6y9tHA5asx_72dApG X-Proofpoint-ORIG-GUID: LH6vItoeJHXNSRr_Yd6_7ZjHsS7TPMRX X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTA2MDEyOSBTYWx0ZWRfXwq+t0zjp0sVW Qs5THQ7ti2YJ1MKCi0emkKF+Tv1XpAJkyqCI9k9bJCjuOlYkId9Ix5P8ymYqBinwcLkgL+1rcv7 YpNCHoqysgqBzAWIrxovGIR5oJ2SIsyubJ51L8Ys9q9JzDKFxG3YX2BKsiU2LiBjDRaxP2ajp4x G0m18T1PJf0bU6sNvGlXVgmoCjruH9A8Jrr6LdYMz67c3Gy00LXqHUHx4sSUc4WCmVV4Fzyb+14 WSiD9ZrYCEyQxBlLRZ9sYOfme7dQSKFr6hJwX6rwTT1MgCJidPqOHTdfqLADAYDYB0/an9QCFcC K2yOuRyC90d6fEMG2jMUv27kx2sDUxaeVSc6LJTWYB8QXNlyjxhWiUa845obKobIstWFCJRgh8B zumVfKN/bN7n4eJXIJhsEPbsvX3QEgejrMjr5CvT9ba2v1jkchO7eu72r13+4sFvLlnqT6ZX7qp nHP3QYHFkG6LHH7LwvA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-06_01,2026-01-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 adultscore=0 lowpriorityscore=0 bulkscore=0 malwarescore=0 priorityscore=1501 clxscore=1015 phishscore=0 spamscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601060129 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 --- arch/powerpc/include/asm/plpks.h | 77 ------ arch/powerpc/platforms/pseries/plpks.c | 328 ++++++++++++++++++++++++- 2 files changed, 318 insertions(+), 87 deletions(-) diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index 7a84069759b0..f303922bf622 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -67,122 +67,45 @@ struct plpks_var_name_list { struct plpks_var_name varlist[]; }; =20 -/** - * Updates the authenticated variable. It expects NULL as the component. - */ int plpks_signed_update_var(struct plpks_var *var, u64 flags); =20 -/** - * Writes the specified var and its data to PKS. - * Any caller of PKS driver should present a valid component type for - * their variable. - */ int plpks_write_var(struct plpks_var var); =20 -/** - * Removes the specified var and its data from PKS. - */ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname); =20 -/** - * Returns the data for the specified os variable. - * - * Caller must allocate a buffer in var->data with length in var->datalen. - * If no buffer is provided, var->datalen will be populated with the objec= t's - * size. - */ int plpks_read_os_var(struct plpks_var *var); =20 -/** - * Returns the data for the specified firmware variable. - * - * Caller must allocate a buffer in var->data with length in var->datalen. - * If no buffer is provided, var->datalen will be populated with the objec= t's - * size. - */ int plpks_read_fw_var(struct plpks_var *var); =20 -/** - * Returns the data for the specified bootloader variable. - * - * Caller must allocate a buffer in var->data with length in var->datalen. - * If no buffer is provided, var->datalen will be populated with the objec= t's - * size. - */ int plpks_read_bootloader_var(struct plpks_var *var); =20 -/** - * Returns if PKS is available on this LPAR. - */ bool plpks_is_available(void); =20 -/** - * Returns version of the Platform KeyStore. - */ u8 plpks_get_version(void); =20 -/** - * Returns hypervisor storage overhead per object, not including the size = of - * the object or label. Only valid for config version >=3D 2 - */ u16 plpks_get_objoverhead(void); =20 -/** - * Returns maximum password size. Must be >=3D 32 bytes - */ u16 plpks_get_maxpwsize(void); =20 -/** - * Returns maximum object size supported by Platform KeyStore. - */ u16 plpks_get_maxobjectsize(void); =20 -/** - * Returns maximum object label size supported by Platform KeyStore. - */ u16 plpks_get_maxobjectlabelsize(void); =20 -/** - * Returns total size of the configured Platform KeyStore. - */ u32 plpks_get_totalsize(void); =20 -/** - * Returns used space from the total size of the Platform KeyStore. - */ u32 plpks_get_usedspace(void); =20 -/** - * Returns bitmask of policies supported by the hypervisor. - */ u32 plpks_get_supportedpolicies(void); =20 -/** - * Returns maximum byte size of a single object supported by the hyperviso= r. - * Only valid for config version >=3D 3 - */ u32 plpks_get_maxlargeobjectsize(void); =20 -/** - * Returns bitmask of signature algorithms supported for signed updates. - * Only valid for config version >=3D 3 - */ u64 plpks_get_signedupdatealgorithms(void); =20 -/** - * Returns the length of the PLPKS password in bytes. - */ u16 plpks_get_passwordlen(void); =20 -/** - * Called in early init to retrieve and clear the PLPKS password from the = DT. - */ void plpks_early_init_devtree(void); =20 -/** - * Populates the FDT with the PLPKS password to prepare for kexec. - */ int plpks_populate_fdt(void *fdt); #else // CONFIG_PSERIES_PLPKS static inline bool plpks_is_available(void) { return false; } diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platform= s/pseries/plpks.c index b1667ed05f98..03722fabf9c3 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -312,40 +312,107 @@ static int _plpks_get_config(void) return rc; } =20 +/** + * plpks_get_version() - Get the version of the PLPKS config structure. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the PLPKS config structure version and saves it in a file local s= tatic + * version variable. + * + * Returns: On success the saved PLPKS config structure version is returne= d, 0 + * if not. + */ u8 plpks_get_version(void) { return version; } =20 +/** + * plpks_get_objoverhead() - Get the hypervisor storage overhead per objec= t. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the per object hypervisor storage overhead in bytes into the local + * static objoverhead variable, excluding the size of the object or the la= bel. + * This value can be treated as valid only when the PLPKS config structure + * version >=3D 2. + * + * Returns: If PLPKS config structure version >=3D 2 then the storage over= head is + * returned, 0 otherwise. + */ u16 plpks_get_objoverhead(void) { return objoverhead; } =20 +/** + * plpks_get_maxpwsize() - Get the maximum password size. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum password size and checks if it is 32 bytes at the lea= st + * before storing it in the local static maxpwsize variable. + * + * Returns: On success the maximum password size is returned, 0 if not. + */ u16 plpks_get_maxpwsize(void) { return maxpwsize; } =20 +/** + * plpks_get_maxobjectsize() - Get the maximum object size supported by the + * PLPKS. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum object size into the file local static maxobjsize var= iable. + * + * Returns: On success the maximum object size is returned, 0 if not. + */ u16 plpks_get_maxobjectsize(void) { return maxobjsize; } =20 +/** + * plpks_get_maxobjectlabelsize() - Get the maximum object label size supp= orted + * by the PLPKS. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum object label size into the local static maxobjlabelsi= ze + * variable. + * + * Returns: On success the maximum object label size is returned, 0 if not. + */ u16 plpks_get_maxobjectlabelsize(void) { return maxobjlabelsize; } =20 +/** + * plpks_get_totalsize() - Get the total size of the PLPKS that is configu= red. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the total size of the PLPKS that is configured for the LPAR into = the + * file local static totalsize variable. + * + * Returns: On success the total size of the PLPKS configured is returned,= 0 if + * not. + */ u32 plpks_get_totalsize(void) { return totalsize; } =20 +/** + * plpks_get_usedspace() - Get the used space from the total size of the P= LPKS. + * + * Invoke the H_PKS_GET_CONFIG HCALL to refresh the latest value for the u= sed + * space as this keeps changing with the creation and removal of objects i= n the + * PLPKS. + * + * Returns: On success the used space is returned, 0 if not. + */ u32 plpks_get_usedspace(void) { - // Unlike other config values, usedspace regularly changes as objects - // are updated, so we need to refresh. int rc =3D _plpks_get_config(); if (rc) { pr_err("Couldn't get config, rc: %d\n", rc); @@ -354,26 +421,84 @@ u32 plpks_get_usedspace(void) return usedspace; } =20 +/** + * plpks_get_supportedpolicies() - Get a bitmask of the policies supported= by + * the hypervisor. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads a bitmask of the policies supported by the hypervisor into the fi= le + * local static supportedpolicies variable. + * + * Returns: On success the bitmask of the policies supported by the hyperv= isor + * are returned, 0 if not. + */ u32 plpks_get_supportedpolicies(void) { return supportedpolicies; } =20 +/** + * plpks_get_maxlargeobjectsize() - Get the maximum object size supported = for + * PLPKS config structure version >=3D 3 + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads the maximum object size into the local static maxlargeobjectsize + * variable for PLPKS config structure version >=3D 3. This was introduced + * starting with PLPKS config structure version 3 to allow for objects of + * size >=3D 64K. + * + * Returns: If PLPKS config structure version >=3D 3 then the new maximum = object + * size is returned, 0 if not. + */ u32 plpks_get_maxlargeobjectsize(void) { return maxlargeobjectsize; } =20 +/** + * plpks_get_signedupdatealgorithms() - Get a bitmask of the signature + * algorithms supported for signed updates. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads a bitmask of the signature algorithms supported for signed update= s into + * the file local static signedupdatealgorithms variable. This is valid on= ly + * when the PLPKS config structure version >=3D 3. + * + * Returns: On success the bitmask of the signature algorithms supported f= or + * signed updates is returned, 0 if not. + */ u64 plpks_get_signedupdatealgorithms(void) { return signedupdatealgorithms; } =20 +/** + * plpks_get_passwordlen() - Get the length of the PLPKS password in bytes. + * + * The H_PKS_GEN_PASSWORD HCALL makes the hypervisor generate a random pas= sword + * for the specified consumer, apply that password to the PLPKS and return= it to + * the caller. In this process, the password length for the OS consumer is + * stored in the local static ospasswordlength variable. + * + * Returns: On success the password length for the OS consumer in bytes is + * returned, 0 if not. + */ u16 plpks_get_passwordlen(void) { return ospasswordlength; } =20 +/** + * plpks_is_available() - Get the PLPKS availability status for the LPAR. + * + * The availability of PLPKS is inferred based upon the successful executi= on of + * the H_PKS_GET_CONFIG HCALL provided the firmware supports this feature.= The + * H_PKS_GET_CONFIG HCALL reads the configuration and status information r= elated + * to the PLPKS. The configuration structure provides a version number to = inform + * the caller of the supported features. + * + * Returns: true is returned if PLPKS is available, false if not. + */ bool plpks_is_available(void) { int rc; @@ -425,6 +550,35 @@ static int plpks_confirm_object_flushed(struct label *= label, return pseries_status_to_err(rc); } =20 +/** + * plpks_signed_update_var() - Update the specified authenticated variable. + * @var: authenticated variable to be updated + * @flags: signed update request operation flags + * + * The H_PKS_SIGNED_UPDATE HCALL performs a signed update to an object in = the + * PLPKS. The object must have the signed update policy flag set. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid or unsupported policy declaration + * if invalid signed update flags + * if invalid input data parameter + * if invalid input data len parameter + * if invalid continue token parameter + * -EPERM if access is denied + * -ENOMEM if there is inadequate memory to perform the operation + * -EBUSY if unable to handle the request or long running operation + * initiated, retry later + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_signed_update_var(struct plpks_var *var, u64 flags) { unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] =3D {0}; @@ -481,6 +635,33 @@ int plpks_signed_update_var(struct plpks_var *var, u64= flags) return rc; } =20 +/** + * plpks_write_var() - Write the specified variable and its data to PLPKS. + * @var: variable to be written into the PLPKS + * + * The H_PKS_WRITE_OBJECT HCALL writes an object into the PLPKS. The calle= r must + * provide a valid component type for the variable, and the signed update = policy + * flag must not be set. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid or unsupported policy declaration + * if invalid input data parameter + * if invalid input data len parameter + * -EPERM if access is denied + * -ENOMEM if unable to store the requested object in the space available + * -EBUSY if unable to handle the request + * -EEXIST if the object label already exists + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_write_var(struct plpks_var var) { unsigned long retbuf[PLPAR_HCALL_BUFSIZE] =3D { 0 }; @@ -520,6 +701,30 @@ int plpks_write_var(struct plpks_var var) return rc; } =20 +/** + * plpks_remove_var() - Remove the specified variable and its data from PL= PKS. + * @component: metadata prefix in the object label metadata structure + * @varos: metadata OS flags in the object label metadata structure + * @vname: object label for the object that needs to be removed + * + * The H_PKS_REMOVE_OBJECT HCALL removes an object from the PLPKS. The rem= oval + * is independent of the policy bits that are set. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vnam= e) { unsigned long retbuf[PLPAR_HCALL_BUFSIZE] =3D { 0 }; @@ -619,21 +824,119 @@ static int plpks_read_var(u8 consumer, struct plpks_= var *var) return rc; } =20 +/** + * plpks_read_os_var() - Fetch the data for the specified variable that is + * owned by the OS consumer. + * @var: variable to be read from the PLPKS + * + * The consumer or the owner of the object is the os kernel. The + * H_PKS_READ_OBJECT HCALL reads an object from the PLPKS. The caller must + * allocate the buffer var->data and specify the length for this buffer in + * var->datalen. If no buffer is provided, var->datalen will be populated = with + * the requested object's size. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid output data parameter + * if invalid output data len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EFBIG if the requested object couldn't be + * stored in the buffer provided + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_read_os_var(struct plpks_var *var) { return plpks_read_var(PLPKS_OS_OWNER, var); } =20 +/** + * plpks_read_fw_var() - Fetch the data for the specified variable that is + * owned by the firmware consumer. + * @var: variable to be read from the PLPKS + * + * The consumer or the owner of the object is the firmware. The + * H_PKS_READ_OBJECT HCALL reads an object from the PLPKS. The caller must + * allocate the buffer var->data and specify the length for this buffer in + * var->datalen. If no buffer is provided, var->datalen will be populated = with + * the requested object's size. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid output data parameter + * if invalid output data len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EFBIG if the requested object couldn't be + * stored in the buffer provided + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_read_fw_var(struct plpks_var *var) { return plpks_read_var(PLPKS_FW_OWNER, var); } =20 +/** + * plpks_read_bootloader_var() - Fetch the data for the specified variable + * owned by the bootloader consumer. + * @var: variable to be read from the PLPKS + * + * The consumer or the owner of the object is the bootloader. The + * H_PKS_READ_OBJECT HCALL reads an object from the PLPKS. The caller must + * allocate the buffer var->data and specify the length for this buffer in + * var->datalen. If no buffer is provided, var->datalen will be populated = with + * the requested object's size. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid output data parameter + * if invalid output data len parameter + * -EPERM if access is denied + * -ENOENT if the requested object was not found + * -EFBIG if the requested object couldn't be + * stored in the buffer provided + * -EBUSY if unable to handle the request + * + * Returns: On success 0 is returned, a negative errno if not. + */ int plpks_read_bootloader_var(struct plpks_var *var) { return plpks_read_var(PLPKS_BOOTLOADER_OWNER, var); } =20 +/** + * plpks_populate_fdt(): Populates the FDT with the PLPKS password to prep= are + * for kexec. + * @fdt: pointer to the device tree blob + * + * Upon confirming the existence of the chosen node, invoke fdt_setprop to + * populate the device tree with the PLPKS password in order to prepare for + * kexec. + * + * Returns: On success 0 is returned, a negative value if not. + */ int plpks_populate_fdt(void *fdt) { int chosen_offset =3D fdt_path_offset(fdt, "/chosen"); @@ -647,14 +950,19 @@ int plpks_populate_fdt(void *fdt) return fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw", ospassword, ospass= wordlength); } =20 -// Once a password is registered with the hypervisor it cannot be cleared = without -// rebooting the LPAR, so to keep using the PLPKS across kexec boots we ne= ed to -// recover the previous password from the FDT. -// -// There are a few challenges here. We don't want the password to be visi= ble to -// users, so we need to clear it from the FDT. This has to be done in ear= ly boot. -// Clearing it from the FDT would make the FDT's checksum invalid, so we h= ave to -// manually cause the checksum to be recalculated. +/** + * plpks_early_init_devtree() - Retrieves and clears the PLPKS password fr= om the + * DT in early init. + * + * Once a password is registered with the hypervisor it cannot be cleared + * without rebooting the LPAR, so to keep using the PLPKS across kexec boo= ts we + * need to recover the previous password from the FDT. + * + * There are a few challenges here. We don't want the password to be visi= ble to + * users, so we need to clear it from the FDT. This has to be done in ear= ly + * boot. Clearing it from the FDT would make the FDT's checksum invalid, s= o we + * have to manually cause the checksum to be recalculated. + */ void __init plpks_early_init_devtree(void) { void *fdt =3D initial_boot_params; --=20 2.47.3 From nobody Sun Feb 8 15:59:17 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 5320433A6F8; Tue, 6 Jan 2026 15:06:16 +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=1767711979; cv=none; b=W6ED6S43FLM5gOjyAKbyu+xOjliOTmsF5Qg7KFipOLXbiHxrLFUOTdEP605k5yXYZ0rtzKREYsMGM9KGcUAGOuO0GEnVeMzpTylw3vVp9t/LroEi5ZIRsPAARWdcuI6AB75D3H3Ms7qwCUK0Sbma5xvn4WHjPeTVfFu1dl0IyJc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767711979; c=relaxed/simple; bh=6G58g9crEgE57aep4YmCSRDvwVu4Es3NNVhZc8cDP7Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jVAExn5hgh/t5wDRZPkhmfZaNIiA9laKTw2QIcySZe2zWffs2mImQapyxm6Q/VfFtEOekX3RhiE8+RISf+bdL9ebNjtp6+9wV12TJA8TabliDH6J61kwH8s5EjdpYVh1K1Pu4AmrE/wmUrHwDFnpTrA1lMDZqdX5GMwJh2L05Is= 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=OUIGp/mo; 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="OUIGp/mo" Received: from pps.filterd (m0360083.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 6063qTIv011837; Tue, 6 Jan 2026 15:06:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=yc4kRWNOeDA46cfmO ijRYwTfYPM4pX1pzJgtVu4tPVs=; b=OUIGp/mobKktUMBxGcoLeULN2S9wAbxhb WgriGqPfePD/zcUrwshfe/IR103GA52VyTefN8JRKvlh7T3uC8CG4wxkZuWsD3uo JFcv9bMDlKYXIIowosNRWfG5P9rnk/9LRC8emML4lIoEhYasdpv+41dt23a3neJd +Rp+DFYK2J/kBrM7xvZ7vJk+4zLTACo3uKleRqzX8SZzIhtvndNtbUVXfpJeIdp8 9YU24sUpQHRb19FG0cDcB1jeHskRES5BKZzJMk/L4GfyEiPm7zOimCQuF7XmAxDU jJnuJfCGq1yWhq6tj9ocRxUilT09ftvz9efXJ3b01r3WhR4cXtc7w== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4betm74f4c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:03 +0000 (GMT) Received: from m0360083.ppops.net (m0360083.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 606F5OWF017045; Tue, 6 Jan 2026 15:06:03 GMT Received: from ppma22.wdc07v.mail.ibm.com (5c.69.3da9.ip4.static.sl-reverse.com [169.61.105.92]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4betm74f49-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:03 +0000 (GMT) Received: from pps.filterd (ppma22.wdc07v.mail.ibm.com [127.0.0.1]) by ppma22.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 606CKWqG023487; Tue, 6 Jan 2026 15:06:01 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma22.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bg3rm8mn2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:01 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay03.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 606F5veB54395238 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 6 Jan 2026 15:05:57 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7893F2004B; Tue, 6 Jan 2026 15:05:57 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4BCE520040; Tue, 6 Jan 2026 15:05:53 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.214.6]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 6 Jan 2026 15:05:52 +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 v3 2/6] powerpc/pseries: move the PLPKS config inside its own sysfs directory Date: Tue, 6 Jan 2026 20:35:23 +0530 Message-ID: <20260106150527.446525-3-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260106150527.446525-1-ssrish@linux.ibm.com> References: <20260106150527.446525-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=OdmVzxTY c=1 sm=1 tr=0 ts=695d24db cx=c_pps a=5BHTudwdYE3Te8bg5FgnPg==:117 a=5BHTudwdYE3Te8bg5FgnPg==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=mWGr4ncSMiNchjaCnzgA:9 X-Proofpoint-GUID: gXwv__6au3Iq6Tbke66C70-q34VxkINi X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTA2MDEyOSBTYWx0ZWRfX+DC+qczo3hSK jiDUd0nl+3qnz4bN8Jdgve+FhU7WeXrUh7fYtd8mGIhRXbSwynnUy1o6fT9bcU4EcmRp8bgpIKT /KNNbq8ti91N16Vw7bTAVWcF6ov9V/ck2kLJkDmLSOFIbvnWpDqiSABS04hSwfWTrqd8Uhvt3rx rMDNBEYJBskI3KWkiAHf/4RxkYvKGj9/l0DwUyG2Kg/+pX9HjiFVKKsxDS63hoOwtRr63nmDNgw VM40zoqHuD08mf7M3ZO8VF8PpYpY3scWc4A96eTgJHp6O5enF57Cu1oUJITK94YdEa8tqDiWRDl U4fN9XCJbwQJYZ/oGW0+aPS2tZBpk+BY8p3mXUmzOID9HIyQ/DTiObn/j4vpqvmRZepMu/lJ4e/ GuBBrue6Fnt+M2dH9mZkwbFMykwIrvOzejDw4n9Bczv2G7ONki2HJf0D6jWOPfOu29qmo69xHP+ nPQ16DuO4PS6SJcpiBQ== X-Proofpoint-ORIG-GUID: 6YnUO8xr2WD2pmkLsA53c5gzDD5dP_Q4 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-06_01,2026-01-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 clxscore=1015 phishscore=0 malwarescore=0 adultscore=0 lowpriorityscore=0 priorityscore=1501 impostorscore=0 bulkscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601060129 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 --- .../ABI/testing/sysfs-firmware-plpks | 50 ++++++++++ Documentation/ABI/testing/sysfs-secvar | 65 ------------- arch/powerpc/include/asm/plpks.h | 5 + arch/powerpc/include/asm/secvar.h | 1 - arch/powerpc/kernel/secvar-sysfs.c | 21 ++--- arch/powerpc/platforms/pseries/Makefile | 2 +- arch/powerpc/platforms/pseries/plpks-secvar.c | 29 ------ arch/powerpc/platforms/pseries/plpks-sysfs.c | 94 +++++++++++++++++++ 8 files changed, 156 insertions(+), 111 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-firmware-plpks create mode 100644 arch/powerpc/platforms/pseries/plpks-sysfs.c diff --git a/Documentation/ABI/testing/sysfs-firmware-plpks b/Documentation= /ABI/testing/sysfs-firmware-plpks new file mode 100644 index 000000000000..af0353f34115 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-plpks @@ -0,0 +1,50 @@ +What: /sys/firmware/plpks/config +Date: February 2023 +Contact: Nayna Jain +Description: This optional directory contains read-only config attributes = as + defined by the PLPKS implementation. All data is in ASCII + format. + +What: /sys/firmware/plpks/config/version +Date: February 2023 +Contact: Nayna Jain +Description: Config version as reported by the hypervisor in ASCII decimal + format. + +What: /sys/firmware/plpks/config/max_object_size +Date: February 2023 +Contact: Nayna Jain +Description: Maximum allowed size of objects in the keystore in bytes, + represented in ASCII decimal format. + + This is not necessarily the same as the max size that can be + written to an update file as writes can contain more than + object data, you should use the size of the update file for + that purpose. + +What: /sys/firmware/plpks/config/total_size +Date: February 2023 +Contact: Nayna Jain +Description: Total size of the PLPKS in bytes, represented in ASCII decimal + format. + +What: /sys/firmware/plpks/config/used_space +Date: February 2023 +Contact: Nayna Jain +Description: Current space consumed by the key store, in bytes, represented + in ASCII decimal format. + +What: /sys/firmware/plpks/config/supported_policies +Date: February 2023 +Contact: Nayna Jain +Description: Bitmask of supported policy flags by the hypervisor, represen= ted + as an 8 byte hexadecimal ASCII string. Consult the hypervisor + documentation for what these flags are. + +What: /sys/firmware/plpks/config/signed_update_algorithms +Date: February 2023 +Contact: Nayna Jain +Description: Bitmask of flags indicating which algorithms the hypervisor + supports for signed update of objects, represented as a 16 byte + hexadecimal ASCII string. Consult the hypervisor documentation + for what these flags mean. diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/tes= ting/sysfs-secvar index 1016967a730f..c52a5fd15709 100644 --- a/Documentation/ABI/testing/sysfs-secvar +++ b/Documentation/ABI/testing/sysfs-secvar @@ -63,68 +63,3 @@ Contact: Nayna Jain Description: A write-only file that is used to submit the new value for the variable. The size of the file represents the maximum size of the variable data that can be written. - -What: /sys/firmware/secvar/config -Date: February 2023 -Contact: Nayna Jain -Description: This optional directory contains read-only config attributes = as - defined by the secure variable implementation. All data is in - ASCII format. The directory is only created if the backing - implementation provides variables to populate it, which at - present is only PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/version -Date: February 2023 -Contact: Nayna Jain -Description: Config version as reported by the hypervisor in ASCII decimal - format. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/max_object_size -Date: February 2023 -Contact: Nayna Jain -Description: Maximum allowed size of objects in the keystore in bytes, - represented in ASCII decimal format. - - This is not necessarily the same as the max size that can be - written to an update file as writes can contain more than - object data, you should use the size of the update file for - that purpose. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/total_size -Date: February 2023 -Contact: Nayna Jain -Description: Total size of the PLPKS in bytes, represented in ASCII decimal - format. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/used_space -Date: February 2023 -Contact: Nayna Jain -Description: Current space consumed by the key store, in bytes, represented - in ASCII decimal format. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/supported_policies -Date: February 2023 -Contact: Nayna Jain -Description: Bitmask of supported policy flags by the hypervisor, - represented as an 8 byte hexadecimal ASCII string. Consult the - hypervisor documentation for what these flags are. - - Currently only provided by PLPKS on the pseries platform. - -What: /sys/firmware/secvar/config/signed_update_algorithms -Date: February 2023 -Contact: Nayna Jain -Description: Bitmask of flags indicating which algorithms the hypervisor - supports for signed update of objects, represented as a 16 byte - hexadecimal ASCII string. Consult the hypervisor documentation - for what these flags mean. - - Currently only provided by PLPKS on the pseries platform. diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index f303922bf622..8829a13bfda0 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -13,6 +13,7 @@ =20 #include #include +#include =20 // Object policy flags from supported_policies #define PLPKS_OSSECBOOTAUDIT PPC_BIT32(1) // OS secure boot must be audit/= enforce @@ -107,11 +108,15 @@ u16 plpks_get_passwordlen(void); void plpks_early_init_devtree(void); =20 int plpks_populate_fdt(void *fdt); + +int plpks_config_create_softlink(struct kobject *from); #else // CONFIG_PSERIES_PLPKS static inline bool plpks_is_available(void) { return false; } static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); } static inline void plpks_early_init_devtree(void) { } static inline int plpks_populate_fdt(void *fdt) { BUILD_BUG(); } +static inline int plpks_config_create_softlink(struct kobject *from) + { return 0; } #endif // CONFIG_PSERIES_PLPKS =20 #endif // _ASM_POWERPC_PLPKS_H diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/s= ecvar.h index 4828e0ab7e3c..fd5006307f2a 100644 --- a/arch/powerpc/include/asm/secvar.h +++ b/arch/powerpc/include/asm/secvar.h @@ -20,7 +20,6 @@ struct secvar_operations { int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size); ssize_t (*format)(char *buf, size_t bufsize); int (*max_size)(u64 *max_size); - const struct attribute **config_attrs; =20 // NULL-terminated array of fixed variable names // Only used if get_next() isn't provided diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secva= r-sysfs.c index ec900bce0257..4111b21962eb 100644 --- a/arch/powerpc/kernel/secvar-sysfs.c +++ b/arch/powerpc/kernel/secvar-sysfs.c @@ -12,6 +12,7 @@ #include #include #include +#include =20 #define NAME_MAX_SIZE 1024 =20 @@ -145,19 +146,6 @@ static __init int update_kobj_size(void) return 0; } =20 -static __init int secvar_sysfs_config(struct kobject *kobj) -{ - struct attribute_group config_group =3D { - .name =3D "config", - .attrs =3D (struct attribute **)secvar_ops->config_attrs, - }; - - if (secvar_ops->config_attrs) - return sysfs_create_group(kobj, &config_group); - - return 0; -} - static __init int add_var(const char *name) { struct kobject *kobj; @@ -260,12 +248,15 @@ static __init int secvar_sysfs_init(void) goto err; } =20 - rc =3D secvar_sysfs_config(secvar_kobj); + rc =3D plpks_config_create_softlink(secvar_kobj); if (rc) { - pr_err("Failed to create config directory\n"); + pr_err("Failed to create softlink to PLPKS config directory"); goto err; } =20 + pr_info("/sys/firmware/secvar/config is now deprecated.\n"); + pr_info("Will be removed in future versions.\n"); + if (secvar_ops->get_next) rc =3D secvar_sysfs_load(); else diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platfor= ms/pseries/Makefile index 931ebaa474c8..3ced289a675b 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_PAPR_SCM) +=3D papr_scm.o obj-$(CONFIG_PPC_SPLPAR) +=3D vphn.o obj-$(CONFIG_PPC_SVM) +=3D svm.o obj-$(CONFIG_FA_DUMP) +=3D rtas-fadump.o -obj-$(CONFIG_PSERIES_PLPKS) +=3D plpks.o +obj-$(CONFIG_PSERIES_PLPKS) +=3D plpks.o plpks-sysfs.o obj-$(CONFIG_PPC_SECURE_BOOT) +=3D plpks-secvar.o obj-$(CONFIG_PSERIES_PLPKS_SED) +=3D plpks_sed_ops.o obj-$(CONFIG_SUSPEND) +=3D suspend.o diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/p= latforms/pseries/plpks-secvar.c index f9e9cc40c9d0..a50ff6943d80 100644 --- a/arch/powerpc/platforms/pseries/plpks-secvar.c +++ b/arch/powerpc/platforms/pseries/plpks-secvar.c @@ -20,33 +20,6 @@ #include #include =20 -// Config attributes for sysfs -#define PLPKS_CONFIG_ATTR(name, fmt, func) \ - static ssize_t name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ - char *buf) \ - { \ - return sysfs_emit(buf, fmt, func()); \ - } \ - static struct kobj_attribute attr_##name =3D __ATTR_RO(name) - -PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version); -PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize); -PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize); -PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace); -PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicie= s); -PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedu= pdatealgorithms); - -static const struct attribute *config_attrs[] =3D { - &attr_version.attr, - &attr_max_object_size.attr, - &attr_total_size.attr, - &attr_used_space.attr, - &attr_supported_policies.attr, - &attr_signed_update_algorithms.attr, - NULL, -}; - static u32 get_policy(const char *name) { if ((strcmp(name, "db") =3D=3D 0) || @@ -225,7 +198,6 @@ static const struct secvar_operations plpks_secvar_ops_= static =3D { .set =3D plpks_set_variable, .format =3D plpks_secvar_format, .max_size =3D plpks_max_size, - .config_attrs =3D config_attrs, .var_names =3D plpks_var_names_static, }; =20 @@ -234,7 +206,6 @@ static const struct secvar_operations plpks_secvar_ops_= dynamic =3D { .set =3D plpks_set_variable, .format =3D plpks_secvar_format, .max_size =3D plpks_max_size, - .config_attrs =3D config_attrs, .var_names =3D plpks_var_names_dynamic, }; =20 diff --git a/arch/powerpc/platforms/pseries/plpks-sysfs.c b/arch/powerpc/pl= atforms/pseries/plpks-sysfs.c new file mode 100644 index 000000000000..01d526185783 --- /dev/null +++ b/arch/powerpc/platforms/pseries/plpks-sysfs.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 IBM Corporation, Srish Srinivasan + * + * This code exposes PLPKS config to user via sysfs + */ + +#define pr_fmt(fmt) "plpks-sysfs: "fmt + +#include +#include +#include +#include +#include + +/* config attributes for sysfs */ +#define PLPKS_CONFIG_ATTR(name, fmt, func) \ + static ssize_t name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *buf) \ + { \ + return sysfs_emit(buf, fmt, func()); \ + } \ + static struct kobj_attribute attr_##name =3D __ATTR_RO(name) + +PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version); +PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize); +PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize); +PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace); +PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicie= s); +PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", + plpks_get_signedupdatealgorithms); + +static const struct attribute *config_attrs[] =3D { + &attr_version.attr, + &attr_max_object_size.attr, + &attr_total_size.attr, + &attr_used_space.attr, + &attr_supported_policies.attr, + &attr_signed_update_algorithms.attr, + NULL, +}; + +static struct kobject *plpks_kobj, *plpks_config_kobj; + +int plpks_config_create_softlink(struct kobject *from) +{ + if (!plpks_config_kobj) + return -EINVAL; + return sysfs_create_link(from, plpks_config_kobj, "config"); +} + +static __init int plpks_sysfs_config(struct kobject *kobj) +{ + struct attribute_group config_group =3D { + .name =3D NULL, + .attrs =3D (struct attribute **)config_attrs, + }; + + return sysfs_create_group(kobj, &config_group); +} + +static __init int plpks_sysfs_init(void) +{ + int rc; + + if (!plpks_is_available()) + return -ENODEV; + + plpks_kobj =3D kobject_create_and_add("plpks", firmware_kobj); + if (!plpks_kobj) { + pr_err("Failed to create plpks kobj\n"); + return -ENOMEM; + } + + plpks_config_kobj =3D kobject_create_and_add("config", plpks_kobj); + if (!plpks_config_kobj) { + pr_err("Failed to create plpks config kobj\n"); + kobject_put(plpks_kobj); + return -ENOMEM; + } + + rc =3D plpks_sysfs_config(plpks_config_kobj); + if (rc) { + pr_err("Failed to create attribute group for plpks config\n"); + kobject_put(plpks_config_kobj); + kobject_put(plpks_kobj); + return rc; + } + + return 0; +} + +machine_subsys_initcall(pseries, plpks_sysfs_init); --=20 2.47.3 From nobody Sun Feb 8 15:59:17 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 EBEAE339853; Tue, 6 Jan 2026 15:06:28 +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=1767711991; cv=none; b=VOjNGVo5kUTl1G8m9nMOX/QcYGDFQi6ErrmeMg86QWth+8UQ/edg31VHTvbObahSpP3zMiS07CLBWye+a64b29pNFq4WVn4obiFpAxtHrastjEGv0DcYbpYZl2g5Lgms6oHc6Csi2oWoke7Z+Dhw5NMxdHR935m9XK7x0A2Zh7U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767711991; c=relaxed/simple; bh=o+HNAoXe5dmj0ZXKdP/IxAcP+iQNOhjsPp/2eXaFA04=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rPlA6jRykBxRhKjsaQMLwA2bJU5uVb2UY5fu13IBtDQqrCd1ek7oFS4ie1yI0L3z9IHMaoE2bAQRgbic3I0Qj+d4JgxvBh2PUEE6MWUPeFvFx/woplrvplbxaUy1K//nJN3DgMtzDTJNsNTjIgTzAondOVlHDotj2UdK6Yz+E94= 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=NZoFSFXA; 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="NZoFSFXA" 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 6062S8YI002998; Tue, 6 Jan 2026 15:06:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=E9q9MwLx+QxB8gPZo WTVfIF6m08d+i7ReyBrKfC6Vc8=; b=NZoFSFXAuKp8hdEUbjjyasmHZ4eEnPyeS cG8gPb+M3XttjTACaVvttpAdWO0O50ecqTayPhOp1sbrUcEc/zQRTW7Outg1XQPm EZ5Fp1a9e82upQqqvgk9sh6yWQLzsKI6sz48hUdDSA0+7/vmoNW4ao6UoQEoeeRH TW3XFAW5Tj1Ior0V39/NOiszByM227Ps1F09cq8rt8A2StTkrTKVX6Q0jP04YcQd xhj34OSU4kqlRk96Idtj+lAHhP23oxe6PevTQkNSIE6UOiXxbNdB07Z7deqw9+dZ 0I8qZISRpXGHGKPZHadIYc9wgGFD0zchSupmo0sWrsQNK35HNA6NQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4besheup8b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:13 +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 606F6DkF000791; Tue, 6 Jan 2026 15:06:13 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 4besheup89-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:13 +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 606Ctxlu014595; Tue, 6 Jan 2026 15:06:12 GMT Received: from smtprelay06.fra02v.mail.ibm.com ([9.218.2.230]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bfeemuyw5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:12 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay06.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 606F68B931785238 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 6 Jan 2026 15:06:08 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 30CE02004B; Tue, 6 Jan 2026 15:06:08 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0CBDC20040; Tue, 6 Jan 2026 15:05:58 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.214.6]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 6 Jan 2026 15:05:57 +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 v3 3/6] pseries/plpks: expose PowerVM wrapping features via the sysfs Date: Tue, 6 Jan 2026 20:35:24 +0530 Message-ID: <20260106150527.446525-4-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260106150527.446525-1-ssrish@linux.ibm.com> References: <20260106150527.446525-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: AW1haW4tMjYwMTA2MDEyOSBTYWx0ZWRfX1gzHik3CYd2j kx7Ssf6x+B2Bsj708jSSNaw6LCyM2He8McELdiptPgo7mPqZKmxgm4lplTG6rRNMQ011mxzY2+l 486sZ8AsWv6Jx8w2A24tsVhbkQjX4EYtU2hVBILdo/3WG0Ns1We0F0Puv4SdVOrwXGpXeVP3346 HR5PQQ7BAkhVfO2Or/DEpIOBygqfV+s7tzQM07VgS7f229GRNnLApA+DkfKKY/C6hzAlJp/w2TG vSOCGm1rjs3OI6ZDhj8IHx+bZjJU+1wExtxWQliyNi0LuJJ3u8+oqsy8xWFZR5sJAaR44Fc8Ni8 YUYta3JZhPRAZLBa9Z8RS6Y3k/2A53glYR59+V33PEZFdKRX/nVzo1LyLcUaGE0pl5O2xKZ7u7G oKYZZ+iA5yLg1+kWIU/GqLoTtE3Krc/qoKmEfhVCZOaHMkOOedgScDP6mw134W2KIGkN88jfvJI G+0+AneayeRCLfuIEeQ== X-Proofpoint-GUID: eJM8s1mKxJO8ih6RT1pvelLIx_3zjr72 X-Proofpoint-ORIG-GUID: 0llFYB6QUSqf6cItBX7ySUJfxzKMl9nM X-Authority-Analysis: v=2.4 cv=AOkvhdoa c=1 sm=1 tr=0 ts=695d24e5 cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=z7cUUKlKUSfJ7xv5IYMA:9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-06_01,2026-01-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 spamscore=0 adultscore=0 malwarescore=0 impostorscore=0 clxscore=1015 suspectscore=0 bulkscore=0 phishscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601060129 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 --- .../ABI/testing/sysfs-firmware-plpks | 8 ++++++++ arch/powerpc/include/asm/hvcall.h | 4 +++- arch/powerpc/include/asm/plpks.h | 3 +++ arch/powerpc/platforms/pseries/plpks-sysfs.c | 2 ++ arch/powerpc/platforms/pseries/plpks.c | 20 +++++++++++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-firmware-plpks b/Documentation= /ABI/testing/sysfs-firmware-plpks index af0353f34115..cba061e4eee2 100644 --- a/Documentation/ABI/testing/sysfs-firmware-plpks +++ b/Documentation/ABI/testing/sysfs-firmware-plpks @@ -48,3 +48,11 @@ Description: Bitmask of flags indicating which algorithm= s the hypervisor supports for signed update of objects, represented as a 16 byte hexadecimal ASCII string. Consult the hypervisor documentation for what these flags mean. + +What: /sys/firmware/plpks/config/wrapping_features +Date: November 2025 +Contact: Srish Srinivasan +Description: Bitmask of the wrapping features indicating the wrapping + algorithms that are supported for the H_PKS_WRAP_OBJECT requests + , represented as a 8 byte hexadecimal ASCII string. Consult the + hypervisor documentation for what these flags mean. diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/h= vcall.h index 9aef16149d92..dff90a7d7f70 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -360,7 +360,9 @@ #define H_GUEST_RUN_VCPU 0x480 #define H_GUEST_COPY_MEMORY 0x484 #define H_GUEST_DELETE 0x488 -#define MAX_HCALL_OPCODE H_GUEST_DELETE +#define H_PKS_WRAP_OBJECT 0x490 +#define H_PKS_UNWRAP_OBJECT 0x494 +#define MAX_HCALL_OPCODE H_PKS_UNWRAP_OBJECT =20 /* Scope args for H_SCM_UNBIND_ALL */ #define H_UNBIND_SCOPE_ALL (0x1) diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index 8829a13bfda0..8f034588fdf7 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -23,6 +23,7 @@ #define PLPKS_IMMUTABLE PPC_BIT32(5) // Once written, object cannot be re= moved #define PLPKS_TRANSIENT PPC_BIT32(6) // Object does not persist through r= eboot #define PLPKS_SIGNEDUPDATE PPC_BIT32(7) // Object can only be modified by = signed updates +#define PLPKS_WRAPPINGKEY PPC_BIT32(8) // Object contains a wrapping key #define PLPKS_HVPROVISIONED PPC_BIT32(28) // Hypervisor has provisioned th= is object =20 // Signature algorithm flags from signed_update_algorithms @@ -103,6 +104,8 @@ u32 plpks_get_maxlargeobjectsize(void); =20 u64 plpks_get_signedupdatealgorithms(void); =20 +u64 plpks_get_wrappingfeatures(void); + u16 plpks_get_passwordlen(void); =20 void plpks_early_init_devtree(void); diff --git a/arch/powerpc/platforms/pseries/plpks-sysfs.c b/arch/powerpc/pl= atforms/pseries/plpks-sysfs.c index 01d526185783..c2ebcbb41ae3 100644 --- a/arch/powerpc/platforms/pseries/plpks-sysfs.c +++ b/arch/powerpc/platforms/pseries/plpks-sysfs.c @@ -30,6 +30,7 @@ PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace= ); PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicie= s); PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms); +PLPKS_CONFIG_ATTR(wrapping_features, "%016llx\n", plpks_get_wrappingfeatur= es); =20 static const struct attribute *config_attrs[] =3D { &attr_version.attr, @@ -38,6 +39,7 @@ static const struct attribute *config_attrs[] =3D { &attr_used_space.attr, &attr_supported_policies.attr, &attr_signed_update_algorithms.attr, + &attr_wrapping_features.attr, NULL, }; =20 diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platform= s/pseries/plpks.c index 03722fabf9c3..4a08f51537c8 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -38,6 +38,7 @@ static u32 usedspace; static u32 supportedpolicies; static u32 maxlargeobjectsize; static u64 signedupdatealgorithms; +static u64 wrappingfeatures; =20 struct plpks_auth { u8 version; @@ -248,6 +249,7 @@ static int _plpks_get_config(void) __be32 supportedpolicies; __be32 maxlargeobjectsize; __be64 signedupdatealgorithms; + __be64 wrappingfeatures; u8 rsvd1[476]; } __packed * config; size_t size; @@ -280,6 +282,7 @@ static int _plpks_get_config(void) supportedpolicies =3D be32_to_cpu(config->supportedpolicies); maxlargeobjectsize =3D be32_to_cpu(config->maxlargeobjectsize); signedupdatealgorithms =3D be64_to_cpu(config->signedupdatealgorithms); + wrappingfeatures =3D be64_to_cpu(config->wrappingfeatures); =20 // Validate that the numbers we get back match the requirements of the sp= ec if (maxpwsize < 32) { @@ -472,6 +475,23 @@ u64 plpks_get_signedupdatealgorithms(void) return signedupdatealgorithms; } =20 +/** + * plpks_get_wrappingfeatures() - Returns a bitmask of the wrapping featur= es + * supported by the hypervisor. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * reads a bitmask of the wrapping features supported by the hypervisor in= to the + * file local static wrappingfeatures variable. This is valid only when the + * PLPKS config structure version >=3D 3. + * + * Return: + * bitmask of the wrapping features supported by the hypervisor + */ +u64 plpks_get_wrappingfeatures(void) +{ + return wrappingfeatures; +} + /** * plpks_get_passwordlen() - Get the length of the PLPKS password in bytes. * --=20 2.47.3 From nobody Sun Feb 8 15:59:17 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 2D9BA339866; Tue, 6 Jan 2026 15:06:34 +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=1767712000; cv=none; b=PGSfAv4f7cif6SFSFBBjRi0xglOXeWWSqqhnI6N5mnZGP8ThDpi1XzYUzy9JIlNw4FoirOcVoEVmRBpiRzZr+BUDIw1M7iuTHgWkgz+zbBW4xqVXNJxv8p6eYBWETML8juAyRQoV63zze0hwEx65DNCrqsJ7xZwIGQyllV/sUsA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767712000; c=relaxed/simple; bh=EO9Tig3LhbapD+MHuJBvhoq42q2dpqC+RXL2MlMDSuc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZeYIRY3ERmuw3xGexXyPSfPteXvKPJesKwsdpZZo9Rj+ChP3wdgVehgCuQ+SbowrCPaXjMD3A7ManZwiGkuvE0JevUycAHgbesjoy+NfX5/pe7OTyOmWE16OiXeX03Z992LvfWee3RFXYQgN5yH5ZCfC7TqM9AbFO3VBTelplfg= 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=gIQPkNMh; 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="gIQPkNMh" Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 606F2xx2028393; Tue, 6 Jan 2026 15:06:21 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=K+Od8GxrmnkejjBFN +JWdeN3Q1DWJCSa8u930e/Rdjc=; b=gIQPkNMhAj9bvOSCi8rbH85Fizk+SDqmJ s2C4QTIyROO+J935xaDzDLAx6SsBL9sEV3dSDCvHtFKGIs88pm9ArxyMZpZ0CGTU BkRdrz5Z1OiS3zk5jfRNeXHyt//POrGKfbTnZbg3KJd1x9MYebKpMqNIrSCz90kz tzMhUpMDMdpJEdeUtqrZsv0QYaMyljdxgFi9g6FJ03gH41IA3g92i+AOYIBmmSlQ /2ZJRCZNPdRh2P9SWnVjPqb44cgBTs3W4iHyiRPEfH1Rh/thn6OoszEQZEPeIBps R6MVb4BHA61Yd/eIktEyj+PpLlHzMixwf/XWYXEfTJTHnEXEGG2mg== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4betrtkjm2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:20 +0000 (GMT) Received: from m0360072.ppops.net (m0360072.ppops.net [127.0.0.1]) by pps.reinject (8.18.1.12/8.18.0.8) with ESMTP id 606F4UI6023157; Tue, 6 Jan 2026 15:06:20 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 4betrtkjky-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:20 +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 606DV8MT014503; Tue, 6 Jan 2026 15:06:19 GMT Received: from smtprelay01.fra02v.mail.ibm.com ([9.218.2.227]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4bfeemuywj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:19 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay01.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 606F6EX258917288 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 6 Jan 2026 15:06:15 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DA79320043; Tue, 6 Jan 2026 15:06:14 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8A7FE20040; Tue, 6 Jan 2026 15:06:08 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.214.6]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 6 Jan 2026 15:06:08 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v3 4/6] pseries/plpks: add HCALLs for PowerVM Key Wrapping Module Date: Tue, 6 Jan 2026 20:35:25 +0530 Message-ID: <20260106150527.446525-5-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260106150527.446525-1-ssrish@linux.ibm.com> References: <20260106150527.446525-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=aaJsXBot c=1 sm=1 tr=0 ts=695d24ec cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=nO4dFLMeAchwtJrxA4IA:9 a=POYjf8jjcDEwoKyR:21 X-Proofpoint-GUID: 3O9WBkDyT7f1i3ALqM4ynwnPYZmr6cN4 X-Proofpoint-ORIG-GUID: gO3Sz3Kwre_WJ086W51DTQakSMEsmfj6 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTA2MDEyOSBTYWx0ZWRfX6r33HHiCpRQh 4Y+QuSmEUgz7pozkUjXDqWcbe6UxzYWCX1m5jBQvvpT94j6oIgsy9WHGwJPFlN6dVgL9NMZ/2tb zcziPL6JdHd1+/16/9MpOL9L8t6TGmDySMPEzrtX5izDyahgGGkV47LJrpypVDRAblF3mtrQV5I yWXZ07rEAtikgQDJITQ9Qoyt+xGY8Yahf2WyE514X6HjVVD9medBulKPa4A9EXDPtMe+GBEslOq 2Tf4ArOvJrdESDI+BoLv6h/zbc8f4wOa4JFP4DLDmmrFneybcD7mKAVURb8XTS4RV+wgHCSk3Hy 2kW6nz7YZGzzZCv52GSvZO8EYtCQyXScHvd5+55O6mUk5GVGyCZ7eR/6HhWcE/mlZLCMAIT07lU vlnIB1W8jgHI9Uww0Ef2hwSf3pdpEkxlyXqCP1OUK8/ZpiNBRvzWBe3RwfZAMXV3WgNzrYrDoja JlpwAlq6KCLLp1/w7MA== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-06_01,2026-01-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 adultscore=0 lowpriorityscore=0 bulkscore=0 malwarescore=0 priorityscore=1501 clxscore=1015 phishscore=0 spamscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601060129 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 --- Documentation/arch/powerpc/papr_hcalls.rst | 43 +++ arch/powerpc/include/asm/plpks.h | 10 + arch/powerpc/platforms/pseries/plpks.c | 342 ++++++++++++++++++++- 3 files changed, 393 insertions(+), 2 deletions(-) diff --git a/Documentation/arch/powerpc/papr_hcalls.rst b/Documentation/arc= h/powerpc/papr_hcalls.rst index 805e1cb9bab9..14e39f095a1c 100644 --- a/Documentation/arch/powerpc/papr_hcalls.rst +++ b/Documentation/arch/powerpc/papr_hcalls.rst @@ -300,6 +300,49 @@ H_HTM supports setup, configuration, control and dumpi= ng of Hardware Trace Macro (HTM) function and its data. HTM buffer stores tracing data for func= tions like core instruction, core LLAT and nest. =20 +**H_PKS_GEN_KEY** + +| Input: authorization, objectlabel, objectlabellen, policy, out, outlen +| Out: *Hypervisor Generated Key, or None when the wrapping key policy is = set* +| Return Value: *H_SUCCESS, H_Function, H_State, H_R_State, H_Parameter, H= _P2, + H_P3, H_P4, H_P5, H_P6, H_Authority, H_Nomem, H_Busy, H_Re= source, + H_Aborted* + +H_PKS_GEN_KEY is used to have the hypervisor generate a new random key. +This key is stored as an object in the Power LPAR Platform KeyStore with +the provided object label. With the wrapping key policy set the key is only +visible to the hypervisor, while the key's label would still be visible to +the user. Generation of wrapping keys is supported only for a key size of +32 bytes. + +**H_PKS_WRAP_OBJECT** + +| Input: authorization, wrapkeylabel, wrapkeylabellen, objectwrapflags, in, +| inlen, out, outlen, continue-token +| Out: *continue-token, byte size of wrapped object, wrapped object* +| Return Value: *H_SUCCESS, H_Function, H_State, H_R_State, H_Parameter, H= _P2, + H_P3, H_P4, H_P5, H_P6, H_P7, H_P8, H_P9, H_Authority, H_I= nvalid_Key, + H_NOT_FOUND, H_Busy, H_LongBusy, H_Aborted* + +H_PKS_WRAP_OBJECT is used to wrap an object using a wrapping key stored in= the +Power LPAR Platform KeyStore and return the wrapped object to the caller. = The +caller provides a label to a wrapping key with the 'wrapping key' policy s= et, +which must have been previously created with H_PKS_GEN_KEY. The provided o= bject +is then encrypted with the wrapping key and additional metadata and the re= sult +is returned to the caller. + + +**H_PKS_UNWRAP_OBJECT** + +| Input: authorization, objectwrapflags, in, inlen, out, outlen, continue-= token +| Out: *continue-token, byte size of unwrapped object, unwrapped object* +| Return Value: *H_SUCCESS, H_Function, H_State, H_R_State, H_Parameter, H= _P2, + H_P3, H_P4, H_P5, H_P6, H_P7, H_Authority, H_Unsupported, = H_Bad_Data, + H_NOT_FOUND, H_Invalid_Key, H_Busy, H_LongBusy, H_Aborted* + +H_PKS_UNWRAP_OBJECT is used to unwrap an object that was previously warapp= ed with +H_PKS_WRAP_OBJECT. + References =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D .. [1] "Power Architecture Platform Reference" diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/pl= pks.h index 8f034588fdf7..e87f90e40d4e 100644 --- a/arch/powerpc/include/asm/plpks.h +++ b/arch/powerpc/include/asm/plpks.h @@ -113,6 +113,16 @@ void plpks_early_init_devtree(void); int plpks_populate_fdt(void *fdt); =20 int plpks_config_create_softlink(struct kobject *from); + +bool plpks_wrapping_is_supported(void); + +int plpks_gen_wrapping_key(void); + +int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags, + u8 **output_buf, u32 *output_len); + +int plpks_unwrap_object(u8 **input_buf, u32 input_len, + u8 **output_buf, u32 *output_len); #else // CONFIG_PSERIES_PLPKS static inline bool plpks_is_available(void) { return false; } static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); } diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platform= s/pseries/plpks.c index 4a08f51537c8..b97b7750f6a8 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -9,6 +9,32 @@ =20 #define pr_fmt(fmt) "plpks: " fmt =20 +#define PLPKS_WRAPKEY_COMPONENT "PLPKSWR" +#define PLPKS_WRAPKEY_NAME "default-wrapping-key" + +/* + * To 4K align the {input, output} buffers to the {UN}WRAP H_CALLs + */ +#define PLPKS_WRAPPING_BUF_ALIGN 4096 + +/* + * To ensure the output buffer's length is at least 1024 bytes greater + * than the input buffer's length during the WRAP H_CALL + */ +#define PLPKS_WRAPPING_BUF_DIFF 1024 + +#define PLPKS_WRAP_INTERFACE_BIT 3 +#define PLPKS_WRAPPING_KEY_LENGTH 32 + +#define WRAPFLAG_BE_BIT_SET(be_bit) \ + BIT_ULL(63 - (be_bit)) + +#define WRAPFLAG_BE_GENMASK(be_bit_hi, be_bit_lo) \ + GENMASK_ULL(63 - (be_bit_hi), 63 - (be_bit_lo)) + +#define WRAPFLAG_BE_FIELD_PREP(be_bit_hi, be_bit_lo, val) \ + FIELD_PREP(WRAPFLAG_BE_GENMASK(be_bit_hi, be_bit_lo), (val)) + #include #include #include @@ -39,6 +65,7 @@ static u32 supportedpolicies; static u32 maxlargeobjectsize; static u64 signedupdatealgorithms; static u64 wrappingfeatures; +static bool wrapsupport; =20 struct plpks_auth { u8 version; @@ -283,6 +310,7 @@ static int _plpks_get_config(void) maxlargeobjectsize =3D be32_to_cpu(config->maxlargeobjectsize); signedupdatealgorithms =3D be64_to_cpu(config->signedupdatealgorithms); wrappingfeatures =3D be64_to_cpu(config->wrappingfeatures); + wrapsupport =3D config->flags & PPC_BIT8(PLPKS_WRAP_INTERFACE_BIT); =20 // Validate that the numbers we get back match the requirements of the sp= ec if (maxpwsize < 32) { @@ -614,6 +642,9 @@ int plpks_signed_update_var(struct plpks_var *var, u64 = flags) if (!(var->policy & PLPKS_SIGNEDUPDATE)) return -EINVAL; =20 + if (var->policy & PLPKS_WRAPPINGKEY) + return -EINVAL; + // Signed updates need the component to be NULL. if (var->component) return -EINVAL; @@ -696,6 +727,9 @@ int plpks_write_var(struct plpks_var var) if (var.policy & PLPKS_SIGNEDUPDATE) return -EINVAL; =20 + if (var.policy & PLPKS_WRAPPINGKEY) + return -EINVAL; + auth =3D construct_auth(PLPKS_OS_OWNER); if (IS_ERR(auth)) return PTR_ERR(auth); @@ -790,6 +824,9 @@ static int plpks_read_var(u8 consumer, struct plpks_var= *var) if (var->namelen > PLPKS_MAX_NAME_SIZE) return -EINVAL; =20 + if (var->policy & PLPKS_WRAPPINGKEY) + return -EINVAL; + auth =3D construct_auth(consumer); if (IS_ERR(auth)) return PTR_ERR(auth); @@ -845,8 +882,309 @@ static int plpks_read_var(u8 consumer, struct plpks_v= ar *var) } =20 /** - * plpks_read_os_var() - Fetch the data for the specified variable that is - * owned by the OS consumer. + * plpks_wrapping_is_supported() - Get the H_PKS_WRAP_OBJECT interface + * availability status for the LPAR. + * + * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization + * sets bit 3 of the flags variable in the PLPKS config structure if the + * H_PKS_WRAP_OBJECT interface is supported. + * + * Returns: true if the H_PKS_WRAP_OBJECT interface is supported, false if= not. + */ +bool plpks_wrapping_is_supported(void) +{ + return wrapsupport; +} + +/** + * plpks_gen_wrapping_key() - Generate a new random key with the 'wrapping= key' + * policy set. + * + * The H_PKS_GEN_KEY HCALL makes the hypervisor generate a new random key = and + * store the key in a PLPKS object with the provided object label. With the + * 'wrapping key' policy set, only the label to the newly generated random= key + * would be visible to the user. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid object label parameter + * if invalid object label len parameter + * if invalid or unsupported policy declaration + * if invalid output buffer parameter + * if invalid output buffer length parameter + * -EPERM if access is denied + * -ENOMEM if there is inadequate memory to perform this operation + * -EBUSY if unable to handle the request + * -EEXIST if the object label already exists + * + * Returns: On success 0 is returned, a negative errno if not. + */ +int plpks_gen_wrapping_key(void) +{ + unsigned long retbuf[PLPAR_HCALL_BUFSIZE] =3D { 0 }; + struct plpks_auth *auth; + struct label *label; + int rc =3D 0, pseries_status =3D 0; + struct plpks_var var =3D { + .name =3D PLPKS_WRAPKEY_NAME, + .namelen =3D strlen(var.name), + .policy =3D PLPKS_WRAPPINGKEY, + .os =3D PLPKS_VAR_LINUX, + .component =3D PLPKS_WRAPKEY_COMPONENT + }; + + auth =3D construct_auth(PLPKS_OS_OWNER); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + label =3D construct_label(var.component, var.os, var.name, var.namelen); + if (IS_ERR(label)) { + rc =3D PTR_ERR(label); + goto out; + } + + rc =3D plpar_hcall(H_PKS_GEN_KEY, retbuf, + virt_to_phys(auth), virt_to_phys(label), + label->size, var.policy, + NULL, PLPKS_WRAPPING_KEY_LENGTH); + + if (!rc) + rc =3D plpks_confirm_object_flushed(label, auth); + + pseries_status =3D rc; + rc =3D pseries_status_to_err(rc); + + if (rc && rc !=3D -EEXIST) { + pr_err("H_PKS_GEN_KEY failed. pseries_status=3D%d, rc=3D%d", + pseries_status, rc); + } else { + rc =3D 0; + } + + kfree(label); +out: + kfree(auth); + return rc; +} +EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key); + +/** + * plpks_wrap_object() - Wrap an object using the default wrapping key sto= red in + * the PLPKS. + * @input_buf: buffer containing the data to be wrapped + * @input_len: length of the input buffer + * @wrap_flags: object wrapping flags + * @output_buf: buffer to store the wrapped data + * @output_len: length of the output buffer + * + * The H_PKS_WRAP_OBJECT HCALL wraps an object using a wrapping key stored= in + * the PLPKS and returns the wrapped object to the caller. The caller prov= ides a + * label to the wrapping key with the 'wrapping key' policy set that must = have + * been previously created with the H_PKS_GEN_KEY HCALL. The provided obje= ct is + * then encrypted with the wrapping key and additional metadata and the re= sult + * is returned to the user. The metadata includes the wrapping algorithm a= nd the + * wrapping key name so those parameters are not required during unwrap. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid wrapping key label parameter + * if invalid wrapping key label length parameter + * if invalid or unsupported object wrapping flags + * if invalid input buffer parameter + * if invalid input buffer length parameter + * if invalid output buffer parameter + * if invalid output buffer length parameter + * if invalid continue token parameter + * if the wrapping key is not compatible with the wrapping + * algorithm + * -EPERM if access is denied + * -ENOENT if the requested wrapping key was not found + * -EBUSY if unable to handle the request or long running operation + * initiated, retry later. + * + * Returns: On success 0 is returned, a negative errno if not. + */ +int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags, + u8 **output_buf, u32 *output_len) +{ + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] =3D { 0 }; + struct plpks_auth *auth; + struct label *label; + u64 continuetoken =3D 0; + u64 objwrapflags =3D 0; + int rc =3D 0, pseries_status =3D 0; + bool sb_audit_or_enforce_bit =3D wrap_flags & BIT(0); + bool sb_enforce_bit =3D wrap_flags & BIT(1); + struct plpks_var var =3D { + .name =3D PLPKS_WRAPKEY_NAME, + .namelen =3D strlen(var.name), + .os =3D PLPKS_VAR_LINUX, + .component =3D PLPKS_WRAPKEY_COMPONENT + }; + + auth =3D construct_auth(PLPKS_OS_OWNER); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + label =3D construct_label(var.component, var.os, var.name, var.namelen); + if (IS_ERR(label)) { + rc =3D PTR_ERR(label); + goto out; + } + + /* Set the consumer password requirement bit. A must have. */ + objwrapflags |=3D WRAPFLAG_BE_BIT_SET(3); + + /* Set the wrapping algorithm bit. Just one algorithm option for now */ + objwrapflags |=3D WRAPFLAG_BE_FIELD_PREP(60, 63, 0x1); + + if (sb_audit_or_enforce_bit & sb_enforce_bit) { + pr_err("Cannot set both audit/enforce and enforce bits."); + rc =3D -EINVAL; + goto out_free_label; + } else if (sb_audit_or_enforce_bit) { + objwrapflags |=3D WRAPFLAG_BE_BIT_SET(1); + } else if (sb_enforce_bit) { + objwrapflags |=3D WRAPFLAG_BE_BIT_SET(2); + } + + *output_len =3D input_len + PLPKS_WRAPPING_BUF_DIFF; + + *output_buf =3D kzalloc(ALIGN(*output_len, PLPKS_WRAPPING_BUF_ALIGN), + GFP_KERNEL); + if (!(*output_buf)) { + pr_err("Output buffer allocation failed. Returning -ENOMEM."); + rc =3D -ENOMEM; + goto out_free_label; + } + + do { + rc =3D plpar_hcall9(H_PKS_WRAP_OBJECT, retbuf, + virt_to_phys(auth), virt_to_phys(label), + label->size, objwrapflags, + virt_to_phys(*input_buf), input_len, + virt_to_phys(*output_buf), *output_len, + continuetoken); + + continuetoken =3D retbuf[0]; + pseries_status =3D rc; + rc =3D pseries_status_to_err(rc); + } while (rc =3D=3D -EBUSY); + + if (rc) { + pr_err("H_PKS_WRAP_OBJECT failed. pseries_status=3D%d, rc=3D%d", + pseries_status, rc); + kfree(*output_buf); + *output_buf =3D NULL; + } else { + *output_len =3D retbuf[1]; + } + +out_free_label: + kfree(label); +out: + kfree(auth); + return rc; +} +EXPORT_SYMBOL_GPL(plpks_wrap_object); + +/** + * plpks_unwrap_object() - Unwrap an object using the default wrapping key + * stored in the PLPKS. + * @input_buf: buffer containing the data to be unwrapped + * @input_len: length of the input buffer + * @output_buf: buffer to store the unwrapped data + * @output_len: length of the output buffer + * + * The H_PKS_UNWRAP_OBJECT HCALL unwraps an object that was previously wra= pped + * using the H_PKS_WRAP_OBJECT HCALL. + * + * Possible reasons for the returned errno values: + * + * -ENXIO if PLPKS is not supported + * -EIO if PLPKS access is blocked due to the LPAR's state + * if PLPKS modification is blocked due to the LPAR's state + * if an error occurred while processing the request + * -EINVAL if invalid authorization parameter + * if invalid or unsupported object unwrapping flags + * if invalid input buffer parameter + * if invalid input buffer length parameter + * if invalid output buffer parameter + * if invalid output buffer length parameter + * if invalid continue token parameter + * if the wrapping key is not compatible with the wrapping + * algorithm + * if the wrapped object's format is not supported + * if the wrapped object is invalid + * -EPERM if access is denied + * -ENOENT if the wrapping key for the provided object was not found + * -EBUSY if unable to handle the request or long running operation + * initiated, retry later. + * + * Returns: On success 0 is returned, a negative errno if not. + */ +int plpks_unwrap_object(u8 **input_buf, u32 input_len, u8 **output_buf, + u32 *output_len) +{ + unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] =3D { 0 }; + struct plpks_auth *auth; + u64 continuetoken =3D 0; + u64 objwrapflags =3D 0; + int rc =3D 0, pseries_status =3D 0; + + auth =3D construct_auth(PLPKS_OS_OWNER); + if (IS_ERR(auth)) + return PTR_ERR(auth); + + *output_len =3D input_len - PLPKS_WRAPPING_BUF_DIFF; + *output_buf =3D kzalloc(ALIGN(*output_len, PLPKS_WRAPPING_BUF_ALIGN), + GFP_KERNEL); + if (!(*output_buf)) { + pr_err("Output buffer allocation failed. Returning -ENOMEM."); + rc =3D -ENOMEM; + goto out; + } + + do { + rc =3D plpar_hcall9(H_PKS_UNWRAP_OBJECT, retbuf, + virt_to_phys(auth), objwrapflags, + virt_to_phys(*input_buf), input_len, + virt_to_phys(*output_buf), *output_len, + continuetoken); + + continuetoken =3D retbuf[0]; + pseries_status =3D rc; + rc =3D pseries_status_to_err(rc); + } while (rc =3D=3D -EBUSY); + + if (rc) { + pr_err("H_PKS_UNWRAP_OBJECT failed. pseries_status=3D%d, rc=3D%d", + pseries_status, rc); + kfree(*output_buf); + *output_buf =3D NULL; + } else { + *output_len =3D retbuf[1]; + } + +out: + kfree(auth); + return rc; +} +EXPORT_SYMBOL_GPL(plpks_unwrap_object); + +/** + * plpks_read_os_var() - Fetch the data for the specified variable that is= owned + * by the OS consumer. * @var: variable to be read from the PLPKS * * The consumer or the owner of the object is the os kernel. The --=20 2.47.3 From nobody Sun Feb 8 15:59:17 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 2F31333C1AC; Tue, 6 Jan 2026 15:06:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767712008; cv=none; b=AGhvQLHoLkhB6tQ0j1Chr8qVyGdvaZPzAUqlhkKQYven4Z21zVypwCrcQN6iX708rPw8eSfTDPIOzVkh3t4iWvPiJqoRiBrWc34pHlYIW3CkB9LaquSd1ZoOkZUeQSzbp3yldkM9uKHOqI13Vleo2Tt8aTHRGsD44X8JglYM1GA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767712008; c=relaxed/simple; bh=mfmgNmNhNh2yEKEMtswZS8CfpOkqmjXjNuzqRSjS/kw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=A8Jv6H0CTU8Gfapokxs7A1pZSxSls9o+bUONKAThg09F9bawaGLcT0KFs5jixNzFFF4JCft/7t8Yj4+M83N+Js9ELnwlj7siBvY/MhGbsQJMY8gl5wBhWYyD7zfWoLaZTnn9UPpOSGhEXFFSDAntCTYAp7aVzXbb2JTkvKmyTzU= 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=YXHTG/JQ; 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="YXHTG/JQ" 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 6062UbrT019611; Tue, 6 Jan 2026 15:06:28 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=xDBxcISNOWJvWwLKw V3ZsoV8qyzYOiD+man+szZctG4=; b=YXHTG/JQNFZVmxf2qeHhMBCJrfLpKx1RG KiE6jbx/vc5RXZYiZ42TmgBWWDFw9ecn8PeudXRibJMwSv8Ac4duqAqhHaw4dt4G MrlT///+jfULk3+noXXU2k/pX/LAL7i0/s3irPC4Y+TcLMOMwt5Ilg2KWN+k+ZgJ U8YA49Kol+S1rA2GP+vwSsGBvgb+EBuv3ydCkxZ6IzH4Sg2V81/xxduOeQIfz1TL z7BEzD/XTNvuBANNBZgCX7QmbngbV1kKsm6gSp9uhTxNerrjuV8yA1a/z1gNfv3q Lycc+E6VpHn4yktQcWdzwQRJE2VuxBiUfYf1XwNhXPhNc1Oi0Sbjw== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4berhk3uef-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:28 +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 606F6Rqs030797; Tue, 6 Jan 2026 15:06:27 GMT Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4berhk3ue9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:27 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 606E1YeF019166; Tue, 6 Jan 2026 15:06:26 GMT Received: from smtprelay07.fra02v.mail.ibm.com ([9.218.2.229]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bfg513q80-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:26 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay07.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 606F6Nm139846288 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 6 Jan 2026 15:06:23 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id ED44B20043; Tue, 6 Jan 2026 15:06:22 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 40E9E20040; Tue, 6 Jan 2026 15:06:15 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.214.6]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 6 Jan 2026 15:06:15 +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 v3 5/6] keys/trusted_keys: establish PKWM as a trusted source Date: Tue, 6 Jan 2026 20:35:26 +0530 Message-ID: <20260106150527.446525-6-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260106150527.446525-1-ssrish@linux.ibm.com> References: <20260106150527.446525-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=P4s3RyAu c=1 sm=1 tr=0 ts=695d24f4 cx=c_pps a=aDMHemPKRhS1OARIsFnwRA==:117 a=aDMHemPKRhS1OARIsFnwRA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=VwQbUJbxAAAA:8 a=SGwaXr-4V_wxwTcTBwMA:9 X-Proofpoint-ORIG-GUID: vnPkrhGbMrRSLHEeiXK4pTY2F22dh7oe X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTA2MDEyOSBTYWx0ZWRfXwyqjdVCWwqLn QwEfaYdcvIk6gWfs8L9naMgB7wcH+1V61CM4h0vp9wfG1je8TE6VA7+u9ly/zRod0GsFIIf2syd c7zbj7STTs2lqwcxX0Rh/idJ6J2FBGsXAjedXVP6Xb06v8HjW4z8IXbiicAMWCbwlhCMtXd1WJ1 k/SY7os65aYUgqKTk0SKEw0L4UvIaXTUTInlhMc440rqoAXm1q8wRg90zh710siAYdW+gqEP7HL vKWKH6wsK1pGWxq2GLK831s1ghuM6RIG0XLpOJ11NaV2PYZLNCoM5qcWQXIjgwpufXFzu3s7BhO lbI8hIhJxs8j8y0d6FKuiZAjDXMqiL9i1epdeWx24GFlIZIL9o5UK96pdbCOmSCXmzEyLbon1IN +QjOl/rYlHjTBMtnRpSiMuyep8B5ZECClVDabi34nV1yfrjYe+hX/Au3mcwBtrCGHkG+HhAQ2Gu qRAP5LHlg3Vfw7SPphQ== X-Proofpoint-GUID: lsG-O-ANMj0T7dIYgdbA7fGV4iChZNV7 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-06_01,2026-01-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 bulkscore=0 priorityscore=1501 clxscore=1015 suspectscore=0 phishscore=0 adultscore=0 spamscore=0 impostorscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601060129 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 --- MAINTAINERS | 9 ++ include/keys/trusted-type.h | 7 +- include/keys/trusted_pkwm.h | 22 +++ 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 | 168 ++++++++++++++++++++++ 7 files changed, 220 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 a0dd762f5648..ba51eff21a16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14003,6 +14003,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_plpks.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..45c6c538df22 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; + uint16_t wrap_flags; }; =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..c7249d08b4d8 --- /dev/null +++ b/include/keys/trusted_pkwm.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PKWM_TRUSTED_KEY_H +#define __PKWM_TRUSTED_KEY_H + +#include + +extern struct trusted_key_ops pkwm_trusted_key_ops; + +static inline void dump_options(struct trusted_key_options *o) +{ + bool sb_audit_or_enforce_bit =3D o->wrap_flags & BIT(0); + bool sb_enforce_bit =3D o->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..d822b81afacf --- /dev/null +++ b/security/keys/trusted-keys/trusted_pkwm.c @@ -0,0 +1,168 @@ +// 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; + unsigned long wrap_flags; + unsigned long token_mask =3D 0; + + if (!datablob) + return 0; + + 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 kstrtoul(args[0].from, 16, &wrap_flags); + if (res < 0 || wrap_flags > 2) + return -EINVAL; + (*opt)->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; + + options =3D kzalloc(sizeof(*options), GFP_KERNEL); + return options; +} + +static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob) +{ + struct trusted_key_options *options =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."); + return -ENOMEM; + } + + memcpy(input_buf, p->key, p->key_len); + + rc =3D plpks_wrap_object(&input_buf, input_len, options->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); + return rc; +} + +static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *databl= ob) +{ + u8 *input_buf, *output_buf; + u32 input_len, output_len; + int rc; + + input_len =3D p->blob_len; + input_buf =3D kmalloc(ALIGN(input_len, 4096), GFP_KERNEL); + if (!input_buf) { + pr_err("Input buffer allocation failed. Returning -ENOMEM."); + return -ENOMEM; + } + + memcpy(input_buf, p->blob, p->blob_len); + + rc =3D plpks_unwrap_object(&input_buf, input_len, &output_buf, + &output_len); + if (!rc) { + memcpy(p->key, output_buf, output_len); + p->key_len =3D output_len; + dump_payload(p); + } else { + pr_err("Unwrapping of payload failed: %d\n", rc); + } + + kfree(input_buf); + kfree(output_buf); + + return rc; +} + +static int trusted_pkwm_init(void) +{ + int ret; + + if (!plpks_wrapping_is_supported()) { + pr_err("H_PKS_WRAP_OBJECT interface not supported\n"); + return -ENODEV; + } + + ret =3D plpks_gen_wrapping_key(); + if (ret) { + pr_err("Failed to generate default wrapping key\n"); + return -EINVAL; + } + + return register_key_type(&key_type_trusted); +} + +static void trusted_pkwm_exit(void) +{ + unregister_key_type(&key_type_trusted); +} + +struct trusted_key_ops pkwm_trusted_key_ops =3D { + .migratable =3D 0, /* non-migratable */ + .init =3D trusted_pkwm_init, + .seal =3D trusted_pkwm_seal, + .unseal =3D trusted_pkwm_unseal, + .exit =3D trusted_pkwm_exit, +}; --=20 2.47.3 From nobody Sun Feb 8 15:59:17 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 B378D33A6F4; Tue, 6 Jan 2026 15:06:53 +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=1767712017; cv=none; b=AcdkH4VAN8rwGXLFMYEdhA2ONLO+ffSUhvVIhetlVqy5SWUk5xB7qDKCQ+LUvOUrA/KvY08N/B91EAiA+03ekUamCNkyXwDuC8PKnXc4icOwWMyCOZ+jb5ZFQneXlIGgrQAfcM1TPIV63dQng6atkl+beOul0N8v02ps5uqC4VI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767712017; c=relaxed/simple; bh=aqRdULq4kucJKLo7juH0QAnXYCAWo1Kzpfc6JBUoEtQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kwVt54C+i6QeMGKbg0Q8RV5eVhBGYDO0FbNfGWInx+Z+fUgSC+DUnYwkVGM5EW3QQlTv1uP5PvGuzZOIsL+tE8eWzmdOb1jw0oLgpiHR0cA8HEK8NLlg3XA1YCfIelaAa4rIcTtSvyMwKSTSNlMhoFfkFIuoNeGdXGiMu/00pqs= 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=CF14Dwj3; 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="CF14Dwj3" 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 60635BNb004619; Tue, 6 Jan 2026 15:06:40 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=56BhBO+/eHWjmoR1c 5fXFEtI4KtKouXiVgC1S4fhn/U=; b=CF14Dwj3UBUJgn98kZLWz8PbqMgTOZvi6 eg/mbWzRWBkX/K1VQckCKljgjnb+Suw6YGyijipPuZdzNycU9j9y/fLAbaxK3rrp jGYvcn0RWQY78AHK71yqaMRjbpIs/foxojLH3DboEeFU68iejA+hSBu5Hh/m/Fp5 nZeon83ZZ55mAkzxZow6pUAMAr25XI4ovOLdYzV6WCt7rXK71DLkPmSifj+891ac oelmfgMk0YlCjK2M3VXbFzi6fjGHBgeRMxPwJiiBK7bKLcPRAQ+0Hs+yUYIJGEE3 5+m0uSd51SXUmLAunqoteaFNspCGVwgfjn9f0XBXTWrgA5Uppwg6A== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4betsq4fge-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:39 +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 606EtRVX027333; Tue, 6 Jan 2026 15:06:39 GMT Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4betsq4fg9-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:39 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 606EMRIa019171; Tue, 6 Jan 2026 15:06:38 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 4bfg513q9k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 06 Jan 2026 15:06:38 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 606F6YSw29819208 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 6 Jan 2026 15:06:34 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 66C3D20043; Tue, 6 Jan 2026 15:06:34 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7777720040; Tue, 6 Jan 2026 15:06:26 +0000 (GMT) Received: from li-fc74f8cc-3279-11b2-a85c-ef5828687581.ibm.com.com (unknown [9.124.214.6]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Tue, 6 Jan 2026 15:06:23 +0000 (GMT) From: Srish Srinivasan To: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, christophe.leroy@csgroup.eu, James.Bottomley@HansenPartnership.com, jarkko@kernel.org, zohar@linux.ibm.com, nayna@linux.ibm.com, rnsastry@linux.ibm.com, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, ssrish@linux.ibm.com Subject: [PATCH v3 6/6] docs: trusted-encryped: add PKWM as a new trust source Date: Tue, 6 Jan 2026 20:35:27 +0530 Message-ID: <20260106150527.446525-7-ssrish@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260106150527.446525-1-ssrish@linux.ibm.com> References: <20260106150527.446525-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: 0vCL7wsg6svZqr5ra1KM-xkw_vyouRul X-Authority-Analysis: v=2.4 cv=Jvf8bc4C c=1 sm=1 tr=0 ts=695d24ff cx=c_pps a=aDMHemPKRhS1OARIsFnwRA==:117 a=aDMHemPKRhS1OARIsFnwRA==:17 a=vUbySO9Y5rIA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VnNF1IyMAAAA:8 a=ULK339cd-4IVAxCgyX4A:9 X-Proofpoint-ORIG-GUID: _zB0Xh2NfwnIXkSUHuJUf7fE77svI2yA X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTA2MDEyOSBTYWx0ZWRfX4cag9wppnDX3 OhNgl1SMEIJiXQz/+dCFJpz3OCKVH8okJK7mEqeTHnoPwuF6M4MB06/pHWqI9AMawKskbX9oEHV LGlLlbtNlDYnAA/SeLzCiEPOuW6FyH0aLZ86CKoR1tSathgGDAE83F9p6hqsMVqs18G+tnc1LE4 98JoBnvjnNPQHPFS0aD/bGrRtRdrG++t7gxVjYeDG6cMSf5pHZLhivqcKSzSWxFKkAfdFDTls0S J9zxKxgyZEXsy7hsMICaZnNAwFLqbV5woodN5NgpdvjjsLxBBuOzlBNBclNhhAMisPQJnXyRigr YLwEy5k2HmytlD26SUDOXeFUPLhz7Ig6EPMgFOeSjjt/Cw1ly8tsa6zNnALFtsB7iSnsfbaM5yF dnlcqzaczZg1tptLvjVwrl20J3YMeyQaMgqZRhj4iXShLoOWcCm5RMNgOAMvb3shj+A7VG3S/3S +gf6v+p26MrVPRZrp3Q== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2026-01-06_01,2026-01-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 suspectscore=0 impostorscore=0 lowpriorityscore=0 priorityscore=1501 phishscore=0 adultscore=0 spamscore=0 bulkscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2512120000 definitions=main-2601060129 Content-Type: text/plain; charset="utf-8" From: Nayna Jain Update Documentation/security/keys/trusted-encrypted.rst and Documentation/ admin-guide/kernel-parameters.txt with PowerVM Key Wrapping Module (PKWM) as a new trust source Signed-off-by: Nayna Jain Signed-off-by: Srish Srinivasan Reviewed-by: Mimi Zohar --- .../admin-guide/kernel-parameters.txt | 1 + .../security/keys/trusted-encrypted.rst | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index a8d0afde7f85..ccb9c2f502fb 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -7755,6 +7755,7 @@ Kernel parameters - "tee" - "caam" - "dcp" + - "pkwm" If not specified then it defaults to iterating through the trust source list starting with TPM and assigns the first trust source as a backend which is initialized diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentat= ion/security/keys/trusted-encrypted.rst index eae6a36b1c9a..ddff7c7c2582 100644 --- a/Documentation/security/keys/trusted-encrypted.rst +++ b/Documentation/security/keys/trusted-encrypted.rst @@ -81,6 +81,14 @@ safe. and the UNIQUE key. Default is to use the UNIQUE key, but selecti= ng the OTP key can be done via a module parameter (dcp_use_otp_key). =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Rooted to a unique, per-LPAR key, which is derived from a system-= wide, + randomly generated LPAR root key. Both the per-LPAR keys and the = LPAR + root key are stored in hypervisor-owned secure memory at runtime, + and the LPAR root key is additionally persisted in secure locatio= ns + such as the processor SEEPROMs and encrypted NVRAM. + * Execution isolation =20 (1) TPM @@ -102,6 +110,14 @@ safe. environment. Only basic blob key encryption is executed there. The actual key sealing/unsealing is done on main processor/kernel= space. =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Fixed set of cryptographic operations done on on-chip hardware + cryptographic acceleration unit NX. Keys for wrapping and unwrapp= ing + are managed by PowerVM Platform KeyStore, which stores keys in an + isolated in-memory copy in secure hypervisor memory, as well as i= n a + persistent copy in hypervisor-encrypted NVRAM. + * Optional binding to platform integrity state =20 (1) TPM @@ -129,6 +145,11 @@ safe. Relies on Secure/Trusted boot process (called HAB by vendor) for platform integrity. =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Relies on secure and trusted boot process of IBM Power systems for + platform integrity. + * Interfaces and APIs =20 (1) TPM @@ -149,6 +170,11 @@ safe. Vendor-specific API that is implemented as part of the DCP crypto= driver in ``drivers/crypto/mxs-dcp.c``. =20 + (5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStor= e) + + Platform Keystore has well documented interfaces in PAPR document. + Refer to ``Documentation/arch/powerpc/papr_hcalls.rst`` + * Threat model =20 The strength and appropriateness of a particular trust source for a g= iven @@ -191,6 +217,10 @@ selected trust source: a dedicated hardware RNG that is independent from DCP which can be en= abled to back the kernel RNG. =20 + * PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore) + + The normal kernel random number generator is used to generate keys. + Users may override this by specifying ``trusted.rng=3Dkernel`` on the kern= el command-line to override the used RNG with the kernel's random number pool. =20 @@ -321,6 +351,26 @@ Usage:: specific to this DCP key-blob implementation. The key length for new keys= is always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits). =20 +Trusted Keys usage: PKWM +------------------------ + +Usage:: + + keyctl add trusted name "new keylen [options]" ring + keyctl add trusted name "load hex_blob" ring + keyctl print keyid + + options: + wrap_flags=3D ascii hex value of security policy requirement + 0x00: no secure boot requirement (default) + 0x01: require secure boot to be in either audit or + enforced mode + 0x02: require secure boot to be in enforced mode + +"keyctl print" returns an ASCII hex copy of the sealed key, which is in fo= rmat +specific to PKWM key-blob implementation. The key length for new keys is +always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits). + Encrypted Keys usage -------------------- =20 --=20 2.47.3