summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/nwflash.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c63
-rw-r--r--drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c8
-rw-r--r--drivers/macintosh/ans-lcd.c6
-rw-r--r--drivers/mtd/ubi/cdev.c4
-rw-r--r--drivers/pci/proc.c20
-rw-r--r--drivers/pnp/isapnp/proc.c2
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim_blk.c9
-rw-r--r--drivers/vdpa/vdpa_sim/vdpa_sim_net.c9
-rw-r--r--drivers/vhost/vringh.c4
-rw-r--r--drivers/xen/gntdev.c4
-rw-r--r--drivers/xen/privcmd.c6
13 files changed, 86 insertions, 57 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 5b93c92c2cf1..c4c78182b56e 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -372,7 +372,7 @@ static ssize_t read_port(struct file *file, char __user *buf,
if (!access_ok(buf, count))
return -EFAULT;
while (count-- > 0 && i < 65536) {
- if (__put_user(inb(i), tmp) < 0)
+ if (put_user(inb(i), tmp) < 0)
return -EFAULT;
i++;
tmp++;
@@ -392,7 +392,7 @@ static ssize_t write_port(struct file *file, const char __user *buf,
while (count-- > 0 && i < 65536) {
char c;
- if (__get_user(c, tmp)) {
+ if (get_user(c, tmp)) {
if (tmp > buf)
break;
return -EFAULT;
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index 9f52f0306ef7..c3df2b032e29 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -422,7 +422,7 @@ static int write_block(unsigned long p, const char __user *buf, int count)
for (offset = 0; offset < count; offset++, pWritePtr++) {
uAddress = (unsigned int) pWritePtr;
uAddress &= 0xFFFFFFFC;
- if (__get_user(c2, buf + offset))
+ if (get_user(c2, buf + offset))
return -EFAULT;
WriteRetry:
@@ -533,7 +533,7 @@ static int write_block(unsigned long p, const char __user *buf, int count)
for (offset = 0; offset < count; offset++) {
char c, c1;
- if (__get_user(c, buf))
+ if (get_user(c, buf))
return -EFAULT;
buf++;
if ((c1 = *pWritePtr++) != c) {
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index d5aadced7da0..1b7f5bf13e50 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -1522,8 +1522,9 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
/*
* We must check that the entire relocation array is safe
- * to read. However, if the array is not writable the user loses
- * the updated relocation values.
+ * to read. Whether it is also writable only shows when we
+ * write back the presumed offsets below, and if that fails we
+ * fall back to the slow path.
*/
if (unlikely(!access_ok(urelocs, remain * sizeof(*urelocs))))
return -EFAULT;
@@ -1553,6 +1554,7 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
remain -= count;
do {
u64 offset = eb_relocate_entry(eb, ev, r);
+ int err;
if (likely(offset == 0))
continue;
@@ -1562,28 +1564,41 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct eb_vma *ev)
goto out;
}
/*
- * Note that reporting an error now
- * leaves everything in an inconsistent
- * state as we have *already* changed
- * the relocation value inside the
- * object. As we have not changed the
- * reloc.presumed_offset or will not
- * change the execobject.offset, on the
- * call we may not rewrite the value
- * inside the object, leaving it
- * dangling and causing a GPU hang. Unless
- * userspace dynamically rebuilds the
- * relocations on each execbuf rather than
- * presume a static tree.
+ * Write back the presumed offset. We hold the
+ * objects' dma_resv locks here, so this must not
+ * take a page fault: that would take mmap_lock
+ * under dma_resv, the opposite of the order our
+ * own fault handler uses.
*
- * We did previously check if the relocations
- * were writable (access_ok), an error now
- * would be a strange race with mprotect,
- * having already demonstrated that we
- * can read from this userspace address.
+ * If the write fails (the page is read-only,
+ * copy-on-write, or gone since we read it), we
+ * must not just carry on. We have already changed
+ * the relocation value inside the object, and a
+ * stale presumed_offset could later match again
+ * and make us skip a relocation that is needed,
+ * hanging the GPU. So fall back to the slow path,
+ * as for a failed read: it retries after
+ * prefaulting and, failing that, marks every
+ * presumed_offset invalid with faults allowed and
+ * no locks held.
*/
offset = gen8_canonical_addr(offset & ~UPDATE);
- __put_user(offset, &urelocs[r - stack].presumed_offset);
+ pagefault_disable();
+ err = put_user(offset, &urelocs[r - stack].presumed_offset);
+ pagefault_enable();
+
+ /*
+ * Error handling is disabled on purpose. No, it makes
+ * no sense, and the code will loop over the relocations
+ * without writing them back and just waste CPU time,
+ * but that's apparently what the mprotect test-cases
+ * want. See commit 97a37c919f62 ("drm/i915/gem: Ignore
+ * readonly failures when updating relocs")
+ */
+ if (unlikely(err) && 0) {
+ remain = -EFAULT;
+ goto out;
+ }
} while (r++, --count);
urelocs += ARRAY_SIZE(stack);
} while (remain);
@@ -1635,11 +1650,11 @@ static int check_relocations(const struct drm_i915_gem_exec_object2 *entry)
end = addr + size;
for (; addr < end; addr += PAGE_SIZE) {
- int err = __get_user(c, addr);
+ int err = get_user(c, addr);
if (err)
return err;
}
- return __get_user(c, end - 1);
+ return get_user(c, end - 1);
}
static int eb_copy_relocations(const struct i915_execbuffer *eb)
@@ -2837,7 +2852,7 @@ add_timeline_fence_array(struct i915_execbuffer *eb,
if (user_fence.flags & __I915_EXEC_FENCE_UNKNOWN_FLAGS)
return -EINVAL;
- if (__get_user(point, user_values++))
+ if (get_user(point, user_values++))
return -EFAULT;
syncobj = drm_syncobj_find(eb->file, user_fence.handle);
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index d01acfb7d93d..e6748856a0a8 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -1465,7 +1465,7 @@ static int __igt_mmap_access(struct drm_i915_private *i915,
return addr;
ptr = (unsigned long __user *)addr;
- err = __put_user(A, ptr);
+ err = put_user(A, ptr);
if (err) {
pr_err("%s(%s): failed to write into user mmap\n",
obj->mm.region->name, repr_mmap_type(type));
@@ -1490,7 +1490,7 @@ static int __igt_mmap_access(struct drm_i915_private *i915,
intel_gt_flush_ggtt_writes(to_gt(i915));
- err = __get_user(y, ptr);
+ err = get_user(y, ptr);
if (err) {
pr_err("%s(%s): failed to read from user mmap\n",
obj->mm.region->name, repr_mmap_type(type));
@@ -1738,12 +1738,12 @@ static int prefault_range(u64 start, u64 len)
end = addr + len;
for (; addr < end; addr += PAGE_SIZE) {
- err = __get_user(c, addr);
+ err = get_user(c, addr);
if (err)
return err;
}
- return __get_user(c, end - 1);
+ return get_user(c, end - 1);
}
static int __igt_mmap_revoke(struct drm_i915_private *i915,
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index fa904b24a600..673ff672af8a 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -71,7 +71,7 @@ anslcd_write( struct file * file, const char __user * buf,
for ( i = *ppos; count > 0; ++i, ++p, --count )
{
char c;
- __get_user(c, p);
+ get_user(c, p);
anslcd_write_byte_data( c );
}
mutex_unlock(&anslcd_mutex);
@@ -102,10 +102,10 @@ anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
case ANSLCD_SENDCTRL:
temp = (char __user *) arg;
- __get_user(ch, temp);
+ get_user(ch, temp);
for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */
anslcd_write_byte_ctrl ( ch );
- __get_user(ch, temp);
+ get_user(ch, temp);
}
break;
case ANSLCD_SETSHORTDELAY:
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 54acd8394d67..8dd005ef376b 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -861,7 +861,7 @@ static int ubi_get_ec_info(struct ubi_device *ubi, struct ubi_ecinfo_req __user
int ec;
if (ubi_io_is_bad(ubi, peb)) {
- if (__put_user(UBI_UNKNOWN, ureq->erase_counters+read_cnt))
+ if (put_user(UBI_UNKNOWN, ureq->erase_counters+read_cnt))
return -EFAULT;
continue;
@@ -877,7 +877,7 @@ static int ubi_get_ec_info(struct ubi_device *ubi, struct ubi_ecinfo_req __user
spin_unlock(&ubi->wl_lock);
- if (__put_user(ec, ureq->erase_counters+read_cnt))
+ if (put_user(ec, ureq->erase_counters+read_cnt))
return -EFAULT;
}
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index f5fd860a0540..3d7a9ed5fc22 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -67,7 +67,7 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if ((pos & 1) && cnt) {
unsigned char val;
pci_user_read_config_byte(dev, pos, &val);
- __put_user(val, buf);
+ put_user(val, buf);
buf++;
pos++;
cnt--;
@@ -76,7 +76,7 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if ((pos & 3) && cnt > 2) {
unsigned short val;
pci_user_read_config_word(dev, pos, &val);
- __put_user(cpu_to_le16(val), (__le16 __user *) buf);
+ put_user(cpu_to_le16(val), (__le16 __user *) buf);
buf += 2;
pos += 2;
cnt -= 2;
@@ -85,7 +85,7 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
while (cnt >= 4) {
unsigned int val;
pci_user_read_config_dword(dev, pos, &val);
- __put_user(cpu_to_le32(val), (__le32 __user *) buf);
+ put_user(cpu_to_le32(val), (__le32 __user *) buf);
buf += 4;
pos += 4;
cnt -= 4;
@@ -95,7 +95,7 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if (cnt >= 2) {
unsigned short val;
pci_user_read_config_word(dev, pos, &val);
- __put_user(cpu_to_le16(val), (__le16 __user *) buf);
+ put_user(cpu_to_le16(val), (__le16 __user *) buf);
buf += 2;
pos += 2;
cnt -= 2;
@@ -104,7 +104,7 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if (cnt) {
unsigned char val;
pci_user_read_config_byte(dev, pos, &val);
- __put_user(val, buf);
+ put_user(val, buf);
pos++;
}
@@ -151,7 +151,7 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if ((pos & 1) && cnt) {
unsigned char val;
- __get_user(val, buf);
+ get_user(val, buf);
pci_user_write_config_byte(dev, pos, val);
buf++;
pos++;
@@ -160,7 +160,7 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if ((pos & 3) && cnt > 2) {
__le16 val;
- __get_user(val, (__le16 __user *) buf);
+ get_user(val, (__le16 __user *) buf);
pci_user_write_config_word(dev, pos, le16_to_cpu(val));
buf += 2;
pos += 2;
@@ -169,7 +169,7 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
while (cnt >= 4) {
__le32 val;
- __get_user(val, (__le32 __user *) buf);
+ get_user(val, (__le32 __user *) buf);
pci_user_write_config_dword(dev, pos, le32_to_cpu(val));
buf += 4;
pos += 4;
@@ -178,7 +178,7 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if (cnt >= 2) {
__le16 val;
- __get_user(val, (__le16 __user *) buf);
+ get_user(val, (__le16 __user *) buf);
pci_user_write_config_word(dev, pos, le16_to_cpu(val));
buf += 2;
pos += 2;
@@ -187,7 +187,7 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if (cnt) {
unsigned char val;
- __get_user(val, buf);
+ get_user(val, buf);
pci_user_write_config_byte(dev, pos, val);
pos++;
}
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 55ae72a2818b..c1f6e6bd0eb2 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -41,7 +41,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,
for (; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
unsigned char val;
val = isapnp_read_byte(pos);
- __put_user(val, buf);
+ put_user(val, buf);
}
isapnp_cfg_end();
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
index 76dd5b0828d7..4d3e36fb59d5 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim_blk.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/uaccess.h>
#include <linux/blkdev.h>
#include <linux/vringh.h>
#include <linux/vdpa.h>
@@ -343,11 +344,17 @@ static void vdpasim_blk_work(struct vdpasim *vdpasim)
continue;
while (vdpasim_blk_handle_req(vdpasim, vq)) {
+ bool notify;
+
/* Make sure used is visible before rasing the interrupt. */
smp_wmb();
local_bh_disable();
- if (vringh_need_notify_iotlb(&vq->vring) > 0)
+ /* The ring may be in user memory, and we can't take faults here */
+ pagefault_disable();
+ notify = vringh_need_notify_iotlb(&vq->vring) > 0;
+ pagefault_enable();
+ if (notify)
vringh_notify(&vq->vring);
local_bh_enable();
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
index a6514b5ccd86..543a58abcdb8 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/uaccess.h>
#include <linux/etherdevice.h>
#include <linux/vringh.h>
#include <linux/vdpa.h>
@@ -68,6 +69,8 @@ static struct vdpasim_net *sim_to_net(struct vdpasim *vdpasim)
static void vdpasim_net_complete(struct vdpasim_virtqueue *vq, size_t len)
{
+ bool notify;
+
/* Make sure data is wrote before advancing index */
smp_wmb();
@@ -77,7 +80,11 @@ static void vdpasim_net_complete(struct vdpasim_virtqueue *vq, size_t len)
smp_wmb();
local_bh_disable();
- if (vringh_need_notify_iotlb(&vq->vring) > 0)
+ /* The ring may be in user memory, and we can't take faults here */
+ pagefault_disable();
+ notify = vringh_need_notify_iotlb(&vq->vring) > 0;
+ pagefault_enable();
+ if (notify)
vringh_notify(&vq->vring);
local_bh_enable();
}
diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
index 9066f9f12ba1..74836eb60c7a 100644
--- a/drivers/vhost/vringh.c
+++ b/drivers/vhost/vringh.c
@@ -1213,7 +1213,7 @@ static inline int getu16_iotlb(const struct vringh *vrh,
return ret;
if (vrh->use_va) {
- ret = __get_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base);
+ ret = get_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base);
if (ret)
return ret;
} else {
@@ -1251,7 +1251,7 @@ static inline int putu16_iotlb(const struct vringh *vrh,
tmp = cpu_to_vringh16(vrh, val);
if (vrh->use_va) {
- ret = __put_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base);
+ ret = put_user(tmp, (__virtio16 __user *)ivec.iov.iovec[0].iov_base);
if (ret)
return ret;
} else {
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index b71f5bae25b6..49957e3ab49d 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -849,13 +849,13 @@ static int gntdev_copy(struct gntdev_copy_batch *batch)
if (status == GNTST_okay)
continue;
- if (__get_user(old_status, batch->status[i]))
+ if (get_user(old_status, batch->status[i]))
return -EFAULT;
if (old_status != GNTST_okay)
continue;
- if (__put_user(status, batch->status[i]))
+ if (put_user(status, batch->status[i]))
return -EFAULT;
}
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index c67ec6d282cf..5e56fbc93447 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -411,12 +411,12 @@ static int mmap_return_error(int err, struct mmap_batch_state *st)
gfn |= (err == -ENOENT) ?
PRIVCMD_MMAPBATCH_PAGED_ERROR :
PRIVCMD_MMAPBATCH_MFN_ERROR;
- return __put_user(gfn, st->user_gfn++);
+ return put_user(gfn, st->user_gfn++);
} else
st->user_gfn++;
} else { /* st->version == 2 */
if (err)
- return __put_user(err, st->user_err++);
+ return put_user(err, st->user_err++);
else
st->user_err++;
}
@@ -777,7 +777,7 @@ static long privcmd_ioctl_mmap_resource(struct file *file,
rc = HYPERVISOR_memory_op(XENMEM_acquire_resource, &xdata);
if (rc)
return rc;
- return __put_user(xdata.nr_frames, &udata->num);
+ return put_user(xdata.nr_frames, &udata->num);
}
mmap_write_lock(mm);