From 79d54b249c176ba4abb9a580951400246dd974b1 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 14 Sep 2012 18:03:59 +0200 Subject: uprobes: Do not leak UTASK_BP_HIT if find_active_uprobe() fails If handle_swbp()->find_active_uprobe() fails we return with utask->state = UTASK_BP_HIT. Change handle_swbp() to reset utask->state at the start. Note that we do this unconditionally, see the next patch(es). Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 912ef48d28ab..2c1ff05af6f5 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1468,6 +1468,10 @@ static void handle_swbp(struct pt_regs *regs) bp_vaddr = uprobe_get_swbp_addr(regs); uprobe = find_active_uprobe(bp_vaddr, &is_swbp); + utask = current->utask; + if (utask) + utask->state = UTASK_RUNNING; + if (!uprobe) { if (is_swbp > 0) { /* No matching uprobe; signal SIGTRAP. */ @@ -1486,7 +1490,6 @@ static void handle_swbp(struct pt_regs *regs) return; } - utask = current->utask; if (!utask) { utask = add_utask(); /* Cannot allocate; re-execute the instruction. */ -- cgit v1.2.3 From 746a9e6ba24af2ccf03279c99d435a1b88ca5d17 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 14 Sep 2012 18:23:51 +0200 Subject: uprobes: Do not setup ->active_uprobe/state prematurely handle_swbp() sets utask->active_uprobe before handler_chain(), and UTASK_SSTEP before pre_ssout(). This complicates the code for no reason, arch_ hooks or consumer->handler() should not (and can't) use this info. Change handle_swbp() to initialize them after pre_ssout(), and remove the no longer needed cleanup-utask code. Signed-off-by: Oleg Nesterov cked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 2c1ff05af6f5..41f048c91425 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1496,22 +1496,19 @@ static void handle_swbp(struct pt_regs *regs) if (!utask) goto cleanup_ret; } - utask->active_uprobe = uprobe; + handler_chain(uprobe, regs); if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs)) goto cleanup_ret; - utask->state = UTASK_SSTEP; if (!pre_ssout(uprobe, regs, bp_vaddr)) { arch_uprobe_enable_step(&uprobe->arch); + utask->active_uprobe = uprobe; + utask->state = UTASK_SSTEP; return; } cleanup_ret: - if (utask) { - utask->active_uprobe = NULL; - utask->state = UTASK_RUNNING; - } if (!(uprobe->flags & UPROBE_SKIP_SSTEP)) /* -- cgit v1.2.3 From 0578a97098dab967ece4b025fe5eb4984c4c86c0 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 14 Sep 2012 18:31:23 +0200 Subject: uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp() If handle_swbp()->add_utask() fails but UPROBE_SKIP_SSTEP is set, cleanup_ret: path do not restart the insn, this is wrong. Remove this check and add the additional label for can_skip_sstep() = T case. Note also that UPROBE_SKIP_SSTEP can be false positive, we simply can not trust it unless arch_uprobe_skip_sstep() was already called. Also, move another UPROBE_SKIP_SSTEP check before can_skip_sstep() into this helper, this looks more clean and understandable. Note: probably we should rename "skip" to "emulate" and I think that "clear UPROBE_SKIP_SSTEP" should be moved to arch_can_skip. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 41f048c91425..d2392968d4e6 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1389,10 +1389,11 @@ bool uprobe_deny_signal(void) */ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) { - if (arch_uprobe_skip_sstep(&uprobe->arch, regs)) - return true; - - uprobe->flags &= ~UPROBE_SKIP_SSTEP; + if (uprobe->flags & UPROBE_SKIP_SSTEP) { + if (arch_uprobe_skip_sstep(&uprobe->arch, regs)) + return true; + uprobe->flags &= ~UPROBE_SKIP_SSTEP; + } return false; } @@ -1494,12 +1495,12 @@ static void handle_swbp(struct pt_regs *regs) utask = add_utask(); /* Cannot allocate; re-execute the instruction. */ if (!utask) - goto cleanup_ret; + goto restart; } handler_chain(uprobe, regs); - if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs)) - goto cleanup_ret; + if (can_skip_sstep(uprobe, regs)) + goto out; if (!pre_ssout(uprobe, regs, bp_vaddr)) { arch_uprobe_enable_step(&uprobe->arch); @@ -1508,15 +1509,13 @@ static void handle_swbp(struct pt_regs *regs) return; } -cleanup_ret: - if (!(uprobe->flags & UPROBE_SKIP_SSTEP)) - - /* - * cannot singlestep; cannot skip instruction; - * re-execute the instruction. - */ - instruction_pointer_set(regs, bp_vaddr); - +restart: + /* + * cannot singlestep; cannot skip instruction; + * re-execute the instruction. + */ + instruction_pointer_set(regs, bp_vaddr); +out: put_uprobe(uprobe); } -- cgit v1.2.3 From 1b08e907211cdc744f54871736005d9f3e7f182c Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 14 Sep 2012 18:52:10 +0200 Subject: uprobes: Kill UTASK_BP_HIT state Kill UTASK_BP_HIT state, it buys nothing but complicates the code. It is only used in uprobe_notify_resume() to decide who should be called, we can check utask->active_uprobe != NULL instead. And this allows us to simplify handle_swbp(), no need to clear utask->state. Likewise we could kill UTASK_SSTEP, but UTASK_BP_HIT is worse and imho should die. The problem is, it creates the special case when task->utask is NULL, we can't distinguish RUNNING and BP_HIT. With this patch utask == NULL always means RUNNING. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- include/linux/uprobes.h | 1 - kernel/events/uprobes.c | 29 +++++++++-------------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index e6f0331e3d45..18d839da6517 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -59,7 +59,6 @@ struct uprobe_consumer { #ifdef CONFIG_UPROBES enum uprobe_task_state { UTASK_RUNNING, - UTASK_BP_HIT, UTASK_SSTEP, UTASK_SSTEP_ACK, UTASK_SSTEP_TRAPPED, diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index d2392968d4e6..d3f5381e7482 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1469,10 +1469,6 @@ static void handle_swbp(struct pt_regs *regs) bp_vaddr = uprobe_get_swbp_addr(regs); uprobe = find_active_uprobe(bp_vaddr, &is_swbp); - utask = current->utask; - if (utask) - utask->state = UTASK_RUNNING; - if (!uprobe) { if (is_swbp > 0) { /* No matching uprobe; signal SIGTRAP. */ @@ -1491,6 +1487,7 @@ static void handle_swbp(struct pt_regs *regs) return; } + utask = current->utask; if (!utask) { utask = add_utask(); /* Cannot allocate; re-execute the instruction. */ @@ -1547,13 +1544,12 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) } /* - * On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag. (and on - * subsequent probe hits on the thread sets the state to UTASK_BP_HIT) and - * allows the thread to return from interrupt. + * On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag and + * allows the thread to return from interrupt. After that handle_swbp() + * sets utask->active_uprobe. * - * On singlestep exception, singlestep notifier sets the TIF_UPROBE flag and - * also sets the state to UTASK_SSTEP_ACK and allows the thread to return from - * interrupt. + * On singlestep exception, singlestep notifier sets the TIF_UPROBE flag + * and allows the thread to return from interrupt. * * While returning to userspace, thread notices the TIF_UPROBE flag and calls * uprobe_notify_resume(). @@ -1563,10 +1559,10 @@ void uprobe_notify_resume(struct pt_regs *regs) struct uprobe_task *utask; utask = current->utask; - if (!utask || utask->state == UTASK_BP_HIT) - handle_swbp(regs); - else + if (utask && utask->active_uprobe) handle_singlestep(utask, regs); + else + handle_swbp(regs); } /* @@ -1575,17 +1571,10 @@ void uprobe_notify_resume(struct pt_regs *regs) */ int uprobe_pre_sstep_notifier(struct pt_regs *regs) { - struct uprobe_task *utask; - if (!current->mm || !test_bit(MMF_HAS_UPROBES, ¤t->mm->flags)) return 0; - utask = current->utask; - if (utask) - utask->state = UTASK_BP_HIT; - set_thread_flag(TIF_UPROBE); - return 1; } -- cgit v1.2.3 From db023ea595015058270be6a62fe60a7b6b5c50d7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 14 Sep 2012 19:05:46 +0200 Subject: uprobes: Move clear_thread_flag(TIF_UPROBE) to uprobe_notify_resume() Move clear_thread_flag(TIF_UPROBE) from do_notify_resume() to uprobe_notify_resume() for !CONFIG_UPROBES case. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- arch/x86/kernel/signal.c | 4 +--- kernel/events/uprobes.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index b280908a376e..0041e5a5293b 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -785,10 +785,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) mce_notify_process(); #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ - if (thread_info_flags & _TIF_UPROBE) { - clear_thread_flag(TIF_UPROBE); + if (thread_info_flags & _TIF_UPROBE) uprobe_notify_resume(regs); - } /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index d3f5381e7482..198d732ab901 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1558,6 +1558,8 @@ void uprobe_notify_resume(struct pt_regs *regs) { struct uprobe_task *utask; + clear_thread_flag(TIF_UPROBE); + utask = current->utask; if (utask && utask->active_uprobe) handle_singlestep(utask, regs); -- cgit v1.2.3 From 75ed82ea53bd0d2d8083261123576250f7ba851e Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 16 Sep 2012 17:20:06 +0200 Subject: uprobes: Change write_opcode() to use FOLL_FORCE write_opcode()->get_user_pages() needs FOLL_FORCE to ensure we can read the page even if the probed task did mprotect(PROT_NONE) after uprobe_register(). Without FOLL_WRITE, FOLL_FORCE doesn't have any side effect but allows to read the !VM_READ memory. Otherwiese the subsequent uprobe_unregister()->set_orig_insn() fails and we leak "int3". If that task does mprotect(PROT_READ | EXEC) and execute the probed insn later it will be killed. Note: in fact this is also needed for _register, see the next patch. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 198d732ab901..80e8c7b697b9 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -221,7 +221,7 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, retry: /* Read the page with vaddr into memory */ - ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); + ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma); if (ret <= 0) return ret; -- cgit v1.2.3 From 78a320542e6cdb2800cd736b2d136e4261d34f43 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 16 Sep 2012 19:07:41 +0200 Subject: uprobes: Change valid_vma() to demand VM_MAYEXEC rather than VM_EXEC uprobe_register() or uprobe_mmap() requires VM_READ | VM_EXEC, this is not right. An apllication can do mprotect(PROT_EXEC) later and execute this code. Change valid_vma(is_register => true) to check VM_MAYEXEC instead. No need to check VM_MAYREAD, it is always set. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 80e8c7b697b9..a9de40815391 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -106,8 +106,8 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register) if (!is_register) return true; - if ((vma->vm_flags & (VM_HUGETLB|VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) - == (VM_READ|VM_EXEC)) + if ((vma->vm_flags & (VM_HUGETLB | VM_WRITE | VM_MAYEXEC | VM_SHARED)) + == VM_MAYEXEC) return true; return false; -- cgit v1.2.3 From e40cfce626a5537994058ee9a940dcfdc0f68ef0 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 16 Sep 2012 19:31:39 +0200 Subject: uprobes: Restrict valid_vma(false) to skip VM_SHARED vmas valid_vma(false) ignores ->vm_flags, this is not actually right. We should never try to write into MAP_SHARED mapping, this can confuse an apllication which actually writes to ->vm_file. With this patch valid_vma(false) ignores VM_WRITE only but checks other (immutable) bits checked by valid_vma(true). This can also speedup uprobe_munmap() and uprobe_unregister(). Note: even after this patch _unregister can confuse the probed application if it does mprotect(PROT_WRITE) after _register and installs "int3", but this is hardly possible to avoid and this doesn't differ from gdb case. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index a9de40815391..8d182bdecc2e 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -100,17 +100,12 @@ struct uprobe { */ static bool valid_vma(struct vm_area_struct *vma, bool is_register) { - if (!vma->vm_file) - return false; - - if (!is_register) - return true; + vm_flags_t flags = VM_HUGETLB | VM_MAYEXEC | VM_SHARED; - if ((vma->vm_flags & (VM_HUGETLB | VM_WRITE | VM_MAYEXEC | VM_SHARED)) - == VM_MAYEXEC) - return true; + if (is_register) + flags |= VM_WRITE; - return false; + return vma->vm_file && (vma->vm_flags & flags) == VM_MAYEXEC; } static unsigned long offset_to_vaddr(struct vm_area_struct *vma, loff_t offset) -- cgit v1.2.3 From e97f65a17deafacc360a4cb75ae944897ecea6d7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 19 Sep 2012 16:36:01 +0200 Subject: uprobes: Kill set_swbp()->is_swbp_at_addr() A separate patch for better documentation. set_swbp()->is_swbp_at_addr() is not needed for correctness, it is harmless to do the unnecessary __replace_page(old_page, new_page) when these 2 pages are identical. And it can not be counted as optimization. mmap/register races are very unlikely, while in the likely case is_swbp_at_addr() adds the extra get_user_pages() even if the caller is uprobe_mmap(current->mm) and returns false. Note also that the semantics/usage of is_swbp_at_addr() in uprobe.c is confusing. set_swbp() uses it to detect the case when this insn was already modified by uprobes, that is why it should always compare the opcode with UPROBE_SWBP_INSN even if the hardware (like powerpc) has other trap insns. It doesn't matter if this breakpoint was in fact installed by gdb or application itself, we are going to "steal" this breakpoint anyway and execute the original insn from vm_file even if it no longer matches the memory. OTOH, handle_swbp()->find_active_uprobe() uses is_swbp_at_addr() to figure out whether we need to send SIGTRAP or not if we can not find uprobe, so in this case it should return true for all trap variants, not only for UPROBE_SWBP_INSN. This patch removes set_swbp()->is_swbp_at_addr(), the next patches will remove it from set_orig_insn() which is similar to set_swbp() in this respect. So the only caller will be handle_swbp() and we can make its semantics clear. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 8d182bdecc2e..a4453d1c8199 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -321,17 +321,6 @@ out: */ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) { - int result; - /* - * See the comment near uprobes_hash(). - */ - result = is_swbp_at_addr(mm, vaddr); - if (result == 1) - return 0; - - if (result) - return result; - return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); } -- cgit v1.2.3 From cceb55aab73d2aea8f4d6f7414d2e1b647a3dacb Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 23 Sep 2012 21:10:18 +0200 Subject: uprobes: Introduce copy_opcode(), kill read_opcode() No functional changes, preparations. 1. Extract the kmap-and-memcpy code from read_opcode() into the new trivial helper, copy_opcode(). The next patch will add another user. 2. read_opcode() becomes really trivial, fold it into its single caller, is_swbp_at_addr(). 3. Remove "auprobe" argument from write_opcode(), it is not used since f403072c6. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 63 +++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index a4453d1c8199..b6f0f716a884 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -183,19 +183,25 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn) return *insn == UPROBE_SWBP_INSN; } +static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode) +{ + void *kaddr = kmap_atomic(page); + memcpy(opcode, kaddr + (vaddr & ~PAGE_MASK), UPROBE_SWBP_INSN_SIZE); + kunmap_atomic(kaddr); +} + /* * NOTE: * Expect the breakpoint instruction to be the smallest size instruction for * the architecture. If an arch has variable length instruction and the * breakpoint instruction is not of the smallest length instruction - * supported by that architecture then we need to modify read_opcode / + * supported by that architecture then we need to modify is_swbp_at_addr and * write_opcode accordingly. This would never be a problem for archs that * have fixed length instructions. */ /* * write_opcode - write the opcode at a given virtual address. - * @auprobe: arch breakpointing information. * @mm: the probed process address space. * @vaddr: the virtual address to store the opcode. * @opcode: opcode to be written at @vaddr. @@ -206,8 +212,8 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn) * For mm @mm, write the opcode at @vaddr. * Return 0 (success) or a negative errno. */ -static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, - unsigned long vaddr, uprobe_opcode_t opcode) +static int write_opcode(struct mm_struct *mm, unsigned long vaddr, + uprobe_opcode_t opcode) { struct page *old_page, *new_page; void *vaddr_old, *vaddr_new; @@ -253,40 +259,9 @@ put_old: return ret; } -/** - * read_opcode - read the opcode at a given virtual address. - * @mm: the probed process address space. - * @vaddr: the virtual address to read the opcode. - * @opcode: location to store the read opcode. - * - * Called with mm->mmap_sem held (for read and with a reference to - * mm. - * - * For mm @mm, read the opcode at @vaddr and store it in @opcode. - * Return 0 (success) or a negative errno. - */ -static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode) -{ - struct page *page; - void *vaddr_new; - int ret; - - ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); - if (ret <= 0) - return ret; - - vaddr_new = kmap_atomic(page); - vaddr &= ~PAGE_MASK; - memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE); - kunmap_atomic(vaddr_new); - - put_page(page); - - return 0; -} - static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) { + struct page *page; uprobe_opcode_t opcode; int result; @@ -300,14 +275,14 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) goto out; } - result = read_opcode(mm, vaddr, &opcode); - if (result) + result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); + if (result < 0) return result; -out: - if (is_swbp_insn(&opcode)) - return 1; - return 0; + copy_opcode(page, vaddr, &opcode); + put_page(page); + out: + return is_swbp_insn(&opcode); } /** @@ -321,7 +296,7 @@ out: */ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) { - return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN); + return write_opcode(mm, vaddr, UPROBE_SWBP_INSN); } /** @@ -345,7 +320,7 @@ set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long v if (result != 1) return result; - return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); + return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); } static int match_uprobe(struct uprobe *l, struct uprobe *r) -- cgit v1.2.3 From ed6f6a50dc5f183c53e7b3b7fed4794bc50d9aa7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 23 Sep 2012 21:30:44 +0200 Subject: uprobes: Kill set_orig_insn()->is_swbp_at_addr() Unlike set_swbp(), set_orig_insn()->is_swbp_at_addr() makes sense, although it can't prevent all confusions. But the usage of is_swbp_at_addr() is equally confusing, and it adds the extra get_user_pages() we can avoid. This patch removes set_orig_insn()->is_swbp_at_addr() but changes write_opcode() to do the necessary checks before replace_page(). Perhaps it also makes sense to ensure PAGE_MAPPING_ANON in unregister case. find_active_uprobe() becomes the only user of is_swbp_at_addr(), we can change its semantics. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index b6f0f716a884..9248ee76b4bb 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -190,6 +190,25 @@ static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t kunmap_atomic(kaddr); } +static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *new_opcode) +{ + uprobe_opcode_t old_opcode; + bool is_swbp; + + copy_opcode(page, vaddr, &old_opcode); + is_swbp = is_swbp_insn(&old_opcode); + + if (is_swbp_insn(new_opcode)) { + if (is_swbp) /* register: already installed? */ + return 0; + } else { + if (!is_swbp) /* unregister: was it changed by us? */ + return -EINVAL; + } + + return 1; +} + /* * NOTE: * Expect the breakpoint instruction to be the smallest size instruction for @@ -226,6 +245,10 @@ retry: if (ret <= 0) return ret; + ret = verify_opcode(old_page, vaddr, &opcode); + if (ret <= 0) + goto put_old; + ret = -ENOMEM; new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); if (!new_page) @@ -311,15 +334,6 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned int __weak set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) { - int result; - - result = is_swbp_at_addr(mm, vaddr); - if (!result) - return -EINVAL; - - if (result != 1) - return result; - return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); } -- cgit v1.2.3 From ec75fba93ef0c00c91545b5e53841a80cffad0c4 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 23 Sep 2012 21:55:19 +0200 Subject: uprobes: Simplify is_swbp_at_addr(), remove stale comments After the previous change is_swbp_at_addr() is always called with current->mm. Remove this check and move it close to its single caller. Also, remove the obsolete comment about is_swbp_at_addr() and uprobe_state.count. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 73 ++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 49 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 9248ee76b4bb..6136854da6c6 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -282,32 +282,6 @@ put_old: return ret; } -static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) -{ - struct page *page; - uprobe_opcode_t opcode; - int result; - - if (current->mm == mm) { - pagefault_disable(); - result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr, - sizeof(opcode)); - pagefault_enable(); - - if (likely(result == 0)) - goto out; - } - - result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); - if (result < 0) - return result; - - copy_opcode(page, vaddr, &opcode); - put_page(page); - out: - return is_swbp_insn(&opcode); -} - /** * set_swbp - store breakpoint at a given address. * @auprobe: arch specific probepoint information. @@ -589,29 +563,6 @@ static int copy_insn(struct uprobe *uprobe, struct file *filp) return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); } -/* - * How mm->uprobes_state.count gets updated - * uprobe_mmap() increments the count if - * - it successfully adds a breakpoint. - * - it cannot add a breakpoint, but sees that there is a underlying - * breakpoint (via a is_swbp_at_addr()). - * - * uprobe_munmap() decrements the count if - * - it sees a underlying breakpoint, (via is_swbp_at_addr) - * (Subsequent uprobe_unregister wouldnt find the breakpoint - * unless a uprobe_mmap kicks in, since the old vma would be - * dropped just after uprobe_munmap.) - * - * uprobe_register increments the count if: - * - it successfully adds a breakpoint. - * - * uprobe_unregister decrements the count if: - * - it sees a underlying breakpoint and removes successfully. - * (via is_swbp_at_addr) - * (Subsequent uprobe_munmap wouldnt find the breakpoint - * since there is no underlying breakpoint after the - * breakpoint removal.) - */ static int install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long vaddr) @@ -1389,6 +1340,30 @@ static void mmf_recalc_uprobes(struct mm_struct *mm) clear_bit(MMF_HAS_UPROBES, &mm->flags); } +static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) +{ + struct page *page; + uprobe_opcode_t opcode; + int result; + + pagefault_disable(); + result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr, + sizeof(opcode)); + pagefault_enable(); + + if (likely(result == 0)) + goto out; + + result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); + if (result < 0) + return result; + + copy_opcode(page, vaddr, &opcode); + put_page(page); + out: + return is_swbp_insn(&opcode); +} + static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) { struct mm_struct *mm = current->mm; -- cgit v1.2.3 From 33766368f6532313571534f9112b1796d6651bbe Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 30 Sep 2012 19:47:40 +0300 Subject: mac80211: Fix FC masking in BIP AAD generation The bits used in the mask were off-by-one and ended up masking PwrMgt, MoreData, Protected fields instead of Retry, PwrMgt, MoreData. Fix this and to mask the correct fields. While doing so, convert the code to mask the full FC using IEEE80211_FCTL_* defines similarly to how CCMP AAD is built. Since BIP is used only with broadcast/multicast management frames, the Retry field is always 0 in these frames. The Protected field is also zero to maintain backwards compatibility. As such, the incorrect mask here does not really cause any problems for valid frames. In theory, an invalid BIP frame with Retry or Protected field set to 1 could be rejected because of BIP validation. However, no such frame should show up with standard compliant implementations, so this does not cause problems in normal BIP use. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg --- net/mac80211/wpa.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index bdb53aba888e..e58bf3fe3ed9 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -545,14 +545,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) static void bip_aad(struct sk_buff *skb, u8 *aad) { + __le16 mask_fc; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + /* BIP AAD: FC(masked) || A1 || A2 || A3 */ /* FC type/subtype */ - aad[0] = skb->data[0]; /* Mask FC Retry, PwrMgt, MoreData flags to zero */ - aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6)); + mask_fc = hdr->frame_control; + mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM | + IEEE80211_FCTL_MOREDATA); + put_unaligned(mask_fc, (__le16 *) &aad[0]); /* A1 || A2 || A3 */ - memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN); + memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN); } -- cgit v1.2.3 From 1396adc3c2bdc556d4cdd1cf107aa0b6d59fbb1e Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 1 Oct 2012 14:34:42 -0700 Subject: x86, suspend: Correct the restore of CR4, EFER; skip computing EFLAGS.ID The patch: 73201dbe x86, suspend: On wakeup always initialize cr4 and EFER ... was incorrectly committed in an intermediate (unfinished) form. - We need to test CF, not ZF, for a bit test with btl. - We don't actually need to compute the existence of EFLAGS.ID, since we set a flag at suspend time if CR4 should be restored. Signed-off-by: H. Peter Anvin Cc: Rafael J. Wysocki Link: http://lkml.kernel.org/r/1348529239-17943-1-git-send-email-hpa@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/realmode/rm/wakeup_asm.S | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S index e56479e58053..9e7e14797a72 100644 --- a/arch/x86/realmode/rm/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup_asm.S @@ -74,18 +74,9 @@ ENTRY(wakeup_start) lidtl wakeup_idt - /* Clear the EFLAGS but remember if we have EFLAGS.ID */ - movl $X86_EFLAGS_ID, %ecx - pushl %ecx - popfl - pushfl - popl %edi + /* Clear the EFLAGS */ pushl $0 popfl - pushfl - popl %edx - xorl %edx, %edi - andl %ecx, %edi /* %edi is zero iff CPUID & %cr4 are missing */ /* Check header signature... */ movl signature, %eax @@ -120,12 +111,12 @@ ENTRY(wakeup_start) movl %eax, %cr3 btl $WAKEUP_BEHAVIOR_RESTORE_CR4, %edi - jz 1f + jnc 1f movl pmode_cr4, %eax movl %eax, %cr4 1: btl $WAKEUP_BEHAVIOR_RESTORE_EFER, %edi - jz 1f + jnc 1f movl pmode_efer, %eax movl pmode_efer + 4, %edx movl $MSR_EFER, %ecx -- cgit v1.2.3 From fcd8af585f587741c051f7124b8dee6c73c8629b Mon Sep 17 00:00:00 2001 From: David Hooper Date: Tue, 2 Oct 2012 15:26:53 +0100 Subject: x86/reboot: Remove quirk entry for SBC FITPC Remove the quirk for the SBC FITPC. It seems ot have been required when the default was kbd reboot, but no longer required now that the default is acpi reboot. Furthermore, BIOS reboot no longer works for this board as of 2.6.39 or any of the 3.x kernels. Signed-off-by: David Hooper Signed-off-by: Alan Cox Link: http://lkml.kernel.org/r/20121002142635.17403.59959.stgit@localhost.localdomain Signed-off-by: Ingo Molnar --- arch/x86/kernel/reboot.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 52190a938b4a..4e8ba39eaf0f 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -358,14 +358,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), }, }, - { /* Handle problems with rebooting on CompuLab SBC-FITPC2 */ - .callback = set_bios_reboot, - .ident = "CompuLab SBC-FITPC2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "CompuLab"), - DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"), - }, - }, { /* Handle problems with rebooting on ASUS P4S800 */ .callback = set_bios_reboot, .ident = "ASUS P4S800", -- cgit v1.2.3 From 961c79761dda351b5fb263a0654b98daac130b7a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Oct 2012 11:34:09 +0300 Subject: x86/cache_info: Use ARRAY_SIZE() in amd_l3_attrs() Using ARRAY_SIZE() is more readable. Signed-off-by: Dan Carpenter Reviewed-by: Srivatsa S. Bhat Cc: Shai Fultheim Cc: Greg Kroah-Hartman Cc: Andreas Herrmann Link: http://lkml.kernel.org/r/20121002083409.GM12398@elgon.mountain Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/intel_cacheinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 9a7c90d80bc4..93c5451bdd52 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -991,7 +991,7 @@ static struct attribute ** __cpuinit amd_l3_attrs(void) if (attrs) return attrs; - n = sizeof (default_attrs) / sizeof (struct attribute *); + n = ARRAY_SIZE(default_attrs); if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) n += 2; -- cgit v1.2.3 From 07ac2296fb24e40ba8271a08167b588f4bbbe90c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Oct 2012 14:15:02 +0300 Subject: ASoC: twl6040: Fix Stream DAPM mapping Fixes commit: 805238b ASoC: twl6040: Convert to use DAI DAPM widgets where the connection between the stream widgets and the ADC widgets was reversed and because of this on capture the DAPM is not powering up the codec. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl6040.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index e8f97af75928..00b85cc1b9a3 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -820,10 +820,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"VIBRA DAC", NULL, "Vibra Playback"}, /* ADC -> Stream mapping */ - {"ADC Left", NULL, "Legacy Capture"}, - {"ADC Left", NULL, "Capture"}, - {"ADC Right", NULL, "Legacy Capture"}, - {"ADC Right", NULL, "Capture"}, + {"Legacy Capture" , NULL, "ADC Left"}, + {"Capture", NULL, "ADC Left"}, + {"Legacy Capture", NULL, "ADC Right"}, + {"Capture" , NULL, "ADC Right"}, /* Capture path */ {"Analog Left Capture Route", "Headset Mic", "HSMIC"}, -- cgit v1.2.3 From 034940a6b3afbe79022ab6922dd9d2982b78e6d5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 2 Oct 2012 15:31:16 +0300 Subject: ASoC: omap-abe-twl6040: Fix typo of Vibrator It is not Vinrator but Vibrator. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-abe-twl6040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c index be525dfe9faa..750d595d01d7 100644 --- a/sound/soc/omap/omap-abe-twl6040.c +++ b/sound/soc/omap/omap-abe-twl6040.c @@ -220,7 +220,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk"); twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk"); twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out"); - twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator"); + twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator"); twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic"); twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic"); twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic"); -- cgit v1.2.3 From 07b706dc9e92f030cfca330879aa8b7ecbb7b79a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 4 Oct 2012 11:27:15 +0300 Subject: ASoC: Fix wrong include for McPDM McPDM needs platt/cpu.h for omap_rev and not omap_hwmod.h. Drivers must not include omap_hwmod.h at, it will be private to mach-omap2 soon. Fix the problem before other drivers will also start including omap_hwmod.h. Note that also plat/cpu.h will be going away, so the omap_rev check needs to be replaced with mcpdm-watchdog flag from platform_data or DT. Signed-off-by: Tony Lindgren Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index 775565032ce3..fdf655e3f1b3 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include "omap-mcpdm.h" #include "omap-pcm.h" -- cgit v1.2.3 From 68214d998a2e3102854cf10ebe505243035702fc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 4 Oct 2012 11:27:16 +0300 Subject: ASoC: omap-mcpdm: Remove OMAP revision check The OMAP revision check is not needed since the watchdog bit is not in use on 4430 ES1.0 and have no effect when we set the bit. The watchdog need to be enabled on all other revisions. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcpdm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index fdf655e3f1b3..e134b271a70a 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c @@ -40,7 +40,6 @@ #include #include -#include #include "omap-mcpdm.h" #include "omap-pcm.h" @@ -258,13 +257,9 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, mutex_lock(&mcpdm->mutex); if (!dai->active) { - /* Enable watch dog for ES above ES 1.0 to avoid saturation */ - if (omap_rev() != OMAP4430_REV_ES1_0) { - u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); + u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); - omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, - ctrl | MCPDM_WD_EN); - } + omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); omap_mcpdm_open_streams(mcpdm); } mutex_unlock(&mcpdm->mutex); -- cgit v1.2.3 From b764de2d8bafff3a52aa6ee66cedf435486974f4 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 3 Oct 2012 12:46:57 +0200 Subject: ASoC: ams-delta: Convert to use snd_soc_register_card() The old method of registering with the ASoC core by creating a "soc-audio" platform device no longer works for Amstrad Delta sound card after recent changes to drvdata handling (commit 0998d0631001288a5974afc0b2a5f568bcdecb4d, 'device-core: Ensure drvdata = NULL when no driver is bound'. Use snd_soc_register_card() method instead, as suggested by the ASoC core generated warning message, and move both the card and codec platform device registration to the arch board file where those belong. Created and tested against linux-3.6-rc5. Signed-off-by: Janusz Krzysztofik Acked-by: Tony Lindgren Signed-off-by: Mark Brown --- arch/arm/mach-omap1/board-ams-delta.c | 12 +++++++ sound/soc/omap/ams-delta.c | 63 +++++++++++++++++------------------ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index c53469802c03..5ab9c6bdce84 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -444,16 +444,28 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = { .lclk_khz_max = 1334, /* results in 5fps CIF, 10fps QCIF */ }; +static struct platform_device ams_delta_audio_device = { + .name = "ams-delta-audio", + .id = -1, +}; + +static struct platform_device cx20442_codec_device = { + .name = "cx20442-codec", + .id = -1, +}; + static struct platform_device *ams_delta_devices[] __initdata = { &latch1_gpio_device, &latch2_gpio_device, &ams_delta_kp_device, &ams_delta_camera_device, + &ams_delta_audio_device, }; static struct platform_device *late_devices[] __initdata = { &ams_delta_nand_device, &ams_delta_lcd_device, + &cx20442_codec_device, }; static void __init ams_delta_init(void) diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 7d4fa8ed6699..7b18b748c177 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -575,56 +575,53 @@ static struct snd_soc_card ams_delta_audio_card = { }; /* Module init/exit */ -static struct platform_device *ams_delta_audio_platform_device; -static struct platform_device *cx20442_platform_device; - -static int __init ams_delta_module_init(void) +static __devinit int ams_delta_probe(struct platform_device *pdev) { + struct snd_soc_card *card = &ams_delta_audio_card; int ret; - if (!(machine_is_ams_delta())) - return -ENODEV; - - ams_delta_audio_platform_device = - platform_device_alloc("soc-audio", -1); - if (!ams_delta_audio_platform_device) - return -ENOMEM; + card->dev = &pdev->dev; - platform_set_drvdata(ams_delta_audio_platform_device, - &ams_delta_audio_card); - - ret = platform_device_add(ams_delta_audio_platform_device); - if (ret) - goto err; - - /* - * Codec platform device could be registered from elsewhere (board?), - * but I do it here as it makes sense only if used with the card. - */ - cx20442_platform_device = - platform_device_register_simple("cx20442-codec", -1, NULL, 0); + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + card->dev = NULL; + return ret; + } return 0; -err: - platform_device_put(ams_delta_audio_platform_device); - return ret; } -late_initcall(ams_delta_module_init); -static void __exit ams_delta_module_exit(void) +static int __devexit ams_delta_remove(struct platform_device *pdev) { + struct snd_soc_card *card = platform_get_drvdata(pdev); + if (tty_unregister_ldisc(N_V253) != 0) - dev_warn(&ams_delta_audio_platform_device->dev, + dev_warn(&pdev->dev, "failed to unregister V253 line discipline\n"); snd_soc_jack_free_gpios(&ams_delta_hook_switch, ARRAY_SIZE(ams_delta_hook_switch_gpios), ams_delta_hook_switch_gpios); - platform_device_unregister(cx20442_platform_device); - platform_device_unregister(ams_delta_audio_platform_device); + snd_soc_unregister_card(card); + card->dev = NULL; + return 0; } -module_exit(ams_delta_module_exit); + +#define DRV_NAME "ams-delta-audio" + +static struct platform_driver ams_delta_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ams_delta_probe, + .remove = __devexit_p(ams_delta_remove), +}; + +module_platform_driver(ams_delta_driver); MODULE_AUTHOR("Janusz Krzysztofik "); MODULE_DESCRIPTION("ALSA SoC driver for Amstrad E3 (Delta) videophone"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From eac77839f9707c4813344bef64e8b62d128236dd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Sep 2012 16:22:32 +0100 Subject: ASoC: bells: Correct typo in sub speaker DAI name for WM5110 Signed-off-by: Mark Brown --- sound/soc/samsung/bells.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 5dc10dfc0d42..a2ca1567b9e4 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -247,7 +247,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { { .name = "Sub", .stream_name = "Sub", - .cpu_dai_name = "wm5102-aif3", + .cpu_dai_name = "wm5110-aif3", .codec_dai_name = "wm9081-hifi", .codec_name = "wm9081.1-006c", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -- cgit v1.2.3 From 5ae9eb4cbdfd640269dbd66aa3c92ea8e11cc838 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 12:02:48 +0100 Subject: ASoC: wm2200: Use rev A register patches on rev B Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/wm2200.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index efa93dbb0191..2008b7b533bb 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2091,6 +2091,7 @@ static __devinit int wm2200_i2c_probe(struct i2c_client *i2c, switch (wm2200->rev) { case 0: + case 1: ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch, ARRAY_SIZE(wm2200_reva_patch)); if (ret != 0) { -- cgit v1.2.3 From a1b98e12b7f8fad2f0aa3c08a3302bcac7ae1ec7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Oct 2012 19:10:43 +0100 Subject: ASoC: wm2200: Fix non-inverted OUT2 mute control Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/wm2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 2008b7b533bb..eab64a193989 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1028,7 +1028,7 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L, WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0, digital_tlv), SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT, - WM2200_SPK1R_MUTE_SHIFT, 1, 0), + WM2200_SPK1R_MUTE_SHIFT, 1, 1), }; WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE); -- cgit v1.2.3 From 60d4616f3dc63371b3dc367e5e88fd4b4f037f65 Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Fri, 5 Oct 2012 11:32:02 -0400 Subject: ext4: serialize fallocate with ext4_convert_unwritten_extents Fallocate should wait for pended ext4_convert_unwritten_extents() otherwise following race may happen: ftruncate( ,12288); fallocate( ,0, 4096) io_sibmit( ,0, 4096); /* Write to fallocated area, split extent if needed */ fallocate( ,0, 8192); /* Grow extent and broke assumption about extent */ Later kwork completion will do: ->ext4_convert_unwritten_extents (0, 4096) ->ext4_map_blocks(handle, inode, &map, EXT4_GET_BLOCKS_IO_CONVERT_EXT); ->ext4_ext_map_blocks() /* Will find new extent: ex = [0,2] !!!!!! */ ->ext4_ext_handle_uninitialized_extents() ->ext4_convert_unwritten_extents_endio() /* convert [0,2] extent to initialized, but only[0,1] was written */ Signed-off-by: Dmitry Monakhov Signed-off-by: "Theodore Ts'o" --- fs/ext4/extents.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 1c94cca35ed1..c2789271e7b4 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4428,6 +4428,9 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) */ if (len <= EXT_UNINIT_MAX_LEN << blkbits) flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; + + /* Prevent race condition between unwritten */ + ext4_flush_unwritten_io(inode); retry: while (ret >= 0 && ret < max_blocks) { map.m_lblk = map.m_lblk + ret; -- cgit v1.2.3 From 6f5601251d7e306b8a7bf5e674c5307d865c0fa1 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 4 Oct 2012 20:01:21 -0400 Subject: net, TTY: initialize tty->driver_data before usage Commit 9c650ffc ("TTY: ircomm_tty, add tty install") split _open() to _install() and _open(). It also moved the initialization of driver_data out of open(), but never added it to install() - causing a NULL ptr deref whenever the driver was used. Signed-off-by: Sasha Levin Acked-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- net/irda/ircomm/ircomm_tty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 95a3a7a336ba..496ce2cebcd7 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -421,6 +421,8 @@ static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); } + tty->driver_data = self; + return tty_port_install(&self->port, driver, tty); } -- cgit v1.2.3 From 2351a6c6e7d5a5e848411b5dd2c02142497624cc Mon Sep 17 00:00:00 2001 From: Markus Trippelsdorf Date: Fri, 5 Oct 2012 14:57:17 +0200 Subject: tty: Fix bogus "callbacks suppressed" messages On the current git tree one sees messages such as: tty_init_dev: 24 callbacks suppressed tty_init_dev: 3 callbacks suppressed To fix this we need to look at condition before calling __ratelimit in the WARN_RATELIMIT macro. While at it remove the superfluous __WARN_RATELIMIT macros. Original patch is from Joe Perches and Jiri Slaby. Signed-off-by: Markus Trippelsdorf Acked-and-tested-by: Borislav Petkov Signed-off-by: Greg Kroah-Hartman --- include/linux/ratelimit.h | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h index e11ccb4cf48d..0a260d8a18bf 100644 --- a/include/linux/ratelimit.h +++ b/include/linux/ratelimit.h @@ -46,20 +46,17 @@ extern int ___ratelimit(struct ratelimit_state *rs, const char *func); #define WARN_ON_RATELIMIT(condition, state) \ WARN_ON((condition) && __ratelimit(state)) -#define __WARN_RATELIMIT(condition, state, format...) \ -({ \ - int rtn = 0; \ - if (unlikely(__ratelimit(state))) \ - rtn = WARN(condition, format); \ - rtn; \ -}) - -#define WARN_RATELIMIT(condition, format...) \ +#define WARN_RATELIMIT(condition, format, ...) \ ({ \ static DEFINE_RATELIMIT_STATE(_rs, \ DEFAULT_RATELIMIT_INTERVAL, \ DEFAULT_RATELIMIT_BURST); \ - __WARN_RATELIMIT(condition, &_rs, format); \ + int rtn = !!(condition); \ + \ + if (unlikely(rtn && __ratelimit(&_rs))) \ + WARN(rtn, format, ##__VA_ARGS__); \ + \ + rtn; \ }) #else @@ -67,15 +64,9 @@ extern int ___ratelimit(struct ratelimit_state *rs, const char *func); #define WARN_ON_RATELIMIT(condition, state) \ WARN_ON(condition) -#define __WARN_RATELIMIT(condition, state, format...) \ -({ \ - int rtn = WARN(condition, format); \ - rtn; \ -}) - -#define WARN_RATELIMIT(condition, format...) \ +#define WARN_RATELIMIT(condition, format, ...) \ ({ \ - int rtn = WARN(condition, format); \ + int rtn = WARN(condition, format, ##__VA_ARGS__); \ rtn; \ }) -- cgit v1.2.3 From 725dd00a99dd5fb94af55115bf7ade59624c8bc3 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 30 Sep 2012 13:19:19 +0400 Subject: serial: sccnxp: Allows the driver to be compiled as a module Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 233fbaaf2559..2a53be5f010d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1150,7 +1150,7 @@ config SERIAL_SC26XX_CONSOLE Support for Console on SC2681/SC2692 serial ports. config SERIAL_SCCNXP - bool "SCCNXP serial port support" + tristate "SCCNXP serial port support" depends on !SERIAL_SC26XX select SERIAL_CORE default n @@ -1162,7 +1162,7 @@ config SERIAL_SCCNXP config SERIAL_SCCNXP_CONSOLE bool "Console on SCCNXP serial port" - depends on SERIAL_SCCNXP + depends on SERIAL_SCCNXP=y select SERIAL_CORE_CONSOLE help Support for console on SCCNXP serial ports. -- cgit v1.2.3 From ee98581f624a6ce0f17706d7ff2a161aacfb977a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 Sep 2012 20:38:26 +0200 Subject: staging: serial: dgrp: Add missing #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On m68k: drivers/staging/dgrp/dgrp_mon_ops.c: In function ‘dgrp_mon_read’: drivers/staging/dgrp/dgrp_mon_ops.c:304: error: implicit declaration of function ‘copy_to_user’ drivers/staging/dgrp/dgrp_specproc.c: In function ‘config_proc_write’: drivers/staging/dgrp/dgrp_specproc.c:470: error: implicit declaration of function ‘copy_from_user’ drivers/staging/dgrp/dgrp_tty.c: In function ‘drp_wmove’: drivers/staging/dgrp/dgrp_tty.c:1284: error: implicit declaration of function ‘copy_from_user’ drivers/staging/dgrp/dgrp_tty.c: In function ‘get_modem_info’: drivers/staging/dgrp/dgrp_tty.c:2267: error: implicit declaration of function ‘put_user’ drivers/staging/dgrp/dgrp_tty.c: In function ‘set_modem_info’: drivers/staging/dgrp/dgrp_tty.c:2283: error: implicit declaration of function ‘access_ok’ drivers/staging/dgrp/dgrp_tty.c:2283: error: ‘VERIFY_READ’ undeclared (first use in this function) drivers/staging/dgrp/dgrp_tty.c:2283: error: (Each undeclared identifier is reported only once drivers/staging/dgrp/dgrp_tty.c:2283: error: for each function it appears in.) drivers/staging/dgrp/dgrp_tty.c:2287: error: implicit declaration of function ‘get_user’ drivers/staging/dgrp/dgrp_tty.c: In function ‘dgrp_tty_digigetedelay’: drivers/staging/dgrp/dgrp_tty.c:2474: error: implicit declaration of function ‘copy_to_user’ drivers/staging/dgrp/dgrp_tty.c: In function ‘dgrp_tty_ioctl’: drivers/staging/dgrp/dgrp_tty.c:2618: error: ‘VERIFY_WRITE’ undeclared (first use in this function) Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgrp/dgrp_mon_ops.c | 1 + drivers/staging/dgrp/dgrp_specproc.c | 1 + drivers/staging/dgrp/dgrp_tty.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/staging/dgrp/dgrp_mon_ops.c b/drivers/staging/dgrp/dgrp_mon_ops.c index 268dcb95204b..4792d056a365 100644 --- a/drivers/staging/dgrp/dgrp_mon_ops.c +++ b/drivers/staging/dgrp/dgrp_mon_ops.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "dgrp_common.h" diff --git a/drivers/staging/dgrp/dgrp_specproc.c b/drivers/staging/dgrp/dgrp_specproc.c index 28f5c9ab6b43..a5840e7d6665 100644 --- a/drivers/staging/dgrp/dgrp_specproc.c +++ b/drivers/staging/dgrp/dgrp_specproc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "dgrp_common.h" diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c index 7d7de873870c..72f6fcfa9878 100644 --- a/drivers/staging/dgrp/dgrp_tty.c +++ b/drivers/staging/dgrp/dgrp_tty.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "dgrp_common.h" -- cgit v1.2.3 From b70936d9ffbf0f45f4fa13a03122f015f13ecdb0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 5 Oct 2012 09:34:37 -0700 Subject: tty: serial: sccnxp: Fix bug with unterminated platform_id list The build even tells you that this is a bad thing: drivers/tty/serial/sccnxp: struct platform_device_id is 32 bytes. The last of 8 is: 0x73 0x63 0x36 0x38 0x36 0x39 0x32 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x54 0x0c 0x01 0x00 0x00 0x00 0x00 0x00 FATAL: drivers/tty/serial/sccnxp: struct platform_device_id is not terminated with a NULL entry! So fix this problem up before someone oopses their box when loading the driver, as this breaks the build. Cc: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sccnxp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index b7086d004f5f..e821068cd95b 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -971,6 +971,7 @@ static const struct platform_device_id sccnxp_id_table[] = { { "sc28202", SCCNXP_TYPE_SC28202 }, { "sc68681", SCCNXP_TYPE_SC68681 }, { "sc68692", SCCNXP_TYPE_SC68692 }, + { }, }; MODULE_DEVICE_TABLE(platform, sccnxp_id_table); -- cgit v1.2.3 From b64b9c937a533f0bfbfc9f6ac93d3c3e2f97ab02 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 29 Sep 2012 21:31:08 +0200 Subject: uprobes/x86: Only rep+nop can be emulated correctly __skip_sstep() correctly detects the "nontrivial" nop insns, but since it doesn't update regs->ip we can not really skip "0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0", the probed application is killed by SIGILL'ed handle_swbp(). Remove these additional checks. If we want to implement this correctly we need to know the full insn length to update ->ip. rep* + nop is fine even without updating ->ip. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- arch/x86/kernel/uprobes.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 9538f00827a9..aafa5557b396 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -651,31 +651,19 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) /* * Skip these instructions as per the currently known x86 ISA. - * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } + * rep=0x66*; nop=0x90 */ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { int i; for (i = 0; i < MAX_UINSN_BYTES; i++) { - if ((auprobe->insn[i] == 0x66)) + if (auprobe->insn[i] == 0x66) continue; if (auprobe->insn[i] == 0x90) return true; - if (i == (MAX_UINSN_BYTES - 1)) - break; - - if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f)) - return true; - - if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x19)) - return true; - - if ((auprobe->insn[i] == 0x87) && (auprobe->insn[i+1] == 0xc0)) - return true; - break; } return false; -- cgit v1.2.3 From a5f658b71bc622b731961ea3addcf146ed3c599f Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 30 Sep 2012 18:21:09 +0200 Subject: uprobes: Don't return success if alloc_uprobe() fails If alloc_uprobe() fails uprobe_register() should return ENOMEM, not 0. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 6136854da6c6..588a5575d64c 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -813,7 +813,9 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * mutex_lock(uprobes_hash(inode)); uprobe = alloc_uprobe(inode, offset); - if (uprobe && !consumer_add(uprobe, uc)) { + if (!uprobe) { + ret = -ENOMEM; + } else if (!consumer_add(uprobe, uc)) { ret = __uprobe_register(uprobe); if (ret) { uprobe->consumers = NULL; -- cgit v1.2.3 From 076a365b3da99b68c5d58e394714d0611f1fa002 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 30 Sep 2012 18:54:53 +0200 Subject: uprobes: Do not delete uprobe if uprobe_unregister() fails delete_uprobe() must not be called if register_for_each_vma(false) fails to remove all breakpoints, __uprobe_unregister() is correct. The problem is that register_for_each_vma(false) always returns 0 and thus this logic does not work. 1. Change verify_opcode() to return 0 rather than -EINVAL when unregister detects the !is_swbp insn, we can treat this case as success and currently unregister paths ignore the error code anyway. 2. Change remove_breakpoint() to propagate the error code from write_opcode(). 3. Change register_for_each_vma(is_register => false) to remove as much breakpoints as possible but return non-zero if remove_breakpoint() fails at least once. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 588a5575d64c..a1b466d17c17 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -203,7 +203,7 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t return 0; } else { if (!is_swbp) /* unregister: was it changed by us? */ - return -EINVAL; + return 0; } return 1; @@ -616,15 +616,15 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, return ret; } -static void +static int remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) { /* can happen if uprobe_register() fails */ if (!test_bit(MMF_HAS_UPROBES, &mm->flags)) - return; + return 0; set_bit(MMF_RECALC_UPROBES, &mm->flags); - set_orig_insn(&uprobe->arch, mm, vaddr); + return set_orig_insn(&uprobe->arch, mm, vaddr); } /* @@ -740,7 +740,7 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) struct mm_struct *mm = info->mm; struct vm_area_struct *vma; - if (err) + if (err && is_register) goto free; down_write(&mm->mmap_sem); @@ -756,7 +756,7 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) if (is_register) err = install_breakpoint(uprobe, mm, vma, info->vaddr); else - remove_breakpoint(uprobe, mm, info->vaddr); + err |= remove_breakpoint(uprobe, mm, info->vaddr); unlock: up_write(&mm->mmap_sem); -- cgit v1.2.3 From 142b18ddc81439acda4bc4231b291e99fe67d507 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 29 Sep 2012 21:56:57 +0200 Subject: uprobes: Fix handle_swbp() vs unregister() + register() race Strictly speaking this race was added by me in 56bb4cf6. However I think that this bug is just another indication that we should move copy_insn/uprobe_analyze_insn code from install_breakpoint() to uprobe_register(), there are a lot of other reasons for that. Until then, add a hack to close the race. A task can hit uprobe U1, but before it calls find_uprobe() this uprobe can be unregistered *AND* another uprobe U2 can be added to uprobes_tree at the same inode/offset. In this case handle_swbp() will use the not-fully-initialized U2, in particular its arch.insn for xol. Add the additional !UPROBE_COPY_INSN check into handle_swbp(), if this flag is not set we simply restart as if the new uprobe was not inserted yet. This is not very nice, we need barriers, but we will remove this hack when we change uprobe_register(). Note: with or without this patch install_breakpoint() can race with itself, yet another reson to kill UPROBE_COPY_INSN altogether. And even the usage of uprobe->flags is not safe. See the next patches. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- kernel/events/uprobes.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.