From c9901b68b44c9c6b8713a74c28f78137dca314ce Mon Sep 17 00:00:00 2001 From: Sergey Cheremencev Date: Thu, 15 Apr 2021 17:14:51 +0300 Subject: [PATCH] LU-13587 quota: protect qpi in proc Access to pool info only when pool is fully inited. This patch protects from following panic: [212010.467347] BUG: unable to handle kernel NULL pointer dereference at (null) [212010.468205] IP: [] qpi_state_seq_show+0x86/0xe0 [lquota] ... [212010.486786] Call Trace: [212010.487344] [] seq_read+0x130/0x440 [212010.487741] [] proc_reg_read+0x40/0x80 [212010.488445] [] vfs_read+0x9f/0x170 [212010.489056] [] SyS_read+0x7f/0xf0 [212010.489920] [] system_call_fastpath+0x22/0x27 [212010.490861] Code: 5c a8 01 00 00 41 8b 8c 1c c0 01 00 00 48 c7 c6 18 [212010.493235] RIP [] qpi_state_seq_show+0x86/0xe0 [lquota] [212010.493672] RSP [212010.494161] CR2: 0000000000000000 Add test 79 to sanity-quota to check that race between access to /proc/.../dt-pool_name/info of non-existed pool with this pool creating doesn't cause a panic. HPE-bug-id: LUS-9938 Change-Id: I8eff846c6c3881a8431a98efb54e660ecb9155bf Signed-off-by: Sergey Cheremencev Reviewed-on: https://review.whamcloud.com/43987 Tested-by: jenkins Reviewed-by: Andreas Dilger Reviewed-by: Patrick Farrell Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/quota/qmt_internal.h | 1 + lustre/quota/qmt_pool.c | 8 ++++++++ lustre/tests/sanity-quota.sh | 16 ++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/lustre/quota/qmt_internal.h b/lustre/quota/qmt_internal.h index 7d3b7ce..72b4c22 100644 --- a/lustre/quota/qmt_internal.h +++ b/lustre/quota/qmt_internal.h @@ -100,6 +100,7 @@ enum { enum { /* set while recalc_thread is working */ QPI_FLAG_RECALC_OFFSET, + QPI_FLAG_STATE_INITED, }; /* diff --git a/lustre/quota/qmt_pool.c b/lustre/quota/qmt_pool.c index 7bb1ee3..bf9241c 100644 --- a/lustre/quota/qmt_pool.c +++ b/lustre/quota/qmt_pool.c @@ -79,6 +79,8 @@ static int qpi_state_seq_show(struct seq_file *m, void *data) int type; LASSERT(pool != NULL); + if (unlikely(!test_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags))) + return -ENOENT; seq_printf(m, "pool:\n" " id: %u\n" @@ -106,6 +108,8 @@ static int qpi_soft_least_qunit_seq_show(struct seq_file *m, void *data) { struct qmt_pool_info *pool = m->private; LASSERT(pool != NULL); + if (unlikely(!test_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags))) + return -ENOENT; seq_printf(m, "%lu\n", pool->qpi_soft_least_qunit); return 0; @@ -121,6 +125,8 @@ qpi_soft_least_qunit_seq_write(struct file *file, const char __user *buffer, int rc; LASSERT(pool != NULL); + if (unlikely(!test_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags))) + return -ENOENT; /* Not tuneable for inode limit */ if (pool->qpi_rtype != LQUOTA_RES_DT) @@ -177,6 +183,7 @@ static int qmt_pool_alloc(const struct lu_env *env, struct qmt_device *qmt, init_rwsem(&pool->qpi_recalc_sem); pool->qpi_rtype = pool_type; + pool->qpi_flags = 0; /* initialize refcount to 1, hash table will then grab an additional * reference */ @@ -670,6 +677,7 @@ int qmt_pool_prepare(const struct lu_env *env, struct qmt_device *qmt, qmt->qmt_svname, PFID(&qti->qti_fid), rc); #endif } + set_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags); if (name) break; } diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh index 52b820b..614fd46 100755 --- a/lustre/tests/sanity-quota.sh +++ b/lustre/tests/sanity-quota.sh @@ -5105,6 +5105,22 @@ test_78() } run_test 78 "Check fallocate increase quota usage" +test_79() +{ + local qpool="qpool1" + local cmd="$LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$qpool.info" + local stopf=$TMP/$tfile + + do_facet mds1 "touch $stopf" + stack_trap "do_facet mds1 'rm -f $stopf'" + do_facet mds1 "while [ -e $stopf ]; do $cmd &>/dev/null; done"& + local pid=$! + pool_add $qpool || error "pool_add failed" + do_facet mds1 "rm $stopf" + wait $pid +} +run_test 79 "access to non-existed dt-pool/info doesn't cause a panic" + quota_fini() { do_nodes $(comma_list $(nodes_list)) \ -- 1.8.3.1