1 /* Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License, version 2.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 #include "modcommon.h"
19 #include <linux/kthread.h>
20 #include <linux/proc_fs.h>
21 #include <linux/sched.h>
22 #include <linux/stop_machine.h>
23 #include <linux/time.h>
24 #include <asm/uaccess.h>
26 #ifndef task_thread_info
27 #define task_thread_info(task) (task)->thread_info
28 #endif /* task_thread_info */
31 #ifdef __ASM_X86_PROCESSOR_H
32 #define KSPLICE_EIP(x) ((x)->thread.ip)
33 #define KSPLICE_ESP(x) ((x)->thread.sp)
34 #elif BITS_PER_LONG == 32
35 #define KSPLICE_EIP(x) ((x)->thread.eip)
36 #define KSPLICE_ESP(x) ((x)->thread.esp)
37 #elif BITS_PER_LONG == 64
38 #define KSPLICE_EIP(x) (KSTK_EIP(x))
39 #define KSPLICE_ESP(x) ((x)->thread.rsp)
40 #endif /* __ASM_X86_PROCESSOR_H */
42 /* defined by modcommon.c */
43 extern int safe
, debug
;
45 /* defined by ksplice-create */
46 extern struct ksplice_reloc ksplice_init_relocs
, ksplice_relocs
;
47 extern struct ksplice_patch ksplice_patches
;
48 extern struct ksplice_size ksplice_sizes
;
50 LIST_HEAD(reloc_addrmaps
);
51 LIST_HEAD(reloc_namevals
);
52 LIST_HEAD(safety_records
);
54 struct module_pack
KSPLICE_UNIQ(pack
) = {
55 .name
= "ksplice_" STR(KSPLICE_ID
),
56 .map_printk
= MAP_PRINTK
,
57 .primary_relocs
= &ksplice_relocs
,
58 .primary_sizes
= &ksplice_sizes
,
59 .patches
= &ksplice_patches
,
60 .reloc_addrmaps
= &reloc_addrmaps
,
61 .reloc_namevals
= &reloc_namevals
,
62 .safety_records
= &safety_records
,
63 .activate_primary
= &activate_primary
,
65 EXPORT_SYMBOL_GPL(KSPLICE_UNIQ(pack
));
69 struct module_pack
*pack
= &KSPLICE_UNIQ(pack
);
70 if (process_ksplice_relocs(pack
, &ksplice_init_relocs
) != 0)
77 void cleanup_module(void)
79 cleanup_ksplice_module(&KSPLICE_UNIQ(pack
));
82 void cleanup_ksplice_module(struct module_pack
*pack
)
84 remove_proc_entry(pack
->name
, &proc_root
);
87 int activate_primary(struct module_pack
*pack
)
90 struct proc_dir_entry
*proc_entry
;
94 if (process_ksplice_relocs(pack
, pack
->primary_relocs
) != 0)
97 if (resolve_patch_symbols(pack
) != 0)
100 proc_entry
= create_proc_entry(pack
->name
, 0644, NULL
);
101 if (proc_entry
== NULL
) {
102 remove_proc_entry(pack
->name
, &proc_root
);
103 print_abort("primary module: could not create proc entry");
107 proc_entry
->read_proc
= procfile_read
;
108 proc_entry
->write_proc
= procfile_write
;
109 proc_entry
->data
= pack
;
110 proc_entry
->owner
= THIS_MODULE
;
111 proc_entry
->mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
114 proc_entry
->size
= 0;
116 for (i
= 0; pack
->state
!= KSPLICE_APPLIED
&& i
< 5; i
++) {
118 stop_machine_run(__apply_patches
, pack
, NR_CPUS
);
120 set_current_state(TASK_INTERRUPTIBLE
);
121 schedule_timeout(msecs_to_jiffies(1000));
123 if (pack
->state
!= KSPLICE_APPLIED
) {
124 remove_proc_entry(pack
->name
, &proc_root
);
125 print_abort("stack check: to-be-replaced code is busy");
129 printk("ksplice: Update %s applied successfully\n", pack
->name
);
133 int resolve_patch_symbols(struct module_pack
*pack
)
135 struct ksplice_patch
*p
;
138 for (p
= pack
->patches
; p
->oldstr
; p
++) {
139 p
->saved
= kmalloc(5, GFP_KERNEL
);
142 add_candidate_val(&vals
, p
->oldaddr
);
144 compute_address(pack
, p
->oldstr
, &vals
);
145 if (!singular(&vals
)) {
147 failed_to_find(p
->oldstr
);
151 list_entry(vals
.next
, struct candidate_val
, list
)->val
;
158 int procfile_read(char *buffer
, char **buffer_location
,
159 off_t offset
, int buffer_length
, int *eof
, void *data
)
164 int procfile_write(struct file
*file
, const char *buffer
, unsigned long count
,
168 struct module_pack
*pack
= data
;
169 printk("ksplice: Preparing to reverse %s\n", pack
->name
);
171 for (i
= 0; pack
->state
== KSPLICE_APPLIED
&& i
< 5; i
++) {
173 stop_machine_run(__reverse_patches
, pack
, NR_CPUS
);
175 set_current_state(TASK_INTERRUPTIBLE
);
176 schedule_timeout(msecs_to_jiffies(1000));
178 if (pack
->state
== KSPLICE_APPLIED
)
179 print_abort("stack check: to-be-reversed code is busy");
184 int __apply_patches(void *packptr
)
186 struct module_pack
*pack
= packptr
;
187 struct ksplice_patch
*p
;
188 struct list_head
*pos
;
189 struct safety_record
*rec
;
191 list_for_each(pos
, pack
->safety_records
) {
192 rec
= list_entry(pos
, struct safety_record
, list
);
193 for (p
= pack
->patches
; p
->oldstr
; p
++) {
194 if (p
->oldaddr
== rec
->addr
) {
200 if (check_each_task(pack
) != 0)
203 if (!try_module_get(THIS_MODULE
))
206 pack
->state
= KSPLICE_APPLIED
;
208 for (p
= pack
->patches
; p
->oldstr
; p
++) {
209 memcpy((void *)p
->saved
, (void *)p
->oldaddr
, 5);
210 *((u8
*) p
->oldaddr
) = 0xE9;
211 *((u32
*) (p
->oldaddr
+ 1)) = p
->repladdr
- (p
->oldaddr
+ 5);
216 int __reverse_patches(void *packptr
)
218 struct module_pack
*pack
= packptr
;
219 struct ksplice_patch
*p
;
221 if (pack
->state
!= KSPLICE_APPLIED
)
224 if (check_each_task(pack
) != 0)
227 clear_list(pack
->safety_records
, struct safety_record
, list
);
228 pack
->state
= KSPLICE_REVERSED
;
229 module_put(THIS_MODULE
);
232 for (; p
->oldstr
; p
++) {
233 memcpy((void *)p
->oldaddr
, (void *)p
->saved
, 5);
235 *((u8
*) p
->repladdr
) = 0xE9;
236 *((u32
*) (p
->repladdr
+ 1)) = p
->oldaddr
- (p
->repladdr
+ 5);
239 printk("ksplice: Update %s reversed successfully\n", pack
->name
);
243 int check_each_task(struct module_pack
*pack
)
245 struct task_struct
*g
, *p
;
247 read_lock(&tasklist_lock
);
248 do_each_thread(g
, p
) {
249 /* do_each_thread is a double loop! */
250 if (check_task(pack
, p
) != 0) {
259 while_each_thread(g
, p
);
260 read_unlock(&tasklist_lock
);
264 int check_task(struct module_pack
*pack
, struct task_struct
*t
)
267 long addr
= KSPLICE_EIP(t
);
268 int conflict
= check_address_for_conflict(pack
, addr
);
270 printk("ksplice: stack check: pid %d (%s) eip %08lx",
271 t
->pid
, t
->comm
, KSPLICE_EIP(t
));
273 printk(" [<-- CONFLICT]: ");
279 check_stack(pack
, task_thread_info(t
),
280 (long *)__builtin_frame_address(0));
281 } else if (!task_curr(t
)) {
283 check_stack(pack
, task_thread_info(t
),
284 (long *)KSPLICE_ESP(t
));
285 } else if (strcmp(t
->comm
, "kstopmachine") == 0) {
291 printk("unexpected running task!\n");
300 /* Modified version of Linux's print_context_stack */
301 int check_stack(struct module_pack
*pack
, struct thread_info
*tinfo
,
304 int conflict
, status
= 0;
307 while (valid_stack_ptr(tinfo
, stack
)) {
309 if (__kernel_text_address(addr
)) {
310 conflict
= check_address_for_conflict(pack
, addr
);
314 printk("%08lx ", addr
);
316 printk("[<-- CONFLICT] ");
326 int check_address_for_conflict(struct module_pack
*pack
, long addr
)
328 struct ksplice_size
*s
= pack
->primary_sizes
;
329 struct list_head
*pos
;
330 struct safety_record
*rec
;
332 list_for_each(pos
, pack
->safety_records
) {
333 rec
= list_entry(pos
, struct safety_record
, list
);
334 if (rec
->care
== 1 && addr
> rec
->addr
335 && addr
<= (rec
->addr
+ rec
->size
)) {
339 for (; s
->name
!= NULL
; s
++) {
340 if (addr
> s
->thismod_addr
341 && addr
<= (s
->thismod_addr
+ s
->size
)) {
349 /* Modified version of Linux's valid_stack_ptr */
350 int valid_stack_ptr(struct thread_info
*tinfo
, void *p
)
352 return p
> (void *)tinfo
353 && p
<= (void *)tinfo
+ THREAD_SIZE
- sizeof(long);