<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.
</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/b0ed43beb82dc4e1688a68e1ffa18531fca4b94a">https://github.com/macports/macports-legacy-support/commit/b0ed43beb82dc4e1688a68e1ffa18531fca4b94a</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit b0ed43beb82dc4e1688a68e1ffa18531fca4b94a
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Tue Jun 24 23:42:01 2025 -0700
<span style='display:block; white-space:pre;color:#404040;'> fcntl: Fix F_GETPATH bug in 10.4 ppc64.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This applies a bounce buffer to get around an access-checking
</span><span style='display:block; white-space:pre;color:#404040;'> bug in F_GETPATH. See the comments for more details.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'> Tests pass on all platforms, including 10.4 ppc64.
</span>---
src/fcntl.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 190 insertions(+)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/fcntl.c b/src/fcntl.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..50a34da
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/fcntl.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,190 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2025 Frederick H. G. Wright II <fw@fwright.net>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* MP support header */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "MacportsLegacySupport.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MPLS_LIB_FIX_TIGER_PPC64__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * In 10.4 ppc64, there is a bug in fcntl() which doesn't handle 64-bit
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * addresses correctly for F_GETPATH. To work around this, we need to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * use a buffer in the low 4GiB of memory for the temporary path. Since
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 64-bit builds on 10.4 don't bother to steer clear of the low 4GiB,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * this can be accomplished with a static buffer, but we need to lock it
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * against thread collisions.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Wrapping fcntl() is made drastically more complicated by the fact that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * it's a variadic function and there's no vfcntl(). So we try to get
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the argument type correct based on the 'cmd' argument. We use
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * void * for all pointers (except the one we operate on), since the pointers
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * themselves aren't type-specific.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Further complicating things is that we don't want to crash on a genuinely
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * bad pointer, so we need to check it explicitly.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <dlfcn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <pthread.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdarg.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <mach/mach.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <mach/mach_vm.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "compiler.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_access(void *adr, mach_vm_size_t size, vm_prot_t access)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ vm_map_t task = mach_task_self();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_vm_address_t address;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_vm_size_t msize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ vm_region_basic_info_data_64_t info;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_msg_type_number_t count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_port_t object_name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ kern_return_t ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ address = (mach_vm_address_t) adr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ msize = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ count = VM_REGION_BASIC_INFO_COUNT_64;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = mach_vm_region(task, &address, &msize, VM_REGION_BASIC_INFO_64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (vm_region_info_t)&info, &count, &object_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ret != KERN_SUCCESS) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((mach_vm_address_t) adr < address) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (access & ~info.protection) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ address = (mach_vm_address_t) ((uint8_t *) adr + size -1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ msize = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ count = VM_REGION_BASIC_INFO_COUNT_64;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = mach_vm_region(task, &address, &msize, VM_REGION_BASIC_INFO_64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (vm_region_info_t)&info, &count, &object_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ret != KERN_SUCCESS) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((mach_vm_address_t) adr < address) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (access & ~info.protection) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static pthread_mutex_t path_lock = PTHREAD_MUTEX_INITIALIZER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char pathbuf[MAXPATHLEN];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int (fcntl_fn_t)(int fildes, int cmd, ...);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+fcntl(int fildes, int cmd, ...)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_list ap;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ union arg_u {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int num;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pid_t pid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ off_t off;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void *ptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *str;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static fcntl_fn_t *os_fcntl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (MPLS_SLOWPATH(!os_fcntl)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ os_fcntl = dlsym(RTLD_NEXT, "fcntl");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Something's badly broken if this fails */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!os_fcntl) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_start(ap, cmd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (cmd) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_GETFD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_GETFL:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_GETOWN:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_FULLFSYNC:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_FREEZE_FS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_THAW_FS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (*os_fcntl)(fildes, cmd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_DUPFD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_SETFD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_SETFL:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_RDAHEAD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_NOCACHE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ arg.num = va_arg(ap, int);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (*os_fcntl)(fildes, cmd, arg.num);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_SETOWN:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ arg.pid = va_arg(ap, pid_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (*os_fcntl)(fildes, cmd, arg.pid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_SETSIZE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ arg.off = va_arg(ap, off_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (*os_fcntl)(fildes, cmd, arg.off);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_PREALLOCATE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_READBOOTSTRAP:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_WRITEBOOTSTRAP:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_LOG2PHYS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_PATHPKG_CHECK:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ arg.ptr = va_arg(ap, void *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (*os_fcntl)(fildes, cmd, arg.ptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case F_GETPATH:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ arg.str = va_arg(ap, char *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = (*os_fcntl)(fildes, cmd, arg.str);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ret != -1 || errno != EFAULT) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ arg.ptr = va_arg(ap, void *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ va_end(ap);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (*os_fcntl)(fildes, cmd, arg.ptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Here when F_GETPATH gets EFAULT */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If not a 64-bit issue, just punt (probably genuine bad adr). */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((uint64_t) arg.ptr < (1ULL << 32)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Now do a correct access check on the result buffer, & fail if bad */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (check_access(arg.ptr, MAXPATHLEN, VM_PROT_WRITE)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = EFAULT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* All OK, now just use our local buffer and copy it (with locking). */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (pthread_mutex_lock(&path_lock)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ret = (*os_fcntl)(fildes, cmd, pathbuf))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) pthread_mutex_unlock(&path_lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ memcpy(arg.ptr, pathbuf, MAXPATHLEN);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return (errno = pthread_mutex_unlock(&path_lock)) ? -1 : 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MPLS_LIB_FIX_TIGER_PPC64__ */
</span></pre><pre style='margin:0'>
</pre>