Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'uprobes/core' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc into perf/core

Fix uprobes bugs that happen if fork() is called with pending ret-probes,
from Oleg Nesterov.

Signed-off-by: Ingo Molnar <mingo@kernel.org>

+139 -55
+3 -3
include/linux/uprobes.h
··· 117 117 extern void uprobe_end_dup_mmap(void); 118 118 extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); 119 119 extern void uprobe_free_utask(struct task_struct *t); 120 - extern void uprobe_copy_process(struct task_struct *t); 120 + extern void uprobe_copy_process(struct task_struct *t, unsigned long flags); 121 121 extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); 122 122 extern int uprobe_post_sstep_notifier(struct pt_regs *regs); 123 123 extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); 124 124 extern void uprobe_notify_resume(struct pt_regs *regs); 125 125 extern bool uprobe_deny_signal(void); 126 - extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); 126 + extern bool arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); 127 127 extern void uprobe_clear_state(struct mm_struct *mm); 128 128 #else /* !CONFIG_UPROBES */ 129 129 struct uprobes_state { ··· 174 174 static inline void uprobe_free_utask(struct task_struct *t) 175 175 { 176 176 } 177 - static inline void uprobe_copy_process(struct task_struct *t) 177 + static inline void uprobe_copy_process(struct task_struct *t, unsigned long flags) 178 178 { 179 179 } 180 180 static inline void uprobe_clear_state(struct mm_struct *mm)
+135 -51
kernel/events/uprobes.c
··· 35 35 #include <linux/kdebug.h> /* notifier mechanism */ 36 36 #include "../../mm/internal.h" /* munlock_vma_page */ 37 37 #include <linux/percpu-rwsem.h> 38 + #include <linux/task_work.h> 38 39 39 40 #include <linux/uprobes.h> 40 41 ··· 1097 1096 } 1098 1097 1099 1098 /* Slot allocation for XOL */ 1100 - static int xol_add_vma(struct xol_area *area) 1099 + static int xol_add_vma(struct mm_struct *mm, struct xol_area *area) 1101 1100 { 1102 - struct mm_struct *mm = current->mm; 1103 1101 int ret = -EALREADY; 1104 1102 1105 1103 down_write(&mm->mmap_sem); 1106 1104 if (mm->uprobes_state.xol_area) 1107 1105 goto fail; 1108 1106 1109 - ret = -ENOMEM; 1110 - /* Try to map as high as possible, this is only a hint. */ 1111 - area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0); 1112 - if (area->vaddr & ~PAGE_MASK) { 1113 - ret = area->vaddr; 1114 - goto fail; 1107 + if (!area->vaddr) { 1108 + /* Try to map as high as possible, this is only a hint. */ 1109 + area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, 1110 + PAGE_SIZE, 0, 0); 1111 + if (area->vaddr & ~PAGE_MASK) { 1112 + ret = area->vaddr; 1113 + goto fail; 1114 + } 1115 1115 } 1116 1116 1117 1117 ret = install_special_mapping(mm, area->vaddr, PAGE_SIZE, ··· 1122 1120 1123 1121 smp_wmb(); /* pairs with get_xol_area() */ 1124 1122 mm->uprobes_state.xol_area = area; 1125 - ret = 0; 1126 1123 fail: 1127 1124 up_write(&mm->mmap_sem); 1128 1125 1129 1126 return ret; 1127 + } 1128 + 1129 + static struct xol_area *__create_xol_area(unsigned long vaddr) 1130 + { 1131 + struct mm_struct *mm = current->mm; 1132 + uprobe_opcode_t insn = UPROBE_SWBP_INSN; 1133 + struct xol_area *area; 1134 + 1135 + area = kmalloc(sizeof(*area), GFP_KERNEL); 1136 + if (unlikely(!area)) 1137 + goto out; 1138 + 1139 + area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL); 1140 + if (!area->bitmap) 1141 + goto free_area; 1142 + 1143 + area->page = alloc_page(GFP_HIGHUSER); 1144 + if (!area->page) 1145 + goto free_bitmap; 1146 + 1147 + area->vaddr = vaddr; 1148 + init_waitqueue_head(&area->wq); 1149 + /* Reserve the 1st slot for get_trampoline_vaddr() */ 1150 + set_bit(0, area->bitmap); 1151 + atomic_set(&area->slot_count, 1); 1152 + copy_to_page(area->page, 0, &insn, UPROBE_SWBP_INSN_SIZE); 1153 + 1154 + if (!xol_add_vma(mm, area)) 1155 + return area; 1156 + 1157 + __free_page(area->page); 1158 + free_bitmap: 1159 + kfree(area->bitmap); 1160 + free_area: 1161 + kfree(area); 1162 + out: 1163 + return NULL; 1130 1164 } 1131 1165 1132 1166 /* ··· 1175 1137 { 1176 1138 struct mm_struct *mm = current->mm; 1177 1139 struct xol_area *area; 1178 - uprobe_opcode_t insn = UPROBE_SWBP_INSN; 1140 + 1141 + if (!mm->uprobes_state.xol_area) 1142 + __create_xol_area(0); 1179 1143 1180 1144 area = mm->uprobes_state.xol_area; 1181 - if (area) 1182 - goto ret; 1183 - 1184 - area = kzalloc(sizeof(*area), GFP_KERNEL); 1185 - if (unlikely(!area)) 1186 - goto out; 1187 - 1188 - area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL); 1189 - if (!area->bitmap) 1190 - goto free_area; 1191 - 1192 - area->page = alloc_page(GFP_HIGHUSER); 1193 - if (!area->page) 1194 - goto free_bitmap; 1195 - 1196 - /* allocate first slot of task's xol_area for the return probes */ 1197 - set_bit(0, area->bitmap); 1198 - copy_to_page(area->page, 0, &insn, UPROBE_SWBP_INSN_SIZE); 1199 - atomic_set(&area->slot_count, 1); 1200 - init_waitqueue_head(&area->wq); 1201 - 1202 - if (!xol_add_vma(area)) 1203 - return area; 1204 - 1205 - __free_page(area->page); 1206 - free_bitmap: 1207 - kfree(area->bitmap); 1208 - free_area: 1209 - kfree(area); 1210 - out: 1211 - area = mm->uprobes_state.xol_area; 1212 - ret: 1213 - smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */ 1145 + smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */ 1214 1146 return area; 1215 1147 } 1216 1148 ··· 1353 1345 } 1354 1346 1355 1347 /* 1356 - * Called in context of a new clone/fork from copy_process. 1357 - */ 1358 - void uprobe_copy_process(struct task_struct *t) 1359 - { 1360 - t->utask = NULL; 1361 - } 1362 - 1363 - /* 1364 1348 * Allocate a uprobe_task object for the task if if necessary. 1365 1349 * Called when the thread hits a breakpoint. 1366 1350 * ··· 1365 1365 if (!current->utask) 1366 1366 current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL); 1367 1367 return current->utask; 1368 + } 1369 + 1370 + static int dup_utask(struct task_struct *t, struct uprobe_task *o_utask) 1371 + { 1372 + struct uprobe_task *n_utask; 1373 + struct return_instance **p, *o, *n; 1374 + 1375 + n_utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL); 1376 + if (!n_utask) 1377 + return -ENOMEM; 1378 + t->utask = n_utask; 1379 + 1380 + p = &n_utask->return_instances; 1381 + for (o = o_utask->return_instances; o; o = o->next) { 1382 + n = kmalloc(sizeof(struct return_instance), GFP_KERNEL); 1383 + if (!n) 1384 + return -ENOMEM; 1385 + 1386 + *n = *o; 1387 + atomic_inc(&n->uprobe->ref); 1388 + n->next = NULL; 1389 + 1390 + *p = n; 1391 + p = &n->next; 1392 + n_utask->depth++; 1393 + } 1394 + 1395 + return 0; 1396 + } 1397 + 1398 + static void uprobe_warn(struct task_struct *t, const char *msg) 1399 + { 1400 + pr_warn("uprobe: %s:%d failed to %s\n", 1401 + current->comm, current->pid, msg); 1402 + } 1403 + 1404 + static void dup_xol_work(struct callback_head *work) 1405 + { 1406 + kfree(work); 1407 + 1408 + if (current->flags & PF_EXITING) 1409 + return; 1410 + 1411 + if (!__create_xol_area(current->utask->vaddr)) 1412 + uprobe_warn(current, "dup xol area"); 1413 + } 1414 + 1415 + /* 1416 + * Called in context of a new clone/fork from copy_process. 1417 + */ 1418 + void uprobe_copy_process(struct task_struct *t, unsigned long flags) 1419 + { 1420 + struct uprobe_task *utask = current->utask; 1421 + struct mm_struct *mm = current->mm; 1422 + struct callback_head *work; 1423 + struct xol_area *area; 1424 + 1425 + t->utask = NULL; 1426 + 1427 + if (!utask || !utask->return_instances) 1428 + return; 1429 + 1430 + if (mm == t->mm && !(flags & CLONE_VFORK)) 1431 + return; 1432 + 1433 + if (dup_utask(t, utask)) 1434 + return uprobe_warn(t, "dup ret instances"); 1435 + 1436 + /* The task can fork() after dup_xol_work() fails */ 1437 + area = mm->uprobes_state.xol_area; 1438 + if (!area) 1439 + return uprobe_warn(t, "dup xol area"); 1440 + 1441 + if (mm == t->mm) 1442 + return; 1443 + 1444 + /* TODO: move it into the union in uprobe_task */ 1445 + work = kmalloc(sizeof(*work), GFP_KERNEL); 1446 + if (!work) 1447 + return uprobe_warn(t, "dup xol area"); 1448 + 1449 + utask->vaddr = area->vaddr; 1450 + init_task_work(work, dup_xol_work); 1451 + task_work_add(t, work, true); 1368 1452 } 1369 1453 1370 1454 /*
+1 -1
kernel/fork.c
··· 1373 1373 INIT_LIST_HEAD(&p->pi_state_list); 1374 1374 p->pi_state_cache = NULL; 1375 1375 #endif 1376 - uprobe_copy_process(p); 1377 1376 /* 1378 1377 * sigaltstack should be cleared when sharing the same VM 1379 1378 */ ··· 1489 1490 perf_event_fork(p); 1490 1491 1491 1492 trace_task_newtask(p, clone_flags); 1493 + uprobe_copy_process(p, clone_flags); 1492 1494 1493 1495 return p; 1494 1496