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

Protect Processor::Context#run with a mutex #2773

Merged
merged 3 commits into from
Apr 13, 2023
Merged

Conversation

lloeki
Copy link
Contributor

@lloeki lloeki commented Apr 11, 2023

What does this PR do?

Protect Processor::Context#run with a mutex

Motivation

ddwaf_run mutates ddwaf_context in a non-thread-safe way.

Additional Notes

Sicne there is a 1:1:1 context - request - web worker thread mapping it should very rarely happen in typical apps so the lock will just fly through.

This aims to protect from code that spawns threads within a request and that would theoretically trigger a context run (e.g ActionController::Live). There is currently none but there could be in the future.

How to test the change?

Difficult since there's no such real case currently. Even synthetically (e.g in a spec) it would be hard as it would require producing a reliably failing case of libddwaf stepping onto itself.

@lloeki lloeki requested a review from a team April 11, 2023 21:11
@github-actions github-actions bot added the appsec Application Security monitoring product label Apr 11, 2023
Copy link
Member

@GustavoCaso GustavoCaso left a comment

Choose a reason for hiding this comment

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

Makes sense. Feel free to 🚢 once Steep is happy

Copy link
Member

@ivoanjo ivoanjo left a comment

Choose a reason for hiding this comment

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

This seems reasonable, but it's a very small/subtle code change for a potential big issue. Thus, I would suggest perhaps leaving a few comments in the code explaining why this tiny addition is important, otherwise this may get hard to maintain in the future (since people would need to partially "reverse engineer" why this was added here and what it's protecting exactly).

Comment on lines +21 to 23
@run_mutex.lock

start_ns = Core::Utils::Time.get_time(:nanosecond)
Copy link
Member

Choose a reason for hiding this comment

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

Minor: Consider using @run_mutex.synchronize -- I think that one's a bit easier to maintain and "break" with future changes.

Copy link
Contributor Author

@lloeki lloeki Apr 12, 2023

Choose a reason for hiding this comment

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

Rationale:

  • blocks carry a cost: def/ensure/end is faster
  • it makes the function return value less explicit (you have to konw/remember/lookup that synchronize does return the block value)
  • it creates whitespace churn on the code change
  • maybe I'm doing too much Go but def/ensure/end is a common pattern that matches Go's defer ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a comment to clarify the intent!

Copy link
Member

Choose a reason for hiding this comment

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

Thanks!

@time_ns += res.total_runtime
@time_ext_ns += (stop_ns - start_ns)
@timeouts += 1 if res.timeout

res
ensure
@run_mutex.unlock
end

def finalize
Copy link
Member

Choose a reason for hiding this comment

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

Just a final question -- does @context.finalize not need protecting too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, that one is fine.

Context initialization and finalization happen on the same thread and should outlive any transient thread that would theoretically use the same context (you'd get much bigger problems otherwise, that a simple synchronize would not solve). It's all theoretical anyway because no code is currently allowing getting the context from another thread, so this is mostly bulletproofing following a discussion around run.

Copy link
Member

@ivoanjo ivoanjo left a comment

Choose a reason for hiding this comment

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

👍 LGTM

@lloeki lloeki merged commit ef4ab52 into master Apr 13, 2023
@lloeki lloeki deleted the add-processor-run-mutex branch April 13, 2023 20:06
@github-actions github-actions bot added this to the 1.11.0 milestone Apr 13, 2023
@lloeki lloeki modified the milestones: 1.11.0, 1.11.0.beta1 Apr 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
appsec Application Security monitoring product
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants