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);
 }
