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

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
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
#define MAX_DMA_PFN ((16UL * 1024 * 1024) >> PAGE_SHIFT) #define MAX_DMA_PFN ((16UL * 1024 * 1024) >> PAGE_SHIFT)
/* 4GB broken PCI/AGP hardware bus master zone */ /* 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 #ifdef CONFIG_X86_32
/* The maximum address that we can perform a DMA transfer to on this platform */ /* The maximum address that we can perform a DMA transfer to on this platform */
......
...@@ -17,7 +17,7 @@ struct task_struct; ...@@ -17,7 +17,7 @@ struct task_struct;
#ifdef CONFIG_X86_IOPL_IOPERM #ifdef CONFIG_X86_IOPL_IOPERM
void io_bitmap_share(struct task_struct *tsk); 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); void native_tss_update_io_bitmap(void);
...@@ -29,7 +29,7 @@ void native_tss_update_io_bitmap(void); ...@@ -29,7 +29,7 @@ void native_tss_update_io_bitmap(void);
#else #else
static inline void io_bitmap_share(struct task_struct *tsk) { } 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) { } static inline void tss_update_io_bitmap(void) { }
#endif #endif
......
...@@ -2,8 +2,15 @@ ...@@ -2,8 +2,15 @@
#ifndef _UAPI_ASM_X86_UNISTD_H #ifndef _UAPI_ASM_X86_UNISTD_H
#define _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__ #ifndef __KERNEL__
# ifdef __i386__ # ifdef __i386__
......
...@@ -957,18 +957,31 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures) ...@@ -957,18 +957,31 @@ static inline bool xfeatures_mxcsr_quirk(u64 xfeatures)
return true; return true;
} }
/* static void fill_gap(unsigned to, void **kbuf, unsigned *pos, unsigned *count)
* 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)
{ {
if (offset < size_total) { if (*pos < to) {
unsigned int copy = min(size, size_total - offset); unsigned size = to - *pos;
if (size > *count)
size = *count;
memcpy(*kbuf, (void *)&init_fpstate.xsave + *pos, size);
*kbuf += size;
*pos += size;
*count -= size;
}
}
memcpy(kbuf + offset, data, copy); 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, ...@@ -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) 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; struct xstate_header header;
const unsigned off_mxcsr = offsetof(struct fxregs_state, mxcsr);
unsigned count = size_total;
int i; int i;
/* /*
...@@ -998,46 +1012,42 @@ int copy_xstate_to_kernel(void *kbuf, struct xregs_state *xsave, unsigned int of ...@@ -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 = xsave->header.xfeatures;
header.xfeatures &= ~XFEATURE_MASK_SUPERVISOR; 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: * Copy xregs_state->header:
*/ */
offset = offsetof(struct xregs_state, header); copy_part(offsetof(struct xregs_state, header), sizeof(header),
size = 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: * Copy only in-use xstates:
*/ */
if ((header.xfeatures >> i) & 1) { if ((header.xfeatures >> i) & 1) {
void *src = __raw_xsave_addr(xsave, i); void *src = __raw_xsave_addr(xsave, i);
offset = xstate_offsets[i]; copy_part(xstate_offsets[i], xstate_sizes[i],
size = xstate_sizes[i]; src, &kbuf, &offset_start, &count);
/* 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);
} }
} }
fill_gap(size_total, &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);
return 0; return 0;
} }
......
...@@ -33,15 +33,15 @@ void io_bitmap_share(struct task_struct *tsk) ...@@ -33,15 +33,15 @@ void io_bitmap_share(struct task_struct *tsk)
set_tsk_thread_flag(tsk, TIF_IO_BITMAP); 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) { if (t->iopl_emul == 3 || t->io_bitmap) {
/* TSS update is handled on exit to user space */ /* TSS update is handled on exit to user space */
set_thread_flag(TIF_IO_BITMAP); set_tsk_thread_flag(tsk, TIF_IO_BITMAP);
} else { } else {
clear_thread_flag(TIF_IO_BITMAP); clear_tsk_thread_flag(tsk, TIF_IO_BITMAP);
/* Invalidate TSS */ /* Invalidate TSS */
preempt_disable(); preempt_disable();
tss_update_io_bitmap(); tss_update_io_bitmap();
...@@ -49,12 +49,12 @@ static void task_update_io_bitmap(void) ...@@ -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; tsk->thread.io_bitmap = NULL;
task_update_io_bitmap(); task_update_io_bitmap(tsk);
if (iobm && refcount_dec_and_test(&iobm->refcnt)) if (iobm && refcount_dec_and_test(&iobm->refcnt))
kfree(iobm); kfree(iobm);
} }
...@@ -102,7 +102,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) ...@@ -102,7 +102,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
if (!iobm) if (!iobm)
return -ENOMEM; return -ENOMEM;
refcount_set(&iobm->refcnt, 1); 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) ...@@ -134,7 +134,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
} }
/* All permissions dropped? */ /* All permissions dropped? */
if (max_long == UINT_MAX) { if (max_long == UINT_MAX) {
io_bitmap_exit(); io_bitmap_exit(current);
return 0; return 0;
} }
...@@ -192,7 +192,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) ...@@ -192,7 +192,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
} }
t->iopl_emul = level; t->iopl_emul = level;
task_update_io_bitmap(); task_update_io_bitmap(current);
return 0; return 0;
} }
......
...@@ -96,7 +96,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) ...@@ -96,7 +96,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
} }
/* /*
* Free current thread data structures etc.. * Free thread data structures etc..
*/ */
void exit_thread(struct task_struct *tsk) void exit_thread(struct task_struct *tsk)
{ {
...@@ -104,7 +104,7 @@ void exit_thread(struct task_struct *tsk) ...@@ -104,7 +104,7 @@ void exit_thread(struct task_struct *tsk)
struct fpu *fpu = &t->fpu; struct fpu *fpu = &t->fpu;
if (test_thread_flag(TIF_IO_BITMAP)) if (test_thread_flag(TIF_IO_BITMAP))
io_bitmap_exit(); io_bitmap_exit(tsk);
free_vm86(t); free_vm86(t);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#define _UAPI_ASM_X86_UNISTD_H #define _UAPI_ASM_X86_UNISTD_H
/* x32 syscall flag bit */ /* x32 syscall flag bit */
#define __X32_SYSCALL_BIT 0x40000000UL #define __X32_SYSCALL_BIT 0x40000000
#ifndef __KERNEL__ #ifndef __KERNEL__
# ifdef __i386__ # ifdef __i386__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment