Browse Source

Add a paranoid 'must be provided' option to ReceivePack

By default a receive pack assumes that its user will only provide
references to objects that the user already has access to on their
local client.  In certain cases, an additional check to verify the
references point only to reachable objects is necessary.

This additional checking is useful when the code doesn't trust
the client not to provide a forged SHA-1 reference to an object,
in an attempt to access parts of the DAG that they weren't allowed
to see by the configured RefFilter.

Change-Id: I3e4b8505cb2992e3e4be253abb14a1501e47b970
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
stable-0.8
Nico Sallembien 15 years ago committed by Shawn O. Pearce
parent
commit
0f95d2d046
  1. 58
      org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java

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

@ -70,6 +70,7 @@ import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdSubclassMap;
import org.eclipse.jgit.lib.PackLock; import org.eclipse.jgit.lib.PackLock;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
@ -77,6 +78,7 @@ import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.Config.SectionParser; import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.revwalk.ObjectWalk; import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag; import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevObject;
@ -184,6 +186,8 @@ public class ReceivePack {
private boolean needBaseObjectIds; private boolean needBaseObjectIds;
private boolean ensureObjectsProvidedVisible;
/** /**
* Create a new pack receive for an open repository. * Create a new pack receive for an open repository.
* *
@ -288,6 +292,26 @@ public class ReceivePack {
return ip.getNewObjectIds(); return ip.getNewObjectIds();
} }
/**
* Configure this receive pack instance to ensure that the provided
* objects are visible to the user.
* <p>
* By default, a receive pack assumes that its user will only provide
* references to objects that it can see. Setting this flag to {@code true}
* will add an additional check that verifies that the objects that were
* provided are reachable by a tree or a commit that the user can see.
* <p>
* This option is useful when the code doesn't trust the client not to
* provide a forged SHA-1 reference to an object in an attempt to access
* parts of the DAG that they aren't allowed to see, via the configured
* {@link RefFilter}.
*
* @param b {@code true} to enable the additional check.
*/
public void setEnsureProvidedObjectsVisible(boolean b) {
this.ensureObjectsProvidedVisible = b;
}
/** /**
* @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.
@ -777,8 +801,9 @@ public class ReceivePack {
ip = IndexPack.create(db, rawIn); ip = IndexPack.create(db, rawIn);
ip.setFixThin(true); ip.setFixThin(true);
ip.setNeedNewObjectIds(needNewObjectIds); ip.setNeedNewObjectIds(needNewObjectIds || ensureObjectsProvidedVisible);
ip.setNeedBaseObjectIds(needBaseObjectIds); ip.setNeedBaseObjectIds(needBaseObjectIds
|| ensureObjectsProvidedVisible);
ip.setObjectChecking(isCheckReceivedObjects()); ip.setObjectChecking(isCheckReceivedObjects());
ip.index(NullProgressMonitor.INSTANCE); ip.index(NullProgressMonitor.INSTANCE);
@ -802,7 +827,34 @@ public class ReceivePack {
} }
for (final Ref ref : refs.values()) for (final Ref ref : refs.values())
ow.markUninteresting(ow.parseAny(ref.getObjectId())); ow.markUninteresting(ow.parseAny(ref.getObjectId()));
ow.checkConnectivity();
ObjectIdSubclassMap<ObjectId> provided =
new ObjectIdSubclassMap<ObjectId>();
if (ensureObjectsProvidedVisible) {
for (ObjectId id : getBaseObjectIds()) {
RevObject b = ow.lookupAny(id, Constants.OBJ_BLOB);
if (!b.has(RevFlag.UNINTERESTING))
throw new MissingObjectException(b, b.getType());
}
for (ObjectId id : getNewObjectIds()) {
provided.add(id);
}
}
RevCommit c;
while ((c = ow.next()) != null) {
if (ensureObjectsProvidedVisible && !provided.contains(c))
throw new MissingObjectException(c, Constants.TYPE_COMMIT);
}
RevObject o;
while ((o = ow.nextObject()) != null) {
if (o instanceof RevBlob && !db.hasObject(o))
throw new MissingObjectException(o, Constants.TYPE_BLOB);
if (ensureObjectsProvidedVisible && !provided.contains(o))
throw new MissingObjectException(o, Constants.TYPE_BLOB);
}
} }
private void validateCommands() { private void validateCommands() {

Loading…
Cancel
Save