* [PATCH RFC 1/2] sysfs: add helpers for safely showing simple strings
2020-08-29 23:37 [PATCH RFC 0/2] simple sysfs wrappers for single values Alex Dewar
@ 2020-08-29 23:37 ` Alex Dewar
2020-08-29 23:37 ` [PATCH RFC 2/2] sysfs: add helper macro for showing simple integer values Alex Dewar
2020-08-30 0:28 ` [PATCH RFC 0/2] simple sysfs wrappers for single values Joe Perches
2 siblings, 0 replies; 8+ messages in thread
From: Alex Dewar @ 2020-08-29 23:37 UTC (permalink / raw)
Cc: Alex Dewar, Greg Kroah-Hartman, Rafael J. Wysocki,
David S. Miller, Christian Brauner, Nayna Jain, Dan Williams,
Mauro Carvalho Chehab, Sourabh Jain, linux-kernel
Add a helper, sysfs_strscpy(), which simply copies a string and
appends a newline and NUL char to the end, making sure not to overflow
the destination buffer, which MUST be PAGE_SIZE bytes (which is true for
buffers in this context). It includes a compile time check for the
specified destination buffer size.
Also add a helper macro, sysfs_strcpy(), which calls sysfs_strscpy() with
count == PAGE_SIZE, for use with regular NUL-terminated strings. If the
src buffer is a fixed-size array, guarantee that we don't copy beyond its
end by only copying a maximum of sizeof(src) bytes.
Signed-off-by: Alex Dewar <alex.dewar90@gmail.com>
---
fs/sysfs/file.c | 14 ++++++++++++++
include/linux/sysfs.h | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index eb6897ab78e7..2a60e5c6392d 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -707,3 +707,17 @@ int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)
return 0;
}
EXPORT_SYMBOL_GPL(sysfs_change_owner);
+
+ssize_t __sysfs_strscpy(char *dest, const char *src, size_t count)
+{
+ ssize_t written;
+
+ if (count > PAGE_SIZE)
+ return -EINVAL;
+
+ written = strscpy(dest, src, count - 1);
+ dest[written++] = '\n';
+ dest[written] = '\0';
+ return written;
+}
+EXPORT_SYMBOL_GPL(__sysfs_strscpy);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 34e84122f635..26e7d9f69dfd 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -162,6 +162,41 @@ static const struct attribute_group _name##_group = { \
}; \
__ATTRIBUTE_GROUPS(_name)
+/**
+ * sysfs_strscpy - return a string from a show method with terminating
+ * newline to a maximum of count bytes
+ * @dest: destination buffer
+ * @src: string to be emitted
+ * @count: maximum number of bytes to be written to dest
+ */
+#define sysfs_strscpy(dest, src, count) \
+({ \
+ BUILD_BUG_ON(__builtin_constant_p(count) && (count) > PAGE_SIZE); \
+ __sysfs_strscpy((dest), (src), (count)); \
+})
+
+ssize_t __sysfs_strscpy(char *dest, const char *src, size_t count);
+
+/**
+ * sysfs_strcpy - return a string from a show method with terminating
+ * newline
+ * @dest: destination buffer
+ * @src: string to be emitted
+ *
+ * This method will only write a maximum of PAGE_SIZE bytes to dest,
+ * ensuring that the output buffer is not overflown. If src is a
+ * fixed-size array, a maximum of sizeof(src) bytes will be copied,
+ * ensuring that memory is not read beyond the end of the array.
+ */
+#define sysfs_strcpy(dest, src) \
+sysfs_strscpy((dest), (src), \
+ __builtin_choose_expr( \
+ __same_type((src), &(src)[0]), \
+ PAGE_SIZE, \
+ min(sizeof(src) + 2, PAGE_SIZE) \
+ ) \
+)
+
struct file;
struct vm_area_struct;
--
2.28.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH RFC 2/2] sysfs: add helper macro for showing simple integer values
2020-08-29 23:37 [PATCH RFC 0/2] simple sysfs wrappers for single values Alex Dewar
2020-08-29 23:37 ` [PATCH RFC 1/2] sysfs: add helpers for safely showing simple strings Alex Dewar
@ 2020-08-29 23:37 ` Alex Dewar
2020-08-30 9:13 ` Greg Kroah-Hartman
2020-08-30 0:28 ` [PATCH RFC 0/2] simple sysfs wrappers for single values Joe Perches
2 siblings, 1 reply; 8+ messages in thread
From: Alex Dewar @ 2020-08-29 23:37 UTC (permalink / raw)
Cc: Alex Dewar, Greg Kroah-Hartman, Rafael J. Wysocki,
Christian Brauner, David S. Miller, Nayna Jain, Dan Williams,
Mauro Carvalho Chehab, Sourabh Jain, linux-kernel
sysfs attributes are supposed to be only single values, which are
printed into a buffer of PAGE_SIZE. Accordingly, for many simple
attributes, sprintf() can be used like so:
static ssize_t my_show(..., char *buf)
{
...
return sprintf("%d\n", my_integer);
}
The problem is that whilst this use of sprintf() is memory safe, other
cases where e.g. a possibly unterminated string is passed as input, are
not and so use of sprintf() here might make it more difficult to
identify these problematic cases.
Define a macro, sysfs_sprinti(), which outputs the value of a single
integer to a buffer (with terminating "\n\0") and returns the size written.
This way, we can convert over the some of the trivially correct users of
sprintf() and decrease its usage in the kernel source tree.
Another advantage of this approach is that we can now statically check
the type of the integer so that e.g. an unsigned long long will be
formatted as %llu. This will fix cases where the wrong format string has
been passed to sprintf().
Signed-off-by: Alex Dewar <alex.dewar90@gmail.com>
---
include/linux/sysfs.h | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 26e7d9f69dfd..763316788153 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -197,6 +197,37 @@ sysfs_strscpy((dest), (src), \
) \
)
+/**
+ * sysfs_sprinti - emit an integer-type value from a sysfs show method
+ * @buf: destination buffer
+ * @x: the variable whose value is to be shown
+ *
+ * The appropriate format is passed to sprintf() according to the type of
+ * x, preventing accidental misuse of format strings.
+ */
+#define sysfs_sprinti(buf, x) \
+({ \
+ BUILD_BUG_ON(!__builtin_types_compatible_p(typeof(x), unsigned int) && \
+ !__builtin_types_compatible_p(typeof(x), unsigned long) && \
+ !__builtin_types_compatible_p(typeof(x), unsigned long long) && \
+ !__builtin_types_compatible_p(typeof(x), int) && \
+ !__builtin_types_compatible_p(typeof(x), short) && \
+ !__builtin_types_compatible_p(typeof(x), unsigned short)); \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), unsigned int), \
+ sprintf(buf, "%u\n", (unsigned int)(x)), \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), unsigned long), \
+ sprintf(buf, "%lu\n", (unsigned long)(x)), \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), unsigned long long), \
+ sprintf(buf, "%llu\n", (unsigned long long)(x)), \
+ sprintf(buf, "%d\n", (int)(x)) \
+ ) \
+ ) \
+ ); \
+})
+
struct file;
struct vm_area_struct;
--
2.28.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH RFC 2/2] sysfs: add helper macro for showing simple integer values
2020-08-29 23:37 ` [PATCH RFC 2/2] sysfs: add helper macro for showing simple integer values Alex Dewar
@ 2020-08-30 9:13 ` Greg Kroah-Hartman
2020-09-02 15:31 ` Alex Dewar
0 siblings, 1 reply; 8+ messages in thread
From: Greg Kroah-Hartman @ 2020-08-30 9:13 UTC (permalink / raw)
To: Alex Dewar
Cc: Rafael J. Wysocki, Christian Brauner, David S. Miller, Nayna Jain,
Dan Williams, Mauro Carvalho Chehab, Sourabh Jain, linux-kernel
On Sun, Aug 30, 2020 at 12:37:17AM +0100, Alex Dewar wrote:
> sysfs attributes are supposed to be only single values, which are
> printed into a buffer of PAGE_SIZE. Accordingly, for many simple
> attributes, sprintf() can be used like so:
> static ssize_t my_show(..., char *buf)
> {
> ...
> return sprintf("%d\n", my_integer);
> }
>
> The problem is that whilst this use of sprintf() is memory safe, other
> cases where e.g. a possibly unterminated string is passed as input, are
> not and so use of sprintf() here might make it more difficult to
> identify these problematic cases.
>
> Define a macro, sysfs_sprinti(), which outputs the value of a single
> integer to a buffer (with terminating "\n\0") and returns the size written.
> This way, we can convert over the some of the trivially correct users of
> sprintf() and decrease its usage in the kernel source tree.
>
> Another advantage of this approach is that we can now statically check
> the type of the integer so that e.g. an unsigned long long will be
> formatted as %llu. This will fix cases where the wrong format string has
> been passed to sprintf().
>
> Signed-off-by: Alex Dewar <alex.dewar90@gmail.com>
> ---
> include/linux/sysfs.h | 31 +++++++++++++++++++++++++++++++
> 1 file changed, 31 insertions(+)
Did you try this out? Don't you need to return the number of bytes
written?
I like Joe's patches better, this feels like more work...
thanks,
greg k-h
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH RFC 2/2] sysfs: add helper macro for showing simple integer values
2020-08-30 9:13 ` Greg Kroah-Hartman
@ 2020-09-02 15:31 ` Alex Dewar
0 siblings, 0 replies; 8+ messages in thread
From: Alex Dewar @ 2020-09-02 15:31 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Alex Dewar, Rafael J. Wysocki, Christian Brauner, David S. Miller,
Nayna Jain, Dan Williams, Mauro Carvalho Chehab, Sourabh Jain,
linux-kernel
On Sun, Aug 30, 2020 at 11:13:53AM +0200, Greg Kroah-Hartman wrote:
> On Sun, Aug 30, 2020 at 12:37:17AM +0100, Alex Dewar wrote:
> > sysfs attributes are supposed to be only single values, which are
> > printed into a buffer of PAGE_SIZE. Accordingly, for many simple
> > attributes, sprintf() can be used like so:
> > static ssize_t my_show(..., char *buf)
> > {
> > ...
> > return sprintf("%d\n", my_integer);
> > }
> >
> > The problem is that whilst this use of sprintf() is memory safe, other
> > cases where e.g. a possibly unterminated string is passed as input, are
> > not and so use of sprintf() here might make it more difficult to
> > identify these problematic cases.
> >
> > Define a macro, sysfs_sprinti(), which outputs the value of a single
> > integer to a buffer (with terminating "\n\0") and returns the size written.
> > This way, we can convert over the some of the trivially correct users of
> > sprintf() and decrease its usage in the kernel source tree.
> >
> > Another advantage of this approach is that we can now statically check
> > the type of the integer so that e.g. an unsigned long long will be
> > formatted as %llu. This will fix cases where the wrong format string has
> > been passed to sprintf().
> >
> > Signed-off-by: Alex Dewar <alex.dewar90@gmail.com>
> > ---
> > include/linux/sysfs.h | 31 +++++++++++++++++++++++++++++++
> > 1 file changed, 31 insertions(+)
>
> Did you try this out? Don't you need to return the number of bytes
> written?
I tried it out, but maybe not thoroughly enough ;-)
>
> I like Joe's patches better, this feels like more work...
Fair enough. As Joe's pointed out, even for single numbers the
formatting is sometimes more complicated, so his approach does seem
best. Thanks for looking though :-)
>
> thanks,
>
> greg k-h
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 0/2] simple sysfs wrappers for single values
2020-08-29 23:37 [PATCH RFC 0/2] simple sysfs wrappers for single values Alex Dewar
2020-08-29 23:37 ` [PATCH RFC 1/2] sysfs: add helpers for safely showing simple strings Alex Dewar
2020-08-29 23:37 ` [PATCH RFC 2/2] sysfs: add helper macro for showing simple integer values Alex Dewar
@ 2020-08-30 0:28 ` Joe Perches
2020-08-30 1:23 ` Joe Perches
2 siblings, 1 reply; 8+ messages in thread
From: Joe Perches @ 2020-08-30 0:28 UTC (permalink / raw)
To: Alex Dewar
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Christian Brauner,
David S. Miller, Nayna Jain, Dan Williams, Sourabh Jain,
Mauro Carvalho Chehab, linux-kernel
On Sun, 2020-08-30 at 00:37 +0100, Alex Dewar wrote:
> Hi all,
>
> I've noticed there seems to have been a fair amount of discussion around
> the subject of possible helper methods for use in the context of sysfs
> show methods (which I haven't had a chance to go through in detail yet
> -- sorry!), so I thought I'd send out a couple of patches I've been
> working on for this, in case it's of any interest to anyone.
If you really want to do this, I suggest you get use
wrappers like sysfs_emit_string, sysfs_emit_int, sysfs_emit_u64
though I don't see _that_ much value.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFC 0/2] simple sysfs wrappers for single values
2020-08-30 0:28 ` [PATCH RFC 0/2] simple sysfs wrappers for single values Joe Perches
@ 2020-08-30 1:23 ` Joe Perches
2020-09-02 15:29 ` Alex Dewar
0 siblings, 1 reply; 8+ messages in thread
From: Joe Perches @ 2020-08-30 1:23 UTC (permalink / raw)
To: Alex Dewar
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Christian Brauner,
David S. Miller, Nayna Jain, Dan Williams, Sourabh Jain,
Mauro Carvalho Chehab, linux-kernel
On Sat, 2020-08-29 at 17:28 -0700, Joe Perches wrote:
> On Sun, 2020-08-30 at 00:37 +0100, Alex Dewar wrote:
> > Hi all,
> >
> > I've noticed there seems to have been a fair amount of discussion around
> > the subject of possible helper methods for use in the context of sysfs
> > show methods (which I haven't had a chance to go through in detail yet
> > -- sorry!), so I thought I'd send out a couple of patches I've been
> > working on for this, in case it's of any interest to anyone.
>
> If you really want to do this, I suggest you get use
> wrappers like sysfs_emit_string, sysfs_emit_int, sysfs_emit_u64
> though I don't see _that_ much value.
Just fyi:
the treewide converted sysfs_emit uses
end up with these integer outputs:
$ git grep -P -oh 'sysfs_emit\(buf, "%\d*[luixd]*\\n"' | \
sort | uniq -c | sort -rn
1482 sysfs_emit(buf, "%d\n"
549 sysfs_emit(buf, "%u\n"
118 sysfs_emit(buf, "%ld\n"
100 sysfs_emit(buf, "%lu\n"
78 sysfs_emit(buf, "%llu\n"
62 sysfs_emit(buf, "%i\n"
47 sysfs_emit(buf, "%x\n"
24 sysfs_emit(buf, "%lld\n"
12 sysfs_emit(buf, "%llx\n"
12 sysfs_emit(buf, "%08x\n"
12 sysfs_emit(buf, "%02x\n"
10 sysfs_emit(buf, "%016llx\n"
8 sysfs_emit(buf, "%04x\n"
6 sysfs_emit(buf, "%lx\n"
5 sysfs_emit(buf, "%02d\n"
4 sysfs_emit(buf, "%04d\n"
2 sysfs_emit(buf, "%08lx\n"
1 sysfs_emit(buf, "%li\n"
1 sysfs_emit(buf, "%4x\n"
1 sysfs_emit(buf, "%0x\n"
1 sysfs_emit(buf, "%06x\n"
1 sysfs_emit(buf, "%03x\n"
1 sysfs_emit(buf, "%01x\n"
>
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH RFC 0/2] simple sysfs wrappers for single values
2020-08-30 1:23 ` Joe Perches
@ 2020-09-02 15:29 ` Alex Dewar
0 siblings, 0 replies; 8+ messages in thread
From: Alex Dewar @ 2020-09-02 15:29 UTC (permalink / raw)
To: Joe Perches
Cc: Alex Dewar, Greg Kroah-Hartman, Rafael J. Wysocki,
Christian Brauner, David S. Miller, Nayna Jain, Dan Williams,
Sourabh Jain, Mauro Carvalho Chehab, linux-kernel
On Sat, Aug 29, 2020 at 06:23:13PM -0700, Joe Perches wrote:
> On Sat, 2020-08-29 at 17:28 -0700, Joe Perches wrote:
> > On Sun, 2020-08-30 at 00:37 +0100, Alex Dewar wrote:
> > > Hi all,
> > >
> > > I've noticed there seems to have been a fair amount of discussion around
> > > the subject of possible helper methods for use in the context of sysfs
> > > show methods (which I haven't had a chance to go through in detail yet
> > > -- sorry!), so I thought I'd send out a couple of patches I've been
> > > working on for this, in case it's of any interest to anyone.
> >
> > If you really want to do this, I suggest you get use
> > wrappers like sysfs_emit_string, sysfs_emit_int, sysfs_emit_u64
> > though I don't see _that_ much value.
>
> Just fyi:
>
> the treewide converted sysfs_emit uses
> end up with these integer outputs:
Thanks for looking at the code. It does look like my approach was a bit
too simplistic!
>
> $ git grep -P -oh 'sysfs_emit\(buf, "%\d*[luixd]*\\n"' | \
> sort | uniq -c | sort -rn
> 1482 sysfs_emit(buf, "%d\n"
> 549 sysfs_emit(buf, "%u\n"
> 118 sysfs_emit(buf, "%ld\n"
> 100 sysfs_emit(buf, "%lu\n"
> 78 sysfs_emit(buf, "%llu\n"
> 62 sysfs_emit(buf, "%i\n"
> 47 sysfs_emit(buf, "%x\n"
> 24 sysfs_emit(buf, "%lld\n"
> 12 sysfs_emit(buf, "%llx\n"
> 12 sysfs_emit(buf, "%08x\n"
> 12 sysfs_emit(buf, "%02x\n"
> 10 sysfs_emit(buf, "%016llx\n"
> 8 sysfs_emit(buf, "%04x\n"
> 6 sysfs_emit(buf, "%lx\n"
> 5 sysfs_emit(buf, "%02d\n"
> 4 sysfs_emit(buf, "%04d\n"
> 2 sysfs_emit(buf, "%08lx\n"
> 1 sysfs_emit(buf, "%li\n"
> 1 sysfs_emit(buf, "%4x\n"
> 1 sysfs_emit(buf, "%0x\n"
> 1 sysfs_emit(buf, "%06x\n"
> 1 sysfs_emit(buf, "%03x\n"
> 1 sysfs_emit(buf, "%01x\n"
> >
>
^ permalink raw reply [flat|nested] 8+ messages in thread