Blame view
kernel/kexec.c
7.01 KB
dc009d924 [PATCH] kexec: ad... |
1 |
/* |
2965faa5e kexec: split kexe... |
2 |
* kexec.c - kexec_load system call |
dc009d924 [PATCH] kexec: ad... |
3 4 5 6 7 |
* Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com> * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ |
de90a6bca kexec: use file n... |
8 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
c59ede7b7 [PATCH] move capa... |
9 |
#include <linux/capability.h> |
dc009d924 [PATCH] kexec: ad... |
10 11 |
#include <linux/mm.h> #include <linux/file.h> |
dc009d924 [PATCH] kexec: ad... |
12 |
#include <linux/kexec.h> |
8c5a1cf0a kexec: use a mute... |
13 |
#include <linux/mutex.h> |
dc009d924 [PATCH] kexec: ad... |
14 |
#include <linux/list.h> |
dc009d924 [PATCH] kexec: ad... |
15 |
#include <linux/syscalls.h> |
a43cac0d9 kexec: split kexe... |
16 |
#include <linux/vmalloc.h> |
2965faa5e kexec: split kexe... |
17 |
#include <linux/slab.h> |
dc009d924 [PATCH] kexec: ad... |
18 |
|
a43cac0d9 kexec: split kexe... |
19 |
#include "kexec_internal.h" |
dabe78628 kexec: move segme... |
20 21 22 |
static int copy_user_segment_list(struct kimage *image, unsigned long nr_segments, struct kexec_segment __user *segments) |
dc009d924 [PATCH] kexec: ad... |
23 |
{ |
dabe78628 kexec: move segme... |
24 |
int ret; |
dc009d924 [PATCH] kexec: ad... |
25 |
size_t segment_bytes; |
dc009d924 [PATCH] kexec: ad... |
26 27 28 29 |
/* Read in the segments */ image->nr_segments = nr_segments; segment_bytes = nr_segments * sizeof(*segments); |
dabe78628 kexec: move segme... |
30 31 32 33 34 35 |
ret = copy_from_user(image->segment, segments, segment_bytes); if (ret) ret = -EFAULT; return ret; } |
255aedd90 kexec: use common... |
36 37 38 39 |
static int kimage_alloc_init(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags) |
dc009d924 [PATCH] kexec: ad... |
40 |
{ |
255aedd90 kexec: use common... |
41 |
int ret; |
dc009d924 [PATCH] kexec: ad... |
42 |
struct kimage *image; |
255aedd90 kexec: use common... |
43 44 45 46 |
bool kexec_on_panic = flags & KEXEC_ON_CRASH; if (kexec_on_panic) { /* Verify we have a valid entry point */ |
43546d866 kexec: allow arch... |
47 48 |
if ((entry < phys_to_boot_phys(crashk_res.start)) || (entry > phys_to_boot_phys(crashk_res.end))) |
255aedd90 kexec: use common... |
49 50 |
return -EADDRNOTAVAIL; } |
dc009d924 [PATCH] kexec: ad... |
51 52 |
/* Allocate and initialize a controlling structure */ |
dabe78628 kexec: move segme... |
53 54 55 56 57 |
image = do_kimage_alloc_init(); if (!image) return -ENOMEM; image->start = entry; |
255aedd90 kexec: use common... |
58 59 |
ret = copy_user_segment_list(image, nr_segments, segments); if (ret) |
dabe78628 kexec: move segme... |
60 |
goto out_free_image; |
255aedd90 kexec: use common... |
61 |
if (kexec_on_panic) { |
cdf4b3fa0 kexec: set KEXEC_... |
62 |
/* Enable special crash kernel control page alloc policy. */ |
255aedd90 kexec: use common... |
63 64 65 |
image->control_page = crashk_res.start; image->type = KEXEC_TYPE_CRASH; } |
cdf4b3fa0 kexec: set KEXEC_... |
66 67 68 |
ret = sanity_check_segment_list(image); if (ret) goto out_free_image; |
dc009d924 [PATCH] kexec: ad... |
69 70 71 72 73 |
/* * Find a location for the control code buffer, and add it * the vector of segments so that it's pages will also be * counted as destination pages. */ |
255aedd90 kexec: use common... |
74 |
ret = -ENOMEM; |
dc009d924 [PATCH] kexec: ad... |
75 |
image->control_code_page = kimage_alloc_control_pages(image, |
163f6876f kexec jump: renam... |
76 |
get_order(KEXEC_CONTROL_PAGE_SIZE)); |
dc009d924 [PATCH] kexec: ad... |
77 |
if (!image->control_code_page) { |
e1bebcf41 kernel/kexec.c: c... |
78 79 |
pr_err("Could not allocate control_code_buffer "); |
dabe78628 kexec: move segme... |
80 |
goto out_free_image; |
dc009d924 [PATCH] kexec: ad... |
81 |
} |
255aedd90 kexec: use common... |
82 83 84 85 86 87 88 |
if (!kexec_on_panic) { image->swap_page = kimage_alloc_control_pages(image, 0); if (!image->swap_page) { pr_err("Could not allocate swap buffer "); goto out_free_control_pages; } |
3ab835213 kexec jump |
89 |
} |
b92e7e0da kexec: fix memory... |
90 91 |
*rimage = image; return 0; |
dabe78628 kexec: move segme... |
92 |
out_free_control_pages: |
b92e7e0da kexec: fix memory... |
93 |
kimage_free_page_list(&image->control_pages); |
dabe78628 kexec: move segme... |
94 |
out_free_image: |
b92e7e0da kexec: fix memory... |
95 |
kfree(image); |
255aedd90 kexec: use common... |
96 |
return ret; |
dc009d924 [PATCH] kexec: ad... |
97 |
} |
0eea08678 kexec: do a clean... |
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
static int do_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags) { struct kimage **dest_image, *image; unsigned long i; int ret; if (flags & KEXEC_ON_CRASH) { dest_image = &kexec_crash_image; if (kexec_crash_image) arch_kexec_unprotect_crashkres(); } else { dest_image = &kexec_image; } if (nr_segments == 0) { /* Uninstall image */ kimage_free(xchg(dest_image, NULL)); return 0; } if (flags & KEXEC_ON_CRASH) { /* * Loading another kernel to switch to if this one * crashes. Free any current crash dump kernel before * we corrupt it. */ kimage_free(xchg(&kexec_crash_image, NULL)); } ret = kimage_alloc_init(&image, entry, nr_segments, segments, flags); if (ret) return ret; |
0eea08678 kexec: do a clean... |
130 131 132 133 134 135 |
if (flags & KEXEC_PRESERVE_CONTEXT) image->preserve_context = 1; ret = machine_kexec_prepare(image); if (ret) goto out; |
1229384f5 kdump: protect vm... |
136 137 138 139 140 141 142 |
/* * Some architecture(like S390) may touch the crash memory before * machine_kexec_prepare(), we must copy vmcoreinfo data after it. */ ret = kimage_crash_copy_vmcoreinfo(image); if (ret) goto out; |
0eea08678 kexec: do a clean... |
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
for (i = 0; i < nr_segments; i++) { ret = kimage_load_segment(image, &image->segment[i]); if (ret) goto out; } kimage_terminate(image); /* Install the new kernel and uninstall the old */ image = xchg(dest_image, image); out: if ((flags & KEXEC_ON_CRASH) && kexec_crash_image) arch_kexec_protect_crashkres(); |
0eea08678 kexec: do a clean... |
157 158 159 |
kimage_free(image); return ret; } |
dc009d924 [PATCH] kexec: ad... |
160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
/* * Exec Kernel system call: for obvious reasons only root may call it. * * This call breaks up into three pieces. * - A generic part which loads the new kernel from the current * address space, and very carefully places the data in the * allocated pages. * * - A generic part that interacts with the kernel and tells all of * the devices to shut down. Preventing on-going dmas, and placing * the devices in a consistent state so a later kernel can * reinitialize them. * * - A machine specific part that includes the syscall number |
002ace782 kexec: Typo s/the... |
174 |
* and then copies the image to it's final destination. And |
dc009d924 [PATCH] kexec: ad... |
175 176 177 178 179 |
* jumps into the image at entry. * * kexec does not sync, or unmount filesystems so if you need * that to happen you need to do that yourself. */ |
8c5a1cf0a kexec: use a mute... |
180 |
|
754fe8d29 [CVE-2009-0029] S... |
181 182 |
SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, struct kexec_segment __user *, segments, unsigned long, flags) |
dc009d924 [PATCH] kexec: ad... |
183 |
{ |
dc009d924 [PATCH] kexec: ad... |
184 185 186 |
int result; /* We only trust the superuser with rebooting the system. */ |
7984754b9 kexec: add sysctl... |
187 |
if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) |
dc009d924 [PATCH] kexec: ad... |
188 189 190 191 192 193 194 195 196 197 198 199 |
return -EPERM; /* * Verify we have a legal set of flags * This leaves us room for future extensions. */ if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK)) return -EINVAL; /* Verify we are on the appropriate architecture */ if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) && ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT)) |
dc009d924 [PATCH] kexec: ad... |
200 |
return -EINVAL; |
dc009d924 [PATCH] kexec: ad... |
201 202 203 204 205 206 |
/* Put an artificial cap on the number * of segments passed to kexec_load. */ if (nr_segments > KEXEC_SEGMENT_MAX) return -EINVAL; |
dc009d924 [PATCH] kexec: ad... |
207 208 209 210 211 212 213 214 |
/* Because we write directly to the reserved memory * region when loading crash kernels we need a mutex here to * prevent multiple crash kernels from attempting to load * simultaneously, and to prevent a crash kernel from loading * over the top of a in use crash kernel. * * KISS: always take the mutex. */ |
8c5a1cf0a kexec: use a mute... |
215 |
if (!mutex_trylock(&kexec_mutex)) |
dc009d924 [PATCH] kexec: ad... |
216 |
return -EBUSY; |
72414d3f1 [PATCH] kexec cod... |
217 |
|
0eea08678 kexec: do a clean... |
218 |
result = do_kexec_load(entry, nr_segments, segments, flags); |
dc009d924 [PATCH] kexec: ad... |
219 |
|
8c5a1cf0a kexec: use a mute... |
220 |
mutex_unlock(&kexec_mutex); |
72414d3f1 [PATCH] kexec cod... |
221 |
|
dc009d924 [PATCH] kexec: ad... |
222 223 224 225 |
return result; } #ifdef CONFIG_COMPAT |
ca2c405ab kexec/compat: con... |
226 227 228 229 |
COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry, compat_ulong_t, nr_segments, struct compat_kexec_segment __user *, segments, compat_ulong_t, flags) |
dc009d924 [PATCH] kexec: ad... |
230 231 232 233 234 235 236 237 |
{ struct compat_kexec_segment in; struct kexec_segment out, __user *ksegments; unsigned long i, result; /* Don't allow clients that don't understand the native * architecture to do anything. */ |
72414d3f1 [PATCH] kexec cod... |
238 |
if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT) |
dc009d924 [PATCH] kexec: ad... |
239 |
return -EINVAL; |
dc009d924 [PATCH] kexec: ad... |
240 |
|
72414d3f1 [PATCH] kexec cod... |
241 |
if (nr_segments > KEXEC_SEGMENT_MAX) |
dc009d924 [PATCH] kexec: ad... |
242 |
return -EINVAL; |
dc009d924 [PATCH] kexec: ad... |
243 244 |
ksegments = compat_alloc_user_space(nr_segments * sizeof(out)); |
e1bebcf41 kernel/kexec.c: c... |
245 |
for (i = 0; i < nr_segments; i++) { |
dc009d924 [PATCH] kexec: ad... |
246 |
result = copy_from_user(&in, &segments[i], sizeof(in)); |
72414d3f1 [PATCH] kexec cod... |
247 |
if (result) |
dc009d924 [PATCH] kexec: ad... |
248 |
return -EFAULT; |
dc009d924 [PATCH] kexec: ad... |
249 250 251 252 253 254 255 |
out.buf = compat_ptr(in.buf); out.bufsz = in.bufsz; out.mem = in.mem; out.memsz = in.memsz; result = copy_to_user(&ksegments[i], &out, sizeof(out)); |
72414d3f1 [PATCH] kexec cod... |
256 |
if (result) |
dc009d924 [PATCH] kexec: ad... |
257 |
return -EFAULT; |
dc009d924 [PATCH] kexec: ad... |
258 259 260 261 262 |
} return sys_kexec_load(entry, nr_segments, ksegments, flags); } #endif |