[ARVADOS] created: 1.2.0-85-g720e76bb1
Git user
git at public.curoverse.com
Wed Sep 19 16:16:30 EDT 2018
at 720e76bb1d82d5a5448ce395df634310ceee473e (commit)
commit 720e76bb1d82d5a5448ce395df634310ceee473e
Author: Peter Amstutz <pamstutz at veritasgenetics.com>
Date: Wed Sep 19 16:15:47 2018 -0400
14197: Verify manifest text matches portable data hash that was requested
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz at veritasgenetics.com>
diff --git a/lib/controller/federation.go b/lib/controller/federation.go
index a18148fc5..3715edae9 100644
--- a/lib/controller/federation.go
+++ b/lib/controller/federation.go
@@ -8,9 +8,11 @@ import (
"bufio"
"bytes"
"context"
+ "crypto/md5"
"database/sql"
"encoding/json"
"fmt"
+ "io"
"io/ioutil"
"net/http"
"net/url"
@@ -76,9 +78,12 @@ func (h *genericFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req *h
h.handler.remoteClusterRequest(m[1], w, req, nil)
}
-type rewriteSignaturesClusterId string
+type rewriteSignaturesClusterId struct {
+ clusterID string
+ expectHash string
+}
-func (clusterId rewriteSignaturesClusterId) rewriteSignatures(resp *http.Response, requestError error) (newResponse *http.Response, err error) {
+func (rw rewriteSignaturesClusterId) rewriteSignatures(resp *http.Response, requestError error) (newResponse *http.Response, err error) {
if requestError != nil {
return resp, requestError
}
@@ -100,6 +105,10 @@ func (clusterId rewriteSignaturesClusterId) rewriteSignatures(resp *http.Respons
// capacity accordingly
updatedManifest := bytes.NewBuffer(make([]byte, 0, int(float64(len(col.ManifestText))*1.1)))
+ hasher := md5.New()
+ mw := io.MultiWriter(hasher, updatedManifest)
+ sz := 0
+
scanner := bufio.NewScanner(strings.NewReader(col.ManifestText))
scanner.Buffer(make([]byte, 1048576), len(col.ManifestText))
for scanner.Scan() {
@@ -109,19 +118,56 @@ func (clusterId rewriteSignaturesClusterId) rewriteSignatures(resp *http.Respons
return nil, fmt.Errorf("Invalid stream (<3 tokens): %q", line)
}
- updatedManifest.WriteString(tokens[0])
+ n, err := mw.Write([]byte(tokens[0]))
+ if err != nil {
+ return nil, fmt.Errorf("Error updating manifest: %v", err)
+ }
+ sz += n
for _, token := range tokens[1:] {
- updatedManifest.WriteString(" ")
+ n, err = mw.Write([]byte(" "))
+ if err != nil {
+ return nil, fmt.Errorf("Error updating manifest: %v", err)
+ }
+ sz += n
+
m := keepclient.SignedLocatorRe.FindStringSubmatch(token)
if m != nil {
// Rewrite the block signature to be a remote signature
- fmt.Fprintf(updatedManifest, "%s%s%s+R%s-%s%s", m[1], m[2], m[3], clusterId, m[5][2:], m[8])
+ _, err = fmt.Fprintf(updatedManifest, "%s%s%s+R%s-%s%s", m[1], m[2], m[3], rw.clusterID, m[5][2:], m[8])
+ if err != nil {
+ return nil, fmt.Errorf("Error updating manifest: %v", err)
+ }
+
+ // for hash checking, ignore signatures
+ n, err = fmt.Fprintf(hasher, "%s%s", m[1], m[2])
+ if err != nil {
+ return nil, fmt.Errorf("Error updating manifest: %v", err)
+ }
+ sz += n
} else {
- updatedManifest.WriteString(token)
+ n, err = mw.Write([]byte(token))
+ if err != nil {
+ return nil, fmt.Errorf("Error updating manifest: %v", err)
+ }
+ sz += n
}
-
}
- updatedManifest.WriteString("\n")
+ n, err = mw.Write([]byte("\n"))
+ if err != nil {
+ return nil, fmt.Errorf("Error updating manifest: %v", err)
+ }
+ sz += n
+ }
+
+ // Certify that the computed hash of the manifest matches our expectation
+ if rw.expectHash == "" {
+ rw.expectHash = col.PortableDataHash
+ }
+
+ sum := hasher.Sum(nil)
+ computedHash := fmt.Sprintf("%x+%v", sum, sz)
+ if computedHash != rw.expectHash {
+ return nil, fmt.Errorf("Computed hash %q did not match expected hash %q", computedHash, rw.expectHash)
}
col.ManifestText = updatedManifest.String()
@@ -159,6 +205,7 @@ func (s *searchLocalClusterForPDH) filterLocalClusterResponse(resp *http.Respons
}
type searchRemoteClusterForPDH struct {
+ pdh string
remoteID string
mtx *sync.Mutex
sentResponse *bool
@@ -202,7 +249,7 @@ func (s *searchRemoteClusterForPDH) filterRemoteClusterResponse(resp *http.Respo
// also have made it to this point, and we don't want a
// slow response holding the lock to block a faster response
// that is waiting on the lock.
- newResponse, err = rewriteSignaturesClusterId(s.remoteID).rewriteSignatures(resp, nil)
+ newResponse, err = rewriteSignaturesClusterId{s.remoteID, s.pdh}.rewriteSignatures(resp, nil)
s.mtx.Lock()
@@ -234,7 +281,7 @@ func (h *collectionFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req
if len(m) == 2 && m[1] != h.handler.Cluster.ClusterID {
// request for remote collection by uuid
h.handler.remoteClusterRequest(m[1], w, req,
- rewriteSignaturesClusterId(m[1]).rewriteSignatures)
+ rewriteSignaturesClusterId{m[1], ""}.rewriteSignatures)
return
}
// not a collection UUID request, or it is a request
@@ -296,7 +343,7 @@ func (h *collectionFederatedRequestHandler) ServeHTTP(w http.ResponseWriter, req
if sentResponse {
break
}
- search := &searchRemoteClusterForPDH{remoteID, &mtx, &sentResponse,
+ search := &searchRemoteClusterForPDH{m[1], remoteID, &mtx, &sentResponse,
&sharedContext, cancelFunc, &errors, &errorCode}
wg.Add(1)
go func() {
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list