Path: blob/master/arch/powerpc/platforms/pseries/papr-phy-attest.c
26481 views
// SPDX-License-Identifier: GPL-2.0-only12#define pr_fmt(fmt) "papr-phy-attest: " fmt34#include <linux/build_bug.h>5#include <linux/file.h>6#include <linux/fs.h>7#include <linux/init.h>8#include <linux/lockdep.h>9#include <linux/kernel.h>10#include <linux/miscdevice.h>11#include <linux/signal.h>12#include <linux/slab.h>13#include <linux/string.h>14#include <linux/string_helpers.h>15#include <linux/uaccess.h>16#include <asm/machdep.h>17#include <asm/rtas-work-area.h>18#include <asm/rtas.h>19#include <uapi/asm/papr-physical-attestation.h>20#include "papr-rtas-common.h"2122/**23* struct rtas_phy_attest_params - Parameters (in and out) for24* ibm,physical-attestation.25*26* @cmd: In: Caller-provided attestation command buffer. Must be27* RTAS-addressable.28* @work_area: In: Caller-provided work area buffer for attestation29* command structure30* Out: Caller-provided work area buffer for the response31* @cmd_len: In: Caller-provided attestation command structure32* length33* @sequence: In: Sequence number. Out: Next sequence number.34* @written: Out: Bytes written by ibm,physical-attestation to35* @work_area.36* @status: Out: RTAS call status.37*/38struct rtas_phy_attest_params {39struct papr_phy_attest_io_block cmd;40struct rtas_work_area *work_area;41u32 cmd_len;42u32 sequence;43u32 written;44s32 status;45};4647/**48* rtas_physical_attestation() - Call ibm,physical-attestation to49* fill a work area buffer.50* @params: See &struct rtas_phy_attest_params.51*52* Calls ibm,physical-attestation until it errors or successfully53* deposits data into the supplied work area. Handles RTAS retry54* statuses. Maps RTAS error statuses to reasonable errno values.55*56* The caller is expected to invoke rtas_physical_attestation()57* multiple times to retrieve all the data for the provided58* attestation command. Only one sequence should be in progress at59* any time; starting a new sequence will disrupt any sequence60* already in progress. Serialization of attestation retrieval61* sequences is the responsibility of the caller.62*63* The caller should inspect @params.status to determine whether more64* calls are needed to complete the sequence.65*66* Context: May sleep.67* Return: -ve on error, 0 otherwise.68*/69static int rtas_physical_attestation(struct rtas_phy_attest_params *params)70{71struct rtas_work_area *work_area;72s32 fwrc, token;73u32 rets[2];74int ret;7576work_area = params->work_area;77token = rtas_function_token(RTAS_FN_IBM_PHYSICAL_ATTESTATION);78if (token == RTAS_UNKNOWN_SERVICE)79return -ENOENT;8081lockdep_assert_held(&rtas_ibm_physical_attestation_lock);8283do {84fwrc = rtas_call(token, 3, 3, rets,85rtas_work_area_phys(work_area),86params->cmd_len,87params->sequence);88} while (rtas_busy_delay(fwrc));8990switch (fwrc) {91case RTAS_HARDWARE_ERROR:92ret = -EIO;93break;94case RTAS_INVALID_PARAMETER:95ret = -EINVAL;96break;97case RTAS_SEQ_MORE_DATA:98params->sequence = rets[0];99fallthrough;100case RTAS_SEQ_COMPLETE:101params->written = rets[1];102/*103* Kernel or firmware bug, do not continue.104*/105if (WARN(params->written > rtas_work_area_size(work_area),106"possible write beyond end of work area"))107ret = -EFAULT;108else109ret = 0;110break;111default:112ret = -EIO;113pr_err_ratelimited("unexpected ibm,get-phy_attest status %d\n", fwrc);114break;115}116117params->status = fwrc;118return ret;119}120121/*122* Internal physical-attestation sequence APIs. A physical-attestation123* sequence is a series of calls to get ibm,physical-attestation124* for a given attestation command. The sequence ends when an error125* is encountered or all data for the attestation command has been126* returned.127*/128129/**130* phy_attest_sequence_begin() - Begin a response data for attestation131* command retrieval sequence.132* @seq: user specified parameters for RTAS call from seq struct.133*134* Context: May sleep.135*/136static void phy_attest_sequence_begin(struct papr_rtas_sequence *seq)137{138struct rtas_phy_attest_params *param;139140/*141* We could allocate the work area before acquiring the142* function lock, but that would allow concurrent requests to143* exhaust the limited work area pool for no benefit. So144* allocate the work area under the lock.145*/146mutex_lock(&rtas_ibm_physical_attestation_lock);147param = (struct rtas_phy_attest_params *)seq->params;148param->work_area = rtas_work_area_alloc(SZ_4K);149memcpy(rtas_work_area_raw_buf(param->work_area), ¶m->cmd,150param->cmd_len);151param->sequence = 1;152param->status = 0;153}154155/**156* phy_attest_sequence_end() - Finalize a attestation command157* response retrieval sequence.158* @seq: Sequence state.159*160* Releases resources obtained by phy_attest_sequence_begin().161*/162static void phy_attest_sequence_end(struct papr_rtas_sequence *seq)163{164struct rtas_phy_attest_params *param;165166param = (struct rtas_phy_attest_params *)seq->params;167rtas_work_area_free(param->work_area);168mutex_unlock(&rtas_ibm_physical_attestation_lock);169kfree(param);170}171172/*173* Generator function to be passed to papr_rtas_blob_generate().174*/175static const char *phy_attest_sequence_fill_work_area(struct papr_rtas_sequence *seq,176size_t *len)177{178struct rtas_phy_attest_params *p;179bool init_state;180181p = (struct rtas_phy_attest_params *)seq->params;182init_state = (p->written == 0) ? true : false;183184if (papr_rtas_sequence_should_stop(seq, p->status, init_state))185return NULL;186if (papr_rtas_sequence_set_err(seq, rtas_physical_attestation(p)))187return NULL;188*len = p->written;189return rtas_work_area_raw_buf(p->work_area);190}191192static const struct file_operations papr_phy_attest_handle_ops = {193.read = papr_rtas_common_handle_read,194.llseek = papr_rtas_common_handle_seek,195.release = papr_rtas_common_handle_release,196};197198/**199* papr_phy_attest_create_handle() - Create a fd-based handle for200* reading the response for the given attestation command.201* @ulc: Attestation command in user memory; defines the scope of202* data for the attestation command to retrieve.203*204* Handler for PAPR_PHYSICAL_ATTESTATION_IOC_CREATE_HANDLE ioctl205* command. Validates @ulc and instantiates an immutable response206* "blob" for attestation command. The blob is attached to a file207* descriptor for reading by user space. The memory backing the blob208* is freed when the file is released.209*210* The entire requested response buffer for the attestation command211* retrieved by this call and all necessary RTAS interactions are212* performed before returning the fd to user space. This keeps the213* read handler simple and ensures that kernel can prevent214* interleaving ibm,physical-attestation call sequences.215*216* Return: The installed fd number if successful, -ve errno otherwise.217*/218static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user *ulc)219{220struct rtas_phy_attest_params *params;221struct papr_rtas_sequence seq = {};222int fd;223224/*225* Freed in phy_attest_sequence_end().226*/227params = kzalloc(sizeof(*params), GFP_KERNEL_ACCOUNT);228if (!params)229return -ENOMEM;230231if (copy_from_user(¶ms->cmd, ulc,232sizeof(struct papr_phy_attest_io_block)))233return -EFAULT;234235params->cmd_len = be32_to_cpu(params->cmd.length);236seq = (struct papr_rtas_sequence) {237.begin = phy_attest_sequence_begin,238.end = phy_attest_sequence_end,239.work = phy_attest_sequence_fill_work_area,240};241242seq.params = (void *)params;243244fd = papr_rtas_setup_file_interface(&seq,245&papr_phy_attest_handle_ops,246"[papr-physical-attestation]");247248return fd;249}250251/*252* Top-level ioctl handler for /dev/papr-physical-attestation.253*/254static long papr_phy_attest_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)255{256void __user *argp = (__force void __user *)arg;257long ret;258259switch (ioctl) {260case PAPR_PHY_ATTEST_IOC_HANDLE:261ret = papr_phy_attest_create_handle(argp);262break;263default:264ret = -ENOIOCTLCMD;265break;266}267return ret;268}269270static const struct file_operations papr_phy_attest_ops = {271.unlocked_ioctl = papr_phy_attest_dev_ioctl,272};273274static struct miscdevice papr_phy_attest_dev = {275.minor = MISC_DYNAMIC_MINOR,276.name = "papr-physical-attestation",277.fops = &papr_phy_attest_ops,278};279280static __init int papr_phy_attest_init(void)281{282if (!rtas_function_implemented(RTAS_FN_IBM_PHYSICAL_ATTESTATION))283return -ENODEV;284285return misc_register(&papr_phy_attest_dev);286}287machine_device_initcall(pseries, papr_phy_attest_init);288289290