|
|
@@ -2479,6 +2479,23 @@ static int elf_header_check(struct load_info *info)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#define COPY_CHUNK_SIZE (16*PAGE_SIZE)
|
|
|
+
|
|
|
+static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned long len)
|
|
|
+{
|
|
|
+ do {
|
|
|
+ unsigned long n = min(len, COPY_CHUNK_SIZE);
|
|
|
+
|
|
|
+ if (copy_from_user(dst, usrc, n) != 0)
|
|
|
+ return -EFAULT;
|
|
|
+ cond_resched();
|
|
|
+ dst += n;
|
|
|
+ usrc += n;
|
|
|
+ len -= n;
|
|
|
+ } while (len);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* Sets info->hdr and info->len. */
|
|
|
static int copy_module_from_user(const void __user *umod, unsigned long len,
|
|
|
struct load_info *info)
|
|
|
@@ -2498,7 +2515,7 @@ static int copy_module_from_user(const void __user *umod, unsigned long len,
|
|
|
if (!info->hdr)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- if (copy_from_user(info->hdr, umod, info->len) != 0) {
|
|
|
+ if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) {
|
|
|
vfree(info->hdr);
|
|
|
return -EFAULT;
|
|
|
}
|