简体   繁体   English

套接字连接上的缓冲区溢出

[英]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. 我们正在使用Rapidjson库发送数据,我不知道为什么如果完全相同的代码在他的计算机上可以完美运行,为什么会发生这种情况,唯一的区别是我在VM上运行Ubuntu,而他在将Ubuntu作为主要操作系统。 I would really appreciate your help, the code fails on this if: 非常感谢您的帮助,如果出现以下情况,代码将失败:

if ((valread = read( sd , buffer, 1024)) == 0) 如果((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. 顺便说一句,我们俩都使用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: 还要注意,使用TCP读取时,您可能无法在read()调用中获得整个消息,因此buffer可能不会以null终止,这可能会在这里引起问题:

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 在这里,您向操作系统说谎的时候,关于buffer的大小是400,而不是1024。这行代码应该是

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

and you also need to check it for -1. 并且还需要检查它是否为-1。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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