Module Name: src
Committed By: bouyer
Date: Wed Apr 19 22:19:12 UTC 2017
Modified Files:
src/sys/netcan [bouyer-socketcan]: can.c
Log Message:
can_mbuf_tag_clean(): make sure we won't free the tag we will reuse.
Avoid mbuf leak in error paths.
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.9 -r1.1.2.10 src/sys/netcan/can.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/netcan/can.c
diff -u src/sys/netcan/can.c:1.1.2.9 src/sys/netcan/can.c:1.1.2.10
--- src/sys/netcan/can.c:1.1.2.9 Wed Apr 19 17:52:37 2017
+++ src/sys/netcan/can.c Wed Apr 19 22:19:12 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: can.c,v 1.1.2.9 2017/04/19 17:52:37 bouyer Exp $ */
+/* $NetBSD: can.c,v 1.1.2.10 2017/04/19 22:19:12 bouyer Exp $ */
/*-
* Copyright (c) 2003, 2017 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.9 2017/04/19 17:52:37 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: can.c,v 1.1.2.10 2017/04/19 22:19:12 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -214,24 +214,20 @@ static int
can_output(struct mbuf *m, struct canpcb *canp)
{
struct ifnet *ifp;
- int error = 0;
struct m_tag *sotag;
if (canp == NULL) {
printf("can_output: no pcb\n");
- error = EINVAL;
- return error;
+ return EINVAL;
}
ifp = canp->canp_ifp;
if (ifp == 0) {
- error = EDESTADDRREQ;
- goto bad;
+ return EDESTADDRREQ;
}
sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT);
if (sotag == NULL) {
ifp->if_oerrors++;
- error = ENOMEM;
- goto bad;
+ return ENOMEM;
}
*(struct socket **)(sotag + 1) = canp->canp_socket;
m_tag_prepend(m, sotag);
@@ -240,10 +236,7 @@ can_output(struct mbuf *m, struct canpcb
can_output_cnt++;
return ifq_enqueue(ifp, m);
} else
- error = EMSGSIZE;
-bad:
- m_freem(m);
- return (error);
+ return EMSGSIZE;
}
/*
@@ -255,6 +248,9 @@ can_mbuf_tag_clean(struct mbuf *m)
struct m_tag *sotag;
sotag = m_tag_find(m, PACKET_TAG_SO, NULL);
+ if (sotag)
+ m_tag_unlink(m, sotag);
+
m_tag_delete_nonpersistent(m);
if (sotag)
m_tag_prepend(m, sotag);
@@ -285,9 +281,9 @@ can_input(struct ifnet *ifp, struct mbuf
} else {
IF_ENQUEUE(inq, m);
IFQ_UNLOCK(inq);
- schednetisr(NETISR_CAN);
ifp->if_ipackets++;
ifp->if_ibytes += m->m_pkthdr.len;
+ schednetisr(NETISR_CAN);
}
}
@@ -356,7 +352,7 @@ canintr(void)
* we can't be sure we won't need
* the original mbuf later so copy
*/
- mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+ mc = m_copypacket(m, M_NOWAIT);
if (mc == NULL) {
/* deliver this mbuf and abort */
mc = m;
@@ -574,11 +570,15 @@ can_send(struct socket *so, struct mbuf
int s;
if (control && control->m_len) {
- return EINVAL;
+ m_freem(control);
+ error = EINVAL;
+ goto err;
}
if (m->m_len > sizeof(struct can_frame) ||
- m->m_len < offsetof(struct can_frame, can_dlc))
- return EINVAL;
+ m->m_len < offsetof(struct can_frame, can_dlc)) {
+ error = EINVAL;
+ goto err;
+ }
/* we expect all data in the first mbuf */
KASSERT((m->m_flags & M_PKTHDR) != 0);
@@ -586,20 +586,24 @@ can_send(struct socket *so, struct mbuf
if (nam) {
if ((so->so_state & SS_ISCONNECTED) != 0) {
- return EISCONN;
+ error = EISCONN;
+ goto err;
}
s = splnet();
error = can_pcbbind(canp, (struct sockaddr_can *)nam, l);
if (error) {
splx(s);
- return error;
+ goto err;
}
} else {
if ((so->so_state & SS_ISCONNECTED) == 0) {
- return EDESTADDRREQ;
+ error = EDESTADDRREQ;
+ goto err;
}
}
error = can_output(m, canp);
+ if (error)
+ goto err;
if (nam) {
struct sockaddr_can lscan;
memset(&lscan, 0, sizeof(lscan));
@@ -607,6 +611,10 @@ can_send(struct socket *so, struct mbuf
lscan.can_len = sizeof(lscan);
can_pcbbind(canp, &lscan, l);
}
+ return 0;
+
+err:
+ m_freem(m);
return error;
}