diff options
-rw-r--r-- | include/linux/printk.h | 6 | ||||
-rw-r--r-- | lib/hexdump.c | 73 | ||||
-rw-r--r-- | lib/test-hexdump.c | 45 |
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 | }; |
420 | extern void hex_dump_to_buffer(const void *buf, size_t len, | 420 | extern 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 |
424 | extern void print_hex_dump(const char *level, const char *prefix_str, | 424 | extern 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 | */ |
101 | void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, | 107 | int 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 | } |
163 | nil: | 195 | nil: |
196 | linebuf[lx] = '\0'; | ||
197 | return lx; | ||
198 | overflow2: | ||
164 | linebuf[lx++] = '\0'; | 199 | linebuf[lx++] = '\0'; |
200 | overflow1: | ||
201 | return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1; | ||
165 | } | 202 | } |
166 | EXPORT_SYMBOL(hex_dump_to_buffer); | 203 | EXPORT_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 | ||
117 | static 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 | |||
117 | static int __init test_hexdump_init(void) | 156 | static 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 | } |
134 | module_init(test_hexdump_init); | 179 | module_init(test_hexdump_init); |