简体   繁体   中英

Buffer overflow on socket connection

i was working on a socket server on a friend's computer and everythng was working fine but then i executed the code on my computer and it throws a buffer overflow like this

*** buffer overflow detected ***: /home/erick/CLionProjects/AirWar++/cmake-build-debug/AirWar__ terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f906c5047e5]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7f906c5a556c]
/lib/x86_64-linux-gnu/libc.so.6(+0x116570)[0x7f906c5a3570]
/lib/x86_64-linux-gnu/libc.so.6(+0x1169da)[0x7f906c5a39da]

We are using rapidjson library to send the data, i dont know why this happens if the exact same code runs perfectly on his computer, the only difference is that i am running Ubuntu on a VM and he was running Ubuntu as the main OS. I would really appreciate your help, the code fails on this if:

if ((valread = read( sd , buffer, 1024)) == 0)

int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[3] ,
max_clients = 3 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;

void server::init() {

using namespace rapidjson;
char buffer[400];

//set of socket descriptors
fd_set readfds;

//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
    client_socket[i] = 0;
}

//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
    perror("socket failed");
    exit(EXIT_FAILURE);
}

//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
               sizeof(opt)) < 0 )
{
    perror("setsockopt");
    exit(EXIT_FAILURE);
}

//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.100.19");//Write your IP
address.sin_port = htons( PORT );

//bind the socket to localhost port 8080
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
    perror("bind failed");
    exit(EXIT_FAILURE);
}
printf("Escuchando en el puerto %d \n", PORT);

//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
    perror("listen");
    exit(EXIT_FAILURE);
}

//accept the incoming connection
addrlen = sizeof(address);


puts("Esperando conexiones ...");

while(TRUE)
{
    //clear the socket set
    FD_ZERO(&readfds);

    //add master socket to set
    FD_SET(master_socket, &readfds);
    max_sd = master_socket;

    //add child sockets to set
    for ( i = 0 ; i < max_clients ; i++)
    {
        //socket descriptor
        sd = client_socket[i];

        //if valid socket descriptor then add to read list
        if(sd > 0)
            FD_SET( sd , &readfds);

        //highest file descriptor number, need it for the select function
        if(sd > max_sd)
            max_sd = sd;
    }

    //wait for an activity on one of the sockets , timeout is NULL ,
    //so wait indefinitely
    activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);

    if ((activity < 0) && (errno!=EINTR))
    {
        printf("select error");
    }

    //If something happened on the master socket ,
    //then its an incoming connection
    if (FD_ISSET(master_socket, &readfds))
    {
        if ((new_socket = accept(master_socket,
                                 (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
        {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        //inform user of socket number
        printf("Nueva conexion , socket fd %d , ip : %s , puerto : %d\n" , new_socket , inet_ntoa(address.sin_addr) , ntohs
        (address.sin_port));

        //send new connection message
        //if( send(new_socket, "Conectado", strlen("Conectado"), 0) != strlen("Conectado") )
        //{
        //  perror("send");
        //}

        //puts("Mensaje enviado con exito");//succesfully send


        //add new socket to array of sockets
        for (i = 0; i < max_clients; i++)
        {
            //if position is empty
            if( client_socket[i] == 0 )
            {
                client_socket[i] = new_socket;
                printf("Añadido a la lista de sockets como %d\n" , i);
                break;
            }
        }
    }

    //else its some IO operation on some other socket
    for (i = 0; i < max_clients; i++)
    {
        sd = client_socket[i];

        if (FD_ISSET( sd , &readfds))
        {
            //Check if it was for closing , and read the message
            if ((valread = read( sd , buffer, 1024)) == 0)
            {
                //Somebody disconnected , get his details and print
                getpeername(sd , (struct sockaddr*)&address , \
                    (socklen_t*)&addrlen);
                printf("Cliente desconectado , ip %s , port %d \n" ,
                       inet_ntoa(address.sin_addr) , ntohs(address.sin_port));

                //Close the socket and mark as 0 in list for reuse
                run=FALSE;
                close( sd );
                client_socket[i] = 0;
            }

                //Echo back the message that came in
            else
            {

                //se eliminan dos caracteres nulos del buffer;


                std::string m=buffer;
                std::string s(m.substr(0,valread));
                const char * json= s.c_str();
                std::cout<<json;

                Document d;
                d.Parse(json);
                Value& type=d["type"];


                if(strcmp(type.GetString(),"shoot")==0){
                    stat= 5;//Dispara
                }else if(strcmp(type.GetString(),"izq")==0){
                    //Mov. izquierda
                    stat= 4;
                }else if(strcmp(type.GetString(),"der")==0){
                    //Mov. derecha
                    stat=6;
                }else if(strcmp(type.GetString(),"arr")==0){
                    //Mov. arriba
                    stat=8;
                }else if(strcmp(type.GetString(),"aba")==0){
                    //Mov. abajo
                    stat= 2;
                }else{
                    stat=0;//Quieta
                }



            }
        }
    }
}
}  
long server:: Send(const char * msg){
send(client_socket[0],msg,strlen(msg),0);
}

Btw we both use CLion. Will be waiting for your help, thanks!

char buffer[400];
//          ^^^

...

if ((valread = read( sd , buffer, 1024)) == 0)
//                                ^^^^

I hate to sound like a jerk, but didn't the error message prompt you to check the size of buffers that you were reading data into?

Also note that with TCP reads you might not get the entire message in a read() call so buffer might not be null terminated which can cause problems here:

std::string m=buffer;

And this line makes me think that the null terminator might not even be part of the message (we'd have to see the client code to be sure):

send(client_socket[0],msg,strlen(msg),0);

Buffer overflow is exactly what it is.

if ((valread = read( sd , buffer, 1024)) == 0)

Here you are lying to the operating system about the size of buffer , which is 400, not 1024. This line of code should be

if ((valread = read( sd , buffer, sizeof buffer)) == 0)

and you also need to check it for -1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM