Commit 3d13f313 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds
Browse files

uaccess: add force_uaccess_{begin,end} helpers

Add helpers to wrap the get_fs/set_fs magic for undoing any damange done
by set_fs(KERNEL_DS).  There is no real functional benefit, but this
documents the intent of these calls better, and will allow stubbing the
functions out easily for kernels builds that do not allow address space
overrides in the future.

[hch@lst.de: drop two incorrect hunks, fix a commit log typo]
  Link: http://lkml.kernel.org/r/20200714105505.935079-6-hch@lst.de



Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Acked-by: default avatarMark Rutland <mark.rutland@arm.com>
Acked-by: default avatarGreentime Hu <green.hu@gmail.com>
Acked-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Cc: Nick Hu <nickhu@andestech.com>
Cc: Vincent Chen <deanbo422@gmail.com>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Link: http://lkml.kernel.org/r/20200710135706.537715-6-hch@lst.de


Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 428e2976
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -180,7 +180,7 @@ static __kprobes unsigned long _sdei_handler(struct pt_regs *regs,

	/*
	 * We didn't take an exception to get here, set PAN. UAO will be cleared
	 * by sdei_event_handler()s set_fs(USER_DS) call.
	 * by sdei_event_handler()s force_uaccess_begin() call.
	 */
	__uaccess_enable_hw_pan();

+3 −3
Original line number Diff line number Diff line
@@ -85,10 +85,10 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
{
	if (vma->vm_mm == current->active_mm) {
		mm_segment_t old_fs = get_fs();
		set_fs(USER_DS);
		mm_segment_t old_fs = force_uaccess_begin();

		__flush_tlb_one(addr);
		set_fs(old_fs);
		force_uaccess_end(old_fs);
	}
}

+13 −14
Original line number Diff line number Diff line
@@ -191,17 +191,16 @@ 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 = get_fs();
			set_fs(USER_DS);
			seg = force_uaccess_begin();
			switch (insn.spec3_format.func) {
			case lhe_op:
				if (!access_ok(addr, 2)) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto sigbus;
				}
				LoadHWE(addr, value, res);
				if (res) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto fault;
				}
				compute_return_epc(regs);
@@ -209,12 +208,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
				break;
			case lwe_op:
				if (!access_ok(addr, 4)) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto sigbus;
				}
				LoadWE(addr, value, res);
				if (res) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto fault;
				}
				compute_return_epc(regs);
@@ -222,12 +221,12 @@ static void emulate_load_store_insn(struct pt_regs *regs,
				break;
			case lhue_op:
				if (!access_ok(addr, 2)) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto sigbus;
				}
				LoadHWUE(addr, value, res);
				if (res) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto fault;
				}
				compute_return_epc(regs);
@@ -235,35 +234,35 @@ static void emulate_load_store_insn(struct pt_regs *regs,
				break;
			case she_op:
				if (!access_ok(addr, 2)) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto sigbus;
				}
				compute_return_epc(regs);
				value = regs->regs[insn.spec3_format.rt];
				StoreHWE(addr, value, res);
				if (res) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto fault;
				}
				break;
			case swe_op:
				if (!access_ok(addr, 4)) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto sigbus;
				}
				compute_return_epc(regs);
				value = regs->regs[insn.spec3_format.rt];
				StoreWE(addr, value, res);
				if (res) {
					set_fs(seg);
					force_uaccess_end(seg);
					goto fault;
				}
				break;
			default:
				set_fs(seg);
				force_uaccess_end(seg);
				goto sigill;
			}
			set_fs(seg);
			force_uaccess_end(seg);
		}
#endif
		break;
+3 −4
Original line number Diff line number Diff line
@@ -512,7 +512,7 @@ int do_unaligned_access(unsigned long addr, struct pt_regs *regs)
{
	unsigned long inst;
	int ret = -EFAULT;
	mm_segment_t seg = get_fs();
	mm_segment_t seg;

	inst = get_inst(regs->ipc);

@@ -520,13 +520,12 @@ int do_unaligned_access(unsigned long addr, struct pt_regs *regs)
	      "Faulting addr: 0x%08lx, pc: 0x%08lx [inst: 0x%08lx ]\n", addr,
	      regs->ipc, inst);

	set_fs(USER_DS);

	seg = force_uaccess_begin();
	if (inst & NDS32_16BIT_INSTRUCTION)
		ret = do_16((inst >> 16) & 0xffff, regs);
	else
		ret = do_32(inst, regs);
	set_fs(seg);
	force_uaccess_end(seg);

	return ret;
}
+5 −7
Original line number Diff line number Diff line
@@ -482,8 +482,6 @@ asmlinkage void do_address_error(struct pt_regs *regs,
	error_code = lookup_exception_vector();
#endif

	oldfs = get_fs();

	if (user_mode(regs)) {
		int si_code = BUS_ADRERR;
		unsigned int user_action;
@@ -491,13 +489,13 @@ asmlinkage void do_address_error(struct pt_regs *regs,
		local_irq_enable();
		inc_unaligned_user_access();

		set_fs(USER_DS);
		oldfs = force_uaccess_begin();
		if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1),
				   sizeof(instruction))) {
			set_fs(oldfs);
			force_uaccess_end(oldfs);
			goto uspace_segv;
		}
		set_fs(oldfs);
		force_uaccess_end(oldfs);

		/* shout about userspace fixups */
		unaligned_fixups_notify(current, instruction, regs);
@@ -520,11 +518,11 @@ asmlinkage void do_address_error(struct pt_regs *regs,
			goto uspace_segv;
		}

		set_fs(USER_DS);
		oldfs = force_uaccess_begin();
		tmp = handle_unaligned_access(instruction, regs,
					      &user_mem_access, 0,
					      address);
		set_fs(oldfs);
		force_uaccess_end(oldfs);

		if (tmp == 0)
			return; /* sorted */
Loading