if (cmd->in_len > MAX_RPC_LEN || cmd->out_len > MAX_RPC_LEN) return -EMSGSIZE;
switch (cmd->scope) { case FWCTL_RPC_CONFIGURATION: case FWCTL_RPC_DEBUG_READ_ONLY: break;
case FWCTL_RPC_DEBUG_WRITE_FULL: if (!capable(CAP_SYS_RAWIO)) return -EPERM;
fallthrough; case FWCTL_RPC_DEBUG_WRITE: if (!test_and_set_bit(0, &fwctl_tainted)) {
dev_warn(
&fwctl->dev, "%s(%d): has requested full access to the physical device",
current->comm, task_pid_nr(current));
add_taint(TAINT_FWCTL, LOCKDEP_STILL_OK);
} break; default: return -EOPNOTSUPP;
}
void *inbuf __free(kvfree) = kvzalloc(cmd->in_len, GFP_KERNEL_ACCOUNT); if (!inbuf) return -ENOMEM; if (copy_from_user(inbuf, u64_to_user_ptr(cmd->in), cmd->in_len)) return -EFAULT;
out_len = cmd->out_len; void *outbuf __free(kvfree) = fwctl->ops->fw_rpc(
ucmd->uctx, cmd->scope, inbuf, cmd->in_len, &out_len); if (IS_ERR(outbuf)) return PTR_ERR(outbuf); if (outbuf == inbuf) { /* The driver can re-use inbuf as outbuf */
inbuf = NULL;
}
if (copy_to_user(u64_to_user_ptr(cmd->out), outbuf,
min(cmd->out_len, out_len))) return -EFAULT;
scoped_guard(rwsem_read, &fwctl->registration_lock) { /* * NULL ops means fwctl_unregister() has already removed the * driver and destroyed the uctx.
*/ if (fwctl->ops) {
guard(mutex)(&fwctl->uctx_list_lock);
fwctl_destroy_uctx(uctx);
}
}
cdev_init(&fwctl->cdev, &fwctl_fops); /* * The driver module is protected by fwctl_register/unregister(), * unregister won't complete until we are done with the driver's module.
*/
fwctl->cdev.owner = THIS_MODULE;
if (dev_set_name(&fwctl->dev, "fwctl%d", fwctl->dev.devt - fwctl_dev)) return NULL;
/** * fwctl_register - Register a new device to the subsystem * @fwctl: Previously allocated fwctl_device * * On return the device is visible through sysfs and /dev, driver ops may be * called.
*/ int fwctl_register(struct fwctl_device *fwctl)
{ return cdev_device_add(&fwctl->cdev, &fwctl->dev);
}
EXPORT_SYMBOL_NS_GPL(fwctl_register, "FWCTL");
/** * fwctl_unregister - Unregister a device from the subsystem * @fwctl: Previously allocated and registered fwctl_device * * Undoes fwctl_register(). On return no driver ops will be called. The * caller must still call fwctl_put() to free the fwctl. * * Unregister will return even if userspace still has file descriptors open. * This will call ops->close_uctx() on any open FDs and after return no driver * op will be called. The FDs remain open but all fops will return -ENODEV. * * The design of fwctl allows this sort of disassociation of the driver from the * subsystem primarily by keeping memory allocations owned by the core subsytem. * The fwctl_device and fwctl_uctx can both be freed without requiring a driver * callback. This allows the module to remain unlocked while FDs are open.
*/ void fwctl_unregister(struct fwctl_device *fwctl)
{ struct fwctl_uctx *uctx;
cdev_device_del(&fwctl->cdev, &fwctl->dev);
/* Disable and free the driver's resources for any still open FDs. */
guard(rwsem_write)(&fwctl->registration_lock);
guard(mutex)(&fwctl->uctx_list_lock); while ((uctx = list_first_entry_or_null(&fwctl->uctx_list, struct fwctl_uctx,
uctx_list_entry)))
fwctl_destroy_uctx(uctx);
/* * The driver module may unload after this returns, the op pointer will * not be valid.
*/
fwctl->ops = NULL;
}
EXPORT_SYMBOL_NS_GPL(fwctl_unregister, "FWCTL");
staticint __init fwctl_init(void)
{ int ret;
ret = alloc_chrdev_region(&fwctl_dev, 0, FWCTL_MAX_DEVICES, "fwctl"); if (ret) return ret;
ret = class_register(&fwctl_class); if (ret) goto err_chrdev; return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.