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>] [day] [month] [year] [list]
Message-ID: <20241205221928.1155984-2-david@ixit.cz>
Date: Thu,  5 Dec 2024 17:18:39 -0500
From: David Heidelberg <david@...t.cz>
To: Andrew Morton <akpm@...ux-foundation.org>,
	David Heidelberg <david@...t.cz>,
	Dmitry Rokosov <ddrokosov@...utedevices.com>
Cc: linux-kernel@...r.kernel.org
Subject: [PATCH] samples: add a sample list module

Sample list module that creates a proc entry /proc/sample_list
and registers read/write file operations.

Each write to the proc will copy the buffer
and store it in a data structure.

Each read from the proc will populate the read buffer with
list entries, up to the read length (buffer size).

Signed-off-by: David Heidelberg <david@...t.cz>
---
I would love to receive feedback on this list implementation approach.
If there are any implementation mistakes, I am open to revising
this sample to make it more accurate.

 samples/Kconfig       |  13 +++++
 samples/Makefile      |   1 +
 samples/list/Makefile |   2 +
 samples/list/list.c   | 125 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 samples/list/Makefile
 create mode 100644 samples/list/list.c

diff --git ./samples/Kconfig ./samples/Kconfig
index b288d9991d27..7bc9c2c85599 100644
--- ./samples/Kconfig
+++ ./samples/Kconfig
@@ -128,6 +128,19 @@ config SAMPLE_RPMSG_CLIENT
 	  to communicate with an AMP-configured remote processor over
 	  the rpmsg bus.
 
+config SAMPLE_LIST
+	tristate "Build list implementation sample"
+	depends on PROC_FS
+	help
+	  Build a sample list module that creates a proc entry
+	  /proc/sample_list and registers read/write file operations.
+
+	  Each write to the proc will copy the buffer
+	  and store it in a data structure.
+
+	  Each read from the proc will populate the read buffer with
+	  list entries, up to the read length (buffer size).
+
 config SAMPLE_LIVEPATCH
 	tristate "Build live patching samples -- loadable modules only"
 	depends on LIVEPATCH && m
diff --git ./samples/Makefile ./samples/Makefile
index b85fa64390c5..68158af60c96 100644
--- ./samples/Makefile
+++ ./samples/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SAMPLE_KFIFO)		+= kfifo/
 obj-$(CONFIG_SAMPLE_KOBJECT)		+= kobject/
 obj-$(CONFIG_SAMPLE_KPROBES)		+= kprobes/
 subdir-$(CONFIG_SAMPLE_LANDLOCK)	+= landlock
+obj-$(CONFIG_SAMPLE_LIST)		+= list/
 obj-$(CONFIG_SAMPLE_LIVEPATCH)		+= livepatch/
 subdir-$(CONFIG_SAMPLE_PIDFD)		+= pidfd
 obj-$(CONFIG_SAMPLE_QMI_CLIENT)		+= qmi/
diff --git ./samples/list/Makefile ./samples/list/Makefile
new file mode 100644
index 000000000000..8e77d97aaa9c
--- /dev/null
+++ ./samples/list/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_SAMPLE_LIST) += list.o
diff --git ./samples/list/list.c ./samples/list/list.c
new file mode 100644
index 000000000000..1db693ee65b3
--- /dev/null
+++ ./samples/list/list.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * list.c - Kernel list sample code
+ *
+ * Copyright 2024 David Heidelberg <david@...t.cz>
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#define PROC_NAME "list_sample"
+#define BUFFER_SIZE 128
+
+LIST_HEAD(data_list);
+
+struct data_node {
+	struct list_head list;
+	char data[BUFFER_SIZE];
+};
+
+static struct proc_dir_entry *proc_entry;
+
+static ssize_t proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
+{
+	struct data_node *new_node;
+
+	if (count >= BUFFER_SIZE)
+		count = BUFFER_SIZE - 1;
+
+	new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
+	if (!new_node)
+		return -ENOMEM;
+
+	if (strncpy_from_user(new_node->data, buffer, count) < 0) {
+		kfree(new_node);
+		return -EFAULT;
+	}
+
+	list_add_tail(&new_node->list, &data_list);
+
+	return count;
+}
+
+/*
+ * Several copy_to_user() is a bit less efficient
+ * comparing to list_for_each_entry_safe, but makes code simpler.
+ */
+static ssize_t proc_read(struct file *file, char __user *buffer, size_t count, loff_t *pos)
+{
+	static struct list_head *start, *cur;
+	struct data_node *node;
+	size_t data_len, batch_len = 0;
+	char temp_buf[2 * BUFFER_SIZE] = {0};
+
+	if (*pos == 0) {
+		start = &data_list;
+		cur = &data_list;
+	}
+
+	if (*pos != 0 && cur->next == start)
+		return 0;
+
+	if (list_empty(cur))
+		return 0;
+
+	while (batch_len < BUFFER_SIZE) {
+		node = list_entry(cur->next, struct data_node, list);
+		data_len = snprintf(temp_buf + strlen(temp_buf),
+				     BUFFER_SIZE - strlen(temp_buf),
+				     "%s",
+				     node->data);
+		if (data_len + batch_len > BUFFER_SIZE)
+			break;
+
+		batch_len += data_len;
+
+		cur = cur->next;
+		if (cur->next == start)
+			break;
+	}
+
+	if (copy_to_user(buffer, temp_buf, batch_len))
+		return -EFAULT;
+
+	*pos += batch_len;
+
+	return batch_len;
+}
+
+static const struct proc_ops proc_fops = {
+	.proc_read = proc_read,
+	.proc_write = proc_write,
+};
+
+static int __init list_sample_init(void)
+{
+	proc_entry = proc_create(PROC_NAME, 0666, NULL, &proc_fops);
+	if (!proc_entry) {
+		pr_err("Failed to create proc entry\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void __exit list_sample_exit(void)
+{
+	struct data_node *node, *tmp;
+
+	proc_remove(proc_entry);
+
+	list_for_each_entry_safe(node, tmp, &data_list, list) {
+		list_del(&node->list);
+		kfree(node);
+	}
+}
+
+module_init(list_sample_init);
+module_exit(list_sample_exit);
+
+MODULE_AUTHOR("David Heidelberg");
+MODULE_DESCRIPTION("List sample module.");
+MODULE_LICENSE("GPL v2");
-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ