Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fwctl: FWCTL_RPC to execute a Remote Procedure Call to device firmware

Add the FWCTL_RPC ioctl which allows a request/response RPC call to device
firmware. Drivers implementing this call must follow the security
guidelines under Documentation/userspace-api/fwctl.rst

The core code provides some memory management helpers to get the messages
copied from and back to userspace. The driver is responsible for
allocating the output message memory and delivering the message to the
device.

Link: https://patch.msgid.link/r/5-v5-642aa0c94070+4447f-fwctl_jgg@nvidia.com
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Shannon Nelson <shannon.nelson@amd.com>
Tested-by: Dave Jiang <dave.jiang@intel.com>
Tested-by: Shannon Nelson <shannon.nelson@amd.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

+137
+60
drivers/fwctl/main.c
··· 8 8 #include <linux/container_of.h> 9 9 #include <linux/fs.h> 10 10 #include <linux/module.h> 11 + #include <linux/sizes.h> 11 12 #include <linux/slab.h> 12 13 13 14 #include <uapi/fwctl/fwctl.h> 14 15 15 16 enum { 16 17 FWCTL_MAX_DEVICES = 4096, 18 + MAX_RPC_LEN = SZ_2M, 17 19 }; 18 20 static_assert(FWCTL_MAX_DEVICES < (1U << MINORBITS)); 19 21 20 22 static dev_t fwctl_dev; 21 23 static DEFINE_IDA(fwctl_ida); 24 + static unsigned long fwctl_tainted; 22 25 23 26 struct fwctl_ucmd { 24 27 struct fwctl_uctx *uctx; ··· 83 80 return ucmd_respond(ucmd, sizeof(*cmd)); 84 81 } 85 82 83 + static int fwctl_cmd_rpc(struct fwctl_ucmd *ucmd) 84 + { 85 + struct fwctl_device *fwctl = ucmd->uctx->fwctl; 86 + struct fwctl_rpc *cmd = ucmd->cmd; 87 + size_t out_len; 88 + 89 + if (cmd->in_len > MAX_RPC_LEN || cmd->out_len > MAX_RPC_LEN) 90 + return -EMSGSIZE; 91 + 92 + switch (cmd->scope) { 93 + case FWCTL_RPC_CONFIGURATION: 94 + case FWCTL_RPC_DEBUG_READ_ONLY: 95 + break; 96 + 97 + case FWCTL_RPC_DEBUG_WRITE_FULL: 98 + if (!capable(CAP_SYS_RAWIO)) 99 + return -EPERM; 100 + fallthrough; 101 + case FWCTL_RPC_DEBUG_WRITE: 102 + if (!test_and_set_bit(0, &fwctl_tainted)) { 103 + dev_warn( 104 + &fwctl->dev, 105 + "%s(%d): has requested full access to the physical device device", 106 + current->comm, task_pid_nr(current)); 107 + add_taint(TAINT_FWCTL, LOCKDEP_STILL_OK); 108 + } 109 + break; 110 + default: 111 + return -EOPNOTSUPP; 112 + } 113 + 114 + void *inbuf __free(kvfree) = kvzalloc(cmd->in_len, GFP_KERNEL_ACCOUNT); 115 + if (!inbuf) 116 + return -ENOMEM; 117 + if (copy_from_user(inbuf, u64_to_user_ptr(cmd->in), cmd->in_len)) 118 + return -EFAULT; 119 + 120 + out_len = cmd->out_len; 121 + void *outbuf __free(kvfree) = fwctl->ops->fw_rpc( 122 + ucmd->uctx, cmd->scope, inbuf, cmd->in_len, &out_len); 123 + if (IS_ERR(outbuf)) 124 + return PTR_ERR(outbuf); 125 + if (outbuf == inbuf) { 126 + /* The driver can re-use inbuf as outbuf */ 127 + inbuf = NULL; 128 + } 129 + 130 + if (copy_to_user(u64_to_user_ptr(cmd->out), outbuf, 131 + min(cmd->out_len, out_len))) 132 + return -EFAULT; 133 + 134 + cmd->out_len = out_len; 135 + return ucmd_respond(ucmd, sizeof(*cmd)); 136 + } 137 + 86 138 /* On stack memory for the ioctl structs */ 87 139 union fwctl_ucmd_buffer { 88 140 struct fwctl_info info; 141 + struct fwctl_rpc rpc; 89 142 }; 90 143 91 144 struct fwctl_ioctl_op { ··· 162 103 } 163 104 static const struct fwctl_ioctl_op fwctl_ioctl_ops[] = { 164 105 IOCTL_OP(FWCTL_INFO, fwctl_cmd_info, struct fwctl_info, out_device_data), 106 + IOCTL_OP(FWCTL_RPC, fwctl_cmd_rpc, struct fwctl_rpc, out), 165 107 }; 166 108 167 109 static long fwctl_fops_ioctl(struct file *filp, unsigned int cmd,
+8
include/linux/fwctl.h
··· 47 47 * ignore length on input, the core code will handle everything. 48 48 */ 49 49 void *(*info)(struct fwctl_uctx *uctx, size_t *length); 50 + /** 51 + * @fw_rpc: Implement FWCTL_RPC. Deliver rpc_in/in_len to the FW and 52 + * return the response and set out_len. rpc_in can be returned as the 53 + * response pointer. Otherwise the returned pointer is freed with 54 + * kvfree(). 55 + */ 56 + void *(*fw_rpc)(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, 57 + void *rpc_in, size_t in_len, size_t *out_len); 50 58 }; 51 59 52 60 /**
+69
include/uapi/fwctl/fwctl.h
··· 37 37 enum { 38 38 FWCTL_CMD_BASE = 0, 39 39 FWCTL_CMD_INFO = 0, 40 + FWCTL_CMD_RPC = 1, 40 41 }; 41 42 42 43 enum fwctl_device_type { ··· 66 65 __aligned_u64 out_device_data; 67 66 }; 68 67 #define FWCTL_INFO _IO(FWCTL_TYPE, FWCTL_CMD_INFO) 68 + 69 + /** 70 + * enum fwctl_rpc_scope - Scope of access for the RPC 71 + * 72 + * Refer to fwctl.rst for a more detailed discussion of these scopes. 73 + */ 74 + enum fwctl_rpc_scope { 75 + /** 76 + * @FWCTL_RPC_CONFIGURATION: Device configuration access scope 77 + * 78 + * Read/write access to device configuration. When configuration 79 + * is written to the device it remains in a fully supported state. 80 + */ 81 + FWCTL_RPC_CONFIGURATION = 0, 82 + /** 83 + * @FWCTL_RPC_DEBUG_READ_ONLY: Read only access to debug information 84 + * 85 + * Readable debug information. Debug information is compatible with 86 + * kernel lockdown, and does not disclose any sensitive information. For 87 + * instance exposing any encryption secrets from this information is 88 + * forbidden. 89 + */ 90 + FWCTL_RPC_DEBUG_READ_ONLY = 1, 91 + /** 92 + * @FWCTL_RPC_DEBUG_WRITE: Writable access to lockdown compatible debug information 93 + * 94 + * Allows write access to data in the device which may leave a fully 95 + * supported state. This is intended to permit intensive and possibly 96 + * invasive debugging. This scope will taint the kernel. 97 + */ 98 + FWCTL_RPC_DEBUG_WRITE = 2, 99 + /** 100 + * @FWCTL_RPC_DEBUG_WRITE_FULL: Write access to all debug information 101 + * 102 + * Allows read/write access to everything. Requires CAP_SYS_RAW_IO, so 103 + * it is not required to follow lockdown principals. If in doubt 104 + * debugging should be placed in this scope. This scope will taint the 105 + * kernel. 106 + */ 107 + FWCTL_RPC_DEBUG_WRITE_FULL = 3, 108 + }; 109 + 110 + /** 111 + * struct fwctl_rpc - ioctl(FWCTL_RPC) 112 + * @size: sizeof(struct fwctl_rpc) 113 + * @scope: One of enum fwctl_rpc_scope, required scope for the RPC 114 + * @in_len: Length of the in memory 115 + * @out_len: Length of the out memory 116 + * @in: Request message in device specific format 117 + * @out: Response message in device specific format 118 + * 119 + * Deliver a Remote Procedure Call to the device FW and return the response. The 120 + * call's parameters and return are marshaled into linear buffers of memory. Any 121 + * errno indicates that delivery of the RPC to the device failed. Return status 122 + * originating in the device during a successful delivery must be encoded into 123 + * out. 124 + * 125 + * The format of the buffers matches the out_device_type from FWCTL_INFO. 126 + */ 127 + struct fwctl_rpc { 128 + __u32 size; 129 + __u32 scope; 130 + __u32 in_len; 131 + __u32 out_len; 132 + __aligned_u64 in; 133 + __aligned_u64 out; 134 + }; 135 + #define FWCTL_RPC _IO(FWCTL_TYPE, FWCTL_CMD_RPC) 69 136 70 137 #endif