ublk: don't return 0 in case of any failure
[linux-block.git] / drivers / block / ublk_drv.c
index 1223fcbfc6c9ccb686a5dcadbc5fe7250264483d..253008b2091d69be99d34376ef1488fc47a5e426 100644 (file)
@@ -53,7 +53,8 @@
                | UBLK_F_NEED_GET_DATA \
                | UBLK_F_USER_RECOVERY \
                | UBLK_F_USER_RECOVERY_REISSUE \
-               | UBLK_F_UNPRIVILEGED_DEV)
+               | UBLK_F_UNPRIVILEGED_DEV \
+               | UBLK_F_CMD_IOCTL_ENCODE)
 
 /* All UBLK_PARAM_TYPE_* should be included here */
 #define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | \
@@ -1253,6 +1254,19 @@ static void ublk_handle_need_get_data(struct ublk_device *ub, int q_id,
        ublk_queue_cmd(ubq, req);
 }
 
+static inline int ublk_check_cmd_op(u32 cmd_op)
+{
+       u32 ioc_type = _IOC_TYPE(cmd_op);
+
+       if (IS_ENABLED(CONFIG_BLKDEV_UBLK_LEGACY_OPCODES) && ioc_type != 'u')
+               return -EOPNOTSUPP;
+
+       if (ioc_type != 'u' && ioc_type != 0)
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+
 static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
 {
        struct ublksrv_io_cmd *ub_cmd = (struct ublksrv_io_cmd *)cmd->cmd;
@@ -1294,10 +1308,15 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
         * iff the driver have set the UBLK_IO_FLAG_NEED_GET_DATA.
         */
        if ((!!(io->flags & UBLK_IO_FLAG_NEED_GET_DATA))
-                       ^ (cmd_op == UBLK_IO_NEED_GET_DATA))
+                       ^ (_IOC_NR(cmd_op) == UBLK_IO_NEED_GET_DATA))
+               goto out;
+
+       ret = ublk_check_cmd_op(cmd_op);
+       if (ret)
                goto out;
 
-       switch (cmd_op) {
+       ret = -EINVAL;
+       switch (_IOC_NR(cmd_op)) {
        case UBLK_IO_FETCH_REQ:
                /* UBLK_IO_FETCH_REQ is only allowed before queue is setup */
                if (ublk_queue_ready(ubq)) {
@@ -1743,6 +1762,8 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
        if (!IS_BUILTIN(CONFIG_BLK_DEV_UBLK))
                ub->dev_info.flags |= UBLK_F_URING_CMD_COMP_IN_TASK;
 
+       ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE;
+
        /* We are not ready to support zero copy */
        ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;
 
@@ -2099,7 +2120,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
                 * know if the specified device is created as unprivileged
                 * mode.
                 */
-               if (cmd->cmd_op != UBLK_CMD_GET_DEV_INFO2)
+               if (_IOC_NR(cmd->cmd_op) != UBLK_CMD_GET_DEV_INFO2)
                        return 0;
        }
 
@@ -2125,7 +2146,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
        dev_path[header->dev_path_len] = 0;
 
        ret = -EINVAL;
-       switch (cmd->cmd_op) {
+       switch (_IOC_NR(cmd->cmd_op)) {
        case UBLK_CMD_GET_DEV_INFO:
        case UBLK_CMD_GET_DEV_INFO2:
        case UBLK_CMD_GET_QUEUE_AFFINITY:
@@ -2164,6 +2185,7 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
 {
        struct ublksrv_ctrl_cmd *header = (struct ublksrv_ctrl_cmd *)cmd->cmd;
        struct ublk_device *ub = NULL;
+       u32 cmd_op = cmd->cmd_op;
        int ret = -EINVAL;
 
        if (issue_flags & IO_URING_F_NONBLOCK)
@@ -2174,22 +2196,22 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
        if (!(issue_flags & IO_URING_F_SQE128))
                goto out;
 
-       if (cmd->cmd_op != UBLK_CMD_ADD_DEV) {
+       ret = ublk_check_cmd_op(cmd_op);
+       if (ret)
+               goto out;
+
+       if (_IOC_NR(cmd_op) != UBLK_CMD_ADD_DEV) {
                ret = -ENODEV;
                ub = ublk_get_device_from_id(header->dev_id);
                if (!ub)
                        goto out;
 
                ret = ublk_ctrl_uring_cmd_permission(ub, cmd);
-       } else {
-               /* ADD_DEV permission check is done in command handler */
-               ret = 0;
+               if (ret)
+                       goto put_dev;
        }
 
-       if (ret)
-               goto put_dev;
-
-       switch (cmd->cmd_op) {
+       switch (_IOC_NR(cmd_op)) {
        case UBLK_CMD_START_DEV:
                ret = ublk_ctrl_start_dev(ub, cmd);
                break;