Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package org.aspectj.ajde.internal;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -24,25 +25,56 @@
*/
public class LstBuildConfigFileParser extends ConfigParser {

private final File topLevelConfigDirectory;
private List<File> importedFiles = new ArrayList<>();
private List<String> problemEntries = new ArrayList<>();

// private String currFilePath;

public LstBuildConfigFileParser(String currFilePath) {
// this.currFilePath = currFilePath;
File canonicalConfigFile;
try {
canonicalConfigFile = new File(currFilePath).getCanonicalFile();
} catch (IOException e) {
canonicalConfigFile = new File(currFilePath).getAbsoluteFile();
}
this.topLevelConfigDirectory = canonicalConfigFile.getParentFile();
}

protected void showWarning(String message) {
problemEntries.add(message);
}

protected void parseImportedConfigFile(String relativeFilePath) {
importedFiles.add(makeFile(relativeFilePath));
super.files.add(new File(relativeFilePath));
File importedFile = makeFile(relativeFilePath);
if (!isSafeImportedConfigFile(importedFile)) {
showError("imported config file outside project root directory: " + relativeFilePath);
return;
}
importedFiles.add(importedFile);
super.files.add(importedFile);
super.parseImportedConfigFile(relativeFilePath);
}

private boolean isSafeImportedConfigFile(File importedFile) {
if (topLevelConfigDirectory == null) {
return false;
}
try {
File safeRoot = topLevelConfigDirectory.getCanonicalFile();
File candidate = importedFile.getCanonicalFile();
while (candidate != null) {
if (safeRoot.equals(candidate)) {
return true;
}
candidate = candidate.getParentFile();
}
} catch (IOException e) {
// If canonicalization fails, fall back to rejecting the import.
}
return false;
}

protected void showError(String message) {
problemEntries.add(message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.aspectj.ajde.internal;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

Expand Down Expand Up @@ -76,5 +77,26 @@ public void testFileRelativePathSameDir() throws IOException {
assertTrue("single file", true);
}

public void testRejectImportedConfigFileOutsideProjectRoot() throws IOException {
File outsideConfig = new File(getWorkingDir(), "outside.lst");
try (FileOutputStream out = new FileOutputStream(outsideConfig)) {
out.write("A.java\n".getBytes("UTF-8"));
}

File configFile = openFile("path-traversal.lst");
try (FileOutputStream out = new FileOutputStream(configFile)) {
out.write("@../outside.lst\n".getBytes("UTF-8"));
}

BuildConfigModel model = buildConfigManager.buildModel(configFile.getCanonicalPath());
assertNotNull("expected model root to be created", model.getRoot());

List messages = getErrorMessages("path-traversal.lst");
assertFalse("expected an error message for imports outside project root", messages.isEmpty());

TestMessage message = (TestMessage) messages.get(0);
assertTrue(message.getContainedMessage().getMessage(), message.getContainedMessage().getMessage().contains("outside project root directory"));
}

}

Loading