]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
mm,hwpoison: check mm when killing accessing process
authorShuai Xue <xueshuai@linux.alibaba.com>
Wed, 14 Sep 2022 06:49:35 +0000 (14:49 +0800)
committerStefan Bader <stefan.bader@canonical.com>
Mon, 14 Nov 2022 10:25:28 +0000 (11:25 +0100)
BugLink: https://bugs.launchpad.net/bugs/1995517
commit 77677cdbc2aa4b5d5d839562793d3d126201d18d upstream.

The GHES code calls memory_failure_queue() from IRQ context to queue work
into workqueue and schedule it on the current CPU.  Then the work is
processed in memory_failure_work_func() by kworker and calls
memory_failure().

When a page is already poisoned, commit a3f5d80ea401 ("mm,hwpoison: send
SIGBUS with error virutal address") make memory_failure() call
kill_accessing_process() that:

    - holds mmap locking of current->mm
    - does pagetable walk to find the error virtual address
    - and sends SIGBUS to the current process with error info.

However, the mm of kworker is not valid, resulting in a null-pointer
dereference.  So check mm when killing the accessing process.

[akpm@linux-foundation.org: remove unrelated whitespace alteration]
Link: https://lkml.kernel.org/r/20220914064935.7851-1-xueshuai@linux.alibaba.com
Fixes: a3f5d80ea401 ("mm,hwpoison: send SIGBUS with error virutal address")
Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
Acked-by: Naoya Horiguchi <naoya.horiguchi@nec.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Bixuan Cui <cuibixuan@linux.alibaba.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
mm/memory-failure.c

index c71135edd0a10b4c2078b81e99767d0ee06db90b..31db222b6deb8591335b889100e0e22ce6c965ec 100644 (file)
@@ -700,6 +700,9 @@ static int kill_accessing_process(struct task_struct *p, unsigned long pfn,
        };
        priv.tk.tsk = p;
 
+       if (!p->mm)
+               return -EFAULT;
+
        mmap_read_lock(p->mm);
        ret = walk_page_range(p->mm, 0, TASK_SIZE, &hwp_walk_ops,
                              (void *)&priv);