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: o"Make __X32_SYSCALL_BIT be unsigned long" as it turned out that existing user space fails to build. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAl7Tt8YTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYobtTEACukhGsuivgiTwltWuHcATqrcNbgHSu nnhuQrjJ8KJiF5O60nDztPAVzxD+Ww2tzuDnD1BLFDI9cEA5oPhzXf7kUuJvrYUK INY+OALPPpw2iWjmygIsEyw3Pzmnm6peRA4h5UZSZdFxdROGGwBeGYNxowuVWFiH X7Fa1J4QxTI7e2X3psDVz94bOnVTPRPAR2bNpX8K8Qs+Wn1FFO92LFU04EvJTCHe JdN73VAS+0o0qPlPMewiuyfxaHexc8eJySMdOiysPnGRy+vagyyMPOV2Kg0DD6bp caDxCXNjIxXlRExV6F75s8hnl42DwXzLSzY/G7L/HVJ5r3voqcREYtXHgfenl7Jg 8o6tEi+qFduPJ6SuRjfjPBDBF4wJvcjgmCwJaPJbMkrg8p5jH9Xg35egmEMo9cF8 JQa2RzWJTR9XUjuPAuHJZR6f9jnle01PCznmw7Mavoed82udW1Lo32+QnvWsx6Qq 4uuV38FqK3lsVCfFjyZir9OB9DGeuT/NETs3WJuGW5QUnC1mqfvIYipL3BkxNMKP IBB7n5X2iCJ545JkydepXF2I+b/i8XhNcIwYMVoSbZzBKccwCZ7zxHFNj6YAWG+M TN77x/+lw5zbnxhL3YzK+fgPNLio/By4Zcpmq6uppaf9Ip67SJGVq22Ef3S0w8vG X1inh1zqLX9hsQ== =DmSb -----END PGP SIGNATURE----- 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"
This commit is contained in:
commit
8fc984aedc
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 = ¤t->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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -104,7 +104,7 @@ void exit_thread(struct task_struct *tsk)
|
|||
struct fpu *fpu = &t->fpu;
|
||||
|
||||
if (test_thread_flag(TIF_IO_BITMAP))
|
||||
io_bitmap_exit();
|
||||
io_bitmap_exit(tsk);
|
||||
|
||||
free_vm86(t);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#define _UAPI_ASM_X86_UNISTD_H
|
||||
|
||||
/* x32 syscall flag bit */
|
||||
#define __X32_SYSCALL_BIT 0x40000000UL
|
||||
#define __X32_SYSCALL_BIT 0x40000000
|
||||
|
||||
#ifndef __KERNEL__
|
||||
# ifdef __i386__
|
||||
|
|
Loading…
Reference in New Issue
Block a user