Browse Source

Allow users of ReceivePack access to the objects being sent

When implementing branch read access, we need to prove that the
newly created reference(s) point to objects that the user can see.

There are two ways that an object is reachable:
1)  It's reachable from a branch or change the user can see
2)  It was uploaded as part of the pack file the user sent us

This change adds additional methods in ReceivePack that will allow a
server to check the above conditions, in order to ensure that a user
is not trying to create a reference that they cannot see, or that a
malicious user isn't attempting to forge the SHA-1 of an object that
they cannot see in order to base a change off of it.

Change-Id: Ieba75b4f0331e06a03417c37f4ae1ebca4fbee5a
stable-0.7
Nico Sallembien 15 years ago
parent
commit
19126f70e9
  1. 75
      org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java
  2. 49
      org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java

75
org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008-2009, Google Inc. * Copyright (C) 2008-2010, Google Inc.
* Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log. * and other copyright owners as documented in the project's IP log.
@ -54,7 +54,10 @@ import java.io.RandomAccessFile;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.DataFormatException; import java.util.zip.DataFormatException;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@ -158,6 +161,8 @@ public class IndexPack {
private boolean keepEmpty; private boolean keepEmpty;
private boolean needBaseObjectIds;
private int outputVersion; private int outputVersion;
private final File dstPack; private final File dstPack;
@ -168,6 +173,8 @@ public class IndexPack {
private PackedObjectInfo[] entries; private PackedObjectInfo[] entries;
private Set<ObjectId> newObjectIds;
private int deltaCount; private int deltaCount;
private int entryCount; private int entryCount;
@ -176,6 +183,8 @@ public class IndexPack {
private ObjectIdSubclassMap<DeltaChain> baseById; private ObjectIdSubclassMap<DeltaChain> baseById;
private Set<ObjectId> baseIds;
private LongMap<UnresolvedDelta> baseByPos; private LongMap<UnresolvedDelta> baseByPos;
private byte[] objectData; private byte[] objectData;
@ -267,6 +276,54 @@ public class IndexPack {
keepEmpty = empty; keepEmpty = empty;
} }
/**
* Configure this index pack instance to keep track of new objects.
* <p>
* By default an index pack doesn't save the new objects that were created
* when it was instantiated. Setting this flag to {@code true} allows the
* caller to use {@link #getNewObjectIds()} to retrieve that list.
*
* @param b {@code true} to enable keeping track of new objects.
*/
public void setNeedNewObjectIds(boolean b) {
if (b)
newObjectIds = new HashSet<ObjectId>();
else
newObjectIds = null;
}
private boolean needNewObjectIds() {
return newObjectIds != null;
}
/**
* Configure this index pack instance to keep track of the objects assumed
* for delta bases.
* <p>
* By default an index pack doesn't save the objects that were used as delta
* bases. Setting this flag to {@code true} will allow the caller to
* use {@link #getBaseObjectIds()} to retrieve that list.
*
* @param b {@code true} to enable keeping track of delta bases.
*/
public void setNeedBaseObjectIds(boolean b) {
this.needBaseObjectIds = b;
}
/** @return the new objects that were sent by the user */
public Set<ObjectId> getNewObjectIds() {
return newObjectIds == null ?
Collections.<ObjectId>emptySet() : newObjectIds;
}
/**
* @return the set of objects the incoming pack assumed for delta purposes
*/
public Set<ObjectId> getBaseObjectIds() {
return baseIds == null ?
Collections.<ObjectId>emptySet() : baseIds;
}
/** /**
* Configure the checker used to validate received objects. * Configure the checker used to validate received objects.
* <p> * <p>
@ -333,6 +390,12 @@ public class IndexPack {
if (packOut == null) if (packOut == null)
throw new IOException("need packOut"); throw new IOException("need packOut");
resolveDeltas(progress); resolveDeltas(progress);
if (needBaseObjectIds) {
baseIds = new HashSet<ObjectId>();
for (DeltaChain c : baseById) {
baseIds.add(c);
}
}
if (entryCount < objectCount) { if (entryCount < objectCount) {
if (!fixThin) { if (!fixThin) {
throw new IOException("pack has " throw new IOException("pack has "
@ -453,7 +516,7 @@ public class IndexPack {
verifySafeObject(tempObjectId, type, data); verifySafeObject(tempObjectId, type, data);
oe = new PackedObjectInfo(pos, crc32, tempObjectId); oe = new PackedObjectInfo(pos, crc32, tempObjectId);
entries[entryCount++] = oe; addObjectAndTrack(oe);
} }
resolveChildDeltas(pos, type, data, oe); resolveChildDeltas(pos, type, data, oe);
@ -749,7 +812,7 @@ public class IndexPack {
verifySafeObject(tempObjectId, type, data); verifySafeObject(tempObjectId, type, data);
final int crc32 = (int) crc.getValue(); final int crc32 = (int) crc.getValue();
entries[entryCount++] = new PackedObjectInfo(pos, crc32, tempObjectId); addObjectAndTrack(new PackedObjectInfo(pos, crc32, tempObjectId));
} }
private void verifySafeObject(final AnyObjectId id, final int type, private void verifySafeObject(final AnyObjectId id, final int type,
@ -1112,4 +1175,10 @@ public class IndexPack {
if (!dstPack.delete()) if (!dstPack.delete())
dstPack.deleteOnExit(); dstPack.deleteOnExit();
} }
private void addObjectAndTrack(PackedObjectInfo oe) {
entries[entryCount++] = oe;
if (needNewObjectIds())
newObjectIds.add(oe);
}
} }

49
org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java

@ -153,6 +153,8 @@ public class ReceivePack {
private PrintWriter msgs; private PrintWriter msgs;
private IndexPack ip;
/** The refs we advertised as existing at the start of the connection. */ /** The refs we advertised as existing at the start of the connection. */
private Map<String, Ref> refs; private Map<String, Ref> refs;
@ -171,6 +173,10 @@ public class ReceivePack {
/** Lock around the received pack file, while updating refs. */ /** Lock around the received pack file, while updating refs. */
private PackLock packLock; private PackLock packLock;
private boolean needNewObjectIds;
private boolean needBaseObjectIds;
/** /**
* Create a new pack receive for an open repository. * Create a new pack receive for an open repository.
* *
@ -236,6 +242,45 @@ public class ReceivePack {
return refs; return refs;
} }
/**
* Configure this receive pack instance to keep track of the objects assumed
* for delta bases.
* <p>
* By default a receive pack doesn't save the objects that were used as
* delta bases. Setting this flag to {@code true} will allow the caller to
* use {@link #getBaseObjectIds()} to retrieve that list.
*
* @param b {@code true} to enable keeping track of delta bases.
*/
public void setNeedBaseObjectIds(boolean b) {
this.needBaseObjectIds = b;
}
/**
* @return the set of objects the incoming pack assumed for delta purposes
*/
public final Set<ObjectId> getBaseObjectIds() {
return ip.getBaseObjectIds();
}
/**
* Configure this receive pack instance to keep track of new objects.
* <p>
* By default a receive pack doesn't save the new objects that were created
* when it was instantiated. Setting this flag to {@code true} allows the
* caller to use {@link #getNewObjectIds()} to retrieve that list.
*
* @param b {@code true} to enable keeping track of new objects.
*/
public void setNeedNewObjectIds(boolean b) {
this.needNewObjectIds = b;
}
/** @return the new objects that were sent by the user */
public final Set<ObjectId> getNewObjectIds() {
return ip.getNewObjectIds();
}
/** /**
* @return true if this class expects a bi-directional pipe opened between * @return true if this class expects a bi-directional pipe opened between
* the client and itself. The default is true. * the client and itself. The default is true.
@ -685,8 +730,10 @@ public class ReceivePack {
if (timeoutIn != null) if (timeoutIn != null)
timeoutIn.setTimeout(10 * timeout * 1000); timeoutIn.setTimeout(10 * timeout * 1000);
final IndexPack ip = IndexPack.create(db, rawIn); ip = IndexPack.create(db, rawIn);
ip.setFixThin(true); ip.setFixThin(true);
ip.setNeedNewObjectIds(needNewObjectIds);
ip.setNeedBaseObjectIds(needBaseObjectIds);
ip.setObjectChecking(isCheckReceivedObjects()); ip.setObjectChecking(isCheckReceivedObjects());
ip.index(NullProgressMonitor.INSTANCE); ip.index(NullProgressMonitor.INSTANCE);

Loading…
Cancel
Save