Blame SOURCES/CVE-2020-36385.patch

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