From: Thomas Gleixner <tglx@linutronix.de>
To: reveliofuzzing <reveliofuzzing@gmail.com>,
Dave Hansen <dave.hansen@intel.com>
Cc: mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com,
kirill.shutemov@linux.intel.com, x86@kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: reproducible GPF error in native_tss_update_io_bitmap
Date: Wed, 15 Jan 2025 15:22:14 +0100 [thread overview]
Message-ID: <871px4cg2x.ffs@tglx> (raw)
In-Reply-To: <CA+-ZZ_jfkdgs+cz+HED+0k2tDFpuDgev9pBDYF0hYuAnO5yOCg@mail.gmail.com>
On Tue, Jan 07 2025 at 19:24, reveliofuzzing@gmail.com wrote:
> On Tue, Jan 7, 2025 at 4:28 PM Dave Hansen <dave.hansen@intel.com> wrote:
>>
>> On 1/6/25 18:32, reveliofuzzing wrote:
>> > Hello,
>> >
>> > We found the following general protection fault bug in Linux kernel 6.12, and
>> > it can be reproduced stably in a QEMU VM. To our knowledge, this problem has not
>> > been observed by SyzBot so we would like to report it for your reference.
>> >
>> > - dmesg
>> > syzkaller login: [ 90.849309] Oops: general protection fault,
>> > probably for non-canonical address 0xdffffc0000000000: 0000 [#1]
>> > PREEMPTI
>> > [ 90.853735] KASAN: null-ptr-deref in range
>> > [0x0000000000000000-0x0000000000000007]
>> > [ 90.856772] CPU: 0 PID: 3265 Comm: iou-sqp-3264 Not tainted 6.10.0 #2
>> > [ 90.859386] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
>> > BIOS 1.13.0-1ubuntu1.1 04/01/2014
>> > [ 90.862774] RIP: 0010:native_tss_update_io_bitmap+0x143/0x510
>>
>> The whole thing looks like an issue in the failure path when trying to
>> create an io_uring io worker thread. It's probably some confusion in
>> treating the worker thread like a userspace thread with an io bitmap
>> when the worker thread doesn't have one.
>>
>> It's _probably_ only reproducible with io_uring. It's arguable whether
>> it's likely an x86 issue or an io_uring issue.
>>
>> In any case, running:
>>
>> scripts/decode_stacktrace.sh
>>
> Here is the output of running this script:
So looking at it from the call chain:
> [ 90.935319] copy_process (linux-6.12/kernel/fork.c:1764
This means copy_process() failed at some point and then invokes:
> [ 90.933995] exit_thread (linux-6.12/arch/x86/kernel/process.c:122)
which in turn invokes:
> [ 90.932599] io_bitmap_exit (linux-6.12/arch/x86/kernel/ioport.c:58)
> linux-6.12/arch/x86/kernel/ioport.c:36 - task_update_io_bitmap()
> linux-6.12/arch/x86/kernel/ioport.c:48 - tss_update_io_bitmap()
which ends up in native_tss_update_io_bitmap()
> [ 90.853735] KASAN: null-ptr-deref in range
> [0x0000000000000000-0x0000000000000007]
> [ 90.856772] CPU: 0 PID: 3265 Comm: iou-sqp-3264 Not tainted 6.10.0 #2
> [ 90.859386] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
> BIOS 1.13.0-1ubuntu1.1 04/01/2014
> [ 90.862774] RIP: 0010:native_tss_update_io_bitmap
> (linux-6.12/arch/x86/kernel/process.c:470)
Which is this code:
if (tss->io_bitmap.prev_sequence != iobm->sequence)
where @iobm is NULL.
But to reach that code it's required that the current task has
TIF_IO_BITMAP set, which is wrong to begin with.
The context of this is:
[ 90.963627] io_sq_thread+0xaf9/0x1620
which is a IO worker thread created via io_uring_setup(). So that thread
inherits the user space thread TIF flags and indeed the syzkaller
reproducer does:
syscall(__NR_ioperm, /*from=*/0ul, /*num=*/0xd8ul, /*on=*/0x80000000ul);
before invoking the io_uring setup.
That inheritance is wrong and easy to fix, but that does not explain the
actual failure. That's a bit more subtle.
copy_thread() sets p->thread.io_bitmap to NULL, leaves TIF_IO_BITMAP set
and then returns before sharing the bitmap of the parent thread.
Now copy_process() fails after copy_thread() and invokes exit_thread()
and due to TIF_IO_BITMAP being set it calls io_bitmap_exit(). The latter
invokes task_update_io_bitmap(), which clears the newly created thread's
IO_BITMAP flag because the new thread has neither iopl_emul == 3 nor a
io_valid bitmap.
task_update_io_bitmap() then invokes tss_update_io_bitmap(), which
checks the current thread's TIF_IO_BITMAP bit, which is set, but the
io_sq_thread (current) does neither have iopl_emul == 3 nor a bitmap
pointer. Game over.
Invoking task_update_io_bitmap() in the failure path of copy_process()
is completely wrong as the newly created task never got active and
therefore has never changed the TSS side. So invalidating or updating
anything here is just bogus. The only important part is to drop the
reference count on the bitmap if it got shared in copy_thread().
Tentative uncompiled fix below.
Thanks,
tglx
---
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
index e2fab3ceb09f..fa7113babc8e 100644
--- a/arch/x86/kernel/ioport.c
+++ b/arch/x86/kernel/ioport.c
@@ -21,6 +21,9 @@ static atomic64_t io_bitmap_sequence;
void io_bitmap_share(struct task_struct *tsk)
{
+ /* Inherit the IOPL level of the parent */
+ tsk->thread.iopl_emul = current->thread.iopl_emul;
+
/* Can be NULL when current->thread.iopl_emul == 3 */
if (current->thread.io_bitmap) {
/*
@@ -54,7 +57,12 @@ void io_bitmap_exit(struct task_struct *tsk)
struct io_bitmap *iobm = tsk->thread.io_bitmap;
tsk->thread.io_bitmap = NULL;
- task_update_io_bitmap(tsk);
+ /*
+ * Only update when a task is exiting, not when a newly created
+ * task is mopped up in the failure path of copy_process().
+ */
+ if (tsk == current)
+ task_update_io_bitmap(tsk);
if (iobm && refcount_dec_and_test(&iobm->refcnt))
kfree(iobm);
}
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index f63f8fd00a91..89c16dc135cf 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -176,6 +176,8 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
p->thread.sp = (unsigned long) fork_frame;
p->thread.io_bitmap = NULL;
p->thread.iopl_warn = 0;
+ p->thread.iopl_emul = 0;
+ clear_tsk_thread_flag(p, TIF_IO_BITMAP);
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
#ifdef CONFIG_X86_64
prev parent reply other threads:[~2025-01-15 14:22 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-07 2:32 reproducible GPF error in native_tss_update_io_bitmap reveliofuzzing
2025-01-07 21:28 ` Dave Hansen
2025-01-08 0:24 ` reveliofuzzing
2025-01-15 14:22 ` Thomas Gleixner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=871px4cg2x.ffs@tglx \
--to=tglx@linutronix.de \
--cc=bp@alien8.de \
--cc=dave.hansen@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=kirill.shutemov@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=reveliofuzzing@gmail.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox