summaryrefslogtreecommitdiffstats
path: root/fs/smb/server/proc.c
diff options
context:
space:
mode:
authorAli Ahmet Memis <ali@iusegentoo.com>2026-08-21 01:45:27 +0000
committerStafford Horne <shorne@gmail.com>2026-08-29 07:32:26 +0100
commit78004e9a87f240df03e2f73120d291763c32e0a7 (patch)
tree137c22dd795222931b9d2bf2501d37cd766741aa /fs/smb/server/proc.c
downloadlinux-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 'fs/smb/server/proc.c')
-rw-r--r--fs/smb/server/proc.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/fs/smb/server/proc.c b/fs/smb/server/proc.c
new file mode 100644
index 000000000..101a2cc45
--- /dev/null
+++ b/fs/smb/server/proc.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025, LG Electronics.
+ * Author(s): Hyunchul Lee <hyc.lee@gmail.com>
+ * Copyright (C) 2025, Samsung Electronics.
+ * Author(s): Vedansh Bhardwaj <v.bhardwaj@samsung.com>
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "misc.h"
+#include "server.h"
+#include "stats.h"
+#include "smb_common.h"
+#include "smb2pdu.h"
+
+static struct proc_dir_entry *ksmbd_proc_fs;
+struct ksmbd_counters ksmbd_counters;
+
+struct proc_dir_entry *ksmbd_proc_create(const char *name,
+ int (*show)(struct seq_file *m, void *v),
+ void *v)
+{
+ return proc_create_single_data(name, 0400, ksmbd_proc_fs,
+ show, v);
+}
+
+struct ksmbd_const_smb2_process_req {
+ unsigned int const_value;
+ const char *name;
+};
+
+static const struct ksmbd_const_smb2_process_req smb2_process_req[KSMBD_COUNTER_MAX_REQS] = {
+ {le16_to_cpu(SMB2_NEGOTIATE), "SMB2_NEGOTIATE"},
+ {le16_to_cpu(SMB2_SESSION_SETUP), "SMB2_SESSION_SETUP"},
+ {le16_to_cpu(SMB2_LOGOFF), "SMB2_LOGOFF"},
+ {le16_to_cpu(SMB2_TREE_CONNECT), "SMB2_TREE_CONNECT"},
+ {le16_to_cpu(SMB2_TREE_DISCONNECT), "SMB2_TREE_DISCONNECT"},
+ {le16_to_cpu(SMB2_CREATE), "SMB2_CREATE"},
+ {le16_to_cpu(SMB2_CLOSE), "SMB2_CLOSE"},
+ {le16_to_cpu(SMB2_FLUSH), "SMB2_FLUSH"},
+ {le16_to_cpu(SMB2_READ), "SMB2_READ"},
+ {le16_to_cpu(SMB2_WRITE), "SMB2_WRITE"},
+ {le16_to_cpu(SMB2_LOCK), "SMB2_LOCK"},
+ {le16_to_cpu(SMB2_IOCTL), "SMB2_IOCTL"},
+ {le16_to_cpu(SMB2_CANCEL), "SMB2_CANCEL"},
+ {le16_to_cpu(SMB2_ECHO), "SMB2_ECHO"},
+ {le16_to_cpu(SMB2_QUERY_DIRECTORY), "SMB2_QUERY_DIRECTORY"},
+ {le16_to_cpu(SMB2_CHANGE_NOTIFY), "SMB2_CHANGE_NOTIFY"},
+ {le16_to_cpu(SMB2_QUERY_INFO), "SMB2_QUERY_INFO"},
+ {le16_to_cpu(SMB2_SET_INFO), "SMB2_SET_INFO"},
+ {le16_to_cpu(SMB2_OPLOCK_BREAK), "SMB2_OPLOCK_BREAK"},
+};
+
+static int proc_show_ksmbd_stats(struct seq_file *m, void *v)
+{
+ int i;
+
+ seq_puts(m, "Server\n");
+ seq_printf(m, "name: %s\n", ksmbd_server_string());
+ seq_printf(m, "netbios: %s\n", ksmbd_netbios_name());
+ seq_printf(m, "work group: %s\n", ksmbd_work_group());
+ seq_printf(m, "min protocol: %s\n", ksmbd_get_protocol_string(server_conf.min_protocol));
+ seq_printf(m, "max protocol: %s\n", ksmbd_get_protocol_string(server_conf.max_protocol));
+ seq_printf(m, "flags: 0x%08x\n", server_conf.flags);
+ seq_printf(m, "share_fake_fscaps: 0x%08x\n",
+ server_conf.share_fake_fscaps);
+ seq_printf(m, "sessions: %lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_SESSIONS));
+ seq_printf(m, "tree connects: %lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_TREE_CONNS));
+ seq_printf(m, "read bytes: %lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_READ_BYTES));
+ seq_printf(m, "written bytes: %lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_WRITE_BYTES));
+
+ seq_puts(m, "\nSMB2\n");
+ for (i = 0; i < KSMBD_COUNTER_MAX_REQS; i++)
+ seq_printf(m, "%-20s:\t%lld\n", smb2_process_req[i].name,
+ ksmbd_counter_sum(KSMBD_COUNTER_FIRST_REQ + i));
+ return 0;
+}
+
+void ksmbd_proc_cleanup(void)
+{
+ int i;
+
+ if (!ksmbd_proc_fs)
+ return;
+
+ proc_remove(ksmbd_proc_fs);
+
+ for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++)
+ percpu_counter_destroy(&ksmbd_counters.counters[i]);
+
+ ksmbd_proc_fs = NULL;
+}
+
+void ksmbd_proc_reset(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++)
+ percpu_counter_set(&ksmbd_counters.counters[i], 0);
+}
+
+void ksmbd_proc_init(void)
+{
+ int i;
+ int retval;
+
+ ksmbd_proc_fs = proc_mkdir("fs/ksmbd", NULL);
+ if (!ksmbd_proc_fs)
+ return;
+
+ if (!proc_mkdir_mode("sessions", 0400, ksmbd_proc_fs))
+ goto err_out;
+
+ for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++) {
+ retval = percpu_counter_init(&ksmbd_counters.counters[i], 0, GFP_KERNEL);
+ if (retval)
+ goto err_out;
+ }
+
+ if (!ksmbd_proc_create("server", proc_show_ksmbd_stats, NULL))
+ goto err_out;
+
+ ksmbd_proc_reset();
+ return;
+err_out:
+ ksmbd_proc_cleanup();
+}