<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>