diff options
| author | Ali Ahmet Memis <ali@iusegentoo.com> | 2026-08-21 01:45:27 +0000 |
|---|---|---|
| committer | Stafford Horne <shorne@gmail.com> | 2026-08-29 07:32:26 +0100 |
| commit | 78004e9a87f240df03e2f73120d291763c32e0a7 (patch) | |
| tree | 137c22dd795222931b9d2bf2501d37cd766741aa /tools/perf/util/top.c | |
| download | linux-stable-78004e9a87f240df03e2f73120d291763c32e0a7.tar.gz linux-stable-78004e9a87f240df03e2f73120d291763c32e0a7.zip | |
openrisc: fix arbitrary kernel memory access via or1k_atomic syscallgrafted
sys_or1k_atomic() (syscall 244 in the "or1k" ABI) takes two user
pointers, v1 and v2, and swaps the words they point to in hand-written
assembly.
l.lwz r29,0(r4)
l.lwz r27,0(r5)
l.sw 0(r4),r27
l.sw 0(r5),r29
The pointers are not checked with access_ok(). The four memory
accesses also have no exception table entries.
A caller passes a kernel address as either pointer, and the syscall
reads from and writes to it directly.
This gives an unprivileged process a kernel read/write primitive. It
overwrites kernel data such as the sys_call_table, gaining code
execution in kernel context.
Check both pointers before entering the critical section. Add fixups
for the four memory accesses so faults on valid but unmapped user
addresses return -EFAULT.
[shorne@gmail.com: fix comment style]
Fixes: 9d02a4283e9c ("OpenRISC: Boot code")
Cc: stable@vger.kernel.org
Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Stafford Horne <shorne@gmail.com>
Diffstat (limited to 'tools/perf/util/top.c')
| -rw-r--r-- | tools/perf/util/top.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c new file mode 100644 index 000000000..b06e10a11 --- /dev/null +++ b/tools/perf/util/top.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + * + * Refactored from builtin-top.c, see that files for further copyright notes. + */ + +#include "event.h" +#include "evlist.h" +#include "evsel.h" +#include "parse-events.h" +#include "symbol.h" +#include "top.h" +#include "util.h" +#include <inttypes.h> + +#define SNPRINTF(buf, size, fmt, args...) \ +({ \ + size_t r = snprintf(buf, size, fmt, ## args); \ + r > size ? size : r; \ +}) + +size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) +{ + float samples_per_sec; + float ksamples_per_sec; + float esamples_percent; + struct record_opts *opts = &top->record_opts; + struct target *target = &opts->target; + size_t ret = 0; + int nr_cpus; + + if (top->samples) { + samples_per_sec = top->samples / top->delay_secs; + ksamples_per_sec = top->kernel_samples / top->delay_secs; + esamples_percent = (100.0 * top->exact_samples) / top->samples; + } else { + samples_per_sec = ksamples_per_sec = esamples_percent = 0.0; + } + + if (!perf_guest) { + float ksamples_percent = 0.0; + + if (samples_per_sec) + ksamples_percent = (100.0 * ksamples_per_sec) / + samples_per_sec; + ret = SNPRINTF(bf, size, + " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" + " exact: %4.1f%% lost: %" PRIu64 "/%" PRIu64 " drop: %" PRIu64 "/%" PRIu64 " [", + samples_per_sec, ksamples_percent, esamples_percent, + top->lost, top->lost_total, top->drop, top->drop_total); + } else { + float us_samples_per_sec = top->us_samples / top->delay_secs; + float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; + float guest_us_samples_per_sec = top->guest_us_samples / top->delay_secs; + + ret = SNPRINTF(bf, size, + " PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" + " guest kernel:%4.1f%% guest us:%4.1f%%" + " exact: %4.1f%% [", samples_per_sec, + 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / + samples_per_sec)), + 100.0 - (100.0 * ((samples_per_sec - us_samples_per_sec) / + samples_per_sec)), + 100.0 - (100.0 * ((samples_per_sec - + guest_kernel_samples_per_sec) / + samples_per_sec)), + 100.0 - (100.0 * ((samples_per_sec - + guest_us_samples_per_sec) / + samples_per_sec)), + esamples_percent); + } + + if (top->evlist->core.nr_entries == 1) { + struct evsel *first = evlist__first(top->evlist); + ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", + (uint64_t)first->core.attr.sample_period, + opts->freq ? "Hz" : ""); + } + + ret += SNPRINTF(bf + ret, size - ret, "%s", evsel__name(top->sym_evsel)); + + ret += SNPRINTF(bf + ret, size - ret, "], "); + + if (target->pid) + ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", + target->pid); + else if (target->tid) + ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", + target->tid); + else if (top->uid_str != NULL) + ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", + top->uid_str); + else + ret += SNPRINTF(bf + ret, size - ret, " (all"); + + nr_cpus = perf_cpu_map__nr(top->evlist->core.user_requested_cpus); + if (target->cpu_list) + ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", + nr_cpus > 1 ? "s" : "", + target->cpu_list); + else { + if (target->tid) + ret += SNPRINTF(bf + ret, size - ret, ")"); + else + ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", + nr_cpus, nr_cpus > 1 ? "s" : ""); + } + + perf_top__reset_sample_counters(top); + return ret; +} + +void perf_top__reset_sample_counters(struct perf_top *top) +{ + top->samples = top->us_samples = top->kernel_samples = + top->exact_samples = top->guest_kernel_samples = + top->guest_us_samples = top->lost = top->drop = 0; +} |
