[PATCH] Fix build on GNU/hurd via dynamic allocation
Dear Dillo Maintainers, I noticed that the Dillo 3.3.0 Debian package build was failing on GNU/hurd due to the PATH_MAX macro not being defined on that platform. This is a common portability issue on the platform, and the following page indicates why the macro is not defined in GNU/hurd https://www.gnu.org/software/hurd/faq/foo_max It was pointed out to me that commit b43ab26e81a1e399e3cb148b972a284518aa4d39 has addressed the hurd build failure already, but it does so by simply defining PATH_MAX to an arbitrary value. As per the page above, the preferred way to address the issue by allocating the size of the path dynamically. I submit the following patch to your consideration. The patch applies to version 3.3.0 of the file present in Debian, before the above mentioned commit. Best regards, João
Hi, On Mon, Aug 31, 2026 at 05:43:53PM +0100, João Pedro Malhado wrote:
Dear Dillo Maintainers,
I noticed that the Dillo 3.3.0 Debian package build was failing on GNU/hurd due to the PATH_MAX macro not being defined on that platform. This is a common portability issue on the platform, and the following page indicates why the macro is not defined in GNU/hurd https://www.gnu.org/software/hurd/faq/foo_max
It was pointed out to me that commit b43ab26e81a1e399e3cb148b972a284518aa4d39 has addressed the hurd build failure already, but it does so by simply defining PATH_MAX to an arbitrary value.
Yes, it is set to 4096 if not defined. Debian thread for reference: https://lists.debian.org/debian-hurd/2026/08/msg00023.html
As per the page above, the preferred way to address the issue by allocating the size of the path dynamically.
That path will be concatenated with the PID to form the UNIX socket path that must fit into sun_path, currently holding up to 108 bytes: demo@debian:~$ uname -a GNU debian 0.9 GNU-Mach 1.8+git20260805-up-amd64/Hurd-0.9 x86_64 GNU demo@debian:~$ grep -C 3 'char sun_path' /usr/include/x86_64-gnu/sys/un.h struct __attribute_struct_may_alias__ sockaddr_un { __SOCKADDR_COMMON (sun_); char sun_path[108]; /* Path name. */ }; demo@debian:~$ cat a.c #include <sys/un.h> #include <stdio.h> int main() { struct sockaddr_un a; printf("sun_path takes %zd bytes\n", sizeof(a.sun_path)); } demo@debian:~$ gcc a.c -o a demo@debian:~$ ./a sun_path takes 108 bytes So I don't see a need for it to be longer than 4096 bytes, but let me know otherwise. Notice that asprintf() is not portable, is a GNU extension. The utility of having a compile time limit is to be able to build the ctlpath in the stack and avoid freeing the heap on errors, as you see in your 5 extra calls to free(). It is not only cleaner, but also faster: demo@debian:~$ cat b.c #define _GNU_SOURCE #include <time.h> #include <stdio.h> #include <stdlib.h> static double get_time(void) { struct timespec tv; if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) { perror("clock_gettime failed"); exit(EXIT_FAILURE); } return (double) (tv.tv_sec) + (double) tv.tv_nsec * 1.0e-9; } int main() { long nruns = 10; for (long run = 0; run < nruns; run++) { long n = 1000000; double t0 = get_time(); for (long i = 0; i < n; i++) { char path[4096]; if (snprintf(path, 4096, "foobar/%ld", i) >= 4096) { fprintf(stderr, "path too long\n"); exit(1); } } double t1 = get_time(); for (long i = 0; i < n; i++) { char *path; if (asprintf(&path, "foobar/%ld", i) < 0) { fprintf(stderr, "asprintf failed\n"); exit(1); } free(path); } double t2 = get_time(); printf("stack took %e s, asprintf took %e s\n", t1 - t0, t2 - t1); } } demo@debian:~$ gcc -O3 b.c -o b demo@debian:~$ ./b stack took 4.706729e-02 s, asprintf took 5.388443e-02 s stack took 4.644344e-02 s, asprintf took 5.432338e-02 s stack took 5.084137e-02 s, asprintf took 5.387238e-02 s stack took 4.659570e-02 s, asprintf took 5.408105e-02 s stack took 4.678890e-02 s, asprintf took 5.416419e-02 s stack took 4.688072e-02 s, asprintf took 5.322799e-02 s stack took 4.711744e-02 s, asprintf took 5.319471e-02 s stack took 4.713604e-02 s, asprintf took 5.314928e-02 s stack took 4.717523e-02 s, asprintf took 5.360440e-02 s stack took 4.717370e-02 s, asprintf took 5.796235e-02 s demo@debian:~$
Allocating dynamically would use much less memory.
Notice that having a compile-time limit for paths doesn't need to cause paths to always require that size for storage. You can still store only the strlen(path) + 1, but allow building them on the stack having a known limit. Having an unbounded path means that any untrusted input path from the user is potentially a DoS as the path can happily take 1 TiB. It might be worth reconsidering this decision on GNU/hurd. Best, Rodrigo.
I submit the following patch to your consideration. The patch applies to version 3.3.0 of the file present in Debian, before the above mentioned commit.
Best regards, João
--- dillo-3.3.0.orig/src/dilloc.c +++ dillo-3.3.0/src/dilloc.c @@ -16,6 +16,7 @@ #include <dirent.h> #include <errno.h> #include <limits.h> +#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> @@ -104,9 +105,9 @@ connect_given_pid(int *sock, const char static int find_working_socket(int *sock) { - char ctlpath[PATH_MAX]; - if (snprintf(ctlpath, PATH_MAX, "%s/.dillo/ctl", dGethomedir()) >= PATH_MAX) { - fprintf(stderr, "path too long\n"); + char *ctlpath = NULL; + if (asprintf(ctlpath, "%s/.dillo/ctl", dGethomedir()) == -1) { + fprintf(stderr, "path copy error: %s\n", strerror(errno)); return -1; }
@@ -116,10 +117,11 @@ find_working_socket(int *sock) fprintf(stderr, "error: cannot open %s directory: %s\n", ctlpath, strerror(errno)); fprintf(stderr, "hint: is dillo running?\n"); + free(ctlpath); return -1; }
- int found_pid = 0; + int found_pid = 0; struct sockaddr_un addr; addr.sun_family = AF_UNIX;
@@ -136,6 +138,7 @@ find_working_socket(int *sock) #define LEN ((int) sizeof(addr.sun_path)) if (snprintf(addr.sun_path, LEN, "%s/%s", ctlpath, num) >= LEN) { fprintf(stderr, "pid path too long\n"); + free(ctlpath); return -1; } #undef LEN @@ -143,6 +146,7 @@ find_working_socket(int *sock) int fd; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "socket() failed: %s\n", strerror(errno)); + free(ctlpath); return -1; }
@@ -170,11 +174,13 @@ find_working_socket(int *sock)
if (fd != -1 && dClose(fd) != 0) { fprintf(stderr, "cannot close fd: %s", strerror(errno)); + free(ctlpath); return -1; } }
closedir(dp); + free(ctlpath);
if (found_pid == 1) return 0;
_______________________________________________ Dillo-dev mailing list -- dillo-dev@mailman3.com To unsubscribe send an email to dillo-dev-leave@mailman3.com
Hello Rodrigo, Thank you for getting back to me. On Mon, Aug 31, 2026 at 09:02:25PM +0200, Rodrigo Arias wrote:
So I don't see a need for it to be longer than 4096 bytes, but let me know otherwise. Notice that asprintf() is not portable, is a GNU extension.
It is my understanding that asprintf has been added to the POSIX 2024 standard https://pubs.opengroup.org/onlinepubs/9799919799/functions/fprintf.html But if you prefer to avoid it there are off course other ways to achieve the same thing.
The utility of having a compile time limit is to be able to build the ctlpath in the stack and avoid freeing the heap on errors, as you see in your 5 extra calls to free().
If your preference is to allocate on the stack that is what is achieved with my first proposed patch at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1146261#5 but it seems that allocation on the heap is usually preferred https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1146261#6
Having an unbounded path means that any untrusted input path from the user is potentially a DoS as the path can happily take 1 TiB. It might be worth reconsidering this decision on GNU/hurd.
It is not so much that the path length is unbound, there will be a limit in practice, but the arbitrariness of the value (which often does not actually correspond to a maximum), whether this should be defined at the ABI level and the problems and inconsistencies that arise from it. I am not the best person to to make a convincing argument about this, but others have done, and I don't see GNU/Hurd changing on this (it would be very easy to do so, so the reasons for not doing it hold). How you deal with how Dillo builds on the hurd if off course your call, and thank you for caring about making your software available on this OS. Best regards, João
Please disregard the patch I sent previously which was bogus. Sending a corrected patch now. If this approach is deemed acceptable, the _GNU_SOURCE option could be added to the build system instead. Best regards, João On Mon, Aug 31, 2026 at 05:43:53PM +0100, João Pedro Malhado wrote:
Dear Dillo Maintainers,
I noticed that the Dillo 3.3.0 Debian package build was failing on GNU/hurd due to the PATH_MAX macro not being defined on that platform. This is a common portability issue on the platform, and the following page indicates why the macro is not defined in GNU/hurd https://www.gnu.org/software/hurd/faq/foo_max
It was pointed out to me that commit b43ab26e81a1e399e3cb148b972a284518aa4d39 has addressed the hurd build failure already, but it does so by simply defining PATH_MAX to an arbitrary value. As per the page above, the preferred way to address the issue by allocating the size of the path dynamically. I submit the following patch to your consideration. The patch applies to version 3.3.0 of the file present in Debian, before the above mentioned commit.
Best regards, João
participants (2)
-
João Pedro Malhado -
Rodrigo Arias