aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-09-23 15:30:44 -0400
committerOleg Nesterov <oleg@redhat.com>2012-09-29 15:21:54 -0400
commited6f6a50dc5f183c53e7b3b7fed4794bc50d9aa7 (patch)
tree8ef3472db708804bb292a79752d0b04de8f2060d /kernel
parentcceb55aab73d2aea8f4d6f7414d2e1b647a3dacb (diff)
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 <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/uprobes.c32
1 files 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
190 kunmap_atomic(kaddr); 190 kunmap_atomic(kaddr);
191} 191}
192 192
193static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *new_opcode)
194{
195 uprobe_opcode_t old_opcode;
196 bool is_swbp;
197
198 copy_opcode(page, vaddr, &old_opcode);
199 is_swbp = is_swbp_insn(&old_opcode);
200
201 if (is_swbp_insn(new_opcode)) {
202 if (is_swbp) /* register: already installed? */
203 return 0;
204 } else {
205 if (!is_swbp) /* unregister: was it changed by us? */
206 return -EINVAL;
207 }
208
209 return 1;
210}
211
193/* 212/*
194 * NOTE: 213 * NOTE:
195 * Expect the breakpoint instruction to be the smallest size instruction for 214 * Expect the breakpoint instruction to be the smallest size instruction for
@@ -226,6 +245,10 @@ retry:
226 if (ret <= 0) 245 if (ret <= 0)
227 return ret; 246 return ret;
228 247
248 ret = verify_opcode(old_page, vaddr, &opcode);
249 if (ret <= 0)
250 goto put_old;
251
229 ret = -ENOMEM; 252 ret = -ENOMEM;
230 new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); 253 new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
231 if (!new_page) 254 if (!new_page)
@@ -311,15 +334,6 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned
311int __weak 334int __weak
312set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) 335set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
313{ 336{
314 int result;
315
316 result = is_swbp_at_addr(mm, vaddr);
317 if (!result)
318 return -EINVAL;
319
320 if (result != 1)
321 return result;
322
323 return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); 337 return write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
324} 338}
325 339