mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] vsprintf: Do not have bprintf dereference pointers
@ 2017-12-29  1:40 Steven Rostedt
  2017-12-31 15:18 ` kbuild test robot
  0 siblings, 1 reply; 2+ messages in thread
From: Steven Rostedt @ 2017-12-29  1:40 UTC (permalink / raw)
  To: LKML; +Cc: Linus Torvalds, Thomas Gleixner, Andrew Morton, Frederic Weisbecker

From: "Steven Rostedt (VMware)" <rostedt@goodmis.org>

When trace_printk() was introduced, it was discussed that making it be as
low overhead as possible, that the processing of the format string should be
delayed until it is read. That is, a "trace_printk()" should not convert
the %d into numbers and so on, but instead, save the fmt string and all the
args in the buffer at the time of recording. When the trace_printk() data is
read, it would then parse the format string and do the conversions of the
saved arguments in the tracing buffer.

The code to perform this was added to vsprintf where vbin_printf() would
save the arguments of a specified format string in a buffer, then
bstr_printf() could be used to convert the buffer with the same format
string into the final output, as if vsprintf() was called in one go.

The issue arises when dereferenced pointers are used. The problem is that
something like %*pbl which reads a bitmask, will save the pointer to the
bitmask in the buffer. Then the reading of the buffer via bstr_printf() will
then look at the pointer to process the final output. Obviously the value of
that pointer could have changed since the time it was recorded to the time
the buffer is read. Worse yet, the bitmask could be unmapped, and the
reading of the trace buffer could actually cause a kernel oops.

Another problem is that user space tools such as perf and trace-cmd do not
have access to the contents of these pointers, and they become useless when
the tracing buffer is extracted.

Instead of having vbin_printf() simply save the pointer in the buffer for
later processing, have it perform the formatting at the time bin_printf() is
called. This will fix the issue of dereferencing pointers at a later time,
and has the extra benefit of having user space tools understand these
values.

Since perf and trace-cmd already can handle %p[sSfF] via saving kallsyms,
their pointers are saved and not processed during vbin_printf(). If they
were converted, it would break perf and trace-cmd, as they would not know
how to deal with the conversion.

Reported-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---

Changes from v1:

 - Have str increment by how much should be copied, not how much that
   was.
 - Use '\0' and not 0 for nul string terminator.

 lib/vsprintf.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 01c3957b2de6..d73e0c3fadf4 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -2516,14 +2516,15 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
 {
 	struct printf_spec spec = {0};
 	char *str, *end;
+	int width;
 
 	str = (char *)bin_buf;
 	end = (char *)(bin_buf + size);
 
 #define save_arg(type)							\
-do {									\
+({									\
+	unsigned long long value;					\
 	if (sizeof(type) == 8) {					\
-		unsigned long long value;				\
 		str = PTR_ALIGN(str, sizeof(u32));			\
 		value = va_arg(args, unsigned long long);		\
 		if (str + sizeof(type) <= end) {			\
@@ -2531,14 +2532,14 @@ do {									\
 			*(u32 *)(str + 4) = *((u32 *)&value + 1);	\
 		}							\
 	} else {							\
-		unsigned long value;					\
 		str = PTR_ALIGN(str, sizeof(type));			\
 		value = va_arg(args, int);				\
 		if (str + sizeof(type) <= end)				\
 			*(typeof(type) *)str = (type)value;		\
 	}								\
 	str += sizeof(type);						\
-} while (0)
+	value;								\
+})
 
 	while (*fmt) {
 		int read = format_decode(fmt, &spec);
@@ -2554,7 +2555,10 @@ do {									\
 
 		case FORMAT_TYPE_WIDTH:
 		case FORMAT_TYPE_PRECISION:
-			save_arg(int);
+			width = (int)save_arg(int);
+			/* Pointers may require the width */
+			if (*fmt == 'p')
+				set_field_width(&spec, width);
 			break;
 
 		case FORMAT_TYPE_CHAR:
@@ -2576,7 +2580,27 @@ do {									\
 		}
 
 		case FORMAT_TYPE_PTR:
-			save_arg(void *);
+			/* Dereferenced pointers must be done now */
+			switch (*fmt) {
+			/* Dereference of functions is still OK */
+			case 'S':
+			case 's':
+			case 'F':
+			case 'f':
+				save_arg(void *);
+				break;
+			default:
+				if (!isalnum(*fmt)) {
+					save_arg(void *);
+					break;
+				}
+				str = pointer(fmt, str, end, va_arg(args, void *),
+					      spec);
+				if (str + 1 < end)
+					*str++ = '\0';
+				else
+					end[-1] = '\0'; /* Must be nul terminated */
+			}
 			/* skip all alphanumeric pointer suffixes */
 			while (isalnum(*fmt))
 				fmt++;
@@ -2728,11 +2752,39 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
 			break;
 		}
 
-		case FORMAT_TYPE_PTR:
-			str = pointer(fmt, str, end, get_arg(void *), spec);
+		case FORMAT_TYPE_PTR: {
+			bool process = false;
+			int copy, len;
+			/* Non function dereferences were already done */
+			switch (*fmt) {
+			case 'S':
+			case 's':
+			case 'F':
+			case 'f':
+				process = true;
+				break;
+			default:
+				if (!isalnum(*fmt)) {
+					process = true;
+					break;
+				}
+				/* Pointer dereference was already processed */
+				if (str < end) {
+					len = copy = strlen(args);
+					if (copy > end - str)
+						copy = end - str;
+					memcpy(str, args, copy);
+					str += len;
+					args += len;
+				}
+			}
+			if (process)
+				str = pointer(fmt, str, end, get_arg(void *), spec);
+
 			while (isalnum(*fmt))
 				fmt++;
 			break;
+		}
 
 		case FORMAT_TYPE_PERCENT_CHAR:
 			if (str < end)
-- 
2.13.6

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] vsprintf: Do not have bprintf dereference pointers
  2017-12-29  1:40 [PATCH v2] vsprintf: Do not have bprintf dereference pointers Steven Rostedt
@ 2017-12-31 15:18 ` kbuild test robot
  0 siblings, 0 replies; 2+ messages in thread
From: kbuild test robot @ 2017-12-31 15:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: kbuild-all, LKML, Linus Torvalds, Thomas Gleixner, Andrew Morton,
	Frederic Weisbecker

[-- Attachment #1: Type: text/plain, Size: 13420 bytes --]

Hi Steven,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v4.15-rc5 next-20171222]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Steven-Rostedt/vsprintf-Do-not-have-bprintf-dereference-pointers/20171231-223129
config: i386-randconfig-x072-201753 (attached as .config)
compiler: gcc-7 (Debian 7.2.0-12) 7.2.1 20171025
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   lib/vsprintf.c: In function 'vbin_printf':
>> lib/vsprintf.c:2538:27: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       *(typeof(type) *)str = (type)value;  \
                              ^
>> lib/vsprintf.c:2590:5: note: in expansion of macro 'save_arg'
        save_arg(void *);
        ^~~~~~~~
>> lib/vsprintf.c:2538:27: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       *(typeof(type) *)str = (type)value;  \
                              ^
   lib/vsprintf.c:2594:6: note: in expansion of macro 'save_arg'
         save_arg(void *);
         ^~~~~~~~

vim +2538 lib/vsprintf.c

^1da177e4c Linus Torvalds          2005-04-16  2490  
4370aa4aa7 Lai Jiangshan           2009-03-06  2491  #ifdef CONFIG_BINARY_PRINTF
4370aa4aa7 Lai Jiangshan           2009-03-06  2492  /*
4370aa4aa7 Lai Jiangshan           2009-03-06  2493   * bprintf service:
4370aa4aa7 Lai Jiangshan           2009-03-06  2494   * vbin_printf() - VA arguments to binary data
4370aa4aa7 Lai Jiangshan           2009-03-06  2495   * bstr_printf() - Binary data to text string
4370aa4aa7 Lai Jiangshan           2009-03-06  2496   */
4370aa4aa7 Lai Jiangshan           2009-03-06  2497  
4370aa4aa7 Lai Jiangshan           2009-03-06  2498  /**
4370aa4aa7 Lai Jiangshan           2009-03-06  2499   * vbin_printf - Parse a format string and place args' binary value in a buffer
4370aa4aa7 Lai Jiangshan           2009-03-06  2500   * @bin_buf: The buffer to place args' binary value
4370aa4aa7 Lai Jiangshan           2009-03-06  2501   * @size: The size of the buffer(by words(32bits), not characters)
4370aa4aa7 Lai Jiangshan           2009-03-06  2502   * @fmt: The format string to use
4370aa4aa7 Lai Jiangshan           2009-03-06  2503   * @args: Arguments for the format string
4370aa4aa7 Lai Jiangshan           2009-03-06  2504   *
4370aa4aa7 Lai Jiangshan           2009-03-06  2505   * The format follows C99 vsnprintf, except %n is ignored, and its argument
da3dae54e4 Masanari Iida           2014-09-09  2506   * is skipped.
4370aa4aa7 Lai Jiangshan           2009-03-06  2507   *
4370aa4aa7 Lai Jiangshan           2009-03-06  2508   * The return value is the number of words(32bits) which would be generated for
4370aa4aa7 Lai Jiangshan           2009-03-06  2509   * the given input.
4370aa4aa7 Lai Jiangshan           2009-03-06  2510   *
4370aa4aa7 Lai Jiangshan           2009-03-06  2511   * NOTE:
4370aa4aa7 Lai Jiangshan           2009-03-06  2512   * If the return value is greater than @size, the resulting bin_buf is NOT
4370aa4aa7 Lai Jiangshan           2009-03-06  2513   * valid for bstr_printf().
4370aa4aa7 Lai Jiangshan           2009-03-06  2514   */
4370aa4aa7 Lai Jiangshan           2009-03-06  2515  int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
4370aa4aa7 Lai Jiangshan           2009-03-06  2516  {
fef20d9c13 Frederic Weisbecker     2009-03-06  2517  	struct printf_spec spec = {0};
4370aa4aa7 Lai Jiangshan           2009-03-06  2518  	char *str, *end;
168dccad05 Steven Rostedt (VMware  2017-12-28  2519) 	int width;
4370aa4aa7 Lai Jiangshan           2009-03-06  2520  
4370aa4aa7 Lai Jiangshan           2009-03-06  2521  	str = (char *)bin_buf;
4370aa4aa7 Lai Jiangshan           2009-03-06  2522  	end = (char *)(bin_buf + size);
4370aa4aa7 Lai Jiangshan           2009-03-06  2523  
4370aa4aa7 Lai Jiangshan           2009-03-06  2524  #define save_arg(type)							\
168dccad05 Steven Rostedt (VMware  2017-12-28  2525) ({									\
4370aa4aa7 Lai Jiangshan           2009-03-06  2526  	unsigned long long value;					\
168dccad05 Steven Rostedt (VMware  2017-12-28  2527) 	if (sizeof(type) == 8) {					\
4370aa4aa7 Lai Jiangshan           2009-03-06  2528  		str = PTR_ALIGN(str, sizeof(u32));			\
4370aa4aa7 Lai Jiangshan           2009-03-06  2529  		value = va_arg(args, unsigned long long);		\
4370aa4aa7 Lai Jiangshan           2009-03-06  2530  		if (str + sizeof(type) <= end) {			\
4370aa4aa7 Lai Jiangshan           2009-03-06  2531  			*(u32 *)str = *(u32 *)&value;			\
4370aa4aa7 Lai Jiangshan           2009-03-06  2532  			*(u32 *)(str + 4) = *((u32 *)&value + 1);	\
4370aa4aa7 Lai Jiangshan           2009-03-06  2533  		}							\
4370aa4aa7 Lai Jiangshan           2009-03-06  2534  	} else {							\
4370aa4aa7 Lai Jiangshan           2009-03-06  2535  		str = PTR_ALIGN(str, sizeof(type));			\
4370aa4aa7 Lai Jiangshan           2009-03-06  2536  		value = va_arg(args, int);				\
4370aa4aa7 Lai Jiangshan           2009-03-06  2537  		if (str + sizeof(type) <= end)				\
4370aa4aa7 Lai Jiangshan           2009-03-06 @2538  			*(typeof(type) *)str = (type)value;		\
4370aa4aa7 Lai Jiangshan           2009-03-06  2539  	}								\
4370aa4aa7 Lai Jiangshan           2009-03-06  2540  	str += sizeof(type);						\
168dccad05 Steven Rostedt (VMware  2017-12-28  2541) 	value;								\
168dccad05 Steven Rostedt (VMware  2017-12-28  2542) })
4370aa4aa7 Lai Jiangshan           2009-03-06  2543  
fef20d9c13 Frederic Weisbecker     2009-03-06  2544  	while (*fmt) {
d4be151b21 André Goddard Rosa      2009-12-14  2545  		int read = format_decode(fmt, &spec);
4370aa4aa7 Lai Jiangshan           2009-03-06  2546  
fef20d9c13 Frederic Weisbecker     2009-03-06  2547  		fmt += read;
4370aa4aa7 Lai Jiangshan           2009-03-06  2548  
fef20d9c13 Frederic Weisbecker     2009-03-06  2549  		switch (spec.type) {
fef20d9c13 Frederic Weisbecker     2009-03-06  2550  		case FORMAT_TYPE_NONE:
d4be151b21 André Goddard Rosa      2009-12-14  2551  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c13 Frederic Weisbecker     2009-03-06  2552  			break;
b006f19b05 Rasmus Villemoes        2015-11-06  2553  		case FORMAT_TYPE_INVALID:
b006f19b05 Rasmus Villemoes        2015-11-06  2554  			goto out;
4370aa4aa7 Lai Jiangshan           2009-03-06  2555  
ed681a91ab Vegard Nossum           2009-03-14  2556  		case FORMAT_TYPE_WIDTH:
fef20d9c13 Frederic Weisbecker     2009-03-06  2557  		case FORMAT_TYPE_PRECISION:
168dccad05 Steven Rostedt (VMware  2017-12-28  2558) 			width = (int)save_arg(int);
168dccad05 Steven Rostedt (VMware  2017-12-28  2559) 			/* Pointers may require the width */
168dccad05 Steven Rostedt (VMware  2017-12-28  2560) 			if (*fmt == 'p')
168dccad05 Steven Rostedt (VMware  2017-12-28  2561) 				set_field_width(&spec, width);
fef20d9c13 Frederic Weisbecker     2009-03-06  2562  			break;
4370aa4aa7 Lai Jiangshan           2009-03-06  2563  
fef20d9c13 Frederic Weisbecker     2009-03-06  2564  		case FORMAT_TYPE_CHAR:
4370aa4aa7 Lai Jiangshan           2009-03-06  2565  			save_arg(char);
fef20d9c13 Frederic Weisbecker     2009-03-06  2566  			break;
fef20d9c13 Frederic Weisbecker     2009-03-06  2567  
fef20d9c13 Frederic Weisbecker     2009-03-06  2568  		case FORMAT_TYPE_STR: {
4370aa4aa7 Lai Jiangshan           2009-03-06  2569  			const char *save_str = va_arg(args, char *);
4370aa4aa7 Lai Jiangshan           2009-03-06  2570  			size_t len;
6c35663411 André Goddard Rosa      2009-12-14  2571  
4370aa4aa7 Lai Jiangshan           2009-03-06  2572  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
4370aa4aa7 Lai Jiangshan           2009-03-06  2573  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce9 André Goddard Rosa      2009-12-14  2574  				save_str = "(null)";
6c35663411 André Goddard Rosa      2009-12-14  2575  			len = strlen(save_str) + 1;
6c35663411 André Goddard Rosa      2009-12-14  2576  			if (str + len < end)
6c35663411 André Goddard Rosa      2009-12-14  2577  				memcpy(str, save_str, len);
6c35663411 André Goddard Rosa      2009-12-14  2578  			str += len;
fef20d9c13 Frederic Weisbecker     2009-03-06  2579  			break;
4370aa4aa7 Lai Jiangshan           2009-03-06  2580  		}
fef20d9c13 Frederic Weisbecker     2009-03-06  2581  
fef20d9c13 Frederic Weisbecker     2009-03-06  2582  		case FORMAT_TYPE_PTR:
168dccad05 Steven Rostedt (VMware  2017-12-28  2583) 			/* Dereferenced pointers must be done now */
168dccad05 Steven Rostedt (VMware  2017-12-28  2584) 			switch (*fmt) {
168dccad05 Steven Rostedt (VMware  2017-12-28  2585) 			/* Dereference of functions is still OK */
168dccad05 Steven Rostedt (VMware  2017-12-28  2586) 			case 'S':
168dccad05 Steven Rostedt (VMware  2017-12-28  2587) 			case 's':
168dccad05 Steven Rostedt (VMware  2017-12-28  2588) 			case 'F':
168dccad05 Steven Rostedt (VMware  2017-12-28  2589) 			case 'f':
4370aa4aa7 Lai Jiangshan           2009-03-06 @2590  				save_arg(void *);
168dccad05 Steven Rostedt (VMware  2017-12-28  2591) 				break;
168dccad05 Steven Rostedt (VMware  2017-12-28  2592) 			default:
168dccad05 Steven Rostedt (VMware  2017-12-28  2593) 				if (!isalnum(*fmt)) {
168dccad05 Steven Rostedt (VMware  2017-12-28  2594) 					save_arg(void *);
168dccad05 Steven Rostedt (VMware  2017-12-28  2595) 					break;
168dccad05 Steven Rostedt (VMware  2017-12-28  2596) 				}
168dccad05 Steven Rostedt (VMware  2017-12-28  2597) 				str = pointer(fmt, str, end, va_arg(args, void *),
168dccad05 Steven Rostedt (VMware  2017-12-28  2598) 					      spec);
168dccad05 Steven Rostedt (VMware  2017-12-28  2599) 				if (str + 1 < end)
168dccad05 Steven Rostedt (VMware  2017-12-28  2600) 					*str++ = '\0';
168dccad05 Steven Rostedt (VMware  2017-12-28  2601) 				else
168dccad05 Steven Rostedt (VMware  2017-12-28  2602) 					end[-1] = '\0'; /* Must be nul terminated */
168dccad05 Steven Rostedt (VMware  2017-12-28  2603) 			}
4370aa4aa7 Lai Jiangshan           2009-03-06  2604  			/* skip all alphanumeric pointer suffixes */
fef20d9c13 Frederic Weisbecker     2009-03-06  2605  			while (isalnum(*fmt))
4370aa4aa7 Lai Jiangshan           2009-03-06  2606  				fmt++;
fef20d9c13 Frederic Weisbecker     2009-03-06  2607  			break;
fef20d9c13 Frederic Weisbecker     2009-03-06  2608  
fef20d9c13 Frederic Weisbecker     2009-03-06  2609  		default:
fef20d9c13 Frederic Weisbecker     2009-03-06  2610  			switch (spec.type) {
fef20d9c13 Frederic Weisbecker     2009-03-06  2611  
fef20d9c13 Frederic Weisbecker     2009-03-06  2612  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa7 Lai Jiangshan           2009-03-06  2613  				save_arg(long long);
fef20d9c13 Frederic Weisbecker     2009-03-06  2614  				break;
fef20d9c13 Frederic Weisbecker     2009-03-06  2615  			case FORMAT_TYPE_ULONG:
fef20d9c13 Frederic Weisbecker     2009-03-06  2616  			case FORMAT_TYPE_LONG:
4370aa4aa7 Lai Jiangshan           2009-03-06  2617  				save_arg(unsigned long);
fef20d9c13 Frederic Weisbecker     2009-03-06  2618  				break;
fef20d9c13 Frederic Weisbecker     2009-03-06  2619  			case FORMAT_TYPE_SIZE_T:
4370aa4aa7 Lai Jiangshan           2009-03-06  2620  				save_arg(size_t);
fef20d9c13 Frederic Weisbecker     2009-03-06  2621  				break;
fef20d9c13 Frederic Weisbecker     2009-03-06  2622  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa7 Lai Jiangshan           2009-03-06  2623  				save_arg(ptrdiff_t);
fef20d9c13 Frederic Weisbecker     2009-03-06  2624  				break;
a4e94ef0dd Zhaolei                 2009-03-27  2625  			case FORMAT_TYPE_UBYTE:
a4e94ef0dd Zhaolei                 2009-03-27  2626  			case FORMAT_TYPE_BYTE:
a4e94ef0dd Zhaolei                 2009-03-27  2627  				save_arg(char);
a4e94ef0dd Zhaolei                 2009-03-27  2628  				break;
fef20d9c13 Frederic Weisbecker     2009-03-06  2629  			case FORMAT_TYPE_USHORT:
fef20d9c13 Frederic Weisbecker     2009-03-06  2630  			case FORMAT_TYPE_SHORT:
4370aa4aa7 Lai Jiangshan           2009-03-06  2631  				save_arg(short);
fef20d9c13 Frederic Weisbecker     2009-03-06  2632  				break;
4370aa4aa7 Lai Jiangshan           2009-03-06  2633  			default:
fef20d9c13 Frederic Weisbecker     2009-03-06  2634  				save_arg(int);
fef20d9c13 Frederic Weisbecker     2009-03-06  2635  			}
4370aa4aa7 Lai Jiangshan           2009-03-06  2636  		}
4370aa4aa7 Lai Jiangshan           2009-03-06  2637  	}
fef20d9c13 Frederic Weisbecker     2009-03-06  2638  
b006f19b05 Rasmus Villemoes        2015-11-06  2639  out:
7b9186f5eb André Goddard Rosa      2009-12-14  2640  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c13 Frederic Weisbecker     2009-03-06  2641  #undef save_arg
4370aa4aa7 Lai Jiangshan           2009-03-06  2642  }
4370aa4aa7 Lai Jiangshan           2009-03-06  2643  EXPORT_SYMBOL_GPL(vbin_printf);
4370aa4aa7 Lai Jiangshan           2009-03-06  2644  

:::::: The code at line 2538 was first introduced by commit
:::::: 4370aa4aa75391a5e2e06bccb0919109f725ed8e vsprintf: add binary printf

:::::: TO: Lai Jiangshan <laijs@cn.fujitsu.com>
:::::: CC: Ingo Molnar <mingo@elte.hu>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 30060 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-12-31 15:18 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-29  1:40 [PATCH v2] vsprintf: Do not have bprintf dereference pointers Steven Rostedt
2017-12-31 15:18 ` kbuild test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®