NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/44054: Stacksmashing in handling of ioctl OOSIO* parameter



>Number:         44054
>Category:       kern
>Synopsis:       Stacksmashing in handling of ioctl OOSIO* parameter
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Nov 06 11:25:00 +0000 2010
>Originator:     Onno van der Linden
>Release:        NetBSD/i386 5.99.39
>Organization:
>Environment:
NetBSD sheep 5.99.39 NetBSD 5.99.39 (SHEEP) #35: Sat Nov  6 11:40:11 MET 2010  
onno@sheep:/usr/src/sys/arch/i386/compile/SHEEP i386
>Description:
For ioctl parameters OOSIOCGIFADDR, OOSIOCGIFDSTADDR, OOSIOCGIFBRDADDR and 
OOSIOCGIFNETMASK a  wrongly sized data buffer is passed on the stack to
ifreq_setaddr() where the call to memset() will smash the stack.
>How-To-Repeat:
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct oifreq {
        char    ifr_name[IFNAMSIZ];             /* if name, e.g. "en0" */
        union {
                struct  sockaddr ifru_addr;
                struct  sockaddr ifru_dstaddr;
                struct  sockaddr ifru_broadaddr;
                short   ifru_flags;  
                int     ifru_metric;
                int     ifru_mtu; 
                int     ifru_dlt;
                u_int   ifru_value;
                void *  ifru_data;
                struct {
                        uint32_t        b_buflen;
                        void            *b_buf;
                } ifru_b;
        } ifr_ifru;
};      


#define OOSIOCGIFBRDADDR _IOWR('i', 18, struct oifreq)

main()
{
        int     fd;
        struct oifreq   ifreq;
        struct sockaddr_in      *sin;

        memset(&ifreq,'\0',sizeof ifreq);
        strcpy(ifreq.ifr_name,"wm0");

        fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (fd < 0) {
                perror("socket");
                exit(1);
        }

        if (ioctl(fd, OOSIOCGIFBRDADDR, &ifreq) < 0) {
                perror("OOSIOCGIFBRDADDR");
                exit(1);
        }
        sin = (struct sockaddr_in *)&ifreq.ifr_broadaddr;
        printf("broadcast: %s\n", inet_ntoa(sin->sin_addr));

        close(fd);
}

>Fix:
compat_cvtcmd() doesn't translate the OOSIO parameter into its SIO counterpart,
there's some special handling in compat_ifioctl() already which could be used
to pass a rightly sized buffer, like the way the OSIO parameters are handled in 
ifioctl().

Another possible fix is to put a case statement in compat_cvtcmd() in place of 
the
ncmd assignment where the OOSIO parameters (and others ?) are handled as
seperate cases and in which the default case gets the ncmd assignment. But 
that probably needs some additional changes to compat_ifioctl() too.





Home | Main Index | Thread Index | Old Index