Skip to content

Commit

Permalink
net/smc: Use a mutex for locking "struct smc_pnettable"
Browse files Browse the repository at this point in the history
commit 7ff57e9 upstream.

smc_pnetid_by_table_ib() uses read_lock() and then it calls smc_pnet_apply_ib()
which, in turn, calls mutex_lock(&smc_ib_devices.mutex).

read_lock() disables preemption. Therefore, the code acquires a mutex while in
atomic context and it leads to a SAC bug.

Fix this bug by replacing the rwlock with a mutex.

Reported-and-tested-by: syzbot+4f322a6d84e991c38775@syzkaller.appspotmail.com
Fixes: 64e28b5 ("net/smc: add pnet table namespace support")
Confirmed-by: Tony Lu <tonylu@linux.alibaba.com>
Signed-off-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
Acked-by: Karsten Graul <kgraul@linux.ibm.com>
Link: https://lore.kernel.org/r/20220223100252.22562-1-fmdefrancesco@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
xp4ns3 authored and gregkh committed Mar 2, 2022
1 parent 7e9880e commit 91f56a8
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 22 deletions.
42 changes: 21 additions & 21 deletions net/smc/smc_pnet.c
Expand Up @@ -112,7 +112,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
pnettable = &sn->pnettable;

/* remove table entry */
write_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist,
list) {
if (!pnet_name ||
Expand All @@ -130,7 +130,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
rc = 0;
}
}
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);

/* if this is not the initial namespace, stop here */
if (net != &init_net)
Expand Down Expand Up @@ -191,7 +191,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev)
sn = net_generic(net, smc_net_id);
pnettable = &sn->pnettable;

write_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev &&
!strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) {
Expand All @@ -205,7 +205,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev)
break;
}
}
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
return rc;
}

Expand All @@ -223,7 +223,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
sn = net_generic(net, smc_net_id);
pnettable = &sn->pnettable;

write_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) {
dev_put(pnetelem->ndev);
Expand All @@ -236,7 +236,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
break;
}
}
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
return rc;
}

Expand Down Expand Up @@ -371,7 +371,7 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,

rc = -EEXIST;
new_netdev = true;
write_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
if (tmp_pe->type == SMC_PNET_ETH &&
!strncmp(tmp_pe->eth_name, eth_name, IFNAMSIZ)) {
Expand All @@ -381,9 +381,9 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
}
if (new_netdev) {
list_add_tail(&new_pe->list, &pnettable->pnetlist);
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
} else {
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
kfree(new_pe);
goto out_put;
}
Expand Down Expand Up @@ -445,7 +445,7 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
new_pe->ib_port = ib_port;

new_ibdev = true;
write_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
if (tmp_pe->type == SMC_PNET_IB &&
!strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
Expand All @@ -455,9 +455,9 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
}
if (new_ibdev) {
list_add_tail(&new_pe->list, &pnettable->pnetlist);
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
} else {
write_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
kfree(new_pe);
}
return (new_ibdev) ? 0 : -EEXIST;
Expand Down Expand Up @@ -602,7 +602,7 @@ static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
pnettable = &sn->pnettable;

/* dump pnettable entries */
read_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
continue;
Expand All @@ -617,7 +617,7 @@ static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
break;
}
}
read_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
return idx;
}

Expand Down Expand Up @@ -859,7 +859,7 @@ int smc_pnet_net_init(struct net *net)
struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev;

INIT_LIST_HEAD(&pnettable->pnetlist);
rwlock_init(&pnettable->lock);
mutex_init(&pnettable->lock);
INIT_LIST_HEAD(&pnetids_ndev->list);
rwlock_init(&pnetids_ndev->lock);

Expand Down Expand Up @@ -939,7 +939,7 @@ static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
sn = net_generic(net, smc_net_id);
pnettable = &sn->pnettable;

read_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (pnetelem->type == SMC_PNET_ETH && ndev == pnetelem->ndev) {
/* get pnetid of netdev device */
Expand All @@ -948,7 +948,7 @@ static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
break;
}
}
read_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);
return rc;
}

Expand Down Expand Up @@ -1129,7 +1129,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
sn = net_generic(&init_net, smc_net_id);
pnettable = &sn->pnettable;

read_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
if (tmp_pe->type == SMC_PNET_IB &&
!strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX) &&
Expand All @@ -1139,7 +1139,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
break;
}
}
read_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);

return rc;
}
Expand All @@ -1158,7 +1158,7 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
sn = net_generic(&init_net, smc_net_id);
pnettable = &sn->pnettable;

read_lock(&pnettable->lock);
mutex_lock(&pnettable->lock);
list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
if (tmp_pe->type == SMC_PNET_IB &&
!strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
Expand All @@ -1167,7 +1167,7 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
break;
}
}
read_unlock(&pnettable->lock);
mutex_unlock(&pnettable->lock);

return rc;
}
2 changes: 1 addition & 1 deletion net/smc/smc_pnet.h
Expand Up @@ -29,7 +29,7 @@ struct smc_link_group;
* @pnetlist: List of PNETIDs
*/
struct smc_pnettable {
rwlock_t lock;
struct mutex lock;
struct list_head pnetlist;
};

Expand Down

0 comments on commit 91f56a8

Please sign in to comment.