Skip to content

Commit d17b664

Browse files
solbjorntsbogend
authored andcommitted
MIPS: fix fortify panic when copying asm exception handlers
With KCFLAGS="-O3", I was able to trigger a fortify-source memcpy() overflow panic on set_vi_srs_handler(). Although O3 level is not supported in the mainline, under some conditions that may've happened with any optimization settings, it's just a matter of inlining luck. The panic itself is correct, more precisely, 50/50 false-positive and not at the same time. From the one side, no real overflow happens. Exception handler defined in asm just gets copied to some reserved places in the memory. But the reason behind is that C code refers to that exception handler declares it as `char`, i.e. something of 1 byte length. It's obvious that the asm function itself is way more than 1 byte, so fortify logics thought we are going to past the symbol declared. The standard way to refer to asm symbols from C code which is not supposed to be called from C is to declare them as `extern const u8[]`. This is fully correct from any point of view, as any code itself is just a bunch of bytes (including 0 as it is for syms like _stext/_etext/etc.), and the exact size is not known at the moment of compilation. Adjust the type of the except_vec_vi_*() and related variables. Make set_handler() take `const` as a second argument to avoid cast-away warnings and give a little more room for optimization. Signed-off-by: Alexander Lobakin <alobakin@pm.me> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
1 parent 4a0a143 commit d17b664

2 files changed

Lines changed: 12 additions & 12 deletions

File tree

arch/mips/include/asm/setup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ static inline void setup_8250_early_printk_port(unsigned long base,
1616
unsigned int reg_shift, unsigned int timeout) {}
1717
#endif
1818

19-
extern void set_handler(unsigned long offset, void *addr, unsigned long len);
19+
void set_handler(unsigned long offset, const void *addr, unsigned long len);
2020
extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
2121

2222
typedef void (*vi_handler_t)(void);

arch/mips/kernel/traps.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,19 +2091,19 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
20912091
* If no shadow set is selected then use the default handler
20922092
* that does normal register saving and standard interrupt exit
20932093
*/
2094-
extern char except_vec_vi, except_vec_vi_lui;
2095-
extern char except_vec_vi_ori, except_vec_vi_end;
2096-
extern char rollback_except_vec_vi;
2097-
char *vec_start = using_rollback_handler() ?
2098-
&rollback_except_vec_vi : &except_vec_vi;
2094+
extern const u8 except_vec_vi[], except_vec_vi_lui[];
2095+
extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
2096+
extern const u8 rollback_except_vec_vi[];
2097+
const u8 *vec_start = using_rollback_handler() ?
2098+
rollback_except_vec_vi : except_vec_vi;
20992099
#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
2100-
const int lui_offset = &except_vec_vi_lui - vec_start + 2;
2101-
const int ori_offset = &except_vec_vi_ori - vec_start + 2;
2100+
const int lui_offset = except_vec_vi_lui - vec_start + 2;
2101+
const int ori_offset = except_vec_vi_ori - vec_start + 2;
21022102
#else
2103-
const int lui_offset = &except_vec_vi_lui - vec_start;
2104-
const int ori_offset = &except_vec_vi_ori - vec_start;
2103+
const int lui_offset = except_vec_vi_lui - vec_start;
2104+
const int ori_offset = except_vec_vi_ori - vec_start;
21052105
#endif
2106-
const int handler_len = &except_vec_vi_end - vec_start;
2106+
const int handler_len = except_vec_vi_end - vec_start;
21072107

21082108
if (handler_len > VECTORSPACING) {
21092109
/*
@@ -2311,7 +2311,7 @@ void per_cpu_trap_init(bool is_boot_cpu)
23112311
}
23122312

23132313
/* Install CPU exception handler */
2314-
void set_handler(unsigned long offset, void *addr, unsigned long size)
2314+
void set_handler(unsigned long offset, const void *addr, unsigned long size)
23152315
{
23162316
#ifdef CONFIG_CPU_MICROMIPS
23172317
memcpy((void *)(ebase + offset), ((unsigned char *)addr - 1), size);

0 commit comments

Comments
 (0)