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,
@ -63,7 +63,7 @@
#include <sys/cdefs.h>
#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 */
#include <string.h>
@ -184,15 +184,21 @@ savenames(int fd)
bwrite(fd, bases, sizeof bases);
bwrite(fd, objects, sizeof objects);
/*
* as long as we use only one version of Hack/Quest we need not save
* oc_name and oc_descr, but we must save oc_uname for all objects
* We must save not only oc_uname but also oc_name and oc_descr,
* because they are string constants whose pointer values aren't
* peristent when ASLR is enabled.
*/
for (i = 0; i < SIZE(objects); i++) {
if (objects[i].oc_uname) {
len = strlen(objects[i].oc_uname) + 1;
bwrite(fd, &len, sizeof len);
bwrite(fd, objects[i].oc_uname, len);
#define SAVE_NAME_FIELD(FIELD) \
if (objects[i].FIELD) { \
len = strlen(objects[i].FIELD) + 1; \
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)
{
int i;
unsigned len;
size_t len;
mread(fd, bases, sizeof bases);
mread(fd, objects, sizeof objects);
for (i = 0; i < SIZE(objects); i++)
if (objects[i].oc_uname) {
mread(fd, &len, sizeof len);
objects[i].oc_uname = alloc(len);
mread(fd, objects[i].oc_uname, len);
for (i = 0; i < SIZE(objects); i++) {
#define RESTORE_NAME_FIELD(FIELD) \
if (objects[i].FIELD) { \
mread(fd, &len, sizeof 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
}
}