Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVE: Fix Receiver malicious tenant #5969

Merged
merged 1 commit into from
Jan 30, 2023

Conversation

danielmellado
Copy link
Contributor

@danielmellado danielmellado commented Dec 14, 2022

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 [email protected]

@@ -202,7 +203,7 @@ func NewHandler(logger log.Logger, o *Options) *Handler {
ins := extpromhttp.NewNopInstrumentationMiddleware()
if o.Registry != nil {
ins = extpromhttp.NewTenantInstrumentationMiddleware(
o.TenantHeader,
path.Base(o.TenantHeader),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there are a couple of things here. I don't think this is the right place/input to sanitize, as this is the HTTP header name (by default THANOS-TENANT) and this is passed to the Prometheus registry for collecting metrics. We would need to sanitize the value of this HTTP header instead.

To highlight the full flow, this header value is fetched in the receiveHTTP handler, and then goes through handleRequest -> forward -> fanoutForward and passed to h.writer.Write() which creates a multiTSDB TenantAppendable to write data for that tenant. There is some logic (getOrLoadTenant) around how a tenant TSDB is started, but the HTTP header value is eventually used to decide dataDir for the tenant using the defaultTenantDataDir method.

So, we can sanitize this in receiveHTTP itself, but I wonder if we should treat tenant id like a path at all. If tenant header value is set to something like ///, path.Base would return /. Instead maybe we should use some regex that fails if tenant id has some backward/forward slash. WDYT? 🙂

Also, I think we'd need to sanitize --receive.default-tenant-id in a similar way.

Copy link
Member

@GiedriusS GiedriusS Dec 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about having an aliased type that would be used for this? For example:

type tenantID string

func (t *tenantID) String() string {
  return string(*t)
}

func NewTenantID(s string) *tenantID {
  s = path.Base(s)
  return &tenantID{s}
}

(untested but shows my idea). We could put this in a separate package so that it would be impossible to use tenantID directly. This way, we would have the cleaning-up logic only in one place.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I think this would make it way cleaner!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi all I think that using path.Base is only safe at configuration parse-time. Any time this is used at run-time we are liable to run into very sketchy situations where we think we are safe but we actually aren't. Consider for example nice tenant A and malicious tenant B/A. If we path.Base at run-time and let tenant B/A write data to disk, they will be writing into tenant A's directory.

This means that we cannot just rely on doing path.Base(tenantHeaderValue) to find the directory to write to. We actually have to test path.Base(tenantHeaderValue) == tenantHeaderValue and return a 503 or something if not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi o/ thanks for the review! totally, I didn't think of that, but deff can be used for overriding a tenant :\

@danielmellado
Copy link
Contributor Author

danielmellado commented Dec 19, 2022

@GiedriusS how about putting that for now in the receive package? would you folks prefer other follow-up PR for that?

if tenant == "" {
tenant = h.options.DefaultTenantID
tenant = path.Base(h.options.DefaultTenantID)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the logic can be simplified so that there is less room for error if we keep the original code as-is and then add the following four lines right here. We should determine the tenant value like we did originally and then sanitize it. Otherwise, we are doing path.Base too many times, which spreads out our sanitation logic and makes it more likely that we will miss one of the lines in future maintenance:

if tenant != path.Base(tenant) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
	return
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, totally agree, still new to the codebase so thanks for pointing that out. I'll update the PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that's better! Thinking about it more, we should actually move this sanitization down below the next if block where we get the tenant from the certificate.

Maybe we even want to extract tenant value extraction and sanitization into its own, isolated function to keep the logic very tight.

Copy link
Member

@saswatamcode saswatamcode Dec 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think @GiedriusS recommended something similar too. 🙂

I wonder if we should use path.Base at all here, though. In case the tenant header value is set to something like /, we can still have path.Base("/") == "/". Maybe instead just checking if the string contains any / would be easier here?

@danielmellado danielmellado changed the title [WIP/DNM] CVE: Fix Receiver malicious tenant CVE: Fix Receiver malicious tenant Dec 19, 2022
func (h *Handler) isTenantValid(tenant string, err error, w http.ResponseWriter) {
if tenant != path.Base(tenant) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
Copy link
Member

@saswatamcode saswatamcode Jan 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can return an error here, and then log + respond 400 in receiveHTTP instead? 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, will make the changes, it'll make testing easier. Will push a draft so we can iterate

Copy link
Collaborator

@matej-g matej-g left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's shaping up nicely @danielmellado! 👍 Adding a test case for this would be nice.

Comment on lines 21 to 23
"github.com/mwitkow/go-conntrack"
"github.com/opentracing/opentracing-go"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidentally changed formatting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

damn, blame the IDE, I'll put it back on my next commit xD

@@ -403,6 +405,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, err error, w http.ResponseWriter) {
if tenant != path.Base(tenant) {
http.Error(w, err.Error(), http.StatusInternalServerError)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be server error? 🤔 Or bad request?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm that's a good point. It could be either but in any case I'll go with Saswata's suggestion, stay tuned!

@pull-request-size pull-request-size bot added size/M and removed size/S labels Jan 23, 2023
@danielmellado danielmellado changed the title CVE: Fix Receiver malicious tenant [WIP] CVE: Fix Receiver malicious tenant Jan 23, 2023
@danielmellado danielmellado changed the title [WIP] CVE: Fix Receiver malicious tenant CVE: Fix Receiver malicious tenant Jan 26, 2023
@danielmellado danielmellado force-pushed the fix_cve branch 2 times, most recently from c5391f8 to e382d5a Compare January 26, 2023 10:36
saswatamcode
saswatamcode previously approved these changes Jan 29, 2023
Copy link
Member

@saswatamcode saswatamcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
Just a few small suggestions.

pkg/receive/handler.go Show resolved Hide resolved
pkg/receive/handler_test.go Show resolved Hide resolved
@danielmellado
Copy link
Contributor Author

Failure on the tests seems totally unrealted

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 <[email protected]>
@saswatamcode saswatamcode merged commit 5625a3b into thanos-io:main Jan 30, 2023
rabenhorst added a commit to rabenhorst/thanos that referenced this pull request Feb 8, 2023
* Update Thanos engine to latest version (thanos-io#6069)

This commit updates the Thanos PromQL engine to the latest version.

Signed-off-by: Filip Petkovski <[email protected]>

Signed-off-by: Filip Petkovski <[email protected]>

* Receive: Tenants' external labels proposal (thanos-io#5720)

* Receive external labels proposal

Signed-off-by: haanhvu <[email protected]>

* Restructure and edit proposal's content

Signed-off-by: haanhvu <[email protected]>

* Update proposal

Signed-off-by: haanhvu <[email protected]>

* Fix doc error

Signed-off-by: haanhvu <[email protected]>

Signed-off-by: haanhvu <[email protected]>

* fixing doc CI (thanos-io#6072)

Signed-off-by: Ben Ye <[email protected]>

Signed-off-by: Ben Ye <[email protected]>

* Fix stores filtering resets on reload (thanos-io#6063)

* Fix stores filtering resets on reload

`g0.store_matches` parameter appears in the url but doesn't applies
in the frontend. Looks like it has been done on purpose and by
removing a small piece of code fixes this issue.

variable named `debugMode` is used for the store filtering checkbox
which is an unappropriate name. Using `enableStoreFiltering`
variable to represent the state of checkbox.

Signed-off-by: Pradyumna Krishna <[email protected]>

* Regenerate bindata.go

Signed-off-by: Pradyumna Krishna <[email protected]>

Signed-off-by: Pradyumna Krishna <[email protected]>

* Store: Make initial sync more robust

Added re-try mechanism for store inital sync, where if the initial sync fails, it tries to do the initial sync again for given timeout duration.

Signed-off-by: Kartik-Garg <[email protected]>

* Recover from panics in Series calls (thanos-io#6077)

* Recover from panics in Series calls

This commit adds panic recovery for Series calls in all Store servers.

Signed-off-by: Filip Petkovski <[email protected]>

* Apply error suggestion

Signed-off-by: Filip Petkovski <[email protected]>

---------

Signed-off-by: Filip Petkovski <[email protected]>

* query: reuse our own gate (thanos-io#6079)

Do not call promgate directly but rather use our own wrapper that does
everything we want - duration histogram, current in-flight calls, total
calls.

Signed-off-by: Giedrius Statkevičius <[email protected]>

* Store: Support disable cache index header file. (thanos-io#5773)

* Store: Support disable cache index header file.

Signed-off-by: wanjunlei <[email protected]>

* Store: add a seprate flag to disable caching index header file

Signed-off-by: wanjunlei <[email protected]>

* Tools: add cleanup API for bucket web

Signed-off-by: wanjunlei <[email protected]>

* resolve conversation

Signed-off-by: wanjunlei <[email protected]>

* resolve confilcts

Signed-off-by: wanjunlei <[email protected]>

* change the flag to `--cache-index-header`

Signed-off-by: wanjunlei <[email protected]>

* Wrap mem writer in file writer

Signed-off-by: wanjunlei <[email protected]>

* update CHANGELOG

Signed-off-by: wanjunlei <[email protected]>

* update CHANGELOG

Signed-off-by: wanjunlei <[email protected]>

* fix bug

Signed-off-by: wanjunlei <[email protected]>

---------

Signed-off-by: wanjunlei <[email protected]>
Co-authored-by: wanjunlei <[email protected]>

* CVE: Fix Receiver malicious tenant (thanos-io#5969)

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 <[email protected]>

* Add adopter Grupo MasMovil (thanos-io#6084)

Signed-off-by: Pablo Moncada Isla <[email protected]>

* fix typo (thanos-io#6087)

Signed-off-by: cyip <[email protected]>
Co-authored-by: cyip <[email protected]>

* optimize selector to string (thanos-io#6076)

Signed-off-by: Kama Huang <[email protected]>

* Fix: Failure to close BlockSeriesClient cause store-gateway deadlock (thanos-io#6086)

* Fix: Failure to close BlockSeriesClient cause store-gateway deadlock

Signed-off-by: Alan Protasio <[email protected]>

* Adding tests

Signed-off-by: Alan Protasio <[email protected]>

* reverting the change on get series

Signed-off-by: Alan Protasio <[email protected]>

* fix lint

Signed-off-by: Alan Protasio <[email protected]>

---------

Signed-off-by: Alan Protasio <[email protected]>

* Cut 0.30.2 (thanos-io#6081)

* tracing: fixed panic because of nil sampler (thanos-io#6066)

* fixed panic because of nil sampler

Signed-off-by: Vasiliy Rumyantsev <[email protected]>

* added CHANGELOG entry

Signed-off-by: Vasiliy Rumyantsev <[email protected]>

Signed-off-by: Vasiliy Rumyantsev <[email protected]>

* bump version to 0.30.2

Signed-off-by: Ben Ye <[email protected]>

* Updates busybox SHA (thanos-io#6046)

Signed-off-by: GitHub <[email protected]>

Signed-off-by: GitHub <[email protected]>
Co-authored-by: yeya24 <[email protected]>

* Use `e2edb.NewMinio` to disable SSE-S3 in e2e tests (thanos-io#6055)

* Use e2edb.NewMinio to disable SSE

Signed-off-by: Saswata Mukherjee <[email protected]>

* Use temp fork for TLS

Signed-off-by: Saswata Mukherjee <[email protected]>

* Fix broken rules api fanout test

Signed-off-by: Saswata Mukherjee <[email protected]>

* Fix broken query compatibility test

Signed-off-by: Saswata Mukherjee <[email protected]>

* Remove fork

Signed-off-by: Saswata Mukherjee <[email protected]>

Signed-off-by: Saswata Mukherjee <[email protected]>

---------

Signed-off-by: Vasiliy Rumyantsev <[email protected]>
Signed-off-by: Ben Ye <[email protected]>
Signed-off-by: GitHub <[email protected]>
Signed-off-by: Saswata Mukherjee <[email protected]>
Co-authored-by: Vasiliy Rumyantsev <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: yeya24 <[email protected]>
Co-authored-by: Saswata Mukherjee <[email protected]>

* cherry pick store gateway fix to release 0.30 (thanos-io#6089)

* Fix: Failure to close BlockSeriesClient cause store-gateway deadlock (thanos-io#6086)

* Fix: Failure to close BlockSeriesClient cause store-gateway deadlock

Signed-off-by: Alan Protasio <[email protected]>

* Adding tests

Signed-off-by: Alan Protasio <[email protected]>

* reverting the change on get series

Signed-off-by: Alan Protasio <[email protected]>

* fix lint

Signed-off-by: Alan Protasio <[email protected]>

---------

Signed-off-by: Alan Protasio <[email protected]>

* update changelog

Signed-off-by: Ben Ye <[email protected]>

---------

Signed-off-by: Alan Protasio <[email protected]>
Signed-off-by: Ben Ye <[email protected]>
Co-authored-by: Alan Protasio <[email protected]>

* fix changelog entries

Signed-off-by: Ben Ye <[email protected]>

* docs: improving the description for tsdb.retention on the receiver

Signed-off-by: Victor Fernandes <[email protected]>

* Receiver: Use `intern` package when reallocating label strings (thanos-io#5926)

* Cleanup go mod

Signed-off-by: Matej Gera <[email protected]>

* Use string interning for labels realloc method

Signed-off-by: Matej Gera <[email protected]>

* Enhance label realloc benchmarks

Signed-off-by: Matej Gera <[email protected]>

* Make interning optional; put behind hiddend flag

Signed-off-by: Matej Gera <[email protected]>

* Update CHANGELOG

Signed-off-by: Matej Gera <[email protected]>

* Address feedback

- Fix wrong condition
- Adjust benchmarks

Signed-off-by: Matej Gera <[email protected]>

---------

Signed-off-by: Matej Gera <[email protected]>
Signed-off-by: Matej Gera <[email protected]>
Signed-off-by: Matej Gera <[email protected]>

* Updaing README with drawing fixes and minor wording clarification (thanos-io#6078)

* New drawing and wording for Thanos other deployment models

Signed-off-by: Jonah Kowall <[email protected]>

* New drawing and wording for Thanos other deployment models

Signed-off-by: Jonah Kowall <[email protected]>

* Added comments to README.md and updated the quick-tutorial.md with the same diagram updates and text to match

Signed-off-by: Jonah Kowall <[email protected]>

* Ran make docs

Signed-off-by: Jonah Kowall <[email protected]>

---------

Signed-off-by: Jonah Kowall <[email protected]>

* Compact: Remove spam of replica label removed log (thanos-io#6088)

* Remove spam of replica label removed log

Signed-off-by: Douglas Camata <[email protected]>

* Reduce amount of removed replica label instead of removing it

Signed-off-by: Douglas Camata <[email protected]>

* Reformat code

Signed-off-by: Douglas Camata <[email protected]>

---------

Signed-off-by: Douglas Camata <[email protected]>

* Store: Don't error when no stores are matched (thanos-io#6082)

It's normal and not an error if a query does not match due to no
downstream stores. This is common when querying with external labels and
tiered query servers.

This bug was introduced in thanos-io#5296

Fixes: thanos-io#5862

Signed-off-by: SuperQ <[email protected]>

* docs: Fix must have Ruler alerts definition (thanos-io#6058)

* Fix must have Ruler alerts definition

ThanosRuler missing rule intervals metric used the wrong comparator sign, confusing users trying to create the rule.



Signed-off-by: Maxim Muzafarov <[email protected]>

* Update docs/components/rule.md

Co-authored-by: Saswata Mukherjee <[email protected]>
Signed-off-by: Maxim Muzafarov <[email protected]>

---------

Signed-off-by: Maxim Muzafarov <[email protected]>
Co-authored-by: Saswata Mukherjee <[email protected]>

* Fix conflicts

Signed-off-by: haanhvu <[email protected]>

* Specify overwriting behavior in flag and add validation

Signed-off-by: haanhvu <[email protected]>

* Add log and doc

Signed-off-by: haanhvu <[email protected]>

* Mixins(Rule): Fix query for long rule evaluations (thanos-io#6103)

* mixin(Rule): Fix query for long rule evaluations

Signed-off-by: Douglas Camata <[email protected]>

* Update changelog

Signed-off-by: Douglas Camata <[email protected]>

---------

Signed-off-by: Douglas Camata <[email protected]>

---------

Signed-off-by: Filip Petkovski <[email protected]>
Signed-off-by: haanhvu <[email protected]>
Signed-off-by: Ben Ye <[email protected]>
Signed-off-by: Pradyumna Krishna <[email protected]>
Signed-off-by: Kartik-Garg <[email protected]>
Signed-off-by: Giedrius Statkevičius <[email protected]>
Signed-off-by: wanjunlei <[email protected]>
Signed-off-by: Daniel Mellado <[email protected]>
Signed-off-by: Pablo Moncada Isla <[email protected]>
Signed-off-by: cyip <[email protected]>
Signed-off-by: Kama Huang <[email protected]>
Signed-off-by: Alan Protasio <[email protected]>
Signed-off-by: Vasiliy Rumyantsev <[email protected]>
Signed-off-by: GitHub <[email protected]>
Signed-off-by: Saswata Mukherjee <[email protected]>
Signed-off-by: Victor Fernandes <[email protected]>
Signed-off-by: Matej Gera <[email protected]>
Signed-off-by: Matej Gera <[email protected]>
Signed-off-by: Matej Gera <[email protected]>
Signed-off-by: Jonah Kowall <[email protected]>
Signed-off-by: Douglas Camata <[email protected]>
Signed-off-by: SuperQ <[email protected]>
Signed-off-by: Maxim Muzafarov <[email protected]>
Signed-off-by: Sebastian Rabenhorst <[email protected]>
Co-authored-by: Filip Petkovski <[email protected]>
Co-authored-by: Ha Anh Vu <[email protected]>
Co-authored-by: Ben Ye <[email protected]>
Co-authored-by: Pradyumna Krishna <[email protected]>
Co-authored-by: Kartik-Garg <[email protected]>
Co-authored-by: Giedrius Statkevičius <[email protected]>
Co-authored-by: wanjunlei <[email protected]>
Co-authored-by: wanjunlei <[email protected]>
Co-authored-by: Daniel Mellado <[email protected]>
Co-authored-by: Pablo Moncada <[email protected]>
Co-authored-by: Chantel Yip <[email protected]>
Co-authored-by: cyip <[email protected]>
Co-authored-by: Kama Huang <[email protected]>
Co-authored-by: Alan Protasio <[email protected]>
Co-authored-by: Vasiliy Rumyantsev <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: yeya24 <[email protected]>
Co-authored-by: Saswata Mukherjee <[email protected]>
Co-authored-by: Victor Fernandes <[email protected]>
Co-authored-by: Matej Gera <[email protected]>
Co-authored-by: Jonah Kowall <[email protected]>
Co-authored-by: Douglas Camata <[email protected]>
Co-authored-by: Ben Kochie <[email protected]>
Co-authored-by: Maxim Muzafarov <[email protected]>
Co-authored-by: haanhvu <[email protected]>
@danielmellado danielmellado deleted the fix_cve branch February 22, 2023 10:25
ngraham20 pushed a commit to ngraham20/thanos that referenced this pull request Apr 17, 2023
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 <[email protected]>
ngraham20 pushed a commit to ngraham20/thanos that referenced this pull request Apr 17, 2023
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 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants