# Extended 3.1 — UnixOSProcessPlugin realpathAsType: 1024-byte buffer for realpath(3)

Bug ref      : pharo.md §3.1
Severity     : HIGH (linear heap overwrite via deep symlink chains / network mounts)
File         : extracted/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c
Lines (HEAD) : 4180-4219 (`realpathAsType`)

## Problem

`realpath(pathString, buffer)` is allowed to write up to `PATH_MAX`
bytes (4096 on Linux), but the buffer is sized 1024. The post-call
check `if (strlen(realpathResult) >= 1024)` runs **after** the write,
acknowledging in its own warning message that "object memory may
have been corrupted."

## Fix

Use a local stack buffer of `PATH_MAX` for realpath; allocate the
Pharo String sized to the actual result.

```diff
diff --git a/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c b/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c
index c21e34894..540fcf8b3 100644
--- a/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c
+++ b/plugins/UnixOSProcessPlugin/src/common/UnixOSProcessPlugin.c
@@ -4183,38 +4183,27 @@ primitiveVersionString(void)
 static sqInt
 realpathAsType(sqInt classIdentifier)
 {
-    char *buffer;
-    sqInt bufferSize;
+    char stackBuffer[PATH_MAX];
     sqInt len;
-    sqInt newPathString;
     sqInt newString;
     char *pathString;
     char * realpathResult;
     sqInt s;
 
-	bufferSize = 1024;
-	newPathString = instantiateClassindexableSize(classString(), bufferSize);
-	pushRemappableOop(newPathString);
 	pathString = transientCStringFromString(stackObjectValue(0));
-	newPathString = popRemappableOop();
-	buffer = arrayValueOf(newPathString);
-	realpathResult = realpath(pathString, buffer);
+	realpathResult = realpath(pathString, stackBuffer);
 	if (realpathResult == 0) {
 		return primitiveFail();
 	}
-	else {
-		if ((strlen(realpathResult)) >= 1024) {
-			logErrorFromErrno("warning: statically allocated array exceeded in UnixOSProcessPlugin>>primitiveRealPath, object memory may have been corrupted");
-			return primitiveFail();
-		}
-		/* begin cString:asCollection: */
-		len = strlen(realpathResult);
-		newString = instantiateClassindexableSize(classIdentifier, len);
-		strncpy(arrayValueOf(newString), realpathResult, len);
-		s = newString;
-		pop(2);
-		push(s);
+	len = strlen(realpathResult);
+	if (len >= PATH_MAX) {  /* defensive; realpath cannot exceed */
+		return primitiveFail();
 	}
+	newString = instantiateClassindexableSize(classIdentifier, len);
+	strncpy(arrayValueOf(newString), realpathResult, len);
+	s = newString;
+	pop(2);
+	push(s);
 	return 0;
 }

```

## Test plan

- Resolve a path whose `realpath` result is between 1024 and PATH_MAX
  bytes (achievable via a chain of long symlinks on Linux). Before:
  warning logged, object memory clobbered. After: primitive succeeds
  with the correct path.
- Resolve a short path: returns the expected string.

## Risk notes

- Removes the pre-allocated Pharo string buffer; uses a C stack
  buffer for the syscall and instantiates the result-sized string
  afterwards. Matches what other realpath wrappers in glibc do.
- 4 KiB on the C stack is well within the VM thread's stack size.
