Skip to content

Commit

Permalink
From f4b7b6786a8d5672a35ed59f4e66c77fe6f321aa Mon Sep 17 00:00:00 2001
Browse files Browse the repository at this point in the history
From: Andrey Nazarov <[email protected]>
Date: Mon, 20 Sep 2021 19:41:42 +0300
Subject: [PATCH 389/396] Don't crash with fatal error if model hunk is
 exhausted.

Loading oversize MD2 or MD3 model can legitimately exhaust default 4 MiB
hunk and crash with fatal error.

Change Hunk_Alloc() to return NULL on allocation failure and add
specific checks, so that oversize model simply fails to load with
ENOMEM.

Note that all other users of Hunk_Alloc() already reserve enough memory,
thus no additional checks are needed.
  • Loading branch information
Paril committed Dec 10, 2021
1 parent 442306e commit 749fe69
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 50 deletions.
2 changes: 2 additions & 0 deletions inc/refresh/models.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#define MOD_Malloc(size) Hunk_Alloc(&model->hunk, size)

#define CHECK(x) if (!(x)) { ret = Q_ERR(ENOMEM); goto fail; }

#define MAX_ALIAS_SKINS 32
#define MAX_ALIAS_VERTS 4096

Expand Down
25 changes: 14 additions & 11 deletions src/refresh/gl/models.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,17 @@ int MOD_LoadMD2_GL(model_t *model, const void *rawdata, size_t length, const cha
model->type = MOD_ALIAS;
model->nummeshes = 1;
model->numframes = header.num_frames;
model->meshes = MOD_Malloc(sizeof(maliasmesh_t));
model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t));
CHECK(model->meshes = MOD_Malloc(sizeof(maliasmesh_t)));
CHECK(model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t)));

dst_mesh = model->meshes;
dst_mesh->numtris = numindices / 3;
dst_mesh->numindices = numindices;
dst_mesh->numverts = numverts;
dst_mesh->numskins = header.num_skins;
dst_mesh->verts = MOD_Malloc(numverts * header.num_frames * sizeof(maliasvert_t));
dst_mesh->tcoords = MOD_Malloc(numverts * sizeof(maliastc_t));
dst_mesh->indices = MOD_Malloc(numindices * sizeof(QGL_INDEX_TYPE));
CHECK(dst_mesh->verts = MOD_Malloc(numverts * header.num_frames * sizeof(maliasvert_t)));
CHECK(dst_mesh->tcoords = MOD_Malloc(numverts * sizeof(maliastc_t)));
CHECK(dst_mesh->indices = MOD_Malloc(numindices * sizeof(QGL_INDEX_TYPE)));

if (dst_mesh->numtris != header.num_tris) {
Com_DPrintf("%s has %d bad triangles\n", model->name, header.num_tris - dst_mesh->numtris);
Expand Down Expand Up @@ -253,7 +253,7 @@ static int MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,
QGL_INDEX_TYPE *dst_idx;
uint32_t index;
char skinname[MAX_QPATH];
int i, j, k;
int i, j, k, ret;

if (length < sizeof(header))
return Q_ERR_BAD_EXTENT;
Expand Down Expand Up @@ -290,9 +290,9 @@ static int MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,
mesh->numindices = header.num_tris * 3;
mesh->numverts = header.num_verts;
mesh->numskins = header.num_skins;
mesh->verts = MOD_Malloc(sizeof(maliasvert_t) * header.num_verts * model->numframes);
mesh->tcoords = MOD_Malloc(sizeof(maliastc_t) * header.num_verts);
mesh->indices = MOD_Malloc(sizeof(QGL_INDEX_TYPE) * header.num_tris * 3);
CHECK(mesh->verts = MOD_Malloc(sizeof(maliasvert_t) * header.num_verts * model->numframes));
CHECK(mesh->tcoords = MOD_Malloc(sizeof(maliastc_t) * header.num_verts));
CHECK(mesh->indices = MOD_Malloc(sizeof(QGL_INDEX_TYPE) * header.num_tris * 3));

// load all skins
src_skin = (dmd3skin_t *)(rawdata + header.ofs_skins);
Expand Down Expand Up @@ -347,6 +347,9 @@ static int MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,

*offset_p = header.meshsize;
return Q_ERR_SUCCESS;

fail:
return ret;
}

int MOD_LoadMD3_GL(model_t *model, const void *rawdata, size_t length, const char* mod_name)
Expand Down Expand Up @@ -387,8 +390,8 @@ int MOD_LoadMD3_GL(model_t *model, const void *rawdata, size_t length, const cha
model->type = MOD_ALIAS;
model->numframes = header.num_frames;
model->nummeshes = header.num_meshes;
model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * header.num_meshes);
model->frames = MOD_Malloc(sizeof(maliasframe_t) * header.num_frames);
CHECK(model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * header.num_meshes));
CHECK(model->frames = MOD_Malloc(sizeof(maliasframe_t) * header.num_frames));

// load all frames
src_frame = (dmd3frame_t *)((byte *)rawdata + header.ofs_frames);
Expand Down
40 changes: 22 additions & 18 deletions src/refresh/model_iqm.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ int MOD_LoadIQM_Base(model_t* model, const void* rawdata, size_t length, const c
iqm_model_t* iqmData;
char meshName[MAX_QPATH];
int vertexArrayFormat[IQM_COLOR + 1];
int ret;

if (length < sizeof(iqmHeader_t))
{
Expand Down Expand Up @@ -445,7 +446,7 @@ int MOD_LoadIQM_Base(model_t* model, const void* rawdata, size_t length, const c
}
}

iqmData = (iqm_model_t*)MOD_Malloc(sizeof(iqm_model_t));
CHECK(iqmData = (iqm_model_t*)MOD_Malloc(sizeof(iqm_model_t)));
model->iqmData = iqmData;

// fill header
Expand All @@ -458,53 +459,53 @@ int MOD_LoadIQM_Base(model_t* model, const void* rawdata, size_t length, const c

if (header->num_meshes)
{
iqmData->meshes = (iqm_mesh_t*)MOD_Malloc(header->num_meshes * sizeof(iqm_mesh_t));
iqmData->indices = (uint32_t*)MOD_Malloc(header->num_triangles * 3 * sizeof(int));
iqmData->positions = (float*)MOD_Malloc(header->num_vertexes * 3 * sizeof(float));
iqmData->texcoords = (float*)MOD_Malloc(header->num_vertexes * 2 * sizeof(float));
iqmData->normals = (float*)MOD_Malloc(header->num_vertexes * 3 * sizeof(float));
CHECK(iqmData->meshes = (iqm_mesh_t*)MOD_Malloc(header->num_meshes * sizeof(iqm_mesh_t)));
CHECK(iqmData->indices = (uint32_t*)MOD_Malloc(header->num_triangles * 3 * sizeof(int)));
CHECK(iqmData->positions = (float*)MOD_Malloc(header->num_vertexes * 3 * sizeof(float)));
CHECK(iqmData->texcoords = (float*)MOD_Malloc(header->num_vertexes * 2 * sizeof(float)));
CHECK(iqmData->normals = (float*)MOD_Malloc(header->num_vertexes * 3 * sizeof(float)));

if (vertexArrayFormat[IQM_TANGENT] != -1)
{
iqmData->tangents = (float*)MOD_Malloc(header->num_vertexes * 4 * sizeof(float));
CHECK(iqmData->tangents = (float*)MOD_Malloc(header->num_vertexes * 4 * sizeof(float)));
}

if (vertexArrayFormat[IQM_COLOR] != -1)
{
iqmData->colors = (byte*)MOD_Malloc(header->num_vertexes * 4 * sizeof(byte));
CHECK(iqmData->colors = (byte*)MOD_Malloc(header->num_vertexes * 4 * sizeof(byte)));
}

if (vertexArrayFormat[IQM_BLENDINDEXES] != -1)
{
iqmData->blend_indices = MOD_Malloc(header->num_vertexes * 4 * sizeof(byte));
CHECK(iqmData->blend_indices = MOD_Malloc(header->num_vertexes * 4 * sizeof(byte)));
}

if (vertexArrayFormat[IQM_BLENDWEIGHTS] != -1)
{
iqmData->blend_weights = (float*)MOD_Malloc(header->num_vertexes * 4 * sizeof(float));
CHECK(iqmData->blend_weights = (float*)MOD_Malloc(header->num_vertexes * 4 * sizeof(float)));
}
}

if (header->num_joints)
{
iqmData->jointNames = (char*)MOD_Malloc(joint_names);
iqmData->jointParents = (int*)MOD_Malloc(header->num_joints * sizeof(int));
iqmData->bindJoints = (float*)MOD_Malloc(header->num_joints * 12 * sizeof(float)); // bind joint matricies
iqmData->invBindJoints = (float*)MOD_Malloc(header->num_joints * 12 * sizeof(float)); // inverse bind joint matricies
CHECK(iqmData->jointNames = (char*)MOD_Malloc(joint_names));
CHECK(iqmData->jointParents = (int*)MOD_Malloc(header->num_joints * sizeof(int)));
CHECK(iqmData->bindJoints = (float*)MOD_Malloc(header->num_joints * 12 * sizeof(float))); // bind joint matricies
CHECK(iqmData->invBindJoints = (float*)MOD_Malloc(header->num_joints * 12 * sizeof(float))); // inverse bind joint matricies
}

if (header->num_poses)
{
iqmData->poses = (iqm_transform_t*)MOD_Malloc(header->num_poses * header->num_frames * sizeof(iqm_transform_t)); // pose transforms
CHECK(iqmData->poses = (iqm_transform_t*)MOD_Malloc(header->num_poses * header->num_frames * sizeof(iqm_transform_t))); // pose transforms
}

if (header->ofs_bounds)
{
iqmData->bounds = (float*)MOD_Malloc(header->num_frames * 6 * sizeof(float)); // model bounds
CHECK(iqmData->bounds = (float*)MOD_Malloc(header->num_frames * 6 * sizeof(float))); // model bounds
}
else if (header->num_meshes && header->num_frames == 0)
{
iqmData->bounds = (float*)MOD_Malloc(6 * sizeof(float)); // model bounds
CHECK(iqmData->bounds = (float*)MOD_Malloc(6 * sizeof(float))); // model bounds
}

if (header->num_meshes)
Expand Down Expand Up @@ -717,7 +718,7 @@ int MOD_LoadIQM_Base(model_t* model, const void* rawdata, size_t length, const c
if (header->num_anims)
{
iqmData->num_animations = header->num_anims;
iqmData->animations = (iqm_anim_t*)MOD_Malloc(header->num_anims * sizeof(iqm_anim_t));
CHECK(iqmData->animations = (iqm_anim_t*)MOD_Malloc(header->num_anims * sizeof(iqm_anim_t)));

const iqmAnim_t* src = (const iqmAnim_t*)((const byte*)header + header->ofs_anims);
iqm_anim_t* dst = iqmData->animations;
Expand All @@ -734,6 +735,9 @@ int MOD_LoadIQM_Base(model_t* model, const void* rawdata, size_t length, const c
}

return Q_ERR_SUCCESS;

fail:
return ret;
}

/*
Expand Down
9 changes: 6 additions & 3 deletions src/refresh/models.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ static int MOD_LoadSP2(model_t *model, const void *rawdata, size_t length, const
dsp2frame_t *src_frame;
mspriteframe_t *dst_frame;
char buffer[SP2_MAX_FRAMENAME];
int i;
int i, ret;

if (length < sizeof(header))
return Q_ERR_FILE_TOO_SMALL;
Expand All @@ -254,10 +254,10 @@ static int MOD_LoadSP2(model_t *model, const void *rawdata, size_t length, const
if (sizeof(dsp2header_t) + sizeof(dsp2frame_t) * header.numframes > length)
return Q_ERR_BAD_EXTENT;

Hunk_Begin(&model->hunk, 0x10000);
Hunk_Begin(&model->hunk, sizeof(mspriteframe_t) * header.numframes);
model->type = MOD_SPRITE;

model->spriteframes = MOD_Malloc(sizeof(mspriteframe_t) * header.numframes);
CHECK(model->spriteframes = MOD_Malloc(sizeof(mspriteframe_t) * header.numframes));
model->numframes = header.numframes;

src_frame = (dsp2frame_t *)((byte *)rawdata + sizeof(dsp2header_t));
Expand All @@ -284,6 +284,9 @@ static int MOD_LoadSP2(model_t *model, const void *rawdata, size_t length, const
Hunk_End(&model->hunk);

return Q_ERR_SUCCESS;

fail:
return ret;
}

#define TRY_MODEL_SRC_GAME 1
Expand Down
41 changes: 25 additions & 16 deletions src/refresh/vkpt/models.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ static void extract_model_lights(model_t* model)

// Actually extract the lights now

model->light_polys = Hunk_Alloc(&model->hunk, sizeof(light_poly_t) * num_lights);
if (!(model->light_polys = Hunk_Alloc(&model->hunk, sizeof(light_poly_t) * num_lights))) {
Com_DPrintf("Warning: unable to allocate memory for %i light polygons.\n", num_lights);
return;
}
model->num_light_polys = num_lights;

num_lights = 0;
Expand Down Expand Up @@ -325,18 +328,18 @@ int MOD_LoadMD2_RTX(model_t *model, const void *rawdata, size_t length, const ch
model->type = MOD_ALIAS;
model->nummeshes = 1;
model->numframes = header.num_frames;
model->meshes = MOD_Malloc(sizeof(maliasmesh_t));
model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t));
CHECK(model->meshes = MOD_Malloc(sizeof(maliasmesh_t)));
CHECK(model->frames = MOD_Malloc(header.num_frames * sizeof(maliasframe_t)));

dst_mesh = model->meshes;
dst_mesh->numtris = numindices / 3;
dst_mesh->numindices = numindices;
dst_mesh->numverts = numverts;
dst_mesh->numskins = header.num_skins;
dst_mesh->positions = MOD_Malloc(numverts * header.num_frames * sizeof(vec3_t));
dst_mesh->normals = MOD_Malloc(numverts * header.num_frames * sizeof(vec3_t));
dst_mesh->tex_coords = MOD_Malloc(numverts * header.num_frames * sizeof(vec2_t));
dst_mesh->indices = MOD_Malloc(numindices * sizeof(int));
CHECK(dst_mesh->positions = MOD_Malloc(numverts * header.num_frames * sizeof(vec3_t)));
CHECK(dst_mesh->normals = MOD_Malloc(numverts * header.num_frames * sizeof(vec3_t)));
CHECK(dst_mesh->tex_coords = MOD_Malloc(numverts * header.num_frames * sizeof(vec2_t)));
CHECK(dst_mesh->indices = MOD_Malloc(numindices * sizeof(int)));

if (dst_mesh->numtris != header.num_tris) {
Com_DPrintf("%s has %d bad triangles\n", model->name, header.num_tris - dst_mesh->numtris);
Expand Down Expand Up @@ -488,7 +491,7 @@ static int MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,
vec2_t *dst_tc;
int *dst_idx;
char skinname[MAX_QPATH];
int i;
int i, ret;

if (length < sizeof(header))
return Q_ERR_BAD_EXTENT;
Expand Down Expand Up @@ -525,10 +528,10 @@ static int MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,
mesh->numindices = header.num_tris * 3;
mesh->numverts = header.num_verts;
mesh->numskins = header.num_skins;
mesh->positions = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec3_t));
mesh->normals = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec3_t));
mesh->tex_coords = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec2_t));
mesh->indices = MOD_Malloc(sizeof(int) * header.num_tris * 3);
CHECK(mesh->positions = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec3_t)));
CHECK(mesh->normals = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec3_t)));
CHECK(mesh->tex_coords = MOD_Malloc(header.num_verts * model->numframes * sizeof(vec2_t)));
CHECK(mesh->indices = MOD_Malloc(sizeof(int) * header.num_tris * 3));

// load all skins
src_skin = (dmd3skin_t *)(rawdata + header.ofs_skins);
Expand Down Expand Up @@ -600,6 +603,9 @@ static int MOD_LoadMD3Mesh(model_t *model, maliasmesh_t *mesh,
*offset_p = header.meshsize;

return Q_ERR_SUCCESS;

fail:
return ret;
}

int MOD_LoadMD3_RTX(model_t *model, const void *rawdata, size_t length, const char* mod_name)
Expand Down Expand Up @@ -640,8 +646,8 @@ int MOD_LoadMD3_RTX(model_t *model, const void *rawdata, size_t length, const ch
model->type = MOD_ALIAS;
model->numframes = header.num_frames;
model->nummeshes = header.num_meshes;
model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * header.num_meshes);
model->frames = MOD_Malloc(sizeof(maliasframe_t) * header.num_frames);
CHECK(model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * header.num_meshes));
CHECK(model->frames = MOD_Malloc(sizeof(maliasframe_t) * header.num_frames));

// load all frames
src_frame = (dmd3frame_t *)((byte *)rawdata + header.ofs_frames);
Expand Down Expand Up @@ -696,7 +702,7 @@ int MOD_LoadIQM_RTX(model_t* model, const void* rawdata, size_t length, const ch
Hunk_Begin(&model->hunk, 0x4000000);
model->type = MOD_ALIAS;

int res = MOD_LoadIQM_Base(model, rawdata, length, mod_name);
int res = MOD_LoadIQM_Base(model, rawdata, length, mod_name), ret;

if (res != Q_ERR_SUCCESS)
{
Expand All @@ -707,7 +713,7 @@ int MOD_LoadIQM_RTX(model_t* model, const void* rawdata, size_t length, const ch
char base_path[MAX_QPATH];
COM_FilePath(mod_name, base_path, sizeof(base_path));

model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * model->iqmData->num_meshes);
CHECK(model->meshes = MOD_Malloc(sizeof(maliasmesh_t) * model->iqmData->num_meshes));
model->nummeshes = (int)model->iqmData->num_meshes;
model->numframes = 1; // these are baked frames, so that the VBO uploader will only make one copy of the vertices

Expand Down Expand Up @@ -755,6 +761,9 @@ int MOD_LoadIQM_RTX(model_t* model, const void* rawdata, size_t length, const ch
Hunk_End(&model->hunk);

return Q_ERR_SUCCESS;

fail:
return ret;
}

void MOD_Reference_RTX(model_t *model)
Expand Down
2 changes: 1 addition & 1 deletion src/unix/hunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void *Hunk_Alloc(memhunk_t *hunk, size_t size)
Com_Error(ERR_FATAL, "%s: cursize > maxsize", __func__);

if (size > hunk->maxsize - hunk->cursize)
Com_Error(ERR_FATAL, "%s: couldn't allocate %zu bytes", __func__, size);
return NULL;

buf = (byte *)hunk->base + hunk->cursize;
hunk->cursize += size;
Expand Down
2 changes: 1 addition & 1 deletion src/windows/hunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void *Hunk_Alloc(memhunk_t *hunk, size_t size)
Com_Error(ERR_FATAL, "%s: cursize > maxsize", __func__);

if (size > hunk->maxsize - hunk->cursize)
Com_Error(ERR_FATAL, "%s: couldn't allocate %zu bytes", __func__, size);
return NULL;

hunk->cursize += size;

Expand Down

0 comments on commit 749fe69

Please sign in to comment.