Messages in this thread Patch in this message | | | From | Joe Perches <> | Subject | [PATCH] sysfs: Add sysfs_emit to replace sprintf to PAGE_SIZE buffers. | Date | Fri, 28 Aug 2020 15:52:13 -0700 |
| |
sprintf does not know the PAGE_SIZE maximum of the temporary buffer used for outputting sysfs content requests and it's possible to overrun the buffer length.
Add a generic sysfs_emit mechanism that knows that the size of the temporary buffer and ensures that no overrun is done.
Signed-off-by: Joe Perches <joe@perches.com> --- fs/sysfs/file.c | 30 ++++++++++++++++++++++++++++++ include/linux/sysfs.h | 8 ++++++++ 2 files changed, 38 insertions(+)
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index eb6897ab78e7..06a13bbd7080 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -707,3 +707,33 @@ int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid) return 0; } EXPORT_SYMBOL_GPL(sysfs_change_owner); + +/** + * sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer. + * @buf: start of PAGE_SIZE buffer. + * @pos: current position in buffer + * (pos - buf) must always be < PAGE_SIZE + * @fmt: format + * @...: arguments to format + * + * + * Returns number of characters written at pos. + */ +int sysfs_emit(char *buf, char *pos, const char *fmt, ...) +{ + va_list args; + bool bad_pos = pos < buf; + bool bad_len = (pos - buf) >= PAGE_SIZE; + int len; + + if (WARN(bad_pos || bad_len, "(pos < buf):%d (pos >= PAGE_SIZE):%d\n", + bad_pos, bad_len)) + return 0; + + va_start(args, fmt); + len = vscnprintf(pos, PAGE_SIZE - (pos - buf), fmt, args); + va_end(args); + + return len; +} +EXPORT_SYMBOL_GPL(sysfs_emit); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 34e84122f635..5a21d3d30016 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -329,6 +329,8 @@ int sysfs_groups_change_owner(struct kobject *kobj, int sysfs_group_change_owner(struct kobject *kobj, const struct attribute_group *groups, kuid_t kuid, kgid_t kgid); +__printf(3, 4) +int sysfs_emit(char *buf, char *pos, const char *fmt, ...); #else /* CONFIG_SYSFS */ @@ -576,6 +578,12 @@ static inline int sysfs_group_change_owner(struct kobject *kobj, return 0; } +__printf(3, 4) +static inline int sysfs_emit(char *buf, char *pos, const char *fmt, ...) +{ + return 0; +} + #endif /* CONFIG_SYSFS */ static inline int __must_check sysfs_create_file(struct kobject *kobj, -- 2.26.0
| |