forked from Minki/linux
f81393a5b2
Mayuresh reported commit20802d8d47
("riscv: extable: add a dedicated uaccess handler") breaks the writev02 test case in LTP. This is due to the err reg isn't correctly set with the errno(-EFAULT in writev02 case). First of all, the err and zero regs are reg numbers rather than reg offsets in struct pt_regs; Secondly, regs_set_gpr() should write the regs when offset isn't zero(zero means epc) Fix it by correcting regs_set_gpr() logic and passing the correct reg offset to it. Reported-by: Mayuresh Chitale <mchitale@ventanamicro.com> Fixes:20802d8d47
("riscv: extable: add a dedicated uaccess handler") Signed-off-by: Jisheng Zhang <jszhang@kernel.org> Cc: stable@vger.kernel.org Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
72 lines
1.7 KiB
C
72 lines
1.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
|
|
* Lennox Wu <lennox.wu@sunplusct.com>
|
|
* Chen Liqin <liqin.chen@sunplusct.com>
|
|
* Copyright (C) 2013 Regents of the University of California
|
|
*/
|
|
|
|
|
|
#include <linux/bitfield.h>
|
|
#include <linux/extable.h>
|
|
#include <linux/module.h>
|
|
#include <linux/uaccess.h>
|
|
#include <asm/asm-extable.h>
|
|
#include <asm/ptrace.h>
|
|
|
|
static inline unsigned long
|
|
get_ex_fixup(const struct exception_table_entry *ex)
|
|
{
|
|
return ((unsigned long)&ex->fixup + ex->fixup);
|
|
}
|
|
|
|
static bool ex_handler_fixup(const struct exception_table_entry *ex,
|
|
struct pt_regs *regs)
|
|
{
|
|
regs->epc = get_ex_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset,
|
|
unsigned long val)
|
|
{
|
|
if (unlikely(offset > MAX_REG_OFFSET))
|
|
return;
|
|
|
|
if (offset)
|
|
*(unsigned long *)((unsigned long)regs + offset) = val;
|
|
}
|
|
|
|
static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
|
|
struct pt_regs *regs)
|
|
{
|
|
int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
|
|
int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
|
|
|
|
regs_set_gpr(regs, reg_err * sizeof(unsigned long), -EFAULT);
|
|
regs_set_gpr(regs, reg_zero * sizeof(unsigned long), 0);
|
|
|
|
regs->epc = get_ex_fixup(ex);
|
|
return true;
|
|
}
|
|
|
|
bool fixup_exception(struct pt_regs *regs)
|
|
{
|
|
const struct exception_table_entry *ex;
|
|
|
|
ex = search_exception_tables(regs->epc);
|
|
if (!ex)
|
|
return false;
|
|
|
|
switch (ex->type) {
|
|
case EX_TYPE_FIXUP:
|
|
return ex_handler_fixup(ex, regs);
|
|
case EX_TYPE_BPF:
|
|
return ex_handler_bpf(ex, regs);
|
|
case EX_TYPE_UACCESS_ERR_ZERO:
|
|
return ex_handler_uaccess_err_zero(ex, regs);
|
|
}
|
|
|
|
BUG();
|
|
}
|