hack(6): Fix a segfault that occurs when ASLR is enabled

Prior to this change, savenames() would store "objects" in save files as a
blob, and restnames() would load it and overwrite "objects". But since
objclass::oc_name and oc_descr are pointers to string constants, they would
be invalid when the next time the process is spawned, and opening the
inventory would crash by dereferencing invalid pointers.
This commit is contained in:
pho 2023-07-30 09:23:21 +00:00
parent 3b7c09b692
commit 9904cea545
1 changed files with 30 additions and 14 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: hack.o_init.c,v 1.14 2011/08/06 20:42:43 dholland Exp $ */ /* $NetBSD: hack.o_init.c,v 1.15 2023/07/30 09:23:21 pho Exp $ */
/* /*
* Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
@ -63,7 +63,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
__RCSID("$NetBSD: hack.o_init.c,v 1.14 2011/08/06 20:42:43 dholland Exp $"); __RCSID("$NetBSD: hack.o_init.c,v 1.15 2023/07/30 09:23:21 pho Exp $");
#endif /* not lint */ #endif /* not lint */
#include <string.h> #include <string.h>
@ -184,15 +184,21 @@ savenames(int fd)
bwrite(fd, bases, sizeof bases); bwrite(fd, bases, sizeof bases);
bwrite(fd, objects, sizeof objects); bwrite(fd, objects, sizeof objects);
/* /*
* as long as we use only one version of Hack/Quest we need not save * We must save not only oc_uname but also oc_name and oc_descr,
* oc_name and oc_descr, but we must save oc_uname for all objects * because they are string constants whose pointer values aren't
* peristent when ASLR is enabled.
*/ */
for (i = 0; i < SIZE(objects); i++) { for (i = 0; i < SIZE(objects); i++) {
if (objects[i].oc_uname) { #define SAVE_NAME_FIELD(FIELD) \
len = strlen(objects[i].oc_uname) + 1; if (objects[i].FIELD) { \
bwrite(fd, &len, sizeof len); len = strlen(objects[i].FIELD) + 1; \
bwrite(fd, objects[i].oc_uname, len); bwrite(fd, &len, sizeof len); \
bwrite(fd, objects[i].FIELD, len); \
} }
SAVE_NAME_FIELD(oc_name);
SAVE_NAME_FIELD(oc_descr);
SAVE_NAME_FIELD(oc_uname);
#undef SAVE_NAME_FIELD
} }
} }
@ -200,14 +206,24 @@ void
restnames(int fd) restnames(int fd)
{ {
int i; int i;
unsigned len; size_t len;
mread(fd, bases, sizeof bases); mread(fd, bases, sizeof bases);
mread(fd, objects, sizeof objects); mread(fd, objects, sizeof objects);
for (i = 0; i < SIZE(objects); i++) for (i = 0; i < SIZE(objects); i++) {
if (objects[i].oc_uname) { #define RESTORE_NAME_FIELD(FIELD) \
mread(fd, &len, sizeof len); if (objects[i].FIELD) { \
objects[i].oc_uname = alloc(len); mread(fd, &len, sizeof len); \
mread(fd, objects[i].oc_uname, len); objects[i].FIELD = alloc(len); \
mread(fd, __UNCONST(objects[i].FIELD), len); \
}
/*
* This leaks memory but who cares? Restoration only
* happens on the process startup.
*/
RESTORE_NAME_FIELD(oc_name);
RESTORE_NAME_FIELD(oc_descr);
RESTORE_NAME_FIELD(oc_uname);
#undef RESTORE_NAME_FIELD
} }
} }