bug-gnu-chess
[Top][All Lists]
Advanced

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

Re: Buffer overflows


From: Lukas Geyer
Subject: Re: Buffer overflows
Date: 08 Oct 2002 16:36:27 -0400
User-agent: Gnus/5.0808 (Gnus v5.8.8) XEmacs/21.4 (Common Lisp)

Hi,

there was still something stupid in the patch, a missing return in 

+     if (r < 0 || c > 8) return EPD_ERROR;
+     if (c == 8 && p[1] != '/' && p[1] != ' ') EPD_ERROR;

So here is an updated patch, hopefully without those flaws. Note that
solveepd returns with a totally empty board when you feed it garbage
but I guess that is ok, the user can just type "new" (or click on
"Reset" in xboard, whatever) then. It should work as before with
conforming EPD files.

Lukas

P.S.: Again the patch is against 5.04.

--- gnuchess-5.04.orig/src/common.h
+++ gnuchess-5.04/src/common.h
@@ -524,9 +524,15 @@
 
 /*  The EPD routines  */
 short ReadEPDFile (const char *, short);
-void ParseEPD (char *);
+int ParseEPD (char *);
 void LoadEPD (char *);
 void SaveEPD (char *);
+
+/* Error codes for ParseEPD */
+enum {
+   EPD_SUCCESS,
+   EPD_ERROR
+};
 
 /*  The command routines */
 void InputCmd (void);
--- gnuchess-5.04.orig/src/pgn.c
+++ gnuchess-5.04/src/pgn.c
@@ -148,7 +148,7 @@
       c = fgetc(fp);
       if (c == '*') break;
       ungetc (c, fp);
-      fscanf (fp, "%d. %s %s ", &moveno, wmv, bmv);
+      fscanf (fp, "%d. %7s %7s ", &moveno, wmv, bmv);
       p = ValidateMove (wmv);
       if (!p)
       {
--- gnuchess-5.04.orig/src/epd.c
+++ gnuchess-5.04/src/epd.c
@@ -48,7 +48,7 @@
  ****************************************************************************/
 {
    static FILE *fp = NULL;
-   char line[255];
+   char line[1025];
 
    /*  If first time through, must open file  */
    if (fp == NULL)
@@ -69,11 +69,15 @@
       return (false);
    }
 
+next_line:
    /*  Okay, we read in an EPD entry  */
-   fgets (line, 255, fp);
+   fgets (line, 1024, fp);
    if (!feof(fp)) 
    {
-      ParseEPD (line);
+      int ret = ParseEPD (line);
+
+      /* For now just ignore malformed lines */
+      if (ret != EPD_SUCCESS) goto next_line;
       if (op != 2)
          printf ("\n%s : Best move = %s\n", id, solution);
       return (true);
@@ -87,8 +91,14 @@
    }
 }
 
+/*
+ * Returns EPD_SUCCESS on success, EPD_ERROR on error. We try to be
+ * quite tough on the format. However, as of yet no legality checking
+ * is done and the board is not reset on error, this should be done by
+ * the caller.
+ */
 
-void ParseEPD (char *p)
+int ParseEPD (char *p)
 /**************************************************************************
  *   
  *  Parses an EPD input line.  A few global variables are updated e.g.
@@ -97,13 +107,13 @@
  **************************************************************************/
 {
    short r, c, sq;
-   char s[8];
+   char *str_p;
 
    r = 56;
    c = 0;
    memset (&board, 0, sizeof (board));
 
-   while (*p != ' ')
+   while (p && *p != ' ')
    {
      sq = r + c;
      switch (*p)
@@ -187,6 +197,8 @@
         c += (*p - '0');
      else
         c++;
+     if (r < 0 || c > 8) return EPD_ERROR;
+     if (c == 8 && p[1] != '/' && p[1] != ' ') return EPD_ERROR;
      p++;
    }
 
@@ -201,41 +213,58 @@
    UpdateMvboard ();
 
    /*  Get side to move  */
-   sscanf (p, " %s %[^\n]", s, p);
-   if (s[0] == 'w')
-      board.side = white;
-   else if (s[0] == 'b')
-      board.side = black;
-
+   if (!++p) return EPD_ERROR;
+   if      (*p == 'w') board.side = white; 
+   else if (*p == 'b') board.side = black;
+   else return EPD_ERROR;
+
+   /* Isn't this one cute? */
+   if (!++p || *p != ' ' || !++p) return EPD_ERROR;
+  
    /*  Castling status  */
-   sscanf (p, " %s %[^\n]", s, p);
-   if (strchr (s, 'K'))
-      board.flag |= WKINGCASTLE;
-   if (strchr (s, 'Q'))
-      board.flag |= WQUEENCASTLE;
-   if (strchr (s, 'k'))
-      board.flag |= BKINGCASTLE;
-   if (strchr (s, 'q'))
-      board.flag |= BQUEENCASTLE;
-
-   /*  En passant square */
-   sscanf (p, " %s %[^\n]", s, p);
-   if (s[0] != '-')
-      board.ep = (s[0] - 'a') + (s[1] - '1')*8;
-   else
+   while (p && *p != ' ') {
+      if      (*p == 'K') board.flag |= WKINGCASTLE;
+      else if (*p == 'Q') board.flag |= WQUEENCASTLE;
+      else if (*p == 'k') board.flag |= BKINGCASTLE;
+      else if (*p == 'q') board.flag |= BQUEENCASTLE;
+      else if (*p == '-') { p++; break; }
+      else return EPD_ERROR;
+      p++;
+   }
+   if (!p || *p != ' ' || !++p) return EPD_ERROR;
+
+   /*
+    * En passant square, can only be '-' or [a-h][36]
+    * In fact, one could add more sanity checks here.
+    */
+   if (*p != '-') {
+      if (!p[1] || *p < 'a' || *p > 'h' ||
+         !(p[1] == '3' || p[1] == '6')) return EPD_ERROR;
+      board.ep = (*p - 'a') + (p[1] - '1')*8;
+      p++;
+   } else {
       board.ep = -1;
+   }
+
+   solution[0] = '\0';
+   id[0] = '\0';
+
+   if (!++p) return EPD_SUCCESS;
+
+   /* The opcodes are optional, so we should not generate errors here */
 
    /*  Read in best move; "bm" operator */
-   if (!strncmp (p, "bm", 2))
-      sscanf (p, "%*s %[^;]; %[^\n]", solution, p); 
+   str_p = strstr(p, "bm");
+   if (str_p) sscanf (str_p, "bm %63[^;];", solution); 
 
    /*  Read in the description; "id" operator */
-   if (!strncmp (p, "id", 2))
-      sscanf (p, "%*s %[^;]; %[^\n]", id, p); 
+   str_p = strstr(p, "id");
+   if (str_p) sscanf (p, "id %31[^;];", id);
 
    CalcHashKey ();
    phase = PHASE;
-   return;
+
+   return EPD_SUCCESS;
 }
 
 
@@ -249,7 +278,7 @@
    char file[32];
    short N = 1;
 
-   sscanf (p, "%s %hd ", file, &N);
+   sscanf (p, "%31s %hd ", file, &N);
    if (strcmp (file, "next") == 0)
    {
       ReadEPDFile (file, 0);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]