x86/ioperm: Extend IOPL config to control ioperm() as well

If iopl() is disabled, then providing ioperm() does not make much sense.

Rename the config option and disable/enable both syscalls with it. Guard
the code with #ifdefs where appropriate.

Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Thomas Gleixner 2019-11-12 21:40:33 +01:00
parent a24ca99768
commit 111e7b15cf
7 changed files with 65 additions and 20 deletions

View File

@ -1254,10 +1254,13 @@ config X86_VSYSCALL_EMULATION
Disabling this option saves about 7K of kernel size and
possibly 4K of additional runtime pagetable memory.
config X86_IOPL_EMULATION
bool "IOPL Emulation"
config X86_IOPL_IOPERM
bool "IOPERM and IOPL Emulation"
default y
---help---
This enables the ioperm() and iopl() syscalls which are necessary
for legacy applications.
Legacy IOPL support is an overbroad mechanism which allows user
space aside of accessing all 65536 I/O ports also to disable
interrupts. To gain this access the caller needs CAP_SYS_RAWIO

View File

@ -15,9 +15,15 @@ struct io_bitmap {
struct task_struct;
#ifdef CONFIG_X86_IOPL_IOPERM
void io_bitmap_share(struct task_struct *tsk);
void io_bitmap_exit(void);
void 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 tss_update_io_bitmap(void) { }
#endif
#endif

View File

@ -340,13 +340,18 @@ struct x86_hw_tss {
(offsetof(struct tss_struct, io_bitmap.mapall) - \
offsetof(struct tss_struct, x86_tss))
#ifdef CONFIG_X86_IOPL_IOPERM
/*
* sizeof(unsigned long) coming from an extra "long" at the end of the
* iobitmap. The limit is inclusive, i.e. the last valid byte.
*/
#define __KERNEL_TSS_LIMIT \
# define __KERNEL_TSS_LIMIT \
(IO_BITMAP_OFFSET_VALID_ALL + IO_BITMAP_BYTES + \
sizeof(unsigned long) - 1)
#else
# define __KERNEL_TSS_LIMIT \
(offsetof(struct tss_struct, x86_tss) + sizeof(struct x86_hw_tss) - 1)
#endif
/* Base offset outside of TSS_LIMIT so unpriviledged IO causes #GP */
#define IO_BITMAP_OFFSET_INVALID (__KERNEL_TSS_LIMIT + 1)
@ -398,7 +403,9 @@ struct tss_struct {
*/
struct x86_hw_tss x86_tss;
#ifdef CONFIG_X86_IOPL_IOPERM
struct x86_io_bitmap io_bitmap;
#endif
} __aligned(PAGE_SIZE);
DECLARE_PER_CPU_PAGE_ALIGNED(struct tss_struct, cpu_tss_rw);

View File

@ -156,8 +156,13 @@ struct thread_info {
# define _TIF_WORK_CTXSW (_TIF_WORK_CTXSW_BASE)
#endif
#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW| _TIF_USER_RETURN_NOTIFY | \
#ifdef CONFIG_X86_IOPL_IOPERM
# define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW| _TIF_USER_RETURN_NOTIFY | \
_TIF_IO_BITMAP)
#else
# define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW| _TIF_USER_RETURN_NOTIFY)
#endif
#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
#define STACK_WARN (THREAD_SIZE/8)

View File

@ -1804,6 +1804,22 @@ static inline void gdt_setup_doublefault_tss(int cpu)
}
#endif /* !CONFIG_X86_64 */
static inline void tss_setup_io_bitmap(struct tss_struct *tss)
{
tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_INVALID;
#ifdef CONFIG_X86_IOPL_IOPERM
tss->io_bitmap.prev_max = 0;
tss->io_bitmap.prev_sequence = 0;
memset(tss->io_bitmap.bitmap, 0xff, sizeof(tss->io_bitmap.bitmap));
/*
* Invalidate the extra array entry past the end of the all
* permission bitmap as required by the hardware.
*/
tss->io_bitmap.mapall[IO_BITMAP_LONGS] = ~0UL;
#endif
}
/*
* cpu_init() initializes state that is per-CPU. Some data is already
* initialized (naturally) in the bootstrap process, such as the GDT
@ -1860,15 +1876,7 @@ void cpu_init(void)
/* Initialize the TSS. */
tss_setup_ist(tss);
tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_INVALID;
tss->io_bitmap.prev_max = 0;
tss->io_bitmap.prev_sequence = 0;
memset(tss->io_bitmap.bitmap, 0xff, sizeof(tss->io_bitmap.bitmap));
/*
* Invalidate the extra array entry past the end of the all
* permission bitmap as required by the hardware.
*/
tss->io_bitmap.mapall[IO_BITMAP_LONGS] = ~0UL;
tss_setup_io_bitmap(tss);
set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
load_TR_desc();

View File

@ -14,6 +14,8 @@
#include <asm/io_bitmap.h>
#include <asm/desc.h>
#ifdef CONFIG_X86_IOPL_IOPERM
static atomic64_t io_bitmap_sequence;
void io_bitmap_share(struct task_struct *tsk)
@ -172,13 +174,6 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
struct thread_struct *t = &current->thread;
unsigned int old;
/*
* Careful: the IOPL bits in regs->flags are undefined under Xen PV
* and changing them has no effect.
*/
if (IS_ENABLED(CONFIG_X86_IOPL_NONE))
return -ENOSYS;
if (level > 3)
return -EINVAL;
@ -200,3 +195,20 @@ SYSCALL_DEFINE1(iopl, unsigned int, level)
return 0;
}
#else /* CONFIG_X86_IOPL_IOPERM */
long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
return -ENOSYS;
}
SYSCALL_DEFINE3(ioperm, unsigned long, from, unsigned long, num, int, turn_on)
{
return -ENOSYS;
}
SYSCALL_DEFINE1(iopl, unsigned int, level)
{
return -ENOSYS;
}
#endif

View File

@ -322,6 +322,7 @@ void arch_setup_new_exec(void)
}
}
#ifdef CONFIG_X86_IOPL_IOPERM
static inline void tss_invalidate_io_bitmap(struct tss_struct *tss)
{
/*
@ -409,6 +410,9 @@ void tss_update_io_bitmap(void)
tss_invalidate_io_bitmap(tss);
}
}
#else /* CONFIG_X86_IOPL_IOPERM */
static inline void switch_to_bitmap(unsigned long tifp) { }
#endif
#ifdef CONFIG_SMP