summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorNico Sallembien2010-03-12 19:07:19 (EST)
committer Shawn O. Pearce2010-03-18 14:37:59 (EDT)
commit0f95d2d0462f8badd3cdb1fadb6dbb3fe84074b4 (patch)
treebdbd00a736e617678617f51b97856bd51248a96a
parent6fabb6d20427591fb754f6dc4632187ebc0edb55 (diff)
downloadjgit-0f95d2d0462f8badd3cdb1fadb6dbb3fe84074b4.zip
jgit-0f95d2d0462f8badd3cdb1fadb6dbb3fe84074b4.tar.gz
jgit-0f95d2d0462f8badd3cdb1fadb6dbb3fe84074b4.tar.bz2
Add a paranoid 'must be provided' option to ReceivePackrefs/changes/54/354/5
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>
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java58
1 files changed, 55 insertions, 3 deletions
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 dae28ab..6ba326c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/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.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdSubclassMap;
import org.eclipse.jgit.lib.PackLock;
import org.eclipse.jgit.lib.PersonIdent;
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.Config.SectionParser;
import org.eclipse.jgit.revwalk.ObjectWalk;
+import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject;
@@ -184,6 +186,8 @@ public class ReceivePack {
private boolean needBaseObjectIds;
+ private boolean ensureObjectsProvidedVisible;
+
/**
* Create a new pack receive for an open repository.
*
@@ -289,6 +293,26 @@ public class ReceivePack {
}
/**
+ * 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
* the client and itself. The default is true.
*/
@@ -777,8 +801,9 @@ public class ReceivePack {
ip = IndexPack.create(db, rawIn);
ip.setFixThin(true);
- ip.setNeedNewObjectIds(needNewObjectIds);
- ip.setNeedBaseObjectIds(needBaseObjectIds);
+ ip.setNeedNewObjectIds(needNewObjectIds || ensureObjectsProvidedVisible);
+ ip.setNeedBaseObjectIds(needBaseObjectIds
+ || ensureObjectsProvidedVisible);
ip.setObjectChecking(isCheckReceivedObjects());
ip.index(NullProgressMonitor.INSTANCE);
@@ -802,7 +827,34 @@ public class ReceivePack {
}
for (final Ref ref : refs.values())
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() {