git: 2f62f92e3745 - main - tcp: Fix a locking issue related to logging
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 14 Nov 2021 14:04:35 UTC
The branch main has been updated by tuexen:
URL: https://cgit.FreeBSD.org/src/commit/?id=2f62f92e3745095b64433ed9369b70ccf126328b
commit 2f62f92e3745095b64433ed9369b70ccf126328b
Author: Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2021-11-14 13:56:43 +0000
Commit: Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2021-11-14 14:04:27 +0000
tcp: Fix a locking issue related to logging
tcp_respond() is sometimes called with only a read lock.
The logging however, requires a write lock. So either
try to upgrade the lock if needed, or don't log the packet.
Reported by: syzbot+8151ef969c170f76706b@syzkaller.appspotmail.com
Reported by: syzbot+eb679adb3304c511c1e4@syzkaller.appspotmail.com
Reviewed by: markj, rrs
Sponsored by: Netflix, Inc.
Differential Revision: https://reviews.freebsd.org/D32983
---
sys/netinet/tcp_subr.c | 38 +++++++++++++++++++++++---------------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 4805d6c80327..5563148a52ad 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1755,7 +1755,7 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
int isipv6;
#endif /* INET6 */
int optlen, tlen, win, ulen;
- bool incl_opts;
+ bool incl_opts, lock_upgraded;
uint16_t port;
int output_ret;
@@ -2088,21 +2088,29 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
TCP_PROBE3(debug__output, tp, th, m);
if (flags & TH_RST)
TCP_PROBE5(accept__refused, NULL, NULL, m, tp, nth);
+ lock_upgraded = false;
+ lgb = NULL;
if ((tp != NULL) && (tp->t_logstate != TCP_LOG_STATE_OFF)) {
union tcp_log_stackspecific log;
struct timeval tv;
- memset(&log.u_bbr, 0, sizeof(log.u_bbr));
- log.u_bbr.inhpts = tp->t_inpcb->inp_in_hpts;
- log.u_bbr.ininput = tp->t_inpcb->inp_in_input;
- log.u_bbr.flex8 = 4;
- log.u_bbr.pkts_out = tp->t_maxseg;
- log.u_bbr.timeStamp = tcp_get_usecs(&tv);
- log.u_bbr.delivered = 0;
- lgb = tcp_log_event_(tp, nth, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK,
- 0, &log, false, NULL, NULL, 0, &tv);
- } else
- lgb = NULL;
+ lock_upgraded = !INP_WLOCKED(inp) && INP_TRY_UPGRADE(inp);
+ /*
+ *`If we don't already own the write lock and can't upgrade,
+ * just don't log the event, but still send the response.
+ */
+ if (INP_WLOCKED(inp)) {
+ memset(&log.u_bbr, 0, sizeof(log.u_bbr));
+ log.u_bbr.inhpts = tp->t_inpcb->inp_in_hpts;
+ log.u_bbr.ininput = tp->t_inpcb->inp_in_input;
+ log.u_bbr.flex8 = 4;
+ log.u_bbr.pkts_out = tp->t_maxseg;
+ log.u_bbr.timeStamp = tcp_get_usecs(&tv);
+ log.u_bbr.delivered = 0;
+ lgb = tcp_log_event_(tp, nth, NULL, NULL, TCP_LOG_OUT, ERRNO_UNK,
+ 0, &log, false, NULL, NULL, 0, &tv);
+ }
+ }
#ifdef INET6
if (isipv6) {
@@ -2119,10 +2127,10 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
output_ret = ip_output(m, NULL, NULL, 0, NULL, inp);
}
#endif
- if (lgb) {
+ if (lgb != NULL)
lgb->tlb_errno = output_ret;
- lgb = NULL;
- }
+ if (lock_upgraded)
+ INP_DOWNGRADE(inp);
}
/*