Changes since v2 [1]:
- revised commit comment for clarification;
- cc linux-mm for expert's review on the kern_addr_valid() usage as suggested by Petr;
- cc Kefeng Wang in light of his recent patch [2]
[1]: https://lore.kernel.org/lkml/[email protected]/T/
[2]: https://lore.kernel.org/lkml/[email protected]/
Jane Chu (1):
vsprintf: protect kernel from panic due to non-canonical pointer
dereference
lib/vsprintf.c | 3 +++
1 file changed, 3 insertions(+)
--
2.18.4
Having stepped on a local kernel bug where reading sysfs has led to
out-of-bound pointer dereference by vsprintf() which led to GPF panic.
And the reason for GPF is that the OOB pointer was turned to a
non-canonical address such as 0x7665645f63616465.
vsprintf() already has this line of defense
if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr))
return "(efault)";
Since a non-canonical pointer can be detected by kern_addr_valid()
on architectures that present VM holes as well as meaningful
implementation of kern_addr_valid() that detects the non-canonical
addresses, this patch addes a check on non-canonical string pointer by
kern_addr_valid() and display "(efault)" to alert user that something
is wrong instead of unecessarily panic the server.
On the other hand, if the non-canonical string pointer is dereferenced
else where in the kernel, by virtue of being non-canonical, a crash
is expected to be immediate.
Signed-off-by: Jane Chu <[email protected]>
---
lib/vsprintf.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c414a8d9f1ea..b38c12ef1e45 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -698,6 +698,9 @@ static const char *check_pointer_msg(const void *ptr)
if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr))
return "(efault)";
+ if (!kern_addr_valid((unsigned long)ptr))
+ return "(efault)";
+
return NULL;
}
--
2.18.4
Hi Jane,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on linus/master]
[also build test ERROR on v6.1-rc1]
[cannot apply to next-20221020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Jane-Chu/vsprintf-check-non-canonical-pointer-by-kern_addr_valid/20221020-103535
patch link: https://lore.kernel.org/r/20221019193431.2923462-2-jane.chu%40oracle.com
patch subject: [PATCH v3 1/1] vsprintf: protect kernel from panic due to non-canonical pointer dereference
config: x86_64-rhel-8.3-func
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
reproduce (this is a W=1 build):
# https://github.com/intel-lab-lkp/linux/commit/7da79322bb256f65be136ef3ca3d557e42da8ffe
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Jane-Chu/vsprintf-check-non-canonical-pointer-by-kern_addr_valid/20221020-103535
git checkout 7da79322bb256f65be136ef3ca3d557e42da8ffe
# save the config file
mkdir build_dir && cp config build_dir/.config
make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
All errors (new ones prefixed by >>):
lib/vsprintf.c: In function 'check_pointer_msg':
>> lib/vsprintf.c:701:14: error: implicit declaration of function 'kern_addr_valid'; did you mean 'virt_addr_valid'? [-Werror=implicit-function-declaration]
701 | if (!kern_addr_valid((unsigned long)ptr))
| ^~~~~~~~~~~~~~~
| virt_addr_valid
lib/vsprintf.c: In function 'va_format':
lib/vsprintf.c:1688:9: warning: function 'va_format' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format]
1688 | buf += vsnprintf(buf, end > buf ? end - buf : 0, va_fmt->fmt, va);
| ^~~
cc1: some warnings being treated as errors
vim +701 lib/vsprintf.c
687
688 /*
689 * Do not call any complex external code here. Nested printk()/vsprintf()
690 * might cause infinite loops. Failures might break printk() and would
691 * be hard to debug.
692 */
693 static const char *check_pointer_msg(const void *ptr)
694 {
695 if (!ptr)
696 return "(null)";
697
698 if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr))
699 return "(efault)";
700
> 701 if (!kern_addr_valid((unsigned long)ptr))
702 return "(efault)";
703
704 return NULL;
705 }
706
--
0-DAY CI Kernel Test Service
https://01.org/lkp
On 2022/10/20 3:34, Jane Chu wrote:
> Changes since v2 [1]:
> - revised commit comment for clarification;
> - cc linux-mm for expert's review on the kern_addr_valid() usage as suggested by Petr;
but this won't fix issue on archs which don't have correct
kern_addr_valid(), right?
could we call copy_from_kernel_nofault() when it could works well, and
skip it on early boot?
other options, call some functions in include/asm-generic/sections.h or
include/linux/kallsyms.h?
> - cc Kefeng Wang in light of his recent patch [2]
>
> [1]: https://lore.kernel.org/lkml/[email protected]/T/
> [2]: https://lore.kernel.org/lkml/[email protected]/
>
> Jane Chu (1):
> vsprintf: protect kernel from panic due to non-canonical pointer
> dereference
>
> lib/vsprintf.c | 3 +++
> 1 file changed, 3 insertions(+)
>