sh: fix unaligned and nonexistent address handling
unaligned and nonexistent address causes wrong exception handling in traps_32.c(handle_unaligned_access). 'handle_unalinged_ins' should return -EFAULT if address error is fixed up with kernel exception table, otherwise 'handle_unaligned_access' increases already fixed program counter and then crash. for example ioctl(fd, TCGETA, (struct termio *)-1) never return and stay in TASK_UNINTERRUPTIBLE state forever in my kernel. Signed-off-by: SUGIOKA Toshinobu <sugioka@itonet.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
eb6434d9e7
commit
2afb447f33
1 changed files with 4 additions and 5 deletions
|
@ -125,20 +125,18 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs,
|
||||||
* - userspace errors just cause EFAULT to be returned, resulting in SEGV
|
* - userspace errors just cause EFAULT to be returned, resulting in SEGV
|
||||||
* - kernel/userspace interfaces cause a jump to an appropriate handler
|
* - kernel/userspace interfaces cause a jump to an appropriate handler
|
||||||
* - other kernel errors are bad
|
* - other kernel errors are bad
|
||||||
* - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
|
|
||||||
*/
|
*/
|
||||||
static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
|
static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
|
||||||
{
|
{
|
||||||
if (!user_mode(regs)) {
|
if (!user_mode(regs)) {
|
||||||
const struct exception_table_entry *fixup;
|
const struct exception_table_entry *fixup;
|
||||||
fixup = search_exception_tables(regs->pc);
|
fixup = search_exception_tables(regs->pc);
|
||||||
if (fixup) {
|
if (fixup) {
|
||||||
regs->pc = fixup->fixup;
|
regs->pc = fixup->fixup;
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
die(str, regs, err);
|
die(str, regs, err);
|
||||||
}
|
}
|
||||||
return -EFAULT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sign_extend(unsigned int count, unsigned char *dst)
|
static inline void sign_extend(unsigned int count, unsigned char *dst)
|
||||||
|
@ -314,7 +312,8 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs,
|
||||||
/* Argh. Address not only misaligned but also non-existent.
|
/* Argh. Address not only misaligned but also non-existent.
|
||||||
* Raise an EFAULT and see if it's trapped
|
* Raise an EFAULT and see if it's trapped
|
||||||
*/
|
*/
|
||||||
return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
|
die_if_no_fixup("Fault in unaligned fixup", regs, 0);
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Reference in a new issue