x86/ioperm: Move iobitmap data into a struct
authorThomas Gleixner <tglx@linutronix.de>
Mon, 11 Nov 2019 22:03:21 +0000 (23:03 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Sat, 16 Nov 2019 10:24:02 +0000 (11:24 +0100)
No point in having all the data in thread_struct, especially as upcoming
changes add more.

Make the bitmap in the new struct accessible as array of longs and as array
of characters via a union, so both the bitmap functions and the update
logic can avoid type casts.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/include/asm/io_bitmap.h [new file with mode: 0644]
arch/x86/include/asm/processor.h
arch/x86/kernel/ioport.c
arch/x86/kernel/process.c
arch/x86/kernel/ptrace.c

diff --git a/arch/x86/include/asm/io_bitmap.h b/arch/x86/include/asm/io_bitmap.h
new file mode 100644 (file)
index 0000000..1a12b9f
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_IOBITMAP_H
+#define _ASM_X86_IOBITMAP_H
+
+#include <asm/processor.h>
+
+struct io_bitmap {
+       /* The maximum number of bytes to copy so all zero bits are covered */
+       unsigned int    max;
+       unsigned long   bitmap[IO_BITMAP_LONGS];
+};
+
+#endif
index cd7cd7d10b81b95f7d97503244562fe7923cac56..c949e0e5cbe603b61d0ed1f6862036b18505f611 100644 (file)
@@ -7,6 +7,7 @@
 /* Forward declaration, a strange C thing */
 struct task_struct;
 struct mm_struct;
+struct io_bitmap;
 struct vm86;
 
 #include <asm/math_emu.h>
@@ -501,10 +502,8 @@ struct thread_struct {
        struct vm86             *vm86;
 #endif
        /* IO permissions: */
-       unsigned long           *io_bitmap_ptr;
+       struct io_bitmap        *io_bitmap;
        unsigned long           iopl;
-       /* Max allowed port in the bitmap, in bytes: */
-       unsigned                io_bitmap_max;
 
        mm_segment_t            addr_limit;
 
@@ -862,7 +861,6 @@ static inline void spin_lock_prefetch(const void *x)
 #define INIT_THREAD  {                                                   \
        .sp0                    = TOP_OF_INIT_STACK,                      \
        .sysenter_cs            = __KERNEL_CS,                            \
-       .io_bitmap_ptr          = NULL,                                   \
        .addr_limit             = KERNEL_DS,                              \
 }
 
index 80d99bb826f3e357d6fcbc4cb66229eb09a52bed..05f77f3af46d831b9ede54ca9838235f6bdd4056 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 
+#include <asm/io_bitmap.h>
 #include <asm/desc.h>
 
 /*
@@ -21,7 +22,7 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
        unsigned int i, max_long, bytes, bytes_updated;
        struct thread_struct *t = &current->thread;
        struct tss_struct *tss;
-       unsigned long *bitmap;
+       struct io_bitmap *iobm;
 
        if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
                return -EINVAL;
@@ -34,16 +35,16 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
         * IO bitmap up. ioperm() is much less timing critical than clone(),
         * this is why we delay this operation until now:
         */
-       bitmap = t->io_bitmap_ptr;
-       if (!bitmap) {
+       iobm = t->io_bitmap;
+       if (!iobm) {
                /* No point to allocate a bitmap just to clear permissions */
                if (!turn_on)
                        return 0;
-               bitmap = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
-               if (!bitmap)
+               iobm = kmalloc(sizeof(*iobm), GFP_KERNEL);
+               if (!iobm)
                        return -ENOMEM;
 
-               memset(bitmap, 0xff, IO_BITMAP_BYTES);
+               memset(iobm->bitmap, 0xff, sizeof(iobm->bitmap));
        }
 
        /*
@@ -52,9 +53,9 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
         */
        preempt_disable();
        if (turn_on)
-               bitmap_clear(bitmap, from, num);
+               bitmap_clear(iobm->bitmap, from, num);
        else
-               bitmap_set(bitmap, from, num);
+               bitmap_set(iobm->bitmap, from, num);
 
        /*
         * Search for a (possibly new) maximum. This is simple and stupid,
@@ -62,26 +63,26 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on)
         */
        max_long = 0;
        for (i = 0; i < IO_BITMAP_LONGS; i++) {
-               if (bitmap[i] != ~0UL)
+               if (iobm->bitmap[i] != ~0UL)
                        max_long = i;
        }
 
        bytes = (max_long + 1) * sizeof(unsigned long);
-       bytes_updated = max(bytes, t->io_bitmap_max);
+       bytes_updated = max(bytes, t->io_bitmap->max);
 
        /* Update the thread data */
-       t->io_bitmap_max = bytes;
+       iobm->max = bytes;
        /*
         * Store the bitmap pointer (might be the same if the task already
         * head one). Set the TIF flag, just in case this is the first
         * invocation.
         */
-       t->io_bitmap_ptr = bitmap;
+       t->io_bitmap = iobm;
        set_thread_flag(TIF_IO_BITMAP);
 
        /* Update the TSS */
        tss = this_cpu_ptr(&cpu_tss_rw);
-       memcpy(tss->io_bitmap.bitmap, t->io_bitmap_ptr, bytes_updated);
+       memcpy(tss->io_bitmap.bitmap, iobm->bitmap, bytes_updated);
        /* Store the new end of the zero bits */
        tss->io_bitmap.prev_max = bytes;
        /* Make the bitmap base in the TSS valid */
index 35f1c80df7a8e400500edf01a8a9b426873c5731..1504fd2b9bc4b1e12467928ea1cc7102edae9af0 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/desc.h>
 #include <asm/prctl.h>
 #include <asm/spec-ctrl.h>
+#include <asm/io_bitmap.h>
 #include <asm/proto.h>
 
 #include "process.h"
@@ -101,21 +102,20 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 void exit_thread(struct task_struct *tsk)
 {
        struct thread_struct *t = &tsk->thread;
-       unsigned long *bp = t->io_bitmap_ptr;
+       struct io_bitmap *iobm = t->io_bitmap;
        struct fpu *fpu = &t->fpu;
        struct tss_struct *tss;
 
-       if (bp) {
+       if (iobm) {
                preempt_disable();
                tss = this_cpu_ptr(&cpu_tss_rw);
 
-               t->io_bitmap_ptr = NULL;
-               t->io_bitmap_max = 0;
+               t->io_bitmap = NULL;
                clear_thread_flag(TIF_IO_BITMAP);
                /* Invalidate the io bitmap base in the TSS */
                tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_INVALID;
                preempt_enable();
-               kfree(bp);
+               kfree(iobm);
        }
 
        free_vm86(t);
@@ -135,25 +135,25 @@ static int set_new_tls(struct task_struct *p, unsigned long tls)
 
 static inline int copy_io_bitmap(struct task_struct *tsk)
 {
+       struct io_bitmap *iobm = current->thread.io_bitmap;
+
        if (likely(!test_tsk_thread_flag(current, TIF_IO_BITMAP)))
                return 0;
 
-       tsk->thread.io_bitmap_ptr = kmemdup(current->thread.io_bitmap_ptr,
-                                           IO_BITMAP_BYTES, GFP_KERNEL);
-       if (!tsk->thread.io_bitmap_ptr) {
-               tsk->thread.io_bitmap_max = 0;
+       tsk->thread.io_bitmap = kmemdup(iobm, sizeof(*iobm), GFP_KERNEL);
+
+       if (!tsk->thread.io_bitmap)
                return -ENOMEM;
-       }
+
        set_tsk_thread_flag(tsk, TIF_IO_BITMAP);
        return 0;
 }
 
 static inline void free_io_bitmap(struct task_struct *tsk)
 {
-       if (tsk->thread.io_bitmap_ptr) {
-               kfree(tsk->thread.io_bitmap_ptr);
-               tsk->thread.io_bitmap_ptr = NULL;
-               tsk->thread.io_bitmap_max = 0;
+       if (tsk->thread.io_bitmap) {
+               kfree(tsk->thread.io_bitmap);
+               tsk->thread.io_bitmap = NULL;
        }
 }
 
@@ -172,7 +172,7 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
        frame->bp = 0;
        frame->ret_addr = (unsigned long) ret_from_fork;
        p->thread.sp = (unsigned long) fork_frame;
-       p->thread.io_bitmap_ptr = NULL;
+       p->thread.io_bitmap = NULL;
        memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 
 #ifdef CONFIG_X86_64
@@ -366,6 +366,8 @@ static inline void switch_to_bitmap(struct thread_struct *next,
        struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
 
        if (tifn & _TIF_IO_BITMAP) {
+               struct io_bitmap *iobm = next->io_bitmap;
+
                /*
                 * Copy at least the size of the incoming tasks bitmap
                 * which covers the last permitted I/O port.
@@ -374,11 +376,11 @@ static inline void switch_to_bitmap(struct thread_struct *next,
                 * bits permitted, then the copy needs to cover those as
                 * well so they get turned off.
                 */
-               memcpy(tss->io_bitmap.bitmap, next->io_bitmap_ptr,
-                      max(tss->io_bitmap.prev_max, next->io_bitmap_max));
+               memcpy(tss->io_bitmap.bitmap, next->io_bitmap->bitmap,
+                      max(tss->io_bitmap.prev_max, next->io_bitmap->max));
 
                /* Store the new max and set io_bitmap_base valid */
-               tss->io_bitmap.prev_max = next->io_bitmap_max;
+               tss->io_bitmap.prev_max = next->io_bitmap->max;
                tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET_VALID;
 
                /*
index 7c526741215b03fad31cc39fe2030cfaaad06692..066e5b01a7e086a515a405e81ec2eb7baef2921b 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/traps.h>
 #include <asm/syscall.h>
 #include <asm/fsgsbase.h>
+#include <asm/io_bitmap.h>
 
 #include "tls.h"
 
@@ -697,7 +698,9 @@ static int ptrace_set_debugreg(struct task_struct *tsk, int n,
 static int ioperm_active(struct task_struct *target,
                         const struct user_regset *regset)
 {
-       return DIV_ROUND_UP(target->thread.io_bitmap_max, regset->size);
+       struct io_bitmap *iobm = target->thread.io_bitmap;
+
+       return iobm ? DIV_ROUND_UP(iobm->max, regset->size) : 0;
 }
 
 static int ioperm_get(struct task_struct *target,
@@ -705,12 +708,13 @@ static int ioperm_get(struct task_struct *target,
                      unsigned int pos, unsigned int count,
                      void *kbuf, void __user *ubuf)
 {
-       if (!target->thread.io_bitmap_ptr)
+       struct io_bitmap *iobm = target->thread.io_bitmap;
+
+       if (!iobm)
                return -ENXIO;
 
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                  target->thread.io_bitmap_ptr,
-                                  0, IO_BITMAP_BYTES);
+                                  iobm->bitmap, 0, IO_BITMAP_BYTES);
 }
 
 /*