lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue,  7 May 2024 20:52:59 -0700
From: Ian Rogers <irogers@...gle.com>
To: Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...hat.com>, 
	Arnaldo Carvalho de Melo <acme@...nel.org>, Namhyung Kim <namhyung@...nel.org>, 
	Mark Rutland <mark.rutland@....com>, 
	Alexander Shishkin <alexander.shishkin@...ux.intel.com>, Jiri Olsa <jolsa@...nel.org>, 
	Ian Rogers <irogers@...gle.com>, Adrian Hunter <adrian.hunter@...el.com>, 
	Kan Liang <kan.liang@...ux.intel.com>, James Clark <james.clark@....com>, 
	Leo Yan <leo.yan@...ux.dev>, linux-perf-users@...r.kernel.org, 
	linux-kernel@...r.kernel.org
Subject: [PATCH v1 2/4] perf comm: Fix comm_str__put for reference count checking

Searching for the entry in the array needs to avoid the intermediate
pointer with reference count checking. Refactor the array removal to
binary search for the entry. Change the array to hold an entry with a
reference count (so the intermediate pointer can work) and remove from
the array when the reference count on a comm_str falls to 1.

Fixes: 13ca628716c6 ("perf comm: Add reference count checking to 'struct comm_str'")
Signed-off-by: Ian Rogers <irogers@...gle.com>
---
 tools/perf/util/comm.c | 45 +++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 14 deletions(-)

diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index 1aa9a08e5b03..233f2b6edf52 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -19,6 +19,8 @@ static struct comm_strs {
 	int capacity;
 } _comm_strs;
 
+static void comm_strs__remove_if_last(struct comm_str *cs);
+
 static void comm_strs__init(void)
 {
 	init_rwsem(&_comm_strs.lock);
@@ -58,22 +60,15 @@ static struct comm_str *comm_str__get(struct comm_str *cs)
 
 static void comm_str__put(struct comm_str *cs)
 {
-	if (cs && refcount_dec_and_test(comm_str__refcnt(cs))) {
-		struct comm_strs *comm_strs = comm_strs__get();
-		int i;
+	if (!cs)
+		return;
 
-		down_write(&comm_strs->lock);
-		for (i = 0; i < comm_strs->num_strs; i++) {
-			if (comm_strs->strs[i] == cs)
-				break;
-		}
-		for (; i < comm_strs->num_strs - 1; i++)
-			comm_strs->strs[i] = comm_strs->strs[i + 1];
-
-		comm_strs->num_strs--;
-		up_write(&comm_strs->lock);
+	if (refcount_dec_and_test(comm_str__refcnt(cs))) {
 		RC_CHK_FREE(cs);
 	} else {
+		if (refcount_read(comm_str__refcnt(cs)) == 1)
+			comm_strs__remove_if_last(cs);
+
 		RC_CHK_PUT(cs);
 	}
 }
@@ -107,6 +102,28 @@ static int comm_str__search(const void *_key, const void *_member)
 	return strcmp(key, comm_str__str(member));
 }
 
+static void comm_strs__remove_if_last(struct comm_str *cs)
+{
+	struct comm_strs *comm_strs = comm_strs__get();
+
+	down_write(&comm_strs->lock);
+	/*
+	 * Are there only references from the array, if so remove the array
+	 * reference under the write lock so that we don't race with findnew.
+	 */
+	if (refcount_read(comm_str__refcnt(cs)) == 1) {
+		struct comm_str **entry;
+
+		entry = bsearch(comm_str__str(cs), comm_strs->strs, comm_strs->num_strs,
+				sizeof(struct comm_str *), comm_str__search);
+		comm_str__put(*entry);
+		for (int i = entry - comm_strs->strs; i < comm_strs->num_strs - 1; i++)
+			comm_strs->strs[i] = comm_strs->strs[i + 1];
+		comm_strs->num_strs--;
+	}
+	up_write(&comm_strs->lock);
+}
+
 static struct comm_str *__comm_strs__find(struct comm_strs *comm_strs, const char *str)
 {
 	struct comm_str **result;
@@ -158,7 +175,7 @@ static struct comm_str *comm_strs__findnew(const char *str)
 		}
 	}
 	up_write(&comm_strs->lock);
-	return result;
+	return comm_str__get(result);
 }
 
 struct comm *comm__new(const char *str, u64 timestamp, bool exec)
-- 
2.45.0.rc1.225.g2a3ae87e7f-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ