Skip to content

Commit 3105d63

Browse files
authored
sanitize path with revision for diff.jsp (#4834)
1 parent 27968d6 commit 3105d63

File tree

4 files changed

+55
-16
lines changed

4 files changed

+55
-16
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/web/Laundromat.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,21 @@
2525
import org.jetbrains.annotations.NotNull;
2626
import org.jetbrains.annotations.Nullable;
2727

28+
import java.util.ArrayList;
2829
import java.util.Arrays;
2930
import java.util.Collection;
31+
import java.util.List;
3032
import java.util.Map;
3133
import java.util.Optional;
3234
import java.util.stream.Collectors;
3335
import java.util.stream.Stream;
3436

3537
/**
36-
* Represents a container for sanitizing methods for avoiding classifications as
37-
* taint bugs.
38+
* Represents a container for sanitizing methods for avoiding classifications as taint bugs.
3839
*/
3940
public class Laundromat {
4041

41-
private static final String ESC_N_R_T_F = "[\\n\\r\\t\\f]";
42+
private static final String ESC_N_R_T_F = "[\\n\\r\\t\\f\\u0000]";
4243
private static final String ESG_N_R_T_F_1_N = ESC_N_R_T_F + "+";
4344

4445
/**
@@ -62,14 +63,35 @@ public static String launderServerName(String value) {
6263

6364
/**
6465
* Sanitize {@code value} where it will be used in subsequent OpenGrok
65-
* (non-logging) processing.
66+
* (non-logging) processing. The value is assumed to represent a revision string,
67+
* not including file path.
6668
* @return {@code null} if null or else {@code value} with anything besides
6769
* alphanumeric or {@code :} characters removed.
6870
*/
6971
public static String launderRevision(String value) {
7072
return replaceAll(value, "[^a-zA-Z0-9:]", "");
7173
}
7274

75+
/**
76+
* Sanitize {@code value} where it will be used in subsequent OpenGrok
77+
* (non-logging) processing. The value is assumed to represent URI path,
78+
* not necessarily existent on the file system. Further, it assumes that the URI path
79+
* is already decoded, e.g. {@code %2e%2e} turned into {@code ..}.
80+
* @return {@code value} with path traversal path components {@code /../} removed
81+
* and null characters replaced with {@code _}.
82+
*/
83+
public static String launderUriPath(@NotNull String value) {
84+
List<String> pathElements = new ArrayList<>();
85+
String uriPath = Laundromat.launderInput(value);
86+
for (String pathElement : uriPath.split("/")) {
87+
if (pathElement.isEmpty() || pathElement.equals("..")) {
88+
continue;
89+
}
90+
pathElements.add(pathElement);
91+
}
92+
return (uriPath.startsWith("/") ? "/" : "") + String.join("/", pathElements);
93+
}
94+
7395
/**
7496
* Sanitize {@code value} where it will be used in a Lucene query.
7597
* @return {@code null} if null or else {@code value} with "pattern-breaking

opengrok-indexer/src/test/java/org/opengrok/indexer/web/LaundromatTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,22 @@ void testLaunderServerName(Pair<String, String> param) {
7070
assertEquals(param.getLeft(), param.getRight());
7171
}
7272

73+
private static Stream<Pair<String, String>> getParamsForTestLaunderUriPath() {
74+
return Stream.of(Pair.of("foo", Laundromat.launderUriPath("../../../foo")),
75+
Pair.of("/foo/bar", Laundromat.launderUriPath("/foo/../../bar")),
76+
Pair.of("/foo/bar..", Laundromat.launderUriPath("/foo/bar..")),
77+
Pair.of("/foo/bar", Laundromat.launderUriPath("/foo//bar")),
78+
Pair.of("..foo/bar", Laundromat.launderUriPath("..foo/bar")),
79+
Pair.of("/foo/bar.txt", Laundromat.launderUriPath("/foo/bar.txt")),
80+
Pair.of("/foo/bar_.txt", Laundromat.launderUriPath("/foo/bar\u0000.txt")));
81+
}
82+
83+
@ParameterizedTest
84+
@MethodSource("getParamsForTestLaunderUriPath")
85+
void testLaunderUriPath(Pair<String, String> param) {
86+
assertEquals(param.getLeft(), param.getRight());
87+
}
88+
7389
@Test
7490
void launderLogMap() {
7591
HashMap<String, String[]> testMap = new HashMap<>();

opengrok-web/src/main/java/org/opengrok/web/PageConfig.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -232,34 +232,31 @@ public String getHeaderData() {
232232
}
233233

234234
/**
235-
* Extract file path and revision strings from the URL.
236-
* @param data DiffData object
235+
* Extract file path and revision strings from the URI. Basically the request URI looks like this:
236+
* {@code http://$site/$webapp/diff/$resourceFile?r1=$fileA@$revA&r2=$fileB@$revB}
237+
* The code extracts file path and revision from the URI.
238+
* @param data DiffData object (output parameter)
237239
* @param context context path
238240
* @param filepath file path array (output parameter)
239241
* @return true if the extraction was successful, false otherwise
240242
* (in which case {@link DiffData#errorMsg} will be set)
241243
*/
242244
private boolean getFileRevision(DiffData data, String context, String[] filepath) {
243-
/*
244-
* Basically the request URI looks like this:
245-
* http://$site/$webapp/diff/$resourceFile?r1=$fileA@$revA&r2=$fileB@$revB
246-
* The code below extracts file path and revision from the URI.
247-
*/
248245
for (int i = 1; i <= 2; i++) {
249246
String p = req.getParameter(QueryParameters.REVISION_PARAM + i);
250247
if (p != null) {
251248
int j = p.lastIndexOf("@");
252249
if (j != -1) {
253-
filepath[i - 1] = p.substring(0, j);
254-
data.rev[i - 1] = p.substring(j + 1);
250+
filepath[i - 1] = Laundromat.launderUriPath(p.substring(0, j));
251+
data.rev[i - 1] = Laundromat.launderRevision(p.substring(j + 1));
255252
}
256253
}
257254
}
258255

259256
if (data.rev[0] == null || data.rev[1] == null
260257
|| data.rev[0].isEmpty() || data.rev[1].isEmpty()
261258
|| data.rev[0].equals(data.rev[1])) {
262-
data.errorMsg = "Please pick two revisions to compare the changed "
259+
data.errorMsg = "Please pick two revisions to compare the changes "
263260
+ "from the <a href=\"" + context + Prefix.HIST_L
264261
+ getUriEncodedPath() + "\">history</a>";
265262
return false;

opengrok-web/src/test/java/org/opengrok/web/DiffTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/*
21-
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
21+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
2222
*/
2323
package org.opengrok.web;
2424

@@ -32,6 +32,8 @@
3232
import org.opengrok.indexer.util.TestRepository;
3333
import org.opengrok.indexer.web.QueryParameters;
3434

35+
import java.net.URL;
36+
3537
import static org.junit.jupiter.api.Assertions.assertAll;
3638
import static org.junit.jupiter.api.Assertions.assertEquals;
3739
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -50,7 +52,9 @@ class DiffTest {
5052
@BeforeAll
5153
static void setUp() throws Exception {
5254
repository = new TestRepository();
53-
repository.create(DiffTest.class.getResource("/repositories"));
55+
URL resource = DiffTest.class.getResource("/repositories");
56+
assertNotNull(resource);
57+
repository.create(resource);
5458

5559
env.setSourceRoot(repository.getSourceRoot());
5660
env.setDataRoot(repository.getDataRoot());

0 commit comments

Comments
 (0)