package org.eclipse.jgit.transport;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
+import java.text.MessageFormat;
import java.util.zip.Deflater;
+import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.storage.file.PackFile;
import org.eclipse.jgit.util.NB;
import org.eclipse.jgit.util.TemporaryBuffer;
+import org.eclipse.jgit.util.io.UnionInputStream;
import org.junit.After;
import org.junit.Test;
p.parse(NullProgressMonitor.INSTANCE);
}
+ @Test
+ public void testPackWithTrailingGarbage() 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 | 4);
+ a.copyRawTo(pack);
+ deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
+ digest(pack);
+
+ PackParser p = index(new UnionInputStream(
+ new ByteArrayInputStream(pack.toByteArray()),
+ new ByteArrayInputStream(new byte[] { 0x7e })));
+ p.setAllowThin(true);
+ p.setCheckEofAfterPackFooter(true);
+ try {
+ p.parse(NullProgressMonitor.INSTANCE);
+ fail("Pack with trailing garbage was accepted");
+ } catch (IOException err) {
+ assertEquals(
+ MessageFormat.format(JGitText.get().expectedEOFReceived, "\\x73"),
+ err.getMessage());
+ }
+ }
+
private void packHeader(TemporaryBuffer.Heap tinyPack, int cnt)
throws IOException {
final byte[] hdr = new byte[8];
private boolean needBaseObjectIds;
+ private boolean checkEofAfterPackFooter;
+
private long objectCount;
private PackedObjectInfo[] entries;
this.needBaseObjectIds = b;
}
+ /** @return true if the EOF should be read from the input after the footer. */
+ public boolean isCheckEofAfterPackFooter() {
+ return checkEofAfterPackFooter;
+ }
+
+ /**
+ * Ensure EOF is read from the input stream after the footer.
+ *
+ * @param b
+ * true if the EOF should be read; false if it is not checked.
+ */
+ public void setCheckEofAfterPackFooter(boolean b) {
+ checkEofAfterPackFooter = b;
+ }
+
/** @return the new objects that were sent by the user */
public ObjectIdSubclassMap<ObjectId> getNewObjectIds() {
if (newObjectIds != null)
System.arraycopy(buf, c, srcHash, 0, 20);
use(20);
+ // The input stream should be at EOF at this point. We do not support
+ // yielding back any remaining buffered data after the pack footer, so
+ // protocols that embed a pack stream are required to either end their
+ // stream with the pack, or embed the pack with a framing system like
+ // the SideBandInputStream does.
+
+ if (bAvail != 0)
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().expectedEOFReceived,
+ "\\x" + Integer.toHexString(buf[bOffset] & 0xff)));
+
+ if (isCheckEofAfterPackFooter()) {
+ int eof = in.read();
+ if (0 <= eof)
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().expectedEOFReceived,
+ "\\x" + Integer.toHexString(eof)));
+ }
+
if (!Arrays.equals(actHash, srcHash))
throw new CorruptObjectException(
JGitText.get().corruptObjectPackfileChecksumIncorrect);
parser.setAllowThin(true);
parser.setNeedNewObjectIds(checkReferencedIsReachable);
parser.setNeedBaseObjectIds(checkReferencedIsReachable);
+ parser.setCheckEofAfterPackFooter(!biDirectionalPipe);
parser.setObjectChecking(isCheckReceivedObjects());
parser.setLockMessage(lockMsg);
packLock = parser.parse(receiving, resolving);
import java.util.Set;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.lib.Constants;
final boolean sideband = options.contains(OPTION_SIDE_BAND)
|| options.contains(OPTION_SIDE_BAND_64K);
+ if (!biDirectionalPipe) {
+ // Ensure the request was fully consumed. Any remaining input must
+ // be a protocol error. If we aren't at EOF the implementation is broken.
+ int eof = rawIn.read();
+ if (0 <= eof)
+ throw new CorruptObjectException(MessageFormat.format(
+ JGitText.get().expectedEOFReceived,
+ "\\x" + Integer.toHexString(eof)));
+ }
+
ProgressMonitor pm = NullProgressMonitor.INSTANCE;
OutputStream packOut = rawOut;
SideBandOutputStream msgOut = null;