[bug report] drm/xe: missing access_ok() in ioctl

Dan Carpenter dan.carpenter at linaro.org
Thu Jan 4 13:35:33 UTC 2024


Hello Matthew Brost,

The patch dd08ebf6c352: "drm/xe: Introduce a new DRM driver for Intel
GPUs" from Mar 30, 2023 (linux-next), leads to the following Smatch
static checker warning:

	drivers/gpu/drm/xe/xe_exec.c:163 xe_exec_ioctl()
	warn: calling '__copy_from_user()' without access_ok()

drivers/gpu/drm/xe/xe_exec.c
    102 int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
    103 {
    104         struct xe_device *xe = to_xe_device(dev);
    105         struct xe_file *xef = to_xe_file(file);
    106         struct drm_xe_exec *args = data;
    107         struct drm_xe_sync __user *syncs_user = u64_to_user_ptr(args->syncs);
    108         u64 __user *addresses_user = u64_to_user_ptr(args->address);
    109         struct xe_exec_queue *q;
    110         struct xe_sync_entry *syncs = NULL;
    111         u64 addresses[XE_HW_ENGINE_MAX_INSTANCE];
    112         struct drm_gpuvm_exec vm_exec = {.extra.fn = xe_exec_fn};
    113         struct drm_exec *exec = &vm_exec.exec;
    114         u32 i, num_syncs = 0;
    115         struct xe_sched_job *job;
    116         struct dma_fence *rebind_fence;
    117         struct xe_vm *vm;
    118         bool write_locked;
    119         ktime_t end = 0;
    120         int err = 0;
    121 
    122         if (XE_IOCTL_DBG(xe, args->extensions) ||
    123             XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) ||
    124             XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]))
    125                 return -EINVAL;
    126 
    127         q = xe_exec_queue_lookup(xef, args->exec_queue_id);
    128         if (XE_IOCTL_DBG(xe, !q))
    129                 return -ENOENT;
    130 
    131         if (XE_IOCTL_DBG(xe, q->flags & EXEC_QUEUE_FLAG_VM))
    132                 return -EINVAL;
    133 
    134         if (XE_IOCTL_DBG(xe, args->num_batch_buffer &&
    135                          q->width != args->num_batch_buffer))
    136                 return -EINVAL;
    137 
    138         if (XE_IOCTL_DBG(xe, q->flags & EXEC_QUEUE_FLAG_BANNED)) {
    139                 err = -ECANCELED;
    140                 goto err_exec_queue;
    141         }
    142 
    143         if (args->num_syncs) {
    144                 syncs = kcalloc(args->num_syncs, sizeof(*syncs), GFP_KERNEL);
    145                 if (!syncs) {
    146                         err = -ENOMEM;
    147                         goto err_exec_queue;
    148                 }
    149         }
    150 
    151         vm = q->vm;
    152 
    153         for (i = 0; i < args->num_syncs; i++) {
    154                 err = xe_sync_entry_parse(xe, xef, &syncs[num_syncs++],
    155                                           &syncs_user[i], SYNC_PARSE_FLAG_EXEC |
    156                                           (xe_vm_in_lr_mode(vm) ?
    157                                            SYNC_PARSE_FLAG_LR_MODE : 0));
    158                 if (err)
    159                         goto err_syncs;
    160         }
    161 
    162         if (xe_exec_queue_is_parallel(q)) {
--> 163                 err = __copy_from_user(addresses, addresses_user, sizeof(u64) *
    164                                        q->width);

It's been a long time since I've ever reported one of these.  The
difference between copy_from_user() and __copy_from_user() is that the
underscore version means we called
access_ok(addresses_user, sizeof(u64) * q->width) already.  In olden
days if we were doing multiple copies then it was nice to avoid doing
duplicate checks on the fast path.

I don't think we have called access_ok() here.  At one point Linus said
that if we don't call access_ok() in the same function then it should
just automatically considered a bug.  We used to have a lot of issues
with this back in the day...  I don't think anyone took Linus too
seriously on this though.

    165                 if (err) {
    166                         err = -EFAULT;
    167                         goto err_syncs;
    168                 }
    169         }
    170 
    171 retry:
    172         if (!xe_vm_in_lr_mode(vm) && xe_vm_userptr_check_repin(vm)) {
    173                 err = down_write_killable(&vm->lock);
    174                 write_locked = true;
    175         } else {

regards,
dan carpenter


More information about the dri-devel mailing list