From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A0EB3859EB for ; Fri, 8 May 2026 08:27:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778228877; cv=none; b=nejD8jpGDto1zpBDbZFMUPGTdWrs+nqD5G7AfKOp3mOFnlwBxt9gAfgDd9+i9kIh5j2dZ/QOdPuy4QhX97HP3ahflglXAcDO4gIhuYT3s/nf0lG1+lp/K3XmsGOc8LvfPKxRcIdk88RcvQDrNk8VXj4Pfetf5WhpYJxoMCDhJVU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778228877; c=relaxed/simple; bh=YV+jQTzr5U8wqJiMkFv23YvtpmRbZfl0p0/Y4dsUoP0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=dlnGVedNtks3c1+rBOvAzJ0qlJKitzBnqp8R+tVmYwpwAjs5eGZKamhc1wPj4Hg72SilFoJsq0GJ5KAiE9xByokwqsvqtSUI+kvp5iWEgzzkUIz5k7PQ5vZe2LQoKZ7AAALuXBDKHV8XcQR/EwIiGXHo+OXQ6Rctd8qJjjDRDF8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Y8tU9AL2; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Y8tU9AL2" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2ef37c3f773so2054320eec.1 for ; Fri, 08 May 2026 01:27:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1778228864; x=1778833664; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=TaCzln3oP7GCJBDx8P3UztqbyaF0B2xh0/jsYh7hZZo=; b=Y8tU9AL2IqY4y8PuLr3kL8/t6uBLCJ3M1BqbodF4WUfjP72Xpp95CJDU/j/Rw4ab2q XLTpzm8EDI8P1B3cyr5b2Ef1Wm5Cpq0X5gJj7mU3fovEupaNpF9iFTEYL8Lh6AjIQqsq +/IOyGtjqNUFK/lCCJcY1JeAmcRy0F1HkpR7JgDpaGrQVB6893NVOxDiHDwmxrDjxki6 BB0gIqYPzPSQmfMcsO0a4cfz6oY73ex//8c/bbkGWmK2/8bnq4AaqjR0B3Kq13ZJzasr IV80Gx6/Fh6vQfHAjqwNa9YClKDbQwUapqzT7pjTNHSauo/mtPaqQ225ZCSN/t6og+kC UoLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778228864; x=1778833664; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TaCzln3oP7GCJBDx8P3UztqbyaF0B2xh0/jsYh7hZZo=; b=nDTrUvtSjUXCWvU2IJqIzU7okk4Z4YGgAJ2PHp3o4kkYNoNIAyprm2o/twRRJoJDTg 9aj3O5F4M+YBzEbAfRRYrIDNf+KW9l0+9s3JO5uzZR1ng/YI+KkubSDMUq2SROsuTXzK kNkfzOdcjGHUbuOm632BMYBl2NIe1EPdh6ntilaI8xbsyBzg9GlNXkT7QZvlUOLkNRot SgzbYlluyKO2yTfj7HvUDymJfFJJsmFlHnL4YNO3OcPqjNiEyfOQLMsMPVxc1ZA63e+c ViYYLcCupb14Pu4cwj3RxIz1r44I9715go52ewdZIJUVIRxm05001IFlZGq0+YHAYf37 rF0Q== X-Forwarded-Encrypted: i=1; AFNElJ9Te7P0rvpGaq7wXHtsMzPjS2BF4LntXkQcvfQk/KQq9CsTWMzmb/sUjjH+18IHipjts8HBmPLjABiaF97ch9VV@vger.kernel.org X-Gm-Message-State: AOJu0YwgA6s5BGEa4IBCDwikunekSeWA+N2NpAmQGlf82BhT5bJMymyF vGkkIvKrPKwDwhd3C9fAMCltgBbtlFn9drpAsphuunoUCtwnYR53y+s9ixffp1AQHk+vDKNZ6Xa SAcrU8Wkr8w== X-Received: from dybml13.prod.google.com ([2002:a05:7301:150d:b0:2d9:8c75:b19e]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:6d03:b0:2de:3022:a459 with SMTP id 5a478bee46e88-2f549f7c266mr5651619eec.21.1778228863854; Fri, 08 May 2026 01:27:43 -0700 (PDT) Date: Fri, 8 May 2026 01:27:26 -0700 In-Reply-To: <20260508082726.2795191-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-perf-users@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260506004546.3140141-1-irogers@google.com> <20260508082726.2795191-1-irogers@google.com> X-Mailer: git-send-email 2.54.0.563.g4f69b47b94-goog Message-ID: <20260508082726.2795191-7-irogers@google.com> Subject: [PATCH v6 6/6] perf aslr: Strip sample registers From: Ian Rogers To: irogers@google.com, acme@kernel.org, gmx@google.com, james.clark@linaro.org, namhyung@kernel.org Cc: adrian.hunter@intel.com, jolsa@kernel.org, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, mingo@redhat.com, peterz@infradead.org Content-Type: text/plain; charset="UTF-8" When the ASLR tracking tool encounters sample events containing user or interrupt register dumps (PERF_SAMPLE_REGS_USER / PERF_SAMPLE_REGS_INTR), it previously dropped the entire sample event conservatively to prevent absolute virtual memory pointers leakage embedded inside raw register frames. If a trace session was recorded with register collection flags enabled, this resulted in 100% sample drop rates, and this happened by default for ARM64. Refactor the ASLR tool to strip out obly the register dump payload words from PERF_RECORD_SAMPLE event streams, automatically shrinking the output sample header size. Incoming PERF_RECORD_ATTR events are scrubbed up front to clear the register dump bit selection flags and masks, and output sample ABI words are safely overwritten to PERF_SAMPLE_REGS_ABI_NONE. This keeps downstream evsel parsers perfectly synchronized while retaining full, comprehensive sample profiles completely clear of secret register data frames. Verification parity is established inside inject_aslr.sh via a dedicated sorted report diff comparison validation case proving zero starvation and absolute secrecy. Assisted-by: Gemini-CLI:Google Gemini 3 Signed-off-by: Ian Rogers --- tools/perf/builtin-inject.c | 11 ++++++ tools/perf/tests/shell/inject_aslr.sh | 51 +++++++++++++++++++++++++++ tools/perf/util/aslr.c | 27 +++++++------- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 51dcf248b653..7a17ce019657 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -2463,6 +2463,17 @@ static int __cmd_inject(struct perf_inject *inject) } } + if (inject->aslr) { + struct evsel *evsel; + + evlist__for_each_entry(session->evlist, evsel) { + evsel__reset_sample_bit(evsel, REGS_USER); + evsel__reset_sample_bit(evsel, REGS_INTR); + evsel->core.attr.sample_regs_user = 0; + evsel->core.attr.sample_regs_intr = 0; + } + } + session->header.data_offset = output_data_offset; diff --git a/tools/perf/tests/shell/inject_aslr.sh b/tools/perf/tests/shell/inject_aslr.sh index 6363a0f69d2b..323782c3802d 100755 --- a/tools/perf/tests/shell/inject_aslr.sh +++ b/tools/perf/tests/shell/inject_aslr.sh @@ -446,6 +446,56 @@ test_kernel_report_aslr() { fi } +test_regs_stripping() { + echo "Test user register stripping" + local rdata="${temp_dir}/perf.data.regs" + local rdata2="${temp_dir}/perf.data.regs.injected" + local rdata_clean="${temp_dir}/perf.data.regs.clean" + + if ! perf record --user-regs -o "${rdata}" ${prog} > /dev/null 2>&1; then + echo "Skipping user registers test as recording failed (unsupported flag/platform)" + return + fi + + perf inject -b -i "${rdata}" -o "${rdata_clean}" + perf inject -v -b --aslr -i "${rdata}" -o "${rdata2}" + + local report1="${temp_dir}/report_regs1" + local report2="${temp_dir}/report_regs2" + local report1_clean="${temp_dir}/report_regs1.clean" + local report2_clean="${temp_dir}/report_regs2.clean" + local diff_file="${temp_dir}/diff_regs" + + perf report -i "${rdata_clean}" --stdio > "${report1}" 2>/dev/null || true + perf report -i "${rdata2}" --stdio > "${report2}" 2>/dev/null || true + + grep '%' "${report1}" | grep -v '^#' | grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true + grep '%' "${report2}" | grep -v '^#' | grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true + + diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true + + if [ ! -s "${report1_clean}" ]; then + echo "User registers stripping test [Failed - profile trace starved/empty]" + err=1 + return + elif [ -s "${diff_file}" ]; then + echo "User registers stripping test [Failed - report parsing differs]" + echo "Showing first 20 lines of diff:" + head -n 20 "${diff_file}" + err=1 + return + fi + + local script_dump="${temp_dir}/script_regs_dump" + perf script -D -i "${rdata2}" > "${script_dump}" 2>/dev/null || true + if grep -q "PERF_SAMPLE_REGS_USER" "${script_dump}"; then + echo "User registers stripping test [Failed - register dumps still present]" + err=1 + else + echo "User registers stripping test [Success]" + fi +} + test_basic_aslr test_pipe_aslr test_callchain_aslr @@ -455,6 +505,7 @@ test_pipe_out_report_aslr test_dropped_samples test_kernel_aslr test_kernel_report_aslr +test_regs_stripping cleanup exit $err diff --git a/tools/perf/util/aslr.c b/tools/perf/util/aslr.c index 09b7f2f8fb85..e5369589a733 100644 --- a/tools/perf/util/aslr.c +++ b/tools/perf/util/aslr.c @@ -751,18 +751,13 @@ static int aslr_tool__process_sample(const struct perf_tool *tool, union perf_ev if (abi != PERF_SAMPLE_REGS_ABI_NONE) { u64 nr = hweight64(evsel->core.attr.sample_regs_user); - if (nr > max_i - i || nr > max_j - j) { + if (nr > max_i - i) { ret = -EFAULT; goto out_put; } - memcpy(&out_array[j], &in_array[i], nr * sizeof(u64)); i += nr; - j += nr; + out_array[j-1] = PERF_SAMPLE_REGS_ABI_NONE; } - /* TODO: can this be less conservative? */ - pr_debug("Dropping regs user sample as possible ASLR leak\n"); - ret = 0; - goto out_put; } if (sample_type & PERF_SAMPLE_STACK_USER) { u64 size; @@ -806,18 +801,13 @@ static int aslr_tool__process_sample(const struct perf_tool *tool, union perf_ev if (abi != PERF_SAMPLE_REGS_ABI_NONE) { u64 nr = hweight64(evsel->core.attr.sample_regs_intr); - if (nr > max_i - i || nr > max_j - j) { + if (nr > max_i - i) { ret = -EFAULT; goto out_put; } - memcpy(&out_array[j], &in_array[i], nr * sizeof(u64)); i += nr; - j += nr; + out_array[j-1] = PERF_SAMPLE_REGS_ABI_NONE; } - /* TODO: can this be less conservative? */ - pr_debug("Dropping interrupt register sample as possible ASLR leak\n"); - ret = 0; - goto out_put; } if (sample_type & PERF_SAMPLE_PHYS_ADDR) { COPY_U64(); /* phys_addr */ @@ -907,6 +897,15 @@ static int aslr_tool__process_attr(const struct perf_tool *tool, if (new_event->attr.attr.type == PERF_TYPE_BREAKPOINT) new_event->attr.attr.bp_addr = 0; /* Conservatively remove addresses. */ + if (new_event->attr.attr.sample_type & PERF_SAMPLE_REGS_USER) { + new_event->attr.attr.sample_type &= ~PERF_SAMPLE_REGS_USER; + new_event->attr.attr.sample_regs_user = 0; + } + if (new_event->attr.attr.sample_type & PERF_SAMPLE_REGS_INTR) { + new_event->attr.attr.sample_type &= ~PERF_SAMPLE_REGS_INTR; + new_event->attr.attr.sample_regs_intr = 0; + } + return delegate->attr(delegate, new_event, pevlist); } -- 2.54.0.563.g4f69b47b94-goog