diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-07-08 19:00:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 13:33:25 -0400 |
commit | 6961ed96f14463d7c6e38d8c2093f5d53bd70574 (patch) | |
tree | 210e317714fbee7abbe81f16f607693b00286364 /arch/powerpc | |
parent | 02be46fba4b154b4a201a729b2d2b4ff6affd031 (diff) |
ptrace/powerpc: revert "hw_breakpoints: Fix racy access to ptrace breakpoints"
This reverts commit 07fa7a0a8a58 ("hw_breakpoints: Fix racy access to
ptrace breakpoints") and removes ptrace_get/put_breakpoints() added by
other commits.
The patch was fine but we can no longer race with SIGKILL after commit
9899d11f6544 ("ptrace: ensure arch_ptrace/ptrace_request can never race
with SIGKILL"), the __TASK_TRACED tracee can't be woken up and
->ptrace_bps[] can't go away.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Michael Neuling <mikey@neuling.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jan Kratochvil <jan.kratochvil@redhat.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Prasad <prasad@linux.vnet.ibm.com>
Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 30 |
1 files changed, 4 insertions, 26 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 64f7bd5b1b0f..9a0d24c390a3 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -975,16 +975,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
975 | hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL; | 975 | hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL; |
976 | hw_brk.len = 8; | 976 | hw_brk.len = 8; |
977 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 977 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
978 | if (ptrace_get_breakpoints(task) < 0) | ||
979 | return -ESRCH; | ||
980 | |||
981 | bp = thread->ptrace_bps[0]; | 978 | bp = thread->ptrace_bps[0]; |
982 | if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) { | 979 | if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) { |
983 | if (bp) { | 980 | if (bp) { |
984 | unregister_hw_breakpoint(bp); | 981 | unregister_hw_breakpoint(bp); |
985 | thread->ptrace_bps[0] = NULL; | 982 | thread->ptrace_bps[0] = NULL; |
986 | } | 983 | } |
987 | ptrace_put_breakpoints(task); | ||
988 | return 0; | 984 | return 0; |
989 | } | 985 | } |
990 | if (bp) { | 986 | if (bp) { |
@@ -997,11 +993,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
997 | 993 | ||
998 | ret = modify_user_hw_breakpoint(bp, &attr); | 994 | ret = modify_user_hw_breakpoint(bp, &attr); |
999 | if (ret) { | 995 | if (ret) { |
1000 | ptrace_put_breakpoints(task); | ||
1001 | return ret; | 996 | return ret; |
1002 | } | 997 | } |
1003 | thread->ptrace_bps[0] = bp; | 998 | thread->ptrace_bps[0] = bp; |
1004 | ptrace_put_breakpoints(task); | ||
1005 | thread->hw_brk = hw_brk; | 999 | thread->hw_brk = hw_brk; |
1006 | return 0; | 1000 | return 0; |
1007 | } | 1001 | } |
@@ -1016,12 +1010,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
1016 | ptrace_triggered, NULL, task); | 1010 | ptrace_triggered, NULL, task); |
1017 | if (IS_ERR(bp)) { | 1011 | if (IS_ERR(bp)) { |
1018 | thread->ptrace_bps[0] = NULL; | 1012 | thread->ptrace_bps[0] = NULL; |
1019 | ptrace_put_breakpoints(task); | ||
1020 | return PTR_ERR(bp); | 1013 | return PTR_ERR(bp); |
1021 | } | 1014 | } |
1022 | 1015 | ||
1023 | ptrace_put_breakpoints(task); | ||
1024 | |||
1025 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 1016 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
1026 | task->thread.hw_brk = hw_brk; | 1017 | task->thread.hw_brk = hw_brk; |
1027 | #else /* CONFIG_PPC_ADV_DEBUG_REGS */ | 1018 | #else /* CONFIG_PPC_ADV_DEBUG_REGS */ |
@@ -1440,26 +1431,19 @@ static long ppc_set_hwdebug(struct task_struct *child, | |||
1440 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) | 1431 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) |
1441 | brk.type |= HW_BRK_TYPE_WRITE; | 1432 | brk.type |= HW_BRK_TYPE_WRITE; |
1442 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 1433 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
1443 | if (ptrace_get_breakpoints(child) < 0) | ||
1444 | return -ESRCH; | ||
1445 | |||
1446 | /* | 1434 | /* |
1447 | * Check if the request is for 'range' breakpoints. We can | 1435 | * Check if the request is for 'range' breakpoints. We can |
1448 | * support it if range < 8 bytes. | 1436 | * support it if range < 8 bytes. |
1449 | */ | 1437 | */ |
1450 | if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) { | 1438 | if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) |
1451 | len = bp_info->addr2 - bp_info->addr; | 1439 | len = bp_info->addr2 - bp_info->addr; |
1452 | } else if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT) | 1440 | else if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT) |
1453 | len = 1; | 1441 | len = 1; |
1454 | else { | 1442 | else |
1455 | ptrace_put_breakpoints(child); | ||
1456 | return -EINVAL; | 1443 | return -EINVAL; |
1457 | } | ||
1458 | bp = thread->ptrace_bps[0]; | 1444 | bp = thread->ptrace_bps[0]; |
1459 | if (bp) { | 1445 | if (bp) |
1460 | ptrace_put_breakpoints(child); | ||
1461 | return -ENOSPC; | 1446 | return -ENOSPC; |
1462 | } | ||
1463 | 1447 | ||
1464 | /* Create a new breakpoint request if one doesn't exist already */ | 1448 | /* Create a new breakpoint request if one doesn't exist already */ |
1465 | hw_breakpoint_init(&attr); | 1449 | hw_breakpoint_init(&attr); |
@@ -1471,11 +1455,9 @@ static long ppc_set_hwdebug(struct task_struct *child, | |||
1471 | ptrace_triggered, NULL, child); | 1455 | ptrace_triggered, NULL, child); |
1472 | if (IS_ERR(bp)) { | 1456 | if (IS_ERR(bp)) { |
1473 | thread->ptrace_bps[0] = NULL; | 1457 | thread->ptrace_bps[0] = NULL; |
1474 | ptrace_put_breakpoints(child); | ||
1475 | return PTR_ERR(bp); | 1458 | return PTR_ERR(bp); |
1476 | } | 1459 | } |
1477 | 1460 | ||
1478 | ptrace_put_breakpoints(child); | ||
1479 | return 1; | 1461 | return 1; |
1480 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 1462 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
1481 | 1463 | ||
@@ -1519,16 +1501,12 @@ static long ppc_del_hwdebug(struct task_struct *child, long data) | |||
1519 | return -EINVAL; | 1501 | return -EINVAL; |
1520 | 1502 | ||
1521 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 1503 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
1522 | if (ptrace_get_breakpoints(child) < 0) | ||
1523 | return -ESRCH; | ||
1524 | |||
1525 | bp = thread->ptrace_bps[0]; | 1504 | bp = thread->ptrace_bps[0]; |
1526 | if (bp) { | 1505 | if (bp) { |
1527 | unregister_hw_breakpoint(bp); | 1506 | unregister_hw_breakpoint(bp); |
1528 | thread->ptrace_bps[0] = NULL; | 1507 | thread->ptrace_bps[0] = NULL; |
1529 | } else | 1508 | } else |
1530 | ret = -ENOENT; | 1509 | ret = -ENOENT; |
1531 | ptrace_put_breakpoints(child); | ||
1532 | return ret; | 1510 | return ret; |
1533 | #else /* CONFIG_HAVE_HW_BREAKPOINT */ | 1511 | #else /* CONFIG_HAVE_HW_BREAKPOINT */ |
1534 | if (child->thread.hw_brk.address == 0) | 1512 | if (child->thread.hw_brk.address == 0) |