From 865620bad3d2e7f98242e00bf475e8ec4062985c Mon Sep 17 00:00:00 2001
From: Jan Provaznik <jprovaznik@gitlab.com>
Date: Wed, 16 Jan 2019 19:29:57 +0100
Subject: [PATCH] Remove EXIF from JPEG/TIFF images

EXIF may contain sensitive information, when uploading
any file which may be an image (based on filename suffix),
we run it through exiftool which removes any metadata.
---
 .gitlab-ci.yml                                |   1 +
 README.md                                     |  19 ++++
 VERSION                                       |   2 +-
 internal/helper/helpers.go                    |   6 +-
 internal/upload/exif/exif.go                  | 104 ++++++++++++++++++
 internal/upload/exif/exif_test.go             |  77 +++++++++++++
 internal/upload/exif/testdata/sample_exif.jpg | Bin 0 -> 33881 bytes
 internal/upload/rewrite.go                    |  26 ++++-
 internal/upload/uploads.go                    |   3 +
 internal/upload/uploads_test.go               |  90 +++++++++++++++
 10 files changed, 323 insertions(+), 5 deletions(-)
 create mode 100644 internal/upload/exif/exif.go
 create mode 100644 internal/upload/exif/exif_test.go
 create mode 100644 internal/upload/exif/testdata/sample_exif.jpg

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a190ea429d1f..78444f7a80cc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,6 +14,7 @@ verify:
     GITALY_ADDRESS: "tcp://gitaly:8075"
   script:
   - go version
+  - apt-get update && apt-get -y install libimage-exiftool-perl
   - make test
 
 test using go 1.10:
diff --git a/README.md b/README.md
index 5dfce77d5df9..7e94ae6ec793 100644
--- a/README.md
+++ b/README.md
@@ -168,6 +168,25 @@ make install PREFIX=/foo
 On some operating systems, such as FreeBSD, you may have to use
 `gmake` instead of `make`.
 
+## Dependencies
+
+### Exiftool
+
+Workhorse uses [exiftool](https://www.sno.phy.queensu.ca/~phil/exiftool/) for
+removing EXIF data (which may contain sensitive information) from uploaded
+images. If you installed GitLab:
+
+-   Using the Omnibus package, you're all set.
+-   From source, make sure `exiftool` is installed:
+
+    ```sh
+    # Debian/Ubuntu
+    sudo apt-get install libimage-exiftool-perl
+
+    # RHEL/CentOS
+    sudo yum install perl-Image-ExifTool
+    ```
+
 ## Error tracking
 
 GitLab-Workhorse supports remote error tracking with
diff --git a/VERSION b/VERSION
index 2bf50aaf17a6..9c78b761ea12 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.3.0
+8.3.2
diff --git a/internal/helper/helpers.go b/internal/helper/helpers.go
index 5d2cb280871d..2acc357b278f 100644
--- a/internal/helper/helpers.go
+++ b/internal/helper/helpers.go
@@ -37,7 +37,11 @@ func LogError(r *http.Request, err error) {
 }
 
 func RequestEntityTooLarge(w http.ResponseWriter, r *http.Request, err error) {
-	http.Error(w, "Request Entity Too Large", http.StatusRequestEntityTooLarge)
+	CaptureAndFail(w, r, err, "Request Entity Too Large", http.StatusRequestEntityTooLarge)
+}
+
+func CaptureAndFail(w http.ResponseWriter, r *http.Request, err error, msg string, code int) {
+	http.Error(w, msg, code)
 	captureRavenError(r, err)
 	printError(r, err)
 }
diff --git a/internal/upload/exif/exif.go b/internal/upload/exif/exif.go
new file mode 100644
index 000000000000..bf25e595deb5
--- /dev/null
+++ b/internal/upload/exif/exif.go
@@ -0,0 +1,104 @@
+package exif
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"io"
+	"os/exec"
+	"regexp"
+
+	"gitlab.com/gitlab-org/gitlab-workhorse/internal/log"
+)
+
+var ErrRemovingExif = errors.New("error while removing EXIF")
+
+type cleaner struct {
+	ctx      context.Context
+	cmd      *exec.Cmd
+	stdout   io.Reader
+	stderr   bytes.Buffer
+	waitDone chan struct{}
+	waitErr  error
+}
+
+func NewCleaner(ctx context.Context, stdin io.Reader) (io.Reader, error) {
+	c := &cleaner{
+		ctx:      ctx,
+		waitDone: make(chan struct{}),
+	}
+
+	if err := c.startProcessing(stdin); err != nil {
+		return nil, err
+	}
+
+	return c, nil
+}
+
+func (c *cleaner) Read(p []byte) (int, error) {
+	n, err := c.stdout.Read(p)
+	if err == io.EOF {
+		if waitErr := c.wait(); waitErr != nil {
+			log.WithFields(c.ctx, log.Fields{
+				"command": c.cmd.Args,
+				"stderr":  c.stderr.String(),
+				"error":   waitErr.Error(),
+			}).Print("exiftool command failed")
+			return n, ErrRemovingExif
+		}
+	}
+
+	return n, err
+}
+
+func (c *cleaner) startProcessing(stdin io.Reader) error {
+	var err error
+
+	whitelisted_tags := []string{
+		"-ResolutionUnit",
+		"-XResolution",
+		"-YResolution",
+		"-YCbCrSubSampling",
+		"-YCbCrPositioning",
+		"-BitsPerSample",
+		"-ImageHeight",
+		"-ImageWidth",
+		"-ImageSize",
+		"-Copyright",
+		"-CopyrightNotice",
+	}
+
+	args := append([]string{"-all=", "--IPTC:all", "--XMP-iptcExt:all", "-tagsFromFile", "@"}, whitelisted_tags...)
+	args = append(args, "-")
+	c.cmd = exec.CommandContext(c.ctx, "exiftool", args...)
+
+	c.cmd.Stderr = &c.stderr
+	c.cmd.Stdin = stdin
+
+	c.stdout, err = c.cmd.StdoutPipe()
+	if err != nil {
+		return fmt.Errorf("failed to create stdout pipe: %v", err)
+	}
+
+	if err = c.cmd.Start(); err != nil {
+		return fmt.Errorf("start %v: %v", c.cmd.Args, err)
+	}
+	go func() {
+		c.waitErr = c.cmd.Wait()
+		close(c.waitDone)
+	}()
+
+	return nil
+}
+
+func (c *cleaner) wait() error {
+	<-c.waitDone
+	return c.waitErr
+}
+
+func IsExifFile(filename string) bool {
+	filenameMatch := regexp.MustCompile(`(?i)\.(jpg|jpeg|tiff)$`)
+
+	return filenameMatch.MatchString(filename)
+}
diff --git a/internal/upload/exif/exif_test.go b/internal/upload/exif/exif_test.go
new file mode 100644
index 000000000000..83a3d7edb093
--- /dev/null
+++ b/internal/upload/exif/exif_test.go
@@ -0,0 +1,77 @@
+package exif
+
+import (
+	"context"
+	"io"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestIsExifFile(t *testing.T) {
+	tests := []struct {
+		name     string
+		expected bool
+	}{
+		{
+			name:     "/full/path.jpg",
+			expected: true,
+		},
+		{
+			name:     "path.jpeg",
+			expected: true,
+		},
+		{
+			name:     "path.tiff",
+			expected: true,
+		},
+		{
+			name:     "path.JPG",
+			expected: true,
+		},
+		{
+			name:     "path.tar",
+			expected: false,
+		},
+		{
+			name:     "path",
+			expected: false,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			require.Equal(t, test.expected, IsExifFile(test.name))
+		})
+	}
+}
+
+func TestNewCleanerWithValidFile(t *testing.T) {
+	input, err := os.Open("testdata/sample_exif.jpg")
+	require.NoError(t, err)
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	cleaner, err := NewCleaner(ctx, input)
+	require.NoError(t, err, "Expected no error when creating cleaner command")
+
+	size, err := io.Copy(ioutil.Discard, cleaner)
+	require.NoError(t, err, "Expected no error when reading output")
+
+	sizeAfterStrip := int64(25399)
+	require.Equal(t, sizeAfterStrip, size, "Different size of converted image")
+}
+
+func TestNewCleanerWithInvalidFile(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	cleaner, err := NewCleaner(ctx, strings.NewReader("invalid image"))
+	require.NoError(t, err, "Expected no error when creating cleaner command")
+
+	size, err := io.Copy(ioutil.Discard, cleaner)
+	require.Error(t, err, "Expected error when reading output")
+	require.Equal(t, int64(0), size, "Size of invalid image should be 0")
+}
diff --git a/internal/upload/exif/testdata/sample_exif.jpg b/internal/upload/exif/testdata/sample_exif.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..05eda3f7f953eec3f7f9c08428328d9c3922d7d9
GIT binary patch
literal 33881
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
F69C`65P1Lq

literal 0
HcmV?d00001

diff --git a/internal/upload/rewrite.go b/internal/upload/rewrite.go
index 2086c8e95e7e..d7c4d777eab3 100644
--- a/internal/upload/rewrite.go
+++ b/internal/upload/rewrite.go
@@ -12,6 +12,8 @@ import (
 
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
+	"gitlab.com/gitlab-org/gitlab-workhorse/internal/log"
+	"gitlab.com/gitlab-org/gitlab-workhorse/internal/upload/exif"
 )
 
 var (
@@ -113,12 +115,30 @@ func (rew *rewriter) handleFilePart(ctx context.Context, name string, p *multipa
 	opts := filestore.GetOpts(rew.preauth)
 	opts.TempFilePrefix = filename
 
-	fh, err := filestore.SaveFileFromReader(ctx, p, -1, opts)
+	var inputReader io.Reader
+	if exif.IsExifFile(filename) {
+		log.WithFields(ctx, log.Fields{
+			"filename": filename,
+		}).Print("running exiftool to remove any metadata")
+
+		cleaner, err := exif.NewCleaner(ctx, p)
+		if err != nil {
+			return fmt.Errorf("failed to start EXIF metadata cleaner: %v", err)
+		}
+
+		inputReader = cleaner
+	} else {
+		inputReader = p
+	}
+
+	fh, err := filestore.SaveFileFromReader(ctx, inputReader, -1, opts)
 	if err != nil {
-		if err == filestore.ErrEntityTooLarge {
+		switch err {
+		case filestore.ErrEntityTooLarge, exif.ErrRemovingExif:
 			return err
+		default:
+			return fmt.Errorf("persisting multipart file: %v", err)
 		}
-		return fmt.Errorf("persisting multipart file: %v", err)
 	}
 
 	for key, value := range fh.GitLabFinalizeFields(name) {
diff --git a/internal/upload/uploads.go b/internal/upload/uploads.go
index 766d5552096b..32bf514ee1fb 100644
--- a/internal/upload/uploads.go
+++ b/internal/upload/uploads.go
@@ -11,6 +11,7 @@ import (
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
+	"gitlab.com/gitlab-org/gitlab-workhorse/internal/upload/exif"
 )
 
 // These methods are allowed to have thread-unsafe implementations.
@@ -40,6 +41,8 @@ func HandleFileUploads(w http.ResponseWriter, r *http.Request, h http.Handler, p
 			h.ServeHTTP(w, r)
 		case filestore.ErrEntityTooLarge:
 			helper.RequestEntityTooLarge(w, r, err)
+		case exif.ErrRemovingExif:
+			helper.CaptureAndFail(w, r, err, "Failed to process image", http.StatusUnprocessableEntity)
 		default:
 			helper.Fail500(w, r, fmt.Errorf("handleFileUploads: extract files from multipart: %v", err))
 		}
diff --git a/internal/upload/uploads_test.go b/internal/upload/uploads_test.go
index 45f0f6e0a501..e974569fa1b1 100644
--- a/internal/upload/uploads_test.go
+++ b/internal/upload/uploads_test.go
@@ -12,10 +12,13 @@ import (
 	"net/http/httptest"
 	"os"
 	"regexp"
+	"strconv"
 	"strings"
 	"testing"
 	"time"
 
+	"github.com/stretchr/testify/require"
+
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/api"
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/filestore"
 	"gitlab.com/gitlab-org/gitlab-workhorse/internal/helper"
@@ -323,6 +326,93 @@ func TestInvalidFileNames(t *testing.T) {
 	}
 }
 
+func TestUploadHandlerRemovingExif(t *testing.T) {
+	tempPath, err := ioutil.TempDir("", "uploads")
+	require.NoError(t, err)
+	defer os.RemoveAll(tempPath)
+
+	var buffer bytes.Buffer
+
+	content, err := ioutil.ReadFile("exif/testdata/sample_exif.jpg")
+	require.NoError(t, err)
+
+	writer := multipart.NewWriter(&buffer)
+	file, err := writer.CreateFormFile("file", "test.jpg")
+	require.NoError(t, err)
+
+	_, err = file.Write(content)
+	require.NoError(t, err)
+
+	err = writer.Close()
+	require.NoError(t, err)
+
+	ts := testhelper.TestServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
+		err := r.ParseMultipartForm(100000)
+		require.NoError(t, err)
+
+		size, err := strconv.Atoi(r.FormValue("file.size"))
+		require.NoError(t, err)
+		require.True(t, size < len(content), "Expected the file to be smaller after removal of exif")
+		require.True(t, size > 0, "Expected to receive not empty file")
+
+		w.WriteHeader(200)
+		fmt.Fprint(w, "RESPONSE")
+	})
+	defer ts.Close()
+
+	httpRequest, err := http.NewRequest("POST", ts.URL+"/url/path", &buffer)
+	require.NoError(t, err)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	httpRequest = httpRequest.WithContext(ctx)
+	httpRequest.ContentLength = int64(buffer.Len())
+	httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
+	response := httptest.NewRecorder()
+
+	handler := newProxy(ts.URL)
+	HandleFileUploads(response, httpRequest, handler, &api.Response{TempPath: tempPath}, &testFormProcessor{})
+	testhelper.AssertResponseCode(t, response, 200)
+}
+
+func TestUploadHandlerRemovingInvalidExif(t *testing.T) {
+	tempPath, err := ioutil.TempDir("", "uploads")
+	require.NoError(t, err)
+	defer os.RemoveAll(tempPath)
+
+	var buffer bytes.Buffer
+
+	writer := multipart.NewWriter(&buffer)
+	file, err := writer.CreateFormFile("file", "test.jpg")
+	require.NoError(t, err)
+
+	fmt.Fprint(file, "this is not valid image data")
+	err = writer.Close()
+	require.NoError(t, err)
+
+	ts := testhelper.TestServerWithHandler(regexp.MustCompile(`/url/path\z`), func(w http.ResponseWriter, r *http.Request) {
+		err := r.ParseMultipartForm(100000)
+		require.Error(t, err)
+	})
+	defer ts.Close()
+
+	httpRequest, err := http.NewRequest("POST", ts.URL+"/url/path", &buffer)
+	require.NoError(t, err)
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	httpRequest = httpRequest.WithContext(ctx)
+	httpRequest.ContentLength = int64(buffer.Len())
+	httpRequest.Header.Set("Content-Type", writer.FormDataContentType())
+	response := httptest.NewRecorder()
+
+	handler := newProxy(ts.URL)
+	HandleFileUploads(response, httpRequest, handler, &api.Response{TempPath: tempPath}, &testFormProcessor{})
+	testhelper.AssertResponseCode(t, response, 422)
+}
+
 func newProxy(url string) *proxy.Proxy {
 	parsedURL := helper.URLMustParse(url)
 	return proxy.NewProxy(parsedURL, "123", roundtripper.NewTestBackendRoundTripper(parsedURL))
-- 
GitLab