Skip to content

Commit d0aa726

Browse files
Wang Jianjianjankara
authored andcommitted
quota: Fix potential NULL pointer dereference
Below race may cause NULL pointer dereference P1 P2 dquot_free_inode quota_off drop_dquot_ref remove_dquot_ref dquots = i_dquot(inode) dquots = i_dquot(inode) srcu_read_lock dquots[cnt]) != NULL (1) dquots[type] = NULL (2) spin_lock(&dquots[cnt]->dq_dqb_lock) (3) .... If dquot_free_inode(or other routines) checks inode's quota pointers (1) before quota_off sets it to NULL(2) and use it (3) after that, NULL pointer dereference will be triggered. So let's fix it by using a temporary pointer to avoid this issue. Signed-off-by: Wang Jianjian <wangjianjian3@huawei.com> Signed-off-by: Jan Kara <jack@suse.cz> Message-Id: <20240202081852.2514092-1-wangjianjian3@huawei.com>
1 parent a1e1b2b commit d0aa726

File tree

1 file changed

+57
-41
lines changed

1 file changed

+57
-41
lines changed

fs/quota/dquot.c

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -399,15 +399,17 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
399399
EXPORT_SYMBOL(dquot_mark_dquot_dirty);
400400

401401
/* Dirtify all the dquots - this can block when journalling */
402-
static inline int mark_all_dquot_dirty(struct dquot * const *dquot)
402+
static inline int mark_all_dquot_dirty(struct dquot * const *dquots)
403403
{
404404
int ret, err, cnt;
405+
struct dquot *dquot;
405406

406407
ret = err = 0;
407408
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
408-
if (dquot[cnt])
409+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
410+
if (dquot)
409411
/* Even in case of error we have to continue */
410-
ret = mark_dquot_dirty(dquot[cnt]);
412+
ret = mark_dquot_dirty(dquot);
411413
if (!err)
412414
err = ret;
413415
}
@@ -1674,6 +1676,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
16741676
struct dquot_warn warn[MAXQUOTAS];
16751677
int reserve = flags & DQUOT_SPACE_RESERVE;
16761678
struct dquot **dquots;
1679+
struct dquot *dquot;
16771680

16781681
if (!inode_quota_active(inode)) {
16791682
if (reserve) {
@@ -1693,27 +1696,26 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
16931696
index = srcu_read_lock(&dquot_srcu);
16941697
spin_lock(&inode->i_lock);
16951698
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1696-
if (!dquots[cnt])
1699+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1700+
if (!dquot)
16971701
continue;
16981702
if (reserve) {
1699-
ret = dquot_add_space(dquots[cnt], 0, number, flags,
1700-
&warn[cnt]);
1703+
ret = dquot_add_space(dquot, 0, number, flags, &warn[cnt]);
17011704
} else {
1702-
ret = dquot_add_space(dquots[cnt], number, 0, flags,
1703-
&warn[cnt]);
1705+
ret = dquot_add_space(dquot, number, 0, flags, &warn[cnt]);
17041706
}
17051707
if (ret) {
17061708
/* Back out changes we already did */
17071709
for (cnt--; cnt >= 0; cnt--) {
1708-
if (!dquots[cnt])
1710+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1711+
if (!dquot)
17091712
continue;
1710-
spin_lock(&dquots[cnt]->dq_dqb_lock);
1713+
spin_lock(&dquot->dq_dqb_lock);
17111714
if (reserve)
1712-
dquot_free_reserved_space(dquots[cnt],
1713-
number);
1715+
dquot_free_reserved_space(dquot, number);
17141716
else
1715-
dquot_decr_space(dquots[cnt], number);
1716-
spin_unlock(&dquots[cnt]->dq_dqb_lock);
1717+
dquot_decr_space(dquot, number);
1718+
spin_unlock(&dquot->dq_dqb_lock);
17171719
}
17181720
spin_unlock(&inode->i_lock);
17191721
goto out_flush_warn;
@@ -1744,6 +1746,7 @@ int dquot_alloc_inode(struct inode *inode)
17441746
int cnt, ret = 0, index;
17451747
struct dquot_warn warn[MAXQUOTAS];
17461748
struct dquot * const *dquots;
1749+
struct dquot *dquot;
17471750

17481751
if (!inode_quota_active(inode))
17491752
return 0;
@@ -1754,17 +1757,19 @@ int dquot_alloc_inode(struct inode *inode)
17541757
index = srcu_read_lock(&dquot_srcu);
17551758
spin_lock(&inode->i_lock);
17561759
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1757-
if (!dquots[cnt])
1760+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1761+
if (!dquot)
17581762
continue;
1759-
ret = dquot_add_inodes(dquots[cnt], 1, &warn[cnt]);
1763+
ret = dquot_add_inodes(dquot, 1, &warn[cnt]);
17601764
if (ret) {
17611765
for (cnt--; cnt >= 0; cnt--) {
1762-
if (!dquots[cnt])
1766+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1767+
if (!dquot)
17631768
continue;
17641769
/* Back out changes we already did */
1765-
spin_lock(&dquots[cnt]->dq_dqb_lock);
1766-
dquot_decr_inodes(dquots[cnt], 1);
1767-
spin_unlock(&dquots[cnt]->dq_dqb_lock);
1770+
spin_lock(&dquot->dq_dqb_lock);
1771+
dquot_decr_inodes(dquot, 1);
1772+
spin_unlock(&dquot->dq_dqb_lock);
17681773
}
17691774
goto warn_put_all;
17701775
}
@@ -1786,6 +1791,7 @@ EXPORT_SYMBOL(dquot_alloc_inode);
17861791
void dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
17871792
{
17881793
struct dquot **dquots;
1794+
struct dquot *dquot;
17891795
int cnt, index;
17901796

17911797
if (!inode_quota_active(inode)) {
@@ -1801,9 +1807,8 @@ void dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
18011807
spin_lock(&inode->i_lock);
18021808
/* Claim reserved quotas to allocated quotas */
18031809
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1804-
if (dquots[cnt]) {
1805-
struct dquot *dquot = dquots[cnt];
1806-
1810+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1811+
if (dquot) {
18071812
spin_lock(&dquot->dq_dqb_lock);
18081813
if (WARN_ON_ONCE(dquot->dq_dqb.dqb_rsvspace < number))
18091814
number = dquot->dq_dqb.dqb_rsvspace;
@@ -1828,6 +1833,7 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty);
18281833
void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
18291834
{
18301835
struct dquot **dquots;
1836+
struct dquot *dquot;
18311837
int cnt, index;
18321838

18331839
if (!inode_quota_active(inode)) {
@@ -1843,9 +1849,8 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
18431849
spin_lock(&inode->i_lock);
18441850
/* Claim reserved quotas to allocated quotas */
18451851
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
1846-
if (dquots[cnt]) {
1847-
struct dquot *dquot = dquots[cnt];
1848-
1852+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1853+
if (dquot) {
18491854
spin_lock(&dquot->dq_dqb_lock);
18501855
if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number))
18511856
number = dquot->dq_dqb.dqb_curspace;
@@ -1872,6 +1877,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
18721877
unsigned int cnt;
18731878
struct dquot_warn warn[MAXQUOTAS];
18741879
struct dquot **dquots;
1880+
struct dquot *dquot;
18751881
int reserve = flags & DQUOT_SPACE_RESERVE, index;
18761882

18771883
if (!inode_quota_active(inode)) {
@@ -1892,17 +1898,18 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
18921898
int wtype;
18931899

18941900
warn[cnt].w_type = QUOTA_NL_NOWARN;
1895-
if (!dquots[cnt])
1901+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1902+
if (!dquot)
18961903
continue;
1897-
spin_lock(&dquots[cnt]->dq_dqb_lock);
1898-
wtype = info_bdq_free(dquots[cnt], number);
1904+
spin_lock(&dquot->dq_dqb_lock);
1905+
wtype = info_bdq_free(dquot, number);
18991906
if (wtype != QUOTA_NL_NOWARN)
1900-
prepare_warning(&warn[cnt], dquots[cnt], wtype);
1907+
prepare_warning(&warn[cnt], dquot, wtype);
19011908
if (reserve)
1902-
dquot_free_reserved_space(dquots[cnt], number);
1909+
dquot_free_reserved_space(dquot, number);
19031910
else
1904-
dquot_decr_space(dquots[cnt], number);
1905-
spin_unlock(&dquots[cnt]->dq_dqb_lock);
1911+
dquot_decr_space(dquot, number);
1912+
spin_unlock(&dquot->dq_dqb_lock);
19061913
}
19071914
if (reserve)
19081915
*inode_reserved_space(inode) -= number;
@@ -1927,6 +1934,7 @@ void dquot_free_inode(struct inode *inode)
19271934
unsigned int cnt;
19281935
struct dquot_warn warn[MAXQUOTAS];
19291936
struct dquot * const *dquots;
1937+
struct dquot *dquot;
19301938
int index;
19311939

19321940
if (!inode_quota_active(inode))
@@ -1937,16 +1945,16 @@ void dquot_free_inode(struct inode *inode)
19371945
spin_lock(&inode->i_lock);
19381946
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
19391947
int wtype;
1940-
19411948
warn[cnt].w_type = QUOTA_NL_NOWARN;
1942-
if (!dquots[cnt])
1949+
dquot = srcu_dereference(dquots[cnt], &dquot_srcu);
1950+
if (!dquot)
19431951
continue;
1944-
spin_lock(&dquots[cnt]->dq_dqb_lock);
1945-
wtype = info_idq_free(dquots[cnt], 1);
1952+
spin_lock(&dquot->dq_dqb_lock);
1953+
wtype = info_idq_free(dquot, 1);
19461954
if (wtype != QUOTA_NL_NOWARN)
1947-
prepare_warning(&warn[cnt], dquots[cnt], wtype);
1948-
dquot_decr_inodes(dquots[cnt], 1);
1949-
spin_unlock(&dquots[cnt]->dq_dqb_lock);
1955+
prepare_warning(&warn[cnt], dquot, wtype);
1956+
dquot_decr_inodes(dquot, 1);
1957+
spin_unlock(&dquot->dq_dqb_lock);
19501958
}
19511959
spin_unlock(&inode->i_lock);
19521960
mark_all_dquot_dirty(dquots);
@@ -1973,7 +1981,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
19731981
qsize_t rsv_space = 0;
19741982
qsize_t inode_usage = 1;
19751983
struct dquot *transfer_from[MAXQUOTAS] = {};
1976-
int cnt, ret = 0;
1984+
int cnt, index, ret = 0;
19771985
char is_valid[MAXQUOTAS] = {};
19781986
struct dquot_warn warn_to[MAXQUOTAS];
19791987
struct dquot_warn warn_from_inodes[MAXQUOTAS];
@@ -2062,8 +2070,16 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
20622070
spin_unlock(&inode->i_lock);
20632071
spin_unlock(&dq_data_lock);
20642072

2073+
/*
2074+
* These arrays are local and we hold dquot references so we don't need
2075+
* the srcu protection but still take dquot_srcu to avoid warning in
2076+
* mark_all_dquot_dirty().
2077+
*/
2078+
index = srcu_read_lock(&dquot_srcu);
20652079
mark_all_dquot_dirty(transfer_from);
20662080
mark_all_dquot_dirty(transfer_to);
2081+
srcu_read_unlock(&dquot_srcu, index);
2082+
20672083
flush_warnings(warn_to);
20682084
flush_warnings(warn_from_inodes);
20692085
flush_warnings(warn_from_space);

0 commit comments

Comments
 (0)