Skip to contentSkip to conversation

hexdump: fix for non-aligned buffers

PATCH Superseded Horacio Mijail Anton Quiles 2 participants 2 messages Jul 13, 2015 – Jul 14, 2015 Library code

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v5 1/1 hexdump: fix for non-aligned buffers

An hexdump with a buf not aligned to the groupsize causes non-naturally-aligned memory accesses. This was causing a kernel panic on the processor BlackFin BF527, when such an unaligned buffer was fed by the function ubifs_scanned_corruption in fs/ubifs/scan.c .

To fix this, change accesses to the contents of the buffer so they go through get_unaligned(). This change should be harmless to unaligned- access-capable architectures, and any performance hit should be anyway dwarfed by the snprintf() processing time.

---
Changes in v5:
- Instead of trying to detect non-unaligned-capable architectures, change all accesses to unconditionally use get_unaligned() (per Andrew Morton's and Geert Uytterhoeven's comments)

Changes in v4:
- Added space before "*/" (per Joe Perches' indication)

Changes in v3:
- Removed trailing whitespace (per Joe Perches' indication)
- Changed mail headers to avoid encoding issues (per Joe Perches' hint)

Changes in v2:
- Changed from ad-hoc calculation to IS_ALIGNED() for readability (per Joe Perches' indication)
- Made the explanation clearer (aligned vs naturally aligned)

---
 lib/hexdump.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
lib/hexdump.c +5 -3
index 7ea0969..e3af13c 100644
@@ -11,6 +11,7 @@
 #include <linux/ctype.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <asm/unaligned.h>
 
 const char hex_asc[] = "0123456789abcdef";
 EXPORT_SYMBOL(hex_asc);
@@ -139,7 +140,8 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
 		for (j = 0; j < ngroups; j++) {
 			ret = snprintf(linebuf + lx, linebuflen - lx,
 				       "%s%16.16llx", j ? " " : "",
-				       (unsigned long long)*(ptr8 + j));
+				       (unsigned long long)
+					       get_unaligned(ptr8 + j));
 			if (ret >= linebuflen - lx)
 				goto overflow1;
 			lx += ret;
@@ -150,7 +152,7 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
 		for (j = 0; j < ngroups; j++) {
 			ret = snprintf(linebuf + lx, linebuflen - lx,
 				       "%s%8.8x", j ? " " : "",
-				       *(ptr4 + j));
+				       get_unaligned(ptr4 + j));
 			if (ret >= linebuflen - lx)
 				goto overflow1;
 			lx += ret;
@@ -161,7 +163,7 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
 		for (j = 0; j < ngroups; j++) {
 			ret = snprintf(linebuf + lx, linebuflen - lx,
 				       "%s%4.4x", j ? " " : "",
-				       *(ptr2 + j));
+				       get_unaligned(ptr2 + j));
 			if (ret >= linebuflen - lx)
 				goto overflow1;
 			lx += ret;
Signature · 1 line
2.1.4
Acked-by on v5 1/1
#1 lore raw
Quoted 11 lines · Horacio Mijail Anton Quiles

An hexdump with a buf not aligned to the groupsize causes non-naturally-aligned memory accesses. This was causing a kernel panic on the processor BlackFin BF527, when such an unaligned buffer was fed by the function ubifs_scanned_corruption in fs/ubifs/scan.c .

To fix this, change accesses to the contents of the buffer so they go through get_unaligned(). This change should be harmless to unaligned- access-capable architectures, and any performance hit should be anyway dwarfed by the snprintf() processing time.

lib/hexdump.c int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, · line 144

Quoted 11 lines
lib/hexdump.c +2 -1
@@ -11,6 +11,7 @@
 
@@ -139,7 +140,8 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
                for (j = 0; j < ngroups; j++) {
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%16.16llx", j ? " " : "",
-                                      (unsigned long long)*(ptr8 + j));
+                                      (unsigned long long)
+                                              get_unaligned(ptr8 + j));

I think the cast to "unsigned long long" dates back to the days u64 was "unsigned long" on some 64-bit architectures.

As u64 is now "unsigned long long", it can be removed. Would you mind sending a follow-up patch to just do that?

Thanks!

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds