> > look at the second get_msg of t_rcv. send it a heap of tcp oob data and > it overflows right away > > sinner I assume you mean getmsg(2), right? I located t_rcv() in network services libs (libnsl). Jesus, who found this anyway?.. I can't find any indication in the source how it handles OOB. From a glance, I see that the first getmsg receives a message from the transport provider, then depending on the "type" an "Orderly release" (T_ORDREL_IND), or a disconnect indication (T_DISCON_IND) cause the second getmsg(2) if the return from last getmsg has MOREDATA flags set. Where is the overrun though? What buffer, ctlbuf? If so, wouldn't the actual overrun be in getmsg(2)? If you don't know, could you forward my request to the person you're talking to who knows? --8<---src/lib/libnsl/nsl/t_rcv.c:---8<-- t_rcv(fd, buf, nbytes, flags) int fd; register char *buf; unsigned nbytes; int *flags; { struct strbuf ctlbuf, rcvbuf; int retval, flg = 0; int msglen; register union T_primitives *pptr; register struct _ti_user *tiptr; sigset_t mask; trace3(TR_t_rcv, 0, fd, nbytes); if ((tiptr = _t_checkfd(fd)) == NULL) { int sv_errno = errno; trace3(TR_t_rcv, 1, fd, nbytes); errno = sv_errno; return (-1); } MUTEX_LOCK_SIGMASK(&tiptr->ti_lock, mask); if (tiptr->ti_servtype == T_CLTS) { t_errno = TNOTSUPPORT; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); return (-1); } /* * Check in lookbuf for stuff */ if (tiptr->ti_lookflg) { /* * Beware - this is right! * If something in lookbuf then check * read queue to see if there is something there. * If there is something there and there is not a * discon in lookbuf, then it must be a discon. * If so, fall through to get it off of queue. * I fall through to make sure it is a discon, * instead of making check here. * * If nothing in read queue then just return TLOOK. */ if ((retval = ioctl(fd, I_NREAD, &msglen)) < 0) { int sv_errno = errno; t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = sv_errno; return (-1); } if (retval) { if (*((long *)tiptr->ti_lookcbuf) == T_DISCON_IND) { t_errno = TLOOK; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); return (-1); } } else { t_errno = TLOOK; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); return (-1); } } ctlbuf.maxlen = tiptr->ti_ctlsize; ctlbuf.len = 0; ctlbuf.buf = tiptr->ti_ctlbuf; rcvbuf.maxlen = nbytes; rcvbuf.len = 0; rcvbuf.buf = buf; *flags = 0; /* * data goes right in user buffer */ if ((retval = getmsg(fd, &ctlbuf, &rcvbuf, &flg)) < 0) { int sv_errno = errno; if (errno == EAGAIN) t_errno = TNODATA; else t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = sv_errno; return (-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; if (ctlbuf.len > 0) { if (ctlbuf.len < sizeof (long)) { t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = EPROTO; return (-1); } pptr = (union T_primitives *)ctlbuf.buf; switch (pptr->type) { case T_EXDATA_IND: *flags |= T_EXPEDITED; if (retval) tiptr->ti_flags |= EXPEDITED; /* flow thru */ case T_DATA_IND: if ((ctlbuf.len < sizeof (struct T_data_ind)) || (tiptr->ti_lookflg)) { t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = EPROTO; return (-1); } if ((pptr->data_ind.MORE_flag) || retval) *flags |= T_MORE; if ((pptr->data_ind.MORE_flag) && retval) tiptr->ti_flags |= MORE; tiptr->ti_state = TLI_NEXTSTATE(T_RCV, tiptr->ti_state); #ifdef DEBUG if (tiptr->ti_state == nvs) syslog(LOG_ERR, "t_rcv: invalid state event T_RCV"); #endif DEBUG MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); return (rcvbuf.len); case T_ORDREL_IND: if (tiptr->ti_lookflg) { t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = EPROTO; return (-1); } /* flow thru */ case T_DISCON_IND: _t_putback(tiptr, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); if (retval&MOREDATA) { ctlbuf.maxlen = 0; ctlbuf.len = 0; ctlbuf.buf = tiptr->ti_ctlbuf; rcvbuf.maxlen = tiptr->ti_rcvsize - rcvbuf.len; rcvbuf.len = 0; rcvbuf.buf = tiptr->ti_lookdbuf + tiptr->ti_lookdsize; *flags = 0; if ((retval = getmsg(fd, &ctlbuf, &rcvbuf, &flg)) < 0) { int sv_errno = errno; t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK( &tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = sv_errno; return (-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; if (retval) { t_errno = TSYSERR; tiptr->ti_lookflg = 0; MUTEX_UNLOCK_SIGMASK( &tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = EPROTO; return (-1); } tiptr->ti_lookdsize += rcvbuf.len; } t_errno = TLOOK; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); return (-1); default: break; } t_errno = TSYSERR; MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); errno = EPROTO; return (-1); } else { if (!retval && (tiptr->ti_flags&MORE)) { *flags |= T_MORE; tiptr->ti_flags &= ~MORE; } if (retval) *flags |= T_MORE; /* * If inside an ETSDU, set expedited flag and turn * of internal version when reach end of "ETIDU". */ if (tiptr->ti_flags & EXPEDITED) { *flags |= T_EXPEDITED; if (!retval) tiptr->ti_flags &= ~EXPEDITED; } tiptr->ti_state = TLI_NEXTSTATE(T_RCV, tiptr->ti_state); #ifdef DEBUG if (tiptr->ti_state == nvs) syslog(LOG_ERR, "t_rcv: invalid state event T_RCV"); #endif DEBUG MUTEX_UNLOCK_SIGMASK(&tiptr->ti_lock, mask); trace3(TR_t_rcv, 1, fd, nbytes); return (rcvbuf.len); } }