Skip to content

Commit 5d700a0

Browse files
arndbtorvalds
authored andcommitted
kexec: avoid compat_alloc_user_space
kimage_alloc_init() expects a __user pointer, so compat_sys_kexec_load() uses compat_alloc_user_space() to convert the layout and put it back onto the user space caller stack. Moving the user space access into the syscall handler directly actually makes the code simpler, as the conversion for compat mode can now be done on kernel memory. Link: https://lkml.kernel.org/r/[email protected] Link: https://lore.kernel.org/lkml/YPbtsU4GX6PL7%[email protected]/ Link: https://lore.kernel.org/lkml/[email protected]/ Signed-off-by: Arnd Bergmann <[email protected]> Co-developed-by: Eric Biederman <[email protected]> Co-developed-by: Christoph Hellwig <[email protected]> Acked-by: "Eric W. Biederman" <[email protected]> Cc: Al Viro <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Christian Borntraeger <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Feng Tang <[email protected]> Cc: Heiko Carstens <[email protected]> Cc: Helge Deller <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: "James E.J. Bottomley" <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Thomas Bogendoerfer <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vasily Gorbik <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4b692e8 commit 5d700a0

File tree

1 file changed

+25
-36
lines changed

1 file changed

+25
-36
lines changed

kernel/kexec.c

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,9 @@
1919

2020
#include "kexec_internal.h"
2121

22-
static int copy_user_segment_list(struct kimage *image,
23-
unsigned long nr_segments,
24-
struct kexec_segment __user *segments)
25-
{
26-
int ret;
27-
size_t segment_bytes;
28-
29-
/* Read in the segments */
30-
image->nr_segments = nr_segments;
31-
segment_bytes = nr_segments * sizeof(*segments);
32-
ret = copy_from_user(image->segment, segments, segment_bytes);
33-
if (ret)
34-
ret = -EFAULT;
35-
36-
return ret;
37-
}
38-
3922
static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
4023
unsigned long nr_segments,
41-
struct kexec_segment __user *segments,
24+
struct kexec_segment *segments,
4225
unsigned long flags)
4326
{
4427
int ret;
@@ -58,10 +41,8 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
5841
return -ENOMEM;
5942

6043
image->start = entry;
61-
62-
ret = copy_user_segment_list(image, nr_segments, segments);
63-
if (ret)
64-
goto out_free_image;
44+
image->nr_segments = nr_segments;
45+
memcpy(image->segment, segments, nr_segments * sizeof(*segments));
6546

6647
if (kexec_on_panic) {
6748
/* Enable special crash kernel control page alloc policy. */
@@ -104,7 +85,7 @@ static int kimage_alloc_init(struct kimage **rimage, unsigned long entry,
10485
}
10586

10687
static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
107-
struct kexec_segment __user *segments, unsigned long flags)
88+
struct kexec_segment *segments, unsigned long flags)
10889
{
10990
struct kimage **dest_image, *image;
11091
unsigned long i;
@@ -250,7 +231,8 @@ static inline int kexec_load_check(unsigned long nr_segments,
250231
SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
251232
struct kexec_segment __user *, segments, unsigned long, flags)
252233
{
253-
int result;
234+
struct kexec_segment *ksegments;
235+
unsigned long result;
254236

255237
result = kexec_load_check(nr_segments, flags);
256238
if (result)
@@ -261,7 +243,12 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
261243
((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT))
262244
return -EINVAL;
263245

264-
result = do_kexec_load(entry, nr_segments, segments, flags);
246+
ksegments = memdup_user(segments, nr_segments * sizeof(ksegments[0]));
247+
if (IS_ERR(ksegments))
248+
return PTR_ERR(ksegments);
249+
250+
result = do_kexec_load(entry, nr_segments, ksegments, flags);
251+
kfree(ksegments);
265252

266253
return result;
267254
}
@@ -273,7 +260,7 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
273260
compat_ulong_t, flags)
274261
{
275262
struct compat_kexec_segment in;
276-
struct kexec_segment out, __user *ksegments;
263+
struct kexec_segment *ksegments;
277264
unsigned long i, result;
278265

279266
result = kexec_load_check(nr_segments, flags);
@@ -286,24 +273,26 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
286273
if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT)
287274
return -EINVAL;
288275

289-
ksegments = compat_alloc_user_space(nr_segments * sizeof(out));
276+
ksegments = kmalloc_array(nr_segments, sizeof(ksegments[0]),
277+
GFP_KERNEL);
278+
if (!ksegments)
279+
return -ENOMEM;
280+
290281
for (i = 0; i < nr_segments; i++) {
291282
result = copy_from_user(&in, &segments[i], sizeof(in));
292283
if (result)
293-
return -EFAULT;
284+
goto fail;
294285

295-
out.buf = compat_ptr(in.buf);
296-
out.bufsz = in.bufsz;
297-
out.mem = in.mem;
298-
out.memsz = in.memsz;
299-
300-
result = copy_to_user(&ksegments[i], &out, sizeof(out));
301-
if (result)
302-
return -EFAULT;
286+
ksegments[i].buf = compat_ptr(in.buf);
287+
ksegments[i].bufsz = in.bufsz;
288+
ksegments[i].mem = in.mem;
289+
ksegments[i].memsz = in.memsz;
303290
}
304291

305292
result = do_kexec_load(entry, nr_segments, ksegments, flags);
306293

294+
fail:
295+
kfree(ksegments);
307296
return result;
308297
}
309298
#endif

0 commit comments

Comments
 (0)