multi-def values vs. security, elucidated and solved
brian.goetz at oracle.com
Wed Apr 10 19:17:37 UTC 2019
This is a fine technique for defending against such an attack (as is,
don't publish constructors that would let callers create the Gi
objects.) And I'm fine saying "if you want protection, add it."
I think Remi's concern is not that there is no defense, but that authors
might not realize that defense is needed, and might forget to defend
themselves. (Or, a too-clever maintainer might put `inline` on a class
that they don't realize is being used as a capability token.)
On 4/10/2019 2:24 PM, John Rose wrote:
> One recurrent question about inlined value types is
> whether they are less secure than regular object types.
> The question revolves around a scenario where an
> inlined value instance X functions as a security token,
> and the value of a private field of X (X.p) must be
> secured. In this scenario, the attacker creates a
> series of guesses G1, G2, … which attempt to
> replicate the value X, substituting various guessed
> values for X.p (G1.p, G2.p, etc.). If the attacker
> finds a guess Gi where Gi==X, then the attacker
> has "unlocked" X by exposing the value of X.p,
> since it must be the same as Gi.p which the attacker
> has already guessed and now has confirmed.
> This attack scenario is relatively narrow because
> it requires that the possible values of X.p can be
> enumerated in the time the attacker has to perform
> the attack. The time order for this attack is thus
> O(N) where N is the number of possible values of
> (If X implements Comparable and X.p is a key in the
> comparison, then the attack can be performed in
> O(log N). This is often feasible where the O(N)
> attack is not.)
> Why is this not a problem with classic indirect
> objects (those which have identity)? Because the
> tool for comparing Gi with X, the == operator,
> immediately returns false for any of the Gi,
> since those were created by the attacker.
> (If X is a classic object which implements Comparable,
> then the attack is more feasible, even with classic
> objects, since the attacker can use the compareTo
> operation to bracket the X.p value between positive
> and negative results. This problem applies equally
> to classic indirect objects and inline value objects.)
> So classic indirect objects are highly resistant to
> equality tests against attacker-created indirect objects,
> because the equality test will fail unless the attacker
> compares X with X itself—which gives the attacker
> no new information.
> Meanwhile, inline value objects are not resistant to
> equality tests, so the guessing can eventually (in O(N)
> time) produce a match against X.
> In short, an exactly copy of the inline value object X
> can be forged (as a lucky Gi) by an independent party.
> Pulling back from the attack per se, we can observe
> that a classic indirect object possesses an identity
> thas is created at that object's defining site (a "new X"
> expression or bytecode). No other defining site in
> space or time will ever create the same identity.
> An inline value object V possesses no such identity,
> and, therefore, several defining sites (a "new V"
> expression or invokestatic bytecode) can end up
> creating the *same* value, over and over again.
> All occurrences of the same indirect object have
> the same defining site; they are all connected by
> a chain of data-flow from definition to use.
> Multiple occurrences of the same value may have
> *distinct* defining sites, *not* connected by
> chains of data flow. The first time the two copies
> of the same value come together might be when
> they are first compared. They will compare equal
> (if they are the same value), even though they came
> from different data-flow chains of definition to
> use (from two different definitions). This never
> happens for classic indirect objects.
> This difference between classic indirect and
> new inline types suggests a defense against
> the attack scenario proposed above. What if
> we could ask a value type to emulate the special
> property that a definition-to-use data-flow chain
> is the only way for one value (of a given type X)
> to be a copy of itself? Forging a series of guesses
> G1, G2, … would then be impossible.
> In fact, this is readily done, and without damaging
> the other desirable properties of inline value types.
> Simply endow the type "X" with an extra private
> field "X.q" which is initialized (in the constructor
> of X) by the expression, "new Object()". This
> augmented version of X will (drum roll, please)
> possess a bona fide *object identity* which cannot
> be forged by an attacker.
> If you think about this, the status of the JVM's
> invisible object header takes on a new aspect,
> that of a *field* which carries the *object identity*,
> and is *inherited* from the type of all classic
> indirect objects. We have sometimes called this
> hypothetical type "RefObject". The idea here is
> that every classic indirect object inherited,
> from RefObject, an object identity, notionally
> stored in the object header. (Actually, it's the
> address of the object header which is used,
> but the point remains that if you have a header,
> you can derive an object identity from it, by
> taking its address.) Meanwhile, every inline
> value object does *not* have such a header.
> (Some of its many copies *may* have headers,
> but these headers are prevented from being
> significant.) So an instance of C <: RefObject
> *inherits* an object identity from RefObject.
> Meanwhile, an inline value instance X is not
> an instance of RefObject, and does *not* inherit
> the header nor the object identity. *But*,
> if the instance X wishes to acquire an object
> identity, it can do so by *aggregation* instead
> of *inheritance*. Et voila; the upgraded version
> of X has no header, but its object identity lives
> on, in the field X.q. Problem solved.
> Therefore, if an inline value object is going to
> be used as an unforgeable security token, and
> the author is worried about an object-forging
> attack, the attack can be headed off by adding
> an object identity *field*. There will be a cost
> in footprint, but the object will continue to
> possess all the other properties of inline values,
> including flattenability. Perhaps the author of
> the class is already including a classic indirect
> object reference X.a in the class definition.
> If that is the case, a quick "clone" operation in
> the constructor before setting X.a can smuggle in
> an object identity without an increase in footprint.
> I think these observations adequately answer the
> persistent security concern about forging inline
> value objects. And they also help us understand
> more deeply "what's in a value".
> — John
More information about the valhalla-spec-experts