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

Fix DoS vunerability with ujson.Obj and upack.Obj #449

Merged
merged 25 commits into from
Mar 10, 2023

Conversation

lolgab
Copy link
Member

@lolgab lolgab commented Mar 7, 2023

Fixes: #446

Replace scala.collection.mutable.LinkedHashMap with upickle.core.LinkedHashMap in ujson.Obj and upack.Obj

scala.collection.mutable.LinkedHashMap is not secure because of #446
An attacker can create a sequence of keys that return the same hashCode.
This PR replaces it with upickle.core.LinkedHashMap, a bespoke wrapper of java.util.LinkedHashMap which extends scala.collection.mutable.Map since java.util.LinkedHashMap is safe against this kind of hash-collision attacks.

- Replace `mutable.LinkedHashMap` with `mutable.Map` ujson and upack API

`LinkedHashMap` is not secure because of
com-lihaoyi#446
This commit removes it from the API and replaces the implementation with
a bespoke wrapper around java.util.LinkedHashMap that also extends
scala's `mutable.Map`

- Add test for issue com-lihaoyi#446
@lolgab lolgab changed the title Replace LinkedHashMap with mutable.Map ujson and upack API Fix DoS vunerability with ujson.Obj and upack.Obj Mar 9, 2023
@lolgab lolgab added this to the 3.0.0-M3 milestone Mar 9, 2023
@lolgab lolgab requested review from lihaoyi and lefou March 9, 2023 18:55
@lolgab lolgab marked this pull request as ready for review March 9, 2023 18:55
Copy link
Member

@lefou lefou left a comment

Choose a reason for hiding this comment

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

You changed the visibility of various case classes. Is this also motivated by improving binary compatibility story, or only to better control the construction process? If the former, there is more to do, at least for Scala 2, namely hiding the copy and the unapply methods.

upickleReadme/Readme.scalatex Outdated Show resolved Hide resolved
core/src/upickle/core/internal/LinkedHashMap.scala Outdated Show resolved Hide resolved
@lolgab
Copy link
Member Author

lolgab commented Mar 9, 2023

I made the Obj constructor private and removed case so there is no generated apply method. I want to keep a private constructor to wrap a Map so the internal implementation can take advantage of it, while make sure users can't wrap a map that doesn't keep ordering without copying it to a LinkedHashMap.
I privatized the other constructors for consistency since apply is the documented way to instantiate the object and having some that can do new Thing and some that can't seemed inconsistent.
It's not my goal to improve the binary compatibility.

@lihaoyi
Copy link
Member

lihaoyi commented Mar 10, 2023

Rather than privatizing all the constructors, could we just publicize upickle.internal.LinkedHashMap as upickle.StringHashMap and make it the official type signature case class Obj(value: StringHashMap)? That would greatly reduce the churn in the API, keep everything as "simple" case classes, while still leaving us the option to update the StringHashMap implementation in future (e.g. to specialize it for strings for perf)

@lolgab
Copy link
Member Author

lolgab commented Mar 10, 2023

@lihaoyi We also have upack.. So maybe it can be an upickle.core.internal.LinkedHashMap and two public implementations, one with [String, ujson.Value] and one with [upack.Msg, upack.Msg]?
But StringHashMap as a name doesn't communicate the fact that the value is of type ujson.Value.
Maybe something like ujson.ObjMap can be better?
Or making ujson.Obj itself extend internal.LinkedHashMap[String, Value]? We could provide .value as just a method like def value = this, but this would add a lot of bloat from scala.collection.mutable.Map to Obj API, which maybe you don't want to be exposed to if you don't call .value.

@lihaoyi
Copy link
Member

lihaoyi commented Mar 10, 2023

I don't think we need to communicate it's only used in ujson.Value. As you said, it's used in upack as well. It can just be a generic "mutable string map preserving input ordering" class.

StringMap or ObjMap both sound good to me

I don't think we should overhaup the ujson.Obj API in this PR. Not because it doesn't need work, just that that work is pretty orthogonal to fixing this particular performance issue. Regardless, if we wanted to add more helpers on ujson.Obj/ujson.Value it should be possible later without bincompat breakage

@lolgab
Copy link
Member Author

lolgab commented Mar 10, 2023

The problem is that upack doesn't have String as the key type but upack.Msg

@lefou
Copy link
Member

lefou commented Mar 10, 2023

If this map is a pragmatic mostly internal structure, lets find a pragmatic name paired with some ScalaDoc. What about UjsonLinkedHashMap, it transports its properties (hash map, linked) but also that it's tied to u{json,pack,pickle}. The curious user can read the scaladoc to read, why it is needed and whether it is safe to be used in other places.

@lihaoyi
Copy link
Member

lihaoyi commented Mar 10, 2023

sounds good. I think just upickle.core.LinkedHashMap would be fine as well, so not specific to either ujson or upack

@lolgab
Copy link
Member Author

lolgab commented Mar 10, 2023

@lihaoyi @lefou Ready for another review round

Copy link
Member

@lihaoyi lihaoyi left a comment

Choose a reason for hiding this comment

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

Looks good to me i think

ujson/src/ujson/Value.scala Outdated Show resolved Hide resolved
upickle/test/src/upickle/AdvancedTests.scala Outdated Show resolved Hide resolved
upickle/test/src/upickle/AdvancedTests.scala Outdated Show resolved Hide resolved
@lolgab lolgab requested a review from lefou March 10, 2023 09:04
Copy link
Member

@lefou lefou left a comment

Choose a reason for hiding this comment

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

Looks good to me. This was lots of work to be on the safe side. Nice job.

Can you update the PR description? I'd like to use it as commit message, too.

@lolgab lolgab requested a review from lefou March 10, 2023 10:24
@lolgab
Copy link
Member Author

lolgab commented Mar 10, 2023

Thank you very much @lefou!
I updated the PR description.

@lolgab lolgab merged commit 2dcd043 into com-lihaoyi:main Mar 10, 2023
@lolgab lolgab deleted the remove-linked-hash-map branch March 10, 2023 12:30
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.

DoS vulnerability with ujson
3 participants