C-код работает на archlinux, но не на Ubuntu 10.04 - PullRequest
0 голосов
/ 25 февраля 2011

Я работал с другом, чтобы написать какой-то код, и он в основном был протестирован на archlinux. Когда мы пришли к перекомпиляции и тестированию в Ubuntu, она проходит через программу, а затем возвращает ошибку разрушения стека. Я добавил несколько операторов печати, чтобы выяснить, где происходит сбой, но никто из нас не может увидеть причину.

Код такой, как показано ниже, ошибка возникает, когда код возвращается из функции «authenticate»:

/** Includes **/
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>

#include <pthread.h>
#include <mysql.h>


/* Definitions */
#define     LIC_SERVER_PORTNO   2325
//#define       LIC_SERVER_ADDR     "69.68.67.66"
#define     SERVER_PORTNO       4959
#define     UPLEN           45
#define     MAX_USER_NUM        100
//#define       MAX_KA_TIME     2000
#define     MAX_KA_TIME     20

/** Structure to hold info on logged in users **/
typedef struct {
    char *ip;
    time_t login_time;
    time_t last_check;
} user;

/** GLOBALS **/
user *users;
int user_num;

/** Version string function **/
const char* version()
{
     return "0.1r3";
}

void exit_signal(int sig)
{
  pthread_exit(NULL);
   printf("\nTerminating server. Goodbye!\n\n"); 
  (void) signal(SIGINT, SIG_DFL); 
  exit(0);
}

/** Function for error reporting **/
void error(char *msg)
{
    perror(msg);
    exit(1);
}

int authenticate(char* uname,char* pwd)
{
   MYSQL *conn;
   MYSQL_RES *res;
   MYSQL_ROW row;

   int r=0;

   const char *server = "localhost";
   const char *user = "root";
   const char *password = "12345"; /* set me first */
   const char *database = "test";
    printf("inside authenticate %s\n","one");
   conn = mysql_init(NULL);

   /* Connect to database */
   if (!mysql_real_connect(conn, server,user, password, database, 0, NULL, 0)) {
      fprintf(stderr, "%s\n", mysql_error(conn));
      exit(1);
   }
    printf("inside authenticate %s\n","two");
   /* send SQL query */
   char query [] = "select * from users where username='";
   char q2 [] = "';";
   //char *tmp,*query;

   strcat(query,uname);
   strcat(query,q2);
   printf("inside authenticate %s\n","three");
   if (mysql_query(conn,query)) {
      fprintf(stderr, "%s\n", mysql_error(conn));
      exit(1);
   }

   res = mysql_use_result(conn);
   if (res==NULL) return 0;
   row = mysql_fetch_row(res);
   if (row==NULL) return 0;
   printf("inside authenticate %s\n","four");
   if ( (strcmp(row[2],uname)==0) && (strcmp(row[3],pwd)==0) )
    r = 1;

       /* close connection */
       mysql_free_result(res);
       mysql_close(conn);
       printf("inside authenticate %s\n","five");
       return r;
    }

    /** Keep alive guard **/
    void *keep_alive_guard(void *thread_data)
    {
        int i,k,c;
        time_t ts;


        while (1) {
    ts = time(NULL);
        for (i=0;i<user_num;i++) {

            char the_ip[50],the_ip2[50];
    char scall1[1024],scall2[1024];

        if (ts-users[i].last_check>MAX_KA_TIME) {           
              strncpy(the_ip,users[i].ip,50);      
              strncpy(the_ip2,users[i].ip,50);

              // system call to delete redirection for all incoming packets to licence server for port 1055
              strncpy(scall1,"iptables -t nat -D PREROUTING -s ",1024);   

              strcat(scall1,the_ip);
              strcat(scall1," -j REDIRECT -p tcp --to-port 1055 --dport 4957");
              //printf("%s\n",scall1);
              FILE *phony = popen(scall1,"r");
              pclose(phony);

              // system call to delete redirection for all incoming packets to licence server for port 2325
              strncpy(scall2,"iptables -t nat -D PREROUTING -s ",1024);

              strcat(scall2,the_ip2);             
              strcat(scall2," -j REDIRECT -p tcp --to-port 2325 --dport 4958");           
              //printf("%s\n",scall2);
              FILE *phony2 = popen(scall2,"r");
              pclose(phony2);

              for (k=i;k<user_num;k++) {
            if (k!=MAX_USER_NUM-1) {
                memcpy(&users[k],&users[k+1],sizeof(user));
            }
              }
              user_num--;

        }
    }
    }
}

/* Main function */
int main(int argc,char* argv[])
{
     // Initializing
     printf("Licence proxy (server) v%s\n",version());
     printf("Initializing...");

     user_num = 0;
     users = (user*)malloc(MAX_USER_NUM*sizeof(user));

     (void) signal(SIGINT, exit_signal);

     FILE *notha = popen("iptables -A INPUT ! -s 127.0.0.1 -p tcp --dport 1055 -j DROP","r");
     pclose(notha);
     FILE *notha2 = popen("iptables -A INPUT ! -s 127.0.0.1 -p tcp --dport 2325 -j DROP","r");
     pclose(notha2);

     // Basic variables for socket handling
     int sockfd, newsockfd, portno, clilen;
     struct sockaddr_in serv_addr, cli_addr; //addresses
     int n,i;

     // Create socket
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error((char*)"ERROR opening socket");

     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = SERVER_PORTNO;  // Set port number to listen

     // Set options for socket and bind to port
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
              error((char*)"ERROR on binding");

     printf("ok!\n\nRunning...\n\n");

     // Start listening
    listen(sockfd,5);

    // Create thread for keep alive guard
    pthread_t kag;
    int rc;
    rc = pthread_create(&kag,NULL,keep_alive_guard,(void *)user_num);

    char datauser [UPLEN],*user;
    char datapass [UPLEN],*pass;
    char datareq_id [UPLEN],*req_id;
    char respOK [] = "OK";
    char respNK [] = "NK";

    while (1) { 
    // Accept connection from peer
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,(socklen_t*)&clilen);
    if (newsockfd < 0) 
          error((char*)"ERROR on accept");

    n = recv(newsockfd,datareq_id,UPLEN,0);
    if (n < 0) error((char*)"ERROR reading username from client");
    req_id = (char*)malloc(strlen(datareq_id));
    strncpy(req_id,datareq_id,strlen(datareq_id));

    if (req_id[0]=='K') {
        for (i=0;i<user_num;i++) {
        if (strcmp(users[i].ip,inet_ntoa(cli_addr.sin_addr))==0) {
            users[i].last_check = time(NULL);
        }
        }           
    }
    else if (req_id[0]=='L') {

        printf("Transaction requested from %s\n",inet_ntoa(cli_addr.sin_addr)); 

        // Read and wrap username from client   
        n = recv(newsockfd,datauser,UPLEN,0);
            if (n < 0) error((char*)"ERROR reading username from client");
    user = (char*)malloc(strlen(datauser));
        strncpy(user,datauser,strlen(datauser));
        printf("here %s\n","one");
        // Read and wrap password from client   
        n = recv(newsockfd,datapass,UPLEN,0);
        if (n < 0) error((char*)"ERROR reading password from client");      
        pass = (char*)malloc(strlen(datapass));
        strncpy(pass,datapass,strlen(datapass));
        printf("here %s\n","two");
        char scall[1024],scall2[1024];
        printf("here %s\n","two + one line");
        //Cross-check authorization data against MYSQL database and take action
        if (authenticate(user,pass)==1) {
              printf("outside authenticate (success) %s\n","one");
          n = send(newsockfd,respOK,UPLEN,0);
              printf("outside authenticate (success) %s\n","two");
          if (n < 0) error((char*)"ERROR writing to socket");
          printf("here %s\n","two and a lot");
          // system call to redirect all incoming packets to licence server for port 1055
          strncpy(scall,"iptables -t nat -A PREROUTING -s ",1024);   
          printf("here %s\n","three");
          strcat(scall,inet_ntoa(cli_addr.sin_addr));         
          strcat(scall," -j REDIRECT -p tcp --to-port 1055 --dport 4957");
          //printf("%s\n",scall);
          FILE *phony = popen(scall,"r");
          pclose(phony);
            printf("here %s\n","four");
          // system call to redirect all incoming packets to licence server for port 2325
          strncpy(scall2,"iptables -t nat -A PREROUTING -s ",1024);   

          strcat(scall2,inet_ntoa(cli_addr.sin_addr));        
          strcat(scall2," -j REDIRECT -p tcp --to-port 2325 --dport 4958");
          //printf("%s\n",scall2);
          FILE *phony2 = popen(scall2,"r");
          pclose(phony2);                 
          printf("here %s\n","five");
          printf("%s successfully logged in.\n",inet_ntoa(cli_addr.sin_addr));
          users[user_num].ip = (char*)malloc(strlen(inet_ntoa(cli_addr.sin_addr)));
          strncpy(users[user_num].ip,inet_ntoa(cli_addr.sin_addr),strlen(inet_ntoa(cli_addr.sin_addr)));

          printf("here %s\n","six");          
          users[user_num].login_time = time(NULL);
          users[user_num].last_check = time(NULL);
          user_num++;

        }
        else 
        {         
          printf("outside authenticate (fail) %s","one");
          n = send(newsockfd,respNK,UPLEN,0);
          if (n < 0) error((char*)"ERROR writing to socket");
          printf("Access denied to %s.\n",inet_ntoa(cli_addr.sin_addr));
        }

        free(user);
        free(pass);
    }
    close(newsockfd);       
     }
     shutdown(sockfd,SHUT_RDWR);
     close(sockfd);
     pthread_exit(NULL);

     return 0; 
}

Местоположение ошибки указано в выводе консоли ниже:

    Transaction requested from 192.168.1.10
    here one
    here two
    here two + one line
    inside authenticate one
    inside authenticate two
    inside authenticate three
    inside authenticate four
    inside authenticate five
    *** stack smashing detected ***: ./lproxy-server terminated
    ======= Backtrace: =========
    /lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x50)[0xb757f390]
    /lib/tls/i686/cmov/libc.so.6(+0xe233a)[0xb757f33a]
    ./lproxy-server(authenticate+0x28c)[0x8049299]
    ./lproxy-server(main+0x49d)[0x804998e]
    /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb74b3bd6]
    ./lproxy-server[0x8048f41]
    ======= Memory map: ========
    08048000-0804b000 r-xp 00000000 08:01 128583     /home/martin/Downloads/licproxy-server2/lproxy-server
    0804b000-0804c000 r--p 00002000 08:01 128583     /home/martin/Downloads/licproxy-server2/lproxy-server
    0804c000-0804d000 rw-p 00003000 08:01 128583     /home/martin/Downloads/licproxy-server2/lproxy-server
    0915b000-0917c000 rw-p 00000000 00:00 0          [heap]
    b6bce000-b6beb000 r-xp 00000000 08:01 2648       /lib/libgcc_s.so.1
    b6beb000-b6bec000 r--p 0001c000 08:01 2648       /lib/libgcc_s.so.1
    b6bec000-b6bed000 rw-p 0001d000 08:01 2648       /lib/libgcc_s.so.1
    b6bfc000-b6bfd000 ---p 00000000 00:00 0 
    b6bfd000-b73ff000 rw-p 00000000 00:00 0 
    b73ff000-b7412000 r-xp 00000000 08:01 2763       /lib/libz.so.1.2.3.3
    b7412000-b7413000 r--p 00012000 08:01 2763       /lib/libz.so.1.2.3.3
    b7413000-b7414000 rw-p 00013000 08:01 2763       /lib/libz.so.1.2.3.3
    b7414000-b7438000 r-xp 00000000 08:01 8012       /lib/tls/i686/cmov/libm-2.11.1.so
    b7438000-b7439000 r--p 00023000 08:01 8012       /lib/tls/i686/cmov/libm-2.11.1.so
    b7439000-b743a000 rw-p 00024000 08:01 8012       /lib/tls/i686/cmov/libm-2.11.1.so
    b743a000-b744d000 r-xp 00000000 08:01 8048       /lib/tls/i686/cmov/libnsl-2.11.1.so
    b744d000-b744e000 r--p 00012000 08:01 8048       /lib/tls/i686/cmov/libnsl-2.11.1.so
    b744e000-b744f000 rw-p 00013000 08:01 8048       /lib/tls/i686/cmov/libnsl-2.11.1.so
    b744f000-b7451000 rw-p 00000000 00:00 0 
    b7451000-b745a000 r-xp 00000000 08:01 7807       /lib/tls/i686/cmov/libcrypt-2.11.1.so
    b745a000-b745b000 r--p 00008000 08:01 7807       /lib/tls/i686/cmov/libcrypt-2.11.1.so
    b745b000-b745c000 rw-p 00009000 08:01 7807       /lib/tls/i686/cmov/libcrypt-2.11.1.so
    b745c000-b7483000 rw-p 00000000 00:00 0 
    b7483000-b7498000 r-xp 00000000 08:01 8259       /lib/tls/i686/cmov/libpthread-2.11.1.so
    b7498000-b7499000 r--p 00014000 08:01 8259       /lib/tls/i686/cmov/libpthread-2.11.1.so
    b7499000-b749a000 rw-p 00015000 08:01 8259       /lib/tls/i686/cmov/libpthread-2.11.1.so
    b749a000-b749d000 rw-p 00000000 00:00 0 
    b749d000-b75f0000 r-xp 00000000 08:01 7789       /lib/tls/i686/cmov/libc-2.11.1.so
    b75f0000-b75f1000 ---p 00153000 08:01 7789       /lib/tls/i686/cmov/libc-2.11.1.so
    b75f1000-b75f3000 r--p 00153000 08:01 7789       /lib/tls/i686/cmov/libc-2.11.1.so
    b75f3000-b75f4000 rw-p 00155000 08:01 7789       /lib/tls/i686/cmov/libc-2.11.1.so
    b75f4000-b75f7000 rw-p 00000000 00:00 0 
    b75f7000-b77a1000 r-xp 00000000 08:01 5403       /usr/lib/libmysqlclient.so.16.0.0
    b77a1000-b77a2000 ---p 001aa000 08:01 5403       /usr/lib/libmysqlclient.so.16.0.0
    b77a2000-b77a5000 r--p 001aa000 08:01 5403       /usr/lib/libmysqlclient.so.16.0.0
    b77a5000-b77ea000 rw-p 001ad000 08:01 5403       /usr/lib/libmysqlclient.so.16.0.0
    b77ea000-b77eb000 rw-p 00000000 00:00 0 
    b77ed000-b77f7000 r-xp 00000000 08:01 8119       /lib/tls/i686/cmov/libnss_files-2.11.1.so
    b77f7000-b77f8000 r--p 00009000 08:01 8119       /lib/tls/i686/cmov/libnss_files-2.11.1.so
    b77f8000-b77f9000 rw-p 0000a000 08:01 8119       /lib/tls/i686/cmov/libnss_files-2.11.1.so
    b77f9000-b77fc000 rw-p 00000000 00:00 0 
    b77fc000-b77fd000 r-xp 00000000 00:00 0          [vdso]
    b77fd000-b7818000 r-xp 00000000 08:01 2813       /lib/ld-2.11.1.so
    b7818000-b7819000 r--p 0001a000 08:01 2813       /lib/ld-2.11.1.so
    b7819000-b781a000 rw-p 0001b000 08:01 2813       /lib/ld-2.11.1.so
    bfd4c000-bfd61000 rw-p 00000000 00:00 0          [stack]
    Aborted

Может ли кто-нибудь пролить свет на то, что мы сделали неправильно, как мы могли бы сделать это сами и как мы могли бы избежать подобных ошибок в будущем.

Также, если у кого-то есть понимание того, почему он хорошо работает в archlinux, но не в Ubuntu, мне было бы очень интересно услышать это.

Ответы [ 2 ]

3 голосов
/ 25 февраля 2011

Вы используете strcat для добавления к массиву (query), который находится в стеке и имеет только точный размер, необходимый для начального значения.Таким образом, вы переполняете буфер в стеке, что может привести ко всем видам любопытного и интересного поведения.

То, что он работает в Arch Linux, является совпадением;gcc в Ubuntu по умолчанию включает проверку стека и находит ошибку.

1 голос
/ 25 февраля 2011

Эта строка мне кажется подозрительной:

strncpy(users[user_num].ip,inet_ntoa(cli_addr.sin_addr),strlen(inet_ntoa(cli_addr.sin_addr)));

Кстати, strncpy не добавляет трейлинг \0. Если область, возвращаемая функцией malloc, не очищена, это может привести к переполнению последующих строковых операций.

...