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

Use TreeMap in SimpleFacade to solve DoS vuln #390

Merged
merged 2 commits into from
Jan 2, 2022

Conversation

nrktkt
Copy link
Contributor

@nrktkt nrktkt commented Dec 16, 2021

Scala's default Map is vulnerable to a DoS attack where an attacker basically fills up one leaf of the hash trie and causes resource exhaustion as more elements are added to the leaf with poor efficiency.
scala/bug#11203

SimpleFacade should be resistant to this as a "simple" implementation. Users can always implement their own Facade if they trust the input and need the performance edge.
Switching to TreeMap should solve this without any compatibility issues.

@rossabaker
Copy link
Member

Thanks!

Circe uses a LinkedHashMap, which I think we'd have to wrap as an immutable.Map in finish. So does play-json. Even a wrapped java.util.HashMap is sufficient, if we're not trying to optimize iteration of the underlying map. I strongly suspect this would be faster than building TreeMaps. You are of course correct that users can implement their own, but maybe we can avoid a performance regression using the Java types.

There's also a CollisionProofHashMap. That may or may not be faster than the Java one, and could only work for Scala >= 2.13.

Seems like the mutable facade would also be vulnerable?

@nrktkt
Copy link
Contributor Author

nrktkt commented Dec 17, 2021

I haven't looked deep at the implementations for how Circe or Play do that wrapping. But I'd guess that they turn the java map into some non-map type (I vaguely remember play is a Seq of tuples or something?), or have expensive mutations (cloning the underlying mutable map each time), or do something like scala.collection.JavaConverters .toScala.toMap, which would convert to the default HAMT and expose the vuln (I think Circe does on mutation).
None of the above are ideal; for my use case at least. Users would find the map follows the contract, but wouldn't perform as one would assume. So at the end of the day we need a safe immutable map and TreeMap is the only one I'm aware of.
Is there a way to more quickly build a different structure and then convert to TreeMap?

Unfortunately there's no immutable CollisionProofHashMap, so I think that leaves us in about the same situation as the java java.util.HashMap wrapped using JavaConverters.
I think the ideal solution would be an immutable CollisionProofHashMap in the standard library (and added to collections compat), but short of that TreeMap seems like what we're left with.

Let me know if that all sounds correct

Copy link
Member

@rossabaker rossabaker left a comment

Choose a reason for hiding this comment

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

Is there a way to more quickly build a different structure and then convert to TreeMap?

As long as the building can't be observed externally, using a TreeMap.newBuilder and converting at the end would probably be faster.

But we should fix the vulnerabilities first, and we can improve the performance second.

@rossabaker rossabaker merged commit 19ceb95 into typelevel:main Jan 2, 2022
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants