From 74d2560f1c65f2e6635798c20183b5078451a5a7 Mon Sep 17 00:00:00 2001 From: Daniel Mellado Date: Wed, 14 Dec 2022 16:51:18 +0100 Subject: [PATCH] CVE: Fix Receiver malicious tenant If running as root or with enough privileges, receiver can create a directory outside of the configured TenantHeader. This commit fixes it up by sanitizing the user input and explicity not allowing such behavior. Signed-off-by: Daniel Mellado --- pkg/receive/handler.go | 15 ++++++++++++ pkg/receive/handler_test.go | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pkg/receive/handler.go b/pkg/receive/handler.go index 771b85cce8..14b4320795 100644 --- a/pkg/receive/handler.go +++ b/pkg/receive/handler.go @@ -12,6 +12,7 @@ import ( stdlog "log" "net" "net/http" + "path" "sort" "strconv" "sync" @@ -403,6 +404,13 @@ func (h *Handler) handleRequest(ctx context.Context, rep uint64, tenant string, return h.forward(ctx, tenant, r, wreq) } +func (h *Handler) isTenantValid(tenant string) error { + if tenant != path.Base(tenant) { + return errors.New("Tenant name not valid") + } + return nil +} + func (h *Handler) receiveHTTP(w http.ResponseWriter, r *http.Request) { var err error span, ctx := tracing.StartSpan(r.Context(), "receive_http") @@ -422,6 +430,13 @@ func (h *Handler) receiveHTTP(w http.ResponseWriter, r *http.Request) { } } + err = h.isTenantValid(tenant) + if err != nil { + level.Error(h.logger).Log("msg", "tenant name not valid", "tenant", tenant) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + tLogger := log.With(h.logger, "tenant", tenant) writeGate := h.Limiter.WriteGate() diff --git a/pkg/receive/handler_test.go b/pkg/receive/handler_test.go index d363f0deb7..7c9474b85e 100644 --- a/pkg/receive/handler_test.go +++ b/pkg/receive/handler_test.go @@ -1090,6 +1090,54 @@ func Heap(dir string) (err error) { return pprof.WriteHeapProfile(f) } +func TestIsTenantValid(t *testing.T) { + for _, tcase := range []struct { + name string + tenant string + + expectedErr error + }{ + { + name: "test malicious tenant", + tenant: "/etc/foo", + expectedErr: errors.New("Tenant name not valid"), + }, + { + name: "test malicious tenant going out of receiver directory", + tenant: "./../../hacker_dir", + expectedErr: errors.New("Tenant name not valid"), + }, + { + name: "test slash-only tenant", + tenant: "///", + expectedErr: errors.New("Tenant name not valid"), + }, + { + name: "test default tenant", + tenant: "default-tenant", + }, + { + name: "test tenant with uuid", + tenant: "528d0490-8720-4478-aa29-819d90fc9a9f", + }, + { + name: "test valid tenant", + tenant: "foo", + }, + } { + t.Run(tcase.name, func(t *testing.T) { + h := NewHandler(nil, &Options{}) + err := h.isTenantValid(tcase.tenant) + if tcase.expectedErr != nil { + testutil.NotOk(t, err) + testutil.Equals(t, tcase.expectedErr.Error(), err.Error()) + return + } + testutil.Ok(t, err) + }) + } +} + func TestRelabel(t *testing.T) { for _, tcase := range []struct { name string