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-next>] [day] [month] [year] [list]
Message-Id: <20231215140113.57173-1-davydov-max@yandex-team.ru>
Date: Fri, 15 Dec 2023 17:01:13 +0300
From: Maksim Davydov <davydov-max@...dex-team.ru>
To: linux-kernel@...r.kernel.org,
	x86@...nel.org
Cc: davydov-max@...dex-team.ru,
	den-plotnikov@...dex-team.ru,
	tony.luck@...el.com,
	tglx@...utronix.de,
	mingo@...hat.com,
	bp@...en8.de,
	dave.hansen@...ux.intel.com,
	hpa@...or.com,
	peterz@...radead.org,
	juri.lelli@...hat.com,
	vincent.guittot@...aro.org
Subject: [PATCH] x86/split_lock: add split lock counter

Provides per task split locks counter to monitor split locks rate
in the system. It can be helpful in split locks monitoring to get a clear
sense of which process causing split locks and how many of them have
happened by the moment. For instance, it might be used by cloud providers
who can't control guest executable code and want to make decisions based
on the rate value like ratelimiting or notifing the split lock origins.

To implement this functionality the per-task flag have been transformed
into the counter. But procfs interface is used to provide the counter
in machine-readable format.

Signed-off-by: Maksim Davydov <davydov-max@...dex-team.ru>
---
 arch/x86/include/asm/cpu.h  | 18 ++++++++++++++++++
 arch/x86/kernel/cpu/intel.c | 35 +++++++++++++++++++++++++++++++++--
 fs/proc/base.c              |  7 +++++++
 include/linux/sched.h       |  6 +++---
 kernel/fork.c               |  2 +-
 5 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index fecc4fe1d68a..1470124e1d63 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -44,6 +44,12 @@ extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
 extern bool handle_guest_split_lock(unsigned long ip);
 extern void handle_bus_lock(struct pt_regs *regs);
 u8 get_this_hybrid_cpu_type(void);
+extern int proc_pid_split_locks_show(struct seq_file *s,
+		struct pid_namespace *ns, struct pid *pid,
+		struct task_struct *tsk);
+extern int proc_tgid_split_locks_show(struct seq_file *s,
+		struct pid_namespace *ns, struct pid *pid,
+		struct task_struct *tsk);
 #else
 static inline void __init sld_setup(struct cpuinfo_x86 *c) {}
 static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
@@ -62,6 +68,18 @@ static inline u8 get_this_hybrid_cpu_type(void)
 {
 	return 0;
 }
+static inline int proc_pid_split_locks_show(struct seq_file *s,
+		struct pid_namespace *ns, struct pid *pid,
+		struct task_struct *tsk)
+{
+	return 0;
+}
+static inline int proc_tgid_split_locks_show(struct seq_file *s,
+		struct pid_namespace *ns, struct pid *pid,
+		struct task_struct *tsk)
+{
+	return 0;
+}
 #endif
 #ifdef CONFIG_IA32_FEAT_CTL
 void init_ia32_feat_ctl(struct cpuinfo_x86 *c);
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index a927a8fc9624..20640a4b9eac 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -1160,10 +1160,10 @@ static void split_lock_warn(unsigned long ip)
 	struct delayed_work *work;
 	int cpu;
 
-	if (!current->reported_split_lock)
+	if (!current->detected_split_locks)
 		pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n",
 				    current->comm, current->pid, ip);
-	current->reported_split_lock = 1;
+	current->detected_split_locks++;
 
 	if (sysctl_sld_mitigate) {
 		/*
@@ -1191,6 +1191,37 @@ static void split_lock_warn(unsigned long ip)
 	put_cpu();
 }
 
+static int split_locks_show(struct seq_file *s, struct task_struct *tsk,
+			    int whole)
+{
+	u64 detected_split_locks = tsk->detected_split_locks;
+
+	if (whole) {
+		struct task_struct *t = tsk;
+
+		while_each_thread(tsk, t) {
+			detected_split_locks += t->detected_split_locks;
+		}
+	}
+
+	seq_put_decimal_ull(s, "", detected_split_locks);
+	seq_putc(s, '\n');
+
+	return 0;
+}
+
+int proc_pid_split_locks_show(struct seq_file *s, struct pid_namespace *ns,
+			      struct pid *pid, struct task_struct *tsk)
+{
+	return split_locks_show(s, tsk, 0);
+}
+
+int proc_tgid_split_locks_show(struct seq_file *s, struct pid_namespace *ns,
+			       struct pid *pid, struct task_struct *tsk)
+{
+	return split_locks_show(s, tsk, 1);
+}
+
 bool handle_guest_split_lock(unsigned long ip)
 {
 	if (sld_state == sld_warn) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index dd31e3b6bf77..3c533312dbbc 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -98,6 +98,7 @@
 #include <linux/cn_proc.h>
 #include <linux/ksm.h>
 #include <trace/events/oom.h>
+#include <asm/cpu.h>
 #include "internal.h"
 #include "fd.h"
 
@@ -3360,6 +3361,9 @@ static const struct pid_entry tgid_base_stuff[] = {
 	ONE("ksm_merging_pages",  S_IRUSR, proc_pid_ksm_merging_pages),
 	ONE("ksm_stat",  S_IRUSR, proc_pid_ksm_stat),
 #endif
+#ifdef CONFIG_CPU_SUP_INTEL
+	ONE("split_locks", S_IRUGO, proc_tgid_split_locks_show),
+#endif
 };
 
 static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
@@ -3699,6 +3703,9 @@ static const struct pid_entry tid_base_stuff[] = {
 	ONE("ksm_merging_pages",  S_IRUSR, proc_pid_ksm_merging_pages),
 	ONE("ksm_stat",  S_IRUSR, proc_pid_ksm_stat),
 #endif
+#ifdef CONFIG_CPU_SUP_INTEL
+	ONE("split_locks", S_IRUGO, proc_pid_split_locks_show),
+#endif
 };
 
 static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 292c31697248..5b9cd4524405 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -957,9 +957,6 @@ struct task_struct {
 #ifdef CONFIG_IOMMU_SVA
 	unsigned			pasid_activated:1;
 #endif
-#ifdef	CONFIG_CPU_SUP_INTEL
-	unsigned			reported_split_lock:1;
-#endif
 #ifdef CONFIG_TASK_DELAY_ACCT
 	/* delay due to memory thrashing */
 	unsigned                        in_thrashing:1;
@@ -1027,6 +1024,9 @@ struct task_struct {
 	u64				stimescaled;
 #endif
 	u64				gtime;
+#ifdef	CONFIG_CPU_SUP_INTEL
+	u64				detected_split_locks;
+#endif
 	struct prev_cputime		prev_cputime;
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 	struct vtime			vtime;
diff --git a/kernel/fork.c b/kernel/fork.c
index 10917c3e1f03..5a0318010dd5 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1188,7 +1188,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
 #endif
 
 #ifdef CONFIG_CPU_SUP_INTEL
-	tsk->reported_split_lock = 0;
+	tsk->detected_split_locks = 0;
 #endif
 
 #ifdef CONFIG_SCHED_MM_CID
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ