Skip to content

Commit

Permalink
Merge pull request #171 from headius/defensive_alloc_posix_spawn_file
Browse files Browse the repository at this point in the history
Defensive copy of posix_spawn file paths
  • Loading branch information
headius committed Sep 1, 2021
2 parents 3d313ee + abbc4e5 commit 591ee06
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
35 changes: 34 additions & 1 deletion src/main/java/jnr/posix/SpawnFileAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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() {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/jnr/posix/UnixLibC.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 591ee06

Please sign in to comment.