summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java95
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java82
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java46
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java17
6 files changed, 242 insertions, 2 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
index 01e69cb44d..0de58bdf50 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
@@ -47,6 +47,7 @@
package org.eclipse.jgit.transport;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -60,6 +61,7 @@ import java.text.MessageFormat;
import java.util.zip.Deflater;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.TooLargeObjectInPackException;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
@@ -209,6 +211,99 @@ public class PackParserTest extends RepositoryTestCase {
}
}
+ @Test
+ public void testMaxObjectSizeFullBlob() throws Exception {
+ TestRepository d = new TestRepository(db);
+ final byte[] data = Constants.encode("0123456789");
+ d.blob(data);
+
+ TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+
+ packHeader(pack, 1);
+ pack.write((Constants.OBJ_BLOB) << 4 | 10);
+ deflate(pack, data);
+ digest(pack);
+
+ PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setMaxObjectSizeLimit(11);
+ p.parse(NullProgressMonitor.INSTANCE);
+
+ p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setMaxObjectSizeLimit(10);
+ p.parse(NullProgressMonitor.INSTANCE);
+
+ p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setMaxObjectSizeLimit(9);
+ try {
+ p.parse(NullProgressMonitor.INSTANCE);
+ fail("PackParser should have failed");
+ } catch (TooLargeObjectInPackException e) {
+ assertTrue(e.getMessage().contains("10")); // obj size
+ assertTrue(e.getMessage().contains("9")); // max obj size
+ }
+ }
+
+ @Test
+ public void testMaxObjectSizeDeltaBlock() throws Exception {
+ TestRepository d = new TestRepository(db);
+ RevBlob a = d.blob("a");
+
+ TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+
+ packHeader(pack, 1);
+ pack.write((Constants.OBJ_REF_DELTA) << 4 | 14);
+ a.copyRawTo(pack);
+ deflate(pack, new byte[] { 1, 11, 11, 'a', '0', '1', '2', '3', '4',
+ '5', '6', '7', '8', '9' });
+ digest(pack);
+
+ PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setAllowThin(true);
+ p.setMaxObjectSizeLimit(14);
+ p.parse(NullProgressMonitor.INSTANCE);
+
+ p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setAllowThin(true);
+ p.setMaxObjectSizeLimit(13);
+ try {
+ p.parse(NullProgressMonitor.INSTANCE);
+ fail("PackParser should have failed");
+ } catch (TooLargeObjectInPackException e) {
+ assertTrue(e.getMessage().contains("13")); // max obj size
+ assertFalse(e.getMessage().contains("14")); // no delta size
+ }
+ }
+
+ @Test
+ public void testMaxObjectSizeDeltaResultSize() throws Exception {
+ TestRepository d = new TestRepository(db);
+ RevBlob a = d.blob("0123456789");
+
+ TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
+
+ packHeader(pack, 1);
+ pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
+ a.copyRawTo(pack);
+ deflate(pack, new byte[] { 10, 11, 1, 'a' });
+ digest(pack);
+
+ PackParser p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setAllowThin(true);
+ p.setMaxObjectSizeLimit(11);
+ p.parse(NullProgressMonitor.INSTANCE);
+
+ p = index(new ByteArrayInputStream(pack.toByteArray()));
+ p.setAllowThin(true);
+ p.setMaxObjectSizeLimit(10);
+ try {
+ p.parse(NullProgressMonitor.INSTANCE);
+ fail("PackParser should have failed");
+ } catch (TooLargeObjectInPackException e) {
+ assertTrue(e.getMessage().contains("11")); // result obj size
+ assertTrue(e.getMessage().contains("10")); // max obj size
+ }
+ }
+
private void packHeader(TemporaryBuffer.Heap tinyPack, int cnt)
throws IOException {
final byte[] hdr = new byte[8];
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index 9fe603ff8d..a5fea35ab7 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -359,6 +359,8 @@ pushNotPermitted=push not permitted
rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry
readTimedOut=Read timed out
readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0}
+receivePackObjectTooLarge1=Object too large, rejecting the pack. Max object size limit is {0} bytes.
+receivePackObjectTooLarge2=Object too large ({0} bytes), rejecting the pack. Max object size limit is {1} bytes.
receivingObjects=Receiving objects
refAlreadyExists=Ref {0} already exists
refNotResolved=Ref {0} can not be resolved
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
index e64534753e..fcc6cafd5e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -419,6 +419,8 @@ public class JGitText extends TranslationBundle {
/***/ public String rawLogMessageDoesNotParseAsLogEntry;
/***/ public String readTimedOut;
/***/ public String readingObjectsFromLocalRepositoryFailed;
+ /***/ public String receivePackObjectTooLarge1;
+ /***/ public String receivePackObjectTooLarge2;
/***/ public String receivingObjects;
/***/ public String refAlreadyExists;
/***/ public String refNotResolved;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
new file mode 100644
index 0000000000..dbe480ab90
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011, Sasa Zivkov <sasa.zivkov@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.errors;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.jgit.JGitText;
+
+/** Thrown when PackParser finds an object larger than a predefined limit */
+public class TooLargeObjectInPackException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct a too large object in pack exception when the exact size of the
+ * too large object is not available. This will be used when we find out
+ * that a delta sequence is already larger than the maxObjectSizeLimit but
+ * don't want to inflate the delta just to find out the exact size of the
+ * resulting object.
+ *
+ * @param maxObjectSizeLimit
+ * the maximum object size limit
+ */
+ public TooLargeObjectInPackException(long maxObjectSizeLimit) {
+ super(MessageFormat.format(JGitText.get().receivePackObjectTooLarge1,
+ maxObjectSizeLimit));
+ }
+
+ /**
+ * Construct a too large object in pack exception when the exact size of the
+ * too large object is known.
+ *
+ * @param objectSize
+ * @param maxObjectSizeLimit
+ */
+ public TooLargeObjectInPackException(long objectSize,
+ long maxObjectSizeLimit) {
+ super(MessageFormat.format(JGitText.get().receivePackObjectTooLarge2,
+ objectSize, maxObjectSizeLimit));
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index 1b30e859ec..c62959565f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -61,6 +61,7 @@ import java.util.zip.Inflater;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.TooLargeObjectInPackException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.BatchingProgressMonitor;
import org.eclipse.jgit.lib.Constants;
@@ -180,6 +181,9 @@ public abstract class PackParser {
/** Message to protect the pack data from garbage collection. */
private String lockMessage;
+ /** Git object size limit */
+ private long maxObjectSizeLimit;
+
/**
* Initialize a pack parser.
*
@@ -366,6 +370,19 @@ public abstract class PackParser {
}
/**
+ * Set the maximum allowed Git object size.
+ * <p>
+ * If an object is larger than the given size the pack-parsing will throw an
+ * exception aborting the parsing.
+ *
+ * @param limit
+ * the Git object size limit. If zero then there is not limit.
+ */
+ public void setMaxObjectSizeLimit(long limit) {
+ maxObjectSizeLimit = limit;
+ }
+
+ /**
* Get the number of objects in the stream.
* <p>
* The object count is only available after {@link #parse(ProgressMonitor)}
@@ -584,8 +601,11 @@ public abstract class PackParser {
JGitText.get().unknownObjectType, info.type));
}
- visit.data = BinaryDelta.apply(visit.parent.data, //
- inflateAndReturn(Source.DATABASE, info.size));
+ byte[] delta = inflateAndReturn(Source.DATABASE, info.size);
+ checkIfTooLarge(type, BinaryDelta.getResultSize(delta));
+
+ visit.data = BinaryDelta.apply(visit.parent.data, delta);
+ delta = null;
if (!checkCRC(visit.delta.crc))
throw new IOException(MessageFormat.format(
@@ -613,6 +633,26 @@ public abstract class PackParser {
} while (visit != null);
}
+ private final void checkIfTooLarge(int typeCode, long size)
+ throws IOException {
+ if (0 < maxObjectSizeLimit && maxObjectSizeLimit < size)
+ switch (typeCode) {
+ case Constants.OBJ_COMMIT:
+ case Constants.OBJ_TREE:
+ case Constants.OBJ_BLOB:
+ case Constants.OBJ_TAG:
+ throw new TooLargeObjectInPackException(size, maxObjectSizeLimit);
+
+ case Constants.OBJ_OFS_DELTA:
+ case Constants.OBJ_REF_DELTA:
+ throw new TooLargeObjectInPackException(maxObjectSizeLimit);
+
+ default:
+ throw new IOException(MessageFormat.format(
+ JGitText.get().unknownObjectType, typeCode));
+ }
+ }
+
/**
* Read the header of the current object.
* <p>
@@ -856,6 +896,8 @@ public abstract class PackParser {
shift += 7;
}
+ checkIfTooLarge(typeCode, sz);
+
switch (typeCode) {
case Constants.OBJ_COMMIT:
case Constants.OBJ_TREE:
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index c6fe4d18c1..04f8946b2a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -193,6 +193,9 @@ public class ReceivePack {
private boolean checkReferencedIsReachable;
+ /** Git object size limit */
+ private long maxObjectSizeLimit;
+
/**
* Create a new pack receive for an open repository.
*
@@ -493,6 +496,19 @@ public class ReceivePack {
timeout = seconds;
}
+ /**
+ * Set the maximum allowed Git object size.
+ * <p>
+ * If an object is larger than the given size the pack-parsing will throw an
+ * exception aborting the receive-pack operation.
+ *
+ * @param limit
+ * the Git object size limit. If zero then there is not limit.
+ */
+ public void setMaxObjectSizeLimit(final long limit) {
+ maxObjectSizeLimit = limit;
+ }
+
/** @return all of the command received by the current request. */
public List<ReceiveCommand> getAllCommands() {
return Collections.unmodifiableList(commands);
@@ -829,6 +845,7 @@ public class ReceivePack {
parser.setCheckEofAfterPackFooter(!biDirectionalPipe);
parser.setObjectChecking(isCheckReceivedObjects());
parser.setLockMessage(lockMsg);
+ parser.setMaxObjectSizeLimit(maxObjectSizeLimit);
packLock = parser.parse(receiving, resolving);
ins.flush();
} finally {