Hi
On Sat, 08 Jun 2019 12:13:06 -0700 (PDT) syzbot wrote:
> Hello,
>
> syzbot found the following crash on:
>
> HEAD commit: 38e406f6 Merge git://
git.kernel.org/pub/scm/linux/kernel/g..
> git tree: net
> console output:
https://syzkaller.appspot.com/x/log.txt?x=10c90fbaa00000
Ignore my noise if you have no interest seeing the syzbot report.
The following four tiny diffs, made in the hope that they may help you perhaps
handle the report, fix reference count mismatch and do some cleanup in the
path of updating sock map.
Thanks
Hillf
[1/4] Remove old map entry before adding new one
This is a simple code move in bid to make a clean start for adding new sock
map entry.
---
kernel/bpf/sockmap.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 0a0f2ec..46cf204 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -2018,6 +2018,11 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
err = -ENOENT;
goto out_unlock;
}
+ if (osock) {
+ psock = smap_psock_sk(osock);
+ smap_list_map_remove(psock, &stab->sock_map[i]);
+ smap_release_sock(psock, osock);
+ }
e->entry = &stab->sock_map[i];
e->map = map;
@@ -2026,11 +2031,6 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
spin_unlock_bh(&psock->maps_lock);
stab->sock_map[i] = sock;
- if (osock) {
- psock = smap_psock_sk(osock);
- smap_list_map_remove(psock, &stab->sock_map[i]);
- smap_release_sock(psock, osock);
- }
raw_spin_unlock_bh(&stab->lock);
return 0;
out_unlock:
--
[2/4] Pump psock's refcnt up
Trying to successfully increment psock's refcnt makes sure that it is valid and
will not go to mars under our feet. That may make the bot uneasy and a bit
grumpy. As a bonus, it also makes the helper function paired with the pump since
refcnt is decremented in smap_release_sock().
---
kernel/bpf/sockmap.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 46cf204..a987522 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -2020,6 +2020,10 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
}
if (osock) {
psock = smap_psock_sk(osock);
+ if (!psock || !refcount_inc_not_zero(&psock->refcnt)) {
+ err = -ENOENT;
+ goto out_unlock;
+ }
smap_list_map_remove(psock, &stab->sock_map[i]);
smap_release_sock(psock, osock);
}
--
[3/4] Add new map entry
First psock is unbond from osock. Then refcnt pumpup pairs with release.
---
kernel/bpf/sockmap.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index a987522..346156d 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -2028,11 +2028,17 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
smap_release_sock(psock, osock);
}
+ psock = smap_psock_sk(sock);
+ if (!psock || !refcount_inc_not_zero(&psock->refcnt)) {
+ err = -ENOENT;
+ goto out_unlock;
+ }
e->entry = &stab->sock_map[i];
e->map = map;
spin_lock_bh(&psock->maps_lock);
list_add_tail(&e->list, &psock->maps);
spin_unlock_bh(&psock->maps_lock);
+ smap_release_sock(psock, sock);
stab->sock_map[i] = sock;
raw_spin_unlock_bh(&stab->lock);
--
[4/4] Make some code cleanup
We no longer need to derefernce psock before taking lock. What is more
important, there is a psock release that is currently unpaired, time to delete
it.
---
kernel/bpf/sockmap.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 346156d..d925372 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -2006,8 +2006,6 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
if (err)
goto out;
- /* psock guaranteed to be present. */
- psock = smap_psock_sk(sock);
raw_spin_lock_bh(&stab->lock);
osock = stab->sock_map[i];
if (osock && flags == BPF_NOEXIST) {
@@ -2044,7 +2042,6 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
raw_spin_unlock_bh(&stab->lock);
return 0;
out_unlock:
- smap_release_sock(psock, sock);
raw_spin_unlock_bh(&stab->lock);
out:
kfree(e);
--