Synopsis: rogue vulnerability
NetBSD versions: 1.6, 1.5.3, 1.5.2, 1.5.1, 1.5
Thanks to: stanojr, Simon Burge
Reported in NetBSD Security Advisory: NetBSD-SA2002-021

Index: inventory.c
===================================================================
RCS file: /cvsroot/basesrc/games/rogue/inventory.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- inventory.c 2002/07/07 09:35:08     1.7
+++ inventory.c 2002/10/01 14:18:57     1.8
@@ -421,14 +421,14 @@
mix_colors()
{
       short i, j, k;
-       char *t;
+       char t[MAX_ID_TITLE_LEN];

       for (i = 0; i <= 32; i++) {
               j = get_rand(0, (POTIONS - 1));
               k = get_rand(0, (POTIONS - 1));
-               t = id_potions[j].title;
-               id_potions[j].title = id_potions[k].title;
-               id_potions[k].title = t;
+               memcpy(t, id_potions[j].title, MAX_ID_TITLE_LEN);
+               memcpy(id_potions[j].title, id_potions[k].title, MAX_ID_TITLE_LEN);
+               memcpy(id_potions[k].title, t, MAX_ID_TITLE_LEN);
       }
}

Index: message.c
===================================================================
RCS file: /cvsroot/basesrc/games/rogue/message.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- message.c   2000/07/10 10:19:27     1.8
+++ message.c   2002/10/01 14:18:57     1.9
@@ -64,7 +64,7 @@
char msgs[NMESSAGES][DCOLS] = {"", "", "", "", ""};
short msg_col = 0, imsg = -1;
boolean msg_cleared = 1, rmsg = 0;
-char hunger_str[8] = "";
+char hunger_str[HUNGER_STR_LEN] = "";
const char *more = "-more-";

void
Index: rogue.h
===================================================================
RCS file: /cvsroot/basesrc/games/rogue/rogue.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- rogue.h     2001/02/05 01:04:25     1.12
+++ rogue.h     2002/10/01 14:18:57     1.13
@@ -192,9 +192,10 @@

#define MAX_OPT_LEN 40

+#define MAX_ID_TITLE_LEN 64
struct id {
       short value;
-       char *title;
+       char title[MAX_ID_TITLE_LEN];
       char *real;
       unsigned short id_status;
};
@@ -658,7 +659,7 @@
void   rand_place __P((object *));
void   read_pack __P((object *, FILE *, boolean));
void   read_scroll __P((void));
-void   read_string __P((char *, FILE *));
+void   read_string __P((char *, FILE *, size_t));
void   recursive_deadend __P((short, const short *, short, short));
boolean        reg_move __P((void));
void   relight __P((void));
@@ -763,8 +764,9 @@
extern boolean trap_door;
extern boolean wizard;
extern char    hit_message[];
-extern char    hunger_str[];
-extern char    login_name[];
+#define HUNGER_STR_LEN 8
+extern char    hunger_str[HUNGER_STR_LEN];
+extern char    login_name[MAX_OPT_LEN];
extern const char   *byebye_string;
extern const char   *curse_message;
extern const char   *error_file;
Index: save.c
===================================================================
RCS file: /cvsroot/basesrc/games/rogue/save.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- save.c      1999/09/18 19:38:54     1.7
+++ save.c      2002/10/01 14:18:58     1.8
@@ -102,8 +102,8 @@
                       }
               }
       }
-       if (    ((fp = fopen(sfile, "w")) == NULL) ||
-                       ((file_id = md_get_file_id(sfile)) == -1)) {
+       if (((fp = fopen(sfile, "w")) == NULL) ||
+           ((file_id = md_get_file_id(sfile)) == -1)) {
               message("problem accessing the save file", 0);
               return;
       }
@@ -166,8 +166,8 @@
       int new_file_id, saved_file_id;

       fp = NULL;
-       if (    ((new_file_id = md_get_file_id(fname)) == -1) ||
-                       ((fp = fopen(fname, "r")) == NULL)) {
+       if (((new_file_id = md_get_file_id(fname)) == -1) ||
+           ((fp = fopen(fname, "r")) == NULL)) {
               clean_up("cannot open file");
       }
       if (md_link_count(fname) > 1) {
@@ -177,10 +177,10 @@
       r_read(fp, (char *) &detect_monster, sizeof(detect_monster));
       r_read(fp, (char *) &cur_level, sizeof(cur_level));
       r_read(fp, (char *) &max_level, sizeof(max_level));
-       read_string(hunger_str, fp);
+       read_string(hunger_str, fp, sizeof hunger_str);

-       (void) strcpy(tbuf, login_name);
-       read_string(login_name, fp);
+       (void) strlcpy(tbuf, login_name, sizeof tbuf);
+       read_string(login_name, fp, sizeof login_name);
       if (strcmp(tbuf, login_name)) {
               clean_up("you're not the original player");
       }
@@ -269,9 +269,9 @@
               *new_obj = read_obj;
               if (is_rogue) {
                       if (new_obj->in_use_flags & BEING_WORN) {
-                                       do_wear(new_obj);
+                               do_wear(new_obj);
                       } else if (new_obj->in_use_flags & BEING_WIELDED) {
-                                       do_wield(new_obj);
+                               do_wield(new_obj);
                       } else if (new_obj->in_use_flags & (ON_EITHER_HAND)) {
                               do_put_on(new_obj,
                                       ((new_obj->in_use_flags & ON_LEFT_HAND) ? 1 : 0));
@@ -326,7 +326,7 @@
                       r_read(fp, (char *) &(id_table[i].value), sizeof(short));
                       r_read(fp, (char *) &(id_table[i].id_status),
                               sizeof(unsigned short));
-                       read_string(id_table[i].title, fp);
+                       read_string(id_table[i].title, fp, MAX_ID_TITLE_LEN);
               }
       }
}
@@ -345,13 +345,16 @@
}

void
-read_string(s, fp)
+read_string(s, fp, len)
       char *s;
       FILE *fp;
+       size_t len;
{
       short n;

       r_read(fp, (char *) &n, sizeof(short));
+       if (n > len)
+               clean_up("read_string: corrupt game file");
       r_read(fp, s, n);
       xxxx(s, n);
}