Browse Source

ObjectChecker: Disallow ".git." and ".git<space>"

Windows treats "foo." and "foo " as "foo". The ".git" directory is
special, as it contains metadata for a local Git repository. Disallow
variations that Windows considers to be the same.

Change-Id: I28eb48859a95a89111b4987c91de97557e3bb539
stable-3.4
Shawn Pearce 10 years ago committed by Matthias Sohn
parent
commit
10310bf8ef
  1. 10
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java
  2. 96
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
  3. 28
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java

10
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutMaliciousPathTest.java

@ -186,10 +186,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase {
@Test @Test
public void testMaliciousGitPathEndSpaceUnixOk() throws Exception { public void testMaliciousGitPathEndSpaceUnixOk() throws Exception {
if (File.separatorChar == '\\') testMaliciousPathBadFirstCheckout(".git ", "konfig");
return; // cannot emulate Unix on Windows for this test
((MockSystemReader) SystemReader.getInstance()).setUnix();
testMaliciousPathGoodFirstCheckout(".git ", "konfig");
} }
@Test @Test
@ -212,10 +209,7 @@ public class DirCacheCheckoutMaliciousPathTest extends RepositoryTestCase {
@Test @Test
public void testMaliciousGitPathEndDotUnixOk() throws Exception { public void testMaliciousGitPathEndDotUnixOk() throws Exception {
if (File.separatorChar == '\\') testMaliciousPathBadFirstCheckout(".git.", "konfig");
return; // cannot emulate Unix on Windows for this test
((MockSystemReader) SystemReader.getInstance()).setUnix();
testMaliciousPathGoodFirstCheckout(".git.", "konfig");
} }
@Test @Test

96
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java

@ -1307,6 +1307,102 @@ public class ObjectCheckerTest {
} }
} }
@Test
public void testInvalidTreeNameIsDotGitDot() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git.");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git.'", e.getMessage());
}
}
@Test
public void testValidTreeNameIsDotGitDotDot()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git..");
checker.checkTree(Constants.encodeASCII(b.toString()));
}
@Test
public void testInvalidTreeNameIsDotGitSpace() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git ");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git '", e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsDotGitSomething()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitSomethingSpaceSomething()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoo bar");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitSomethingDot()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar.");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitSomethingDotDot()
throws CorruptObjectException {
StringBuilder b = new StringBuilder();
entry(b, "100644 .gitfoobar..");
byte[] data = Constants.encodeASCII(b.toString());
checker.checkTree(data);
}
@Test
public void testInvalidTreeNameIsDotGitDotSpace() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git. ");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git. '", e.getMessage());
}
}
@Test
public void testInvalidTreeNameIsDotGitSpaceDot() {
StringBuilder b = new StringBuilder();
entry(b, "100644 .git . ");
byte[] data = Constants.encodeASCII(b.toString());
try {
checker.checkTree(data);
fail("incorrectly accepted an invalid tree");
} catch (CorruptObjectException e) {
assertEquals("invalid name '.git . '", e.getMessage());
}
}
@Test @Test
public void testInvalidTreeTruncatedInName() { public void testInvalidTreeTruncatedInName() {
final StringBuilder b = new StringBuilder(); final StringBuilder b = new StringBuilder();

28
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java

@ -453,7 +453,13 @@ public class ObjectChecker {
throw new CorruptObjectException("invalid name '..'"); throw new CorruptObjectException("invalid name '..'");
break; break;
case 4: case 4:
if (isDotGit(raw, ptr + 1)) if (isGit(raw, ptr + 1))
throw new CorruptObjectException(String.format(
"invalid name '%s'",
RawParseUtils.decode(raw, ptr, end)));
break;
default:
if (end - ptr > 4 && isNormalizedGit(raw, ptr + 1, end))
throw new CorruptObjectException(String.format( throw new CorruptObjectException(String.format(
"invalid name '%s'", "invalid name '%s'",
RawParseUtils.decode(raw, ptr, end))); RawParseUtils.decode(raw, ptr, end)));
@ -540,12 +546,30 @@ public class ObjectChecker {
return 1 <= c && c <= 31; return 1 <= c && c <= 31;
} }
private static boolean isDotGit(byte[] buf, int p) { private static boolean isGit(byte[] buf, int p) {
return toLower(buf[p]) == 'g' return toLower(buf[p]) == 'g'
&& toLower(buf[p + 1]) == 'i' && toLower(buf[p + 1]) == 'i'
&& toLower(buf[p + 2]) == 't'; && toLower(buf[p + 2]) == 't';
} }
private static boolean isNormalizedGit(byte[] raw, int ptr, int end) {
if (isGit(raw, ptr)) {
int dots = 0;
boolean space = false;
int p = end - 1;
for (; (ptr + 2) < p; p--) {
if (raw[p] == '.')
dots++;
else if (raw[p] == ' ')
space = true;
else
break;
}
return p == ptr + 2 && (dots == 1 || space);
}
return false;
}
private static char toLower(byte b) { private static char toLower(byte b) {
if ('A' <= b && b <= 'Z') if ('A' <= b && b <= 'Z')
return (char) (b + ('a' - 'A')); return (char) (b + ('a' - 'A'));

Loading…
Cancel
Save