[Git][debian-gis-team/mapserver][master] 5 commits: New upstream version 8.6.4
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Mon Jun 1 19:23:08 BST 2026
Bas Couwenberg pushed to branch master at Debian GIS Project / mapserver
Commits:
b17252be by Bas Couwenberg at 2026-06-01T20:10:24+02:00
New upstream version 8.6.4
- - - - -
ec25cebb by Bas Couwenberg at 2026-06-01T20:10:39+02:00
Update upstream source from tag 'upstream/8.6.4'
Update to upstream version '8.6.4'
with Debian dir f95e9e8a710d7fce333bcb506d520f235fa9117b
- - - - -
cbc2019f by Bas Couwenberg at 2026-06-01T20:11:23+02:00
New upstream release.
- - - - -
675dbd05 by Bas Couwenberg at 2026-06-01T20:18:05+02:00
Update symbols for 8.6.4.
- - - - -
9c49374f by Bas Couwenberg at 2026-06-01T20:18:05+02:00
Set distribution to unstable.
- - - - -
20 changed files:
- .github/workflows/start.sh
- CITATION.cff
- CMakeLists.txt
- HISTORY.md
- SECURITY.md
- debian/changelog
- debian/libmapserver2t64.symbols
- src/apps/mapserv.c
- src/cgiutil.c
- src/cgiutil.h
- src/mapogcapi.cpp
- src/mapows.c
- src/mapows.h
- src/mappostgis.cpp
- src/maprasterquery.c
- src/mapscale.c
- src/mapserv-index.cpp
- src/mapserver.h
- src/mapstring.cpp
- src/maptemplate.c
Changes:
=====================================
.github/workflows/start.sh
=====================================
@@ -190,4 +190,11 @@ EOF
MAPSERVER_CONFIG_FILE=/tmp/mapserver.conf mapserv QUERY_STRING="MAP=wfs_simple.map&SERVICE=WFS&REQUEST=GetCapabilities" > /tmp/res.txt
cat /tmp/res.txt | grep "Web application error" >/dev/null || (cat /tmp/res.txt && /bin/false)
+# Check https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv
+MAPSERVER_CONFIG_FILE=${WORK_DIR}/msautotest/etc/mapserv.conf SCRIPT_NAME=mapserv SERVER_PORT=80 HTTP_X_FORWARDED_HOST="with'single'quote" mapserv QUERY_STRING="MAP=wms_simple_no_onlineresource.map&SERVICE=WMS&VERSION=1.1.0&REQUEST=GetMap&SRS=EPSG:4326&BBOX=-67.5725,42.3683,-58.9275,48.13&FORMAT=application/openlayers&WIDTH=300&HEIGHT=200&STYLES=&LAYERS=road" > /tmp/res.txt
+# We need to escape backslash once for the grep regexp, and once for the shell...
+# Hence 4 backslashes for one in the actual output
+cat /tmp/res.txt | grep "with\\\\'single\\\\'quote" >/dev/null || (cat /tmp/res.txt && /bin/false)
+
+
echo "Done !"
=====================================
CITATION.cff
=====================================
@@ -1,8 +1,8 @@
cff-version: 1.2.0
title: MapServer
message: If you use this software, please cite it using the metadata from this file.
-version: 8.6.3
-date-released: 2026-05-07
+version: 8.6.4
+date-released: 2026-06-01
abstract: MapServer is an Open Source platform for publishing spatial data and interactive mapping applications to the web.
type: software
authors:
=====================================
CMakeLists.txt
=====================================
@@ -17,7 +17,7 @@ include(CheckCSourceCompiles)
set (MapServer_VERSION_MAJOR 8)
set (MapServer_VERSION_MINOR 6)
-set (MapServer_VERSION_REVISION 3)
+set (MapServer_VERSION_REVISION 4)
set (MapServer_VERSION_SUFFIX "")
# Set C++ version
=====================================
HISTORY.md
=====================================
@@ -13,6 +13,13 @@ https://mapserver.org/development/changelog/
The online Migration Guide can be found at https://mapserver.org/MIGRATION_GUIDE.html
+8.6.4 release (2026-06-01)
+--------------------------
+
+- security: properly escape mapserv_onlineresource in OpenLayers viewer with WMS (#7517)
+
+- security: PostGIS: make sure identifier value is numeric when the declared type is numeric too (#7516)
+
8.6.3 release (2026-05-07)
--------------------------
=====================================
SECURITY.md
=====================================
@@ -10,6 +10,13 @@ option link at the top of this page, or send your report to the email address:
Please follow the general guidelines for bug
submissions, when describing the vulnerability (see https://mapserver.org/development/bugs.html).
+## Note about use of AI/LLM/automated scanners
+
+While reporters are free to use any tool of their choice to detect issues, they
+must *manually* confirm the findings of those tools with an actual reproducing
+test case, not just a theoretical analysis.
+The report must also be humanly checked and be kept as succint as possible.
+
## Supported Versions
The MapServer PSC (Project Steering Committee) will release patches for security vulnerabilities
=====================================
debian/changelog
=====================================
@@ -1,3 +1,10 @@
+mapserver (8.6.4-1) unstable; urgency=high
+
+ * New upstream release.
+ * Update symbols for 8.6.4.
+
+ -- Bas Couwenberg <sebastic at debian.org> Mon, 01 Jun 2026 20:12:31 +0200
+
mapserver (8.6.3-1) unstable; urgency=high
* New upstream release.
=====================================
debian/libmapserver2t64.symbols
=====================================
@@ -2201,6 +2201,7 @@ libmapserver.so.2 #PACKAGE# #MINVER#
msEncodeUrlExcept at Base 6.2.1
msEncryptStringWithKey at Base 6.2.1
msEndShapeKml at Base 6.4.0
+ msEscapeJSonLikeString at Base 8.6.4
msEscapeJSonString at Base 7.0.0
msEvalContext at Base 6.2.1
msEvalDoubleExpression at Base 7.6.0
@@ -3307,7 +3308,6 @@ libmapserver.so.2 #PACKAGE# #MINVER#
(c++)"virtual thunk to ClipperLib::Clipper::Reset()@Base" 6.2.1
(c++)"virtual thunk to ClipperLib::Clipper::~Clipper()@Base" 6.2.1
writeSymbol at Base 6.2.1
- x2c at Base 6.2.1
yyerror at Base 6.2.1
yylex at Base 6.2.1
yyparse at Base 6.2.1
=====================================
src/apps/mapserv.c
=====================================
@@ -60,6 +60,14 @@ static int finish_process = 0;
static void msCleanupOnSignal(int nInData) {
(void)nInData;
finish_process = 1;
+#ifdef USE_FASTCGI
+ /* Ask libfcgi to stop accepting new requests. This causes a blocked
+ * FCGI_Accept() to return -1, so the main loop can exit promptly
+ * instead of waiting for the next request to arrive. Safe to call
+ * from a signal handler: it just sets an internal flag (declared in
+ * fcgiapp.h, which is pulled in via fcgi_stdio.h above). */
+ FCGX_ShutdownPending();
+#endif
}
#endif
@@ -242,8 +250,22 @@ int main(int argc, char *argv[]) {
/* Setup cleanup magic, mainly for FastCGI case. */
/* -------------------------------------------------------------------- */
#ifndef _WIN32
- signal(SIGUSR1, msCleanupOnSignal);
- signal(SIGTERM, msCleanupOnSignal);
+ {
+ /* Install via sigaction without SA_RESTART so that a blocking
+ * accept()/select() inside FCGI_Accept() returns EINTR when the
+ * signal arrives while the process is idle. Combined with
+ * FCGX_ShutdownPending() in the handler, this lets the FastCGI
+ * loop exit on SIGTERM instead of waiting for the next request. */
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = msCleanupOnSignal;
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGUSR1);
+ sigaddset(&sa.sa_mask, SIGTERM);
+ sa.sa_flags = 0; /* deliberately no SA_RESTART */
+ sigaction(SIGUSR1, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+ }
#endif
#ifdef USE_FASTCGI
=====================================
src/cgiutil.c
=====================================
@@ -396,22 +396,37 @@ char *fmakeword(FILE *f, char stop, int *cl) {
}
}
-char x2c(char *what) {
- register char digit;
-
- digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
- digit *= 16;
- digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
- return (digit);
+static int hex_to_integer(char c) {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
}
void unescape_url(char *url) {
- register int x, y;
+ register int x, y, hi, lo;
for (x = 0, y = 0; url[y]; ++x, ++y) {
- if ((url[x] = url[y]) == '%') {
- url[x] = x2c(&url[y + 1]);
+ if (url[y] == '%') {
+ hi = hex_to_integer(url[y + 1]);
+ if (hi < 0) {
+ /* %-encoding is malformed, leave as-is */
+ url[x] = '%';
+ continue;
+ }
+ lo = hex_to_integer(url[y + 2]);
+ if (lo < 0) {
+ /* %-encoding is malformed, leave as-is */
+ url[x] = '%';
+ continue;
+ }
+ url[x] = (char)(hi * 16 + lo);
y += 2;
+ } else {
+ url[x] = url[y];
}
}
url[x] = '\0';
=====================================
src/cgiutil.h
=====================================
@@ -93,7 +93,6 @@ MS_DLL_EXPORT void getword(char *, char *, char);
MS_DLL_EXPORT char *makeword_skip(char *, char, char);
MS_DLL_EXPORT char *makeword(char *, char);
MS_DLL_EXPORT char *fmakeword(FILE *, char, int *);
-MS_DLL_EXPORT char x2c(char *);
MS_DLL_EXPORT void unescape_url(char *);
MS_DLL_EXPORT void plustospace(char *);
MS_DLL_EXPORT int rind(char *, char);
=====================================
src/mapogcapi.cpp
=====================================
@@ -2023,9 +2023,6 @@ OGCAPIFormat msOGCAPIGetOutputFormat(cgiRequestObj *request) {
strstr(p, OGCAPI_MIMETYPE_HTML) != nullptr)) {
format = OGCAPIFormat::HTML;
} else if (p) {
- std::string errorMsg("Unsupported format requested: ");
- errorMsg += p;
- msOGCAPIOutputError(OGCAPI_PARAM_ERROR, errorMsg.c_str());
format = OGCAPIFormat::Invalid;
} else {
format = OGCAPIFormat::HTML; // default for now
@@ -2060,6 +2057,7 @@ int msOGCAPIDispatchRequest(mapObj *map, cgiRequestObj *request) {
const OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
if (format == OGCAPIFormat::Invalid) {
+ msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
return MS_SUCCESS; // avoid any downstream MapServer processing
}
=====================================
src/mapows.c
=====================================
@@ -1468,7 +1468,7 @@ const char *msOWSGetInspireSchemasLocation(mapObj *map) {
schemas_location =
msLookupHashTable(&(map->web.metadata), "inspire_schemas_location");
if (schemas_location == NULL)
- schemas_location = "http://inspire.ec.europa.eu/schemas";
+ schemas_location = INSPIRE_DEFAULT_SCHEMAS_LOCATION;
return schemas_location;
}
=====================================
src/mapows.h
=====================================
@@ -40,6 +40,13 @@
*/
#define OWS_DEFAULT_SCHEMAS_LOCATION "http://schemas.opengis.net"
+/* Likewise, this is the URL to the official INSPIRE Schema Repository. Used by
+ * default for INSPIRE services (i.e. services that define
+ * ows_inspire_capabilities) unless the inspire_schemas_location web
+ * metadata is set in the mapfile.
+ */
+#define INSPIRE_DEFAULT_SCHEMAS_LOCATION "https://inspire.ec.europa.eu/schemas"
+
#if defined USE_LIBXML2 && defined USE_WFS_SVR
#include <libxml/tree.h>
#endif
=====================================
src/mappostgis.cpp
=====================================
@@ -2024,18 +2024,16 @@ static std::string msPostGISBuildSQLWhere(layerObj *layer, const rectObj *rect,
}
}
}
- bool insert_and = false;
+
std::string strWhere;
if (bIsValidRect && !strRect.empty()) {
strWhere += strRect;
- insert_and = true;
}
/* Handle a translated filter (RFC91). */
if (layer->filter.native_string) {
- if (insert_and) {
+ if (!strWhere.empty()) {
strWhere += " AND ";
- insert_and = true;
}
strWhere += '(';
strWhere += layer->filter.native_string;
@@ -2045,17 +2043,17 @@ static std::string msPostGISBuildSQLWhere(layerObj *layer, const rectObj *rect,
/* Handle a native filter set as a PROCESSING option (#5001). */
const char *native_filter = msLayerGetProcessingKey(layer, "NATIVE_FILTER");
if (native_filter) {
- if (insert_and) {
+ if (!strWhere.empty()) {
strWhere += " AND ";
- insert_and = true;
}
+
strWhere += '(';
strWhere += native_filter;
strWhere += ')';
}
if (uid) {
- if (insert_and) {
+ if (!strWhere.empty()) {
strWhere += " AND ";
}
@@ -3736,6 +3734,17 @@ static int msPostGISLayerTranslateFilter(layerObj *layer, expressionObj *filter,
native_string += stresc;
native_string += '\'';
} else {
+ char *endptr = nullptr;
+ std::strtod(stresc, &endptr);
+ if (endptr != stresc + strlen(stresc)) {
+ if (layer->debug >= 2) {
+ msDebug(
+ "msPostGISLayerTranslateFilter. '%s' is not a numeric value.\n",
+ filter->string);
+ }
+ msFree(stresc);
+ return MS_FAILURE;
+ }
native_string += stresc;
}
msFree(stresc);
=====================================
src/maprasterquery.c
=====================================
@@ -1205,7 +1205,10 @@ int msRASTERLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) {
switch (rlinfo->eDataType) {
case GDT_Byte:
+#if GDAL_VERSION_MAJOR > 3 || \
+ (GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR >= 7)
case GDT_Int8:
+#endif
case GDT_UInt16:
case GDT_Int16:
case GDT_Int32:
=====================================
src/mapscale.c
=====================================
@@ -309,7 +309,7 @@ imageObj *msDrawScalebar(mapObj *map) {
}
}
- sprintf(label, "%g", j * i);
+ snprintf(label, sizeof(label), "%g", j * i);
map->scalebar.label.position = MS_CC;
p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
@@ -320,9 +320,10 @@ imageObj *msDrawScalebar(mapObj *map) {
}
state = -state;
}
- sprintf(label, "%g", j * i);
+ snprintf(label, sizeof(label), "%g", j * i);
ox = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
- sprintf(label, "%g %s", j * i, unitText[map->scalebar.units]);
+ snprintf(label, sizeof(label), "%g %s", j * i,
+ unitText[map->scalebar.units]);
map->scalebar.label.position = MS_CR;
p.x = ox; /* + MS_NINT(fontPtr->w/2); */
p.y = oy + map->scalebar.height + MS_NINT(VSPACING * fontHeight);
@@ -361,12 +362,13 @@ imageObj *msDrawScalebar(mapObj *map) {
goto scale_cleanup;
}
- sprintf(label, "%g", j * i);
+ snprintf(label, sizeof(label), "%g", j * i);
if (j != map->scalebar.intervals) {
map->scalebar.label.position = MS_CC;
p.x = ox + j * isx; /* + MS_NINT(fontPtr->w/2); */
} else {
- sprintf(label, "%g %s", j * i, unitText[map->scalebar.units]);
+ snprintf(label, sizeof(label), "%g %s", j * i,
+ unitText[map->scalebar.units]);
map->scalebar.label.position = MS_CR;
p.x = ox + j * isx - MS_NINT((strlen(label) * fontWidth) / 2.0);
}
=====================================
src/mapserv-index.cpp
=====================================
@@ -425,7 +425,7 @@ static int createHTMLOutput(json response, const char *templateName) {
int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
#ifdef USE_OGCAPI_SVR
if (!mapserv || !config)
- return -1; // Handle null pointers
+ return MS_FAILURE; // Handle null pointers
cgiRequestObj *request = mapserv->request;
@@ -437,6 +437,12 @@ int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
}
OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
+
+ if (format == OGCAPIFormat::Invalid) {
+ msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+ return MS_FAILURE;
+ }
+
const char *key = request->api_path[0];
mapObj *map = getMapFromConfig(config, key);
@@ -479,11 +485,16 @@ int msOGCAPIDispatchMapIndexRequest(mapservObj *mapserv, configObj *config) {
int msOGCAPIDispatchIndexRequest(mapservObj *mapserv, configObj *config) {
#ifdef USE_OGCAPI_SVR
if (!mapserv || !config)
- return -1; // Handle null pointers
+ return MS_FAILURE; // Handle null pointers
cgiRequestObj *request = mapserv->request;
const OGCAPIFormat format = msOGCAPIGetOutputFormat(request);
+ if (format == OGCAPIFormat::Invalid) {
+ msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+ return MS_FAILURE;
+ }
+
const char *key = NULL;
json links = json::array();
@@ -504,7 +515,7 @@ int msOGCAPIDispatchIndexRequest(mapservObj *mapserv, configObj *config) {
} else if (format == OGCAPIFormat::HTML) {
createHTMLOutput(response, TEMPLATE_HTML_INDEX);
} else {
- msOGCAPIOutputError(OGCAPI_PARAM_ERROR, "Unsupported format requested.");
+ assert(false && "Unhandled OGCAPIFormat value");
}
return MS_SUCCESS;
=====================================
src/mapserver.h
=====================================
@@ -2889,7 +2889,8 @@ MS_DLL_EXPORT void msStringFirstCap(char *string);
MS_DLL_EXPORT int msEncodeChar(const char);
MS_DLL_EXPORT char *msEncodeUrlExcept(const char *, const char);
MS_DLL_EXPORT char *msEncodeUrl(const char *);
-MS_DLL_EXPORT char *msEscapeJSonString(const char *pszJSonString);
+MS_DLL_EXPORT char *msEscapeJSonString(const char *pszString);
+MS_DLL_EXPORT char *msEscapeJSonLikeString(const char *pszString, char chQuote);
MS_DLL_EXPORT char *msEncodeHTMLEntities(const char *string);
MS_DLL_EXPORT void msDecodeHTMLEntities(const char *string);
MS_DLL_EXPORT int msIsXMLTagValid(const char *string);
=====================================
src/mapstring.cpp
=====================================
@@ -1205,18 +1205,18 @@ char *msEncodeUrlExcept(const char *data, const char except) {
/* msEscapeJSonString() */
/************************************************************************/
-/* The input (and output) string are not supposed to start/end with double */
-/* quote characters. It is the responsibility of the caller to do that. */
-char *msEscapeJSonString(const char *pszJSonString) {
+/* The input (and output) string are not supposed to start/end with chQuote
+ * characters. It is the responsibility of the caller to do that. */
+char *msEscapeJSonLikeString(const char *pszString, char chQuote) {
/* Worst case is one character to become \uABCD so 6 characters */
char *pszRet;
int i = 0, j = 0;
static const char *pszHex = "0123456789ABCDEF";
- pszRet = (char *)msSmallMalloc(strlen(pszJSonString) * 6 + 1);
+ pszRet = (char *)msSmallMalloc(strlen(pszString) * 6 + 1);
/* From http://www.json.org/ */
- for (i = 0; pszJSonString[i] != '\0'; i++) {
- unsigned char ch = pszJSonString[i];
+ for (i = 0; pszString[i] != '\0'; i++) {
+ unsigned char ch = pszString[i];
if (ch == '\b') {
pszRet[j++] = '\\';
pszRet[j++] = 'b';
@@ -1239,9 +1239,9 @@ char *msEscapeJSonString(const char *pszJSonString) {
pszRet[j++] = '0';
pszRet[j++] = pszHex[ch / 16];
pszRet[j++] = pszHex[ch % 16];
- } else if (ch == '"') {
+ } else if (ch == chQuote) {
pszRet[j++] = '\\';
- pszRet[j++] = '"';
+ pszRet[j++] = chQuote;
} else if (ch == '\\') {
pszRet[j++] = '\\';
pszRet[j++] = '\\';
@@ -1253,6 +1253,12 @@ char *msEscapeJSonString(const char *pszJSonString) {
return pszRet;
}
+/* The input (and output) string are not supposed to start/end with double
+ * quote characters. It is the responsibility of the caller to do that. */
+char *msEscapeJSonString(const char *pszString) {
+ return msEscapeJSonLikeString(pszString, '"');
+}
+
/* msEncodeHTMLEntities()
**
** Return a copy of string after replacing some problematic chars with their
=====================================
src/maptemplate.c
=====================================
@@ -4097,7 +4097,21 @@ static char *processLine(mapservObj *mapserv, const char *instr, FILE *stream,
#else
ol = msBuildOnlineResource(mapserv->map, mapserv->request);
#endif
- outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol);
+
+ if (strstr(outstr, "'[mapserv_onlineresource]'")) {
+ // Fix
+ // https://github.com/MapServer/MapServer/security/advisories/GHSA-xqj6-vjqr-33vv
+ char *pszEscaped = msEscapeJSonLikeString(ol, '\'');
+ const size_t nLen = 1 + strlen(pszEscaped) + 1 + 1;
+ char *pszEscapedWithSingleQuotes = (char *)msSmallMalloc(nLen);
+ snprintf(pszEscapedWithSingleQuotes, nLen, "'%s'", pszEscaped);
+ outstr = msReplaceSubstring(outstr, "'[mapserv_onlineresource]'",
+ pszEscapedWithSingleQuotes);
+ msFree(pszEscapedWithSingleQuotes);
+ msFree(pszEscaped);
+ } else {
+ outstr = msReplaceSubstring(outstr, "[mapserv_onlineresource]", ol);
+ }
msFree(ol);
}
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapserver/-/compare/fae9ca68878a6b8f5d1801b67b5cd150ee3aa623...9c49374f98a2640deefb354ce87701210bb336e6
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapserver/-/compare/fae9ca68878a6b8f5d1801b67b5cd150ee3aa623...9c49374f98a2640deefb354ce87701210bb336e6
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260601/cead7cd4/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list