summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2006-11-08 00:21:13 +0000
committerrrs <rrs@FreeBSD.org>2006-11-08 00:21:13 +0000
commit1bedc49b68670bf727f50429a15911323ca540e3 (patch)
treef6f786f609125bed924191c84569dc69cd63afc8
parent0c2fa6c52c1266ecfbf3b99e2c6c0377acac1444 (diff)
downloadFreeBSD-src-1bedc49b68670bf727f50429a15911323ca540e3.zip
FreeBSD-src-1bedc49b68670bf727f50429a15911323ca540e3.tar.gz
-Fixes first of all the getcred on IPv6 and V4. The
copy's were incorrect and so was the locking. -A bug was also found that would create a race and panic when an abort arrived on a socket being read from. -Also fix the reader to get MSG_TRUNC when a partial delivery is aborted. -Also addresses a couple of coverity caught error path memory leaks and a couple of other valid complaints Approved by: gnn
-rw-r--r--sys/netinet/sctp_asconf.c1
-rw-r--r--sys/netinet/sctp_indata.c2
-rw-r--r--sys/netinet/sctp_input.c3
-rw-r--r--sys/netinet/sctp_output.c3
-rw-r--r--sys/netinet/sctp_pcb.c66
-rw-r--r--sys/netinet/sctp_structs.h11
-rw-r--r--sys/netinet/sctp_uio.h12
-rw-r--r--sys/netinet/sctp_usrreq.c34
-rw-r--r--sys/netinet/sctputil.c173
-rw-r--r--sys/netinet6/sctp6_usrreq.c39
10 files changed, 167 insertions, 177 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 72efc5e..7b44da5 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1274,6 +1274,7 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
sizeof(struct in_addr));
} else {
/* invalid family! */
+ SCTP_FREE(aa);
return (-1);
}
aa->sent = 0; /* clear sent flag */
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index bbb26e9..2da8f8b 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -257,6 +257,7 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
read_queue_e->port_from = stcb->rport;
read_queue_e->do_not_ref_stcb = 0;
read_queue_e->end_added = 0;
+ read_queue_e->pdapi_aborted = 0;
failed_build:
return (read_queue_e);
}
@@ -293,6 +294,7 @@ sctp_build_readq_entry_chk(struct sctp_tcb *stcb,
read_queue_e->port_from = stcb->rport;
read_queue_e->do_not_ref_stcb = 0;
read_queue_e->end_added = 0;
+ read_queue_e->pdapi_aborted = 0;
failed_build:
return (read_queue_e);
}
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 1545e8c..ac8940c 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -582,6 +582,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
*/
SCTP_INP_READ_LOCK(stcb->sctp_ep);
stcb->asoc.control_pdapi->end_added = 1;
+ stcb->asoc.control_pdapi->pdapi_aborted = 1;
if (stcb->asoc.control_pdapi->tail_mbuf) {
stcb->asoc.control_pdapi->tail_mbuf->m_flags |= M_EOR;
}
@@ -673,6 +674,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
*/
SCTP_INP_READ_LOCK(stcb->sctp_ep);
stcb->asoc.control_pdapi->end_added = 1;
+ stcb->asoc.control_pdapi->pdapi_aborted = 1;
if (stcb->asoc.control_pdapi->tail_mbuf) {
stcb->asoc.control_pdapi->tail_mbuf->m_flags |= M_EOR;
}
@@ -1823,6 +1825,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
sig = (uint8_t *) sctp_m_getptr(m_sig, 0, SCTP_SIGNATURE_SIZE, (uint8_t *) & tmp_sig);
if (sig == NULL) {
/* couldn't find signature */
+ sctp_m_freem(m_sig);
return (NULL);
}
/* compare the received digest with the computed digest */
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 094e665..76c2d61 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -9870,6 +9870,9 @@ sctp_lower_sosend(struct socket *so,
}
mm = sctp_copy_resume(sp, uio, srcv, max_len, user_marks_eor, &error, &sndout, &new_tail);
if ((mm == NULL) || error) {
+ if (mm) {
+ sctp_m_freem(mm);
+ }
goto out;
}
/* Update the mbuf and count */
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 24c2ba5..fb74b44 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -1769,8 +1769,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
*/
/* got to be root to get at low ports */
if (ntohs(lport) < IPPORT_RESERVED) {
- if (p && (error = priv_check(p,
- PRIV_NETINET_RESERVEDPORT))) {
+ if (p && (error =
+ priv_check(p,
+ PRIV_NETINET_RESERVEDPORT)
+ )) {
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
@@ -3290,46 +3292,30 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
if (sq->stcb == stcb) {
sq->do_not_ref_stcb = 1;
sq->sinfo_cumtsn = stcb->asoc.cumulative_tsn;
- if ((from_inpcbfree == 0) && so) {
- /*
- * Only if we have a socket lock do
- * we do this
- */
- if ((sq->held_length) ||
- (sq->end_added == 0) ||
- ((sq->length == 0) && (sq->end_added == 0))) {
- /* Held for PD-API */
- sq->held_length = 0;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) {
- /*
- * need to change to
- * PD-API aborted
- */
- stcb->asoc.control_pdapi = sq;
- sctp_notify_partial_delivery_indication(stcb,
- SCTP_PARTIAL_DELIVERY_ABORTED, 1);
- stcb->asoc.control_pdapi = NULL;
- } else {
- /*
- * need to get the
- * reader to remove
- * it
- */
- sq->length = 0;
- if (sq->data) {
- struct mbuf *m;
-
- m = sq->data;
- while (m) {
- sctp_sbfree(sq, stcb, &stcb->sctp_socket->so_rcv, m);
- m = sctp_m_free(m);
- }
- sq->data = NULL;
- sq->tail_mbuf = NULL;
- }
- }
+ /*
+ * If there is no end, there never will be
+ * now.
+ */
+ if (sq->end_added == 0) {
+ /* Held for PD-API clear that. */
+ sq->pdapi_aborted = 1;
+ sq->held_length = 0;
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) {
+ /*
+ * Need to add a PD-API
+ * aborted indication.
+ * Setting the control_pdapi
+ * assures that it will be
+ * added right after this
+ * msg.
+ */
+ stcb->asoc.control_pdapi = sq;
+ sctp_notify_partial_delivery_indication(stcb,
+ SCTP_PARTIAL_DELIVERY_ABORTED, 1);
+ stcb->asoc.control_pdapi = NULL;
}
}
+ /* Add an end to wake them */
sq->end_added = 1;
cnt++;
}
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index c60f04a..6472c2f 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -149,16 +149,6 @@ struct sctp_copy_all {
int cnt_failed;
};
-union sctp_sockstore {
-#ifdef AF_INET
- struct sockaddr_in sin;
-#endif
-#ifdef AF_INET6
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr sa;
-};
-
struct sctp_nets {
TAILQ_ENTRY(sctp_nets) sctp_next; /* next link */
@@ -371,6 +361,7 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
uint16_t port_from;
uint8_t do_not_ref_stcb;
uint8_t end_added;
+ uint8_t pdapi_aborted;
};
/* This data structure will be on the outbound
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 8532b4f..6bd26b3 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <sys/types.h>
#include <sys/socket.h>
+#include <netinet/in.h>
typedef uint32_t sctp_assoc_t;
@@ -871,6 +872,17 @@ struct sctpstat {
#define SCTP_STAT_DECR_COUNTER64(_x) SCTP_STAT_DECR(_x)
#define SCTP_STAT_DECR_GAUGE32(_x) SCTP_STAT_DECR(_x)
+union sctp_sockstore {
+#ifdef AF_INET
+ struct sockaddr_in sin;
+#endif
+#ifdef AF_INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr sa;
+};
+
+
/*
* Kernel defined for sctp_send
*/
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 25d639f..95762b8 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_auth.h>
+
#ifdef IPSEC
#include <netinet6/ipsec.h>
#include <netkey/key.h>
@@ -483,11 +484,12 @@ sctp_ctlinput(cmd, sa, vip)
static int
sctp_getcred(SYSCTL_HANDLER_ARGS)
{
+ struct xucred xuc;
struct sockaddr_in addrs[2];
struct sctp_inpcb *inp;
struct sctp_nets *net;
struct sctp_tcb *stcb;
- int error, s;
+ int error;
/*
* XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket
@@ -502,7 +504,6 @@ sctp_getcred(SYSCTL_HANDLER_ARGS)
if (error)
return (error);
- s = splnet();
stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]),
sintosa(&addrs[1]),
&inp, &net, 1);
@@ -511,15 +512,29 @@ sctp_getcred(SYSCTL_HANDLER_ARGS)
/* reduce ref-count */
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
+ goto cred_can_cont;
}
error = ENOENT;
goto out;
}
- error = SYSCTL_OUT(req, inp->sctp_socket->so_cred, sizeof(struct ucred));
SCTP_TCB_UNLOCK(stcb);
+ /*
+ * We use the write lock here, only since in the error leg we need
+ * it. If we used RLOCK, then we would have to
+ * wlock/decr/unlock/rlock. Which in theory could create a hole.
+ * Better to use higher wlock.
+ */
+ SCTP_INP_WLOCK(inp);
+cred_can_cont:
+ error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
+ if (error) {
+ SCTP_INP_WUNLOCK(inp);
+ goto out;
+ }
+ cru2x(inp->sctp_socket->so_cred, &xuc);
+ SCTP_INP_WUNLOCK(inp);
+ error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
out:
- splx(s);
return (error);
}
@@ -3384,6 +3399,7 @@ sctp_optsset(struct socket *so,
if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) {
/* invalid HMACs were found */ ;
error = EINVAL;
+ sctp_free_hmaclist(hmaclist);
goto sctp_set_hmac_done;
}
}
@@ -4655,8 +4671,10 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port;
sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr;
- if ((error = sa6_recoverscope(sin6)) != 0)
+ if ((error = sa6_recoverscope(sin6)) != 0) {
+ SCTP_FREE_SONAME(sin6);
return (error);
+ }
*addr = (struct sockaddr *)sin6;
}
/* Wake any delayed sleep action */
@@ -4725,6 +4743,10 @@ sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
SCTP_TCB_LOCK(stcb);
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
sin_a = (struct sockaddr_in *)&net->ro._l_addr;
+ if (sin_a == NULL)
+ /* this will make coverity happy */
+ continue;
+
if (sin_a->sin_family == AF_INET) {
fnd = 1;
break;
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 45ebbe5..927e444 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -377,7 +377,12 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
sctp_clog[sctp_cwnd_log_at].time_event = sctp_get_time_of_event();
sctp_clog[sctp_cwnd_log_at].from = (uint8_t) from;
sctp_clog[sctp_cwnd_log_at].event_type = (uint8_t) SCTP_LOG_LOCK_EVENT;
- sctp_clog[sctp_cwnd_log_at].x.lock.sock = (void *)inp->sctp_socket;
+ if (inp) {
+ sctp_clog[sctp_cwnd_log_at].x.lock.sock = (void *)inp->sctp_socket;
+
+ } else {
+ sctp_clog[sctp_cwnd_log_at].x.lock.sock = (void *)NULL;
+ }
sctp_clog[sctp_cwnd_log_at].x.lock.inp = (void *)inp;
if (stcb) {
sctp_clog[sctp_cwnd_log_at].x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx);
@@ -2575,7 +2580,6 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
struct mbuf *m_notify;
struct sctp_assoc_change *sac;
struct sctp_queued_to_read *control;
- int locked = 0;
/*
* First if we are are going down dump everything we can to the
@@ -2589,58 +2593,6 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
/* If the socket is gone we are out of here */
return;
}
- if ((event == SCTP_COMM_LOST) || (event == SCTP_SHUTDOWN_COMP)) {
- if (stcb->asoc.control_pdapi) {
- /*
- * we were in the middle of a PD-API verify its
- * there.
- */
- SCTP_INP_READ_LOCK(stcb->sctp_ep);
- locked = 1;
- TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) {
- if (control == stcb->asoc.control_pdapi) {
- /* Yep its here, notify them */
- if (event == SCTP_COMM_LOST) {
- /*
- * Abort/broken we had a
- * real PD-API aborted
- */
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT)) {
- /*
- * hmm.. don't want
- * a notify if
- * held_lenght is
- * set,they may be
- * stuck. clear and
- * wake.
- */
- if (control->held_length) {
- control->held_length = 0;
- control->end_added = 1;
- }
- } else {
- sctp_notify_partial_delivery_indication(stcb, event, 1);
-
- }
- } else {
- /* implicit EOR on EOF */
- control->held_length = 0;
- control->end_added = 1;
- }
- SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
- locked = 0;
- /* wake him up */
- control->do_not_ref_stcb = 1;
- stcb->asoc.control_pdapi = NULL;
- sorwakeup(stcb->sctp_socket);
- break;
- }
- }
- if (locked)
- SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
-
- }
- }
/*
* For TCP model AND UDP connected sockets we will send an error up
* when an ABORT comes in.
@@ -2936,13 +2888,15 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
&stcb->sctp_socket->so_rcv, 1);
}
+/* This always must be called with the read-queue LOCKED in the INP */
void
sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
- uint32_t error, int no_lock)
+ uint32_t error, int nolock)
{
struct mbuf *m_notify;
struct sctp_pdapi_event *pdapi;
struct sctp_queued_to_read *control;
+ struct sockbuf *sb;
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT))
/* event not enabled */
@@ -2965,62 +2919,44 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
m_notify->m_pkthdr.rcvif = 0;
m_notify->m_len = sizeof(struct sctp_pdapi_event);
m_notify->m_next = NULL;
-
- if (stcb->asoc.control_pdapi != NULL) {
- /* we will do some substitution */
- control = stcb->asoc.control_pdapi;
- if (no_lock == 0)
- SCTP_INP_READ_LOCK(stcb->sctp_ep);
-
- if (control->data == NULL) {
- control->data = control->tail_mbuf = m_notify;
- control->held_length = 0;
- control->length = m_notify->m_len;
- control->end_added = 1;
- sctp_sballoc(stcb,
- &stcb->sctp_socket->so_rcv,
- m_notify);
- } else if (control->end_added == 0) {
- struct mbuf *m = NULL;
-
- m = control->data;
- while (m) {
- sctp_sbfree(control, stcb,
- &stcb->sctp_socket->so_rcv, m);
- m = sctp_m_free(m);
- }
- control->data = NULL;
- control->length = m_notify->m_len;
- control->data = control->tail_mbuf = m_notify;
- control->held_length = 0;
- control->end_added = 1;
- sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
- } else {
- /* Hmm .. should not happen */
- control->end_added = 1;
- stcb->asoc.control_pdapi = NULL;
- goto add_to_end;
- }
- if (no_lock == 0)
- SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+ control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
+ 0, 0, 0, 0, 0, 0,
+ m_notify);
+ if (control == NULL) {
+ /* no memory */
+ sctp_m_freem(m_notify);
+ return;
+ }
+ control->length = m_notify->m_len;
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
+ control->held_length = 0;
+ control->length = 0;
+ if (nolock == 0) {
+ SCTP_INP_READ_LOCK(stcb->sctp_ep);
+ }
+ sb = &stcb->sctp_socket->so_rcv;
+#ifdef SCTP_SB_LOGGING
+ sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, m_notify->m_len);
+#endif
+ sctp_sballoc(stcb, sb, m_notify);
+#ifdef SCTP_SB_LOGGING
+ sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
+#endif
+ atomic_add_int(&control->length, m_notify->m_len);
+ control->end_added = 1;
+ if (stcb->asoc.control_pdapi)
+ TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
+ else {
+ /* we really should not see this case */
+ TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next);
+ }
+ if (nolock == 0) {
+ SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+ }
+ if (stcb->sctp_ep && stcb->sctp_socket) {
+ /* This should always be the case */
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
- } else {
- /* append to socket */
-add_to_end:
- control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
- 0, 0, 0, 0, 0, 0,
- m_notify);
- if (control == NULL) {
- /* no memory */
- sctp_m_freem(m_notify);
- return;
- }
- control->length = m_notify->m_len;
- /* not that we need this */
- control->tail_mbuf = m_notify;
- sctp_add_to_readq(stcb->sctp_ep, stcb,
- control,
- &stcb->sctp_socket->so_rcv, 1);
}
}
@@ -3150,10 +3086,14 @@ void
sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
uint32_t error, void *data)
{
+ if (stcb == NULL) {
+ /* unlikely but */
+ return;
+ }
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)
- ) {
+ ) {
/* No notifications up when we are in a no socket state */
return;
}
@@ -3829,6 +3769,13 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
*/
struct mbuf *m, *prev = NULL;
+ if (inp == NULL) {
+ /* Gak, TSNH!! */
+#ifdef INVARIENTS
+ panic("Gak, inp NULL on add_to_readq");
+#endif
+ return;
+ }
SCTP_INP_READ_LOCK(inp);
m = control->data;
control->held_length = 0;
@@ -5032,6 +4979,8 @@ wait_some_more:
if (control->end_added == 1) {
/* he aborted, or is done i.e.did a shutdown */
out_flags |= MSG_EOR;
+ if (control->pdapi_aborted)
+ out_flags |= MSG_TRUNC;
goto done_with_control;
}
if (so->so_rcv.sb_cc > held_length) {
@@ -5143,6 +5092,8 @@ get_more_data2:
* shutdown
*/
out_flags |= MSG_EOR;
+ if (control->pdapi_aborted)
+ out_flags |= MSG_TRUNC;
goto done_with_control;
}
if (so->so_rcv.sb_cc > held_length) {
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 3483658..8f8b62a 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -476,11 +476,12 @@ sctp6_ctlinput(cmd, pktdst, d)
static int
sctp6_getcred(SYSCTL_HANDLER_ARGS)
{
+ struct xucred xuc;
struct sockaddr_in6 addrs[2];
struct sctp_inpcb *inp;
struct sctp_nets *net;
struct sctp_tcb *stcb;
- int error, s;
+ int error;
/*
* XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket
@@ -499,26 +500,38 @@ sctp6_getcred(SYSCTL_HANDLER_ARGS)
error = SYSCTL_IN(req, addrs, sizeof(addrs));
if (error)
return (error);
- s = splnet();
stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
sin6tosa(&addrs[1]),
&inp, &net, 1);
if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
- error = ENOENT;
- if (inp) {
+ if ((inp != NULL) && (stcb == NULL)) {
+ /* reduce ref-count */
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
+ goto cred_can_cont;
}
+ error = ENOENT;
goto out;
}
- error = SYSCTL_OUT(req, inp->sctp_socket->so_cred,
- sizeof(struct ucred));
-
SCTP_TCB_UNLOCK(stcb);
+ /*
+ * We use the write lock here, only since in the error leg we need
+ * it. If we used RLOCK, then we would have to
+ * wlock/decr/unlock/rlock. Which in theory could create a hole.
+ * Better to use higher wlock.
+ */
+ SCTP_INP_WLOCK(inp);
+cred_can_cont:
+ error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
+ if (error) {
+ SCTP_INP_WUNLOCK(inp);
+ goto out;
+ }
+ cru2x(inp->sctp_socket->so_cred, &xuc);
+ SCTP_INP_WUNLOCK(inp);
+ error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
out:
- splx(s);
return (error);
}
@@ -1177,6 +1190,10 @@ sctp6_getaddr(struct socket *so, struct sockaddr **addr)
sin_a6 = NULL;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
+ if (sin_a6 == NULL)
+ /* this will make coverity happy */
+ continue;
+
if (sin_a6->sin6_family == AF_INET6) {
fnd = 1;
break;
@@ -1217,8 +1234,10 @@ sctp6_getaddr(struct socket *so, struct sockaddr **addr)
}
SCTP_INP_RUNLOCK(inp);
/* Scoping things for v6 */
- if ((error = sa6_recoverscope(sin6)) != 0)
+ if ((error = sa6_recoverscope(sin6)) != 0) {
+ SCTP_FREE_SONAME(sin6);
return (error);
+ }
(*addr) = (struct sockaddr *)sin6;
return (0);
}
OpenPOWER on IntegriCloud