mm: Fix truncated major/minor output in PID maps

The major and minor can be up to 12 bits and 20 bits long, respectively.
The current output generated after the micro-optimizations applied to
show_vma_header_prefix() only show up to 8 bits of each (2 hex digits),
resulting in the major and minor being truncated.

Fix it by introducing new optimized macros to print up to 3 and 5 hex
digits for the major and minor, respectively.

Reported-by: LoveSy <shana@zju.edu.cn>
Reported-by: 南宫雪珊 <vvb2060@gmail.com>
Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Change-Id: I2fb9abe498e401beb39500864f9ba7894b5500e3
Signed-off-by: Richard Raya <rdxzv.dev@gmail.com>
This commit is contained in:
Sultan Alsawaf 2023-02-13 21:58:42 -08:00 committed by Richard Raya
parent 403bf49c69
commit 43dba8f072

View File

@ -390,15 +390,65 @@ static int is_stack(struct vm_area_struct *vma)
__len; \
})
#define print_vma_hex2(out, val) \
#define print_vma_hex5(out, val, clz_fn) \
({ \
const typeof(val) __val = val; \
char *const __out = out; \
size_t __len; \
\
__out[1] = hex_asc[(__val >> 0) & 0xf]; \
__out[0] = hex_asc[(__val >> 4) & 0xf]; \
if (__val) { \
__len = (sizeof(__val) * 8 - clz_fn(__val) + 3) / 4; \
switch (__len) { \
case 5: \
__out[4] = hex_asc[(__val >> 0) & 0xf]; \
__out[3] = hex_asc[(__val >> 4) & 0xf]; \
__out[2] = hex_asc[(__val >> 8) & 0xf]; \
__out[1] = hex_asc[(__val >> 12) & 0xf]; \
__out[0] = hex_asc[(__val >> 16) & 0xf]; \
break; \
case 4: \
__out[3] = hex_asc[(__val >> 0) & 0xf]; \
__out[2] = hex_asc[(__val >> 4) & 0xf]; \
__out[1] = hex_asc[(__val >> 8) & 0xf]; \
__out[0] = hex_asc[(__val >> 12) & 0xf]; \
break; \
case 3: \
__out[2] = hex_asc[(__val >> 0) & 0xf]; \
__out[1] = hex_asc[(__val >> 4) & 0xf]; \
__out[0] = hex_asc[(__val >> 8) & 0xf]; \
break; \
default: \
__out[1] = hex_asc[(__val >> 0) & 0xf]; \
__out[0] = hex_asc[(__val >> 4) & 0xf]; \
__len = 2; \
break; \
} \
} else { \
*(u16 *)__out = U16_C(0x3030); \
__len = 2; \
} \
\
2; \
__len; \
})
#define print_vma_hex3(out, val, clz_fn) \
({ \
const typeof(val) __val = val; \
char *const __out = out; \
size_t __len; \
\
if (__val & 0xf00) { \
__out[2] = hex_asc[(__val >> 0) & 0xf]; \
__out[1] = hex_asc[(__val >> 4) & 0xf]; \
__out[0] = hex_asc[(__val >> 8) & 0xf]; \
__len = 3; \
} else { \
__out[1] = hex_asc[(__val >> 0) & 0xf]; \
__out[0] = hex_asc[(__val >> 4) & 0xf]; \
__len = 2; \
} \
\
__len; \
})
static int show_vma_header_prefix(struct seq_file *m, unsigned long start,
@ -410,7 +460,7 @@ static int show_vma_header_prefix(struct seq_file *m, unsigned long start,
char *out;
/* Set the overflow status to get more memory if there's no space */
if (seq_get_buf(m, &out) < 65) {
if (seq_get_buf(m, &out) < 69) {
seq_commit(m, -1);
return -ENOMEM;
}
@ -435,11 +485,11 @@ static int show_vma_header_prefix(struct seq_file *m, unsigned long start,
out[len++] = ' ';
len += print_vma_hex2(out + len, MAJOR(dev));
len += print_vma_hex3(out + len, MAJOR(dev), __builtin_clz);
out[len++] = ':';
len += print_vma_hex2(out + len, MINOR(dev));
len += print_vma_hex5(out + len, MINOR(dev), __builtin_clz);
out[len++] = ' ';