]> source.dussan.org Git - jgit.git/commitdiff
Allow users of ReceivePack access to the objects being sent 82/282/7
authorNico Sallembien <nsallembien@google.com>
Tue, 9 Feb 2010 23:01:27 +0000 (15:01 -0800)
committerNico Sallembien <nsallembien@google.com>
Thu, 11 Feb 2010 21:01:27 +0000 (13:01 -0800)
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

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

index 7c94767b49f8cbb4860ed5e316f4b527c461ede6..23faa42a24a8275d461f82e92670564898832ec9 100644 (file)
@@ -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) 2008, Shawn O. Pearce <spearce@spearce.org>
  * 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.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.zip.CRC32;
 import java.util.zip.DataFormatException;
 import java.util.zip.Deflater;
@@ -158,6 +161,8 @@ public class IndexPack {
 
        private boolean keepEmpty;
 
+       private boolean needBaseObjectIds;
+
        private int outputVersion;
 
        private final File dstPack;
@@ -168,6 +173,8 @@ public class IndexPack {
 
        private PackedObjectInfo[] entries;
 
+       private Set<ObjectId> newObjectIds;
+
        private int deltaCount;
 
        private int entryCount;
@@ -176,6 +183,8 @@ public class IndexPack {
 
        private ObjectIdSubclassMap<DeltaChain> baseById;
 
+       private Set<ObjectId> baseIds;
+
        private LongMap<UnresolvedDelta> baseByPos;
 
        private byte[] objectData;
@@ -267,6 +276,54 @@ public class IndexPack {
                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.
         * <p>
@@ -333,6 +390,12 @@ public class IndexPack {
                                        if (packOut == null)
                                                throw new IOException("need packOut");
                                        resolveDeltas(progress);
+                                       if (needBaseObjectIds) {
+                                               baseIds = new HashSet<ObjectId>();
+                                               for (DeltaChain c : baseById) {
+                                                       baseIds.add(c);
+                                               }
+                                       }
                                        if (entryCount < objectCount) {
                                                if (!fixThin) {
                                                        throw new IOException("pack has "
@@ -453,7 +516,7 @@ public class IndexPack {
 
                        verifySafeObject(tempObjectId, type, data);
                        oe = new PackedObjectInfo(pos, crc32, tempObjectId);
-                       entries[entryCount++] = oe;
+                       addObjectAndTrack(oe);
                }
 
                resolveChildDeltas(pos, type, data, oe);
@@ -749,7 +812,7 @@ public class IndexPack {
 
                verifySafeObject(tempObjectId, type, data);
                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,
@@ -1112,4 +1175,10 @@ public class IndexPack {
                if (!dstPack.delete())
                        dstPack.deleteOnExit();
        }
-}
+
+       private void addObjectAndTrack(PackedObjectInfo oe) {
+               entries[entryCount++] = oe;
+               if (needNewObjectIds())
+                       newObjectIds.add(oe);
+       }
+}
\ No newline at end of file
index 4d63ee68ef5c4f0799b5a740235e421270d693c1..8d75f3cb92cb0e09e7e71e03b0e4f8b81bbd4b66 100644 (file)
@@ -153,6 +153,8 @@ public class ReceivePack {
 
        private PrintWriter msgs;
 
+       private IndexPack ip;
+
        /** The refs we advertised as existing at the start of the connection. */
        private Map<String, Ref> refs;
 
@@ -171,6 +173,10 @@ public class ReceivePack {
        /** Lock around the received pack file, while updating refs. */
        private PackLock packLock;
 
+       private boolean needNewObjectIds;
+
+       private boolean needBaseObjectIds;
+
        /**
         * Create a new pack receive for an open repository.
         *
@@ -236,6 +242,45 @@ public class ReceivePack {
                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
         *         the client and itself. The default is true.
@@ -685,8 +730,10 @@ public class ReceivePack {
                if (timeoutIn != null)
                        timeoutIn.setTimeout(10 * timeout * 1000);
 
-               final IndexPack ip = IndexPack.create(db, rawIn);
+               ip = IndexPack.create(db, rawIn);
                ip.setFixThin(true);
+               ip.setNeedNewObjectIds(needNewObjectIds);
+               ip.setNeedBaseObjectIds(needBaseObjectIds);
                ip.setObjectChecking(isCheckReceivedObjects());
                ip.index(NullProgressMonitor.INSTANCE);