diff --git a/src/main/java/jnr/posix/SpawnFileAction.java b/src/main/java/jnr/posix/SpawnFileAction.java index c6b945b..1657b3f 100644 --- a/src/main/java/jnr/posix/SpawnFileAction.java +++ b/src/main/java/jnr/posix/SpawnFileAction.java @@ -2,6 +2,11 @@ import jnr.ffi.Pointer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + public abstract class SpawnFileAction { abstract boolean act(POSIX posix, Pointer nativeFileActions); @@ -38,16 +43,44 @@ private static final class Open extends SpawnFileAction { final String path; final int fd; final int flags, mode; + final ByteBuffer nativePath; public Open(String path, int fd, int flags, int mode) { this.path = path; this.fd = fd; this.flags = flags; this.mode = mode; + this.nativePath = defensiveCopy(path); + } + + private ByteBuffer defensiveCopy(String path) { + /* + This logic allocates a direct ByteBuffer to use for the path in order to work around systems that have not + patched CVE-2014-4043, in which older glibc versions do not make a defensive copy of the file path passed to + posix_spawn_file_actions_addopen. The buffer may be freed by the caller before it can be used in an + eventual posix_spawn call. + + See https://bugzilla.redhat.com/show_bug.cgi?id=1983750 for a RHEL version of this issue. + */ + + // determine encoded byte array length + CharsetEncoder encoder = Charset.defaultCharset().newEncoder(); + int bpc = (int) encoder.maxBytesPerChar(); + int size = (path.length() + 1) * bpc; + + // transcode to native buffer + ByteBuffer nativePath = ByteBuffer.allocateDirect(size); + encoder.encode(CharBuffer.wrap(path), nativePath, true); + nativePath.flip(); + + // null terminate + nativePath.limit(nativePath.limit() + bpc); + + return nativePath; } final boolean act(POSIX posix, Pointer nativeFileActions) { - return ((UnixLibC) posix.libc()).posix_spawn_file_actions_addopen(nativeFileActions, fd, path, flags, mode) == 0; + return ((UnixLibC) posix.libc()).posix_spawn_file_actions_addopen(nativeFileActions, fd, nativePath, flags, mode) == 0; } public String toString() { diff --git a/src/main/java/jnr/posix/UnixLibC.java b/src/main/java/jnr/posix/UnixLibC.java index fe40129..89666be 100644 --- a/src/main/java/jnr/posix/UnixLibC.java +++ b/src/main/java/jnr/posix/UnixLibC.java @@ -1,6 +1,7 @@ package jnr.posix; import jnr.ffi.Pointer; +import jnr.ffi.annotations.Direct; import jnr.ffi.annotations.In; import jnr.ffi.annotations.Out; import jnr.ffi.byref.ByReference; @@ -9,6 +10,8 @@ import jnr.ffi.byref.ShortByReference; import jnr.ffi.types.pid_t; +import java.nio.ByteBuffer; + public interface UnixLibC extends LibC { public int posix_spawn(@Out ByReference pid, @In CharSequence path, @In Pointer fileActions, @In Pointer attr, @In CharSequence[] argv, @In CharSequence[] envp); @@ -19,8 +22,15 @@ public int posix_spawnp(@Out ByReference pid, @In CharSequence path, @In Pointer public int posix_spawn_file_actions_init(Pointer fileActions); public int posix_spawn_file_actions_destroy(Pointer fileActions); public int posix_spawn_file_actions_addclose(Pointer fileActions, int filedes); + + /** + * @deprecated due to CVE-2014-4043 (https://bugzilla.redhat.com/show_bug.cgi?id=1983750) + */ + @Deprecated public int posix_spawn_file_actions_addopen(Pointer fileActions, int filedes, CharSequence path, int oflag, int mode); + public int posix_spawn_file_actions_addopen(Pointer fileActions, int filedes, @Direct ByteBuffer path, + int oflag, int mode); public int posix_spawn_file_actions_adddup2(Pointer fileActions, int filedes, int newfiledes); public int posix_spawnattr_init(Pointer attr); public int posix_spawnattr_destroy(Pointer attr);