aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/printk.h6
-rw-r--r--lib/hexdump.c73
-rw-r--r--lib/test-hexdump.c45
3 files changed, 103 insertions, 21 deletions
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 4d5bf5726578..baa3f97d8ce8 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -417,9 +417,9 @@ enum {
417 DUMP_PREFIX_ADDRESS, 417 DUMP_PREFIX_ADDRESS,
418 DUMP_PREFIX_OFFSET 418 DUMP_PREFIX_OFFSET
419}; 419};
420extern void hex_dump_to_buffer(const void *buf, size_t len, 420extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
421 int rowsize, int groupsize, 421 int groupsize, char *linebuf, size_t linebuflen,
422 char *linebuf, size_t linebuflen, bool ascii); 422 bool ascii);
423#ifdef CONFIG_PRINTK 423#ifdef CONFIG_PRINTK
424extern void print_hex_dump(const char *level, const char *prefix_str, 424extern void print_hex_dump(const char *level, const char *prefix_str,
425 int prefix_type, int rowsize, int groupsize, 425 int prefix_type, int rowsize, int groupsize,
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 4af53f73c7cc..7ea09699855d 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -97,22 +97,26 @@ EXPORT_SYMBOL(bin2hex);
97 * 97 *
98 * example output buffer: 98 * example output buffer:
99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO 99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
100 *
101 * Return:
102 * The amount of bytes placed in the buffer without terminating NUL. If the
103 * output was truncated, then the return value is the number of bytes
104 * (excluding the terminating NUL) which would have been written to the final
105 * string if enough space had been available.
100 */ 106 */
101void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, 107int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
102 int groupsize, char *linebuf, size_t linebuflen, 108 char *linebuf, size_t linebuflen, bool ascii)
103 bool ascii)
104{ 109{
105 const u8 *ptr = buf; 110 const u8 *ptr = buf;
106 int ngroups; 111 int ngroups;
107 u8 ch; 112 u8 ch;
108 int j, lx = 0; 113 int j, lx = 0;
109 int ascii_column; 114 int ascii_column;
115 int ret;
110 116
111 if (rowsize != 16 && rowsize != 32) 117 if (rowsize != 16 && rowsize != 32)
112 rowsize = 16; 118 rowsize = 16;
113 119
114 if (!len)
115 goto nil;
116 if (len > rowsize) /* limit to one line at a time */ 120 if (len > rowsize) /* limit to one line at a time */
117 len = rowsize; 121 len = rowsize;
118 if (!is_power_of_2(groupsize) || groupsize > 8) 122 if (!is_power_of_2(groupsize) || groupsize > 8)
@@ -122,27 +126,50 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
122 126
123 ngroups = len / groupsize; 127 ngroups = len / groupsize;
124 ascii_column = rowsize * 2 + rowsize / groupsize + 1; 128 ascii_column = rowsize * 2 + rowsize / groupsize + 1;
129
130 if (!linebuflen)
131 goto overflow1;
132
133 if (!len)
134 goto nil;
135
125 if (groupsize == 8) { 136 if (groupsize == 8) {
126 const u64 *ptr8 = buf; 137 const u64 *ptr8 = buf;
127 138
128 for (j = 0; j < ngroups; j++) 139 for (j = 0; j < ngroups; j++) {
129 lx += scnprintf(linebuf + lx, linebuflen - lx, 140 ret = snprintf(linebuf + lx, linebuflen - lx,
130 "%s%16.16llx", j ? " " : "", 141 "%s%16.16llx", j ? " " : "",
131 (unsigned long long)*(ptr8 + j)); 142 (unsigned long long)*(ptr8 + j));
143 if (ret >= linebuflen - lx)
144 goto overflow1;
145 lx += ret;
146 }
132 } else if (groupsize == 4) { 147 } else if (groupsize == 4) {
133 const u32 *ptr4 = buf; 148 const u32 *ptr4 = buf;
134 149
135 for (j = 0; j < ngroups; j++) 150 for (j = 0; j < ngroups; j++) {
136 lx += scnprintf(linebuf + lx, linebuflen - lx, 151 ret = snprintf(linebuf + lx, linebuflen - lx,
137 "%s%8.8x", j ? " " : "", *(ptr4 + j)); 152 "%s%8.8x", j ? " " : "",
153 *(ptr4 + j));
154 if (ret >= linebuflen - lx)
155 goto overflow1;
156 lx += ret;
157 }
138 } else if (groupsize == 2) { 158 } else if (groupsize == 2) {
139 const u16 *ptr2 = buf; 159 const u16 *ptr2 = buf;
140 160
141 for (j = 0; j < ngroups; j++) 161 for (j = 0; j < ngroups; j++) {
142 lx += scnprintf(linebuf + lx, linebuflen - lx, 162 ret = snprintf(linebuf + lx, linebuflen - lx,
143 "%s%4.4x", j ? " " : "", *(ptr2 + j)); 163 "%s%4.4x", j ? " " : "",
164 *(ptr2 + j));
165 if (ret >= linebuflen - lx)
166 goto overflow1;
167 lx += ret;
168 }
144 } else { 169 } else {
145 for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { 170 for (j = 0; j < len; j++) {
171 if (linebuflen < lx + 3)
172 goto overflow2;
146 ch = ptr[j]; 173 ch = ptr[j];
147 linebuf[lx++] = hex_asc_hi(ch); 174 linebuf[lx++] = hex_asc_hi(ch);
148 linebuf[lx++] = hex_asc_lo(ch); 175 linebuf[lx++] = hex_asc_lo(ch);
@@ -154,14 +181,24 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
154 if (!ascii) 181 if (!ascii)
155 goto nil; 182 goto nil;
156 183
157 while (lx < (linebuflen - 1) && lx < ascii_column) 184 while (lx < ascii_column) {
185 if (linebuflen < lx + 2)
186 goto overflow2;
158 linebuf[lx++] = ' '; 187 linebuf[lx++] = ' ';
159 for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) { 188 }
189 for (j = 0; j < len; j++) {
190 if (linebuflen < lx + 2)
191 goto overflow2;
160 ch = ptr[j]; 192 ch = ptr[j];
161 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; 193 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
162 } 194 }
163nil: 195nil:
196 linebuf[lx] = '\0';
197 return lx;
198overflow2:
164 linebuf[lx++] = '\0'; 199 linebuf[lx++] = '\0';
200overflow1:
201 return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
165} 202}
166EXPORT_SYMBOL(hex_dump_to_buffer); 203EXPORT_SYMBOL(hex_dump_to_buffer);
167 204
diff --git a/lib/test-hexdump.c b/lib/test-hexdump.c
index 9d3bd1e9ae48..daf29a390a89 100644
--- a/lib/test-hexdump.c
+++ b/lib/test-hexdump.c
@@ -114,6 +114,45 @@ static void __init test_hexdump_set(int rowsize, bool ascii)
114 test_hexdump(len, rowsize, 1, ascii); 114 test_hexdump(len, rowsize, 1, ascii);
115} 115}
116 116
117static void __init test_hexdump_overflow(bool ascii)
118{
119 char buf[56];
120 const char *t = test_data_1_le[0];
121 size_t l = get_random_int() % sizeof(buf);
122 bool a;
123 int e, r;
124
125 memset(buf, ' ', sizeof(buf));
126
127 r = hex_dump_to_buffer(data_b, 1, 16, 1, buf, l, ascii);
128
129 if (ascii)
130 e = 50;
131 else
132 e = 2;
133 buf[e + 2] = '\0';
134
135 if (!l) {
136 a = r == e && buf[0] == ' ';
137 } else if (l < 3) {
138 a = r == e && buf[0] == '\0';
139 } else if (l < 4) {
140 a = r == e && !strcmp(buf, t);
141 } else if (ascii) {
142 if (l < 51)
143 a = r == e && buf[l - 1] == '\0' && buf[l - 2] == ' ';
144 else
145 a = r == e && buf[50] == '\0' && buf[49] == '.';
146 } else {
147 a = r == e && buf[e] == '\0';
148 }
149
150 if (!a) {
151 pr_err("Len: %zu rc: %u strlen: %zu\n", l, r, strlen(buf));
152 pr_err("Result: '%s'\n", buf);
153 }
154}
155
117static int __init test_hexdump_init(void) 156static int __init test_hexdump_init(void)
118{ 157{
119 unsigned int i; 158 unsigned int i;
@@ -129,6 +168,12 @@ static int __init test_hexdump_init(void)
129 for (i = 0; i < 16; i++) 168 for (i = 0; i < 16; i++)
130 test_hexdump_set(rowsize, true); 169 test_hexdump_set(rowsize, true);
131 170
171 for (i = 0; i < 16; i++)
172 test_hexdump_overflow(false);
173
174 for (i = 0; i < 16; i++)
175 test_hexdump_overflow(true);
176
132 return -EINVAL; 177 return -EINVAL;
133} 178}
134module_init(test_hexdump_init); 179module_init(test_hexdump_init);