afs: Fix leak in afs_lookup_cell_rcu() [Linux 4.19.72]

This Linux kernel change "afs: Fix leak in afs_lookup_cell_rcu()" is included in the Linux 4.19.72 release. This change is authored by David Howells <dhowells [at] redhat.com> on Thu Aug 22 13:28:43 2019 +0100. The commit for this change in Linux stable tree is 1a31b0d (patch) which is from upstream commit a5fb8e6. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream a5fb8e6.

afs: Fix leak in afs_lookup_cell_rcu()

[ Upstream commit a5fb8e6c02d6a518fb2b1a2b8c2471fa77b69436 ]

Fix a leak on the cell refcount in afs_lookup_cell_rcu() due to
non-clearance of the default error in the case a NULL cell name is passed
and the workstation default cell is used.

Also put a bit at the end to make sure we don't leak a cell ref if we're
going to be returning an error.

This leak results in an assertion like the following when the kafs module is
unloaded:

    AFS: Assertion failed
    2 == 1 is false
    0x2 == 0x1 is false
    ------------[ cut here ]------------
    kernel BUG at fs/afs/cell.c:770!
    ...
    RIP: 0010:afs_manage_cells+0x220/0x42f [kafs]
    ...
     process_one_work+0x4c2/0x82c
     ? pool_mayday_timeout+0x1e1/0x1e1
     ? do_raw_spin_lock+0x134/0x175
     worker_thread+0x336/0x4a6
     ? rescuer_thread+0x4af/0x4af
     kthread+0x1de/0x1ee
     ? kthread_park+0xd4/0xd4
     ret_from_fork+0x24/0x30

Fixes: 989782dcdc91 ("afs: Overhaul cell database management")
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 4 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/afs/cell.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 6127f0f..ee07162 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -76,6 +76,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,
            cell = rcu_dereference_raw(net->ws_cell);
            if (cell) {
                afs_get_cell(cell);
+               ret = 0;
                break;
            }
            ret = -EDESTADDRREQ;
@@ -110,6 +111,9 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,

    done_seqretry(&net->cells_lock, seq);

+   if (ret != 0 && cell)
+       afs_put_cell(net, cell);
+
    return ret == 0 ? cell : ERR_PTR(ret);
 }

Leave a Reply

Your email address will not be published. Required fields are marked *