Skip to content

Commit

Permalink
Make filepaths with null byte fail
Browse files Browse the repository at this point in the history
This patch applies to several methods that deal with filepaths in Dir,
File, File::Stat, IO, and Kernel. All of these methods now raise an
argument error if a null byte is detected in a path argument.

Some of these methods are also slightly refactored, mostly by replacing
context.runtime with just runtime where applicable.

Conflicts:
	core/src/main/java/org/jruby/RubyDir.java
	core/src/main/java/org/jruby/RubyFile.java
	core/src/main/java/org/jruby/RubyFileStat.java
	core/src/main/java/org/jruby/RubyIO.java
	core/src/main/java/org/jruby/RubyKernel.java
	test/mri/excludes/TestFile.rb
  • Loading branch information
lumeet authored and mkristian committed Apr 13, 2015
1 parent f959d12 commit f41b6d9
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 57 deletions.
34 changes: 23 additions & 11 deletions core/src/main/java/org/jruby/RubyDir.java
Expand Up @@ -64,6 +64,7 @@
import org.jruby.util.JRubyFile;
import org.jruby.util.ByteList;
import static org.jruby.CompatVersion.*;
import org.jruby.util.StringSupport;

/**
* .The Ruby built-in class Dir.
Expand Down Expand Up @@ -134,11 +135,12 @@ public IRubyObject initialize(IRubyObject arg) {
*/
@JRubyMethod(compat = RUBY1_8, visibility = Visibility.PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject arg) {
RubyString newPath = arg.convertToString();
Ruby runtime = context.runtime;
RubyString newPath = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, arg.convertToString()));
path = newPath;
pos = 0;

String adjustedPath = RubyFile.adjustRootPathOnWindows(context.runtime, newPath.toString(), null);
String adjustedPath = RubyFile.adjustRootPathOnWindows(runtime, newPath.toString(), null);
checkDirIsTwoSlashesOnWindows(getRuntime(), adjustedPath);

dir = JRubyFile.createResource(context, adjustedPath);
Expand Down Expand Up @@ -269,13 +271,15 @@ public static RubyArray entries(ThreadContext context, IRubyObject recv, IRubyOb

@JRubyMethod(name = "entries", meta = true, compat = RUBY1_9)
public static RubyArray entries19(ThreadContext context, IRubyObject recv, IRubyObject arg) {
return entriesCommon(context, RubyFile.get_path(context, arg).asJavaString());
RubyString path = StringSupport.checkEmbeddedNulls(context.runtime, RubyFile.get_path(context, arg));
return entriesCommon(context, path.asJavaString());
}

@JRubyMethod(name = "entries", meta = true, compat = RUBY1_9)
public static RubyArray entries19(ThreadContext context, IRubyObject recv, IRubyObject arg, IRubyObject opts) {
RubyString path = StringSupport.checkEmbeddedNulls(context.runtime, RubyFile.get_path(context, arg));
// FIXME: do something with opts
return entriesCommon(context, RubyFile.get_path(context, arg).asJavaString());
return entriesCommon(context, path.asJavaString());
}

private static RubyArray entriesCommon(ThreadContext context, String path) {
Expand Down Expand Up @@ -310,7 +314,8 @@ private static void checkDirIsTwoSlashesOnWindows(Ruby runtime, String path) {
public static IRubyObject chdir(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
Ruby runtime = context.runtime;
RubyString path = args.length == 1 ?
RubyFile.get_path(context, args[0]) : getHomeDirectoryPath(context);
StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, args[0])) :
getHomeDirectoryPath(context);
String adjustedPath = RubyFile.adjustRootPathOnWindows(runtime, path.asJavaString(), null);
checkDirIsTwoSlashesOnWindows(runtime, adjustedPath);
String realPath = null;
Expand Down Expand Up @@ -370,7 +375,9 @@ public static IRubyObject rmdir(IRubyObject recv, IRubyObject path) {

@JRubyMethod(name = {"rmdir", "unlink", "delete"}, required = 1, meta = true, compat = RUBY1_9)
public static IRubyObject rmdir19(ThreadContext context, IRubyObject recv, IRubyObject path) {
return rmdirCommon(context.runtime, RubyFile.get_path(context, path).asJavaString());
Ruby runtime = context.runtime;
RubyString cleanPath = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, path));
return rmdirCommon(runtime, cleanPath.asJavaString());
}

private static IRubyObject rmdirCommon(Ruby runtime, String path) {
Expand Down Expand Up @@ -449,7 +456,9 @@ public static IRubyObject mkdir(IRubyObject recv, IRubyObject[] args) {

@JRubyMethod(name = "mkdir", required = 1, optional = 1, meta = true, compat = RUBY1_9)
public static IRubyObject mkdir19(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return mkdirCommon(context.runtime, RubyFile.get_path(context, args[0]).asJavaString(), args);
Ruby runtime = context.runtime;
RubyString path = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, args[0]));
return mkdirCommon(runtime, path.asJavaString(), args);
}

private static IRubyObject mkdirCommon(Ruby runtime, String path, IRubyObject[] args) {
Expand Down Expand Up @@ -612,14 +621,17 @@ public IRubyObject rewind() {

@JRubyMethod(name = {"exists?", "exist?"}, meta = true, compat = RUBY1_9)
public static IRubyObject exist(ThreadContext context, IRubyObject recv, IRubyObject arg) {
Ruby runtime = context.runtime;
// Capture previous exception if any.
IRubyObject exception = context.runtime.getGlobalVariables().get("$!");
IRubyObject exception = runtime.getGlobalVariables().get("$!");
RubyString path = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, arg));

try {
return context.runtime.newFileStat(RubyFile.get_path(context, arg).asJavaString(), false).directory_p();
return runtime.newFileStat(path.asJavaString(), false).directory_p();
} catch (Exception e) {
// Restore $!
context.runtime.getGlobalVariables().set("$!", exception);
return context.runtime.newBoolean(false);
runtime.getGlobalVariables().set("$!", exception);
return runtime.newBoolean(false);
}
}

Expand Down
79 changes: 48 additions & 31 deletions core/src/main/java/org/jruby/RubyFile.java
Expand Up @@ -75,6 +75,7 @@
import org.jruby.util.FileResource;
import org.jruby.util.JRubyFile;
import org.jruby.util.ResourceException;
import org.jruby.util.StringSupport;
import org.jruby.util.TypeConverter;
import org.jruby.util.encoding.Transcoder;
import org.jruby.util.io.BadDescriptorException;
Expand Down Expand Up @@ -451,7 +452,7 @@ public IRubyObject mtime(ThreadContext context) {

@JRubyMethod(meta = true, compat = RUBY1_9)
public static IRubyObject path(ThreadContext context, IRubyObject self, IRubyObject str) {
return get_path(context, str);
return StringSupport.checkEmbeddedNulls(context.runtime, get_path(context, str));
}

@JRubyMethod(name = {"path", "to_path"})
Expand Down Expand Up @@ -511,7 +512,7 @@ public IRubyObject inspect() {
public static IRubyObject basename(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;

RubyString origString = get_path(context,args[0]);
RubyString origString = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[0]));
Encoding origEncoding = origString.getEncoding();
String name = origString.toString();

Expand Down Expand Up @@ -652,11 +653,12 @@ public static IRubyObject chown(ThreadContext context, IRubyObject recv, IRubyOb

@JRubyMethod(required = 1, meta = true)
public static IRubyObject dirname(ThreadContext context, IRubyObject recv, IRubyObject arg) {
RubyString filename = get_path(context, arg);
Ruby runtime = context.runtime;
RubyString filename = StringSupport.checkEmbeddedNulls(runtime, get_path(context, arg));

String jfilename = filename.asJavaString();

return context.runtime.newString(dirname(context, jfilename)).infectBy(filename);
return runtime.newString(dirname(context, jfilename)).infectBy(filename);
}

public static String dirname(ThreadContext context, String jfilename) {
Expand Down Expand Up @@ -828,20 +830,23 @@ public static IRubyObject realpath(ThreadContext context, IRubyObject recv, IRub
*/
@JRubyMethod(name = {"fnmatch", "fnmatch?"}, required = 2, optional = 1, meta = true)
public static IRubyObject fnmatch(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
int flags = args.length == 3 ? RubyNumeric.num2int(args[2]) : 0;

ByteList pattern = args[0].convertToString().getByteList();
ByteList path = get_path(context, args[1]).getByteList();
ByteList path = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[1])).getByteList();

if (org.jruby.util.Dir.fnmatch(pattern.getUnsafeBytes(), pattern.getBegin(), pattern.getBegin()+pattern.getRealSize(), path.getUnsafeBytes(), path.getBegin(), path.getBegin()+path.getRealSize(), flags) == 0) {
return context.runtime.getTrue();
}
return context.runtime.getFalse();
return runtime.getFalse();
}

@JRubyMethod(name = "ftype", required = 1, meta = true)
public static IRubyObject ftype(ThreadContext context, IRubyObject recv, IRubyObject filename) {
return context.runtime.newFileStat(get_path(context, filename).getUnicodeValue(), true).ftype();
Ruby runtime = context.runtime;
RubyString path = StringSupport.checkEmbeddedNulls(runtime, get_path(context, filename));
return runtime.newFileStat(path.getUnicodeValue(), true).ftype();
}

/*
Expand All @@ -855,26 +860,30 @@ public static RubyString join(ThreadContext context, IRubyObject recv, IRubyObje

@JRubyMethod(name = "lstat", required = 1, meta = true)
public static IRubyObject lstat(ThreadContext context, IRubyObject recv, IRubyObject filename) {
String f = get_path(context, filename).getUnicodeValue();
return context.runtime.newFileStat(f, true);
Ruby runtime = context.runtime;
String f = StringSupport.checkEmbeddedNulls(runtime, get_path(context, filename)).getUnicodeValue();
return runtime.newFileStat(f, true);
}

@JRubyMethod(name = "stat", required = 1, meta = true)
public static IRubyObject stat(ThreadContext context, IRubyObject recv, IRubyObject filename) {
String f = get_path(context, filename).getUnicodeValue();
return context.runtime.newFileStat(f, false);
Ruby runtime = context.runtime;
String f = StringSupport.checkEmbeddedNulls(runtime, get_path(context, filename)).getUnicodeValue();
return runtime.newFileStat(f, false);
}

@JRubyMethod(name = "atime", required = 1, meta = true)
public static IRubyObject atime(ThreadContext context, IRubyObject recv, IRubyObject filename) {
String f = get_path(context, filename).getUnicodeValue();
return context.runtime.newFileStat(f, false).atime();
Ruby runtime = context.runtime;
String f = StringSupport.checkEmbeddedNulls(runtime, get_path(context, filename)).getUnicodeValue();
return runtime.newFileStat(f, false).atime();
}

@JRubyMethod(name = "ctime", required = 1, meta = true)
public static IRubyObject ctime(ThreadContext context, IRubyObject recv, IRubyObject filename) {
String f = get_path(context, filename).getUnicodeValue();
return context.runtime.newFileStat(f, false).ctime();
Ruby runtime = context.runtime;
String f = StringSupport.checkEmbeddedNulls(runtime, get_path(context, filename)).getUnicodeValue();
return runtime.newFileStat(f, false).ctime();
}

@JRubyMethod(required = 1, rest = true, meta = true)
Expand Down Expand Up @@ -938,14 +947,16 @@ public static IRubyObject link(ThreadContext context, IRubyObject recv, IRubyObj

@JRubyMethod(name = "mtime", required = 1, meta = true)
public static IRubyObject mtime(ThreadContext context, IRubyObject recv, IRubyObject filename) {
return context.runtime.newFileStat(get_path(context, filename).getUnicodeValue(), false).mtime();
Ruby runtime = context.runtime;
String f = StringSupport.checkEmbeddedNulls(runtime, get_path(context, filename)).getUnicodeValue();
return runtime.newFileStat(f, false).mtime();
}

@JRubyMethod(required = 2, meta = true)
public static IRubyObject rename(ThreadContext context, IRubyObject recv, IRubyObject oldName, IRubyObject newName) {
Ruby runtime = context.runtime;
RubyString oldNameString = get_path(context, oldName);
RubyString newNameString = get_path(context, newName);
RubyString oldNameString = StringSupport.checkEmbeddedNulls(runtime, get_path(context, oldName));
RubyString newNameString = StringSupport.checkEmbeddedNulls(runtime, get_path(context, newName));

String newNameJavaString = newNameString.getUnicodeValue();
String oldNameJavaString = oldNameString.getUnicodeValue();
Expand Down Expand Up @@ -978,17 +989,18 @@ public static IRubyObject rename(ThreadContext context, IRubyObject recv, IRubyO

@JRubyMethod(required = 1, meta = true)
public static RubyArray split(ThreadContext context, IRubyObject recv, IRubyObject arg) {
RubyString filename = get_path(context, arg);
Ruby runtime = context.runtime;
RubyString filename = StringSupport.checkEmbeddedNulls(runtime, get_path(context, arg));

return context.runtime.newArray(dirname(context, recv, filename),
return runtime.newArray(dirname(context, recv, filename),
basename(context, recv, new IRubyObject[]{filename}));
}

@JRubyMethod(required = 2, meta = true)
public static IRubyObject symlink(ThreadContext context, IRubyObject recv, IRubyObject from, IRubyObject to) {
Ruby runtime = context.runtime;
RubyString fromStr = get_path(context, from);
RubyString toStr = get_path(context, to);
RubyString fromStr = StringSupport.checkEmbeddedNulls(runtime, get_path(context, from));
RubyString toStr = StringSupport.checkEmbeddedNulls(runtime, get_path(context, to));
String tovalue = toStr.getUnicodeValue();
tovalue = JRubyFile.create(runtime.getCurrentDirectory(), tovalue).getAbsolutePath();
try {
Expand Down Expand Up @@ -1032,7 +1044,8 @@ public static IRubyObject truncate(ThreadContext context, IRubyObject recv, IRub

@JRubyMethod(name = "truncate", required = 2, meta = true, compat = RUBY1_9)
public static IRubyObject truncate19(ThreadContext context, IRubyObject recv, IRubyObject arg1, IRubyObject arg2) {
return truncateCommon(context, recv, get_path(context, arg1), arg2);
RubyString path = StringSupport.checkEmbeddedNulls(context.runtime, get_path(context, arg1));
return truncateCommon(context, recv, path, arg2);
}

@JRubyMethod(meta = true, optional = 1)
Expand Down Expand Up @@ -1066,7 +1079,7 @@ public static IRubyObject utime(ThreadContext context, IRubyObject recv, IRubyOb
}

for (int i = 2, j = args.length; i < j; i++) {
RubyString filename = get_path(context, args[i]);
RubyString filename = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[i]));

JRubyFile fileToTouch = JRubyFile.create(runtime.getCurrentDirectory(),filename.getUnicodeValue());

Expand All @@ -1088,7 +1101,7 @@ public static IRubyObject unlink(ThreadContext context, IRubyObject recv, IRubyO
Ruby runtime = context.runtime;

for (int i = 0; i < args.length; i++) {
RubyString filename = get_path(context, args[i]);
RubyString filename = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[i]));
JRubyFile lToDelete = JRubyFile.create(runtime.getCurrentDirectory(), filename.getUnicodeValue());

boolean isSymlink = RubyFileTest.symlink_p(recv, filename).isTrue();
Expand Down Expand Up @@ -1149,7 +1162,7 @@ public void setEncoding(Encoding encoding) {
// mri: rb_open_file + rb_scan_open_args
private IRubyObject openFile19(ThreadContext context, IRubyObject args[]) {
Ruby runtime = context.runtime;
RubyString filename = get_path(context, args[0]);
RubyString filename = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[0]));

path = adjustRootPathOnWindows(runtime, filename.asJavaString(), runtime.getCurrentDirectory());

Expand Down Expand Up @@ -1393,7 +1406,8 @@ public static FileResource fileResource(ThreadContext context, IRubyObject pathO

}

return JRubyFile.createResource(runtime, get_path(context, pathOrFile).toString());
RubyString path = StringSupport.checkEmbeddedNulls(runtime, get_path(context, pathOrFile));
return JRubyFile.createResource(runtime, path.toString());
}
/**
* Get the fully-qualified JRubyFile object for the path, taking into
Expand All @@ -1408,7 +1422,9 @@ public static FileResource fileResource(IRubyObject pathOrFile) {
return JRubyFile.createResource(runtime, ((RubyIO) pathOrFile).openFile.getPath());
}

return JRubyFile.createResource(runtime, get_path(runtime.getCurrentContext(), pathOrFile).toString());
ThreadContext context = runtime.getCurrentContext();
RubyString path = StringSupport.checkEmbeddedNulls(runtime, get_path(context, pathOrFile));
return JRubyFile.createResource(runtime, path.toString());
}

@Deprecated // Use fileResource instead
Expand Down Expand Up @@ -1579,7 +1595,8 @@ private static boolean isWindowsDriveLetter(char c) {
private static IRubyObject expandPathInternal(ThreadContext context, IRubyObject recv, IRubyObject[] args, boolean expandUser, boolean canonicalize) {
Ruby runtime = context.runtime;

String relativePath = get_path(context, args[0]).getUnicodeValue();
RubyString origPath = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[0]));
String relativePath = origPath.getUnicodeValue();

// Special /dev/null of windows
if (Platform.IS_WINDOWS && ("NUL:".equalsIgnoreCase(relativePath) || "NUL".equalsIgnoreCase(relativePath))) {
Expand Down Expand Up @@ -1617,7 +1634,7 @@ private static IRubyObject expandPathInternal(ThreadContext context, IRubyObject
if ((args[1] instanceof RubyString) && args[1].asJavaString().startsWith("uri:")) {
cwd = args[1].asJavaString();
} else {
cwd = get_path(context, args[1]).getUnicodeValue();
cwd = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[1])).getUnicodeValue();

// Handle ~user paths.
if (expandUser) {
Expand Down Expand Up @@ -1941,7 +1958,7 @@ private static RubyString join(ThreadContext context, IRubyObject recv, RubyArra
element = inspectJoin(context, recv, ary, ((RubyArray)args[i]));
}
} else {
RubyString path = get_path(context, args[i]);
RubyString path = StringSupport.checkEmbeddedNulls(runtime, get_path(context, args[i]));
element = path.getUnicodeValue();
}

Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/jruby/RubyFileStat.java
Expand Up @@ -49,6 +49,7 @@
import org.jruby.util.FileResource;
import org.jruby.util.JRubyFile;
import org.jruby.util.JRubyNonExistentFile;
import org.jruby.util.StringSupport;

/**
* Implements File::Stat
Expand Down Expand Up @@ -126,6 +127,9 @@ private void setup(String filename, boolean lstat) {

@JRubyMethod(name = "initialize", required = 1, visibility = Visibility.PRIVATE, compat = CompatVersion.RUBY1_8)
public IRubyObject initialize(IRubyObject fname, Block unusedBlock) {
Ruby runtime = getRuntime();
ThreadContext context = runtime.getCurrentContext();
RubyString path = StringSupport.checkEmbeddedNulls(runtime, RubyFile.get_path(context, fname));
setup(fname.convertToString().toString(), false);

return this;
Expand Down

0 comments on commit f41b6d9

Please sign in to comment.