Skip to content

Commit

Permalink
Restrict capacity of plists to 2^28 resp. 2^60
Browse files Browse the repository at this point in the history
By adding bounds checks to GrowPlist and NEW_PLIST, we restrict the capacity
of plain lists to the maximum value of an immediate integer, i.e. 2^28 on a
32 bit system and 2^60 on a 64 bit system. The check in GrowPlist triggers
an error, as it can be triggered by the user. The check in NEW_PLIST is a
run-time assertion, and should never be triggered by user actions, only by
buggy kernel code.

This restriction fixes overflows and other problems, which can lead to
crashes, corrupt data or nonsense computations.

It poses no actual limitation in practice, for the following reasons:

First off, many other places already effectively limited the length of a
plist they can interact with to the maximum value of an immediate integer.
E.g. such limitations exist for sublist access via l{poss}, EmptyPlist(),
ASS_PLIST_DEFAULT, and more.

Secondly, with this change,  the effective size (in bytes) of a plist of
this maximal length would be 2^30 resp. 2^63. The latter certainly poses no
actual limitation. The former corresponds to 1 GB. Conceivably, GAP could
support slightly larger bags on a 32bit system (the GASMAN heap can grow up
to 3GB if the host system supports it). However, there is not much you can
do with GAP if most of its heap is filled with a single gigantic plist, so
this restriction seems acceptable.
  • Loading branch information
fingolfin committed Jan 4, 2018
1 parent 1e9ff7a commit c577b2e
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/plist.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,18 @@ Int GrowPlist (
UInt plen; /* new physical length */
UInt good; /* good new physical length */

if (!UINT_FITS_IN_INTOBJ(need)) {
ErrorMayQuit("GrowPlist: List size too large", 0, 0);
}

/* find out how large the plain list should become */
good = 5 * (SIZE_OBJ(list)/sizeof(Obj)-1) / 4 + 4;

/* but maybe we need more */
if ( need < good ) { plen = good; }
else { plen = need; }
if (need < good && UINT_FITS_IN_INTOBJ(good))
plen = good;
else
plen = need;

/* resize the plain list */
ResizeBag( list, ((plen)+1)*sizeof(Obj) );
Expand Down
1 change: 1 addition & 0 deletions src/plist.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
static inline Obj NEW_PLIST(UInt type, Int plen)
{
GAP_ASSERT(plen >= 0);
GAP_ASSERT(INT_FITS_IN_INTOBJ(plen));
return NewBag(type, (plen + 1) * sizeof(Obj));
}

Expand Down

0 comments on commit c577b2e

Please sign in to comment.