|
Petr Mladek |
c5a70d |
From 2efc459d06f1630001e3984854848a5647086232 Mon Sep 17 00:00:00 2001
|
|
Petr Mladek |
c5a70d |
From: Joe Perches <joe@perches.com>
|
|
Petr Mladek |
c5a70d |
Date: Wed, 16 Sep 2020 13:40:38 -0700
|
|
Petr Mladek |
c5a70d |
Subject: [PATCH] sysfs: Add sysfs_emit and sysfs_emit_at to format sysfs
|
|
Petr Mladek |
c5a70d |
output
|
|
Petr Mladek |
c5a70d |
Git-commit: 2efc459d06f1630001e3984854848a5647086232
|
|
Petr Mladek |
c5a70d |
Patch-mainline: v5.10-rc1
|
|
Petr Mladek |
c5a70d |
References: bsc#1200598 CVE-2022-20166
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
Output defects can exist in sysfs content using sprintf and snprintf.
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
sprintf does not know the PAGE_SIZE maximum of the temporary buffer
|
|
Petr Mladek |
c5a70d |
used for outputting sysfs content and it's possible to overrun the
|
|
Petr Mladek |
c5a70d |
PAGE_SIZE buffer length.
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
Add a generic sysfs_emit function that knows that the size of the
|
|
Petr Mladek |
c5a70d |
temporary buffer and ensures that no overrun is done.
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
Add a generic sysfs_emit_at function that can be used in multiple
|
|
Petr Mladek |
c5a70d |
call situations that also ensures that no overrun is done.
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
Validate the output buffer argument to be page aligned.
|
|
Petr Mladek |
c5a70d |
Validate the offset len argument to be within the PAGE_SIZE buf.
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
Signed-off-by: Joe Perches <joe@perches.com>
|
|
Petr Mladek |
c5a70d |
Link: https://lore.kernel.org/r/884235202216d464d61ee975f7465332c86f76b2.1600285923.git.joe@perches.com
|
|
Petr Mladek |
c5a70d |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Petr Mladek |
c5a70d |
Acked-by: Petr Mladek <pmladek@suse.com>
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
[pmladek@suse.com: Removed changes in the documentation. The new API is not
|
|
Petr Mladek |
c5a70d |
used everywhere in the old code base.
|
|
Petr Mladek |
c5a70d |
]
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
---
|
|
Petr Mladek |
c5a70d |
fs/sysfs/file.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
Petr Mladek |
c5a70d |
include/linux/sysfs.h | 16 ++++++++++++++
|
|
Petr Mladek |
c5a70d |
2 files changed, 71 insertions(+)
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
--- a/fs/sysfs/file.c
|
|
Petr Mladek |
c5a70d |
+++ b/fs/sysfs/file.c
|
|
Petr Mladek |
c5a70d |
@@ -17,6 +17,7 @@
|
|
Petr Mladek |
c5a70d |
#include <linux/list.h>
|
|
Petr Mladek |
c5a70d |
#include <linux/mutex.h>
|
|
Petr Mladek |
c5a70d |
#include <linux/seq_file.h>
|
|
Petr Mladek |
c5a70d |
+#include <linux/mm.h>
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
#include "sysfs.h"
|
|
Petr Mladek |
c5a70d |
#include "../kernfs/kernfs-internal.h"
|
|
Petr Mladek |
c5a70d |
@@ -549,3 +550,57 @@ void sysfs_remove_bin_file(struct kobjec
|
|
Petr Mladek |
c5a70d |
kernfs_remove_by_name(kobj->sd, attr->attr.name);
|
|
Petr Mladek |
c5a70d |
}
|
|
Petr Mladek |
c5a70d |
EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+/**
|
|
Petr Mladek |
c5a70d |
+ * sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
|
|
Petr Mladek |
c5a70d |
+ * @buf: start of PAGE_SIZE buffer.
|
|
Petr Mladek |
c5a70d |
+ * @fmt: format
|
|
Petr Mladek |
c5a70d |
+ * @...: optional arguments to @format
|
|
Petr Mladek |
c5a70d |
+ *
|
|
Petr Mladek |
c5a70d |
+ *
|
|
Petr Mladek |
c5a70d |
+ * Returns number of characters written to @buf.
|
|
Petr Mladek |
c5a70d |
+ */
|
|
Petr Mladek |
c5a70d |
+int sysfs_emit(char *buf, const char *fmt, ...)
|
|
Petr Mladek |
c5a70d |
+{
|
|
Petr Mladek |
c5a70d |
+ va_list args;
|
|
Petr Mladek |
c5a70d |
+ int len;
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+ if (WARN(!buf || offset_in_page(buf),
|
|
Petr Mladek |
c5a70d |
+ "invalid sysfs_emit: buf:%p\n", buf))
|
|
Petr Mladek |
c5a70d |
+ return 0;
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+ va_start(args, fmt);
|
|
Petr Mladek |
c5a70d |
+ len = vscnprintf(buf, PAGE_SIZE, fmt, args);
|
|
Petr Mladek |
c5a70d |
+ va_end(args);
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+ return len;
|
|
Petr Mladek |
c5a70d |
+}
|
|
Petr Mladek |
c5a70d |
+EXPORT_SYMBOL_GPL(sysfs_emit);
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+/**
|
|
Petr Mladek |
c5a70d |
+ * sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
|
|
Petr Mladek |
c5a70d |
+ * @buf: start of PAGE_SIZE buffer.
|
|
Petr Mladek |
c5a70d |
+ * @at: offset in @buf to start write in bytes
|
|
Petr Mladek |
c5a70d |
+ * @at must be >= 0 && < PAGE_SIZE
|
|
Petr Mladek |
c5a70d |
+ * @fmt: format
|
|
Petr Mladek |
c5a70d |
+ * @...: optional arguments to @fmt
|
|
Petr Mladek |
c5a70d |
+ *
|
|
Petr Mladek |
c5a70d |
+ *
|
|
Petr Mladek |
c5a70d |
+ * Returns number of characters written starting at &@buf[@at].
|
|
Petr Mladek |
c5a70d |
+ */
|
|
Petr Mladek |
c5a70d |
+int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
|
|
Petr Mladek |
c5a70d |
+{
|
|
Petr Mladek |
c5a70d |
+ va_list args;
|
|
Petr Mladek |
c5a70d |
+ int len;
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+ if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
|
|
Petr Mladek |
c5a70d |
+ "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
|
|
Petr Mladek |
c5a70d |
+ return 0;
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+ va_start(args, fmt);
|
|
Petr Mladek |
c5a70d |
+ len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
|
|
Petr Mladek |
c5a70d |
+ va_end(args);
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+ return len;
|
|
Petr Mladek |
c5a70d |
+}
|
|
Petr Mladek |
c5a70d |
+EXPORT_SYMBOL_GPL(sysfs_emit_at);
|
|
Petr Mladek |
c5a70d |
--- a/include/linux/sysfs.h
|
|
Petr Mladek |
c5a70d |
+++ b/include/linux/sysfs.h
|
|
Petr Mladek |
c5a70d |
@@ -300,6 +300,11 @@ static inline void sysfs_enable_ns(struc
|
|
Petr Mladek |
c5a70d |
return kernfs_enable_ns(kn);
|
|
Petr Mladek |
c5a70d |
}
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
+__printf(2, 3)
|
|
Petr Mladek |
c5a70d |
+int sysfs_emit(char *buf, const char *fmt, ...);
|
|
Petr Mladek |
c5a70d |
+__printf(3, 4)
|
|
Petr Mladek |
c5a70d |
+int sysfs_emit_at(char *buf, int at, const char *fmt, ...);
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
#else /* CONFIG_SYSFS */
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
|
|
Petr Mladek |
c5a70d |
@@ -506,6 +511,17 @@ static inline void sysfs_enable_ns(struc
|
|
Petr Mladek |
c5a70d |
{
|
|
Petr Mladek |
c5a70d |
}
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
+__printf(2, 3)
|
|
Petr Mladek |
c5a70d |
+static inline int sysfs_emit(char *buf, const char *fmt, ...)
|
|
Petr Mladek |
c5a70d |
+{
|
|
Petr Mladek |
c5a70d |
+ return 0;
|
|
Petr Mladek |
c5a70d |
+}
|
|
Petr Mladek |
c5a70d |
+
|
|
Petr Mladek |
c5a70d |
+__printf(3, 4)
|
|
Petr Mladek |
c5a70d |
+static inline int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
|
|
Petr Mladek |
c5a70d |
+{
|
|
Petr Mladek |
c5a70d |
+ return 0;
|
|
Petr Mladek |
c5a70d |
+}
|
|
Petr Mladek |
c5a70d |
#endif /* CONFIG_SYSFS */
|
|
Petr Mladek |
c5a70d |
|
|
Petr Mladek |
c5a70d |
static inline int __must_check sysfs_create_file(struct kobject *kobj,
|