2021-03-30 17:28:32

by Thomas Bogendoerfer

[permalink] [raw]
Subject: [PATCH 0/3] MIPS: Remove get_fs/set_fs

This series replaces get_fs/set_fs and removes it from MIPS arch code.

Thomas Bogendoerfer (3):
MIPS: uaccess: Added __get/__put_kernel_nofault
MIPS: uaccess: Remove get_fs/set_fs call sites
MIPS: Remove get_fs/set_fs

arch/mips/Kconfig | 1 -
arch/mips/include/asm/processor.h | 4 -
arch/mips/include/asm/thread_info.h | 6 -
arch/mips/include/asm/uaccess.h | 244 +++++++++++-----------------
arch/mips/kernel/asm-offsets.c | 1 -
arch/mips/kernel/process.c | 2 -
arch/mips/kernel/scall32-o32.S | 4 +-
arch/mips/kernel/traps.c | 72 +++-----
arch/mips/kernel/unaligned.c | 197 ++++++++--------------
arch/mips/lib/memset.S | 3 -
arch/mips/lib/strncpy_user.S | 48 ++----
arch/mips/lib/strnlen_user.S | 44 ++---
12 files changed, 215 insertions(+), 411 deletions(-)

--
2.29.2


2021-03-30 17:28:40

by Thomas Bogendoerfer

[permalink] [raw]
Subject: [PATCH 2/3] MIPS: uaccess: Remove get_fs/set_fs call sites

Use new __get_data macro to access user/kernel for functions, which
are used with user/kernel pointers. Instead of dealing with get_fs/set_fs
this macro uses a parameter to select user/kernel access.

Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/include/asm/uaccess.h | 23 ++++
arch/mips/kernel/traps.c | 72 ++++--------
arch/mips/kernel/unaligned.c | 197 ++++++++++++--------------------
3 files changed, 116 insertions(+), 176 deletions(-)

diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index c5cab0b8f902..8b3a4b992ebc 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -355,6 +355,29 @@ do { \
(val) = __gu_tmp.t; \
}

+#define __get_udata(x, ptr, size) \
+({ \
+ int __gu_err; \
+ \
+ __chk_user_ptr(ptr); \
+ __get_user_common((x), size, ptr); \
+ \
+ __gu_err; \
+})
+
+#define __get_kdata(x, ptr, size) \
+({ \
+ int __gu_err; \
+ \
+ __get_kernel_common((x), size, ptr); \
+ \
+ __gu_err; \
+})
+
+#define __get_data(x, ptr, u) \
+ (((u) == true) ? __get_udata((x), (ptr), sizeof(*(ptr))) : \
+ __get_kdata((x), (ptr), sizeof(*(ptr))))
+
#define HAVE_GET_KERNEL_NOFAULT

#define __get_kernel_nofault(dst, src, type, err_label) \
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 808b8b61ded1..6561c0c7841d 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -108,7 +108,8 @@ void (*board_bind_eic_interrupt)(int irq, int regset);
void (*board_ebase_setup)(void);
void(*board_cache_error_setup)(void);

-static void show_raw_backtrace(unsigned long reg29, const char *loglvl)
+static void show_raw_backtrace(unsigned long reg29, const char *loglvl,
+ bool user)
{
unsigned long *sp = (unsigned long *)(reg29 & ~3);
unsigned long addr;
@@ -120,7 +121,7 @@ static void show_raw_backtrace(unsigned long reg29, const char *loglvl)
while (!kstack_end(sp)) {
unsigned long __user *p =
(unsigned long __user *)(unsigned long)sp++;
- if (__get_user(addr, p)) {
+ if (__get_data(addr, p, user)) {
printk("%s (Bad stack address)", loglvl);
break;
}
@@ -141,7 +142,7 @@ __setup("raw_show_trace", set_raw_show_trace);
#endif

static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
- const char *loglvl)
+ const char *loglvl, bool user)
{
unsigned long sp = regs->regs[29];
unsigned long ra = regs->regs[31];
@@ -151,7 +152,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
task = current;

if (raw_show_trace || user_mode(regs) || !__kernel_text_address(pc)) {
- show_raw_backtrace(sp, loglvl);
+ show_raw_backtrace(sp, loglvl, user);
return;
}
printk("%sCall Trace:\n", loglvl);
@@ -167,7 +168,7 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
* with at least a bit of error checking ...
*/
static void show_stacktrace(struct task_struct *task,
- const struct pt_regs *regs, const char *loglvl)
+ const struct pt_regs *regs, const char *loglvl, bool user)
{
const int field = 2 * sizeof(unsigned long);
long stackdata;
@@ -186,7 +187,7 @@ static void show_stacktrace(struct task_struct *task,
break;
}

- if (__get_user(stackdata, sp++)) {
+ if (__get_data(stackdata, sp++, user)) {
pr_cont(" (Bad stack address)");
break;
}
@@ -195,13 +196,12 @@ static void show_stacktrace(struct task_struct *task,
i++;
}
pr_cont("\n");
- show_backtrace(task, regs, loglvl);
+ show_backtrace(task, regs, loglvl, user);
}

void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
{
struct pt_regs regs;
- mm_segment_t old_fs = get_fs();

regs.cp0_status = KSU_KERNEL;
if (sp) {
@@ -217,16 +217,10 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
prepare_frametrace(&regs);
}
}
- /*
- * show_stack() deals exclusively with kernel mode, so be sure to access
- * the stack in the kernel (not user) address space.
- */
- set_fs(KERNEL_DS);
- show_stacktrace(task, &regs, loglvl);
- set_fs(old_fs);
+ show_stacktrace(task, &regs, loglvl, false);
}

-static void show_code(unsigned int __user *pc)
+static void show_code(unsigned int __user *pc, bool user)
{
long i;
unsigned short __user *pc16 = NULL;
@@ -237,7 +231,8 @@ static void show_code(unsigned int __user *pc)
pc16 = (unsigned short __user *)((unsigned long)pc & ~1);
for(i = -3 ; i < 6 ; i++) {
unsigned int insn;
- if (pc16 ? __get_user(insn, pc16 + i) : __get_user(insn, pc + i)) {
+ if (pc16 ? __get_data(insn, pc16 + i, user) :
+ __get_data(insn, pc + i, user)) {
pr_cont(" (Bad address in epc)\n");
break;
}
@@ -356,7 +351,6 @@ void show_regs(struct pt_regs *regs)
void show_registers(struct pt_regs *regs)
{
const int field = 2 * sizeof(unsigned long);
- mm_segment_t old_fs = get_fs();

__show_regs(regs);
print_modules();
@@ -371,13 +365,9 @@ void show_registers(struct pt_regs *regs)
printk("*HwTLS: %0*lx\n", field, tls);
}

- if (!user_mode(regs))
- /* Necessary for getting the correct stack content */
- set_fs(KERNEL_DS);
- show_stacktrace(current, regs, KERN_DEFAULT);
- show_code((unsigned int __user *) regs->cp0_epc);
+ show_stacktrace(current, regs, KERN_DEFAULT, user_mode(regs));
+ show_code((unsigned int __user *) regs->cp0_epc, user_mode(regs));
printk("\n");
- set_fs(old_fs);
}

static DEFINE_RAW_SPINLOCK(die_lock);
@@ -1022,18 +1012,14 @@ asmlinkage void do_bp(struct pt_regs *regs)
unsigned long epc = msk_isa16_mode(exception_epc(regs));
unsigned int opcode, bcode;
enum ctx_state prev_state;
- mm_segment_t seg;
-
- seg = get_fs();
- if (!user_mode(regs))
- set_fs(KERNEL_DS);
+ bool user = user_mode(regs);

prev_state = exception_enter();
current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
if (get_isa16_mode(regs->cp0_epc)) {
u16 instr[2];

- if (__get_user(instr[0], (u16 __user *)epc))
+ if (__get_data(instr[0], (u16 __user *)epc, user))
goto out_sigsegv;

if (!cpu_has_mmips) {
@@ -1044,13 +1030,13 @@ asmlinkage void do_bp(struct pt_regs *regs)
bcode = instr[0] & 0xf;
} else {
/* 32-bit microMIPS BREAK */
- if (__get_user(instr[1], (u16 __user *)(epc + 2)))
+ if (__get_data(instr[1], (u16 __user *)(epc + 2), user))
goto out_sigsegv;
opcode = (instr[0] << 16) | instr[1];
bcode = (opcode >> 6) & ((1 << 20) - 1);
}
} else {
- if (__get_user(opcode, (unsigned int __user *)epc))
+ if (__get_data(opcode, (unsigned int __user *)epc, user))
goto out_sigsegv;
bcode = (opcode >> 6) & ((1 << 20) - 1);
}
@@ -1100,7 +1086,6 @@ asmlinkage void do_bp(struct pt_regs *regs)
do_trap_or_bp(regs, bcode, TRAP_BRKPT, "Break");

out:
- set_fs(seg);
exception_exit(prev_state);
return;

@@ -1114,25 +1099,21 @@ asmlinkage void do_tr(struct pt_regs *regs)
u32 opcode, tcode = 0;
enum ctx_state prev_state;
u16 instr[2];
- mm_segment_t seg;
+ bool user = user_mode(regs);
unsigned long epc = msk_isa16_mode(exception_epc(regs));

- seg = get_fs();
- if (!user_mode(regs))
- set_fs(KERNEL_DS);
-
prev_state = exception_enter();
current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
if (get_isa16_mode(regs->cp0_epc)) {
- if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
- __get_user(instr[1], (u16 __user *)(epc + 2)))
+ if (__get_data(instr[0], (u16 __user *)(epc + 0), user) ||
+ __get_data(instr[1], (u16 __user *)(epc + 2), user))
goto out_sigsegv;
opcode = (instr[0] << 16) | instr[1];
/* Immediate versions don't provide a code. */
if (!(opcode & OPCODE))
tcode = (opcode >> 12) & ((1 << 4) - 1);
} else {
- if (__get_user(opcode, (u32 __user *)epc))
+ if (__get_data(opcode, (u32 __user *)epc, user))
goto out_sigsegv;
/* Immediate versions don't provide a code. */
if (!(opcode & OPCODE))
@@ -1142,7 +1123,6 @@ asmlinkage void do_tr(struct pt_regs *regs)
do_trap_or_bp(regs, tcode, 0, "Trap");

out:
- set_fs(seg);
exception_exit(prev_state);
return;

@@ -1591,7 +1571,6 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
{
int multi_match = regs->cp0_status & ST0_TS;
enum ctx_state prev_state;
- mm_segment_t old_fs = get_fs();

prev_state = exception_enter();
show_regs(regs);
@@ -1602,12 +1581,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
dump_tlb_all();
}

- if (!user_mode(regs))
- set_fs(KERNEL_DS);
-
- show_code((unsigned int __user *) regs->cp0_epc);
-
- set_fs(old_fs);
+ show_code((unsigned int __user *) regs->cp0_epc, user_mode(regs));

/*
* Some chips may have other causes of machine check (e.g. SB1
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 126a5f3f4e4c..fa005cdee0c7 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -112,9 +112,8 @@ static void emulate_load_store_insn(struct pt_regs *regs,
unsigned long origpc, orig31, value;
union mips_instruction insn;
unsigned int res;
-#ifdef CONFIG_EVA
- mm_segment_t seg;
-#endif
+ bool user = user_mode(regs);
+
origpc = (unsigned long)pc;
orig31 = regs->regs[31];

@@ -123,7 +122,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
/*
* This load never faults.
*/
- __get_user(insn.word, pc);
+ __get_data(insn.word, pc, user);

switch (insn.i_format.opcode) {
/*
@@ -163,7 +162,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
if (insn.dsp_format.func == lx_op) {
switch (insn.dsp_format.op) {
case lwx_op:
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;
LoadW(addr, value, res);
if (res)
@@ -172,7 +171,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
regs->regs[insn.dsp_format.rd] = value;
break;
case lhx_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;
LoadHW(addr, value, res);
if (res)
@@ -191,93 +190,66 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* memory, so we need to "switch" the address limit to
* user space, so that address check can work properly.
*/
- seg = force_uaccess_begin();
switch (insn.spec3_format.func) {
case lhe_op:
- if (!access_ok(addr, 2)) {
- force_uaccess_end(seg);
+ if (!access_ok(addr, 2))
goto sigbus;
- }
LoadHWE(addr, value, res);
- if (res) {
- force_uaccess_end(seg);
+ if (res)
goto fault;
- }
compute_return_epc(regs);
regs->regs[insn.spec3_format.rt] = value;
break;
case lwe_op:
- if (!access_ok(addr, 4)) {
- force_uaccess_end(seg);
+ if (!access_ok(addr, 4))
goto sigbus;
- }
LoadWE(addr, value, res);
- if (res) {
- force_uaccess_end(seg);
+ if (res)
goto fault;
- }
compute_return_epc(regs);
regs->regs[insn.spec3_format.rt] = value;
break;
case lhue_op:
- if (!access_ok(addr, 2)) {
- force_uaccess_end(seg);
+ if (!access_ok(addr, 2))
goto sigbus;
- }
LoadHWUE(addr, value, res);
- if (res) {
- force_uaccess_end(seg);
+ if (res)
goto fault;
- }
compute_return_epc(regs);
regs->regs[insn.spec3_format.rt] = value;
break;
case she_op:
- if (!access_ok(addr, 2)) {
- force_uaccess_end(seg);
+ if (!access_ok(addr, 2))
goto sigbus;
- }
compute_return_epc(regs);
value = regs->regs[insn.spec3_format.rt];
StoreHWE(addr, value, res);
- if (res) {
- force_uaccess_end(seg);
+ if (res)
goto fault;
- }
break;
case swe_op:
- if (!access_ok(addr, 4)) {
- force_uaccess_end(seg);
+ if (!access_ok(addr, 4))
goto sigbus;
- }
compute_return_epc(regs);
value = regs->regs[insn.spec3_format.rt];
StoreWE(addr, value, res);
- if (res) {
- force_uaccess_end(seg);
+ if (res)
goto fault;
- }
break;
default:
- force_uaccess_end(seg);
goto sigill;
}
- force_uaccess_end(seg);
}
#endif
break;
case lh_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

- if (IS_ENABLED(CONFIG_EVA)) {
- if (uaccess_kernel())
- LoadHW(addr, value, res);
- else
- LoadHWE(addr, value, res);
- } else {
+ if (IS_ENABLED(CONFIG_EVA) && user)
+ LoadHWE(addr, value, res);
+ else
LoadHW(addr, value, res);
- }

if (res)
goto fault;
@@ -286,17 +258,13 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;

case lw_op:
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

- if (IS_ENABLED(CONFIG_EVA)) {
- if (uaccess_kernel())
- LoadW(addr, value, res);
- else
- LoadWE(addr, value, res);
- } else {
+ if (IS_ENABLED(CONFIG_EVA) && user)
+ LoadWE(addr, value, res);
+ else
LoadW(addr, value, res);
- }

if (res)
goto fault;
@@ -305,17 +273,13 @@ static void emulate_load_store_insn(struct pt_regs *regs,
break;

case lhu_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

- if (IS_ENABLED(CONFIG_EVA)) {
- if (uaccess_kernel())
- LoadHWU(addr, value, res);
- else
- LoadHWUE(addr, value, res);
- } else {
+ if (IS_ENABLED(CONFIG_EVA) && user)
+ LoadHWUE(addr, value, res);
+ else
LoadHWU(addr, value, res);
- }

if (res)
goto fault;
@@ -332,7 +296,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

LoadWU(addr, value, res);
@@ -355,7 +319,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

LoadDW(addr, value, res);
@@ -370,40 +334,32 @@ static void emulate_load_store_insn(struct pt_regs *regs,
goto sigill;

case sh_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

compute_return_epc(regs);
value = regs->regs[insn.i_format.rt];

- if (IS_ENABLED(CONFIG_EVA)) {
- if (uaccess_kernel())
- StoreHW(addr, value, res);
- else
- StoreHWE(addr, value, res);
- } else {
+ if (IS_ENABLED(CONFIG_EVA) && user)
+ StoreHWE(addr, value, res);
+ else
StoreHW(addr, value, res);
- }

if (res)
goto fault;
break;

case sw_op:
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

compute_return_epc(regs);
value = regs->regs[insn.i_format.rt];

- if (IS_ENABLED(CONFIG_EVA)) {
- if (uaccess_kernel())
- StoreW(addr, value, res);
- else
- StoreWE(addr, value, res);
- } else {
+ if (IS_ENABLED(CONFIG_EVA) && user)
+ StoreWE(addr, value, res);
+ else
StoreW(addr, value, res);
- }

if (res)
goto fault;
@@ -418,7 +374,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

compute_return_epc(regs);
@@ -626,6 +582,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
unsigned long origpc, contpc;
union mips_instruction insn;
struct mm_decoded_insn mminsn;
+ bool user = user_mode(regs);

origpc = regs->cp0_epc;
orig31 = regs->regs[31];
@@ -689,7 +646,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if (reg == 31)
goto sigbus;

- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

LoadW(addr, value, res);
@@ -708,7 +665,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if (reg == 31)
goto sigbus;

- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

value = regs->regs[reg];
@@ -728,7 +685,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if (reg == 31)
goto sigbus;

- if (!access_ok(addr, 16))
+ if (user && !access_ok(addr, 16))
goto sigbus;

LoadDW(addr, value, res);
@@ -751,7 +708,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if (reg == 31)
goto sigbus;

- if (!access_ok(addr, 16))
+ if (user && !access_ok(addr, 16))
goto sigbus;

value = regs->regs[reg];
@@ -774,10 +731,10 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
- if (!access_ok(addr, 4 * (rvar + 1)))
+ if (user && !access_ok(addr, 4 * (rvar + 1)))
goto sigbus;
} else {
- if (!access_ok(addr, 4 * rvar))
+ if (user && !access_ok(addr, 4 * rvar))
goto sigbus;
}
if (rvar == 9)
@@ -810,10 +767,10 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
- if (!access_ok(addr, 4 * (rvar + 1)))
+ if (user && !access_ok(addr, 4 * (rvar + 1)))
goto sigbus;
} else {
- if (!access_ok(addr, 4 * rvar))
+ if (user && !access_ok(addr, 4 * rvar))
goto sigbus;
}
if (rvar == 9)
@@ -847,10 +804,10 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
- if (!access_ok(addr, 8 * (rvar + 1)))
+ if (user && !access_ok(addr, 8 * (rvar + 1)))
goto sigbus;
} else {
- if (!access_ok(addr, 8 * rvar))
+ if (user && !access_ok(addr, 8 * rvar))
goto sigbus;
}
if (rvar == 9)
@@ -888,10 +845,10 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
if ((rvar > 9) || !reg)
goto sigill;
if (reg & 0x10) {
- if (!access_ok(addr, 8 * (rvar + 1)))
+ if (user && !access_ok(addr, 8 * (rvar + 1)))
goto sigbus;
} else {
- if (!access_ok(addr, 8 * rvar))
+ if (user && !access_ok(addr, 8 * rvar))
goto sigbus;
}
if (rvar == 9)
@@ -1010,7 +967,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
case mm_lwm16_op:
reg = insn.mm16_m_format.rlist;
rvar = reg + 1;
- if (!access_ok(addr, 4 * rvar))
+ if (user && !access_ok(addr, 4 * rvar))
goto sigbus;

for (i = 16; rvar; rvar--, i++) {
@@ -1030,7 +987,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
case mm_swm16_op:
reg = insn.mm16_m_format.rlist;
rvar = reg + 1;
- if (!access_ok(addr, 4 * rvar))
+ if (user && !access_ok(addr, 4 * rvar))
goto sigbus;

for (i = 16; rvar; rvar--, i++) {
@@ -1084,7 +1041,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
}

loadHW:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

LoadHW(addr, value, res);
@@ -1094,7 +1051,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
goto success;

loadHWU:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

LoadHWU(addr, value, res);
@@ -1104,7 +1061,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
goto success;

loadW:
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

LoadW(addr, value, res);
@@ -1122,7 +1079,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

LoadWU(addr, value, res);
@@ -1144,7 +1101,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

LoadDW(addr, value, res);
@@ -1158,7 +1115,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
goto sigill;

storeHW:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

value = regs->regs[reg];
@@ -1168,7 +1125,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
goto success;

storeW:
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

value = regs->regs[reg];
@@ -1186,7 +1143,7 @@ static void emulate_load_store_microMIPS(struct pt_regs *regs,
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

value = regs->regs[reg];
@@ -1243,6 +1200,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
union mips16e_instruction mips16inst, oldinst;
unsigned int opcode;
int extended = 0;
+ bool user = user_mode(regs);

origpc = regs->cp0_epc;
orig31 = regs->regs[31];
@@ -1344,7 +1302,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
goto sigbus;

case MIPS16e_lh_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

LoadHW(addr, value, res);
@@ -1355,7 +1313,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
break;

case MIPS16e_lhu_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

LoadHWU(addr, value, res);
@@ -1368,7 +1326,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
case MIPS16e_lw_op:
case MIPS16e_lwpc_op:
case MIPS16e_lwsp_op:
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

LoadW(addr, value, res);
@@ -1387,7 +1345,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

LoadWU(addr, value, res);
@@ -1411,7 +1369,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

LoadDW(addr, value, res);
@@ -1426,7 +1384,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
goto sigill;

case MIPS16e_sh_op:
- if (!access_ok(addr, 2))
+ if (user && !access_ok(addr, 2))
goto sigbus;

MIPS16e_compute_return_epc(regs, &oldinst);
@@ -1439,7 +1397,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
case MIPS16e_sw_op:
case MIPS16e_swsp_op:
case MIPS16e_i8_op: /* actually - MIPS16e_swrasp_func */
- if (!access_ok(addr, 4))
+ if (user && !access_ok(addr, 4))
goto sigbus;

MIPS16e_compute_return_epc(regs, &oldinst);
@@ -1459,7 +1417,7 @@ static void emulate_load_store_MIPS16e(struct pt_regs *regs, void __user * addr)
* would blow up, so for now we don't handle unaligned 64-bit
* instructions on 32-bit kernels.
*/
- if (!access_ok(addr, 8))
+ if (user && !access_ok(addr, 8))
goto sigbus;

MIPS16e_compute_return_epc(regs, &oldinst);
@@ -1516,7 +1474,6 @@ asmlinkage void do_ade(struct pt_regs *regs)
{
enum ctx_state prev_state;
unsigned int __user *pc;
- mm_segment_t seg;

prev_state = exception_enter();
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
@@ -1551,24 +1508,14 @@ asmlinkage void do_ade(struct pt_regs *regs)
show_registers(regs);

if (cpu_has_mmips) {
- seg = get_fs();
- if (!user_mode(regs))
- set_fs(KERNEL_DS);
emulate_load_store_microMIPS(regs,
(void __user *)regs->cp0_badvaddr);
- set_fs(seg);
-
return;
}

if (cpu_has_mips16) {
- seg = get_fs();
- if (!user_mode(regs))
- set_fs(KERNEL_DS);
emulate_load_store_MIPS16e(regs,
(void __user *)regs->cp0_badvaddr);
- set_fs(seg);
-
return;
}

@@ -1579,11 +1526,7 @@ asmlinkage void do_ade(struct pt_regs *regs)
show_registers(regs);
pc = (unsigned int __user *)exception_epc(regs);

- seg = get_fs();
- if (!user_mode(regs))
- set_fs(KERNEL_DS);
emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc);
- set_fs(seg);

return;

--
2.29.2

2021-03-30 17:30:34

by Thomas Bogendoerfer

[permalink] [raw]
Subject: [PATCH 1/3] MIPS: uaccess: Added __get/__put_kernel_nofault

Added __get/__put_kernel_nofault as preparation for removing
get/set_fs.

Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/include/asm/uaccess.h | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index d273a3857809..c5cab0b8f902 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -355,6 +355,18 @@ do { \
(val) = __gu_tmp.t; \
}

+#define HAVE_GET_KERNEL_NOFAULT
+
+#define __get_kernel_nofault(dst, src, type, err_label) \
+do { \
+ int __gu_err; \
+ \
+ __get_kernel_common(*((type *)(dst)), sizeof(type), \
+ (__force type *)(src)); \
+ if (unlikely(__gu_err)) \
+ goto err_label; \
+} while (0)
+
#ifndef CONFIG_EVA
#define __put_kernel_common(ptr, size) __put_user_common(ptr, size)
#else
@@ -483,6 +495,18 @@ do { \

extern void __put_user_unknown(void);

+#define __put_kernel_nofault(dst, src, type, err_label) \
+do { \
+ type __pu_val; \
+ int __pu_err = 0; \
+ \
+ __pu_val = *(__force type *)(src); \
+ __put_kernel_common(((type *)(dst)), sizeof(type)); \
+ if (unlikely(__pu_err)) \
+ goto err_label; \
+} while (0)
+
+
/*
* We're generating jump to subroutines which will be outside the range of
* jump instructions
--
2.29.2

2021-03-30 17:30:54

by Thomas Bogendoerfer

[permalink] [raw]
Subject: [PATCH 3/3] MIPS: Remove get_fs/set_fs

All get_fs/set_fs calls in MIPS code are gone, so remove implementation
of it. With the clear separation of user/kernel space access we no
longer need the EVA special handling, so get rid of that, too.

Signed-off-by: Thomas Bogendoerfer <[email protected]>
---
arch/mips/Kconfig | 1 -
arch/mips/include/asm/processor.h | 4 -
arch/mips/include/asm/thread_info.h | 6 -
arch/mips/include/asm/uaccess.h | 197 +++++++---------------------
arch/mips/kernel/asm-offsets.c | 1 -
arch/mips/kernel/process.c | 2 -
arch/mips/kernel/scall32-o32.S | 4 +-
arch/mips/lib/memset.S | 3 -
arch/mips/lib/strncpy_user.S | 48 ++-----
arch/mips/lib/strnlen_user.S | 44 ++-----
10 files changed, 75 insertions(+), 235 deletions(-)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b72458215d20..70faa0686444 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -93,7 +93,6 @@ config MIPS
select PERF_USE_VMALLOC
select PCI_MSI_ARCH_FALLBACKS if PCI_MSI
select RTC_LIB
- select SET_FS
select SYSCTL_EXCEPTION_TRACE
select VIRT_TO_BUS
select ARCH_HAS_ELFCORE_COMPAT
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 8e69e0a35ee9..0c3550c82b72 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -221,10 +221,6 @@ struct nlm_cop2_state {
#define COP2_INIT
#endif

-typedef struct {
- unsigned long seg;
-} mm_segment_t;
-
#ifdef CONFIG_CPU_HAS_MSA
# define ARCH_MIN_TASKALIGN 16
# define FPU_ALIGN __aligned(16)
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index e2c352da3877..0b17aaa9e012 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -28,11 +28,6 @@ struct thread_info {
unsigned long tp_value; /* thread pointer */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */
- mm_segment_t addr_limit; /*
- * thread address space limit:
- * 0x7fffffff for user-thead
- * 0xffffffff for kernel-thread
- */
struct pt_regs *regs;
long syscall; /* syscall number */
};
@@ -46,7 +41,6 @@ struct thread_info {
.flags = _TIF_FIXADE, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
- .addr_limit = KERNEL_DS, \
}

/*
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index 8b3a4b992ebc..5b1fd2e97f57 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -16,13 +16,6 @@
#include <asm/asm-eva.h>
#include <asm/extable.h>

-/*
- * The fs value determines whether argument validity checking should be
- * performed or not. If get_fs() == USER_DS, checking is performed, with
- * get_fs() == KERNEL_DS, checking is bypassed.
- *
- * For historical reasons, these macros are grossly misnamed.
- */
#ifdef CONFIG_32BIT

#define __UA_LIMIT 0x80000000UL
@@ -49,38 +42,6 @@ extern u64 __ua_limit;

#endif /* CONFIG_64BIT */

-/*
- * USER_DS is a bitmask that has the bits set that may not be set in a valid
- * userspace address. Note that we limit 32-bit userspace to 0x7fff8000 but
- * the arithmetic we're doing only works if the limit is a power of two, so
- * we use 0x80000000 here on 32-bit kernels. If a process passes an invalid
- * address in this range it's the process's problem, not ours :-)
- */
-
-#define KERNEL_DS ((mm_segment_t) { 0UL })
-#define USER_DS ((mm_segment_t) { __UA_LIMIT })
-
-#define get_fs() (current_thread_info()->addr_limit)
-#define set_fs(x) (current_thread_info()->addr_limit = (x))
-
-#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg)
-
-/*
- * eva_kernel_access() - determine whether kernel memory access on an EVA system
- *
- * Determines whether memory accesses should be performed to kernel memory
- * on a system using Extended Virtual Addressing (EVA).
- *
- * Return: true if a kernel memory access on an EVA system, else false.
- */
-static inline bool eva_kernel_access(void)
-{
- if (!IS_ENABLED(CONFIG_EVA))
- return false;
-
- return uaccess_kernel();
-}
-
/*
* Is a address valid? This does a straightforward calculation rather
* than tests.
@@ -118,7 +79,7 @@ static inline bool eva_kernel_access(void)
static inline int __access_ok(const void __user *p, unsigned long size)
{
unsigned long addr = (unsigned long)p;
- return (get_fs().seg & (addr | (addr + size) | __ua_size(size))) == 0;
+ return (__UA_LIMIT & (addr | (addr + size) | __ua_size(size))) == 0;
}

#define access_ok(addr, size) \
@@ -276,12 +237,9 @@ do { \
({ \
int __gu_err; \
\
- if (eva_kernel_access()) { \
- __get_kernel_common((x), size, ptr); \
- } else { \
- __chk_user_ptr(ptr); \
- __get_user_common((x), size, ptr); \
- } \
+ __chk_user_ptr(ptr); \
+ __get_user_common((x), size, ptr); \
+ \
__gu_err; \
})

@@ -291,11 +249,8 @@ do { \
const __typeof__(*(ptr)) __user * __gu_ptr = (ptr); \
\
might_fault(); \
- if (likely(access_ok( __gu_ptr, size))) { \
- if (eva_kernel_access()) \
- __get_kernel_common((x), size, __gu_ptr); \
- else \
- __get_user_common((x), size, __gu_ptr); \
+ if (likely(access_ok(__gu_ptr, size))) { \
+ __get_user_common((x), size, __gu_ptr); \
} else \
(x) = 0; \
\
@@ -452,12 +407,9 @@ do { \
int __pu_err = 0; \
\
__pu_val = (x); \
- if (eva_kernel_access()) { \
- __put_kernel_common(ptr, size); \
- } else { \
- __chk_user_ptr(ptr); \
- __put_user_common(ptr, size); \
- } \
+ __chk_user_ptr(ptr); \
+ __put_user_common(ptr, size); \
+ \
__pu_err; \
})

@@ -468,11 +420,8 @@ do { \
int __pu_err = -EFAULT; \
\
might_fault(); \
- if (likely(access_ok( __pu_addr, size))) { \
- if (eva_kernel_access()) \
- __put_kernel_common(__pu_addr, size); \
- else \
- __put_user_common(__pu_addr, size); \
+ if (likely(access_ok(__pu_addr, size))) { \
+ __put_user_common(__pu_addr, size); \
} \
\
__pu_err; \
@@ -595,15 +544,6 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
__cu_len_r; \
})

-#define __invoke_copy_from_kernel(to, from, n) \
- __invoke_copy_from(__copy_user, to, from, n)
-
-#define __invoke_copy_to_kernel(to, from, n) \
- __invoke_copy_to(__copy_user, to, from, n)
-
-#define ___invoke_copy_in_kernel(to, from, n) \
- __invoke_copy_from(__copy_user, to, from, n)
-
#ifndef CONFIG_EVA
#define __invoke_copy_from_user(to, from, n) \
__invoke_copy_from(__copy_user, to, from, n)
@@ -642,19 +582,13 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
static inline unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
{
- if (eva_kernel_access())
- return __invoke_copy_to_kernel(to, from, n);
- else
- return __invoke_copy_to_user(to, from, n);
+ return __invoke_copy_to_user(to, from, n);
}

static inline unsigned long
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
{
- if (eva_kernel_access())
- return __invoke_copy_from_kernel(to, from, n);
- else
- return __invoke_copy_from_user(to, from, n);
+ return __invoke_copy_from_user(to, from, n);
}

#define INLINE_COPY_FROM_USER
@@ -663,13 +597,9 @@ raw_copy_from_user(void *to, const void __user *from, unsigned long n)
static inline unsigned long
raw_copy_in_user(void __user*to, const void __user *from, unsigned long n)
{
- if (eva_kernel_access())
- return ___invoke_copy_in_kernel(to, from, n);
- else
- return ___invoke_copy_in_user(to, from, n);
+ return ___invoke_copy_in_user(to, from, n);
}

-extern __kernel_size_t __bzero_kernel(void __user *addr, __kernel_size_t size);
extern __kernel_size_t __bzero(void __user *addr, __kernel_size_t size);

/*
@@ -695,28 +625,16 @@ __clear_user(void __user *addr, __kernel_size_t size)
#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"
#endif /* CONFIG_CPU_MICROMIPS */

- if (eva_kernel_access()) {
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, $0\n\t"
- "move\t$6, %2\n\t"
- __MODULE_JAL(__bzero_kernel)
- "move\t%0, $6"
- : "=r" (res)
- : "r" (addr), "r" (size)
- : bzero_clobbers);
- } else {
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, $0\n\t"
- "move\t$6, %2\n\t"
- __MODULE_JAL(__bzero)
- "move\t%0, $6"
- : "=r" (res)
- : "r" (addr), "r" (size)
- : bzero_clobbers);
- }
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, $0\n\t"
+ "move\t$6, %2\n\t"
+ __MODULE_JAL(__bzero)
+ "move\t%0, $6"
+ : "=r" (res)
+ : "r" (addr), "r" (size)
+ : bzero_clobbers);

return res;
}
@@ -730,7 +648,6 @@ __clear_user(void __user *addr, __kernel_size_t size)
__cl_size; \
})

-extern long __strncpy_from_kernel_asm(char *__to, const char __user *__from, long __len);
extern long __strncpy_from_user_asm(char *__to, const char __user *__from, long __len);

/*
@@ -756,33 +673,23 @@ strncpy_from_user(char *__to, const char __user *__from, long __len)
{
long res;

- if (eva_kernel_access()) {
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- "move\t$6, %3\n\t"
- __MODULE_JAL(__strncpy_from_kernel_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (__to), "r" (__from), "r" (__len)
- : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
- } else {
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- "move\t$6, %3\n\t"
- __MODULE_JAL(__strncpy_from_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (__to), "r" (__from), "r" (__len)
- : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");
- }
+ if (!access_ok(__from, __len))
+ return -EFAULT;
+
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ "move\t$6, %3\n\t"
+ __MODULE_JAL(__strncpy_from_user_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (__to), "r" (__from), "r" (__len)
+ : "$2", "$3", "$4", "$5", "$6", __UA_t0, "$31", "memory");

return res;
}

-extern long __strnlen_kernel_asm(const char __user *s, long n);
extern long __strnlen_user_asm(const char __user *s, long n);

/*
@@ -802,26 +709,18 @@ static inline long strnlen_user(const char __user *s, long n)
{
long res;

+ if (!access_ok(s, n))
+ return -0;
+
might_fault();
- if (eva_kernel_access()) {
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- __MODULE_JAL(__strnlen_kernel_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s), "r" (n)
- : "$2", "$4", "$5", __UA_t0, "$31");
- } else {
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, %2\n\t"
- __MODULE_JAL(__strnlen_user_asm)
- "move\t%0, $2"
- : "=r" (res)
- : "r" (s), "r" (n)
- : "$2", "$4", "$5", __UA_t0, "$31");
- }
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, %2\n\t"
+ __MODULE_JAL(__strnlen_user_asm)
+ "move\t%0, $2"
+ : "=r" (res)
+ : "r" (s), "r" (n)
+ : "$2", "$4", "$5", __UA_t0, "$31");

return res;
}
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index aebfda81120a..5735b2cd6f2a 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -98,7 +98,6 @@ void output_thread_info_defines(void)
OFFSET(TI_TP_VALUE, thread_info, tp_value);
OFFSET(TI_CPU, thread_info, cpu);
OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
- OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
OFFSET(TI_REGS, thread_info, regs);
DEFINE(_THREAD_SIZE, THREAD_SIZE);
DEFINE(_THREAD_MASK, THREAD_MASK);
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 7efa0d1a4c2b..bff080db0294 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -124,7 +124,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
/* kernel thread */
unsigned long status = p->thread.cp0_status;
memset(childregs, 0, sizeof(struct pt_regs));
- ti->addr_limit = KERNEL_DS;
p->thread.reg16 = usp; /* fn */
p->thread.reg17 = kthread_arg;
p->thread.reg29 = childksp;
@@ -145,7 +144,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
childregs->regs[2] = 0; /* Child gets zero as return value */
if (usp)
childregs->regs[29] = usp;
- ti->addr_limit = USER_DS;

p->thread.reg29 = (unsigned long) childregs;
p->thread.reg31 = (unsigned long) ret_from_fork;
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 84e8624e83a2..b1b2e106f711 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -48,10 +48,8 @@ NESTED(handle_sys, PT_SIZE, sp)
* We intentionally keep the kernel stack a little below the top of
* userspace so we don't have to do a slower byte accurate check here.
*/
- lw t5, TI_ADDR_LIMIT($28)
addu t4, t0, 32
- and t5, t4
- bltz t5, bad_stack # -> sp is bad
+ bltz t4, bad_stack # -> sp is bad

/*
* Ok, copy the args from the luser stack to the kernel stack.
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index d5449e8a3dfc..b0baa3c79fad 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -314,9 +314,6 @@ EXPORT_SYMBOL(memset)
#ifndef CONFIG_EVA
FEXPORT(__bzero)
EXPORT_SYMBOL(__bzero)
-#else
-FEXPORT(__bzero_kernel)
-EXPORT_SYMBOL(__bzero_kernel)
#endif
__BUILD_BZERO LEGACY_MODE

diff --git a/arch/mips/lib/strncpy_user.S b/arch/mips/lib/strncpy_user.S
index acdff66bd5d2..556acf684d7b 100644
--- a/arch/mips/lib/strncpy_user.S
+++ b/arch/mips/lib/strncpy_user.S
@@ -29,19 +29,17 @@
* it happens at most some bytes of the exceptions handlers will be copied.
*/

- .macro __BUILD_STRNCPY_ASM func
-LEAF(__strncpy_from_\func\()_asm)
- LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
- and v0, a1
- bnez v0, .Lfault\@
-
+LEAF(__strncpy_from_user_asm)
move t0, zero
move v1, a1
-.ifeqs "\func","kernel"
-1: EX(lbu, v0, (v1), .Lfault\@)
-.else
-1: EX(lbue, v0, (v1), .Lfault\@)
-.endif
+#ifdef CONFIG_EVA
+ .set push
+ .set eva
+1: EX(lbue, v0, (v1), .Lfault)
+ .set pop
+#else
+1: EX(lbu, v0, (v1), .Lfault)
+#endif
PTR_ADDIU v1, 1
R10KCBARRIER(0(ra))
sb v0, (a0)
@@ -51,35 +49,17 @@ LEAF(__strncpy_from_\func\()_asm)
bne t0, a2, 1b
2: PTR_ADDU v0, a1, t0
xor v0, a1
- bltz v0, .Lfault\@
+ bltz v0, .Lfault
move v0, t0
jr ra # return n
- END(__strncpy_from_\func\()_asm)
+ END(__strncpy_from_user_asm)

-.Lfault\@:
+.Lfault:
li v0, -EFAULT
jr ra

.section __ex_table,"a"
- PTR 1b, .Lfault\@
+ PTR 1b, .Lfault
.previous

- .endm
-
-#ifndef CONFIG_EVA
- /* Set aliases */
- .global __strncpy_from_user_asm
- .set __strncpy_from_user_asm, __strncpy_from_kernel_asm
-EXPORT_SYMBOL(__strncpy_from_user_asm)
-#endif
-
-__BUILD_STRNCPY_ASM kernel
-EXPORT_SYMBOL(__strncpy_from_kernel_asm)
-
-#ifdef CONFIG_EVA
- .set push
- .set eva
-__BUILD_STRNCPY_ASM user
- .set pop
-EXPORT_SYMBOL(__strncpy_from_user_asm)
-#endif
+ EXPORT_SYMBOL(__strncpy_from_user_asm)
diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S
index e1bacf5a3abe..92b63f20ec05 100644
--- a/arch/mips/lib/strnlen_user.S
+++ b/arch/mips/lib/strnlen_user.S
@@ -26,12 +26,7 @@
* bytes. There's nothing secret there. On 64-bit accessing beyond
* the maximum is a tad hairier ...
*/
- .macro __BUILD_STRNLEN_ASM func
-LEAF(__strnlen_\func\()_asm)
- LONG_L v0, TI_ADDR_LIMIT($28) # pointer ok?
- and v0, a0
- bnez v0, .Lfault\@
-
+LEAF(__strnlen_user_asm)
move v0, a0
PTR_ADDU a1, a0 # stop pointer
1:
@@ -40,11 +35,14 @@ LEAF(__strnlen_\func\()_asm)
li AT, 1
#endif
beq v0, a1, 1f # limit reached?
-.ifeqs "\func", "kernel"
- EX(lb, t0, (v0), .Lfault\@)
-.else
- EX(lbe, t0, (v0), .Lfault\@)
-.endif
+#ifdef CONFIG_EVA
+ .set push
+ .set eva
+ EX(lbe, t0, (v0), .Lfault)
+ .set pop
+#else
+ EX(lb, t0, (v0), .Lfault)
+#endif
.set noreorder
bnez t0, 1b
1:
@@ -57,28 +55,10 @@ LEAF(__strnlen_\func\()_asm)
.set reorder
PTR_SUBU v0, a0
jr ra
- END(__strnlen_\func\()_asm)
+ END(__strnlen_user_asm)

-.Lfault\@:
+.Lfault:
move v0, zero
jr ra
- .endm
-
-#ifndef CONFIG_EVA
- /* Set aliases */
- .global __strnlen_user_asm
- .set __strnlen_user_asm, __strnlen_kernel_asm
-EXPORT_SYMBOL(__strnlen_user_asm)
-#endif
-
-__BUILD_STRNLEN_ASM kernel
-EXPORT_SYMBOL(__strnlen_kernel_asm)
-
-#ifdef CONFIG_EVA

- .set push
- .set eva
-__BUILD_STRNLEN_ASM user
- .set pop
-EXPORT_SYMBOL(__strnlen_user_asm)
-#endif
+ EXPORT_SYMBOL(__strnlen_user_asm)
--
2.29.2

2021-03-30 17:50:16

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 1/3] MIPS: uaccess: Added __get/__put_kernel_nofault

On Tue, Mar 30, 2021 at 07:26:58PM +0200, Thomas Bogendoerfer wrote:
> Added __get/__put_kernel_nofault as preparation for removing
> get/set_fs.

For !CONFIG_EVA __get_user_common is simply defined to
__get_kernel_common, which probably does the wrong thing here
as it would allow access to user space addresses, won't it?

2021-03-30 17:51:25

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 2/3] MIPS: uaccess: Remove get_fs/set_fs call sites

On Tue, Mar 30, 2021 at 07:26:59PM +0200, Thomas Bogendoerfer wrote:
> +#define __get_data(x, ptr, u) \
> + (((u) == true) ? __get_udata((x), (ptr), sizeof(*(ptr))) : \
> + __get_kdata((x), (ptr), sizeof(*(ptr))))
> +

I'm a little worried about exposing this in uaccess.h. Can you
have local helpers insted, preferably strongly typed for their
specific use cases?

2021-03-30 17:56:12

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 3/3] MIPS: Remove get_fs/set_fs

> - if (likely(access_ok( __gu_ptr, size))) { \
> - if (eva_kernel_access()) \
> - __get_kernel_common((x), size, __gu_ptr); \

FYI, it might be a good idea to fold __{get,put}_kernel_common into
__{get,put}_kernel_nofault now that these are the only callers left.

Similarly __get_user_common and __put_user_common should probably also
go away.

> static inline unsigned long
> raw_copy_to_user(void __user *to, const void *from, unsigned long n)
> {
> + return __invoke_copy_to_user(to, from, n);

I think __invoke_copy_to_user, __invoke_copy_from_user and
___invoke_copy_in_user can go away now as well.

2021-03-30 20:48:28

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH 2/3] MIPS: uaccess: Remove get_fs/set_fs call sites

On Tue, Mar 30, 2021 at 07:49:43PM +0200, Christoph Hellwig wrote:
> On Tue, Mar 30, 2021 at 07:26:59PM +0200, Thomas Bogendoerfer wrote:
> > +#define __get_data(x, ptr, u) \
> > + (((u) == true) ? __get_udata((x), (ptr), sizeof(*(ptr))) : \
> > + __get_kdata((x), (ptr), sizeof(*(ptr))))
> > +
>
> I'm a little worried about exposing this in uaccess.h. Can you
> have local helpers insted, preferably strongly typed for their
> specific use cases?

sure, no problem.

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]

2021-03-30 20:51:21

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH 1/3] MIPS: uaccess: Added __get/__put_kernel_nofault

On Tue, Mar 30, 2021 at 07:48:35PM +0200, Christoph Hellwig wrote:
> On Tue, Mar 30, 2021 at 07:26:58PM +0200, Thomas Bogendoerfer wrote:
> > Added __get/__put_kernel_nofault as preparation for removing
> > get/set_fs.
>
> For !CONFIG_EVA __get_user_common is simply defined to
> __get_kernel_common, which probably does the wrong thing here
> as it would allow access to user space addresses, won't it?

it does, so I'm missing a copy_from_kernel_nofault_allowed() function,
which only allows kernel access, right ?

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]

2021-03-30 22:15:38

by David Laight

[permalink] [raw]
Subject: RE: [PATCH 2/3] MIPS: uaccess: Remove get_fs/set_fs call sites

From: Christoph Hellwig
> Sent: 30 March 2021 18:50
>
> On Tue, Mar 30, 2021 at 07:26:59PM +0200, Thomas Bogendoerfer wrote:
> > +#define __get_data(x, ptr, u) \
> > + (((u) == true) ? __get_udata((x), (ptr), sizeof(*(ptr))) : \
> > + __get_kdata((x), (ptr), sizeof(*(ptr))))
> > +
>
> I'm a little worried about exposing this in uaccess.h. Can you
> have local helpers insted, preferably strongly typed for their
> specific use cases?

For things that aren't performance critical it may be worth
using a structure that contains both a kernel and user address
(one of which will be NULL) and passing the offset as a separate
parameter.

(That might have been better for the socket option buffer.)

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2021-03-31 01:40:57

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 3/3] MIPS: Remove get_fs/set_fs

Hi Thomas,

I love your patch! Yet something to improve:

[auto build test ERROR on next-20210330]
[cannot apply to linux/master hch-configfs/for-next linus/master v5.12-rc5 v5.12-rc4 v5.12-rc3 v5.12-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Thomas-Bogendoerfer/MIPS-Remove-get_fs-set_fs/20210331-013005
base: 4143e05b7b171902f4938614c2a68821e1af46bc
config: mips-allyesconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/628cb4a48f0f31c44bfc3a41b0bad05ba8b8ed3b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Thomas-Bogendoerfer/MIPS-Remove-get_fs-set_fs/20210331-013005
git checkout 628cb4a48f0f31c44bfc3a41b0bad05ba8b8ed3b
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=mips

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

arch/mips/kernel/ftrace.c: In function 'ftrace_modify_code_2':
>> arch/mips/kernel/ftrace.c:105:11: error: implicit declaration of function 'get_fs'; did you mean 'sget_fc'? [-Werror=implicit-function-declaration]
105 | old_fs = get_fs();
| ^~~~~~
| sget_fc
>> arch/mips/kernel/ftrace.c:105:11: error: incompatible types when assigning to type 'mm_segment_t' {aka 'struct <anonymous>'} from type 'int'
>> arch/mips/kernel/ftrace.c:106:2: error: implicit declaration of function 'set_fs'; did you mean 'sget_fc'? [-Werror=implicit-function-declaration]
106 | set_fs(KERNEL_DS);
| ^~~~~~
| sget_fc
>> arch/mips/kernel/ftrace.c:106:9: error: 'KERNEL_DS' undeclared (first use in this function); did you mean 'KERNFS_NS'?
106 | set_fs(KERNEL_DS);
| ^~~~~~~~~
| KERNFS_NS
arch/mips/kernel/ftrace.c:106:9: note: each undeclared identifier is reported only once for each function it appears in
arch/mips/kernel/ftrace.c: In function 'ftrace_modify_code_2r':
arch/mips/kernel/ftrace.c:129:11: error: incompatible types when assigning to type 'mm_segment_t' {aka 'struct <anonymous>'} from type 'int'
129 | old_fs = get_fs();
| ^~~~~~
arch/mips/kernel/ftrace.c:130:9: error: 'KERNEL_DS' undeclared (first use in this function); did you mean 'KERNFS_NS'?
130 | set_fs(KERNEL_DS);
| ^~~~~~~~~
| KERNFS_NS
arch/mips/kernel/ftrace.c: At top level:
arch/mips/kernel/ftrace.c:313:6: warning: no previous prototype for 'prepare_ftrace_return' [-Wmissing-prototypes]
313 | void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
| ^~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors


vim +105 arch/mips/kernel/ftrace.c

538f19526e40ce Wu Zhangjin 2009-11-20 87
58b69401c797e4 Al Cooper 2013-01-16 88 #ifndef CONFIG_64BIT
58b69401c797e4 Al Cooper 2013-01-16 89 static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
58b69401c797e4 Al Cooper 2013-01-16 90 unsigned int new_code2)
58b69401c797e4 Al Cooper 2013-01-16 91 {
58b69401c797e4 Al Cooper 2013-01-16 92 int faulted;
dce0e7d54a7104 Petri Gynther 2014-07-23 93 mm_segment_t old_fs;
58b69401c797e4 Al Cooper 2013-01-16 94
58b69401c797e4 Al Cooper 2013-01-16 95 safe_store_code(new_code1, ip, faulted);
58b69401c797e4 Al Cooper 2013-01-16 96 if (unlikely(faulted))
58b69401c797e4 Al Cooper 2013-01-16 97 return -EFAULT;
dce0e7d54a7104 Petri Gynther 2014-07-23 98
dce0e7d54a7104 Petri Gynther 2014-07-23 99 ip += 4;
dce0e7d54a7104 Petri Gynther 2014-07-23 100 safe_store_code(new_code2, ip, faulted);
dce0e7d54a7104 Petri Gynther 2014-07-23 101 if (unlikely(faulted))
dce0e7d54a7104 Petri Gynther 2014-07-23 102 return -EFAULT;
dce0e7d54a7104 Petri Gynther 2014-07-23 103
dce0e7d54a7104 Petri Gynther 2014-07-23 104 ip -= 4;
dce0e7d54a7104 Petri Gynther 2014-07-23 @105 old_fs = get_fs();
736706bee32982 Linus Torvalds 2019-03-04 @106 set_fs(KERNEL_DS);
dce0e7d54a7104 Petri Gynther 2014-07-23 107 flush_icache_range(ip, ip + 8);
dce0e7d54a7104 Petri Gynther 2014-07-23 108 set_fs(old_fs);
dce0e7d54a7104 Petri Gynther 2014-07-23 109
dce0e7d54a7104 Petri Gynther 2014-07-23 110 return 0;
dce0e7d54a7104 Petri Gynther 2014-07-23 111 }
dce0e7d54a7104 Petri Gynther 2014-07-23 112

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (5.05 kB)
.config.gz (69.04 kB)
Download all attachments

2021-03-31 11:49:04

by Thomas Bogendoerfer

[permalink] [raw]
Subject: Re: [PATCH 3/3] MIPS: Remove get_fs/set_fs

On Tue, Mar 30, 2021 at 07:54:17PM +0200, Christoph Hellwig wrote:
> > - if (likely(access_ok( __gu_ptr, size))) { \
> > - if (eva_kernel_access()) \
> > - __get_kernel_common((x), size, __gu_ptr); \
>
> FYI, it might be a good idea to fold __{get,put}_kernel_common into
> __{get,put}_kernel_nofault now that these are the only callers left.

__get_data macro used it, but I rewrote it, so I could fold in
__get/__put_kernel_common.

> Similarly __get_user_common and __put_user_common should probably also
> go away.

__get_user_common is used 3 times and __put_user_common twice. So I
left them as they are.

> > static inline unsigned long
> > raw_copy_to_user(void __user *to, const void *from, unsigned long n)
> > {
> > + return __invoke_copy_to_user(to, from, n);
>
> I think __invoke_copy_to_user, __invoke_copy_from_user and
> ___invoke_copy_in_user can go away now as well.

done.

Thomas.

--
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea. [ RFC1925, 2.3 ]