Commit 8fc984ae authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86-urgent-2020-05-31' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Thomas Gleixner:
 "A pile of x86 fixes:

   - Prevent a memory leak in ioperm which was caused by the stupid
     assumption that the exit cleanup is always called for current,
     which is not the case when fork fails after taking a reference on
     the ioperm bitmap.

   - Fix an arithmething overflow in the DMA code on 32bit systems

   - Fill gaps in the xstate copy with defaults instead of leaving them
     uninitialized

   - Revert: "Make __X32_SYSCALL_BIT be unsigned long" as it turned out
     that existing user space fails to build"

* tag 'x86-urgent-2020-05-31' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/ioperm: Prevent a memory leak when fork fails
  x86/dma: Fix max PFN arithmetic overflow on 32 bit systems
  copy_xstate_to_kernel(): don't leave parts of destination uninitialized
  x86/syscalls: Revert "x86/syscalls: Make __X32_SYSCALL_BIT be unsigned long"
parents 3d042823 aa61b7bb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@
#define MAX_DMA_PFN   ((16UL * 1024 * 1024) >> PAGE_SHIFT)

/* 4GB broken PCI/AGP hardware bus master zone */
#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
#define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT))

#ifdef CONFIG_X86_32
/* The maximum address that we can perform a DMA transfer to on this platform */
+2 −2
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ struct task_struct;

#ifdef CONFIG_X86_IOPL_IOPERM
void io_bitmap_share(struct task_struct *tsk);
void io_bitmap_exit(void);
void io_bitmap_exit(struct task_struct *tsk);

void native_tss_update_io_bitmap(void);

@@ -29,7 +29,7 @@ void native_tss_update_io_bitmap(void);

#else
static inline void io_bitmap_share(struct task_struct *tsk) { }
static inline void io_bitmap_exit(void) { }
static inline void io_bitmap_exit(struct task_struct *tsk) { }
static inline void tss_update_io_bitmap(void) { }
#endif

+9 −2
Original line number Diff line number Diff line
@@ -2,8 +2,15 @@
#ifndef _UAPI_ASM_X86_UNISTD_H
#define _UAPI_ASM_X86_UNISTD_H

/* x32 syscall flag bit */
#define __X32_SYSCALL_BIT	0x40000000UL
/*
 * x32 syscall flag bit.  Some user programs expect syscall NR macros
 * and __X32_SYSCALL_BIT to have type int, even though syscall numbers
 * are, for practical purposes, unsigned long.
 *
 * Fortunately, expressions like (nr & ~__X32_SYSCALL_BIT) do the right
 * thing regardless.
 */
#define __X32_SYSCALL_BIT	0x40000000

#ifndef __KERNEL__
# ifdef __i386__
+48 −38
Original line number Diff line number Diff line
@@ -957,18 +957,31 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)
	return true;
}

/*
 * This is similar to user_regset_copyout(), but will not add offset to
 * the source data pointer or increment pos, count, kbuf, and ubuf.
 */
static inline void
__copy_xstate_to_kernel(void *kbuf, const void *data,
			unsigned int offset, unsigned int size, unsigned int size_total)
static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count)
{
	if (offset < size_total) {
		unsigned int copy = min(size, size_total - offset);
	if (*pos < to) {
		unsigned size = to - *pos;

		memcpy(kbuf + offset, data, copy);
		if (size > *count)
			size = *count;
		memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
		*kbuf += size;
		*pos += size;
		*count -= size;
	}
}

static void copy_part(unsigned offset, unsigned size, void *from,
			void **kbuf, unsigned *pos, unsigned *count)
{
	fill_gap(offset, kbuf, pos, count);
	if (size > *count)
		size = *count;
	if (size) {
		memcpy(*kbuf, from, size);
		*kbuf += size;
		*pos += size;
		*count -= size;
	}
}

@@ -981,8 +994,9 @@ __copy_xstate_to_kernel(void *kbuf, const void *data,
 */
int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int offset_start, unsigned int size_total)
{
	unsigned int offset, size;
	struct xstate_header header;
	const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
	unsigned count = size_total;
	int i;

	/*
@@ -998,46 +1012,42 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of
	header.xfeatures = xsave->header.xfeatures;
	header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR;

	if (header.xfeatures & XFEATURE_MASK_FP)
		copy_part(0, off_mxcsr,
			  &xsave->i387, &kbuf, &offset_start, &count);
	if (header.xfeatures & (XFEATURE_MASK_SSE | XFEATURE_MASK_YMM))
		copy_part(off_mxcsr, MXCSR_AND_FLAGS_SIZE,
			  &xsave->i387.mxcsr, &kbuf, &offset_start, &count);
	if (header.xfeatures & XFEATURE_MASK_FP)
		copy_part(offsetof(struct fxregs_state, st_space), 128,
			  &xsave->i387.st_space, &kbuf, &offset_start, &count);
	if (header.xfeatures & XFEATURE_MASK_SSE)
		copy_part(xstate_offsets[XFEATURE_MASK_SSE], 256,
			  &xsave->i387.xmm_space, &kbuf, &offset_start, &count);
	/*
	 * Fill xsave->i387.sw_reserved value for ptrace frame:
	 */
	copy_part(offsetof(struct fxregs_state, sw_reserved), 48,
		  xstate_fx_sw_bytes, &kbuf, &offset_start, &count);
	/*
	 * Copy xregs_state->header:
	 */
	offset = offsetof(struct xregs_state, header);
	size = sizeof(header);
	copy_part(offsetof(struct xregs_state, header), sizeof(header),
		  &header, &kbuf, &offset_start, &count);

	__copy_xstate_to_kernel(kbuf, &header, offset, size, size_total);

	for (i = 0; i < XFEATURE_MAX; i++) {
	for (i = FIRST_EXTENDED_XFEATURE; i < XFEATURE_MAX; i++) {
		/*
		 * Copy only in-use xstates:
		 */
		if ((header.xfeatures >> i) & 1) {
			void *src = __raw_xsave_addr(xsave, i);

			offset = xstate_offsets[i];
			size = xstate_sizes[i];

			/* The next component has to fit fully into the output buffer: */
			if (offset + size > size_total)
				break;

			__copy_xstate_to_kernel(kbuf, src, offset, size, size_total);
		}

			copy_part(xstate_offsets[i], xstate_sizes[i],
				  src, &kbuf, &offset_start, &count);
		}

	if (xfeatures_mxcsr_quirk(header.xfeatures)) {
		offset = offsetof(struct fxregs_state, mxcsr);
		size = MXCSR_AND_FLAGS_SIZE;
		__copy_xstate_to_kernel(kbuf, &xsave->i387.mxcsr, offset, size, size_total);
	}

	/*
	 * Fill xsave->i387.sw_reserved value for ptrace frame:
	 */
	offset = offsetof(struct fxregs_state, sw_reserved);
	size = sizeof(xstate_fx_sw_bytes);

	__copy_xstate_to_kernel(kbuf, xstate_fx_sw_bytes, offset, size, size_total);
	fill_gap(size_total, &kbuf, &offset_start, &count);

	return 0;
}
+11 −11
Original line number Diff line number Diff line
@@ -33,15 +33,15 @@ void io_bitmap_share(struct task_struct *tsk)
	set_tsk_thread_flag(tsk, TIF_IO_BITMAP);
}

static void task_update_io_bitmap(void)
static void task_update_io_bitmap(struct task_struct *tsk)
{
	struct thread_struct *t = &current->thread;
	struct thread_struct *t = &tsk->thread;

	if (t->iopl_emul == 3 || t->io_bitmap) {
		/* TSS update is handled on exit to user space */
		set_thread_flag(TIF_IO_BITMAP);
		set_tsk_thread_flag(tsk, TIF_IO_BITMAP);
	} else {
		clear_thread_flag(TIF_IO_BITMAP);
		clear_tsk_thread_flag(tsk, TIF_IO_BITMAP);
		/* Invalidate TSS */
		preempt_disable();
		tss_update_io_bitmap();
@@ -49,12 +49,12 @@ static void task_update_io_bitmap(void)
	}
}

void io_bitmap_exit(void)
void io_bitmap_exit(struct task_struct *tsk)
{
	struct io_bitmap *iobm = current->thread.io_bitmap;
	struct io_bitmap *iobm = tsk->thread.io_bitmap;

	current->thread.io_bitmap = NULL;
	task_update_io_bitmap();
	tsk->thread.io_bitmap = NULL;
	task_update_io_bitmap(tsk);
	if (iobm && refcount_dec_and_test(&iobm->refcnt))
		kfree(iobm);
}
@@ -102,7 +102,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
		if (!iobm)
			return -ENOMEM;
		refcount_set(&iobm->refcnt, 1);
		io_bitmap_exit();
		io_bitmap_exit(current);
	}

	/*
@@ -134,7 +134,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
	}
	/* All permissions dropped? */
	if (max_long == UINT_MAX) {
		io_bitmap_exit();
		io_bitmap_exit(current);
		return 0;
	}

@@ -192,7 +192,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
	}

	t->iopl_emul = level;
	task_update_io_bitmap();
	task_update_io_bitmap(current);

	return 0;
}
Loading