4.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frederic Weisbecker frederic@kernel.org
[ Upstream commit 9a4903dde2c8633c5fcf887b98c4e047a6154a54 ]
arch_validate_hwbkpt_settings() mixes up attribute check and commit into a single code entity. Therefore the validation may return an error due to incorrect atributes while still leaving halfway modified architecture breakpoint data.
This is harmless when we deal with a new breakpoint but it becomes a problem when we modify an existing breakpoint.
Split attribute parse and commit to fix that. The architecture is passed a "struct arch_hw_breakpoint" to fill on top of the new attr and the core takes care about copying the backend data once it's fully validated. The architectures then need to implement the new API.
Original-patch-by: Andy Lutomirski luto@kernel.org Reported-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Frederic Weisbecker frederic@kernel.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Andy Lutomirski luto@kernel.org Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Arnaldo Carvalho de Melo acme@redhat.com Cc: Benjamin Herrenschmidt benh@kernel.crashing.org Cc: Catalin Marinas catalin.marinas@arm.com Cc: Chris Zankel chris@zankel.net Cc: Jiri Olsa jolsa@redhat.com Cc: Joel Fernandes joel.opensrc@gmail.com Cc: Mark Rutland mark.rutland@arm.com Cc: Max Filippov jcmvbkbc@gmail.com Cc: Michael Ellerman mpe@ellerman.id.au Cc: Namhyung Kim namhyung@kernel.org Cc: Paul Mackerras paulus@samba.org Cc: Peter Zijlstra peterz@infradead.org Cc: Rich Felker dalias@libc.org Cc: Thomas Gleixner tglx@linutronix.de Cc: Will Deacon will.deacon@arm.com Cc: Yoshinori Sato ysato@users.sourceforge.jp Link: http://lkml.kernel.org/r/1529981939-8231-2-git-send-email-frederic@kernel.or... Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Sasha Levin alexander.levin@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- kernel/events/hw_breakpoint.c | 57 ++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-)
--- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c @@ -400,16 +400,35 @@ int dbg_release_bp_slot(struct perf_even return 0; }
-static int validate_hw_breakpoint(struct perf_event *bp) +#ifndef hw_breakpoint_arch_parse +int hw_breakpoint_arch_parse(struct perf_event *bp, + const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw) { - int ret; + int err;
- ret = arch_validate_hwbkpt_settings(bp); - if (ret) - return ret; + err = arch_validate_hwbkpt_settings(bp); + if (err) + return err; + + *hw = bp->hw.info; + + return 0; +} +#endif + +static int hw_breakpoint_parse(struct perf_event *bp, + const struct perf_event_attr *attr, + struct arch_hw_breakpoint *hw) +{ + int err; + + err = hw_breakpoint_arch_parse(bp, attr, hw); + if (err) + return err;
if (arch_check_bp_in_kernelspace(bp)) { - if (bp->attr.exclude_kernel) + if (attr->exclude_kernel) return -EINVAL; /* * Don't let unprivileged users set a breakpoint in the trap @@ -424,19 +443,22 @@ static int validate_hw_breakpoint(struct
int register_perf_hw_breakpoint(struct perf_event *bp) { - int ret; + struct arch_hw_breakpoint hw; + int err;
- ret = reserve_bp_slot(bp); - if (ret) - return ret; - - ret = validate_hw_breakpoint(bp); + err = reserve_bp_slot(bp); + if (err) + return err;
- /* if arch_validate_hwbkpt_settings() fails then release bp slot */ - if (ret) + err = hw_breakpoint_parse(bp, &bp->attr, &hw); + if (err) { release_bp_slot(bp); + return err; + } + + bp->hw.info = hw;
- return ret; + return 0; }
/** @@ -464,6 +486,7 @@ modify_user_hw_breakpoint_check(struct p u64 old_len = bp->attr.bp_len; int old_type = bp->attr.bp_type; bool modify = attr->bp_type != old_type; + struct arch_hw_breakpoint hw; int err = 0;
bp->attr.bp_addr = attr->bp_addr; @@ -473,7 +496,7 @@ modify_user_hw_breakpoint_check(struct p if (check && memcmp(&bp->attr, attr, sizeof(*attr))) return -EINVAL;
- err = validate_hw_breakpoint(bp); + err = hw_breakpoint_parse(bp, attr, &hw); if (!err && modify) err = modify_bp_slot(bp, old_type);
@@ -484,7 +507,9 @@ modify_user_hw_breakpoint_check(struct p return err; }
+ bp->hw.info = hw; bp->attr.disabled = attr->disabled; + return 0; }