1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package org.eclipse.jgit.lib;
39
40 import static org.junit.Assert.assertTrue;
41 import static org.junit.Assert.fail;
42
43 import java.io.File;
44 import java.io.IOException;
45 import java.util.Arrays;
46
47 import org.eclipse.jgit.api.Git;
48 import org.eclipse.jgit.api.errors.GitAPIException;
49 import org.eclipse.jgit.dircache.InvalidPathException;
50 import org.eclipse.jgit.junit.MockSystemReader;
51 import org.eclipse.jgit.junit.RepositoryTestCase;
52 import org.eclipse.jgit.revwalk.RevWalk;
53 import org.eclipse.jgit.util.SystemReader;
54 import org.junit.Test;
55
56 public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase {
57
58 protected ObjectId theHead;
59 protected ObjectId theMerge;
60
61 @Test
62 public void testMaliciousAbsolutePathIsOk() throws Exception {
63 testMaliciousPathGoodFirstCheckout("ok");
64 }
65
66 @Test
67 public void testMaliciousAbsolutePathIsOkSecondCheckout() throws Exception {
68 testMaliciousPathGoodSecondCheckout("ok");
69 }
70
71 @Test
72 public void testMaliciousAbsolutePathIsOkTwoLevels() throws Exception {
73 testMaliciousPathGoodSecondCheckout("a", "ok");
74 }
75
76 @Test
77 public void testMaliciousAbsolutePath() throws Exception {
78 testMaliciousPathBadFirstCheckout("/tmp/x");
79 }
80
81 @Test
82 public void testMaliciousAbsolutePathSecondCheckout() throws Exception {
83 testMaliciousPathBadSecondCheckout("/tmp/x");
84 }
85
86 @Test
87 public void testMaliciousAbsolutePathTwoLevelsFirstBad() throws Exception {
88 testMaliciousPathBadFirstCheckout("/tmp/x", "y");
89 }
90
91 @Test
92 public void testMaliciousAbsolutePathTwoLevelsSecondBad() throws Exception {
93 testMaliciousPathBadFirstCheckout("y", "/tmp/x");
94 }
95
96 @Test
97 public void testMaliciousAbsoluteCurDrivePathWindows() throws Exception {
98 ((MockSystemReader) SystemReader.getInstance()).setWindows();
99 testMaliciousPathBadFirstCheckout("\\somepath");
100 }
101
102 @Test
103 public void testMaliciousAbsoluteCurDrivePathWindowsOnUnix()
104 throws Exception {
105 ((MockSystemReader) SystemReader.getInstance()).setUnix();
106 testMaliciousPathGoodFirstCheckout("\\somepath");
107 }
108
109 @Test
110 public void testMaliciousAbsoluteUNCPathWindows1() throws Exception {
111 ((MockSystemReader) SystemReader.getInstance()).setWindows();
112 testMaliciousPathBadFirstCheckout("\\\\somepath");
113 }
114
115 @Test
116 public void testMaliciousAbsoluteUNCPathWindows1OnUnix() throws Exception {
117 ((MockSystemReader) SystemReader.getInstance()).setUnix();
118 testMaliciousPathGoodFirstCheckout("\\\\somepath");
119 }
120
121 @Test
122 public void testMaliciousAbsoluteUNCPathWindows2() throws Exception {
123 ((MockSystemReader) SystemReader.getInstance()).setWindows();
124 testMaliciousPathBadFirstCheckout("\\/somepath");
125 }
126
127 @Test
128 public void testMaliciousAbsoluteUNCPathWindows2OnUnix() throws Exception {
129 ((MockSystemReader) SystemReader.getInstance()).setUnix();
130 testMaliciousPathBadFirstCheckout("\\/somepath");
131 }
132
133 @Test
134 public void testMaliciousAbsoluteWindowsPath1() throws Exception {
135 ((MockSystemReader) SystemReader.getInstance()).setWindows();
136 testMaliciousPathBadFirstCheckout("c:\\temp\\x");
137 }
138
139 @Test
140 public void testMaliciousAbsoluteWindowsPath1OnUnix() throws Exception {
141 if (File.separatorChar == '\\')
142 return;
143 ((MockSystemReader) SystemReader.getInstance()).setUnix();
144 testMaliciousPathGoodFirstCheckout("c:\\temp\\x");
145 }
146
147 @Test
148 public void testMaliciousAbsoluteWindowsPath2() throws Exception {
149 ((MockSystemReader) SystemReader.getInstance()).setCurrentPlatform();
150 testMaliciousPathBadFirstCheckout("c:/temp/x");
151 }
152
153 @Test
154 public void testMaliciousGitPath1() throws Exception {
155 testMaliciousPathBadFirstCheckout(".git/konfig");
156 }
157
158 @Test
159 public void testMaliciousGitPath2() throws Exception {
160 testMaliciousPathBadFirstCheckout(".git", "konfig");
161 }
162
163 @Test
164 public void testMaliciousGitPath1Case() throws Exception {
165 ((MockSystemReader) SystemReader.getInstance()).setWindows();
166 testMaliciousPathBadFirstCheckout(".Git/konfig");
167 }
168
169 @Test
170 public void testMaliciousGitPath2Case() throws Exception {
171 ((MockSystemReader) SystemReader.getInstance()).setWindows();
172 testMaliciousPathBadFirstCheckout(".gIt", "konfig");
173 }
174
175 @Test
176 public void testMaliciousGitPath3Case() throws Exception {
177 ((MockSystemReader) SystemReader.getInstance()).setWindows();
178 testMaliciousPathBadFirstCheckout(".giT", "konfig");
179 }
180
181 @Test
182 public void testMaliciousGitPathEndSpaceWindows() throws Exception {
183 ((MockSystemReader) SystemReader.getInstance()).setWindows();
184 testMaliciousPathBadFirstCheckout(".git ", "konfig");
185 }
186
187 @Test
188 public void testMaliciousGitPathEndSpaceUnixOk() throws Exception {
189 testMaliciousPathBadFirstCheckout(".git ", "konfig");
190 }
191
192 @Test
193 public void testMaliciousGitPathEndDotWindows1() throws Exception {
194 ((MockSystemReader) SystemReader.getInstance()).setWindows();
195 testMaliciousPathBadFirstCheckout(".git.", "konfig");
196 }
197
198 @Test
199 public void testMaliciousGitPathEndDotWindows2() throws Exception {
200 ((MockSystemReader) SystemReader.getInstance()).setWindows();
201 testMaliciousPathBadFirstCheckout(".f.");
202 }
203
204 @Test
205 public void testMaliciousGitPathEndDotWindows3() throws Exception {
206 ((MockSystemReader) SystemReader.getInstance()).setWindows();
207 testMaliciousPathGoodFirstCheckout(".f");
208 }
209
210 @Test
211 public void testMaliciousGitPathEndDotUnixOk() throws Exception {
212 testMaliciousPathBadFirstCheckout(".git.", "konfig");
213 }
214
215 @Test
216 public void testMaliciousPathDotDot() throws Exception {
217 ((MockSystemReader) SystemReader.getInstance()).setCurrentPlatform();
218 testMaliciousPathBadFirstCheckout("..", "no");
219 }
220
221 @Test
222 public void testMaliciousPathDot() throws Exception {
223 ((MockSystemReader) SystemReader.getInstance()).setCurrentPlatform();
224 testMaliciousPathBadFirstCheckout(".", "no");
225 }
226
227 @Test
228 public void testMaliciousPathEmptyUnix() throws Exception {
229 ((MockSystemReader) SystemReader.getInstance()).setUnix();
230 testMaliciousPathBadFirstCheckout("", "no");
231 }
232
233 @Test
234 public void testMaliciousPathEmptyWindows() throws Exception {
235 ((MockSystemReader) SystemReader.getInstance()).setWindows();
236 testMaliciousPathBadFirstCheckout("", "no");
237 }
238
239 @Test
240 public void testMaliciousWindowsADS() throws Exception {
241 ((MockSystemReader) SystemReader.getInstance()).setWindows();
242 testMaliciousPathBadFirstCheckout("some:path");
243 }
244
245 @Test
246 public void testMaliciousWindowsADSOnUnix() throws Exception {
247 if (File.separatorChar == '\\')
248 return;
249 ((MockSystemReader) SystemReader.getInstance()).setUnix();
250 testMaliciousPathGoodFirstCheckout("some:path");
251 }
252
253 @Test
254 public void testForbiddenNamesOnWindowsEgCon() throws Exception {
255 ((MockSystemReader) SystemReader.getInstance()).setWindows();
256 testMaliciousPathBadFirstCheckout("con");
257 }
258
259 @Test
260 public void testForbiddenNamesOnWindowsEgConDotSuffix() throws Exception {
261 ((MockSystemReader) SystemReader.getInstance()).setWindows();
262 testMaliciousPathBadFirstCheckout("con.txt");
263 }
264
265 @Test
266 public void testForbiddenNamesOnWindowsEgLpt1() throws Exception {
267 ((MockSystemReader) SystemReader.getInstance()).setWindows();
268 testMaliciousPathBadFirstCheckout("lpt1");
269 }
270
271 @Test
272 public void testForbiddenNamesOnWindowsEgLpt1DotSuffix() throws Exception {
273 ((MockSystemReader) SystemReader.getInstance()).setWindows();
274 testMaliciousPathBadFirstCheckout("lpt1.txt");
275 }
276
277 @Test
278 public void testForbiddenNamesOnWindowsEgDotCon() throws Exception {
279 ((MockSystemReader) SystemReader.getInstance()).setWindows();
280 testMaliciousPathGoodFirstCheckout(".con");
281 }
282
283 @Test
284 public void testForbiddenNamesOnWindowsEgLpr() throws Exception {
285 ((MockSystemReader) SystemReader.getInstance()).setWindows();
286 testMaliciousPathGoodFirstCheckout("lpt");
287 }
288
289 @Test
290 public void testForbiddenNamesOnWindowsEgCon1() throws Exception {
291 ((MockSystemReader) SystemReader.getInstance()).setWindows();
292 testMaliciousPathGoodFirstCheckout("con1");
293 }
294
295 @Test
296 public void testForbiddenWindowsNamesOnUnixEgCon() throws Exception {
297 if (File.separatorChar == '\\')
298 return;
299 testMaliciousPathGoodFirstCheckout("con");
300 }
301
302 @Test
303 public void testForbiddenWindowsNamesOnUnixEgLpt1() throws Exception {
304 if (File.separatorChar == '\\')
305 return;
306 testMaliciousPathGoodFirstCheckout("lpt1");
307 }
308
309 private void testMaliciousPathBadFirstCheckout(String... paths)
310 throws Exception {
311 testMaliciousPath(false, false, paths);
312 }
313
314 private void testMaliciousPathBadSecondCheckout(String... paths) throws Exception {
315 testMaliciousPath(false, true, paths);
316 }
317
318 private void testMaliciousPathGoodFirstCheckout(String... paths)
319 throws Exception {
320 testMaliciousPath(true, false, paths);
321 }
322
323 private void testMaliciousPathGoodSecondCheckout(String... paths) throws Exception {
324 testMaliciousPath(true, true, paths);
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339 private void testMaliciousPath(boolean good, boolean secondCheckout,
340 String... path) throws GitAPIException, IOException {
341 try (Git git = new Git(db);
342 RevWalk revWalk = new RevWalk(git.getRepository())) {
343 ObjectInserter newObjectInserter;
344 newObjectInserter = git.getRepository().newObjectInserter();
345 ObjectId blobId = newObjectInserter.insert(Constants.OBJ_BLOB,
346 "data".getBytes());
347 newObjectInserter = git.getRepository().newObjectInserter();
348 FileMode mode = FileMode.REGULAR_FILE;
349 ObjectId insertId = blobId;
350 for (int i = path.length - 1; i >= 0; --i) {
351 TreeFormatter treeFormatter = new TreeFormatter();
352 treeFormatter.append("goodpath", mode, insertId);
353 insertId = newObjectInserter.insert(treeFormatter);
354 mode = FileMode.TREE;
355 }
356 newObjectInserter = git.getRepository().newObjectInserter();
357 CommitBuilder commitBuilder = new CommitBuilder();
358 commitBuilder.setAuthor(author);
359 commitBuilder.setCommitter(committer);
360 commitBuilder.setMessage("foo#1");
361 commitBuilder.setTreeId(insertId);
362 ObjectId firstCommitId = newObjectInserter.insert(commitBuilder);
363
364 newObjectInserter = git.getRepository().newObjectInserter();
365 mode = FileMode.REGULAR_FILE;
366 insertId = blobId;
367 for (int i = path.length - 1; i >= 0; --i) {
368 TreeFormatter treeFormatter = new TreeFormatter();
369 treeFormatter.append(path[i].getBytes(), 0,
370 path[i].getBytes().length,
371 mode, insertId, true);
372 insertId = newObjectInserter.insert(treeFormatter);
373 mode = FileMode.TREE;
374 }
375
376
377 commitBuilder = new CommitBuilder();
378 commitBuilder.setAuthor(author);
379 commitBuilder.setCommitter(committer);
380 commitBuilder.setMessage("foo#2");
381 commitBuilder.setTreeId(insertId);
382 commitBuilder.setParentId(firstCommitId);
383 ObjectId commitId = newObjectInserter.insert(commitBuilder);
384
385 if (!secondCheckout)
386 git.checkout().setStartPoint(revWalk.parseCommit(firstCommitId))
387 .setName("refs/heads/master").setCreateBranch(true).call();
388 try {
389 if (secondCheckout) {
390 git.checkout().setStartPoint(revWalk.parseCommit(commitId))
391 .setName("refs/heads/master").setCreateBranch(true)
392 .call();
393 } else {
394 git.branchCreate().setName("refs/heads/next")
395 .setStartPoint(commitId.name()).call();
396 git.checkout().setName("refs/heads/next")
397 .call();
398 }
399 if (!good)
400 fail("Checkout of Tree " + Arrays.asList(path) + " should fail");
401 } catch (InvalidPathException e) {
402 if (good)
403 throw e;
404 assertTrue(e.getMessage().startsWith("Invalid path"));
405 }
406 }
407 }
408
409 }