Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102707100
D26652.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D26652.diff
View Options
diff --git a/lib/libc/sys/getsockopt.2 b/lib/libc/sys/getsockopt.2
--- a/lib/libc/sys/getsockopt.2
+++ b/lib/libc/sys/getsockopt.2
@@ -28,7 +28,7 @@
.\" @(#)getsockopt.2 8.4 (Berkeley) 5/2/95
.\" $FreeBSD$
.\"
-.Dd June 3, 2020
+.Dd February 8, 2021
.Dt GETSOCKOPT 2
.Os
.Sh NAME
@@ -177,6 +177,7 @@
.It Dv SO_PROTOCOL Ta "get the protocol number for the socket (get only)"
.It Dv SO_PROTOTYPE Ta "SunOS alias for the Linux SO_PROTOCOL (get only)"
.It Dv SO_ERROR Ta "get and clear error on the socket (get only)"
+.It Dv SO_RERROR Ta "enables receive error reporting"
.It Dv SO_SETFIB Ta "set the associated FIB (routing table) for the socket (set only)"
.El
.Pp
@@ -514,6 +515,13 @@
the error status.
It may be used to check for asynchronous errors on connected
datagram sockets or for other asynchronous errors.
+.Dv SO_RERROR
+indicates that receive buffer overflows should be handled as errors.
+Historically receive buffer overflows have been ignored and programs
+could not tell if they missed messages or messages had been truncated
+because of overflows.
+Since programs historically do not expect to get receive overflow errors,
+this behavior is not the default.
.Pp
.Dv SO_LABEL
returns the MAC label of the socket.
diff --git a/sbin/route/route.c b/sbin/route/route.c
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -1444,9 +1444,20 @@
interfaces();
exit(0);
}
+
+#ifdef SO_RERROR
+ n = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_RERROR, &n, sizeof(n)) == -1)
+ warn("SO_RERROR");
+#endif
+
for (;;) {
time_t now;
- n = read(s, msg, 2048);
+ n = read(s, msg, sizeof(msg));
+ if (n == -1) {
+ warn("read");
+ continue;
+ }
now = time(NULL);
(void)printf("\ngot message of size %d on %s", n, ctime(&now));
print_rtmsg((struct rt_msghdr *)(void *)msg, n);
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -436,6 +436,30 @@
mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
}
+void
+soroverflow_locked(struct socket *so)
+{
+
+ SOCKBUF_LOCK_ASSERT(&so->so_rcv);
+
+ if (so->so_options & SO_RERROR) {
+ so->so_rerror = ENOBUFS;
+ sorwakeup_locked(so);
+ } else
+ SOCKBUF_UNLOCK(&so->so_rcv);
+
+ mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
+}
+
+void
+soroverflow(struct socket *so)
+{
+
+ SOCKBUF_LOCK(&so->so_rcv);
+ soroverflow_locked(so);
+ mtx_assert(SOCKBUF_MTX(&so->so_rcv), MA_NOTOWNED);
+}
+
/*
* Wait for data to arrive at/drain from a socket buffer.
*/
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1952,12 +1952,19 @@
KASSERT(m != NULL || !sbavail(&so->so_rcv),
("receive: m == %p sbavail == %u",
m, sbavail(&so->so_rcv)));
- if (so->so_error) {
+ if (so->so_error || so->so_rerror) {
if (m != NULL)
goto dontblock;
- error = so->so_error;
- if ((flags & MSG_PEEK) == 0)
- so->so_error = 0;
+ if (so->so_error)
+ error = so->so_error;
+ else
+ error = so->so_rerror;
+ if ((flags & MSG_PEEK) == 0) {
+ if (so->so_error)
+ so->so_error = 0;
+ else
+ so->so_rerror = 0;
+ }
SOCKBUF_UNLOCK(&so->so_rcv);
goto release;
}
@@ -2302,7 +2309,7 @@
while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 &&
!sosendallatonce(so) && nextrecord == NULL) {
SOCKBUF_LOCK_ASSERT(&so->so_rcv);
- if (so->so_error ||
+ if (so->so_error || so->so_rerror ||
so->so_rcv.sb_state & SBS_CANTRCVMORE)
break;
/*
@@ -3043,6 +3050,7 @@
case SO_NOSIGPIPE:
case SO_NO_DDP:
case SO_NO_OFFLOAD:
+ case SO_RERROR:
error = sooptcopyin(sopt, &optval, sizeof optval,
sizeof optval);
if (error)
@@ -3264,6 +3272,7 @@
case SO_NOSIGPIPE:
case SO_NO_DDP:
case SO_NO_OFFLOAD:
+ case SO_RERROR:
optval = so->so_options & sopt->sopt_name;
integer:
error = sooptcopyout(sopt, &optval, sizeof optval);
@@ -3283,8 +3292,13 @@
case SO_ERROR:
SOCK_LOCK(so);
- optval = so->so_error;
- so->so_error = 0;
+ if (so->so_error) {
+ optval = so->so_error;
+ so->so_error = 0;
+ } else {
+ optval = so->so_rerror;
+ so->so_rerror = 0;
+ }
SOCK_UNLOCK(so);
goto integer;
@@ -3839,7 +3853,7 @@
kn->kn_flags |= EV_EOF;
kn->kn_fflags = so->so_error;
return (1);
- } else if (so->so_error) /* temporary udp error */
+ } else if (so->so_error || so->so_rerror)
return (1);
if (kn->kn_sfflags & NOTE_LOWAT) {
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1060,7 +1060,7 @@
m = NULL;
control = NULL;
} else {
- SOCKBUF_UNLOCK(&so2->so_rcv);
+ soroverflow_locked(so2);
error = ENOBUFS;
}
if (nam != NULL)
diff --git a/sys/net/raw_usrreq.c b/sys/net/raw_usrreq.c
--- a/sys/net/raw_usrreq.c
+++ b/sys/net/raw_usrreq.c
@@ -100,10 +100,10 @@
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
if (n) {
if (sbappendaddr(&last->so_rcv, src,
- n, (struct mbuf *)0) == 0)
- /* should notify about lost packet */
+ n, (struct mbuf *)0) == 0) {
+ soroverflow(last);
m_freem(n);
- else
+ } else
sorwakeup(last);
}
}
@@ -111,9 +111,10 @@
}
if (last) {
if (sbappendaddr(&last->so_rcv, src,
- m, (struct mbuf *)0) == 0)
+ m, (struct mbuf *)0) == 0) {
+ soroverflow(last);
m_freem(m);
- else
+ } else
sorwakeup(last);
} else
m_freem(m);
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
@@ -539,6 +539,7 @@
NG_FREE_M(m);
NG_FREE_M(ctl);
+ soroverflow(pcb->so);
}
}
next:
diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c
--- a/sys/netgraph/ng_socket.c
+++ b/sys/netgraph/ng_socket.c
@@ -993,7 +993,7 @@
/* Send it up to the socket. */
if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)&addr, m,
NULL) == 0) {
- SOCKBUF_UNLOCK(&so->so_rcv);
+ soroverflow_locked(so);
TRAP_ERROR;
m_freem(m);
return (ENOBUFS);
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -295,7 +295,7 @@
if (sbappendaddr_locked(&sa->so_rcv,
(struct sockaddr *)&divsrc, m,
(struct mbuf *)0) == 0) {
- SOCKBUF_UNLOCK(&sa->so_rcv);
+ soroverflow_locked(sa);
sa = NULL; /* force mbuf reclaim below */
} else
sorwakeup_locked(sa);
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -1257,7 +1257,7 @@
sorwakeup_locked(s);
return 0;
}
- SOCKBUF_UNLOCK(&s->so_rcv);
+ soroverflow_locked(s);
}
m_freem(mm);
return -1;
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -263,11 +263,10 @@
SOCKBUF_LOCK(&so->so_rcv);
if (sbappendaddr_locked(&so->so_rcv,
(struct sockaddr *)ripsrc, n, opts) == 0) {
- /* should notify about lost packet */
+ soroverflow_locked(so);
m_freem(n);
if (opts)
m_freem(opts);
- SOCKBUF_UNLOCK(&so->so_rcv);
} else
sorwakeup_locked(so);
} else
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -379,7 +379,7 @@
so = inp->inp_socket;
SOCKBUF_LOCK(&so->so_rcv);
if (sbappendaddr_locked(&so->so_rcv, append_sa, n, opts) == 0) {
- SOCKBUF_UNLOCK(&so->so_rcv);
+ soroverflow(so);
m_freem(n);
if (opts)
m_freem(opts);
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1974,13 +1974,11 @@
&last->inp_socket->so_rcv,
(struct sockaddr *)&fromsa, n, opts)
== 0) {
- /* should notify about lost packet */
+ soroverflow_locked(last->inp_socket);
m_freem(n);
if (opts) {
m_freem(opts);
}
- SOCKBUF_UNLOCK(
- &last->inp_socket->so_rcv);
} else
sorwakeup_locked(last->inp_socket);
opts = NULL;
@@ -2020,7 +2018,7 @@
m_freem(m);
if (opts)
m_freem(opts);
- SOCKBUF_UNLOCK(&last->inp_socket->so_rcv);
+ soroverflow_locked(last->inp_socket);
} else
sorwakeup_locked(last->inp_socket);
INP_RUNLOCK(last);
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1575,6 +1575,7 @@
so = inp->inp_socket;
if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu)
== 0) {
+ soroverflow(so);
m_freem(m_mtu);
/* XXX: should count statistics */
} else
diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c
--- a/sys/netinet6/ip6_mroute.c
+++ b/sys/netinet6/ip6_mroute.c
@@ -1038,7 +1038,8 @@
mm, (struct mbuf *)0) != 0) {
sorwakeup(s);
return (0);
- }
+ } else
+ soroverflow(s);
}
m_freem(mm);
return (-1);
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -214,6 +214,7 @@
if (sbappendaddr(&last->inp_socket->so_rcv,
(struct sockaddr *)&fromsa,
n, opts) == 0) {
+ soroverflow(last->inp_socket);
m_freem(n);
if (opts)
m_freem(opts);
@@ -325,6 +326,7 @@
m_adj(m, *offp);
if (sbappendaddr(&last->inp_socket->so_rcv,
(struct sockaddr *)&fromsa, m, opts) == 0) {
+ soroverflow(last->inp_socket);
m_freem(m);
if (opts)
m_freem(opts);
diff --git a/sys/netinet6/send.c b/sys/netinet6/send.c
--- a/sys/netinet6/send.c
+++ b/sys/netinet6/send.c
@@ -307,7 +307,7 @@
SOCKBUF_LOCK(&V_send_so->so_rcv);
if (sbappendaddr_locked(&V_send_so->so_rcv,
(struct sockaddr *)&sendsrc, m, NULL) == 0) {
- SOCKBUF_UNLOCK(&V_send_so->so_rcv);
+ soroverflow_locked(V_send_so);
/* XXX stats. */
m_freem(m);
} else {
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -197,7 +197,7 @@
SOCKBUF_LOCK(&so->so_rcv);
if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)&fromsa[0], n,
opts) == 0) {
- SOCKBUF_UNLOCK(&so->so_rcv);
+ soroverflow_locked(so);
m_freem(n);
if (opts)
m_freem(opts);
diff --git a/sys/netipsec/keysock.c b/sys/netipsec/keysock.c
--- a/sys/netipsec/keysock.c
+++ b/sys/netipsec/keysock.c
@@ -141,7 +141,6 @@
static int
key_sendup0(struct rawcb *rp, struct mbuf *m, int promisc)
{
- int error;
if (promisc) {
struct sadb_msg *pmsg;
@@ -165,11 +164,12 @@
m, NULL)) {
PFKEYSTAT_INC(in_nomem);
m_freem(m);
- error = ENOBUFS;
- } else
- error = 0;
+ soroverflow(rp->rcb_socket);
+ return ENOBUFS;
+ }
+
sorwakeup(rp->rcb_socket);
- return error;
+ return 0;
}
/* so can be NULL if target != KEY_SENDUP_ONE */
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -147,6 +147,7 @@
#define SO_NO_OFFLOAD 0x00004000 /* socket cannot be offloaded */
#define SO_NO_DDP 0x00008000 /* disable direct data placement */
#define SO_REUSEPORT_LB 0x00010000 /* reuse with load balancing */
+#define SO_RERROR 0x00020000 /* keep track of receive errors */
/*
* Additional options, not kept in so_options.
diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h
--- a/sys/sys/socketvar.h
+++ b/sys/sys/socketvar.h
@@ -100,6 +100,7 @@
struct protosw *so_proto; /* (a) protocol handle */
short so_timeo; /* (g) connection timeout */
u_short so_error; /* (f) error affecting connection */
+ u_short so_rerror; /* (f) error affecting connection */
struct sigio *so_sigio; /* [sg] information for async I/O or
out of band data (SIGURG) */
struct ucred *so_cred; /* (a) user credentials */
@@ -266,7 +267,8 @@
/* can we read something from so? */
#define soreadabledata(so) \
- (sbavail(&(so)->so_rcv) >= (so)->so_rcv.sb_lowat || (so)->so_error)
+ (sbavail(&(so)->so_rcv) >= (so)->so_rcv.sb_lowat || \
+ (so)->so_error || (so)->so_rerror)
#define soreadable(so) \
(soreadabledata(so) || ((so)->so_rcv.sb_state & SBS_CANTRCVMORE))
@@ -480,6 +482,8 @@
void socantrcvmore_locked(struct socket *so);
void socantsendmore(struct socket *so);
void socantsendmore_locked(struct socket *so);
+void soroverflow(struct socket *so);
+void soroverflow_locked(struct socket *so);
/*
* Accept filter functions (duh).
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 17, 3:43 AM (22 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14669765
Default Alt Text
D26652.diff (12 KB)
Attached To
Mode
D26652: Implement SO_RERROR
Attached
Detach File
Event Timeline
Log In to Comment