Message ID | 20200807063539.2620154-2-keescook@chromium.org (mailing list archive) |
---|---|
State | Mainlined |
Commit | 11990a5bd7e558e9203c1070fc52fb6f0488e75b |
Headers | show |
Series | module: Correctly truncate sysfs sections output | expand |
On Thu, Aug 06, 2020 at 11:35:38PM -0700, Kees Cook wrote: > The only-root-readable /sys/module/$module/sections/$section files > did not truncate their output to the available buffer size. While most > paths into the kernfs read handlers end up using PAGE_SIZE buffers, > it's possible to get there through other paths (e.g. splice, sendfile). > Actually limit the output to the "count" passed into the read function, > and report it back correctly. *sigh* Ugh, never thought about that... Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+++ Kees Cook [06/08/20 23:35 -0700]: >The only-root-readable /sys/module/$module/sections/$section files >did not truncate their output to the available buffer size. While most >paths into the kernfs read handlers end up using PAGE_SIZE buffers, >it's possible to get there through other paths (e.g. splice, sendfile). >Actually limit the output to the "count" passed into the read function, >and report it back correctly. *sigh* > >Reported-by: kernel test robot <lkp@intel.com> >Link: https://lore.kernel.org/lkml/20200805002015.GE23458@shao2-debian >Fixes: ed66f991bb19 ("module: Refactor section attr into bin attribute") >Cc: stable@vger.kernel.org >Cc: Jessica Yu <jeyu@kernel.org> >Signed-off-by: Kees Cook <keescook@chromium.org> Oof, thanks for fixing this! Acked-by: Jessica Yu <jeyu@kernel.org> >--- > kernel/module.c | 22 +++++++++++++++++++--- > 1 file changed, 19 insertions(+), 3 deletions(-) > >diff --git a/kernel/module.c b/kernel/module.c >index aa183c9ac0a2..08c46084d8cc 100644 >--- a/kernel/module.c >+++ b/kernel/module.c >@@ -1520,18 +1520,34 @@ struct module_sect_attrs { > struct module_sect_attr attrs[]; > }; > >+#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4)) > static ssize_t module_sect_read(struct file *file, struct kobject *kobj, > struct bin_attribute *battr, > char *buf, loff_t pos, size_t count) > { > struct module_sect_attr *sattr = > container_of(battr, struct module_sect_attr, battr); >+ char bounce[MODULE_SECT_READ_SIZE + 1]; >+ size_t wrote; > > if (pos != 0) > return -EINVAL; > >- return sprintf(buf, "0x%px\n", >- kallsyms_show_value(file->f_cred) ? (void *)sattr->address : NULL); >+ /* >+ * Since we're a binary read handler, we must account for the >+ * trailing NUL byte that sprintf will write: if "buf" is >+ * too small to hold the NUL, or the NUL is exactly the last >+ * byte, the read will look like it got truncated by one byte. >+ * Since there is no way to ask sprintf nicely to not write >+ * the NUL, we have to use a bounce buffer. >+ */ >+ wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n", >+ kallsyms_show_value(file->f_cred) >+ ? (void *)sattr->address : NULL); >+ count = min(count, wrote); >+ memcpy(buf, bounce, count); >+ >+ return count; > } > > static void free_sect_attrs(struct module_sect_attrs *sect_attrs) >@@ -1580,7 +1596,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info) > goto out; > sect_attrs->nsections++; > sattr->battr.read = module_sect_read; >- sattr->battr.size = 3 /* "0x", "\n" */ + (BITS_PER_LONG / 4); >+ sattr->battr.size = MODULE_SECT_READ_SIZE; > sattr->battr.attr.mode = 0400; > *(gattr++) = &(sattr++)->battr; > } >-- >2.25.1 >
diff --git a/kernel/module.c b/kernel/module.c index aa183c9ac0a2..08c46084d8cc 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1520,18 +1520,34 @@ struct module_sect_attrs { struct module_sect_attr attrs[]; }; +#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4)) static ssize_t module_sect_read(struct file *file, struct kobject *kobj, struct bin_attribute *battr, char *buf, loff_t pos, size_t count) { struct module_sect_attr *sattr = container_of(battr, struct module_sect_attr, battr); + char bounce[MODULE_SECT_READ_SIZE + 1]; + size_t wrote; if (pos != 0) return -EINVAL; - return sprintf(buf, "0x%px\n", - kallsyms_show_value(file->f_cred) ? (void *)sattr->address : NULL); + /* + * Since we're a binary read handler, we must account for the + * trailing NUL byte that sprintf will write: if "buf" is + * too small to hold the NUL, or the NUL is exactly the last + * byte, the read will look like it got truncated by one byte. + * Since there is no way to ask sprintf nicely to not write + * the NUL, we have to use a bounce buffer. + */ + wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n", + kallsyms_show_value(file->f_cred) + ? (void *)sattr->address : NULL); + count = min(count, wrote); + memcpy(buf, bounce, count); + + return count; } static void free_sect_attrs(struct module_sect_attrs *sect_attrs) @@ -1580,7 +1596,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info) goto out; sect_attrs->nsections++; sattr->battr.read = module_sect_read; - sattr->battr.size = 3 /* "0x", "\n" */ + (BITS_PER_LONG / 4); + sattr->battr.size = MODULE_SECT_READ_SIZE; sattr->battr.attr.mode = 0400; *(gattr++) = &(sattr++)->battr; }
The only-root-readable /sys/module/$module/sections/$section files did not truncate their output to the available buffer size. While most paths into the kernfs read handlers end up using PAGE_SIZE buffers, it's possible to get there through other paths (e.g. splice, sendfile). Actually limit the output to the "count" passed into the read function, and report it back correctly. *sigh* Reported-by: kernel test robot <lkp@intel.com> Link: https://lore.kernel.org/lkml/20200805002015.GE23458@shao2-debian Fixes: ed66f991bb19 ("module: Refactor section attr into bin attribute") Cc: stable@vger.kernel.org Cc: Jessica Yu <jeyu@kernel.org> Signed-off-by: Kees Cook <keescook@chromium.org> --- kernel/module.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)