Bug 29336

Summary: non-privileged user opening routing socket causes resource leak
Product: Base System Reporter: Richard Andrades <richard>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Richard Andrades 2001-07-31 00:30:01 UTC
If a routing socket is opened without root permissions, the socket() 
call fails. But the kernel fails to free the socket structure which 
it already allocated at the begining of the system call. This causes
a resource leak in the socket table. If this happens often enough,
the system runs out of socket descriptors and is unable to start
any new network operations.

Fix: 

Note: I checked the latest version and this bug has not yet been fixed.

FILE: src/sys/net/rtsock.c
Function: rts_attach()        
---Begin code fragment----------------------------------------
        MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK); /* XXX */
        if (rp == 0)
                return ENOBUFS;
        bzero(rp, sizeof *rp);

        /*
         * The splnet() is necessary to block protocols from sending
         * error notifications (like RTM_REDIRECT or RTM_LOSING) while
         * this PCB is extant but incompletely initialized.
         * Probably we should try to do more of this work beforehand and
         * eliminate the spl.
         */
        s = splnet();
        so->so_pcb = (caddr_t)rp;
        error = raw_usrreqs.pru_attach(so, proto, p); /* NOTE: Will return error if not root */
        rp = sotorawcb(so);
        if (error) {
/* Begin BUG FIX */
                so->so_pcb = 0; /* Otherwise the socket won't be freed */
/* End BUG FIX */
                splx(s);
                free(rp, M_PCB);
                return error;
        }
---End code fragment------------------------------------------------


Explanation:
************

In the function socreate() in the file src/sys/kern/uipc_socket.c
there is the following code fragment:
-----------------------------
        error = (*prp->pr_usrreqs->pru_attach)(so, proto, p); /* NOTE: This goes to rts_attach() */
        if (error) {
                so->so_state |= SS_NOFDREF;
                sofree(so);
                return (error);
        }        
------------------------------------

Looking at the function sofree() in the same file, we find:
-------------------------------------
void
sofree(so)
        register struct socket *so;
{
        struct socket *head = so->so_head;

        if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
                return; 
-----------------------------------

So if rts_attach() fails to reset the so_pcb member, sofree()
will not free the socket.
How-To-Repeat: Run:
---------------------------------------
main()
{
    for(;;)
        socket(AF_ROUTE, SOCK_RAW, 0); 
}
---------------------------------------
as a non-root user.
Comment 1 Jonathan Chen freebsd_committer freebsd_triage 2001-08-02 20:58:03 UTC
State Changed
From-To: open->closed

fix committed in -CURRENT.  MFC after 4.4-RELEASE.