]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - lib/vsprintf.c
lib/vsprintf.c: warn about too large precisions and field widths
[mirror_ubuntu-bionic-kernel.git] / lib / vsprintf.c
index 8056dff6de642d2db005d185b60b64e29dd0d73a..bdc4985b1ea71cc356bb165e8f70408aac10246e 100644 (file)
@@ -389,6 +389,8 @@ struct printf_spec {
        unsigned int    base:8;         /* number base, 8, 10 or 16 only */
        signed int      precision:16;   /* # of digits/chars */
 } __packed;
+#define FIELD_WIDTH_MAX ((1 << 23) - 1)
+#define PRECISION_MAX ((1 << 15) - 1)
 
 static noinline_for_stack
 char *number(char *buf, char *end, unsigned long long num,
@@ -1845,6 +1847,24 @@ qualifier:
        return ++fmt - start;
 }
 
+static void
+set_field_width(struct printf_spec *spec, int width)
+{
+       spec->field_width = width;
+       if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
+               spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
+       }
+}
+
+static void
+set_precision(struct printf_spec *spec, int prec)
+{
+       spec->precision = prec;
+       if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
+               spec->precision = clamp(prec, 0, PRECISION_MAX);
+       }
+}
+
 /**
  * vsnprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
@@ -1912,11 +1932,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
                }
 
                case FORMAT_TYPE_WIDTH:
-                       spec.field_width = va_arg(args, int);
+                       set_field_width(&spec, va_arg(args, int));
                        break;
 
                case FORMAT_TYPE_PRECISION:
-                       spec.precision = va_arg(args, int);
+                       set_precision(&spec, va_arg(args, int));
                        break;
 
                case FORMAT_TYPE_CHAR: {
@@ -2356,11 +2376,11 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
                }
 
                case FORMAT_TYPE_WIDTH:
-                       spec.field_width = get_arg(int);
+                       set_field_width(&spec, get_arg(int));
                        break;
 
                case FORMAT_TYPE_PRECISION:
-                       spec.precision = get_arg(int);
+                       set_precision(&spec, get_arg(int));
                        break;
 
                case FORMAT_TYPE_CHAR: {