Blame SOURCES/CVE-2020-36385.patch

98e09b
From 909e24465c59ba4df4124d7caa0730f609c33369 Mon Sep 17 00:00:00 2001
98e09b
From: Joe Lawrence <joe.lawrence@redhat.com>
98e09b
Date: Tue, 26 Oct 2021 18:00:19 -0400
98e09b
Subject: [KPATCH CVE-2020-36385] RDMA/ucma: kpatch fixes for CVE-2020-36385
98e09b
98e09b
Changes since last build:
98e09b
arches: x86_64 ppc64le
98e09b
ucma.o: changed function: ucma_migrate_id
98e09b
---------------------------
98e09b
98e09b
Kernels:
98e09b
4.18.0-305.el8
98e09b
4.18.0-305.3.1.el8_4
98e09b
4.18.0-305.7.1.el8_4
98e09b
4.18.0-305.10.2.el8_4
98e09b
4.18.0-305.12.1.el8_4
98e09b
4.18.0-305.17.1.el8_4
98e09b
4.18.0-305.19.1.el8_4
98e09b
98e09b
Modifications:
98e09b
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-8/-/merge_requests/1
98e09b
Approved-by: Artem Savkov (@artem.savkov)
98e09b
- Avoid the complications of reworking all the locks (and preceding
98e09b
commits) and apply a minimal patch to avoid the CVE condition.
98e09b
- Always inline ucma_unlock_files() to avoid new function on x64_64
98e09b
98e09b
Z-MR: https://gitlab.com/redhat/rhel/src/kernel/rhel-8/-/merge_requests/961
98e09b
98e09b
KT0 test PASS: https://beaker.engineering.redhat.com/jobs/5944203
98e09b
for kpatch-patch-4_18_0-305-1-6.el8 scratch build:
98e09b
https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=40633078
98e09b
98e09b
commit 15152e7e191054883e2859892e77b442c531d1e1
98e09b
Author: Kamal Heib <kheib@redhat.com>
98e09b
Date:   Sun Mar 7 11:30:04 2021 +0200
98e09b
98e09b
    RDMA/ucma: Rework ucma_migrate_id() to avoid races with destroy
98e09b
98e09b
    Bugzilla: https://bugzilla.redhat.com/1982040
98e09b
    CVE: CVE-2020-36385
98e09b
    Y-Commit: 20c1e291ce96ca474f5e94272d2e6511c6a38d58
98e09b
98e09b
    O-Bugzilla: http://bugzilla.redhat.com/1931846
98e09b
    O-CVE: CVE-2020-36385
98e09b
98e09b
    commit f5449e74802c1112dea984aec8af7a33c4516af1
98e09b
    Author: Jason Gunthorpe <jgg@nvidia.com>
98e09b
    Date:   Mon Sep 14 08:59:56 2020 -0300
98e09b
98e09b
        RDMA/ucma: Rework ucma_migrate_id() to avoid races with destroy
98e09b
98e09b
        ucma_destroy_id() assumes that all things accessing the ctx will do so via
98e09b
        the xarray. This assumption violated only in the case the FD is being
98e09b
        closed, then the ctx is reached via the ctx_list. Normally this is OK
98e09b
        since ucma_destroy_id() cannot run concurrenty with release(), however
98e09b
        with ucma_migrate_id() is involved this can violated as the close of the
98e09b
        2nd FD can run concurrently with destroy on the first:
98e09b
98e09b
                        CPU0                      CPU1
98e09b
                ucma_destroy_id(fda)
98e09b
                                          ucma_migrate_id(fda -> fdb)
98e09b
                                               ucma_get_ctx()
98e09b
                xa_lock()
98e09b
                 _ucma_find_context()
98e09b
                 xa_erase()
98e09b
                xa_unlock()
98e09b
                                               xa_lock()
98e09b
                                                ctx->file = new_file
98e09b
                                                list_move()
98e09b
                                               xa_unlock()
98e09b
                                              ucma_put_ctx()
98e09b
98e09b
                                           ucma_close(fdb)
98e09b
                                              _destroy_id()
98e09b
                                              kfree(ctx)
98e09b
98e09b
                _destroy_id()
98e09b
                  wait_for_completion()
98e09b
                  // boom, ctx was freed
98e09b
98e09b
        The ctx->file must be modified under the handler and xa_lock, and prior to
98e09b
        modification the ID must be rechecked that it is still reachable from
98e09b
        cur_file, ie there is no parallel destroy or migrate.
98e09b
98e09b
        To make this work remove the double locking and streamline the control
98e09b
        flow. The double locking was obsoleted by the handler lock now directly
98e09b
        preventing new uevents from being created, and the ctx_list cannot be read
98e09b
        while holding fgets on both files. Removing the double locking also
98e09b
        removes the need to check for the same file.
98e09b
98e09b
        Fixes: 88314e4dda1e ("RDMA/cma: add support for rdma_migrate_id()")
98e09b
        Link: https://lore.kernel.org/r/0-v1-05c5a4090305+3a872-ucma_syz_migrate_jgg@nvidia.com
98e09b
        Reported-and-tested-by: syzbot+cc6fc752b3819e082d0c@syzkaller.appspotmail.com
98e09b
        Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
98e09b
98e09b
    Signed-off-by: Kamal Heib <kheib@redhat.com>
98e09b
98e09b
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
98e09b
---
98e09b
 drivers/infiniband/core/ucma.c | 11 ++++++++++-
98e09b
 1 file changed, 10 insertions(+), 1 deletion(-)
98e09b
98e09b
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
98e09b
index 138e0096ca8e..2cd4277bf4a8 100644
98e09b
--- a/drivers/infiniband/core/ucma.c
98e09b
+++ b/drivers/infiniband/core/ucma.c
98e09b
@@ -1626,7 +1626,7 @@ static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
98e09b
 	}
98e09b
 }
98e09b
 
98e09b
-static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
98e09b
+static __always_inline void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
98e09b
 {
98e09b
 	if (file1 < file2) {
98e09b
 		mutex_unlock(&file2->mut);
98e09b
@@ -1689,6 +1689,14 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file,
98e09b
 	ucma_lock_files(cur_file, new_file);
98e09b
 	xa_lock(&ctx_table);
98e09b
 
98e09b
+	/* CVE-2020-36385 kpatch: double check the context one last time */
98e09b
+	if (_ucma_find_context(cmd.id, cur_file) != ctx) {
98e09b
+		xa_unlock(&ctx_table);
98e09b
+		ucma_unlock_files(cur_file, new_file);
98e09b
+		ret = -ENOENT;
98e09b
+		goto err_unlock;
98e09b
+	}
98e09b
+
98e09b
 	list_move_tail(&ctx->list, &new_file->ctx_list);
98e09b
 	ucma_move_events(ctx, new_file);
98e09b
 	ctx->file = new_file;
98e09b
@@ -1702,6 +1710,7 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file,
98e09b
 			 &resp, sizeof(resp)))
98e09b
 		ret = -EFAULT;
98e09b
 
98e09b
+err_unlock:
98e09b
 	ucma_put_ctx(ctx);
98e09b
 file_put:
98e09b
 	fdput(f);
98e09b
-- 
98e09b
2.31.1
98e09b
98e09b