The $geoip_latitude and $geoip_longitude values are formatted with
ngx_sprintf(buf, "%.4f", value) into a buffer sized for a coordinate,
but the DOUBLE/FLOAT value is taken from the database with no range
check. A crafted or corrupted MMDB can store a huge magnitude (e.g.
1e30 or an infinity), and ngx_sprintf, which is unbounded, then writes
past the buffer in the request or connection pool.
Coordinates outside [-180, 180] are now rejected, so the variables
report "not found" as they do for a missing entry. The comparison also
rejects a NaN.
Closes: https://github.com/nginx/nginx/issues/1907
#define NGX_GEOIP_CITY_DMA_CODE 10
#define NGX_GEOIP_CITY_AREA_CODE 11
+#define NGX_GEOIP_MAX_COORD 180
+
typedef struct {
#if (NGX_HAVE_GEOIP)
case MMDB_DATA_TYPE_DOUBLE:
*value = entry_data.double_value;
- return NGX_OK;
+ break;
case MMDB_DATA_TYPE_FLOAT:
*value = entry_data.float_value;
- return NGX_OK;
+ break;
default:
return NGX_DECLINED;
}
+
+ /* the range of a coordinate in degrees; NaN fails the comparison */
+
+ if (!(*value >= -NGX_GEOIP_MAX_COORD && *value <= NGX_GEOIP_MAX_COORD)) {
+ return NGX_DECLINED;
+ }
+
+ return NGX_OK;
}
#define NGX_GEOIP_CITY_DMA_CODE 10
#define NGX_GEOIP_CITY_AREA_CODE 11
+#define NGX_GEOIP_MAX_COORD 180
+
typedef struct {
#if (NGX_HAVE_GEOIP)
case MMDB_DATA_TYPE_DOUBLE:
*value = entry_data.double_value;
- return NGX_OK;
+ break;
case MMDB_DATA_TYPE_FLOAT:
*value = entry_data.float_value;
- return NGX_OK;
+ break;
default:
return NGX_DECLINED;
}
+
+ /* the range of a coordinate in degrees; NaN fails the comparison */
+
+ if (!(*value >= -NGX_GEOIP_MAX_COORD && *value <= NGX_GEOIP_MAX_COORD)) {
+ return NGX_DECLINED;
+ }
+
+ return NGX_OK;
}