diff options
author | Noah Misch <noah@leadboat.com> | 2014-02-17 09:33:31 -0500 |
---|---|---|
committer | Noah Misch <noah@leadboat.com> | 2014-02-17 09:33:39 -0500 |
commit | 98be8a6eaa9fe917f6be9e121187b912e19ab484 (patch) | |
tree | 1f0e51b7f00461208ee1bbf9103629b6b38885ca /src/backend/utils/adt/geo_ops.c | |
parent | d0ed1a6c044452a529c1d544647ea1fcb90dcb81 (diff) |
Predict integer overflow to avoid buffer overruns.
Several functions, mostly type input functions, calculated an allocation
size such that the calculation wrapped to a small positive value when
arguments implied a sufficiently-large requirement. Writes past the end
of the inadvertent small allocation followed shortly thereafter.
Coverity identified the path_in() vulnerability; code inspection led to
the rest. In passing, add check_stack_depth() to prevent stack overflow
in related functions.
Back-patch to 8.4 (all supported versions). The non-comment hstore
changes touch code that did not exist in 8.4, so that part stops at 9.0.
Noah Misch and Heikki Linnakangas, reviewed by Tom Lane.
Security: CVE-2014-0064
Diffstat (limited to 'src/backend/utils/adt/geo_ops.c')
-rw-r--r-- | src/backend/utils/adt/geo_ops.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index c1276b78c12..3ffab5eb2de 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -1401,6 +1401,7 @@ path_in(PG_FUNCTION_ARGS) char *s; int npts; int size; + int base_size; int depth = 0; if ((npts = pair_count(str, ',')) <= 0) @@ -1419,7 +1420,15 @@ path_in(PG_FUNCTION_ARGS) depth++; } - size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts; + base_size = sizeof(path->p[0]) * npts; + size = offsetof(PATH, p[0]) + base_size; + + /* Check for integer overflow */ + if (base_size / npts != sizeof(path->p[0]) || size <= base_size) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many points requested"))); + path = (PATH *) palloc(size); SET_VARSIZE(path, size); @@ -3439,6 +3448,7 @@ poly_in(PG_FUNCTION_ARGS) POLYGON *poly; int npts; int size; + int base_size; int isopen; char *s; @@ -3447,7 +3457,15 @@ poly_in(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type polygon: \"%s\"", str))); - size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * npts; + base_size = sizeof(poly->p[0]) * npts; + size = offsetof(POLYGON, p[0]) + base_size; + + /* Check for integer overflow */ + if (base_size / npts != sizeof(poly->p[0]) || size <= base_size) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many points requested"))); + poly = (POLYGON *) palloc0(size); /* zero any holes */ SET_VARSIZE(poly, size); @@ -4216,6 +4234,10 @@ path_poly(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("open path cannot be converted to polygon"))); + /* + * Never overflows: the old size fit in MaxAllocSize, and the new size is + * just a small constant larger. + */ size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * path->npts; poly = (POLYGON *) palloc(size); @@ -4321,6 +4343,10 @@ poly_path(PG_FUNCTION_ARGS) int size; int i; + /* + * Never overflows: the old size fit in MaxAllocSize, and the new size is + * smaller by a small constant. + */ size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * poly->npts; path = (PATH *) palloc(size); |