// SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) "papr-phy-attest: " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "papr-rtas-common.h" /** * struct rtas_phy_attest_params - Parameters (in and out) for * ibm,physical-attestation. * * @cmd: In: Caller-provided attestation command buffer. Must be * RTAS-addressable. * @work_area: In: Caller-provided work area buffer for attestation * command structure * Out: Caller-provided work area buffer for the response * @cmd_len: In: Caller-provided attestation command structure * length * @sequence: In: Sequence number. Out: Next sequence number. * @written: Out: Bytes written by ibm,physical-attestation to * @work_area. * @status: Out: RTAS call status. */ struct rtas_phy_attest_params { struct papr_phy_attest_io_block cmd; struct rtas_work_area *work_area; u32 cmd_len; u32 sequence; u32 written; s32 status; }; /** * rtas_physical_attestation() - Call ibm,physical-attestation to * fill a work area buffer. * @params: See &struct rtas_phy_attest_params. * * Calls ibm,physical-attestation until it errors or successfully * deposits data into the supplied work area. Handles RTAS retry * statuses. Maps RTAS error statuses to reasonable errno values. * * The caller is expected to invoke rtas_physical_attestation() * multiple times to retrieve all the data for the provided * attestation command. Only one sequence should be in progress at * any time; starting a new sequence will disrupt any sequence * already in progress. Serialization of attestation retrieval * sequences is the responsibility of the caller. * * The caller should inspect @params.status to determine whether more * calls are needed to complete the sequence. * * Context: May sleep. * Return: -ve on error, 0 otherwise. */ static int rtas_physical_attestation(struct rtas_phy_attest_params *params) { struct rtas_work_area *work_area; s32 fwrc, token; u32 rets[2]; int ret; work_area = params->work_area; token = rtas_function_token(RTAS_FN_IBM_PHYSICAL_ATTESTATION); if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; lockdep_assert_held(&rtas_ibm_physical_attestation_lock); do { fwrc = rtas_call(token, 3, 3, rets, rtas_work_area_phys(work_area), params->cmd_len, params->sequence); } while (rtas_busy_delay(fwrc)); switch (fwrc) { case RTAS_HARDWARE_ERROR: ret = -EIO; break; case RTAS_INVALID_PARAMETER: ret = -EINVAL; break; case RTAS_SEQ_MORE_DATA: params->sequence = rets[0]; fallthrough; case RTAS_SEQ_COMPLETE: params->written = rets[1]; /* * Kernel or firmware bug, do not continue. */ if (WARN(params->written > rtas_work_area_size(work_area), "possible write beyond end of work area")) ret = -EFAULT; else ret = 0; break; default: ret = -EIO; pr_err_ratelimited("unexpected ibm,get-phy_attest status %d\n", fwrc); break; } params->status = fwrc; return ret; } /* * Internal physical-attestation sequence APIs. A physical-attestation * sequence is a series of calls to get ibm,physical-attestation * for a given attestation command. The sequence ends when an error * is encountered or all data for the attestation command has been * returned. */ /** * phy_attest_sequence_begin() - Begin a response data for attestation * command retrieval sequence. * @seq: user specified parameters for RTAS call from seq struct. * * Context: May sleep. */ static void phy_attest_sequence_begin(struct papr_rtas_sequence *seq) { struct rtas_phy_attest_params *param; /* * We could allocate the work area before acquiring the * function lock, but that would allow concurrent requests to * exhaust the limited work area pool for no benefit. So * allocate the work area under the lock. */ mutex_lock(&rtas_ibm_physical_attestation_lock); param = (struct rtas_phy_attest_params *)seq->params; param->work_area = rtas_work_area_alloc(SZ_4K); memcpy(rtas_work_area_raw_buf(param->work_area), ¶m->cmd, param->cmd_len); param->sequence = 1; param->status = 0; } /** * phy_attest_sequence_end() - Finalize a attestation command * response retrieval sequence. * @seq: Sequence state. * * Releases resources obtained by phy_attest_sequence_begin(). */ static void phy_attest_sequence_end(struct papr_rtas_sequence *seq) { struct rtas_phy_attest_params *param; param = (struct rtas_phy_attest_params *)seq->params; rtas_work_area_free(param->work_area); mutex_unlock(&rtas_ibm_physical_attestation_lock); kfree(param); } /* * Generator function to be passed to papr_rtas_blob_generate(). */ static const char *phy_attest_sequence_fill_work_area(struct papr_rtas_sequence *seq, size_t *len) { struct rtas_phy_attest_params *p; bool init_state; p = (struct rtas_phy_attest_params *)seq->params; init_state = (p->written == 0) ? true : false; if (papr_rtas_sequence_should_stop(seq, p->status, init_state)) return NULL; if (papr_rtas_sequence_set_err(seq, rtas_physical_attestation(p))) return NULL; *len = p->written; return rtas_work_area_raw_buf(p->work_area); } static const struct file_operations papr_phy_attest_handle_ops = { .read = papr_rtas_common_handle_read, .llseek = papr_rtas_common_handle_seek, .release = papr_rtas_common_handle_release, }; /** * papr_phy_attest_create_handle() - Create a fd-based handle for * reading the response for the given attestation command. * @ulc: Attestation command in user memory; defines the scope of * data for the attestation command to retrieve. * * Handler for PAPR_PHYSICAL_ATTESTATION_IOC_CREATE_HANDLE ioctl * command. Validates @ulc and instantiates an immutable response * "blob" for attestation command. The blob is attached to a file * descriptor for reading by user space. The memory backing the blob * is freed when the file is released. * * The entire requested response buffer for the attestation command * retrieved by this call and all necessary RTAS interactions are * performed before returning the fd to user space. This keeps the * read handler simple and ensures that kernel can prevent * interleaving ibm,physical-attestation call sequences. * * Return: The installed fd number if successful, -ve errno otherwise. */ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user *ulc) { struct rtas_phy_attest_params *params; struct papr_rtas_sequence seq = {}; int fd; /* * Freed in phy_attest_sequence_end(). */ params = kzalloc(sizeof(*params), GFP_KERNEL_ACCOUNT); if (!params) return -ENOMEM; if (copy_from_user(¶ms->cmd, ulc, sizeof(struct papr_phy_attest_io_block))) return -EFAULT; params->cmd_len = be32_to_cpu(params->cmd.length); seq = (struct papr_rtas_sequence) { .begin = phy_attest_sequence_begin, .end = phy_attest_sequence_end, .work = phy_attest_sequence_fill_work_area, }; seq.params = (void *)params; fd = papr_rtas_setup_file_interface(&seq, &papr_phy_attest_handle_ops, "[papr-physical-attestation]"); return fd; } /* * Top-level ioctl handler for /dev/papr-physical-attestation. */ static long papr_phy_attest_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { void __user *argp = (__force void __user *)arg; long ret; switch (ioctl) { case PAPR_PHY_ATTEST_IOC_HANDLE: ret = papr_phy_attest_create_handle(argp); break; default: ret = -ENOIOCTLCMD; break; } return ret; } static const struct file_operations papr_phy_attest_ops = { .unlocked_ioctl = papr_phy_attest_dev_ioctl, }; static struct miscdevice papr_phy_attest_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "papr-physical-attestation", .fops = &papr_phy_attest_ops, }; static __init int papr_phy_attest_init(void) { if (!rtas_function_implemented(RTAS_FN_IBM_PHYSICAL_ATTESTATION)) return -ENODEV; return misc_register(&papr_phy_attest_dev); } machine_device_initcall(pseries, papr_phy_attest_init);