diff -uNr a/BUILD b/BUILD --- a/BUILD 1970-01-01 00:00:00 +0000 +++ b/BUILD 1970-01-01 00:00:00 +0000 @@ -102,7 +102,7 @@ mkdir build root mkdir -m 1755 root/package mkdir -m 1755 root/package/admin - cp -r $GALES_REPO/base/* build/ + cp -r $GALES_REPO/base/. build/ mv build/daemontools root/package/admin/daemontools-0.76 2.2. Compile basic build-time tools using the host toolchain diff -uNr a/INSTALL b/INSTALL --- a/INSTALL 1970-01-01 00:00:00 +0000 +++ b/INSTALL 1970-01-01 00:00:00 +0000 @@ -32,7 +32,7 @@ /bin/busybox --install -s 8. Install example config files and source the new shell profile: - cp -rv /etc/examples/* /etc/ + cp -rv /etc/examples/. /etc/ . /etc/profile 9. Set a root password: diff -uNr a/PORTS b/PORTS --- a/PORTS 1970-01-01 00:00:00 +0000 +++ b/PORTS 1970-01-01 00:00:00 +0000 @@ -33,6 +33,7 @@ mandoc ncurses pciutils +pcre perl zlib @@ -48,6 +49,7 @@ 3: bc (automake readline) bison (automake m4) +expat (automake) libtool (automake) strace (autoconf automake) sqlite (readline ncurses) @@ -63,8 +65,8 @@ clisp (automake readline ncurses) cl-hyperspec ocaml -php (autoconf sqlite) -python (autoconf bzip2 db ncurses readline sqlite zlib) +php (autoconf expat pcre sqlite) +python (autoconf bzip2 db expat ncurses readline sqlite zlib) python-docs 5: diff -uNr a/VERSION b/VERSION --- a/VERSION 1970-01-01 00:00:00 +0000 +++ b/VERSION 1970-01-01 00:00:00 +0000 @@ -1,4 +1,4 @@ -26 +26.1 The major version is the year of release, minus 2000. A new base tarball is published for each major release. diff -uNr a/conf/kshrc b/conf/kshrc --- a/conf/kshrc 1970-01-01 00:00:00 +0000 +++ b/conf/kshrc 1970-01-01 00:00:00 +0000 @@ -16,6 +16,8 @@ HISTSIZE=1000 +alias ll='ls -lA' + # For GNU coreutils/grep #alias ls='ls --color=auto' #alias grep='grep --color=auto' diff -uNr a/conf/rc b/conf/rc --- a/conf/rc 1970-01-01 00:00:00 +0000 +++ b/conf/rc 1970-01-01 00:00:00 +0000 @@ -61,7 +61,7 @@ msg "(Re)creating /dev/rtc0 due to dynamic major" [ -e /dev/rtc0 ] && rm -f /dev/rtc0 mknod -m644 /dev/rtc0 c $dec 0 - [ -e /dev/rtc] || ln -s rtc0 /dev/rtc + [ -e /dev/rtc ] || ln -s rtc0 /dev/rtc fi) ifconfig lo 127.0.0.1 diff -uNr a/gports/clockspeed/build.sh b/gports/clockspeed/build.sh --- a/gports/clockspeed/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/clockspeed/build.sh 1970-01-01 00:00:00 +0000 @@ -1,7 +1,7 @@ P=clockspeed V=0.62 MAJOR=0 -MINOR=1 +MINOR=2 S=" $P-$V.tar.gz http://cr.yp.to/$P/$P-$V.tar.gz @@ -12,6 +12,7 @@ clockspeed-cpu-affinity.patch clockspeed-gettime-clockview-adjust.patch clockspeed-rtclock.patch +clockspeed-rtclock-realtime.patch README.gales run " @@ -40,6 +41,7 @@ patch -Ep1 <../clockspeed-cpu-affinity.patch patch -Ep1 <../clockspeed-gettime-clockview-adjust.patch patch -Ep1 <../clockspeed-rtclock.patch + patch -Ep1 <../clockspeed-rtclock-realtime.patch sed -i 's,/usr/local,/gales/pkg,g' clockspeed.1 sed -i "s,/usr/local/$P,/gales/pkg/$Q,g" conf-home make -j$JOBS diff -uNr a/gports/clockspeed/clockspeed-rtclock-realtime.patch b/gports/clockspeed/clockspeed-rtclock-realtime.patch --- a/gports/clockspeed/clockspeed-rtclock-realtime.patch 1970-01-01 00:00:00 +0000 +++ b/gports/clockspeed/clockspeed-rtclock-realtime.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,53 @@ +Attempt to improve accuracy by setting a real-time scheduler policy (generally requires running as root). + +pthread functions are used because musl doesn't implement sched_setscheduler, because the Linux syscall's behavior is too nonstandard for them. It doesn't matter in the single-threaded case, so a custom syscall wrapper would be an alternative here. + + -jfw + +--- a/rtclock.c ++++ b/rtclock.c +@@ -4,6 +4,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include "strerr.h" +@@ -15,6 +17,7 @@ + substdio ssout = SUBSTDIO_FDBUF(write, 1, outbuf, sizeof outbuf); + + #define FATAL "rtclock: fatal: " ++#define WARNING "rtclock: warning: " + + void die_usage() + { +@@ -62,6 +65,7 @@ + char const *devpath = "/dev/rtc"; + int fd; + unsigned long irqdata; ++ static struct sched_param sparam; + struct tm tm_rtc; + struct taia t_rtc; + struct taia t_sys; +@@ -74,6 +78,10 @@ + strerr_die4sys(111, FATAL, "unable to open ", devpath, ": "); + + /* RTC doesn't report sub-seconds but we can wait for its tick */ ++ sparam.sched_priority = 1; ++ errno = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparam); ++ if (errno) ++ strerr_warn2(WARNING, "unable to set real-time priority: ", &strerr_sys); + if (ioctl(fd, RTC_UIE_ON) == -1) + strerr_die2sys(111, FATAL, "unable to set RTC update interrupt: "); + if (read(fd, &irqdata, sizeof irqdata) == -1) +@@ -86,6 +94,8 @@ + + /* try to be nice and disable interrupt */ + ioctl(fd, RTC_UIE_OFF); ++ sparam.sched_priority = 0; ++ pthread_setschedparam(pthread_self(), SCHED_OTHER, &sparam); + close(fd); + + utclike_to_taia(&t_rtc, &tm_rtc); diff -uNr a/gports/djbdns/README.gales b/gports/djbdns/README.gales --- a/gports/djbdns/README.gales 1970-01-01 00:00:00 +0000 +++ b/gports/djbdns/README.gales 1970-01-01 00:00:00 +0000 @@ -10,6 +10,10 @@ # addgroup -S tinydns # adduser -SH -h / -g 'djbdns authoritative nameserver' -s /bin/false -G tinydns tinydns +Or to add axfrdns for TCP service: + + # adduser -SH -h / -g 'djbdns zone transfer and tcp server' -s /bin/false -G tinydns axfrdns + Program and data format documentation is online at: http://cr.yp.to/djbdns.html Example service definitions are provided; the recommendation is to get started in the usual Gales way by copying them into place: @@ -20,6 +24,10 @@ # cp -r /etc/examples/svc/tinydns /etc/svc/ +and optionally + + # cp -r /etc/examples/svc/axfrdns /etc/svc/ + then editing to suit your needs and finally symlinking to /service. For tinydns in particular you'll need to set /etc/svc/tinydns/env/IP to your actual public IP address to bind. If the same machine also runs a cache, the two must be on different IPs. -The dnscache-conf and tinydns-conf programs are still included for those who may be accustomed to them; they should work but are not fully assimilated into Gales conventions. For dnscache-conf you'll need to first copy /etc/examples/dnsroots.global to /etc/, and note that its generated run script uses the default (weak) random seed file mechanism. +The dnscache-conf and tinydns-conf programs are still included for those who may be accustomed to them; they should work but are not fully assimilated into Gales conventions. For dnscache-conf you'll need to first copy /etc/examples/dnsroots.global to /etc/, and note that its generated run script uses the default (weak) random seed file mechanism. For axfrdns-conf, the generated run script uses tcpserver from DJB's ucspi-tcp; the Gales equivalent here is Busybox tcpsvd as seen in the example service, though it doesn't support the tcprules mechanism for client IP based access control. diff -uNr a/gports/djbdns/axfrdns.run b/gports/djbdns/axfrdns.run --- a/gports/djbdns/axfrdns.run 1970-01-01 00:00:00 +0000 +++ b/gports/djbdns/axfrdns.run 1970-01-01 00:00:00 +0000 @@ -0,0 +1,12 @@ +#!/bin/sh +# Even if you don't use zone transfers, axfrdns service is useful for responding to DNS queries on TCP. That isn't normally a sane thing to do, but some upstream zone operators demand it. +exec 2>&1 + +IP=0 + +# $AXFR is a slash-separated list of domain names available for zone transfers. Leave it empty to disallow all zones; if it's not set at all then all are allowed. +export AXFR= +# chroot directory containing data.cdb +export ROOT=/etc/svc/tinydns/root + +exec envuidgid axfrdns softlimit -d300000 tcpsvd -vl0 $IP 53 /gales/pkg/djbdns/bin/axfrdns diff -uNr a/gports/djbdns/build.sh b/gports/djbdns/build.sh --- a/gports/djbdns/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/djbdns/build.sh 1970-01-01 00:00:00 +0000 @@ -2,7 +2,7 @@ P=djbdns V=1.05 MAJOR=0 -MINOR=0 +MINOR=1 S=" $P-$V.tar.gz http://cr.yp.to/djbdns/$P-$V.tar.gz @@ -16,6 +16,7 @@ dnsroots.global dnscache.run tinydns.run +axfrdns.run " SHA512=" @@ -78,6 +79,16 @@ chmod 755 root/add-$type done printf 'data.cdb: data\n\t/gales/pkg/djbdns/bin/tinydns-data\n' >root/Makefile + + # assemble example axfrdns service, replacing axfrdns-conf + cd .. + mkdir svcaxfrdns + cd svcaxfrdns + cp ../../axfrdns.run run + chmod 755 run + + mkdir log + ln -s /etc/svc.defs/multilog log/run } package () { @@ -88,6 +99,7 @@ done a etc/examples/svc/dnscache svcdnscache a etc/examples/svc/tinydns svctinydns + a etc/examples/svc/axfrdns svcaxfrdns # per hier.c f etc/examples/dnsroots.global diff -uNr a/gports/expat/README.gales b/gports/expat/README.gales --- a/gports/expat/README.gales 1970-01-01 00:00:00 +0000 +++ b/gports/expat/README.gales 1970-01-01 00:00:00 +0000 @@ -0,0 +1,15 @@ +This Expat port introduces some deliberate API breakage for security hardening and auditing purposes in Gales, in addition to the existing upstream mitigations for well-known denial of service attacks as of version 2.8.1 (2026). + +As XML libraries go, Expat is relatively lightweight and predictable, lacking the extras like XSLT or schema validation. However, it does expose hooks that enable applications to implement custom hash seeding, processing directives, and external entity expansion (for instance, the -x option of the included xmlwf program). Not all such use is necessarily insecure, but it's a prime avenue for security holes and probably shouldn't be enabled without operator knowledge. Therefore, the affected functions are renamed with _hazmat suffix, namely: + +XML_SetHashSalt -> XML_SetHashSalt_hazmat +XML_SetHashSalt16Bytes -> XML_SetHashSalt16Bytes_hazmat +XML_ExternalEntityParserCreate -> XML_ExternalEntityParserCreate_hazmat +XML_SetExternalEntityRefHandler -> XML_SetExternalEntityRefHandler_hazmat +XML_SetProcessingInstructionHandler -> XML_SetProcessingInstructionHandler_hazmat + +The changes are also noted in the included expat.h. + +For high level language bindings that link these interfaces just in order to expose them to user code, the intended approach is to replicate the renaming at that level too; unfortunately with dynamic languages it won't be as obvious up front when an application is broken by the rename. + +Additionally, the xml context tracking buffer feature (--enable-xml-context), where a security flaw was found in 2022, is disabled at least until we see what actually needs it. diff -uNr a/gports/expat/build.sh b/gports/expat/build.sh --- a/gports/expat/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/expat/build.sh 1970-01-01 00:00:00 +0000 @@ -0,0 +1,73 @@ +P=expat +V=2.8.1 +MAJOR=0 +MINOR=0 + +# Requires: autoconf automake +# TODO: document the API renames + +S=" +$P-$V.tar.gz +expat-2.8.1-kill-libtool.patch +expat-2.8.1-standard-shell.patch +expat-2.8.1-entropy-hardening.patch +expat-2.8.1-xxe-hardening.patch +README.gales +" + +SHA512=" +2b17c1210d7267bdd0bd98d3e093279c56487efec1f2ae725bbc87b834c3f7aa789791ddb89ee324d1a823dc4e65b2f0d1555afb95cc06d64d75821e565dfc8c expat-2.8.1.tar.gz +" + +build () { + root=$PWD/root + tar xzf $P-$V.tar.gz + cd $P-$V + rm -r m4 # contains libtool macros only; their own are under conftools + (cd conftools && rm ar-lib compile config.guess config.sub depcomp install-sh ltmain.sh missing test-driver) + rm aclocal.m4 configure expat_config.h* Makefile.in */Makefile.in */*/Makefile.in lib/libexpat.def.cmake + + patch -Ep1 <../expat-2.8.1-kill-libtool.patch + patch -Ep1 <../expat-2.8.1-standard-shell.patch + rm fix-xmltest-log.sh # the above removes all use of this file, but non-ASCII in copyright comment prevents removing the file itself in the patch. + patch -Ep1 <../expat-2.8.1-entropy-hardening.patch + patch -Ep1 <../expat-2.8.1-xxe-hardening.patch + + autoreconf -fisv + CFLAGS=-O1 ./configure --prefix=/gales/pkg/$Q \ + --datarootdir='${prefix}' \ + --docdir='${prefix}/doc' \ + --disable-dependency-tracking \ + --disable-xml-context \ + --without-examples \ + --without-arc4random \ + --without-arc4random-buf \ + --with-getentropy \ + --without-getrandom \ + --without-sys-getrandom \ + --without-docbook + make -j$JOBS + make install DESTDIR=$root + rm -r $root/gales/pkg/$Q/lib/cmake # exterminate! +} + +check () { + cd $P-$V + make -j$JOBS check + if [ $CHECK_LEVEL -lt 3 ]; then + echo 'skipping broken xmltest suite (needs data from w3c, and possibly python3)' + return + fi + cd tests + ./xmltest.sh +} + +package () { + f gales/pkg/$Q/doc/README.gales + cd root/gales/pkg + a gales/pkg/$Q + l gales/pkg/$P $Q + l gales/command/xmlwf ../pkg/$P/bin/xmlwf + l gales/doc/$P ../pkg/$P/doc + l gales/man/$P ../pkg/$P/man +} diff -uNr a/gports/expat/expat-2.8.1-entropy-hardening.patch b/gports/expat/expat-2.8.1-entropy-hardening.patch --- a/gports/expat/expat-2.8.1-entropy-hardening.patch 1970-01-01 00:00:00 +0000 +++ b/gports/expat/expat-2.8.1-entropy-hardening.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,246 @@ +diff -ur a/fuzz/xml_lpm_fuzzer.cpp b/fuzz/xml_lpm_fuzzer.cpp +--- a/fuzz/xml_lpm_fuzzer.cpp 2026-05-10 12:46:49 +0000 ++++ b/fuzz/xml_lpm_fuzzer.cpp 2026-05-26 06:41:11 +0000 +@@ -383,7 +383,7 @@ + void + InitializeParser(XML_Parser parser) { + XML_SetUserData(parser, (void *)parser); +- XML_SetHashSalt(parser, 0x41414141); ++ XML_SetHashSalt_hazmat(parser, 0x41414141); + XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + + XML_SetElementDeclHandler(parser, ElementDeclHandler); +diff -ur a/fuzz/xml_parse_fuzzer.c b/fuzz/xml_parse_fuzzer.c +--- a/fuzz/xml_parse_fuzzer.c 2026-04-18 16:26:21 +0000 ++++ b/fuzz/xml_parse_fuzzer.c 2026-05-26 06:41:11 +0000 +@@ -60,7 +60,7 @@ + ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) { + // Set the hash salt using siphash to generate a deterministic hash. + struct sipkey *key = sip_keyof(hash_key); +- XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key)); ++ XML_SetHashSalt_hazmat(p, (unsigned long)siphash24(data, size, key)); + (void)sip24_valid; + + XML_SetUserData(p, p); +diff -ur a/fuzz/xml_parsebuffer_fuzzer.c b/fuzz/xml_parsebuffer_fuzzer.c +--- a/fuzz/xml_parsebuffer_fuzzer.c 2026-04-18 16:26:21 +0000 ++++ b/fuzz/xml_parsebuffer_fuzzer.c 2026-05-26 06:41:11 +0000 +@@ -61,7 +61,7 @@ + ParseOneInput(XML_Parser p, const uint8_t *data, size_t size) { + // Set the hash salt using siphash to generate a deterministic hash. + struct sipkey *key = sip_keyof(hash_key); +- XML_SetHashSalt(p, (unsigned long)siphash24(data, size, key)); ++ XML_SetHashSalt_hazmat(p, (unsigned long)siphash24(data, size, key)); + (void)sip24_valid; + + XML_SetUserData(p, p); +diff -ur a/lib/expat.h b/lib/expat.h +--- a/lib/expat.h 2026-05-10 17:16:35 +0000 ++++ b/lib/expat.h 2026-05-26 06:47:03 +0000 +@@ -919,9 +919,10 @@ + Returns 1 if successful, 0 when called after parsing has started. + Note: If parser == NULL, the function will do nothing and return 0. + DEPRECATED since Expat 2.8.0. ++ Renamed to _hazmat as Gales audit for insecure use (it blocks higher entropy automatic salt generation and therefore no longer helps, only hurts; determinism for internal testing is presumed the only legitimate use for these). + */ + XMLPARSEAPI(int) +-XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); ++XML_SetHashSalt_hazmat(XML_Parser parser, unsigned long hash_salt); + + /* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash function behavior. +@@ -929,9 +930,10 @@ + Returns XML_TRUE if successful, XML_FALSE when called after parsing has + started or when parser is NULL. + Added in Expat 2.8.0. ++ Renamed to _hazmat as Gales audit for insecure use (it blocks automatic salt generation; determinism for internal testing is presumed the only legitimate use for these). + */ + XMLPARSEAPI(XML_Bool) +-XML_SetHashSalt16Bytes(XML_Parser parser, const uint8_t entropy[16]); ++XML_SetHashSalt16Bytes_hazmat(XML_Parser parser, const uint8_t entropy[16]); + + /* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +diff -ur a/lib/libexpat.map.in b/lib/libexpat.map.in +--- a/lib/libexpat.map.in 2026-05-08 18:34:38 +0000 ++++ b/lib/libexpat.map.in 2026-05-26 06:41:11 +0000 +@@ -98,7 +98,7 @@ + LIBEXPAT_2.1.0 { + global: + @_EXPAT_COMMENT_ATTR_INFO@ XML_GetAttributeInfo; +- XML_SetHashSalt; ++ XML_SetHashSalt_hazmat; + } LIBEXPAT_1.95.8; + + LIBEXPAT_2.4.0 { +@@ -120,5 +120,5 @@ + + LIBEXPAT_2.8.0 { + global: +- XML_SetHashSalt16Bytes; ++ XML_SetHashSalt16Bytes_hazmat; + } LIBEXPAT_2.7.2; +diff -ur a/lib/random_dev_urandom.c b/lib/random_dev_urandom.c +--- a/lib/random_dev_urandom.c 2026-05-10 12:46:50 +0000 ++++ b/lib/random_dev_urandom.c 2026-05-26 06:41:11 +0000 +@@ -41,10 +41,13 @@ + #include // open + #include // close + +-/* Extract entropy from /dev/urandom */ ++/* Extract entropy from /dev/urandom ++ * XXX This whole family is misnamed, it's obviously not writing but READING: inbound transfer of information to the caller, by convention long predating expat. They seem to focus on what happens at low level to the caller's buffer, rather than the higher meaning of the transfer (everyone's read is someone else's write). -jfw ++ * Returns true on success; returns false and sets errno on failure. ++ * Previously did not set or use errno reliably. That might not matter in current usage, but let's not leave rakes lying around. ++ */ + bool + writeRandomBytes_dev_urandom(void *target, size_t count) { +- int success = false; /* full count bytes written? */ + size_t bytesWrittenTotal = 0; + + const int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); +@@ -52,21 +55,31 @@ + return 0; + } + +- do { ++ while (bytesWrittenTotal < count) { + void *const currentTarget = (void *)((char *)target + bytesWrittenTotal); + const size_t bytesToWrite = count - bytesWrittenTotal; + +- errno = 0; +- + const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite); + +- if (bytesWrittenMore > 0) { +- bytesWrittenTotal += bytesWrittenMore; +- if (bytesWrittenTotal >= count) +- success = true; +- } +- } while (! success && (errno == EINTR)); ++ if (bytesWrittenMore < 0) { ++ if (errno != EINTR) { ++ /* unexpected error! */ ++ int errno_saved = errno; ++ close(fd); ++ errno = errno_saved; ++ return false; ++ } ++ /* for EINTR, simply retry */ ++ } else if (bytesWrittenMore == 0) { ++ /* EOF without error shouldn't happen for urandom, but don't busy loop if it does */ ++ close(fd); ++ errno = EIO; ++ return false; ++ } else { ++ bytesWrittenTotal += bytesWrittenMore; ++ } ++ } + + close(fd); +- return success; ++ return true; + } +diff -ur a/lib/xmlparse.c b/lib/xmlparse.c +--- a/lib/xmlparse.c 2026-05-10 17:16:35 +0000 ++++ b/lib/xmlparse.c 2026-05-26 06:41:54 +0000 +@@ -1110,6 +1110,8 @@ + # endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */ + /* .. and self-made low quality for backup: */ + ++ /* XXX I'd like to remove this fallback and return error to the application, but unclear if that's possible or how; it seems XML_ERROR_NO_MEMORY is the only reportable condition so far. -jfw */ ++ + entropy.k[0] = 0; + entropy.k[1] = gather_time_entropy(); + # if ! defined(__wasi__) +@@ -2206,7 +2208,7 @@ + + // DEPRECATED since Expat 2.8.0. + int XMLCALL +-XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { ++XML_SetHashSalt_hazmat(XML_Parser parser, unsigned long hash_salt) { + if (parser == NULL) + return 0; + +@@ -2233,7 +2235,7 @@ + } + + XML_Bool XMLCALL +-XML_SetHashSalt16Bytes(XML_Parser parser, const uint8_t entropy[16]) { ++XML_SetHashSalt16Bytes_hazmat(XML_Parser parser, const uint8_t entropy[16]) { + if (parser == NULL) + return XML_FALSE; + +diff -ur a/tests/basic_tests.c b/tests/basic_tests.c +--- a/tests/basic_tests.c 2026-05-10 17:16:35 +0000 ++++ b/tests/basic_tests.c 2026-05-26 06:41:11 +0000 +@@ -198,7 +198,7 @@ + "This triggers the table growth and collides with b2\n" + "\n"; + +- XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT); ++ XML_SetHashSalt_hazmat(g_parser, COLLIDING_HASH_SALT); + if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE) + == XML_STATUS_ERROR) + xml_failure(g_parser); +@@ -212,19 +212,19 @@ + XML_Parser parser = XML_ParserCreate(NULL); + + // NULL parser should be rejected +- assert_true(XML_SetHashSalt16Bytes(NULL, entropy) == XML_FALSE); ++ assert_true(XML_SetHashSalt16Bytes_hazmat(NULL, entropy) == XML_FALSE); + + // NULL entropy should be rejected +- assert_true(XML_SetHashSalt16Bytes(parser, NULL) == XML_FALSE); ++ assert_true(XML_SetHashSalt16Bytes_hazmat(parser, NULL) == XML_FALSE); + + // Setting should be allowed more than once +- assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE); +- assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_TRUE); ++ assert_true(XML_SetHashSalt16Bytes_hazmat(parser, entropy) == XML_TRUE); ++ assert_true(XML_SetHashSalt16Bytes_hazmat(parser, entropy) == XML_TRUE); + + // But not after parsing has started + assert_true(XML_Parse(parser, "", 0, XML_FALSE /* isFinal */) + == XML_STATUS_OK); +- assert_true(XML_SetHashSalt16Bytes(parser, entropy) == XML_FALSE); ++ assert_true(XML_SetHashSalt16Bytes_hazmat(parser, entropy) == XML_FALSE); + + XML_ParserFree(parser); + } +@@ -2334,7 +2334,7 @@ + ExtTest test_data = {"", NULL, NULL}; + + /* Check hash salt is passed through too */ +- XML_SetHashSalt(g_parser, 0x12345678); ++ XML_SetHashSalt_hazmat(g_parser, 0x12345678); + XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetUserData(g_parser, &test_data); + XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); +@@ -2353,7 +2353,7 @@ + != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING) + fail("Failed to reject late foreign DTD setting"); + /* Ditto for the hash salt */ +- if (XML_SetHashSalt(g_parser, 0x23456789)) ++ if (XML_SetHashSalt_hazmat(g_parser, 0x23456789)) + fail("Failed to reject late hash salt change"); + + /* Now finish the parse */ +@@ -2404,7 +2404,7 @@ + ExtTest test_data = {"", NULL, NULL}; + + /* Check hash salt is passed through too */ +- XML_SetHashSalt(g_parser, 0x12345678); ++ XML_SetHashSalt_hazmat(g_parser, 0x12345678); + XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS); + XML_SetUserData(g_parser, &test_data); + XML_SetExternalEntityRefHandler(g_parser, external_entity_loader); +@@ -2423,7 +2423,7 @@ + != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING) + fail("Failed to reject late foreign DTD setting"); + /* Ditto for the hash salt */ +- if (XML_SetHashSalt(g_parser, 0x23456789)) ++ if (XML_SetHashSalt_hazmat(g_parser, 0x23456789)) + fail("Failed to reject late hash salt change"); + + /* Now finish the parse */ diff -uNr a/gports/expat/expat-2.8.1-kill-libtool.patch b/gports/expat/expat-2.8.1-kill-libtool.patch --- a/gports/expat/expat-2.8.1-kill-libtool.patch 1970-01-01 00:00:00 +0000 +++ b/gports/expat/expat-2.8.1-kill-libtool.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,287 @@ +diff -uNr a/Makefile.am b/Makefile.am +--- a/Makefile.am 2026-05-10 12:46:48 +0000 ++++ b/Makefile.am 2026-05-25 06:03:38 +0000 +@@ -40,9 +40,6 @@ + foreign \ + subdir-objects + +-ACLOCAL_AMFLAGS = -I m4 +-LIBTOOLFLAGS = --verbose +- + SUBDIRS = lib # lib goes first to build first + if WITH_EXAMPLES + SUBDIRS += examples +diff -uNr a/acinclude.m4 b/acinclude.m4 +--- a/acinclude.m4 2026-02-22 16:06:00 +0000 ++++ b/acinclude.m4 2026-05-25 05:47:33 +0000 +@@ -7,7 +7,6 @@ + m4_include(conftools/ax-append-flag.m4) + m4_include(conftools/ax-append-compile-flags.m4) + m4_include(conftools/ax-append-link-flags.m4) +-m4_include(conftools/expatcfg-compiler-supports-visibility.m4) + m4_include(conftools/ax-cxx-compile-stdcxx.m4) + m4_include(conftools/ax-cxx-compile-stdcxx-11.m4) + +diff -uNr a/configure.ac b/configure.ac +--- a/configure.ac 2026-05-10 17:16:35 +0000 ++++ b/configure.ac 2026-05-25 06:17:17 +0000 +@@ -72,7 +72,6 @@ + + AC_CONFIG_SRCDIR([Makefile.in]) + AC_CONFIG_AUX_DIR([conftools]) +-AC_CONFIG_MACRO_DIR([m4]) + AC_CANONICAL_HOST + AM_INIT_AUTOMAKE + AM_MAINTAINER_MODE([enable]) # to allow argument --disable-maintainer-mode +@@ -101,9 +100,8 @@ + AM_PROG_AR + AC_PROG_INSTALL + AC_PROG_MAKE_SET +- +-LT_PREREQ([2.4]) +-LT_INIT([win32-dll]) ++AC_PROG_RANLIB ++AC_PROG_FGREP + + AC_SUBST(LIBCURRENT) + AC_SUBST(LIBREVISION) +@@ -143,28 +141,6 @@ + AS_IF([test "$GCC" = yes], + [AX_APPEND_LINK_FLAGS([-Wstrict-aliasing=3],[AM_LDFLAGS])]) + +-AC_ARG_ENABLE([symbol-versioning], +- [AS_HELP_STRING([--enable-symbol-versioning], +- [provide symbol versioning for dependency generation @<:@default=no@:>@])], +- [enable_symbol_versioning=$enableval], +- [enable_symbol_versioning=no]) +-AS_IF([test "x$enable_symbol_versioning" != xno], +- [VSCRIPT_LDFLAGS="-Wl,--version-script" +- AC_SUBST([VSCRIPT_LDFLAGS]) +- ]) +-AM_CONDITIONAL([HAVE_VSCRIPT], +- [test "x$enable_symbol_versioning" != xno]) +- +-dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang (issue #312) +-AS_CASE(["$LD"],[*clang*], +- [AS_CASE(["${host_os}"], +- [*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])]) +- +-EXPATCFG_COMPILER_SUPPORTS_VISIBILITY([ +- AX_APPEND_FLAG([-fvisibility=hidden], [AM_CFLAGS]) +- AS_IF([test "${enable_shared}" = yes], +- [AX_APPEND_FLAG([-DXML_ENABLE_VISIBILITY=1], [AM_CPPFLAGS])])]) +- + dnl Checks for typedefs, structures, and compiler characteristics. + + dnl We define BYTEORDER to 1234 when the platform is little endian; it +@@ -215,8 +191,6 @@ + AM_CONDITIONAL([_INTERNAL_MIN_SIZE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_MIN_SIZE >/dev/null]) + AM_CONDITIONAL([_INTERNAL_LARGE_SIZE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_LARGE_SIZE >/dev/null]) + +-LT_LIB_M +- + AC_ARG_WITH([arc4random], + [AS_HELP_STRING([--with-arc4random], + [enforce the use of arc4random function in the system @<:@default=check@:>@]) +@@ -377,6 +351,10 @@ + + AM_CONDITIONAL([WITH_EITHER_GETRANDOM], [test x${have_either_getrandom} = xtrue]) + ++dnl previously done by libtool; not really tested so far as musl doesn't need libm, but @LIBM@ needs to be defined ++AC_CHECK_LIB(m, cos, LIBM=-lm) ++AC_SUBST([LIBM]) ++ + dnl Only needed for xmlwf: + AC_CHECK_HEADERS(fcntl.h unistd.h) + AC_TYPE_OFF_T +@@ -522,14 +500,6 @@ + AC_SUBST([AM_CXXFLAGS]) + AC_SUBST([AM_LDFLAGS]) + +-dnl Emulate the use of CMAKE_SHARED_LIBRARY_PREFIX under CMake +-AC_MSG_CHECKING([for shared library name prefix]) +-AS_CASE("${host_os}", +- [cygwin*], [CMAKE_SHARED_LIBRARY_PREFIX=cyg], +- [CMAKE_SHARED_LIBRARY_PREFIX=lib]) +-AC_MSG_RESULT([${CMAKE_SHARED_LIBRARY_PREFIX}]) +-AC_SUBST([CMAKE_SHARED_LIBRARY_PREFIX]) +- + AS_CASE("${host_os}", + [darwin*], [ + CMAKE_SOURCE=cmake/autotools/expat__macos.cmake.in +diff -uNr a/conftools/expatcfg-compiler-supports-visibility.m4 b/conftools/expatcfg-compiler-supports-visibility.m4 +--- a/conftools/expatcfg-compiler-supports-visibility.m4 2026-02-22 16:06:00 +0000 ++++ b/conftools/expatcfg-compiler-supports-visibility.m4 1970-01-01 00:00:00 +0000 +@@ -1,39 +0,0 @@ +-# expatcfg-compiler-supports-visibility.m4 -- +-# +-# SYNOPSIS +-# +-# EXPATCFG_COMPILER_SUPPORTS_VISIBILITY([ACTION-IF-YES], +-# [ACTION-IF-NO]) +-# +-# DESCRIPTION +-# +-# Check if the selected compiler supports the "visibility" attribute +-# and set the variable "expatcfg_cv_compiler_supports_visibility" +-# accordingly to "yes" or "no". +-# +-# In addition, execute ACTION-IF-YES or ACTION-IF-NO. +-# +-# LICENSE +-# +-# Copyright (c) 2018 The Expat Authors. +-# +-# Copying and distribution of this file, with or without modification, +-# are permitted in any medium without royalty provided the copyright +-# notice and this notice are preserved. This file is offered as-is, +-# without any warranty. +- +-AC_DEFUN([EXPATCFG_COMPILER_SUPPORTS_VISIBILITY], +- [AC_CACHE_CHECK([whether compiler supports visibility], +- [expatcfg_cv_compiler_supports_visibility], +- [AS_VAR_SET([expatcfg_cv_compiler_supports_visibility],[no]) +- AS_VAR_COPY([OLDFLAGS],[CFLAGS]) +- AS_VAR_APPEND([CFLAGS],[" -fvisibility=hidden -Wall -Werror -Wno-unknown-warning-option"]) +- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +- void __attribute__((visibility("default"))) foo(void); +- void foo(void) {} +- ]])], +- [AS_VAR_SET([expatcfg_cv_compiler_supports_visibility],[yes])]) +- AS_VAR_COPY([CFLAGS],[OLDFLAGS])]) +- AS_IF([test "$expatcfg_cv_compiler_supports_visibility" = yes],[$1],[$2])]) +- +-# end of file +diff -uNr a/examples/Makefile.am b/examples/Makefile.am +--- a/examples/Makefile.am 2026-05-10 12:46:49 +0000 ++++ b/examples/Makefile.am 2026-05-25 05:47:33 +0000 +@@ -34,10 +34,10 @@ + noinst_PROGRAMS = element_declarations elements outline + + element_declarations_SOURCES = element_declarations.c +-element_declarations_LDADD = ../lib/libexpat.la ++element_declarations_LDADD = ../lib/libexpat.a + + elements_SOURCES = elements.c +-elements_LDADD = ../lib/libexpat.la ++elements_LDADD = ../lib/libexpat.a + + outline_SOURCES = outline.c +-outline_LDADD = ../lib/libexpat.la ++outline_LDADD = ../lib/libexpat.a +diff -uNr a/lib/Makefile.am b/lib/Makefile.am +--- a/lib/Makefile.am 2026-05-10 12:46:49 +0000 ++++ b/lib/Makefile.am 2026-05-25 05:47:33 +0000 +@@ -36,65 +36,56 @@ + expat.h \ + expat_external.h + +-lib_LTLIBRARIES = libexpat.la ++lib_LIBRARIES = libexpat.a + if WITH_TESTS +-noinst_LTLIBRARIES = libtestpat.la ++noinst_LIBRARIES = libtestpat.a + endif + +-libexpat_la_LDFLAGS = \ +- @AM_LDFLAGS@ \ +- @LIBM@ \ +- -no-undefined \ +- -version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@ +-if HAVE_VSCRIPT +-libexpat_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@builddir@/libexpat.map +-endif +- +-libexpat_la_SOURCES = \ ++libexpat_a_SOURCES = \ + xmlparse.c \ + xmltok.c \ + xmlrole.c + + if WITH_ARC4RANDOM +- libexpat_la_SOURCES += \ ++ libexpat_a_SOURCES += \ + random_arc4random.c \ + random_arc4random.h + endif + + if WITH_ARC4RANDOM_BUF +- libexpat_la_SOURCES += \ ++ libexpat_a_SOURCES += \ + random_arc4random_buf.c \ + random_arc4random_buf.h + endif + + if ! MINGW +- libexpat_la_SOURCES += \ ++ libexpat_a_SOURCES += \ + random_dev_urandom.c \ + random_dev_urandom.h + endif + + if WITH_GETENTROPY +- libexpat_la_SOURCES += \ ++ libexpat_a_SOURCES += \ + random_getentropy.c \ + random_getentropy.h + endif + + if WITH_EITHER_GETRANDOM +- libexpat_la_SOURCES += \ ++ libexpat_a_SOURCES += \ + random_getrandom.c \ + random_getrandom.h + endif + + if MINGW +- libexpat_la_SOURCES += \ ++ libexpat_a_SOURCES += \ + random_rand_s.c \ + random_rand_s.h + endif + + if WITH_TESTS +-libtestpat_la_CPPFLAGS = -DXML_TESTING ++libtestpat_a_CPPFLAGS = -DXML_TESTING + +-libtestpat_la_SOURCES = $(libexpat_la_SOURCES) ++libtestpat_a_SOURCES = $(libexpat_a_SOURCES) + endif + + doc_DATA = \ +diff -uNr a/tests/Makefile.am b/tests/Makefile.am +--- a/tests/Makefile.am 2026-05-10 12:46:51 +0000 ++++ b/tests/Makefile.am 2026-05-25 05:47:33 +0000 +@@ -57,7 +57,7 @@ + runtests.c \ + structdata.c + +-runtests_LDADD = ../lib/libtestpat.la ++runtests_LDADD = ../lib/libtestpat.a + + runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@ + +diff -uNr a/tests/benchmark/Makefile.am b/tests/benchmark/Makefile.am +--- a/tests/benchmark/Makefile.am 2026-05-10 12:46:52 +0000 ++++ b/tests/benchmark/Makefile.am 2026-05-25 05:47:33 +0000 +@@ -35,7 +35,7 @@ + + benchmark_SOURCES = benchmark.c + +-benchmark_LDADD = ../../lib/libexpat.la ++benchmark_LDADD = ../../lib/libexpat.a + + EXTRA_DIST = \ + README.txt +diff -uNr a/xmlwf/Makefile.am b/xmlwf/Makefile.am +--- a/xmlwf/Makefile.am 2026-05-10 12:46:54 +0000 ++++ b/xmlwf/Makefile.am 2026-05-25 05:47:33 +0000 +@@ -30,7 +30,7 @@ + + bin_PROGRAMS = xmlwf + +-xmlwf_LDADD = ../lib/libexpat.la ++xmlwf_LDADD = ../lib/libexpat.a + xmlwf_SOURCES = \ + xmlwf.c \ + xmlfile.c \ diff -uNr a/gports/expat/expat-2.8.1-standard-shell.patch b/gports/expat/expat-2.8.1-standard-shell.patch --- a/gports/expat/expat-2.8.1-standard-shell.patch 1970-01-01 00:00:00 +0000 +++ b/gports/expat/expat-2.8.1-standard-shell.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,204 @@ +Switch to standard /bin/sh, handling some of the trickier bashisms by dropping Windows test support wrappers. + -jfw + +diff -uNr a/Makefile.am b/Makefile.am +--- a/Makefile.am 2026-05-25 06:34:51 +0000 ++++ b/Makefile.am 2026-05-25 06:42:04 +0000 +@@ -103,10 +103,7 @@ + \ + buildconf.sh \ + Changes \ +- README.md \ +- \ +- fix-xmltest-log.sh \ +- test-driver-wrapper.sh ++ README.md + + + .PHONY: buildlib +@@ -165,8 +162,7 @@ + [ -d $(builddir)/tests/xmlconf ] || $(MAKE) extract-xmlts-zip # vpath workaround + $(MAKE) -C lib + $(MAKE) -C xmlwf +- $(srcdir)/tests/xmltest.sh "$(abs_builddir)/run.sh $(abs_builddir)/xmlwf/xmlwf@EXEEXT@" 2>&1 | tee $(builddir)/tests/xmltest.log +- $(srcdir)/fix-xmltest-log.sh $(builddir)/tests/xmltest.log ++ $(srcdir)/tests/xmltest.sh "$(abs_builddir)/xmlwf/xmlwf" 2>&1 | tee $(builddir)/tests/xmltest.log + diff -u $(srcdir)/tests/xmltest.log.expected $(builddir)/tests/xmltest.log + else + @echo 'ERROR: xmlwf is needed for "make run-xmltest".' >&2 +diff -uNr a/buildconf.sh b/buildconf.sh +--- a/buildconf.sh 2026-05-10 12:46:48 +0000 ++++ b/buildconf.sh 2026-05-25 06:52:06 +0000 +@@ -1,4 +1,4 @@ +-#! /usr/bin/env bash ++#!/bin/sh + # __ __ _ + # ___\ \/ /_ __ __ _| |_ + # / _ \\ /| '_ \ / _` | __| +diff -uNr a/configure.ac b/configure.ac +--- a/configure.ac 2026-05-25 06:34:51 +0000 ++++ b/configure.ac 2026-05-25 06:44:05 +0000 +@@ -526,7 +526,6 @@ + [tests/Makefile] + [tests/benchmark/Makefile] + [xmlwf/Makefile]) +-AC_CONFIG_FILES([run.sh], [chmod +x run.sh]) + AC_OUTPUT + + +diff -uNr a/run.sh.in b/run.sh.in +--- a/run.sh.in 2026-05-10 12:46:51 +0000 ++++ b/run.sh.in 1970-01-01 00:00:00 +0000 +@@ -1,47 +0,0 @@ +-#! /usr/bin/env bash +-# __ __ _ +-# ___\ \/ /_ __ __ _| |_ +-# / _ \\ /| '_ \ / _` | __| +-# | __// \| |_) | (_| | |_ +-# \___/_/\_\ .__/ \__,_|\__| +-# |_| XML parser +-# +-# Copyright (c) 2017-2022 Sebastian Pipping +-# Licensed under the MIT license: +-# +-# Permission is hereby granted, free of charge, to any person obtaining +-# a copy of this software and associated documentation files (the +-# "Software"), to deal in the Software without restriction, including +-# without limitation the rights to use, copy, modify, merge, publish, +-# distribute, sublicense, and/or sell copies of the Software, and to permit +-# persons to whom the Software is furnished to do so, subject to the +-# following conditions: +-# +-# The above copyright notice and this permission notice shall be included +-# in all copies or substantial portions of the Software. +-# +-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +-# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +-# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +-# USE OR OTHER DEALINGS IN THE SOFTWARE. +- +-case "@host@" in +-*-mingw*) +- case "$(uname -o)" in +- Cygwin|Msys) +- # Windows binary on Windows host +- exec "$@" +- ;; +- *) +- # Windows binary on non-Windows host +- exec wine "$@" +- ;; +- esac +- ;; +-*) +- exec "$@" +- ;; +-esac +diff -uNr a/test-driver-wrapper.sh b/test-driver-wrapper.sh +--- a/test-driver-wrapper.sh 2026-05-10 12:46:51 +0000 ++++ b/test-driver-wrapper.sh 1970-01-01 00:00:00 +0000 +@@ -1,44 +0,0 @@ +-#! /usr/bin/env bash +-# __ __ _ +-# ___\ \/ /_ __ __ _| |_ +-# / _ \\ /| '_ \ / _` | __| +-# | __// \| |_) | (_| | |_ +-# \___/_/\_\ .__/ \__,_|\__| +-# |_| XML parser +-# +-# Copyright (c) 2017 Sebastian Pipping +-# Copyright (c) 2019 Jeffrey Walton +-# Licensed under the MIT license: +-# +-# Permission is hereby granted, free of charge, to any person obtaining +-# a copy of this software and associated documentation files (the +-# "Software"), to deal in the Software without restriction, including +-# without limitation the rights to use, copy, modify, merge, publish, +-# distribute, sublicense, and/or sell copies of the Software, and to permit +-# persons to whom the Software is furnished to do so, subject to the +-# following conditions: +-# +-# The above copyright notice and this permission notice shall be included +-# in all copies or substantial portions of the Software. +-# +-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +-# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +-# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +-# USE OR OTHER DEALINGS IN THE SOFTWARE. +- +-set -e +-top_srcdir="$(dirname "$(type -p "$0")")" +-top_builddir=.. +- +-# Suck up all dash-dash test-driver arguments +-test_driver_args=() +-while [[ ${1} != '--' ]]; do +- test_driver_args=( "${test_driver_args[@]}" "${1}" ) +- shift +-done +-shift # drop "--" +- +-exec "${top_srcdir}"/conftools/test-driver "${test_driver_args[@]}" "${top_builddir}"/run.sh "$@" +diff -uNr a/tests/Makefile.am b/tests/Makefile.am +--- a/tests/Makefile.am 2026-05-25 06:34:51 +0000 ++++ b/tests/Makefile.am 2026-05-25 06:39:04 +0000 +@@ -38,9 +38,6 @@ + check_PROGRAMS = runtests + TESTS = runtests + +-# To support MinGW and Non-MinGW at the same time: +-LOG_DRIVER = $(srcdir)/../test-driver-wrapper.sh +- + runtests_SOURCES = \ + acc_tests.c \ + alloc_tests.c \ +diff -uNr a/tests/xmltest.sh b/tests/xmltest.sh +--- a/tests/xmltest.sh 2026-05-10 12:46:54 +0000 ++++ b/tests/xmltest.sh 2026-05-25 06:51:32 +0000 +@@ -1,4 +1,4 @@ +-#! /usr/bin/env bash ++#!/bin/sh + # EXPAT TEST SCRIPT FOR W3C XML TEST SUITE + # + # This script can be used to exercise Expat against the +@@ -52,8 +52,6 @@ + # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + # USE OR OTHER DEALINGS IN THE SOFTWARE. + +-shopt -s nullglob +- + # Note: OUTPUT must terminate with the directory separator. + OUTPUT="$PWD/tests/out/" + TS="$PWD/tests/" +@@ -130,7 +128,7 @@ + cd "$TS/xmlconf/$xmldir" + mkdir -p "$OUTPUT$xmldir" + for xmlfile in $(ls -1 *.xml | sort -d) ; do +- [[ -f "$xmlfile" ]] || continue ++ [ -f "$xmlfile" ] || continue + RunXmlwfWF "$xmlfile" "$xmldir/" + UpdateStatus $? + done +@@ -159,6 +157,7 @@ + sun/not-wf ; do + cd "$TS/xmlconf/$xmldir" + for xmlfile in *.xml ; do ++ [ "$xmlfile" = '*.xml' ] && continue + RunXmlwfNotWF "$xmlfile" "$xmldir/" + UpdateStatus $? + done +diff -uNr a/xmlwf/xmlwf_helpgen.sh b/xmlwf/xmlwf_helpgen.sh +--- a/xmlwf/xmlwf_helpgen.sh 2026-05-10 12:46:55 +0000 ++++ b/xmlwf/xmlwf_helpgen.sh 2026-05-25 06:52:28 +0000 +@@ -1,4 +1,4 @@ +-#! /usr/bin/env bash ++#!/bin/sh + # __ __ _ + # ___\ \/ /_ __ __ _| |_ + # / _ \\ /| '_ \ / _` | __| diff -uNr a/gports/expat/expat-2.8.1-xxe-hardening.patch b/gports/expat/expat-2.8.1-xxe-hardening.patch --- a/gports/expat/expat-2.8.1-xxe-hardening.patch 1970-01-01 00:00:00 +0000 +++ b/gports/expat/expat-2.8.1-xxe-hardening.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,152 @@ +diff -ur a/lib/expat.h b/lib/expat.h +--- a/lib/expat.h 2026-05-26 06:48:31 +0000 ++++ b/lib/expat.h 2026-05-26 07:03:20 +0000 +@@ -565,8 +565,9 @@ + XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + ++/* Renamed to _hazmat as Gales audit for insecure use. */ + XMLPARSEAPI(void) +-XML_SetProcessingInstructionHandler(XML_Parser parser, ++XML_SetProcessingInstructionHandler_hazmat(XML_Parser parser, + XML_ProcessingInstructionHandler handler); + XMLPARSEAPI(void) + XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler); +@@ -633,8 +634,9 @@ + XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + ++/* Renamed to _hazmat as Gales audit for insecure use. */ + XMLPARSEAPI(void) +-XML_SetExternalEntityRefHandler(XML_Parser parser, ++XML_SetExternalEntityRefHandler_hazmat(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + + /* If a non-NULL value for arg is specified here, then it will be +@@ -874,9 +876,10 @@ + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. ++ Renamed to _hazmat as Gales audit for insecure use. + */ + XMLPARSEAPI(XML_Parser) +-XML_ExternalEntityParserCreate(XML_Parser parser, const XML_Char *context, ++XML_ExternalEntityParserCreate_hazmat(XML_Parser parser, const XML_Char *context, + const XML_Char *encoding); + + enum XML_ParamEntityParsing { +diff -ur a/lib/xmlparse.c b/lib/xmlparse.c +--- a/lib/xmlparse.c 2026-05-26 06:48:31 +0000 ++++ b/lib/xmlparse.c 2026-05-26 06:58:29 +0000 +@@ -1616,7 +1616,7 @@ + } + + XML_Parser XMLCALL +-XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, ++XML_ExternalEntityParserCreate_hazmat(XML_Parser oldParser, const XML_Char *context, + const XML_Char *encodingName) { + XML_Parser parser = oldParser; + DTD *newDtd = NULL; +@@ -2015,7 +2015,7 @@ + } + + void XMLCALL +-XML_SetProcessingInstructionHandler(XML_Parser parser, ++XML_SetProcessingInstructionHandler_hazmat(XML_Parser parser, + XML_ProcessingInstructionHandler handler) { + if (parser != NULL) + parser->m_processingInstructionHandler = handler; +@@ -2134,7 +2134,7 @@ + } + + void XMLCALL +-XML_SetExternalEntityRefHandler(XML_Parser parser, ++XML_SetExternalEntityRefHandler_hazmat(XML_Parser parser, + XML_ExternalEntityRefHandler handler) { + if (parser != NULL) + parser->m_externalEntityRefHandler = handler; +diff -ur a/tests/common.h b/tests/common.h +--- a/tests/common.h 2026-05-10 12:46:52 +0000 ++++ b/tests/common.h 2026-05-26 07:21:43 +0000 +@@ -148,6 +148,11 @@ + + extern char *portable_strndup(const char *s, size_t n); + ++/* API renames for XXE auditing */ ++#define XML_ExternalEntityParserCreate XML_ExternalEntityParserCreate_hazmat ++#define XML_SetExternalEntityRefHandler XML_SetExternalEntityRefHandler_hazmat ++#define XML_SetProcessingInstructionHandler XML_SetProcessingInstructionHandler_hazmat ++ + #endif /* XML_COMMON_H */ + + #ifdef __cplusplus +diff -ur a/xmlwf/xmlfile.c b/xmlwf/xmlfile.c +--- a/xmlwf/xmlfile.c 2026-05-10 17:16:35 +0000 ++++ b/xmlwf/xmlfile.c 2026-05-26 07:13:22 +0000 +@@ -161,7 +161,7 @@ + int result; + XML_Char *s; + const XML_Char *filename; +- XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); ++ XML_Parser entParser = XML_ExternalEntityParserCreate_hazmat(parser, context, 0); + int filemapRes; + PROCESS_ARGS args; + UNUSED_P(publicId); +@@ -238,7 +238,7 @@ + XML_Char *s; + const XML_Char *filename; + int ret; +- XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); ++ XML_Parser entParser = XML_ExternalEntityParserCreate_hazmat(parser, context, 0); + UNUSED_P(publicId); + filename = resolveSystemId(base, systemId, &s); + XML_SetBase(entParser, filename); +@@ -258,7 +258,7 @@ + } + + if (flags & XML_EXTERNAL_ENTITIES) +- XML_SetExternalEntityRefHandler(parser, (flags & XML_MAP_FILE) ++ XML_SetExternalEntityRefHandler_hazmat(parser, (flags & XML_MAP_FILE) + ? externalEntityRefFilemap + : externalEntityRefStream); + if (flags & XML_MAP_FILE) { +diff -ur a/xmlwf/xmlwf.c b/xmlwf/xmlwf.c +--- a/xmlwf/xmlwf.c 2026-05-10 17:16:35 +0000 ++++ b/xmlwf/xmlwf.c 2026-05-26 07:11:09 +0000 +@@ -1214,7 +1214,7 @@ + outputDir = 0; + XML_SetElementHandler(parser, nopStartElement, nopEndElement); + XML_SetCharacterDataHandler(parser, nopCharacterData); +- XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction); ++ XML_SetProcessingInstructionHandler_hazmat(parser, nopProcessingInstruction); + } else if (outputDir) { + const XML_Char *delim = T("/"); + const XML_Char *file = useStdin ? T("STDIN") : argv[i]; +@@ -1264,7 +1264,7 @@ + case 'm': + XML_UseParserAsHandlerArg(parser); + XML_SetElementHandler(parser, metaStartElement, metaEndElement); +- XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction); ++ XML_SetProcessingInstructionHandler_hazmat(parser, metaProcessingInstruction); + XML_SetCommentHandler(parser, metaComment); + XML_SetCdataSectionHandler(parser, metaStartCdataSection, + metaEndCdataSection); +@@ -1282,8 +1282,7 @@ + XML_SetDefaultHandler(parser, markup); + XML_SetElementHandler(parser, defaultStartElement, defaultEndElement); + XML_SetCharacterDataHandler(parser, defaultCharacterData); +- XML_SetProcessingInstructionHandler(parser, +- defaultProcessingInstruction); ++ XML_SetProcessingInstructionHandler_hazmat(parser, defaultProcessingInstruction); + break; + default: + if (useNamespaces) +@@ -1292,7 +1291,7 @@ + XML_SetElementHandler(parser, startElement, endElement); + XML_SetCharacterDataHandler(parser, characterData); + #ifndef W3C14N +- XML_SetProcessingInstructionHandler(parser, processingInstruction); ++ XML_SetProcessingInstructionHandler_hazmat(parser, processingInstruction); + if (requiresNotations) { + XML_SetDoctypeDeclHandler(parser, startDoctypeDecl, endDoctypeDecl); + XML_SetNotationDeclHandler(parser, notationDecl); diff -uNr a/gports/gales-util/gbuild-run.sh b/gports/gales-util/gbuild-run.sh --- a/gports/gales-util/gbuild-run.sh 1970-01-01 00:00:00 +0000 +++ b/gports/gales-util/gbuild-run.sh 1970-01-01 00:00:00 +0000 @@ -8,7 +8,7 @@ COMPRESS="gzip -n" PKG_EXT=.sh.gz GBUILD_CONF=${GBUILD_CONF:-/etc/gbuild.conf} -[ -f "$GBUILD_CONF" ] && . "$GBUILD_CONF" +if [ -f "$GBUILD_CONF" ]; then . "$GBUILD_CONF"; fi pkg=$P-$MAJOR.$MINOR-$V$PKG_EXT die () { diff -uNr a/gports/gales-util/gbuild-sub.sh b/gports/gales-util/gbuild-sub.sh --- a/gports/gales-util/gbuild-sub.sh 1970-01-01 00:00:00 +0000 +++ b/gports/gales-util/gbuild-sub.sh 1970-01-01 00:00:00 +0000 @@ -13,7 +13,8 @@ Q=$P-$MAJOR.$MINOR-$V JOBS=1 CHECK_LEVEL=1 -if [ -f /etc/gbuild.conf ]; then . /etc/gbuild.conf; fi +GBUILD_CONF=${GBUILD_CONF:-/etc/gbuild.conf} +if [ -f "$GBUILD_CONF" ]; then . "$GBUILD_CONF"; fi case "$1" in package) . ./ar.sh; package ;; diff -uNr a/gports/httpd/README.gales b/gports/httpd/README.gales --- a/gports/httpd/README.gales 1970-01-01 00:00:00 +0000 +++ b/gports/httpd/README.gales 1970-01-01 00:00:00 +0000 @@ -17,7 +17,7 @@ This port uses the "worker" Multi-Processing Module, as a middle-of-the-road choice which offers less overhead per connection than the traditional "prefork" due to multithreading, but still spares the added complexities of "event", which despite its name is still fundamentally based on worker threads, not a fully async model. A different MPM can be selected, or other modules added or removed, by editing the ./configure options in the port's build.sh. -PHP is supported via FastCGI gateway and is not linked directly into the server executable as with mod_php. +PHP is supported via FastCGI (persistent external process group) or plain CGI (subprocess per request) and is not linked directly into the server executable as with mod_php; see the php port for details. In addition to the concise Gales config provided in /etc/examples/httpd, other references on how to configure your server are found under /gales/doc/httpd/ and include: diff -uNr a/gports/httpd/build.sh b/gports/httpd/build.sh --- a/gports/httpd/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/httpd/build.sh 1970-01-01 00:00:00 +0000 @@ -1,7 +1,7 @@ P=httpd V=2.4.65 MAJOR=0 -MINOR=0 +MINOR=1 # Build requires: autoconf libressl libtool pcre (Gales package version >=0.1) python (for apr's buildconf) # Suggested: perl (for dbmmanage script) links (for apachectl status) @@ -177,7 +177,7 @@ --disable-negotiation \ --enable-dir \ --disable-imagemap \ - --disable-actions \ + --enable-actions \ --disable-speling \ --disable-userdir \ --enable-alias \ diff -uNr a/gports/httpd/httpd.conf b/gports/httpd/httpd.conf --- a/gports/httpd/httpd.conf 1970-01-01 00:00:00 +0000 +++ b/gports/httpd/httpd.conf 1970-01-01 00:00:00 +0000 @@ -13,9 +13,6 @@ # Block "httpoxy" attacks by not passing bogus "Proxy:" request headers into the CGI environment as HTTP_PROXY RequestHeader unset Proxy early -# Favor generic FastCGI backends over PHP-FPM; the latter reportedly follows historical quirks and expects a "proxy:fcgi://..." SCRIPT_FILENAME prefix, which breaks the plain old php-cgi -ProxyFCGIBackendType GENERIC - # Major access log fields (see the mod_log_config manual for all options): # %t - time at beginning of request # %a - remote IP address @@ -29,10 +26,17 @@ # Multilog script: no extra timestamps, rotate at 16MB (the max), keeping 10 files in the given directory. (Ensure /var/log/httpd is writable by log user for automatic subdir creation.) CustomLog "|/command/setuidgid log multilog s16777216 n10 /var/log/httpd/access" fancy +# The mime.types database tries to determine what a file is, based on historical extension usage. This works well for known binary and web-centric formats, but does not always elicit satisfactory browser behavior, as some plain-text formats are listed under "application/" and thus pop up for download rather than simply displaying. So here we override known text formats in that category to display as text. +AddType text/plain asc scm csh sh sql tcl tex texinfo texi +# That leaves files with unknown extensions or none at all. Apache 2.4 removed the DefaultType setting; this might make sense from a very academic standpoint, "we have no information so don't make it up, leave it to the browser", but in practice, predictable behavior matters. The workaround is to add a Content-Type header if none was previously determined. +Header set Content-Type text/plain "expr=-z %{CONTENT_TYPE}" +# Browsers may still "helpfully" override server-indicated Content-Type by sniffing, at least for generic types like text/plain and application/octet-stream, which opens the door to parsing arbitrary files as HTML and thus script injection. +Header set X-Content-Type-Options nosniff +# Allow direct display of compressed svg files. +AddEncoding gzip .svgz + DirectoryIndex index.html IndexOptions FancyIndexing HTMLTable NameWidth=* IgnoreClient SuppressIcon SuppressDescription -# Allow browsers to display compressed svg files directly -AddEncoding gzip .svgz # Default Deny @@ -47,20 +51,20 @@ Require all denied +# Turn this on if you want to intercept HTTP error codes from backends for redisplay with the usual Apache mechanisms, such as custom error pages (nice for 404 and 500 errors from PHP) +ProxyErrorOverride Off +# Favor generic FastCGI backends over PHP-FPM; the latter reportedly follows historical quirks and expects a "proxy:fcgi://..." SCRIPT_FILENAME prefix, which breaks the plain old php-cgi +ProxyFCGIBackendType GENERIC + # Example to run PHP scripts by passing to the php gport's default FCGI service -# Omit the If/Else/Redirect lines if you don't mind nonexistent files returning a generic 500 "Failed to open primary script" rather than 404 "Not Found" error page #DirectoryIndex index.php # -# -# SetHandler "proxy:unix:/var/run/php-fastcgi/sock|fcgi://localhost" -# -# -# Redirect 404 -# +# SetHandler "proxy:unix:/var/run/php-fastcgi/sock|fcgi://localhost" # # Top-level settings when no VirtualHost matches ServerName localhost +# This builtin document root is provided as a convenient fallback. It's not advisable to use it as-is for your own data because it's considered part of the package, subject to clobbering and won't automatically transfer over on update. If you don't need virtual hosts, simply change the paths to point to your own document root outside the /gales tree. DocumentRoot /gales/pkg/httpd/htdocs Require all granted @@ -76,7 +80,7 @@ # # ServerName example.com # DocumentRoot /srv/example -# CustomLog "|/command/setuidgid multilog multilog s16777216 n10 /var/log/httpd/example" fancy +# CustomLog "|/command/setuidgid log multilog s16777216 n10 /var/log/httpd/example" fancy # # Require all granted # diff -uNr a/gports/pcre/Makefile b/gports/pcre/Makefile --- a/gports/pcre/Makefile 1970-01-01 00:00:00 +0000 +++ b/gports/pcre/Makefile 1970-01-01 00:00:00 +0000 @@ -44,11 +44,13 @@ pcretest.o: pcretest.c $(CC) $(CFLAGS) $(CPPFLAGS) -DNOPOSIX -c -o $@ $^ -pcretest: pcretest.o pcre_printint.o libpcre.a +PCRETEST_OBJS = pcretest.o pcre_printint.o + +pcretest: $(PCRETEST_OBJS) libpcre.a $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) check: pcretest ./RunTest clean: - rm -f libpcre.a pcretest dftables pcre_chartables.c $(PCRE8_OBJS) + rm -f dftables dftables.o pcre_chartables.c $(PCRE8_OBJS) libpcre.a $(PCRETEST_OBJS) pcretest diff -uNr a/gports/pcre/build.sh b/gports/pcre/build.sh --- a/gports/pcre/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/pcre/build.sh 1970-01-01 00:00:00 +0000 @@ -1,9 +1,10 @@ P=pcre V=8.45 MAJOR=0 -MINOR=1 +MINOR=2 -# So far we try to get away without UTF8 decoding, Unicode character properties, 16- or 32-bit character support, POSIX regex API wrappers, C++ wrappers, or the user programs (pcregrep pcretest). +# So far we try to get away without 16- or 32-bit character support, POSIX regex API wrappers, C++ wrappers, or the user programs (pcregrep pcretest). +# UTF8 decoding and Unicode character properties seem pretty much required by PHP world, but we at least contain the bloat to a separate, opt-in build of the library. S=" $P-$V.tar.bz2 @@ -29,12 +30,39 @@ -e "s,@PACKAGE_VERSION@,$V,g" \ -e "s,@prefix@,/gales/pkg/$Q,g" \ pcre-config.in >pcre-config + + # Lop a couple bad test cases that assume utf8 support implies pcreposix + sed -i 's,/P8$,/8,' testdata/testinput15 testdata/testoutput15 + sed -i 's,/P$,/,; s,/WP$,/W,' testdata/testinput16 testdata/testoutput16 + sed -i 's,: POSIX code .*,,' testdata/testoutput16 + + echo 'Building plain version...' + make -j$JOBS + mv libpcre.a libpcre_plain.a + mv pcretest pcretest_plain + make clean + + echo + echo 'Building unicode-encumbered version...' + echo '#define SUPPORT_UCP 1' >> config.h + echo '#define SUPPORT_UTF 1' >> config.h make -j$JOBS + mv libpcre.a libpcre_unicode.a + mv pcretest pcretest_unicode } check () { cd $P-$V - make check + echo 'Testing plain version...' + ln pcretest_plain pcretest + ./RunTest + rm pcretest + + echo + echo 'Testing unicode-encumbered version...' + ln pcretest_unicode pcretest + ./RunTest + rm pcretest } package () { @@ -46,7 +74,8 @@ f gales/pkg/$Q/doc/README x gales/pkg/$Q/bin/pcre-config f gales/pkg/$Q/include/pcre.h - F gales/pkg/$Q/lib/libpcre.a + F gales/pkg/$Q/lib/libpcre.a libpcre_plain.a + F gales/pkg/$Q/lib/libpcre_unicode.a cd doc for f in *.3 ; do f gales/pkg/$Q/man/man3/$f diff -uNr a/gports/php56/NEWS.gales b/gports/php56/NEWS.gales --- a/gports/php56/NEWS.gales 1970-01-01 00:00:00 +0000 +++ b/gports/php56/NEWS.gales 1970-01-01 00:00:00 +0000 @@ -0,0 +1,118 @@ +2026-08-10: Gales package 506.4 + +This release adds the hard dependencies for running Wordpress while cutting through test suite noise, including all failures resulting from prior changes and some more besides, clarifying the readiness of iconv for replacing mbstring functions. + +Packaging: + + - Enabled xml extension using libexpat backend (does not include xmlreader, xmlwriter, simplexml, or dom extensions). + - Enabled legacy mysql interface (mysqli wasn't enough for Wordpress). + - Switched to pcre_unicode.a in updated pcre gport, restoring /u suffix for preg_* functions. + - Added run-tests.sh script to run the test suite from a fixed environment, preventing breakage that resulted from importing the system's global php.ini. + +ext/iconv: + + - Suppressed tests assuming GNU extensions (//IGNORE, //TRANSLIT) or behavioral details (default failure on invalid input bytes, compacted output for ISO-2022-JP). Either added a skip condition or removed the whole test file, as prior monkeys had left many troublesome to edit due to raw non-ASCII garbage in the source. + +ext/reflection: + + - Marked as expected failure a test which had grabbed the poor unrelated xml extension as its subject, locking in libxml2 dependency structure. + +ext/sockets: + + - Fixed tests locking in glibc specific error strings. + - Fixed tests attempting live connections to yahoo.com in order to test sending and shutdown capabilities. + +ext/standard: + + - Fixed test assuming bash-specific behavior ("sh -c" command turning into a direct subprocess without "exec"). + +ext/xml: + + - Propagated renaming of "hazmat" XML functions from expat, as part of Gales audit for insecure use. + - Fixed tests assuming libxml2 specifics and breaking with expat (callback receiving newline, specific error codes and strings, xml_set_end_namespace_decl_handler callback actually working). + +sapi/cli: + + - Fixed tests broken by expose_php default change (no X-Powered-By). + +sapi/cgi: + + - Fixed tests broken by expose_php default change (no X-Powered-By). + - Fixed tests broken by pathinfo changes (the incorrect "No input file specified" is now 404 Not Found). + +2026-05-12: Gales package 506.3 + +This release reflects a deep dive into smooth integration with Apache 2.4 in both FastCGI and plain CGI modes, as part of a production-ready, easy to deploy and secure-by-default LAMP stack for Gales. + +Packaging: + + - Updated README.gales and wrote this NEWS.gales. + - Switched from bundled to system pcre, now that there's a gport. + - Moved example php.ini to the normal place (/etc/examples), dropping the -development variant. + - Secured fastcgi unix socket permissions in the example run script and added some default concurrency. + +sapi/cgi: + + - Removed cgi.fix_pathinfo hack, which dates from PHP 4.3 and created new security pitfalls by duplicating web server functionality. + - Changed cgi.discard_path default to 1 and straightened out its behavior, providing proper PATH_INFO support in FastCGI mode while making crystal clear which file will execute in all cases. See comments on the option in the example php.ini for details. This replaces the 2018 "No input file specified" change and lets the php_fopen_primary_script failure response be a simple 404. + - Fixed security hole and general dysfunction in cgi.force_redirect, a failsafe that applies in plain CGI mode. + +ext/session: + + - Changed session.cookie_httponly default to 1. + +main: + + - Changed expose_php default to 0. + +2024-03-09: Gales package 506.2 + +Packaging: + + - Updated README.gales. + - Adopted new CHECK_LEVEL gbuild feature to deal with broken test suite. + +2022-05-06: Gales package 506.1 + +Packaging: + + - Updated README.gales. + - Enabled sockets extension (socket_* functions). + +2018-03-05: PHP 5.6.34, Gales package 506.0 + +This was the first port to the static musl environment, with a number of patches mostly focused on the build process. It worked with nginx, the web server available at the time in Gales, connected in a FastCGI gateway setup. + +Build system: + + - Removed libtool bloat since we don't want or need shared objects. + - Largely removed shtool; not now recalling what that was but reportedly horrific, possibly a scripting compatibility wrapper for Windows. + - Portability fix for expr usage in aclocal.m4. + - Stopped autodetecting sendmail path, avoiding unwarranted influence by the build environment. + - Disabled broken "scripts" install process (phpize, php-config). + - Stopped overriding the requested datarootdir setting. + +sapi/cgi and sapi/fpm: + + - Quick initial code cleanup, with removal of redundant comment boilerplate and ifdef bloat for Windows and other obscure platforms. + +sapi/cgi: + + - To aid server config troubleshooting, changed false 404 error message "No input file specified" into a 500 "Failed to open primary script" with path logged to stderr. + +main: + + - Standardized and paths and removed select(2) based emulation of poll(2). + - Fixed broken autoconf check of readdir_r type by removing and standardizing. + +sapi/cli/tests: + + - Redirected development server output to fix tests broken by its banner messages. (This fix looks dubious on review.) + +ext/iconv: + + - Fixed segfault in autoconf test by checking for error on iconv_open. + +Zend, ext/standard: + + - Removed broken autoconf checks for standard floating point macros, allowing them to be just macros. diff -uNr a/gports/php56/README.gales b/gports/php56/README.gales --- a/gports/php56/README.gales 1970-01-01 00:00:00 +0000 +++ b/gports/php56/README.gales 1970-01-01 00:00:00 +0000 @@ -1,33 +1,25 @@ PHP on Gales Linux ================== -This is a fully static build. As such, it does not support dynamic module -loading; any C extensions must be linked in at build time. +This is a fully static build. As such, it does not support dynamic module loading; any C extensions must be linked in at build time. -The included binaries are the CLI SAPI "php", which acts as a more-or-less -normal interpreter, and the CGI SAPI "php-cgi", which can act in CGI mode or as -a FastCGI server listening on a TCP or Unix-domain socket. See the man page for -details. +PHP fits itself into different systems through so-called SAPIs. The executables in this build are the command-line interface SAPI "php", which acts as a more-or-less normal script interpreter, and the Common Gateway Interface SAPI "php-cgi", which can act in plain CGI mode or as a FastCGI server listening on a TCP or Unix-domain socket. See the respective man pages for details. + +For connecting to Apache, FastCGI is recommended as the most efficient and feature-complete alternative to in-process mod_php. Because it does not involve sending remote user controlled strings through operating system environment variables, it is likely more robust to attacks on CGI based on the unbounded scope of such variables, such as the famed "shellshock" and "httpoxy". However, it is imperative that the FastCGI listening socket be protected, because anyone able to connect can use the server's credentials to read and execute arbitrary files as PHP. Deliberately omitted components: -- opcache (aka Zend Optimizer): 16K lines -- half a megabyte -- of source, for - benefits that ought to come free with a proper application server; an - unwarranted risk at this time. - -- phar: const incorrectness, probable memory leaks, history of memory bugs per - NEWS. - -- All the XML extensions: require external libxml2 (TODO). - -- PEAR: requires XML; also not sure if it's even useful with static linking, or - hygienic. - -- FPM: copied from fastcgi and even more bloated. Some desirable stuff: - graceful restart and chroot/setuid, along with much suspicious nonsense: - daemonizing, systemd, multiple logging mechanisms but not stderr, ptrace, - defaulting to "nobody" user, AJAX status page, massive example config. +- opcache (aka Zend Optimizer): 16K lines -- half a megabyte -- of source, for suspect benefits; an unwarranted risk at this time. + +- mbstring: 124K lines; not merely a "unicode-aware strlen" but a whole system of character set transcodings (libmbfl) and Asian encoding aware regex engine (oniguruma). Most common uses can be readily replaced with functions from the included libc-based iconv extension. + +- phar: const incorrectness, probable memory leaks, history of memory bugs per NEWS. +- xmlreader, xmlwriter, simplexml, dom: these require the heavyweight libxml2 from GNOME, whereas the basic xml extension (now included) can still use expat. + +- PEAR: requires XML (and since it deals with downloaded extensions, might not be useful with static linking or may have security considerations to address). + +- PHP-FPM (FastCGI process manager): copied from php-cgi and further bloated. The graceful restart feature sounds nice; the chroot/setuid support is weak or even detrimental because workers still share memory through a large master process running as root. Dynamic process management is iffy since the real constraint is available memory which is basically static in a given server (would be useful if it could securely reapportion a total worker count between different users based on momentary demand). Then it brings in much nonsense and suspicious choices: daemonizing, systemd, multiple logging mechanisms but not stderr, ptrace, defaulting to "nobody" user, AJAX status page, massive example config. FastCGI setup ============= @@ -37,10 +29,10 @@ addgroup -S php adduser -SH -h / -g php -s /bin/false -G php php -2) Create the PHP config file, for example: +2) Create the PHP config file: - cp /gales/doc/php/php.ini-production /etc/php.ini - + cp /etc/examples/php.ini /etc/ + 3) Create a daemontools service: @@ -51,261 +43,40 @@ ln -s /etc/svc/php-fastcgi /service/ +Configuration Notes +=================== -Config Recommendations -====================== - -I recommend against CGI for performance and hygiene reasons, e.g. shellshock -and httpoxy style attacks exploiting the unbounded scope of environment -variables. FastCGI is nice in theory; unfortunately the implementation is -bigger and uglier than I'd prefer, and rumor has it that it too -- quite -unjustifiably -- allows attacker control of environment variables. (This seems -about par for the course in PHP. As I was working on this package, yet another -buffer overflow was found in a core component.) My hope is that FastCGI will -still make for a more tractable setup than linking directly into another C -megalith ala mod_php. +The example php.ini included in this port is based on the upstream php.ini-production variant, with a few changes which the experienced PHP admin may notice: -For the sake of avoiding surprises for the experienced PHP admin, the included -php.ini examples are unchanged from upstream. I recommend starting from the --production version and making at least the following changes: +1) expose_php now defaults internally to Off, making the X-Powered-By marketing header an opt-in for Gales users. Note that if enabled, it will announce not just PHP's presence but its version number. -1) expose_php = Off +2) The cgi.fix_pathinfo feature is removed, while the meaning of cgi.discard_path is simplified and it now defaults to On. The prior model was an overly magical "do what I mean", duplicating web server functionality and undermining security by complicating the picture of what files might execute as PHP code. Further details are noted in the comments for discard_path. - Disables the X-Powered-By header which exposes not just PHP's presence but - its version, which could be used by bulk scanners to select you for further - probing. Sure, better to not have vulnerabilities in the first place, but if - you're running PHP in the first place you're pretty much off that train. +3) session.cookie_httponly now defaults internally to On. This mitigates simpler types of session stealing attacks based on script injection, by advising the browser not to expose the session ID cookie to JavaScript code (the cookie is still sent as normal if the script makes an HTTP request to the site, but at least it can't be read directly). Note that PHP's treatment of session IDs in general does not demonstrate the level of care appropriate to handling of secret key material; for instance, the IDs are visible in filesystem path names and quite likely subject to timing attacks. Applications are advised to take their own measures; for instance, obtain a random session secret from a strong entropy source, save it inside the session and set it in a separate cookie, then on subsequent requests check it using a constant-time string comparison. -2) cgi.fix_pathinfo = 0 (also applies to fastcgi) +Additionally, the following changes may be worth considering for security: - This "fixing" is an overly magical feature that should never have been - implemented. It complicates understanding what files might be executed as - PHP code; not the kind of thing you want to be complicated! If disabling it - breaks your URL scheme, look for a better fix. +4) file_uploads = Off (unless you need it and are aware of the implications, e.g. securing upload_tmp_dir) -3) fastcgi.logging = 0 +5) allow_url_fopen = Off (unless you need it and are aware of the implications) - Not security related, but avoids having some PHP errors logged directly and - others redirected through the fastcgi connection to hopefully end up in the - web server's error log, instead logging them all directly. (FPM had a couple - patches that eventually allowed routing them all through fastcgi, though - it's a bigger change than I care to analyze at present.) +6) session.save_path, session.use_strict_mode, session.entropy_file (more research needed...) -4) file_uploads = Off +Some of the more ill-conceived features that one was previously advised to disable (safe mode, magic_quotes_gpc, register_globals) have been removed in recent PHP versions. - Unless you need it and are aware of the implications, e.g. securing - upload_tmp_dir. +API Breakage +============ -5) allow_url_fopen = Off +The Expat gport introduced some deliberate API breakage for security hardening and auditing purposes in Gales, renaming some functions with a _hazmat suffix. PHP's XML extension wraps two of the affected functions for application use, and this port passes through the renaming, as follows: - Unless you need it and are aware of the implications. + xml_set_external_entity_ref_handler -> xml_set_external_entity_ref_handler_hazmat + xml_set_processing_instruction_handler -> xml_set_processing_instruction_handler_hazmat -6) session.cookie_httponly = On - -7) session.save_path, session.use_strict_mode, session.entropy_file - - More research needed... - -Some of the more ill-conceived features that one was previously advised to -disable (safe mode, magic_quotes_gpc, register_globals) have been removed in recent -PHP versions. - - - J. Welsh, March 2018 +As the names suggest, these functions allow the application to implement XML processing instructions and external entity expansion, blurring the line between a static structured data format and a programming language with access to system resources. Not all use of such features is necessarily insecure, but it's a prime avenue for security holes and probably shouldn't be enabled without operator knowledge or control. +If your PHP code calls these functions, you may want to take a good look at how and why, then rename if still necessary. Test suite results ================== -Number of tests : 13997 8291 -Tests skipped : 5706 ( 40.8%) -------- -Tests warned : 2 ( 0.0%) ( 0.0%) -Tests failed : 66 ( 0.5%) ( 0.8%) -Expected fail : 33 ( 0.2%) ( 0.4%) -Tests passed : 8190 ( 58.5%) ( 98.8%) - - -Failures --------- - -Bug #12647 (Locale settings affecting float parsing) [tests/lang/034.phpt] -- setlocale succeeds despite no de_DE locale - musl incompleteness? - -Bug #30638 (localeconv returns wrong LC_NUMERIC settings) (ok to fail on MacOS X) [tests/lang/bug30638.phpt] -- setlocale succeeds despite no de_DE locale - musl incompleteness? - -strftime() and gmstrftime() tests [ext/date/tests/009.phpt] -- undefined behavior in strftime for invalid conversion specifier, ugh - -Bug #27780 (strtotime(+1 xxx) returns a wrong date/time) [ext/date/tests/bug27780.phpt] -- requires zoneinfo - -Bug #32555 (strtotime("tomorrow") can return false) [ext/date/tests/bug32555.phpt] -- strftime %Z is unreliable - -Bug #33532 (Different output for strftime() and date()) [ext/date/tests/bug33532.phpt] -- strftime %Z is unreliable - -Bug #53437 DateInterval unserialize bad data, 64 bit [ext/date/tests/bug53437_var5.phpt] -- seems to be a deliberate integer overflow giving different results - -Bug #48147 (iconv with //IGNORE cuts the string) [ext/iconv/tests/bug48147.phpt] -- incompleteness of musl iconv - -Bug #52211 (iconv() returns part of string on error) [ext/iconv/tests/bug52211.phpt] - -EUC-JP to ISO-2022-JP [ext/iconv/tests/eucjp2iso2022jp.phpt] - -EUC-JP to SJIS [ext/iconv/tests/eucjp2sjis.phpt] - -Test iconv() function : basic functionality [ext/iconv/tests/iconv_basic.phpt] - -Test the basics to function iconv. [ext/iconv/tests/iconv_basic_001.phpt] - -iconv_mime_decode() [ext/iconv/tests/iconv_mime_decode.phpt] - -iconv_mime_encode() [ext/iconv/tests/iconv_mime_encode.phpt] - -iconv stream filter [ext/iconv/tests/iconv_stream_filter.phpt] - -iconv stream filter [ext/iconv/tests/iconv_stream_filter_delimiter.phpt] - -iconv_strpos() [ext/iconv/tests/iconv_strpos.phpt] - -iconv_strrpos() [ext/iconv/tests/iconv_strrpos.phpt] - -iconv_substr() [ext/iconv/tests/iconv_substr.phpt] - -ob_iconv_handler() [ext/iconv/tests/ob_iconv_handler.phpt] - -Bug #41403 (json_decode cannot decode floats if localeconv decimal_point is not '.') [ext/json/tests/bug41403.phpt] - -Localized match [ext/pcre/tests/locales.phpt] - -Test posix_getgrgid() function : basic functionality [ext/posix/tests/posix_getgrgid_basic.phpt] -- defective test, fails if group password field is empty - -Test posix_kill(), posix_get_last_error and posix_strerror() functions : basic functionality [ext/posix/tests/posix_kill_basic.phpt] -- scrapes "ps -p" output, unsupported on busybox (also WTF, sends SIGKILL to first "unused" PID) - -Test function posix_seteuid() by substituting argument 1 with boolean values. [ext/posix/tests/posix_seteuid_variation2.phpt] -- defective test, skipped if euid is 0 but fails for the same reason if euid is 1 - -Test function posix_seteuid() by substituting argument 1 with int values. [ext/posix/tests/posix_seteuid_variation5.phpt] -- defective test, skipped if euid is 0 but fails for the same reason if euid is 1 - -Test function posix_setgid() by substituting argument 1 with boolean values. [ext/posix/tests/posix_setgid_variation2.phpt] -- defective test, skipped if euid is 0 but fails for the same reason if gid is 1 - -Test function posix_setgid() by substituting argument 1 with int values. [ext/posix/tests/posix_setgid_variation5.phpt] -- defective test, skipped if euid is 0 but fails for the same reason if gid is 1 - -Test function posix_setuid() by substituting argument 1 with boolean values. [ext/posix/tests/posix_setuid_variation2.phpt] -- defective test, skipped if euid is 0 but fails for the same reason if uid is 1 - -Test function posix_setuid() by substituting argument 1 with int values. [ext/posix/tests/posix_setuid_variation5.phpt] -- defective test, skipped if euid is 0 but fails for the same reason if uid is 1 - -Sort with SORT_LOCALE_STRING [ext/standard/tests/array/locale_sort.phpt] -- setlocale succeeds despite no fr_FR locale - -Bug #43008 (php://filter uris ignore url encoded filternames and can't handle slashes) [ext/standard/tests/file/bug43008.phpt] -- looks like another iconv problem - -mkdir(dir, 0777) tests [ext/standard/tests/file/mkdir-002.phpt] -- scrapes "ls -l" output which lacks the "total" line on busybox - -Test popen() and pclose function: error conditions [ext/standard/tests/file/popen_pclose_error.phpt] -- behavior of popen with invalid mode is unspecified by POSIX; musl just takes the first char - -Test function getservbyname() [ext/standard/tests/general_functions/getservbyname_basic.phpt] -- the Gales example /etc/services doesn't include aliases, in this case www for http; should probably add these - -Test function getservbyname() by substituting argument 1 with boolean values. [ext/standard/tests/general_functions/getservbyname_variation2.phpt] -- musl seems to pass through decimal values if in bounds; true -> "1" - -Test function getservbyname() by substituting argument 1 with int values. [ext/standard/tests/general_functions/getservbyname_variation5.phpt] -- musl seems to pass through decimal values if in bounds - -Test function getservbyport() by calling it more than or less than its expected arguments [ext/standard/tests/general_functions/getservbyport_variation1.phpt] -- musl seems to return the decimal value if not found - -proc_nice() basic behaviour [ext/standard/tests/general_functions/proc_nice_basic.phpt] -- scrapes "ps -p" output, unsupported on busybox - -Test mail() function : basic functionality [ext/standard/tests/mail/mail_basic2.phpt] -- "cat -n" unsupported on busybox - -Test mail() function : variation force extra parameters [ext/standard/tests/mail/mail_variation2.phpt] -- "cat -n" unsupported on busybox - -php_strip_whitespace() and output buffer [ext/standard/tests/strings/007.phpt] -- matches exact strerror text; s/File name/Filename/ - -Bug #51059 crypt() segfaults on certain salts [ext/standard/tests/strings/bug51059.phpt] -- musl crypt returns * rather than *0/*1 on error - -Official blowfish tests (http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/glibc/crypt_blowfish/wrapper.c) [ext/standard/tests/strings/crypt_blowfish.phpt] -- musl crypt returns * rather than *0/*1 on error and its crypt_blowfish doesn't accept the $2b$ scheme - -Test Blowfish crypt() with invalid rounds [ext/standard/tests/strings/crypt_blowfish_variation1.phpt] -- musl crypt returns * rather than *0/*1 on error - -Test Blowfish crypt() falls back to DES when rounds are not specified, or Blowfish is not available. [ext/standard/tests/strings/crypt_blowfish_variation2.phpt] -- haven't yet found where this behavior is implemented; musl doesn't seem to do it - -htmlentities() test 2 (setlocale / fr_FR.ISO-8859-15) [ext/standard/tests/strings/htmlentities02.phpt] - -htmlentities() test 4 (setlocale / ja_JP.EUC-JP) [ext/standard/tests/strings/htmlentities04.phpt] - -htmlentities() test 15 (setlocale / KOI8-R) [ext/standard/tests/strings/htmlentities15.phpt] - -money_format test [ext/standard/tests/strings/moneyformat.phpt] -- setlocale succeeds despite no en_US locale? - -Test setlocale() function : basic functionality - setting system locale to a specific [ext/standard/tests/strings/setlocale_basic1.phpt] -- "locale" command not provided by musl or busybox - -Test setlocale() function : basic functionality - set locale using an array [ext/standard/tests/strings/setlocale_basic2.phpt] -- "locale" command not provided by musl or busybox - -Test setlocale() function : basic functionality - passing multiple locales as argument [ext/standard/tests/strings/setlocale_basic3.phpt] - -Test setlocale() function : error condition [ext/standard/tests/strings/setlocale_error.phpt] - -Test setlocale() function : usage variations - passing multiple valid/invlaid locales as argument [ext/standard/tests/strings/setlocale_variation1.phpt] - -Test setlocale() function : usage variations - Setting all available locales in the platform [ext/standard/tests/strings/setlocale_variation2.phpt] - -Test setlocale() function : usage variations - setting system locale = 0 [ext/standard/tests/strings/setlocale_variation3.phpt] - -Test setlocale() function : usage variations - setting system locale as null [ext/standard/tests/strings/setlocale_variation4.phpt] - -Test setlocale() function : usage variations - Setting system locale as empty string [ext/standard/tests/strings/setlocale_variation5.phpt] - -sprintf %f #3 [ext/standard/tests/strings/sprintf_f_3.phpt] -- setlocale succeeds despite no is_IS locale - -Test strtoupper on non-ASCII characters [ext/standard/tests/strings/strtoupper.phpt] -- setlocale succeeds despite no de_DE locale - -Test strptime() function : basic functionality [ext/standard/tests/time/strptime_basic.phpt] -- strftime %Z is unreliable - -Test strptime() function : basic functionality [ext/standard/tests/time/strptime_parts.phpt] -- strftime %Z is unreliable - -using invalid combinations of cmdline options [sapi/cgi/tests/005.phpt] -- messages displayed in varying order, don't know why - -Check cli_process_title support on Unix [sapi/cli/tests/cli_process_title_unix.phpt] -- scrapes "ps -p" output, unsupported on busybox - - -Warnings --------- - -Bug #69111 Crash in SessionHandler::read() [ext/session/tests/bug69111.phpt] (warn: XFAIL section but test passes) -- comment says "it is still a leak"; unclear how this would cause a failure - -Bug #70172 - Use After Free Vulnerability in unserialize() [ext/standard/tests/serialize/bug70172.phpt] (warn: XFAIL section but test passes) -- comment says "memory leak on debug build"; unclear how this would cause a failure +The PHP test suite is notoriously brittle, but progress has been made toward a clean run. See README.tests for summary statistics and notes on the remaining failures. diff -uNr a/gports/php56/README.tests b/gports/php56/README.tests --- a/gports/php56/README.tests 1970-01-01 00:00:00 +0000 +++ b/gports/php56/README.tests 1970-01-01 00:00:00 +0000 @@ -0,0 +1,195 @@ +Test suite results +================== + +2018-03-05: +Number of tests : 13997 8291 +Tests skipped : 5706 ( 40.8%) -------- +Tests warned : 2 ( 0.0%) ( 0.0%) +Tests failed : 66 ( 0.5%) ( 0.8%) +Expected fail : 33 ( 0.2%) ( 0.4%) +Tests passed : 8190 ( 58.5%) ( 98.8%) + +2026-08-07: +Number of tests : 13993 8429 +Tests skipped : 5564 ( 39.8%) -------- +Tests warned : 2 ( 0.0%) ( 0.0%) +Tests failed : 42 ( 0.3%) ( 0.5%) +Expected fail : 34 ( 0.2%) ( 0.4%) +Tests passed : 8351 ( 59.7%) ( 99.1%) + +Relevant changes between then and now: +- musl switched from 1.1.16 to 1.1.21, with improved iconv support +- sockets extension enabled +- xml extension enabled + +The only new failure in the current run compared to 2018 is htmlentities03.phpt. This was no small feat, rather the result of a bunch of cleanup work on test suite fallout from all the other patching (which pointed almost entirely to fragile tests rather than real bugs). + +Failure Analysis +---------------- + +Bug #12647 (Locale settings affecting float parsing) [tests/lang/034.phpt] +- musl's stub setlocale always succeeds, despite not implementing a de_DE locale + +Bug #30638 (localeconv returns wrong LC_NUMERIC settings) (ok to fail on MacOS X) [tests/lang/bug30638.phpt] +- musl's stub setlocale always succeeds, despite not implementing a de_DE locale + +strftime() and gmstrftime() tests [ext/date/tests/009.phpt] +- undefined behavior in strftime for invalid conversion specifier, ugh + +Bug #27780 (strtotime(+1 xxx) returns a wrong date/time) [ext/date/tests/bug27780.phpt] +- requires zoneinfo + +Bug #32555 (strtotime("tomorrow") can return false) [ext/date/tests/bug32555.phpt] +- strftime %Z is unreliable + +Bug #33532 (Different output for strftime() and date()) [ext/date/tests/bug33532.phpt] +- strftime %Z is unreliable + +Bug #53437 DateInterval unserialize bad data, 64 bit [ext/date/tests/bug53437_var5.phpt] +- seems to be a deliberate integer overflow giving different results + +Bug #41403 (json_decode cannot decode floats if localeconv decimal_point is not '.') [ext/json/tests/bug41403.phpt] +- probably again due to musl's stub setlocale always succeeding (no de_DE locale); but localizing float format in var_dump output, as shown in the expected result, is deranged + +Localized match [ext/pcre/tests/locales.phpt] +- probably again due to musl's stub setlocale always succeeding (no pt_PT locale) + +Test posix_getgrgid() function : basic functionality [ext/posix/tests/posix_getgrgid_basic.phpt] +- defective test, fails if group password field is empty +- passing now but probably fragile + +Test posix_kill(), posix_get_last_error and posix_strerror() functions : basic functionality [ext/posix/tests/posix_kill_basic.phpt] +- scrapes "ps -p" output, unsupported on busybox (also WTF, sends SIGKILL to first "unused" PID) + +Test function posix_seteuid() by substituting argument 1 with boolean values. [ext/posix/tests/posix_seteuid_variation2.phpt] +- defective test, skipped if euid is 0 but fails for the same reason if euid is 1 +- passing now but probably fragile + +Test function posix_seteuid() by substituting argument 1 with int values. [ext/posix/tests/posix_seteuid_variation5.phpt] +- defective test, skipped if euid is 0 but fails for the same reason if euid is 1 +- passing now but probably fragile + +Test function posix_setgid() by substituting argument 1 with boolean values. [ext/posix/tests/posix_setgid_variation2.phpt] +- defective test, skipped if euid is 0 but fails for the same reason if gid is 1 +- passing now but probably fragile + +Test function posix_setgid() by substituting argument 1 with int values. [ext/posix/tests/posix_setgid_variation5.phpt] +- defective test, skipped if euid is 0 but fails for the same reason if gid is 1 +- passing now but probably fragile + +Test function posix_setuid() by substituting argument 1 with boolean values. [ext/posix/tests/posix_setuid_variation2.phpt] +- defective test, skipped if euid is 0 but fails for the same reason if uid is 1 +- passing now but probably fragile + +Test function posix_setuid() by substituting argument 1 with int values. [ext/posix/tests/posix_setuid_variation5.phpt] +- defective test, skipped if euid is 0 but fails for the same reason if uid is 1 +- passing now but probably fragile + +Sort with SORT_LOCALE_STRING [ext/standard/tests/array/locale_sort.phpt] +- setlocale succeeds despite no fr_FR locale + +mkdir(dir, 0777) tests [ext/standard/tests/file/mkdir-002.phpt] +- scrapes "ls -l" output which lacks the "total" line on busybox + +Test popen() and pclose function: error conditions [ext/standard/tests/file/popen_pclose_error.phpt] +- behavior of popen with invalid mode is unspecified by POSIX; musl just takes the first char + +Test function getservbyname() by substituting argument 1 with boolean values. [ext/standard/tests/general_functions/getservbyname_variation2.phpt] +- musl seems to pass through decimal values if in bounds; true -> "1" +- passing now but not sure what changed + +Test function getservbyname() by substituting argument 1 with int values. [ext/standard/tests/general_functions/getservbyname_variation5.phpt] +- musl seems to pass through decimal values if in bounds +- passing now but not sure what changed + +Test function getservbyport() by calling it more than or less than its expected arguments [ext/standard/tests/general_functions/getservbyport_variation1.phpt] +- musl seems to return the decimal value if not found +- passing now but not sure what changed + +proc_nice() basic behaviour [ext/standard/tests/general_functions/proc_nice_basic.phpt] +- scrapes "ps -p" output, unsupported on busybox + +Test mail() function : basic functionality [ext/standard/tests/mail/mail_basic2.phpt] +- "cat -n" unsupported on busybox + +Test mail() function : variation force extra parameters [ext/standard/tests/mail/mail_variation2.phpt] +- "cat -n" unsupported on busybox + +php_strip_whitespace() and output buffer [ext/standard/tests/strings/007.phpt] +- matches exact strerror text; s/File name/Filename/ + +Bug #51059 crypt() segfaults on certain salts [ext/standard/tests/strings/bug51059.phpt] +- musl crypt returns * rather than *0/*1 on error + +Official blowfish tests (http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/glibc/crypt_blowfish/wrapper.c) [ext/standard/tests/strings/crypt_blowfish.phpt] +- musl crypt returns * rather than *0/*1 on error and its crypt_blowfish doesn't accept the $2b$ scheme + +Test Blowfish crypt() with invalid rounds [ext/standard/tests/strings/crypt_blowfish_variation1.phpt] +- musl crypt returns * rather than *0/*1 on error + +Test Blowfish crypt() falls back to DES when rounds are not specified, or Blowfish is not available. [ext/standard/tests/strings/crypt_blowfish_variation2.phpt] +- haven't yet found where this behavior is implemented; musl doesn't seem to do it + +htmlentities() test 2 (setlocale / fr_FR.ISO-8859-15) [ext/standard/tests/strings/htmlentities02.phpt] +- a real failure, but of the very obscure corner of charset detection fallbacks in htmlentities, wherein it falls back all the way to checking the libc process-level locale; hard to fix due to musl's stub setlocale + +htmlentities() test 3 (setlocale / de_DE.ISO-8859-1) [ext/standard/tests/strings/htmlentities03.phpt] +- as with htmlentities02.phpt + +htmlentities() test 4 (setlocale / ja_JP.EUC-JP) [ext/standard/tests/strings/htmlentities04.phpt] +- as with htmlentities02.phpt + +htmlentities() test 15 (setlocale / KOI8-R) [ext/standard/tests/strings/htmlentities15.phpt] +- as with htmlentities02.phpt + +money_format test [ext/standard/tests/strings/moneyformat.phpt] +- again due to musl's stub setlocale always succeeding? (no en_US locale) + +Test setlocale() function : basic functionality - setting system locale to a specific [ext/standard/tests/strings/setlocale_basic1.phpt] +- "locale" command not provided by musl or busybox + +Test setlocale() function : basic functionality - set locale using an array [ext/standard/tests/strings/setlocale_basic2.phpt] +- "locale" command not provided by musl or busybox + +Test setlocale() function : basic functionality - passing multiple locales as argument [ext/standard/tests/strings/setlocale_basic3.phpt] +- "locale" command not provided by musl or busybox, among other likely trouble + +Test setlocale() function : error condition [ext/standard/tests/strings/setlocale_error.phpt] + +Test setlocale() function : usage variations - passing multiple valid/invlaid locales as argument [ext/standard/tests/strings/setlocale_variation1.phpt] + +Test setlocale() function : usage variations - Setting all available locales in the platform [ext/standard/tests/strings/setlocale_variation2.phpt] + +Test setlocale() function : usage variations - setting system locale = 0 [ext/standard/tests/strings/setlocale_variation3.phpt] + +Test setlocale() function : usage variations - setting system locale as null [ext/standard/tests/strings/setlocale_variation4.phpt] + +Test setlocale() function : usage variations - Setting system locale as empty string [ext/standard/tests/strings/setlocale_variation5.phpt] + +sprintf %f #3 [ext/standard/tests/strings/sprintf_f_3.phpt] +- again due to musl's stub setlocale always succeeding (no is_IS locale) + +Test strtoupper on non-ASCII characters [ext/standard/tests/strings/strtoupper.phpt] +- again due to musl's stub setlocale always succeeding (no de_DE locale) + +Test strptime() function : basic functionality [ext/standard/tests/time/strptime_basic.phpt] +- strftime %Z is unreliable + +Test strptime() function : basic functionality [ext/standard/tests/time/strptime_parts.phpt] +- strftime %Z is unreliable + +using invalid combinations of cmdline options [sapi/cgi/tests/005.phpt] +- interactive mode messages displayed in varying order; probably due to buffering differences (musl doesn't implicitly flush stdout as much as glibc) and quite annoying for actually using the -a mode + +Check cli_process_title support on Unix [sapi/cli/tests/cli_process_title_unix.phpt] +- scrapes "ps -p" output, unsupported on busybox + + +Warnings +-------- + +Bug #69111 Crash in SessionHandler::read() [ext/session/tests/bug69111.phpt] (warn: XFAIL section but test passes) +- comment says "it is still a leak"; unclear how this would cause a failure + +Bug #70172 - Use After Free Vulnerability in unserialize() [ext/standard/tests/serialize/bug70172.phpt] (warn: XFAIL section but test passes) +- comment says "memory leak on debug build"; unclear how this would cause a failure diff -uNr a/gports/php56/build.sh b/gports/php56/build.sh --- a/gports/php56/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/php56/build.sh 1970-01-01 00:00:00 +0000 @@ -1,11 +1,10 @@ P=php V=5.6.34 MAJOR=506 -MINOR=2 +MINOR=4 -# Build requires: autoconf, sqlite -# TODO: bison, re2c, libxml2 (?) -# Includes bundled: pcre +# Build requires: autoconf, expat, pcre (Gales package version >=0.2), sqlite +# TODO: bison, re2c # To investigate: # - zlib @@ -18,7 +17,9 @@ S=" $P-$V.tar.xz https://secure.php.net/distributions/$P-$V.tar.xz +NEWS.gales README.gales +README.tests kill-libtool.patch kill-shtool.patch expr.patch @@ -31,7 +32,12 @@ kill-scripts.patch hands-off-my-paths.patch fp-macros.patch -fopen-failure.patch +secure-pathinfo.patch +force_redirect-bypass-fix.patch +gales-ini-defaults.patch +follow-expat-xxe-hardening.patch +stable-test-env.patch +misc-test-fixes.patch run " @@ -40,14 +46,35 @@ " build () { + # Set up a virtual PCRE installation, to opt in to the unicode version (needed for /u flag in preg_* functions) without fighting autoconf over the library name + mkdir pcre pcre/lib + ln -s /gales/pkg/pcre/include pcre/include + ln -s /gales/pkg/pcre/lib/libpcre_unicode.a pcre/lib/libpcre.a + pcrepath=$PWD/pcre + tar xJf $P-$V.tar.xz cd $P-$V mv acinclude.m4 aclocal.m4 rm build/libtool.m4 configure ltmain.sh main/php_config.h.in missing mkinstalldirs # Sometimes bundled dependencies are nice, but sqlite is big and they used the predigested amalgamation file. "Open source" huh. rm ext/sqlite3/libsqlite/* + # we now have a pcre gport (a later version, even) + rm -r ext/pcre/pcrelib # And this is a straight-up binary blob. rm pear/install-pear-nozlib.phar + + # Pre-patching surgery on test suite. These ones are troublesome to patch due to non-ASCII or otherwise misformatted source. + # The targetted bug was iconv returning broken partial string on invalid input bytes without reporting the error. Musl emits a * for the bad input then carries on, which is allowable by the standards and seems desirable in practice compared to failing entirely. + rm ext/iconv/tests/bug52211.phpt + # ISO-2022-JP is a non-unique encoding, using escape sequences to switch character sets, so output is implementation dependent. In particular, musl's is verbose because it shifts in and out for each character (less stateful). Test could be salvaged by sniffing the first character's worth then just checking that it round-trips. + rm ext/iconv/tests/eucjp2iso2022jp.phpt + # Tested the //TRANSLIT output charset suffix, a GNU extension which musl rejects; hardly "basic". + rm ext/iconv/tests/iconv_basic_001.phpt + # Another case of ISO-2022-JP, with extra complication of implementation-dependent minimum buffer sizing. + rm ext/iconv/tests/iconv_mime_encode.phpt + # noeol file (missing final newline, whereas only valid text files are in scope for diff/patch) + echo >> ext/xml/tests/xml_set_processing_instruction_handler_basic.phpt + patch -p1 <../kill-libtool.patch patch -p1 <../kill-shtool.patch patch -p1 <../expr.patch @@ -60,11 +87,22 @@ patch -p1 <../kill-scripts.patch patch -p1 <../hands-off-my-paths.patch patch -p1 <../fp-macros.patch - patch -p1 <../fopen-failure.patch + patch -p1 <../secure-pathinfo.patch + patch -p1 <../force_redirect-bypass-fix.patch + patch -p1 <../gales-ini-defaults.patch + patch -p1 <../follow-expat-xxe-hardening.patch + patch -p1 <../stable-test-env.patch + chmod -x run-tests.php + chmod +x run-tests.sh + patch -p1 <../misc-test-fixes.patch + # Re-bundle the amalgamation rather than linking the library so the build system can control the enabled features cp /gales/pkg/sqlite/lib/sqlite3.c /gales/pkg/sqlite/include/sqlite3.h ext/sqlite3/libsqlite/ autoconf autoheader + # At least MP-WP still demands the old "mysql" extension (not mysqli or pdo); PHP 7 removed it. + # MP-WP also uses some mbstring functions, sometimes with fallbacks, but not yet clear if it's worth adding that extension which is heavy on both code and predigested data. + # And it uses the xml extension for xmlrpc pingbacks and other tidbits like feed parsing. CFLAGS=-O2 \ ./configure --prefix=/gales/pkg/$Q \ --sbindir='${prefix}/bin' \ @@ -77,11 +115,16 @@ --disable-libxml \ --disable-dom \ --disable-simplexml \ - --disable-xml \ + --enable-xml \ --disable-xmlreader \ --disable-xmlwriter \ + --disable-mbstring \ + --disable-mbregex \ --enable-sockets \ + --with-libexpat-dir=/gales/pkg/expat \ + --with-mysql \ --with-mysqli \ + --with-pcre-regex=$pcrepath \ --with-pdo-mysql \ --without-pear make -j$JOBS @@ -89,19 +132,22 @@ check () { if [ $CHECK_LEVEL -lt 3 ]; then - echo "skipping: slow, known failures, doesn't return an exit code" + echo "skipping: slow, known failures" return fi cd $P-$V - make test TESTS="-q -s test.log" + ./run-tests.sh -q -s test.log --offline } package () { r=gales/pkg/$Q x etc/examples/svc/php-fastcgi/run l etc/examples/svc/php-fastcgi/log/run /etc/svc.defs/multilog + f $r/doc/NEWS.gales f $r/doc/README.gales + f $r/doc/README.tests cd $P-$V + f etc/examples/php.ini php.ini-production X $r/bin/php sapi/cli/php X $r/bin/php-cgi sapi/cgi/php-cgi f $r/doc/README.cli sapi/cli/README @@ -109,8 +155,6 @@ f $r/doc/LICENSE f $r/doc/NEWS f $r/doc/UPGRADING - f $r/doc/php.ini-development - f $r/doc/php.ini-production f $r/man/man1/php.1 sapi/cli/php.1 l $r/man/man1/php-cgi.1 php.1 l gales/pkg/$P $Q diff -uNr a/gports/php56/follow-expat-xxe-hardening.patch b/gports/php56/follow-expat-xxe-hardening.patch --- a/gports/php56/follow-expat-xxe-hardening.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/follow-expat-xxe-hardening.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,600 @@ +diff -ur a/ext/xml/php_xml.h b/ext/xml/php_xml.h +--- a/ext/xml/php_xml.h 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/php_xml.h 2026-05-26 07:52:49 +0000 +@@ -113,11 +113,11 @@ + PHP_FUNCTION(xml_set_object); + PHP_FUNCTION(xml_set_element_handler); + PHP_FUNCTION(xml_set_character_data_handler); +-PHP_FUNCTION(xml_set_processing_instruction_handler); ++PHP_FUNCTION(xml_set_processing_instruction_handler_hazmat); + PHP_FUNCTION(xml_set_default_handler); + PHP_FUNCTION(xml_set_unparsed_entity_decl_handler); + PHP_FUNCTION(xml_set_notation_decl_handler); +-PHP_FUNCTION(xml_set_external_entity_ref_handler); ++PHP_FUNCTION(xml_set_external_entity_ref_handler_hazmat); + PHP_FUNCTION(xml_set_start_namespace_decl_handler); + PHP_FUNCTION(xml_set_end_namespace_decl_handler); + PHP_FUNCTION(xml_parse); +diff -ur a/ext/xml/tests/xml001.phpt b/ext/xml/tests/xml001.phpt +--- a/ext/xml/tests/xml001.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml001.phpt 2026-05-26 07:59:53 +0000 +@@ -13,9 +13,9 @@ + xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 1); + xml_set_element_handler($xml_parser, "startElement", "endElement"); + xml_set_character_data_handler($xml_parser, "characterData"); +-xml_set_processing_instruction_handler($xml_parser, "PIHandler"); ++xml_set_processing_instruction_handler_hazmat($xml_parser, "PIHandler"); + xml_set_default_handler($xml_parser, "defaultHandler"); +-xml_set_external_entity_ref_handler($xml_parser, "externalEntityRefHandler"); ++xml_set_external_entity_ref_handler_hazmat($xml_parser, "externalEntityRefHandler"); + + if (!($fp = @fopen("xmltest.xml", "r"))) { + die("could not open XML input"); +diff -ur a/ext/xml/tests/xml002.phpt b/ext/xml/tests/xml002.phpt +--- a/ext/xml/tests/xml002.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml002.phpt 2026-05-26 08:00:32 +0000 +@@ -54,9 +54,9 @@ + xml_set_element_handler($xml_parser, array($obj,"startElement"), + array($obj, "endElement")); + xml_set_character_data_handler($xml_parser, array($obj, "characterData")); +-xml_set_processing_instruction_handler($xml_parser, array($obj, "PIHandler")); ++xml_set_processing_instruction_handler_hazmat($xml_parser, array($obj, "PIHandler")); + xml_set_default_handler($xml_parser, array($obj, "defaultHandler")); +-xml_set_external_entity_ref_handler($xml_parser, ++xml_set_external_entity_ref_handler_hazmat($xml_parser, + array($obj, "externalEntityRefHandler")); + + if (!($fp = @fopen("xmltest.xml", "r"))) { +diff -ur a/ext/xml/tests/xml003.phpt b/ext/xml/tests/xml003.phpt +--- a/ext/xml/tests/xml003.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml003.phpt 2026-05-26 08:01:47 +0000 +@@ -54,9 +54,9 @@ + xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 1); + xml_set_element_handler($xml_parser, "startElement", "endElement"); + xml_set_character_data_handler($xml_parser, "characterData"); +-xml_set_processing_instruction_handler($xml_parser, "PIHandler"); ++xml_set_processing_instruction_handler_hazmat($xml_parser, "PIHandler"); + xml_set_default_handler($xml_parser, "defaultHandler"); +-xml_set_external_entity_ref_handler($xml_parser, "externalEntityRefHandler"); ++xml_set_external_entity_ref_handler_hazmat($xml_parser, "externalEntityRefHandler"); + + if (!($fp = @fopen("xmltest.xml", "r"))) { + die("could not open XML input"); +diff -ur a/ext/xml/tests/xml_set_external_entity_ref_handler_error.phpt b/ext/xml/tests/xml_set_external_entity_ref_handler_error.phpt +--- a/ext/xml/tests/xml_set_external_entity_ref_handler_error.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_set_external_entity_ref_handler_error.phpt 2026-05-26 07:58:05 +0000 +@@ -22,12 +22,12 @@ + + $hdl = 'string_val'; + $extra_arg = 10; +-var_dump( xml_set_external_entity_ref_handler(null, $hdl, $extra_arg) ); ++var_dump( xml_set_external_entity_ref_handler_hazmat(null, $hdl, $extra_arg) ); + + // Testing xml_set_external_entity_ref_handler with one less than the expected number of arguments + echo "\n-- Testing xml_set_external_entity_ref_handler() function with less than expected no. of arguments --\n"; + +-var_dump( xml_set_external_entity_ref_handler(null) ); ++var_dump( xml_set_external_entity_ref_handler_hazmat(null) ); + + echo "Done"; + ?> +@@ -36,12 +36,12 @@ + + -- Testing xml_set_external_entity_ref_handler() function with more than expected no. of arguments -- + +-Warning: xml_set_external_entity_ref_handler() expects exactly 2 parameters, 3 given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects exactly 2 parameters, 3 given in %s on line %d + NULL + + -- Testing xml_set_external_entity_ref_handler() function with less than expected no. of arguments -- + +-Warning: xml_set_external_entity_ref_handler() expects exactly 2 parameters, 1 given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects exactly 2 parameters, 1 given in %s on line %d + NULL + Done + +diff -ur a/ext/xml/tests/xml_set_external_entity_ref_handler_variation1.phpt b/ext/xml/tests/xml_set_external_entity_ref_handler_variation1.phpt +--- a/ext/xml/tests/xml_set_external_entity_ref_handler_variation1.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_set_external_entity_ref_handler_variation1.phpt 2026-05-26 07:58:51 +0000 +@@ -93,7 +93,7 @@ + + foreach($values as $value) { + echo @"\nArg value $value \n"; +- var_dump( xml_set_external_entity_ref_handler($value, $hdl) ); ++ var_dump( xml_set_external_entity_ref_handler_hazmat($value, $hdl) ); + }; + + fclose($fp); +@@ -104,142 +104,142 @@ + + Arg value 0 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value 1 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value 12345 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value -2345 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value 10.5 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value -10.5 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value 101234567000 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value 1.07654321E-9 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value 0.5 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + + Arg value 1 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value 1 + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value string + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value string + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value Some Ascii Data + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, object given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, object given in %s on line %d + NULL + + Arg value Resource id %s + +-Warning: xml_set_external_entity_ref_handler(): supplied resource is not a valid XML Parser resource in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat(): supplied resource is not a valid XML Parser resource in %s on line %d + bool(false) + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_external_entity_ref_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_external_entity_ref_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + Done + +diff -ur a/ext/xml/tests/xml_set_processing_instruction_handler_basic.phpt b/ext/xml/tests/xml_set_processing_instruction_handler_basic.phpt +--- a/ext/xml/tests/xml_set_processing_instruction_handler_basic.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_set_processing_instruction_handler_basic.phpt 2026-05-26 07:54:29 +0000 +@@ -27,7 +27,7 @@ + { + $parser = xml_parser_create(); + xml_set_object($parser, $this); +- xml_set_processing_instruction_handler($parser, "PIHandler"); ++ xml_set_processing_instruction_handler_hazmat($parser, "PIHandler"); + xml_parse($parser, $data, true); + xml_parser_free($parser); + } +diff -ur a/ext/xml/tests/xml_set_processing_instruction_handler_error.phpt b/ext/xml/tests/xml_set_processing_instruction_handler_error.phpt +--- a/ext/xml/tests/xml_set_processing_instruction_handler_error.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_set_processing_instruction_handler_error.phpt 2026-05-26 07:56:18 +0000 +@@ -22,12 +22,12 @@ + + $hdl = 'string_val'; + $extra_arg = 10; +-var_dump( xml_set_processing_instruction_handler(null, $hdl, $extra_arg) ); ++var_dump( xml_set_processing_instruction_handler_hazmat(null, $hdl, $extra_arg) ); + + // Testing xml_set_processing_instruction_handler with one less than the expected number of arguments + echo "\n-- Testing xml_set_processing_instruction_handler() function with less than expected no. of arguments --\n"; + +-var_dump( xml_set_processing_instruction_handler(null) ); ++var_dump( xml_set_processing_instruction_handler_hazmat(null) ); + + echo "Done"; + ?> +@@ -36,12 +36,12 @@ + + -- Testing xml_set_processing_instruction_handler() function with more than expected no. of arguments -- + +-Warning: xml_set_processing_instruction_handler() expects exactly 2 parameters, 3 given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects exactly 2 parameters, 3 given in %s on line %d + NULL + + -- Testing xml_set_processing_instruction_handler() function with less than expected no. of arguments -- + +-Warning: xml_set_processing_instruction_handler() expects exactly 2 parameters, 1 given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects exactly 2 parameters, 1 given in %s on line %d + NULL + Done + +diff -ur a/ext/xml/tests/xml_set_processing_instruction_handler_variation1.phpt b/ext/xml/tests/xml_set_processing_instruction_handler_variation1.phpt +--- a/ext/xml/tests/xml_set_processing_instruction_handler_variation1.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_set_processing_instruction_handler_variation1.phpt 2026-05-26 07:57:07 +0000 +@@ -93,7 +93,7 @@ + + foreach($values as $value) { + echo @"\nArg value $value \n"; +- var_dump( xml_set_processing_instruction_handler($value, $hdl) ); ++ var_dump( xml_set_processing_instruction_handler_hazmat($value, $hdl) ); + }; + + fclose($fp); +@@ -104,142 +104,142 @@ + + Arg value 0 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value 1 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value 12345 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value -2345 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, integer given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, integer given in %s on line %d + NULL + + Arg value 10.5 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value -10.5 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value 101234567000 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value 1.07654321E-9 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value 0.5 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, double given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, double given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value Array + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, array given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, array given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + + Arg value 1 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value 1 + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, boolean given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, boolean given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value string + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value string + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, string given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, string given in %s on line %d + NULL + + Arg value Some Ascii Data + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, object given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, object given in %s on line %d + NULL + + Arg value Resource id %s + +-Warning: xml_set_processing_instruction_handler(): supplied resource is not a valid XML Parser resource in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat(): supplied resource is not a valid XML Parser resource in %s on line %d + bool(false) + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + + Arg value + +-Warning: xml_set_processing_instruction_handler() expects parameter 1 to be resource, null given in %s on line %d ++Warning: xml_set_processing_instruction_handler_hazmat() expects parameter 1 to be resource, null given in %s on line %d + NULL + Done + +diff -ur a/ext/xml/xml.c b/ext/xml/xml.c +--- a/ext/xml/xml.c 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/xml.c 2026-05-26 07:52:28 +0000 +@@ -50,8 +50,8 @@ + */ + + /* Long-term TODO list: +- * - Fix the expat library so you can install your own memory manager +- * functions ++ * - Fix the expat library so you can install your own memory manager functions ++ * - This would appear to be done and in use? See php_xml_mem_hdlrs -jfw + */ + + /* Known bugs: +@@ -126,7 +126,7 @@ + ZEND_ARG_INFO(0, hdl) + ZEND_END_ARG_INFO() + +-ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_processing_instruction_handler, 0, 0, 2) ++ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_processing_instruction_handler_hazmat, 0, 0, 2) + ZEND_ARG_INFO(0, parser) + ZEND_ARG_INFO(0, hdl) + ZEND_END_ARG_INFO() +@@ -146,7 +146,7 @@ + ZEND_ARG_INFO(0, hdl) + ZEND_END_ARG_INFO() + +-ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_external_entity_ref_handler, 0, 0, 2) ++ZEND_BEGIN_ARG_INFO_EX(arginfo_xml_set_external_entity_ref_handler_hazmat, 0, 0, 2) + ZEND_ARG_INFO(0, parser) + ZEND_ARG_INFO(0, hdl) + ZEND_END_ARG_INFO() +@@ -223,11 +223,11 @@ + PHP_FE(xml_set_object, arginfo_xml_set_object) + PHP_FE(xml_set_element_handler, arginfo_xml_set_element_handler) + PHP_FE(xml_set_character_data_handler, arginfo_xml_set_character_data_handler) +- PHP_FE(xml_set_processing_instruction_handler, arginfo_xml_set_processing_instruction_handler) ++ PHP_FE(xml_set_processing_instruction_handler_hazmat, arginfo_xml_set_processing_instruction_handler_hazmat) + PHP_FE(xml_set_default_handler, arginfo_xml_set_default_handler) + PHP_FE(xml_set_unparsed_entity_decl_handler,arginfo_xml_set_unparsed_entity_decl_handler) + PHP_FE(xml_set_notation_decl_handler, arginfo_xml_set_notation_decl_handler) +- PHP_FE(xml_set_external_entity_ref_handler, arginfo_xml_set_external_entity_ref_handler) ++ PHP_FE(xml_set_external_entity_ref_handler_hazmat, arginfo_xml_set_external_entity_ref_handler_hazmat) + PHP_FE(xml_set_start_namespace_decl_handler,arginfo_xml_set_start_namespace_decl_handler) + PHP_FE(xml_set_end_namespace_decl_handler, arginfo_xml_set_end_namespace_decl_handler) + PHP_FE(xml_parse, arginfo_xml_parse) +@@ -1310,9 +1310,11 @@ + } + /* }}} */ + +-/* {{{ proto int xml_set_processing_instruction_handler(resource parser, string hdl) +- Set up processing instruction (PI) handler */ +-PHP_FUNCTION(xml_set_processing_instruction_handler) ++/* {{{ proto int xml_set_processing_instruction_handler_hazmat(resource parser, string hdl) ++ Set up processing instruction (PI) handler ++ Renamed to _hazmat as Gales audit for insecure use, following from underlying expat. ++ */ ++PHP_FUNCTION(xml_set_processing_instruction_handler_hazmat) + { + xml_parser *parser; + zval *pind, **hdl; +@@ -1324,7 +1326,7 @@ + ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); + + xml_set_handler(&parser->processingInstructionHandler, hdl); +- XML_SetProcessingInstructionHandler(parser->parser, _xml_processingInstructionHandler); ++ XML_SetProcessingInstructionHandler_hazmat(parser->parser, _xml_processingInstructionHandler); + RETVAL_TRUE; + } + /* }}} */ +@@ -1384,9 +1386,11 @@ + } + /* }}} */ + +-/* {{{ proto int xml_set_external_entity_ref_handler(resource parser, string hdl) +- Set up external entity reference handler */ +-PHP_FUNCTION(xml_set_external_entity_ref_handler) ++/* {{{ proto int xml_set_external_entity_ref_handler_hazmat(resource parser, string hdl) ++ Set up external entity reference handler ++ Renamed to _hazmat as Gales audit for insecure use, following from underlying expat. ++ */ ++PHP_FUNCTION(xml_set_external_entity_ref_handler_hazmat) + { + xml_parser *parser; + zval *pind, **hdl; +@@ -1397,7 +1401,7 @@ + ZEND_FETCH_RESOURCE(parser,xml_parser *, &pind, -1, "XML Parser", le_xml_parser); + + xml_set_handler(&parser->externalEntityRefHandler, hdl); +- XML_SetExternalEntityRefHandler(parser->parser, (void *) _xml_externalEntityRefHandler); ++ XML_SetExternalEntityRefHandler_hazmat(parser->parser, (void *) _xml_externalEntityRefHandler); + RETVAL_TRUE; + } + /* }}} */ diff -uNr a/gports/php56/fopen-failure.patch b/gports/php56/fopen-failure.patch --- a/gports/php56/fopen-failure.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/fopen-failure.patch 1970-01-01 00:00:00 +0000 @@ -1,61 +0,0 @@ -Passing a nonexistent script through to PHP seems to be regarded as a web -server misconfiguration, so return 500 and log the error rather than falsely -writing "no input file specified". - -It's not clear to me that path_translated and errno are necessarily meaningful -in the log message, but this was php-fpm's fix. (You try reading -php_fopen_primary_script and telling me what it does!) - -(Testing found my below noted skepticism to be warranted; that is, it's quite -possible for path_tranlated to be NULL even given (cgi || fastcgi). A regrind -of this patch should remove the offending comment.) - - -jfw - ---- a/sapi/cgi/cgi_main.c -+++ b/sapi/cgi/cgi_main.c -@@ -2222,17 +2222,29 @@ - 2. we are running as cgi or fastcgi - */ - if (cgi || fastcgi || SG(request_info).path_translated) { -+ /* from FPM: -+ * have to duplicate SG(request_info).path_translated to be able to log errrors -+ * php_fopen_primary_script seems to delete SG(request_info).path_translated on failure -+ */ -+ char *primary_script = NULL; -+ /* I'm unconvinced of the above "will be set if" claim. */ -+ if (SG(request_info).path_translated) -+ primary_script = estrdup(SG(request_info).path_translated); -+ - if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) { - zend_try { -- if (errno == EACCES) { -- SG(sapi_headers).http_response_code = 403; -- PUTS("Access denied.\n"); -- } else { -- SG(sapi_headers).http_response_code = 404; -- PUTS("No input file specified.\n"); -- } -+ fprintf(stderr, "Unable to open primary script: %s (%s)\n", -+ primary_script ? primary_script : "(NULL)", -+ strerror(errno)); -+ SG(sapi_headers).http_response_code = 500; -+ PUTS("Failed to open primary script.\n"); - } zend_catch { - } zend_end_try(); -+ if (primary_script) { -+ efree(primary_script); -+ primary_script = NULL; -+ } -+ - /* we want to serve more requests if this is fastcgi - * so cleanup and continue, request shutdown is - * handled later */ -@@ -2256,6 +2268,7 @@ - #endif - return FAILURE; - } -+ if (primary_script) efree(primary_script); - } - - if (CGIG(check_shebang_line)) { diff -uNr a/gports/php56/force_redirect-bypass-fix.patch b/gports/php56/force_redirect-bypass-fix.patch --- a/gports/php56/force_redirect-bypass-fix.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/force_redirect-bypass-fix.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,105 @@ +Fix trivial bypass of cgi.force_redirect protection by Redirect-Status HTTP header. Thus, if php-cgi binary is mapped in URL space for CGI execution e.g. via Apache Action, it can no longer be called directly with PATH_INFO to display or execute arbitrary files from the document root. + +Hole has been present for decades but the PHP rangers noticed in 2024: https://github.com/php/php-src/security/advisories/GHSA-94p6-54jq-9mwp ; I found it independently while straightening out php-cgi's script path handling generally. + +While we're here, also tone down the security blandishment and fix its display: it was shouting into the void because it failed to provide a valid HTTP response header, causing Apache to report a generic 500 error. + +Finally, deduplicate the shutdown sequence in the php_fopen_primary_script failure case, the same way as in the new code and elsewhere. + + -jfw + +diff -ur a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c +--- a/sapi/cgi/cgi_main.c 2026-04-15 20:43:24 +0000 ++++ b/sapi/cgi/cgi_main.c 2026-04-15 20:43:26 +0000 +@@ -1472,46 +1472,6 @@ + return FAILURE; + } + +- /* check force_cgi after startup, so we have proper output */ +- if (cgi && CGIG(force_redirect)) { +- /* Apache will generate REDIRECT_STATUS, +- * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS. +- * redirect.so and installation instructions available from +- * http://www.koehntopp.de/php. +- * -- kk@netuse.de +- */ +- if (!getenv("REDIRECT_STATUS") && +- !getenv ("HTTP_REDIRECT_STATUS") && +- /* this is to allow a different env var to be configured +- * in case some server does something different than above */ +- (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env))) +- ) { +- zend_try { +- SG(sapi_headers).http_response_code = 400; +- PUTS("Security Alert! The PHP CGI cannot be accessed directly.\n\n\ +-

This PHP CGI binary was compiled with force-cgi-redirect enabled. This\n\ +-means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\ +-set, e.g. via an Apache Action directive.

\n\ +-

For more information as to why this behaviour exists, see the \ +-manual page for CGI security.

\n\ +-

For more information about changing this behaviour or re-enabling this webserver,\n\ +-consult the installation file that came with this distribution, or visit \n\ +-the manual page.

\n"); +- } zend_catch { +- } zend_end_try(); +-#if defined(ZTS) && !defined(PHP_DEBUG) +- /* XXX we're crashing here in msvc6 debug builds at +- * php_message_handler_for_zend:839 because +- * SG(request_info).path_translated is an invalid pointer. +- * It still happens even though I set it to null, so something +- * weird is going on. +- */ +- tsrm_shutdown(); +-#endif +- return FAILURE; +- } +- } +- + if (bindpath) { + int backlog = 128; + if (getenv("PHP_FCGI_BACKLOG")) { +@@ -1884,6 +1844,28 @@ + SG(request_info).no_headers = 1; + } + ++ /* check force_cgi after startup, so we have proper output ++ * Now: moved further down to where this actually holds, including proper status code & header output, just before opening the guarded primary script (-jfw 2026) */ ++ if (cgi && CGIG(force_redirect)) { ++ /* Apache will generate REDIRECT_STATUS. ++ * Old comments said Netscape and redirect.so will generate HTTP_REDIRECT_STATUS, but that's in the client-controlled namespace of HTTP headers, so not usable as a security check. (-jfw 2026) ++ * The redirect_status_env setting allows overriding the variable name in case some server does something different. */ ++ if ((CGIG(redirect_status_env) && ++ !getenv(CGIG(redirect_status_env))) || ++ !getenv("REDIRECT_STATUS") ++ ) { ++ /* zend_try/catch here and below seem to be meant to fix a silent exit on HEAD requests pursuant to https://bugs.php.net/bug.php?id=50168 though details are unclear and it doesn't seem reproducible anymore. (-jfw 2026) */ ++ zend_try { ++ SG(sapi_headers).http_response_code = 403; ++ PUTS("Access denied.\n

To prevent execution or display of arbitrary files, when cgi.force_redirect is enabled, the PHP CGI binary serves up a page only if the REDIRECT_STATUS CGI variable is set, e.g. via an Apache Action directive.\n"); ++ } zend_catch { ++ } zend_end_try(); ++ php_request_shutdown(NULL); ++ exit_status = FAILURE; ++ goto out; ++ } ++ } ++ + if (cgi || fastcgi || SG(request_info).path_translated) { + if (!SG(request_info).path_translated) { + sapi_cgi_log_message("Warning: got null primary script path. You may need to adjust web server configuration or cgi.discard_path in php.ini to agree on CGI variables."); +@@ -1910,13 +1892,8 @@ + } + + php_request_shutdown((void *) 0); +- SG(server_context) = NULL; +- php_module_shutdown(TSRMLS_C); +- sapi_shutdown(); +-#ifdef ZTS +- tsrm_shutdown(); +-#endif +- return FAILURE; ++ exit_status = FAILURE; ++ goto out; + } + } + diff -uNr a/gports/php56/gales-ini-defaults.patch b/gports/php56/gales-ini-defaults.patch --- a/gports/php56/gales-ini-defaults.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/gales-ini-defaults.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,526 @@ +diff -ur a/ext/session/session.c b/ext/session/session.c +--- a/ext/session/session.c 2018-02-27 23:15:25 +0000 ++++ b/ext/session/session.c 2026-08-05 21:49:01 +0000 +@@ -797,7 +797,7 @@ + STD_PHP_INI_ENTRY("session.cookie_path", "/", PHP_INI_ALL, OnUpdateString, cookie_path, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.cookie_domain", "", PHP_INI_ALL, OnUpdateString, cookie_domain, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.cookie_secure", "", PHP_INI_ALL, OnUpdateBool, cookie_secure, php_ps_globals, ps_globals) +- STD_PHP_INI_BOOLEAN("session.cookie_httponly", "", PHP_INI_ALL, OnUpdateBool, cookie_httponly, php_ps_globals, ps_globals) ++ STD_PHP_INI_BOOLEAN("session.cookie_httponly", "1", PHP_INI_ALL, OnUpdateBool, cookie_httponly, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.use_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_cookies, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.use_only_cookies", "1", PHP_INI_ALL, OnUpdateBool, use_only_cookies, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.use_strict_mode", "0", PHP_INI_ALL, OnUpdateBool, use_strict_mode, php_ps_globals, ps_globals) +diff -ur a/main/main.c b/main/main.c +--- a/main/main.c 2026-08-05 21:48:40 +0000 ++++ b/main/main.c 2026-08-05 21:49:01 +0000 +@@ -556,7 +556,7 @@ + STD_PHP_INI_ENTRY_EX("display_errors", "1", PHP_INI_ALL, OnUpdateDisplayErrors, display_errors, php_core_globals, core_globals, display_errors_mode) + STD_PHP_INI_BOOLEAN("display_startup_errors", "0", PHP_INI_ALL, OnUpdateBool, display_startup_errors, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("enable_dl", "1", PHP_INI_SYSTEM, OnUpdateBool, enable_dl, php_core_globals, core_globals) +- STD_PHP_INI_BOOLEAN("expose_php", "1", PHP_INI_SYSTEM, OnUpdateBool, expose_php, php_core_globals, core_globals) ++ STD_PHP_INI_BOOLEAN("expose_php", "0", PHP_INI_SYSTEM, OnUpdateBool, expose_php, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("docref_root", "", PHP_INI_ALL, OnUpdateString, docref_root, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("docref_ext", "", PHP_INI_ALL, OnUpdateString, docref_ext, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("html_errors", "1", PHP_INI_ALL, OnUpdateBool, html_errors, php_core_globals, core_globals) +diff -ur a/php.ini-development b/php.ini-development +--- a/php.ini-development 2026-08-05 21:48:40 +0000 ++++ b/php.ini-development 2026-08-05 21:49:01 +0000 +@@ -360,7 +360,7 @@ + ; threat in any way, but it makes it possible to determine whether you use PHP + ; on your server or not. + ; http://php.net/expose-php +-expose_php = On ++;expose_php = On + + ;;;;;;;;;;;;;;;;;;; + ; Resource Limits ; +@@ -1486,7 +1486,8 @@ + + ; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. + ; http://php.net/session.cookie-httponly +-session.cookie_httponly = ++; Gales Linux change: default is now 1 ++;session.cookie_httponly = 0 + + ; Handler used to serialize data. php is the standard serializer of PHP. + ; http://php.net/session.serialize-handler +diff -ur a/php.ini-production b/php.ini-production +--- a/php.ini-production 2026-08-05 21:48:40 +0000 ++++ b/php.ini-production 2026-08-05 21:49:01 +0000 +@@ -360,7 +360,7 @@ + ; threat in any way, but it makes it possible to determine whether you use PHP + ; on your server or not. + ; http://php.net/expose-php +-expose_php = On ++;expose_php = On + + ;;;;;;;;;;;;;;;;;;; + ; Resource Limits ; +@@ -1486,7 +1486,8 @@ + + ; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. + ; http://php.net/session.cookie-httponly +-session.cookie_httponly = ++; Gales Linux change: default is now 1 ++;session.cookie_httponly = 0 + + ; Handler used to serialize data. php is the standard serializer of PHP. + ; http://php.net/session.serialize-handler +diff -ur a/sapi/cgi/tests/002.phpt b/sapi/cgi/tests/002.phpt +--- a/sapi/cgi/tests/002.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/002.phpt 2026-08-06 04:49:15 +0000 +@@ -28,23 +28,19 @@ + echo "Done\n"; + ?> + --EXPECTF-- +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r ++string(%d) "Content-type: text/html%r; charset=.*|%r + + %unicode|string%(3) "111" + " +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r ++string(%d) "Content-type: text/html%r; charset=.*|%r + + %unicode|string%(3) "500" + " +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r ++string(%d) "Content-type: text/html%r; charset=.*|%r + + %unicode|string%(3) "555" + " +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r ++string(%d) "Content-type: text/html%r; charset=.*|%r + + %unicode|string%(3) "555" + %unicode|string%(10) "/test/path" +diff -ur a/sapi/cgi/tests/009.phpt b/sapi/cgi/tests/009.phpt +--- a/sapi/cgi/tests/009.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/009.phpt 2026-08-06 04:50:17 +0000 +@@ -23,7 +23,6 @@ + @unlink($f); + ?> + --EXPECTF-- +-X-Powered-By: PHP/%s + Content-type: text/html%r; charset=.*|%r + + string(%d) "%s/x" +diff -ur a/sapi/cgi/tests/010.phpt b/sapi/cgi/tests/010.phpt +--- a/sapi/cgi/tests/010.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/010.phpt 2026-08-06 04:50:47 +0000 +@@ -39,14 +39,11 @@ + ?> + --EXPECTF-- + Status: 403 Forbidden +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + Status: 403 Forbidden +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + +-X-Powered-By: PHP/%s + Status: 403 Also Forbidden + Content-type: text/html; charset=UTF-8 + +diff -ur a/sapi/cgi/tests/011.phpt b/sapi/cgi/tests/011.phpt +--- a/sapi/cgi/tests/011.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/011.phpt 2026-08-06 04:51:44 +0000 +@@ -64,7 +64,6 @@ + ---------- + + ---------- +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + ---------- +@@ -75,7 +74,6 @@ + ---------- + + ---------- +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + ---------- +@@ -83,7 +81,6 @@ + header("X-Foo: Bar"); + ?> + ---------- +-X-Powered-By: PHP/%s + X-Foo: Bar + Content-type: text/html; charset=UTF-8 + +@@ -94,7 +91,6 @@ + header_remove("X-Foo"); + ?> + ---------- +-X-Powered-By: PHP/%s + X-Bar: Baz + Content-type: text/html; charset=UTF-8 + +@@ -104,7 +100,6 @@ + header_remove("X-Foo: Bar"); + ?> + ---------- +-X-Powered-By: PHP/%s + X-Foo: Bar + Content-type: text/html; charset=UTF-8 + +@@ -116,7 +111,6 @@ + header_remove("X-Foo:"); + ?> + ---------- +-X-Powered-By: PHP/%s + X-Foo: Bar + Content-type: text/html; charset=UTF-8 + +@@ -135,7 +129,6 @@ + header_remove(""); + ?> + ---------- +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + ---------- +@@ -143,7 +136,6 @@ + header_remove(":"); + ?> + ---------- +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + +@@ -156,7 +148,6 @@ + header_remove("X-Foo"); + ?> + ---------- +-X-Powered-By: PHP/%s + X-Foo: Bar + Content-type: text/html; charset=UTF-8 + +diff -ur a/sapi/cgi/tests/apache_request_headers.phpt b/sapi/cgi/tests/apache_request_headers.phpt +--- a/sapi/cgi/tests/apache_request_headers.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/apache_request_headers.phpt 2026-08-06 04:52:55 +0000 +@@ -30,7 +30,6 @@ + echo "Done\n"; + ?> + --EXPECTF-- +-X-Powered-By: PHP/%s + Content-type: text/%s + + Array +diff -ur a/sapi/cli/tests/bug43177.phpt b/sapi/cli/tests/bug43177.phpt +--- a/sapi/cli/tests/bug43177.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug43177.phpt 2026-08-06 05:05:53 +0000 +@@ -59,24 +59,20 @@ + HTTP/1.1 200 OK + Host: localhost + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + OK + HTTP/1.0 500 Internal Server Error + Host: localhost + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + HTTP/1.0 500 Internal Server Error + Host: localhost + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + HTTP/1.0 500 Internal Server Error + Host: localhost + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 +diff -ur a/sapi/cli/tests/bug65066_100.phpt b/sapi/cli/tests/bug65066_100.phpt +--- a/sapi/cli/tests/bug65066_100.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug65066_100.phpt 2026-08-06 05:05:59 +0000 +@@ -35,5 +35,4 @@ + HTTP/1.1 100 Continue + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 +diff -ur a/sapi/cli/tests/bug65066_422.phpt b/sapi/cli/tests/bug65066_422.phpt +--- a/sapi/cli/tests/bug65066_422.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug65066_422.phpt 2026-08-06 05:06:01 +0000 +@@ -35,5 +35,4 @@ + HTTP/1.1 422 Unknown Status Code + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 +diff -ur a/sapi/cli/tests/bug65066_511.phpt b/sapi/cli/tests/bug65066_511.phpt +--- a/sapi/cli/tests/bug65066_511.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug65066_511.phpt 2026-08-06 05:06:02 +0000 +@@ -35,5 +35,4 @@ + HTTP/1.1 511 Network Authentication Required + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 +diff -ur a/sapi/cli/tests/bug65633.phpt b/sapi/cli/tests/bug65633.phpt +--- a/sapi/cli/tests/bug65633.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug65633.phpt 2026-08-06 05:06:04 +0000 +@@ -38,7 +38,6 @@ + --EXPECTF-- + HTTP/1.1 200 OK + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + array(1) { +diff -ur a/sapi/cli/tests/bug66606_2.phpt b/sapi/cli/tests/bug66606_2.phpt +--- a/sapi/cli/tests/bug66606_2.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug66606_2.phpt 2026-08-06 05:06:06 +0000 +@@ -39,7 +39,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(33) "application/x-www-form-urlencoded" +diff -ur a/sapi/cli/tests/bug66830.phpt b/sapi/cli/tests/bug66830.phpt +--- a/sapi/cli/tests/bug66830.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug66830.phpt 2026-08-06 05:06:08 +0000 +@@ -38,6 +38,5 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + +diff -ur a/sapi/cli/tests/bug67429.phpt b/sapi/cli/tests/bug67429.phpt +--- a/sapi/cli/tests/bug67429.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug67429.phpt 2026-08-06 05:06:13 +0000 +@@ -39,11 +39,9 @@ + --EXPECTF-- + HTTP/1.1 308 Permanent Redirect + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + HTTP/1.1 426 Upgrade Required + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + +diff -ur a/sapi/cli/tests/bug68745.phpt b/sapi/cli/tests/bug68745.phpt +--- a/sapi/cli/tests/bug68745.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/bug68745.phpt 2026-08-06 05:06:21 +0000 +@@ -28,7 +28,6 @@ + --EXPECTF-- + HTTP/1.1 200 OK + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + int(%d) +diff -ur a/sapi/cli/tests/php_cli_server_004.phpt b/sapi/cli/tests/php_cli_server_004.phpt +--- a/sapi/cli/tests/php_cli_server_004.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_004.phpt 2026-08-06 05:06:25 +0000 +@@ -39,7 +39,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(19) "HTTP_HOST:localhost" +diff -ur a/sapi/cli/tests/php_cli_server_005.phpt b/sapi/cli/tests/php_cli_server_005.phpt +--- a/sapi/cli/tests/php_cli_server_005.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_005.phpt 2026-08-06 05:06:31 +0000 +@@ -51,7 +51,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + array(1) { +diff -ur a/sapi/cli/tests/php_cli_server_006.phpt b/sapi/cli/tests/php_cli_server_006.phpt +--- a/sapi/cli/tests/php_cli_server_006.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_006.phpt 2026-08-06 05:06:38 +0000 +@@ -35,7 +35,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(3) "foo" +diff -ur a/sapi/cli/tests/php_cli_server_007.phpt b/sapi/cli/tests/php_cli_server_007.phpt +--- a/sapi/cli/tests/php_cli_server_007.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_007.phpt 2026-08-06 05:06:43 +0000 +@@ -35,6 +35,5 @@ + HTTP/1.1 401 Unauthorized + Host: %s + Connection: close +-X-Powered-By: PHP/%s + WWW-Authenticate: Digest realm="foo",qop="auth",nonce="XXXXX",opaque="acbd18db4cc2f85cedef654fccc4a4d8" + Content-type: text/html; charset=UTF-8 +diff -ur a/sapi/cli/tests/php_cli_server_008.phpt b/sapi/cli/tests/php_cli_server_008.phpt +--- a/sapi/cli/tests/php_cli_server_008.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_008.phpt 2026-08-06 05:06:46 +0000 +@@ -55,14 +55,12 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(8) "HTTP/1.1" + HTTP/1.0 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(8) "HTTP/1.0" +diff -ur a/sapi/cli/tests/php_cli_server_009.phpt b/sapi/cli/tests/php_cli_server_009.phpt +--- a/sapi/cli/tests/php_cli_server_009.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_009.phpt 2026-08-06 05:06:49 +0000 +@@ -79,14 +79,12 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(8) "/foo/bar" + HTTP/1.0 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(9) "/foo/bar/" +diff -ur a/sapi/cli/tests/php_cli_server_010.phpt b/sapi/cli/tests/php_cli_server_010.phpt +--- a/sapi/cli/tests/php_cli_server_010.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_010.phpt 2026-08-06 05:06:53 +0000 +@@ -56,7 +56,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(18) "/index.php/foo/bar" +@@ -66,7 +65,6 @@ + HTTP/1.0 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + string(19) "/index.php/foo/bar/" +diff -ur a/sapi/cli/tests/php_cli_server_012.phpt b/sapi/cli/tests/php_cli_server_012.phpt +--- a/sapi/cli/tests/php_cli_server_012.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_012.phpt 2026-08-06 05:06:54 +0000 +@@ -41,7 +41,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + + Array +diff -ur a/sapi/cli/tests/php_cli_server_014.phpt b/sapi/cli/tests/php_cli_server_014.phpt +--- a/sapi/cli/tests/php_cli_server_014.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_014.phpt 2026-08-06 05:06:57 +0000 +@@ -66,7 +66,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: %s + Content-type: %s + + done +diff -ur a/sapi/cli/tests/php_cli_server_015.phpt b/sapi/cli/tests/php_cli_server_015.phpt +--- a/sapi/cli/tests/php_cli_server_015.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_015.phpt 2026-08-06 05:06:59 +0000 +@@ -42,7 +42,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: PHP/%s + Content-type: text/html; charset=UTF-8 + +
+diff -ur a/sapi/cli/tests/php_cli_server_017.phpt b/sapi/cli/tests/php_cli_server_017.phpt +--- a/sapi/cli/tests/php_cli_server_017.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_017.phpt 2026-08-06 05:07:01 +0000 +@@ -38,7 +38,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + string(%d) "%sindex.php" +diff -ur a/sapi/cli/tests/php_cli_server_018.phpt b/sapi/cli/tests/php_cli_server_018.phpt +--- a/sapi/cli/tests/php_cli_server_018.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_018.phpt 2026-08-06 05:07:02 +0000 +@@ -38,7 +38,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: %s + Content-type: text/html; charset=UTF-8 + + string(5) "PATCH" +diff -ur a/sapi/cli/tests/php_cli_server_019.phpt b/sapi/cli/tests/php_cli_server_019.phpt +--- a/sapi/cli/tests/php_cli_server_019.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cli/tests/php_cli_server_019.phpt 2026-08-06 05:07:18 +0000 +@@ -42,7 +42,6 @@ + HTTP/1.1 200 OK + Host: %s + Connection: close +-X-Powered-By: %s + Bar-Foo: Foo + Content-type: text/html; charset=UTF-8 + +@@ -58,9 +57,7 @@ + ["Foo-Bar"]=> + string(3) "Bar" + } +-array(3) { +- ["X-Powered-By"]=> +- string(%d) "P%s" ++array(2) { + ["Bar-Foo"]=> + string(3) "Foo" + ["Content-type"]=> +diff -ur a/tests/basic/024.phpt b/tests/basic/024.phpt +--- a/tests/basic/024.phpt 2018-02-27 23:15:25 +0000 ++++ b/tests/basic/024.phpt 2026-08-06 00:30:57 +0000 +@@ -11,8 +11,6 @@ + ?> + --EXPECT-- + Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input stream instead. in Unknown on line 0 +- +-Warning: Cannot modify header information - headers already sent in Unknown on line 0 + array(3) { + ["a"]=> + string(3) "ABC" +diff -ur a/tests/basic/026.phpt b/tests/basic/026.phpt +--- a/tests/basic/026.phpt 2018-02-27 23:15:25 +0000 ++++ b/tests/basic/026.phpt 2026-08-06 04:02:12 +0000 +@@ -11,8 +11,6 @@ + ?> + --EXPECT-- + Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input stream instead. in Unknown on line 0 +- +-Warning: Cannot modify header information - headers already sent in Unknown on line 0 + array(0) { + } + string(9) "a=1&b=ZYX" diff -uNr a/gports/php56/misc-test-fixes.patch b/gports/php56/misc-test-fixes.patch --- a/gports/php56/misc-test-fixes.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/misc-test-fixes.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,455 @@ +iconv tests assumed GNU extensions, breaking for musl. + +XML tests assumed libxml2 behavior, breaking for expat. + +Socket tests matched exact error strings, breaking for musl. Some even attempted live connections to Yahoo just for testing the local interface. + +proc_open02.phpt assumed bash behavior, breaking for standard shells; it meant to terminate the sleep process but ended up signalling the intermediate 'sh -c' to no effect. + +In bug46699.phpt, expat invoked its callback on all newlines, where libxml2 evidently didn't, giving different output wrapping. + +xml_error_string_variation1.phpt is largely noise, fuzzing the function interface with bad data types as if nobody ever heard of common type checking infrastructure. The particular error strings or NULLs that come out of xml_error_string for values that manage to convert to int are implementation dependent. + +In xml_set_start_namespace_decl_handler_basic.phpt, expat sensibly invoked the Namespace_End_Handler callback at end of block, where libxml2 evidently didn't, so despite calling xml_set_end_namespace_decl_handler they were never effectively testing it. + + -jfw + +diff -ur a/ext/iconv/tests/bug48147.phpt b/ext/iconv/tests/bug48147.phpt +--- a/ext/iconv/tests/bug48147.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/iconv/tests/bug48147.phpt 2026-08-08 01:32:37 +0000 +@@ -2,6 +2,9 @@ + Bug #48147 (iconv with //IGNORE cuts the string) + --SKIPIF-- + ++ + --FILE-- + - #phparty7 - @phpsp - novatec/2015 - sao paulo - br + --SKIPIF-- + + --FILE-- + +- + --EXPECTF-- + okey +diff -ur a/ext/sockets/tests/socket_shutdown.phpt b/ext/sockets/tests/socket_shutdown.phpt +--- a/ext/sockets/tests/socket_shutdown.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/sockets/tests/socket_shutdown.phpt 2026-08-08 01:21:49 +0000 +@@ -1,20 +1,17 @@ + --TEST-- + bool socket_shutdown ( resource $socket [, int $how = 2 ] ) ; +---CREDITS-- +-marcosptf - - #phparty7 - @phpsp - novatec/2015 - sao paulo - br + --SKIPIF-- + + --FILE-- + +---CLEAN-- +- + --EXPECTF-- + + Warning: socket_strerror() expects exactly 1 parameter, 0 given in %s on line %i +-string(7) "Success" +-string(23) "Operation not permitted" +-string(25) "No such file or directory" +-string(15) "No such process" +-string(23) "Interrupted system call" +-string(18) "Input/output error" +-string(25) "No such device or address" +-string(22) "Argument list too long" +-string(17) "Exec format error" +-string(19) "Bad file descriptor" +-string(18) "No child processes" +-string(32) "Resource temporarily unavailable" +-string(22) "Cannot allocate memory" +-string(17) "Permission denied" +-string(11) "Bad address" +-string(21) "Block device required" +-string(23) "Device or resource busy" +-string(11) "File exists" +-string(25) "Invalid cross-device link" +-string(14) "No such device" +-string(15) "Not a directory" +-string(14) "Is a directory" +-string(16) "Invalid argument" +-string(29) "Too many open files in system" +-string(19) "Too many open files" +-string(30) "Inappropriate ioctl for device" +-string(14) "Text file busy" +-string(14) "File too large" +-string(23) "No space left on device" +-string(12) "Illegal seek" +-string(21) "Read-only file system" +-string(14) "Too many links" +-string(11) "Broken pipe" +-string(32) "Numerical argument out of domain" +-string(29) "Numerical result out of range" +-string(25) "Resource deadlock avoided" +-string(18) "File name too long" +-string(18) "No locks available" +-string(24) "Function not implemented" +-string(19) "Directory not empty" +-string(33) "Too many levels of symbolic links" +-string(16) "Unknown error 41" +-string(26) "No message of desired type" +-string(18) "Identifier removed" +-string(27) "Channel number out of range" +-string(24) "Level 2 not synchronized" +-string(14) "Level 3 halted" +-string(13) "Level 3 reset" +-string(24) "Link number out of range" +-string(28) "Protocol driver not attached" +-string(26) "No CSI structure available" +-string(14) "Level 2 halted" +-string(16) "Invalid exchange" +-string(26) "Invalid request descriptor" +-string(13) "Exchange full" +-string(8) "No anode" +-string(20) "Invalid request code" +-string(12) "Invalid slot" +-string(16) "Unknown error 58" +-string(20) "Bad font file format" +-string(19) "Device not a stream" +-string(17) "No data available" +-string(13) "Timer expired" +-string(24) "Out of streams resources" +-string(29) "Machine is not on the network" +-string(21) "Package not installed" +-string(16) "Object is remote" +-string(21) "Link has been severed" +-string(15) "Advertise error" +-string(13) "Srmount error" +-string(27) "Communication error on send" +-string(14) "Protocol error" +-string(18) "Multihop attempted" +-string(18) "RFS specific error" +-string(11) "Bad message" +-string(37) "Value too large for defined data type" +-string(26) "Name not unique on network" +-string(28) "File descriptor in bad state" +-string(22) "Remote address changed" +-string(38) "Can not access a needed shared library" +-string(36) "Accessing a corrupted shared library" +-string(31) ".lib section in a.out corrupted" +-string(47) "Attempting to link in too many shared libraries" +-string(37) "Cannot exec a shared library directly" +-string(49) "Invalid or incomplete multibyte or wide character" +-string(43) "Interrupted system call should be restarted" +-string(18) "Streams pipe error" +-string(14) "Too many users" +-string(30) "Socket operation on non-socket" +-string(28) "Destination address required" +-string(16) "Message too long" +-string(30) "Protocol wrong type for socket" +-string(22) "Protocol not available" +-string(22) "Protocol not supported" +-string(25) "Socket type not supported" +-string(23) "Operation not supported" +-string(29) "Protocol family not supported" +-string(40) "Address family not supported by protocol" +-string(22) "Address already in use" +-string(31) "Cannot assign requested address" +-string(15) "Network is down" +-string(22) "Network is unreachable" +-string(35) "Network dropped connection on reset" +-string(32) "Software caused connection abort" +-string(24) "Connection reset by peer" +-string(25) "No buffer space available" +-string(39) "Transport endpoint is already connected" +-string(35) "Transport endpoint is not connected" +-string(45) "Cannot send after transport endpoint shutdown" +-string(34) "Too many references: cannot splice" +-string(20) "Connection timed out" +-string(18) "Connection refused" +-string(12) "Host is down" +-string(16) "No route to host" +-string(29) "Operation already in progress" +-string(25) "Operation now in progress" +-string(%d) "Stale%sfile handle" +-string(24) "Structure needs cleaning" +-string(27) "Not a XENIX named type file" +-string(29) "No XENIX semaphores available" +-string(20) "Is a named type file" +-string(16) "Remote I/O error" +-string(19) "Disk quota exceeded" +-string(15) "No medium found" +-string(17) "Wrong medium type" +-string(18) "Operation canceled" +-string(26) "Required key not available" +-string(15) "Key has expired" +-string(20) "Key has been revoked" +-string(27) "Key was rejected by service" +-string(10) "Owner died" +-string(21) "State not recoverable" +-string(%d) "%s" +diff -ur a/ext/standard/tests/general_functions/proc_open02.phpt b/ext/standard/tests/general_functions/proc_open02.phpt +--- a/ext/standard/tests/general_functions/proc_open02.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/standard/tests/general_functions/proc_open02.phpt 2026-08-08 01:21:49 +0000 +@@ -10,7 +10,7 @@ + $ds = array(array('pipe', 'r')); + + $cat = proc_open( +- '/bin/sleep 2', ++ 'exec /bin/sleep 2', + $ds, + $pipes + ); +@@ -34,7 +34,7 @@ + bool(true) + array(8) { + ["command"]=> +- string(12) "/bin/sleep 2" ++ string(17) "exec /bin/sleep 2" + ["pid"]=> + int(%d) + ["running"]=> +@@ -53,7 +53,7 @@ + bool(true) + array(8) { + ["command"]=> +- string(12) "/bin/sleep 2" ++ string(17) "exec /bin/sleep 2" + ["pid"]=> + int(%d) + ["running"]=> +diff -ur a/ext/xml/tests/bug46699.phpt b/ext/xml/tests/bug46699.phpt +--- a/ext/xml/tests/bug46699.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/bug46699.phpt 2026-08-08 01:21:49 +0000 +@@ -13,8 +13,7 @@ + } + + $xml = << ++ + 1 + 2 + +diff -ur a/ext/xml/tests/xml_error_string_variation1.phpt b/ext/xml/tests/xml_error_string_variation1.phpt +--- a/ext/xml/tests/xml_error_string_variation1.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_error_string_variation1.phpt 2026-08-08 01:21:49 +0000 +@@ -87,19 +87,19 @@ + *** Testing xml_error_string() : usage variations *** + + Arg value 10.5 +-string(22) "XML_ERR_CHARREF_AT_EOF" ++%A + + Arg value -10.5 +-string(7) "Unknown" ++%A + + Arg value 101234567000 +-string(7) "Unknown" ++%A + + Arg value 1.07654321E-9 +-string(8) "No error" ++%A + + Arg value 0.5 +-string(8) "No error" ++%A + + Arg value Array + +@@ -127,22 +127,22 @@ + NULL + + Arg value +-string(8) "No error" ++%A + + Arg value +-string(8) "No error" ++%A + + Arg value 1 +-string(9) "No memory" ++%A + + Arg value +-string(8) "No error" ++%A + + Arg value 1 +-string(9) "No memory" ++%A + + Arg value +-string(8) "No error" ++%A + + Arg value + +@@ -170,10 +170,10 @@ + NULL + + Arg value +-string(8) "No error" ++%A + + Arg value +-string(8) "No error" ++%A + Done + + +diff -ur a/ext/xml/tests/xml_set_start_namespace_decl_handler_basic.phpt b/ext/xml/tests/xml_set_start_namespace_decl_handler_basic.phpt +--- a/ext/xml/tests/xml_set_start_namespace_decl_handler_basic.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/xml/tests/xml_set_start_namespace_decl_handler_basic.phpt 2026-08-08 01:21:49 +0000 +@@ -26,7 +26,6 @@ + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); + + var_dump(xml_set_start_namespace_decl_handler( $parser, "Namespace_Start_Handler" )); +-var_dump(xml_set_end_namespace_decl_handler( $parser, "Namespace_End_Handler" )); + + xml_parse( $parser, $xml, true); + xml_parser_free( $parser ); +@@ -38,19 +37,9 @@ + echo "...Prefix: ". $prefix . "\n"; + echo "...Uri: ". $uri . "\n"; + } +- +-function Namespace_End_Handler($parser, $prefix) { +- echo "Namespace_End_Handler called\n"; +- echo "...Prefix: ". $prefix . "\n\n"; +-} +- +-function DefaultHandler( $parser, $data ) { +- print( 'DefaultHandler Called
' ); +-} + ?> + --EXPECT-- + bool(true) +-bool(true) + Namespace_Start_Handler called + ...Prefix: aw1 + ...Uri: http://www.somewhere.com/namespace1 diff -uNr a/gports/php56/run b/gports/php56/run --- a/gports/php56/run 1970-01-01 00:00:00 +0000 +++ b/gports/php56/run 1970-01-01 00:00:00 +0000 @@ -1,12 +1,20 @@ #!/bin/sh exec 2>&1 -sockdir=/var/run/php-fastcgi -if ! [ -d $sockdir ]; then - mkdir $sockdir - chown php:php $sockdir + +USER=php +SOCKDIR=/var/run/php-fastcgi + +# $SOCKDIR must be accessible *only* to apache and the target php-cgi user. Otherwise, anyone on the server can control the php process with credentials of the target user, for instance, to read out secret files from the victim or execute code in php files supplied by the attacker. (php-cgi doesn't limit script execution to "user's designated webspace" or the like, trusting Apache for that.) +if ! [ -d $SOCKDIR ]; then + mkdir -p -m 750 $SOCKDIR + chown $USER:apache $SOCKDIR fi + # defaults are as shown in comments #export PHP_FCGI_BACKLOG=128 #export PHP_FCGI_MAX_REQUESTS=500 -#export PHP_FCGI_CHILDREN=0 -exec setuidgid php php-cgi -b $sockdir/sock + +# Concurrency via preforked worker processes. The default of 0 means a single worker with no subprocess management, and it still exits after PHP_FCGI_MAX_REQUESTS, leaving nothing listening on the socket until supervise respawns it. So it doesn't make much sense for production. +export PHP_FCGI_CHILDREN=4 + +exec setuidgid $USER php-cgi -b $SOCKDIR/sock diff -uNr a/gports/php56/secure-pathinfo.patch b/gports/php56/secure-pathinfo.patch --- a/gports/php56/secure-pathinfo.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/secure-pathinfo.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,632 @@ +diff -ur a/php.ini-development b/php.ini-development +--- a/php.ini-development 2018-02-27 23:15:25 +0000 ++++ b/php.ini-development 2026-08-07 05:48:58 +0000 +@@ -761,19 +761,17 @@ + ; http://php.net/cgi.redirect-status-env + ;cgi.redirect_status_env = + +-; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +-; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +-; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +-; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +-; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +-; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +-; http://php.net/cgi.fix-pathinfo +-;cgi.fix_pathinfo=1 +- +-; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside +-; of the web tree and people will not be able to circumvent .htaccess security. +-; http://php.net/cgi.dicard-path +-;cgi.discard_path=1 ++; If cgi.discard_path is enabled, php-cgi ignores the CGI environment's PATH_TRANSLATED and executes SCRIPT_FILENAME. This works for FastCGI, provided of course that the web server correctly sets SCRIPT_FILENAME. It can also work for classical subprocess CGI, provided that the PHP script itself is indicated as the CGI program. That involves using a wrapper script or #! line to execute it under the php-cgi interpreter, with the interpreter kept outside of the web tree. Either way, PATH_INFO and PATH_TRANSLATED are safely available for application use, containing any URL path components that follow the script name (e.g. /yourscript.php/your/file). This is now the default and recommended setting. ++; ++; If disabled, php-cgi executes PATH_TRANSLATED. This supports classical subprocess CGI where SCRIPT_FILENAME is the interpreter binary (URLs like /cgi-bin/php-cgi/yourscript.php) and thus the script path must come from PATH_INFO/PATH_TRANSLATED. It may likewise help support some broken servers that "do not have script_filename or argv0; an example, IIS configured in some ways" (so say the old comments). Note that php-cgi's location in URL space must be blocked from direct access, otherwise web server controls can be bypassed by getting PHP to read out or even execute arbitrary files just by naming them in the PATH_INFO. (See also cgi.force_redirect which tries to block this by default, working with e.g. Apache's Action.) Obviously, PATH_INFO cannot be meaningfully available for application use since it's already used for identifying the script. If you require PATH_INFO for URL path components following the script name, use a configuration that allows the web server to send it. ++; ++; Changes introduced by Gales Linux for security through predictability: ++; - Removed cgi.fix_pathinfo hack from PHP 4.3; it was a shoddy unconfigurable reimplementation of web server functionality, which created new trouble for gateway configurations based on URL regex matching. ++; - Changed cgi.discard_path to act as a simple, unconditional selector for which CGI variable protocol to use; if server and PHP settings disagree then failure will be loud and early. Previously, both cases would fall back, through various code paths, to the opposite variable if the intended one was unset. These efforts to "do what I mean", further complicated by fix_pathinfo, resulted in hiding potentially insecure misconfigurations. ++; - Corrected buggy implementation of cgi.discard_path=1 where PHP_SELF still got PATH_INFO rather than SCRIPT_NAME (known but unfixed upstream for 11 years, https://bugs.php.net/bug.php?id=68053). ++; - Changed cgi.discard_path default from 0 to 1. ++; ++;cgi.discard_path=0 + + ; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate + ; security tokens of the calling client. This allows IIS to define the +diff -ur a/php.ini-production b/php.ini-production +--- a/php.ini-production 2018-02-27 23:15:25 +0000 ++++ b/php.ini-production 2026-08-07 05:48:58 +0000 +@@ -761,19 +761,17 @@ + ; http://php.net/cgi.redirect-status-env + ;cgi.redirect_status_env = + +-; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +-; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +-; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +-; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +-; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +-; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +-; http://php.net/cgi.fix-pathinfo +-;cgi.fix_pathinfo=1 +- +-; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside +-; of the web tree and people will not be able to circumvent .htaccess security. +-; http://php.net/cgi.dicard-path +-;cgi.discard_path=1 ++; If cgi.discard_path is enabled, php-cgi ignores the CGI environment's PATH_TRANSLATED and executes SCRIPT_FILENAME. This works for FastCGI, provided of course that the web server correctly sets SCRIPT_FILENAME. It can also work for classical subprocess CGI, provided that the PHP script itself is indicated as the CGI program. That involves using a wrapper script or #! line to execute it under the php-cgi interpreter, with the interpreter kept outside of the web tree. Either way, PATH_INFO and PATH_TRANSLATED are safely available for application use, containing any URL path components that follow the script name (e.g. /yourscript.php/your/file). This is now the default and recommended setting. ++; ++; If disabled, php-cgi executes PATH_TRANSLATED. This supports classical subprocess CGI where SCRIPT_FILENAME is the interpreter binary (URLs like /cgi-bin/php-cgi/yourscript.php) and thus the script path must come from PATH_INFO/PATH_TRANSLATED. It may likewise help support some broken servers that "do not have script_filename or argv0; an example, IIS configured in some ways" (so say the old comments). Note that php-cgi's location in URL space must be blocked from direct access, otherwise web server controls can be bypassed by getting PHP to read out or even execute arbitrary files just by naming them in the PATH_INFO. (See also cgi.force_redirect which tries to block this by default, working with e.g. Apache's Action.) Obviously, PATH_INFO cannot be meaningfully available for application use since it's already used for identifying the script. If you require PATH_INFO for URL path components following the script name, use a configuration that allows the web server to send it. ++; ++; Changes introduced by Gales Linux for security through predictability: ++; - Removed cgi.fix_pathinfo hack from PHP 4.3; it was a shoddy unconfigurable reimplementation of web server functionality, which created new trouble for gateway configurations based on URL regex matching. ++; - Changed cgi.discard_path to act as a simple, unconditional selector for which CGI variable protocol to use; if server and PHP settings disagree then failure will be loud and early. Previously, both cases would fall back, through various code paths, to the opposite variable if the intended one was unset. These efforts to "do what I mean", further complicated by fix_pathinfo, resulted in hiding potentially insecure misconfigurations. ++; - Corrected buggy implementation of cgi.discard_path=1 where PHP_SELF still got PATH_INFO rather than SCRIPT_NAME (known but unfixed upstream for 11 years, https://bugs.php.net/bug.php?id=68053). ++; - Changed cgi.discard_path default from 0 to 1. ++; ++;cgi.discard_path=0 + + ; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate + ; security tokens of the calling client. This allows IIS to define the +diff -ur a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c +--- a/sapi/cgi/cgi_main.c 2026-08-07 05:48:47 +0000 ++++ b/sapi/cgi/cgi_main.c 2026-08-07 05:48:58 +0000 +@@ -132,7 +132,6 @@ + zend_bool rfc2616_headers; + zend_bool nph; + zend_bool check_shebang_line; +- zend_bool fix_pathinfo; + zend_bool force_redirect; + zend_bool discard_path; + zend_bool fcgi_logging; +@@ -620,54 +619,7 @@ + */ + php_import_environment_variables(track_vars_array TSRMLS_CC); + +- if (CGIG(fix_pathinfo)) { +- char *script_name = SG(request_info).request_uri; +- char *path_info; +- int free_php_self; +- ALLOCA_FLAG(use_heap) +- +- if (fcgi_is_fastcgi()) { +- fcgi_request *request = (fcgi_request*) SG(server_context); +- +- path_info = FCGI_GETENV(request, "PATH_INFO"); +- } else { +- path_info = getenv("PATH_INFO"); +- } +- +- if (path_info) { +- unsigned int path_info_len = strlen(path_info); +- +- if (script_name) { +- unsigned int script_name_len = strlen(script_name); +- +- php_self_len = script_name_len + path_info_len; +- php_self = do_alloca(php_self_len + 1, use_heap); +- memcpy(php_self, script_name, script_name_len + 1); +- memcpy(php_self + script_name_len, path_info, path_info_len + 1); +- free_php_self = 1; +- } else { +- php_self = path_info; +- php_self_len = path_info_len; +- free_php_self = 0; +- } +- } else if (script_name) { +- php_self = script_name; +- php_self_len = strlen(script_name); +- free_php_self = 0; +- } else { +- php_self = ""; +- php_self_len = 0; +- free_php_self = 0; +- } +- +- /* Build the special-case PHP_SELF variable for the CGI version */ +- if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) { +- php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC); +- } +- if (free_php_self) { +- free_alloca(php_self, use_heap); +- } +- } else { ++ { + php_self = SG(request_info).request_uri ? SG(request_info).request_uri : ""; + php_self_len = strlen(php_self); + if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) { +@@ -1009,80 +961,16 @@ + + initializes request_info structure + +- specificly in this section we handle proper translations +- for: +- +- PATH_INFO +- derived from the portion of the URI path following +- the script name but preceding any query data +- may be empty +- +- PATH_TRANSLATED +- derived by taking any path-info component of the +- request URI and performing any virtual-to-physical +- translation appropriate to map it onto the server's +- document repository structure +- +- empty if PATH_INFO is empty ++ The CGI environment variable PATH_TRANSLATED **MAY BE DIFFERENT** than request_info's path_translated; the latter is the filesystem path of the PHP script to run, while the former is configuration dependent. + +- The env var PATH_TRANSLATED **IS DIFFERENT** than the +- request_info.path_translated variable, the latter should +- match SCRIPT_FILENAME instead. +- +- SCRIPT_NAME +- set to a URL path that could identify the CGI script +- rather than the interpreter. PHP_SELF is set to this +- +- REQUEST_URI +- uri section following the domain:port part of a URI +- +- SCRIPT_FILENAME +- The virtual-to-physical translation of SCRIPT_NAME (as per +- PATH_TRANSLATED) +- +- These settings are documented at +- http://cgi-spec.golux.com/ +- +- +- Based on the following URL request: +- +- http://localhost/info.php/test?a=b +- +- should produce, which btw is the same as if +- we were running under mod_cgi on apache (ie. not +- using ScriptAlias directives): +- +- PATH_INFO=/test +- PATH_TRANSLATED=/docroot/test +- SCRIPT_NAME=/info.php +- REQUEST_URI=/info.php/test?a=b +- SCRIPT_FILENAME=/docroot/info.php +- QUERY_STRING=a=b +- +- but what we get is (cgi/mod_fastcgi under apache): +- +- PATH_INFO=/info.php/test +- PATH_TRANSLATED=/docroot/info.php/test +- SCRIPT_NAME=/php/php-cgi (from the Action setting I suppose) +- REQUEST_URI=/info.php/test?a=b +- SCRIPT_FILENAME=/path/to/php/bin/php-cgi (Action setting translated) +- QUERY_STRING=a=b +- +- Comments in the code below refer to using the above URL in a request ++ Similarly, the PHP $_SERVER["REQUEST_URI"] variable **IS DIFFERENT** than request_info's request_uri; the latter is the URI path of the PHP script to run, while the former also includes any trailing PATH_INFO and QUERY_STRING components. + ++ request_uri is used to set PHP_SELF, and may override path_translated in specifying the script file if user_dir or doc_root mapping are in use (per php_fopen_primary_script). + */ + static void init_request_info(fcgi_request *request TSRMLS_DC) + { +- char *env_script_filename = CGI_GETENV("SCRIPT_FILENAME"); +- char *env_path_translated = CGI_GETENV("PATH_TRANSLATED"); +- char *script_path_translated = env_script_filename; +- +- /* some broken servers do not have script_filename or argv0 +- * an example, IIS configured in some ways. then they do more +- * broken stuff and set path_translated to the cgi script location */ +- if (!script_path_translated && env_path_translated) { +- script_path_translated = env_path_translated; +- } ++ char *script_path_translated = CGIG(discard_path) ? ++ CGI_GETENV("SCRIPT_FILENAME") : CGI_GETENV("PATH_TRANSLATED"); + + /* initialize the defaults */ + SG(request_info).path_translated = NULL; +@@ -1102,227 +990,9 @@ + const char *auth; + char *content_length = CGI_GETENV("CONTENT_LENGTH"); + char *content_type = CGI_GETENV("CONTENT_TYPE"); +- char *env_path_info = CGI_GETENV("PATH_INFO"); +- char *env_script_name = CGI_GETENV("SCRIPT_NAME"); + +- if (CGIG(fix_pathinfo)) { +- struct stat st; +- char *real_path = NULL; +- char *env_redirect_url = CGI_GETENV("REDIRECT_URL"); +- char *env_document_root = CGI_GETENV("DOCUMENT_ROOT"); +- char *orig_path_translated = env_path_translated; +- char *orig_path_info = env_path_info; +- char *orig_script_name = env_script_name; +- char *orig_script_filename = env_script_filename; +- int script_path_translated_len; +- +- if (!env_document_root && PG(doc_root)) { +- env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root)); +- } +- +- if (env_path_translated != NULL && env_redirect_url != NULL && +- env_path_translated != script_path_translated && +- strcmp(env_path_translated, script_path_translated) != 0) { +- /* +- * pretty much apache specific. If we have a redirect_url +- * then our script_filename and script_name point to the +- * php executable +- */ +- script_path_translated = env_path_translated; +- /* we correct SCRIPT_NAME now in case we don't have PATH_INFO */ +- env_script_name = env_redirect_url; +- } +- +-#ifdef __riscos__ +- /* Convert path to unix format*/ +- __riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR; +- script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0); +-#endif +- +- /* +- * if the file doesn't exist, try to extract PATH_INFO out +- * of it by stat'ing back through the '/' +- * this fixes url's like /info.php/test +- */ +- if (script_path_translated && +- (script_path_translated_len = strlen(script_path_translated)) > 0 && +- (script_path_translated[script_path_translated_len-1] == '/' || +- (real_path = tsrm_realpath(script_path_translated, NULL TSRMLS_CC)) == NULL) +- ) { +- char *pt = estrndup(script_path_translated, script_path_translated_len); +- int len = script_path_translated_len; +- char *ptr; +- +- while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) { +- *ptr = 0; +- if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) { +- /* +- * okay, we found the base script! +- * work out how many chars we had to strip off; +- * then we can modify PATH_INFO +- * accordingly +- * +- * we now have the makings of +- * PATH_INFO=/test +- * SCRIPT_FILENAME=/docroot/info.php +- * +- * we now need to figure out what docroot is. +- * if DOCUMENT_ROOT is set, this is easy, otherwise, +- * we have to play the game of hide and seek to figure +- * out what SCRIPT_NAME should be +- */ +- int slen = len - strlen(pt); +- int pilen = env_path_info ? strlen(env_path_info) : 0; +- char *path_info = env_path_info ? env_path_info + pilen - slen : NULL; +- +- if (orig_path_info != path_info) { +- if (orig_path_info) { +- char old; +- +- CGI_PUTENV("ORIG_PATH_INFO", orig_path_info); +- old = path_info[0]; +- path_info[0] = 0; +- if (!orig_script_name || +- strcmp(orig_script_name, env_path_info) != 0) { +- if (orig_script_name) { +- CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name); +- } +- SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_path_info); +- } else { +- SG(request_info).request_uri = orig_script_name; +- } +- path_info[0] = old; +- } +- env_path_info = CGI_PUTENV("PATH_INFO", path_info); +- } +- if (!orig_script_filename || +- strcmp(orig_script_filename, pt) != 0) { +- if (orig_script_filename) { +- CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename); +- } +- script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", pt); +- } +- +- /* figure out docroot +- * SCRIPT_FILENAME minus SCRIPT_NAME +- */ +- if (env_document_root) { +- int l = strlen(env_document_root); +- int path_translated_len = 0; +- char *path_translated = NULL; +- +- if (l && env_document_root[l - 1] == '/') { +- --l; +- } +- +- /* we have docroot, so we should have: +- * DOCUMENT_ROOT=/docroot +- * SCRIPT_FILENAME=/docroot/info.php +- */ +- +- /* PATH_TRANSLATED = DOCUMENT_ROOT + PATH_INFO */ +- path_translated_len = l + (env_path_info ? strlen(env_path_info) : 0); +- path_translated = (char *) emalloc(path_translated_len + 1); +- memcpy(path_translated, env_document_root, l); +- if (env_path_info) { +- memcpy(path_translated + l, env_path_info, (path_translated_len - l)); +- } +- path_translated[path_translated_len] = '\0'; +- if (orig_path_translated) { +- CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated); +- } +- env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated); +- efree(path_translated); +- } else if ( env_script_name && +- strstr(pt, env_script_name) +- ) { +- /* PATH_TRANSLATED = PATH_TRANSLATED - SCRIPT_NAME + PATH_INFO */ +- int ptlen = strlen(pt) - strlen(env_script_name); +- int path_translated_len = ptlen + (env_path_info ? strlen(env_path_info) : 0); +- char *path_translated = NULL; +- +- path_translated = (char *) emalloc(path_translated_len + 1); +- memcpy(path_translated, pt, ptlen); +- if (env_path_info) { +- memcpy(path_translated + ptlen, env_path_info, path_translated_len - ptlen); +- } +- path_translated[path_translated_len] = '\0'; +- if (orig_path_translated) { +- CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated); +- } +- env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated); +- efree(path_translated); +- } +- break; +- } +- } +- if (!ptr) { +- /* +- * if we stripped out all the '/' and still didn't find +- * a valid path... we will fail, badly. of course we would +- * have failed anyway... we output 'no input file' now. +- */ +- if (orig_script_filename) { +- CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename); +- } +- script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", NULL); +- SG(sapi_headers).http_response_code = 404; +- } +- if (!SG(request_info).request_uri) { +- if (!orig_script_name || +- strcmp(orig_script_name, env_script_name) != 0) { +- if (orig_script_name) { +- CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name); +- } +- SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name); +- } else { +- SG(request_info).request_uri = orig_script_name; +- } +- } +- if (pt) { +- efree(pt); +- } +- } else { +- /* make sure path_info/translated are empty */ +- if (!orig_script_filename || +- (script_path_translated != orig_script_filename && +- strcmp(script_path_translated, orig_script_filename) != 0)) { +- if (orig_script_filename) { +- CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename); +- } +- script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", script_path_translated); +- } +- if (env_redirect_url) { +- if (orig_path_info) { +- CGI_PUTENV("ORIG_PATH_INFO", orig_path_info); +- CGI_PUTENV("PATH_INFO", NULL); +- } +- if (orig_path_translated) { +- CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated); +- CGI_PUTENV("PATH_TRANSLATED", NULL); +- } +- } +- if (env_script_name != orig_script_name) { +- if (orig_script_name) { +- CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name); +- } +- SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name); +- } else { +- SG(request_info).request_uri = env_script_name; +- } +- efree(real_path); +- } +- } else { +- /* pre 4.3 behaviour, shouldn't be used but provides BC */ +- if (env_path_info) { +- SG(request_info).request_uri = env_path_info; +- } else { +- SG(request_info).request_uri = env_script_name; +- } +- if (!CGIG(discard_path) && env_path_translated) { +- script_path_translated = env_path_translated; +- } +- } ++ SG(request_info).request_uri = CGIG(discard_path) ? ++ CGI_GETENV("SCRIPT_NAME") : CGI_GETENV("PATH_INFO"); + + if (is_valid_path(script_path_translated)) { + SG(request_info).path_translated = estrdup(script_path_translated); +@@ -1368,8 +1038,7 @@ + STD_PHP_INI_ENTRY("cgi.check_shebang_line", "1", PHP_INI_SYSTEM, OnUpdateBool, check_shebang_line, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_ENTRY("cgi.force_redirect", "1", PHP_INI_SYSTEM, OnUpdateBool, force_redirect, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_ENTRY("cgi.redirect_status_env", NULL, PHP_INI_SYSTEM, OnUpdateString, redirect_status_env, php_cgi_globals_struct, php_cgi_globals) +- STD_PHP_INI_ENTRY("cgi.fix_pathinfo", "1", PHP_INI_SYSTEM, OnUpdateBool, fix_pathinfo, php_cgi_globals_struct, php_cgi_globals) +- STD_PHP_INI_ENTRY("cgi.discard_path", "0", PHP_INI_SYSTEM, OnUpdateBool, discard_path, php_cgi_globals_struct, php_cgi_globals) ++ STD_PHP_INI_ENTRY("cgi.discard_path", "1", PHP_INI_SYSTEM, OnUpdateBool, discard_path, php_cgi_globals_struct, php_cgi_globals) + STD_PHP_INI_ENTRY("fastcgi.logging", "1", PHP_INI_SYSTEM, OnUpdateBool, fcgi_logging, php_cgi_globals_struct, php_cgi_globals) + PHP_INI_END() + +@@ -1382,8 +1051,7 @@ + php_cgi_globals->check_shebang_line = 1; + php_cgi_globals->force_redirect = 1; + php_cgi_globals->redirect_status_env = NULL; +- php_cgi_globals->fix_pathinfo = 1; +- php_cgi_globals->discard_path = 0; ++ php_cgi_globals->discard_path = 1; + php_cgi_globals->fcgi_logging = 1; + zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, (dtor_func_t) user_config_cache_entry_dtor, 1); + } +@@ -2216,21 +1884,15 @@ + SG(request_info).no_headers = 1; + } + +- /* +- at this point path_translated will be set if: +- 1. we are running from shell and got filename was there +- 2. we are running as cgi or fastcgi +- */ + if (cgi || fastcgi || SG(request_info).path_translated) { ++ if (!SG(request_info).path_translated) { ++ sapi_cgi_log_message("Warning: got null primary script path. You may need to adjust web server configuration or cgi.discard_path in php.ini to agree on CGI variables."); ++ } + if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) { + zend_try { +- if (errno == EACCES) { +- SG(sapi_headers).http_response_code = 403; +- PUTS("Access denied.\n"); +- } else { +- SG(sapi_headers).http_response_code = 404; +- PUTS("No input file specified.\n"); +- } ++ /* path_translated is not reliable for reporting what was attempted, nor is errno reliable for reporting what happened here. So respond with a generic but correct message. */ ++ SG(sapi_headers).http_response_code = 404; ++ PUTS("404 Not Found\n

Unable to open primary script.

\n"); + } zend_catch { + } zend_end_try(); + /* we want to serve more requests if this is fastcgi +diff -ur a/sapi/cgi/tests/003.phpt b/sapi/cgi/tests/003.phpt +--- a/sapi/cgi/tests/003.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/003.phpt 2026-08-07 05:49:08 +0000 +@@ -32,31 +32,22 @@ + + file_put_contents($filename, $code); + +-var_dump(`$php -n -w "$filename"`); +-var_dump(`$php -n -w "wrong"`); +-var_dump(`echo "" | $php -n -w`); ++var_dump(`$php -n -w -q "$filename"`); ++var_dump(`$php -n -w -q "wrong"`); ++var_dump(`echo "" | $php -n -w -q`); + + @unlink($filename); + + echo "Done\n"; + ?> + --EXPECTF-- +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r +- +- ++string(%d) " + + " +-string(%d) "Status: 404 Not Found +-X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r +- +-No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ " +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r +- +- ++string(%d) " + " + Done +diff -ur a/sapi/cgi/tests/004.phpt b/sapi/cgi/tests/004.phpt +--- a/sapi/cgi/tests/004.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/004.phpt 2026-08-07 05:48:58 +0000 +@@ -38,6 +38,7 @@ +
+ Fatal error: Cannot access private property test::$pri in %s004.test.php on line 8
+ " +-string(25) "No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ " + Done +diff -ur a/sapi/cgi/tests/005.phpt b/sapi/cgi/tests/005.phpt +--- a/sapi/cgi/tests/005.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/005.phpt 2026-08-07 05:48:58 +0000 +@@ -16,11 +16,13 @@ + echo "Done\n"; + ?> + --EXPECTF-- +-string(51) "No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ Interactive mode enabled + + " +-string(51) "No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ Interactive mode enabled + + " +diff -ur a/sapi/cgi/tests/006.phpt b/sapi/cgi/tests/006.phpt +--- a/sapi/cgi/tests/006.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/006.phpt 2026-08-07 05:48:58 +0000 +@@ -53,7 +53,8 @@ + --EXPECTF-- + string(%d) "No syntax errors detected in %s006.test.php + " +-string(%d) "No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ " + string(%d) "
+ Parse error: %s expecting %s{%s in %s006.test.php on line 5
+diff -ur a/sapi/cgi/tests/007.phpt b/sapi/cgi/tests/007.phpt +--- a/sapi/cgi/tests/007.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/007.phpt 2026-08-07 05:48:58 +0000 +@@ -15,7 +15,8 @@ + ?> + ===DONE=== + --EXPECTF-- +-string(25) "No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ " + string(31) "No syntax errors detected in - + " +diff -ur a/sapi/cgi/tests/008.phpt b/sapi/cgi/tests/008.phpt +--- a/sapi/cgi/tests/008.phpt 2018-02-27 23:15:25 +0000 ++++ b/sapi/cgi/tests/008.phpt 2026-08-07 05:48:58 +0000 +@@ -30,25 +30,19 @@ + + file_put_contents($filename, $code); + +-var_dump(`"$php" -n -s "$filename"`); +-var_dump(`"$php" -n -s "unknown"`); ++var_dump(`"$php" -n -s -q "$filename"`); ++var_dump(`"$php" -n -s -q "unknown"`); + + @unlink($filename); + + echo "Done\n"; + ?> + --EXPECTF-- +-string(%d) "X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r +- +- ++string(%d) " +
<?php
$test 
"var"//var
/* test class */
class test {
    private 
$var = array();

    public static function 
foo(Test $arg) {
        echo 
"hello";
        
var_dump($this);
    }
}

$o = new test;
?>
+
+
" +-string(%d) "Status: 404 Not Found +-X-Powered-By: PHP/%s +-Content-type: text/html%r; charset=.*|%r +- +-No input file specified. ++string(%d) "404 Not Found ++

Unable to open primary script.

+ " + Done diff -uNr a/gports/php56/stable-test-env.patch b/gports/php56/stable-test-env.patch --- a/gports/php56/stable-test-env.patch 1970-01-01 00:00:00 +0000 +++ b/gports/php56/stable-test-env.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,70 @@ +First, ext/filter/tests/bug52209.phpt was a triple fail: + +* skip condition was inverted, so it always skipped when PWD *was* set and failed when it wasn't +* import of external environment is dependent on variables_order in php.ini for *the interpreter of run-tests.php*, not merely the well-controlled child processes under test +* PWD isn't even guaranteed to exist in external environment, and indeed doesn't under gbuild + +Then, ext/standard/tests/file/is_uploaded_file_basic.phpt et al still failed if /etc/php.ini set file_uploads=Off. + +So beyond the particular buggy test, we need a way to run tests cleanly without host interference. + +Recommended permission adjustment after applying: enable execute for the run-tests.sh wrapper; disable execute for the subordinate run-tests.php. + + -jfw + +diff -uNr a/Makefile.global b/Makefile.global +--- a/Makefile.global 2026-08-05 21:48:40 +0000 ++++ b/Makefile.global 2026-08-06 20:41:08 +0000 +@@ -8,7 +8,6 @@ + all: $(all_targets) + @echo + @echo "Build complete." +- @echo "Don't forget to run 'make test'." + @echo + + build-modules: $(PHP_MODULES) $(PHP_ZEND_EX) +@@ -86,6 +85,10 @@ + PHP_DEPRECATED_DIRECTIVES_REGEX = '^(magic_quotes_(gpc|runtime|sybase)?|(zend_)?extension(_debug)?(_ts)?)[\t\ ]*=' + + test: all ++ @echo ++ @echo "WARNING: 'make test' was designed to import active php.ini configuration from the host system, which can break various test assumptions." ++ @echo "Use ./run-tests.sh instead for testing the local codebase in a predictable environment." ++ @echo + @if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \ + INI_FILE=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r 'echo php_ini_loaded_file();' 2> /dev/null`; \ + if test "$$INI_FILE"; then \ +diff -uNr a/ext/filter/tests/bug52209.phpt b/ext/filter/tests/bug52209.phpt +--- a/ext/filter/tests/bug52209.phpt 2018-02-27 23:15:25 +0000 ++++ b/ext/filter/tests/bug52209.phpt 2026-08-06 15:42:45 +0000 +@@ -6,13 +6,15 @@ + would never show up in the "set" list. Which means, it's + always undefined in PHP. */ + if(substr(PHP_OS, 0, 3) == "WIN") die("skip Not for Windows"); +-if (!extension_loaded("filter") || !empty($_ENV['PWD'])) die("skip"); ++if (!extension_loaded("filter")) die("skip"); + ?> ++--ENV-- ++CANARY=1 + --INI-- + variables_order=GPCSE + --FILE-- + + --EXPECTF-- + string(%d) "%s" +diff -uNr a/run-tests.sh b/run-tests.sh +--- a/run-tests.sh 1970-01-01 00:00:00 +0000 ++++ b/run-tests.sh 2026-08-06 20:33:11 +0000 +@@ -0,0 +1,9 @@ ++#!/bin/sh ++# Wrapper-firewall to run tests easily and without interference from host system's php binaries or config. ++# "make test" does the opposite, contaminating the test environment with a munged copy of /etc/php.ini. ++ ++export REPORT_EXIT_STATUS=1 ++export TEST_PHP_EXECUTABLE=$PWD/sapi/cli/php ++export TEST_PHP_CGI_EXECUTABLE=$PWD/sapi/cgi/php-cgi ++ ++exec $TEST_PHP_EXECUTABLE -n run-tests.php -n "$@" diff -uNr a/gports/php56/test024.gdb b/gports/php56/test024.gdb --- a/gports/php56/test024.gdb 1970-01-01 00:00:00 +0000 +++ b/gports/php56/test024.gdb 1970-01-01 00:00:00 +0000 @@ -0,0 +1,9 @@ +# Saved for future reference - this gdb script sets up environment & arguments to debug a failing test which runs php-cgi with specific settings and reads POST data from standard input. +set env REQUEST_METHOD=POST +set env CONTENT_TYPE=application/x-www-form-urlencoded +set env CONTENT_LENGTH=30 +set env REDIRECT_STATUS=1 +set env SCRIPT_FILENAME=./tests/basic/024.php +file sapi/cgi/php-cgi +break main +run -C -d output_handler= -d open_basedir= -d safe_mode=0 -d disable_functions= -d output_buffering=Off -d error_reporting=32767 -d display_errors=1 -d display_startup_errors=1 -d log_errors=0 -d html_errors=0 -d track_errors=1 -d report_memleaks=1 -d report_zend_debug=0 -d docref_root= -d docref_ext=.html -d error_prepend_string= -d error_append_string= -d auto_prepend_file= -d auto_append_file= -d magic_quotes_runtime=0 -d ignore_repeated_errors=0 -d precision=14 -d memory_limit=128M -d log_errors_max_len=0 -d opcache.fast_shutdown=0 -d opcache.file_update_protection=0 -d session.auto_start=0 -d always_populate_raw_post_data=1 -d max_input_vars=1000 -f ./tests/basic/024.php setup.py - rm aclocal.m4 configure pyconfig.h.in grep -v PKG_PROG_PKG_CONFIG configure.ac >tmp; mv tmp configure.ac + autoheader autoconf p=/gales/pkg/$Q diff -uNr a/gports/python/python-2.7.13-follow-expat-hardening.patch b/gports/python/python-2.7.13-follow-expat-hardening.patch --- a/gports/python/python-2.7.13-follow-expat-hardening.patch 1970-01-01 00:00:00 +0000 +++ b/gports/python/python-2.7.13-follow-expat-hardening.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,87 @@ +This falls short of propagating the audit/blocking of suspicious interfaces; that'll be a larger project because Python's XML situation is somewhat complex. At least it's no worse than before and we pick up the fixes in the new expat release. + + -jfw + +diff -ur a/Modules/_elementtree.c b/Modules/_elementtree.c +--- a/Modules/_elementtree.c 2016-12-17 20:05:07 +0000 ++++ b/Modules/_elementtree.c 2026-08-18 06:26:43 +0000 +@@ -2539,6 +2539,8 @@ + self->handle_data = PyObject_GetAttrString(target, "data"); + self->handle_end = PyObject_GetAttrString(target, "end"); + self->handle_comment = PyObject_GetAttrString(target, "comment"); ++ /* Undocumented feature allowing a custom tree builder class ("target" object) to receive XML processing instructions by implementing the "pi" method. ++ * TODO the usual _hazmat rename, but throw exception rather than failing silently if .pi is implemented. And there are more affected code paths, like the 'pure' python elementtree and pyexpat. */ + self->handle_pi = PyObject_GetAttrString(target, "pi"); + self->handle_close = PyObject_GetAttrString(target, "close"); + +@@ -2565,7 +2567,7 @@ + (XML_CommentHandler) expat_comment_handler + ); + if (self->handle_pi) +- EXPAT(SetProcessingInstructionHandler)( ++ EXPAT(SetProcessingInstructionHandler_hazmat)( + self->parser, + (XML_ProcessingInstructionHandler) expat_pi_handler + ); +diff -ur a/Modules/pyexpat.c b/Modules/pyexpat.c +--- a/Modules/pyexpat.c 2016-12-17 20:05:07 +0000 ++++ b/Modules/pyexpat.c 2026-08-18 06:50:17 +0000 +@@ -254,7 +254,7 @@ + flag_error(xmlparseobject *self) + { + clear_handlers(self, 0); +- XML_SetExternalEntityRefHandler(self->itself, ++ XML_SetExternalEntityRefHandler_hazmat(self->itself, + error_external_entity_ref_handler); + } + +@@ -1100,7 +1100,7 @@ + new_parser->specified_attributes = self->specified_attributes; + new_parser->in_callback = 0; + new_parser->ns_prefixes = self->ns_prefixes; +- new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context, ++ new_parser->itself = XML_ExternalEntityParserCreate_hazmat(self->itself, context, + encoding); + new_parser->handlers = 0; + new_parser->intern = self->intern; +@@ -1312,13 +1312,6 @@ + else { + self->itself = XML_ParserCreate(encoding); + } +-#if ((XML_MAJOR_VERSION >= 2) && (XML_MINOR_VERSION >= 1)) || defined(XML_HAS_SET_HASH_SALT) +- /* This feature was added upstream in libexpat 2.1.0. Our expat copy +- * has a backport of this feature where we also define XML_HAS_SET_HASH_SALT +- * to indicate that we can still use it. */ +- XML_SetHashSalt(self->itself, +- (unsigned long)_Py_HashSecret.prefix); +-#endif + self->intern = intern; + Py_XINCREF(self->intern); + #ifdef Py_TPFLAGS_HAVE_GC +@@ -2041,7 +2034,7 @@ + capi.SetDefaultHandlerExpand = XML_SetDefaultHandlerExpand; + capi.SetElementHandler = XML_SetElementHandler; + capi.SetNamespaceDeclHandler = XML_SetNamespaceDeclHandler; +- capi.SetProcessingInstructionHandler = XML_SetProcessingInstructionHandler; ++ capi.SetProcessingInstructionHandler = XML_SetProcessingInstructionHandler_hazmat; + capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler; + capi.SetUserData = XML_SetUserData; + +@@ -2077,7 +2070,7 @@ + (xmlhandlersetter)XML_SetEndElementHandler, + (xmlhandler)my_EndElementHandler}, + {"ProcessingInstructionHandler", +- (xmlhandlersetter)XML_SetProcessingInstructionHandler, ++ (xmlhandlersetter)XML_SetProcessingInstructionHandler_hazmat, + (xmlhandler)my_ProcessingInstructionHandler}, + {"CharacterDataHandler", + (xmlhandlersetter)XML_SetCharacterDataHandler, +@@ -2113,7 +2106,7 @@ + (xmlhandlersetter)XML_SetNotStandaloneHandler, + (xmlhandler)my_NotStandaloneHandler}, + {"ExternalEntityRefHandler", +- (xmlhandlersetter)XML_SetExternalEntityRefHandler, ++ (xmlhandlersetter)XML_SetExternalEntityRefHandler_hazmat, + (xmlhandler)my_ExternalEntityRefHandler}, + {"StartDoctypeDeclHandler", + (xmlhandlersetter)XML_SetStartDoctypeDeclHandler, diff -uNr a/gports/tmux/build.sh b/gports/tmux/build.sh --- a/gports/tmux/build.sh 1970-01-01 00:00:00 +0000 +++ b/gports/tmux/build.sh 1970-01-01 00:00:00 +0000 @@ -1,12 +1,18 @@ P=tmux V=2.5 MAJOR=0 -MINOR=0 +MINOR=1 # Requires: libevent ncurses +# FIXME: +# Line drawing characters showing as underscores after switching windows: +# The culprint in 2.5 seems to be tty_draw_line when (gc.attr & GRID_ATTR_CHARSET) and (~tty->flags & TTY_UTF8). +# Try version 2.1 (before utf8 options were removed & made mandatory) or else 3.2 (which changes ACS handling again, perhaps with fallback). + S=" $P-$V.tar.gz +tmux-2.5-fix-acs-non-utf8.patch " SHA512=" @@ -16,6 +22,7 @@ build () { tar xf $P-$V.tar.gz cd $P-$V + patch -p1 <../tmux-2.5-fix-acs-non-utf8.patch # FIXME autoconf fails on PKG_CHECK_MODULES from pkg-config (with misleading error about AC_SEARCH_LIBS) #rm Makefile.in aclocal.m4 configure #aclocal diff -uNr a/gports/tmux/tmux-2.5-fix-acs-non-utf8.patch b/gports/tmux/tmux-2.5-fix-acs-non-utf8.patch --- a/gports/tmux/tmux-2.5-fix-acs-non-utf8.patch 1970-01-01 00:00:00 +0000 +++ b/gports/tmux/tmux-2.5-fix-acs-non-utf8.patch 1970-01-01 00:00:00 +0000 @@ -0,0 +1,152 @@ +tmux 2.4 commit: + + dc8fefe902279836958c7438718e838d3687aed2 Collect strings correctly when on terminals that don't support UTF-8. + +broke display of ACS characters - including tmux's own line drawing - in non-utf8 environments, due to logic errors conflating the separate cases of non-ASCII cell data and GRID_ATTR_CHARSET cell attribute. They'd show correctly when first drawn by the application, then show as underscores when redrawn after switching windows. + +This patch is a manual merge of followups from tmux 2.7: + + 2c5a6f9af599f09d3445dd7ac40af31013e85d77 Simplify character replacement on non-UTF-8 terminals and make a common function. + 75842bfe66d983580dddf11b676445d5b9fa9f8a Fix drawing of ACS characters (they need to go character-at-a-time), accidentally broken in last commit. + + -jfw + +diff -ur a/tty.c b/tty.c +--- a/tty.c 2017-05-29 07:12:06 +0000 ++++ b/tty.c 2026-03-27 21:08:10 +0000 +@@ -761,11 +761,36 @@ + tty_draw_line(tty, wp, wp->screen, py, ox, oy); + } + ++static const struct grid_cell * ++tty_check_codeset(struct tty *tty, const struct grid_cell *gc) ++{ ++ static struct grid_cell new; ++ u_int n; ++ ++ /* Characters less than 0x7f are always fine, no matter what. */ ++ if (gc->data.size == 1 && *gc->data.data < 0x7f) ++ return (gc); ++ ++ /* UTF-8 terminal and a UTF-8 character - fine. */ ++ if (tty->flags & TTY_UTF8) ++ return (gc); ++ ++ /* Replace by the right number of underscores. */ ++ n = gc->data.width; ++ if (n > UTF8_SIZE) ++ n = UTF8_SIZE; ++ memcpy(&new, gc, sizeof new); ++ new.data.size = n; ++ memset(new.data.data, '_', n); ++ return (&new); ++} ++ + void + tty_draw_line(struct tty *tty, const struct window_pane *wp, + struct screen *s, u_int py, u_int ox, u_int oy) + { + struct grid_cell gc, last; ++ const struct grid_cell *gcp; + u_int i, j, sx, width; + int flags, cleared = 0; + char buf[512]; +@@ -815,17 +840,14 @@ + + for (i = 0; i < sx; i++) { + grid_view_get_cell(s->grid, i, py, &gc); ++ gcp = tty_check_codeset(tty, &gc); + if (len != 0 && +- (((~tty->flags & TTY_UTF8) && +- (gc.data.size != 1 || +- *gc.data.data >= 0x7f || +- gc.data.width != 1)) || +- (gc.attr & GRID_ATTR_CHARSET) || +- gc.flags != last.flags || +- gc.attr != last.attr || +- gc.fg != last.fg || +- gc.bg != last.bg || +- (sizeof buf) - len < gc.data.size)) { ++ ((gcp->attr & GRID_ATTR_CHARSET) || ++ gcp->flags != last.flags || ++ gcp->attr != last.attr || ++ gcp->fg != last.fg || ++ gcp->bg != last.bg || ++ (sizeof buf) - len < gcp->data.size)) { + tty_attributes(tty, &last, wp); + tty_putn(tty, buf, len, width); + +@@ -833,27 +855,18 @@ + width = 0; + } + +- if (gc.flags & GRID_FLAG_SELECTED) +- screen_select_cell(s, &last, &gc); ++ if (gcp->flags & GRID_FLAG_SELECTED) ++ screen_select_cell(s, &last, gcp); + else +- memcpy(&last, &gc, sizeof last); +- if (((~tty->flags & TTY_UTF8) && +- (gc.data.size != 1 || +- *gc.data.data >= 0x7f || +- gc.data.width != 1)) || +- (gc.attr & GRID_ATTR_CHARSET)) { ++ memcpy(&last, gcp, sizeof last); ++ if (gcp->attr & GRID_ATTR_CHARSET) { + tty_attributes(tty, &last, wp); +- if (~tty->flags & TTY_UTF8) { +- for (j = 0; j < gc.data.width; j++) +- tty_putc(tty, '_'); +- } else { +- for (j = 0; j < gc.data.size; j++) +- tty_putc(tty, gc.data.data[j]); +- } ++ for (j = 0; j < gcp->data.size; j++) ++ tty_putc(tty, gcp->data.data[j]); + } else { +- memcpy(buf + len, gc.data.data, gc.data.size); +- len += gc.data.size; +- width += gc.data.width; ++ memcpy(buf + len, gcp->data.data, gcp->data.size); ++ len += gcp->data.size; ++ width += gcp->data.width; + } + } + if (len != 0) { +@@ -1349,7 +1362,7 @@ + tty_cell(struct tty *tty, const struct grid_cell *gc, + const struct window_pane *wp) + { +- u_int i; ++ const struct grid_cell *gcp; + + /* Skip last character if terminal is stupid. */ + if ((tty->term->flags & TERM_EARLYWRAP) && +@@ -1365,22 +1378,16 @@ + tty_attributes(tty, gc, wp); + + /* Get the cell and if ASCII write with putc to do ACS translation. */ +- if (gc->data.size == 1) { +- if (*gc->data.data < 0x20 || *gc->data.data == 0x7f) ++ gcp = tty_check_codeset(tty, gc); ++ if (gcp->data.size == 1) { ++ if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f) + return; +- tty_putc(tty, *gc->data.data); +- return; +- } +- +- /* If not UTF-8, write _. */ +- if (!(tty->flags & TTY_UTF8)) { +- for (i = 0; i < gc->data.width; i++) +- tty_putc(tty, '_'); ++ tty_putc(tty, *gcp->data.data); + return; + } + + /* Write the data. */ +- tty_putn(tty, gc->data.data, gc->data.size, gc->data.width); ++ tty_putn(tty, gcp->data.data, gcp->data.size, gcp->data.width); + } + + void diff -uNr a/kconfig/linux-4.9-x86_64-amd-server.config b/kconfig/linux-4.9-x86_64-amd-server.config --- a/kconfig/linux-4.9-x86_64-amd-server.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/linux-4.9-x86_64-amd-server.config 1970-01-01 00:00:00 +0000 @@ -1849,7 +1849,7 @@ # CONFIG_HID=y # CONFIG_HID_BATTERY_STRENGTH is not set -# CONFIG_HIDRAW is not set +CONFIG_HIDRAW=y # CONFIG_UHID is not set CONFIG_HID_GENERIC=y @@ -2030,7 +2030,7 @@ # CONFIG_USB_SERIAL_CH341 is not set # CONFIG_USB_SERIAL_WHITEHEAT is not set # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_CP210X is not set +CONFIG_USB_SERIAL_CP210X=y # CONFIG_USB_SERIAL_CYPRESS_M8 is not set # CONFIG_USB_SERIAL_EMPEG is not set CONFIG_USB_SERIAL_FTDI_SIO=y diff -uNr a/kconfig/linux-4.9-x86_64-apu1-static-debug.config b/kconfig/linux-4.9-x86_64-apu1-static-debug.config --- a/kconfig/linux-4.9-x86_64-apu1-static-debug.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/linux-4.9-x86_64-apu1-static-debug.config 1970-01-01 00:00:00 +0000 @@ -1739,7 +1739,7 @@ # CONFIG_HID=y # CONFIG_HID_BATTERY_STRENGTH is not set -# CONFIG_HIDRAW is not set +CONFIG_HIDRAW=y # CONFIG_UHID is not set CONFIG_HID_GENERIC=y @@ -1922,7 +1922,7 @@ # CONFIG_USB_SERIAL_CH341 is not set # CONFIG_USB_SERIAL_WHITEHEAT is not set # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_CP210X is not set +CONFIG_USB_SERIAL_CP210X=y # CONFIG_USB_SERIAL_CYPRESS_M8 is not set # CONFIG_USB_SERIAL_EMPEG is not set CONFIG_USB_SERIAL_FTDI_SIO=y diff -uNr a/kconfig/linux-4.9-x86_64-apu1-static.config b/kconfig/linux-4.9-x86_64-apu1-static.config --- a/kconfig/linux-4.9-x86_64-apu1-static.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/linux-4.9-x86_64-apu1-static.config 1970-01-01 00:00:00 +0000 @@ -1725,7 +1725,7 @@ # CONFIG_HID=y # CONFIG_HID_BATTERY_STRENGTH is not set -# CONFIG_HIDRAW is not set +CONFIG_HIDRAW=y # CONFIG_UHID is not set CONFIG_HID_GENERIC=y @@ -1908,7 +1908,7 @@ # CONFIG_USB_SERIAL_CH341 is not set # CONFIG_USB_SERIAL_WHITEHEAT is not set # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_CP210X is not set +CONFIG_USB_SERIAL_CP210X=y # CONFIG_USB_SERIAL_CYPRESS_M8 is not set # CONFIG_USB_SERIAL_EMPEG is not set CONFIG_USB_SERIAL_FTDI_SIO=y diff -uNr a/kconfig/linux-4.9-x86_64-thinkpad-static.config b/kconfig/linux-4.9-x86_64-thinkpad-static.config --- a/kconfig/linux-4.9-x86_64-thinkpad-static.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/linux-4.9-x86_64-thinkpad-static.config 1970-01-01 00:00:00 +0000 @@ -2071,7 +2071,7 @@ # CONFIG_HID=y # CONFIG_HID_BATTERY_STRENGTH is not set -# CONFIG_HIDRAW is not set +CONFIG_HIDRAW=y # CONFIG_UHID is not set CONFIG_HID_GENERIC=y @@ -2257,7 +2257,7 @@ # CONFIG_USB_SERIAL_CH341 is not set # CONFIG_USB_SERIAL_WHITEHEAT is not set # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_CP210X is not set +CONFIG_USB_SERIAL_CP210X=y # CONFIG_USB_SERIAL_CYPRESS_M8 is not set # CONFIG_USB_SERIAL_EMPEG is not set CONFIG_USB_SERIAL_FTDI_SIO=y diff -uNr a/kconfig/linux-4.9-x86_64-vm-static.config b/kconfig/linux-4.9-x86_64-vm-static.config --- a/kconfig/linux-4.9-x86_64-vm-static.config 1970-01-01 00:00:00 +0000 +++ b/kconfig/linux-4.9-x86_64-vm-static.config 1970-01-01 00:00:00 +0000 @@ -1657,7 +1657,7 @@ # CONFIG_HID=y # CONFIG_HID_BATTERY_STRENGTH is not set -# CONFIG_HIDRAW is not set +CONFIG_HIDRAW=y # CONFIG_UHID is not set CONFIG_HID_GENERIC=y