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

copy (aka snapshot) any buffersources in options before going async #128

Open
equalsJeffH opened this issue Sep 28, 2018 · 12 comments · May be fixed by #130
Open

copy (aka snapshot) any buffersources in options before going async #128

equalsJeffH opened this issue Sep 28, 2018 · 12 comments · May be fixed by #130
Assignees

Comments

@equalsJeffH
Copy link
Collaborator

equalsJeffH commented Sep 28, 2018

instances of the CredentialCreationOptions and CredentialRequestOptions dictionaries may contain (nested sub)components of type BufferSource.

If so, copies of the buffers must be made before the algorithm in question goes async (aka "in parallel").

E.g., see also: w3c/webauthn#294

@equalsJeffH
Copy link
Collaborator Author

equalsJeffH commented Oct 5, 2018

@jcjones and I have been discussing this. It seems clear that since the overall tasks of credential "creation" and "getting" begin in the credman spec and go async there (e.g., in this alg, in the "create" case), that the issue of creating copies of any buffersources within CredentialCreationOptions or CredentialRequestOptions lie with the credman spec.

Also, since CredentialCreationOptions and CredentialRequestOptions are dictionaries, it is not clear whether we can (or should) use e.g. structuredserialize to perform the copy of CredentialCreationOptions or CredentialRequestOptions or whether we ought to instead craft language such as:

"make a deep copy of |options|, such as by recursively cloning fields, except for BufferSource objects where one will need to get a copy of the bytes held by the buffer source".....

..?

cc: @mikewest @bzbarsky

@equalsJeffH
Copy link
Collaborator Author

equalsJeffH commented Oct 6, 2018

After thinking about the creating-a-deep-copy-of-a-dictionary-with-any-buffersources-bytes-copied thing on my bike ride yesterday evening, it seems that if we need to explicitly specify how we recurse through a potentially complex dictionary and get copies of buffersource bytes, we can perhaps leverage the "[An IDL dictionary value V is converted to an ECMAScript Object value]

[UPDATE 8-Oct-2018]: I realized that since dictionaries are passed-by-value, it seems we do not need to make a copy of the entire options dictionary (?), rather we just need to copy any buffer sources' data, And then in the original options dictionary, update the associated value of type buffer source to point to the newly copied data, and then pass the options dictionary down into the in parallel alg section (?).

So I've updated the below alg to (hopefully) accomplish this (the original "dict deep copy" alg is preserved at end below), my nominal name for this new alg is <dfn>create a copy of any buffer sources' data</dfn>:

To <dfn>create a copy of any buffer sources' data</dfn> 
referenced by a dictionary value |V|, run this algorithm:

1. Let |dictionaries| be a list consisting of |V| and all of |V|'s 
    [=inherited dictionaries=], in order from least to most derived.

2. For each dictionary |dictionary| in |dictionaries|, in order:

    1. For each dictionary member |member| declared on 
         |dictionary|, in lexicographical order:

        1. Let |key| be the [=identifier=] of |member|.

        2. If the dictionary member named |key| is [=present=] in |V|, then:

            1. Let |value| be the value of |member| on |V|.

            2. If |value|'s type is a [=buffer source type=] then 
                [=get a copy of the bytes held by the buffer source=] and 
                set |values|'s value to be a reference to the copy of the bytes.

Then, at the beginning of the credman algorithms to which we pass CredentialCreationOptions or CredentialRequestOptions dictionaries, we can have a new step something like the following (before the alg goes "in parallel":

n. [=create a copy of any buffer sources' data=] referenced by |options|.

..and then use |options| in the "in parallel" portion of the alg.

It seems to me that the specification of the [=create a copy of any buffer sources' data=] alg ought to be in some other spec other than credman -- e.g. Infra? WebIDL?

thoughts?


UPDATE 8-Oct-2018: I'm parking the original <dfn>create a deep copy including any buffer sources</dfn> alg (I previously had written above) here in case it is ever useful

To <dfn>create a deep copy including any buffer sources</dfn> 
|dictCopy| of a dictionary value |V|, run this algorithm:

1. Let |dictCopy| be an empty dictionary of type [=dictionary type=]
    with every [=dictionary member=]
    initially considered to be [=not present=].

2. Let |dictionaries| be a list consisting of |V| and all of |V|'s 
    [=inherited dictionaries=], in order from least to most derived.

3. For each dictionary |dictionary| in |dictionaries|, in order:

    1. For each dictionary member |member| declared on 
         |dictionary|, in lexicographical order:

        1. Let |key| be the [=identifier=] of |member|.

        2. If the dictionary member named |key| is present in |V|, then:

            1. Let |value| be the value of |member| on |V|.

            2. Let |newDictMember| be a new [=dictionary member=]
                of |dictCopy| named |key|, and having the same type as |value|,

            3. If |newDictMember|'s type is:
                <dl class="switch">
                     : a [=buffer source types|buffer source type=]
                     :: [=get a copy of the bytes held by the buffer source=] and 
                        let |newDictMember|'s value be a reference to the copy of the bytes.
                     :  anything else
                     :: Let |newDictMember|'s value be |value|.
                </dl>

@bzbarsky
Copy link

bzbarsky commented Oct 8, 2018

Having some sane way to clone dictionaries like that makes sense to me. @domenic @annevk thoughts on the proposal above and where something like that would live?

@bzbarsky
Copy link

bzbarsky commented Oct 8, 2018

And note that how this should work for dictionaries containing references to instances of WebIDL interfaces (say Node or something) is not really that clear. One option is to have the algorithm preserve all the values in the dictionary except buffer sources, I guess, and copy those....

@equalsJeffH
Copy link
Collaborator Author

equalsJeffH commented Oct 8, 2018

@bzbarsky wrote:

One option is to have the algorithm preserve all the values in the dictionary except buffer sources, I guess, and copy those....

yeah, I attempted to update the alg (apparently while you were reviewing it) to do "preserve all the values in the dictionary except buffer sources ... and copy those".

@annevk
Copy link
Member

annevk commented Oct 9, 2018

If we offered utilities around dictionaries with regards to IDL values, they should be defined in IDL I think. It's not clear something generic is possible though, we'd need several instances to figure out if there's a pattern here, though passing dictionaries to "in parallel" is something I vaguely recall having seen before.

Are you sure you want to create copies by the way? Is the person who passed these values going to reuse them for something? Otherwise it might be more efficient to transfer ownership and detach the passed in objects.

@jcjones
Copy link

jcjones commented Oct 15, 2018

Are you sure you want to create copies by the way? Is the person who passed these values going to reuse them for something? Otherwise it might be more efficient to transfer ownership and detach the passed in objects.

I think that would be fine as well, keeping in mind that the real source issue here is the possibility of asynchronous modification to buffer sources. So detaching everything is fine, as long as we also detach any embedded buffer sources.

@mikewest mikewest self-assigned this Oct 22, 2018
@mikewest
Copy link
Member

Assigning this to me, as per conversation in WebAuthn.

@annevk: Do you think that the "create a deep copy including any buffer sources" algorithm above ought to live in Infra? Or should we just stick it in credential management and call it done?

@equalsJeffH
Copy link
Collaborator Author

equalsJeffH commented Oct 23, 2018

@mikewest noted:

as per conversation in WebAuthn

recap of conversation? It does not seem to be minuted, thx.

Do you think that the "create a deep copy including any buffer sources" algorithm above ought to live in Infra?

So you guys are thinking we ought to codify and use the "create a deep copy including any buffer sources" algorithm rather than the lighter-weight "create a copy of any buffer sources' data" one (both above in #128 (comment)) ? rationale (am curious) ? (note: I think the "create a copy of any buffer sources' data" alg does what @bzbarsky is musing about in #128 (comment)).

Also, why not modify "create a copy of any buffer sources' data" to do a "transfer" per #128 (comment) and #128 (comment) ?

@annevk
Copy link
Member

annevk commented Oct 23, 2018

I think the algorithm should be inline for now. The other consideration with transfer vs copy is size I suppose. If these are never going to be large buffers, it might not be worth trying to free the memory. On the other hand, if they never ought to be reused, you might as well do it that way for safety.

@equalsJeffH
Copy link
Collaborator Author

on 23-Oct-2018 webauthn tpac meeting call -- mikewest & jc think that the way to go is "copy" rather than "transfer" and we just need to figure out which of the versions of the proposed algs in #128 (comment) we ought to use.

@jcjones
Copy link

jcjones commented Oct 23, 2018

And specifically WebAuthn's use case has small, predictable-sized buffers -- they aren't likely to be used for many-kilobyte buffers. A rogue website using megabyte buffers could cause some performance degradation, but they'd have to be able to use WebAuthn anyway (either a top-level document, of (ultimately) permitted via feature-policy).

equalsJeffH added a commit to equalsJeffH/webappsec-credential-management that referenced this issue Oct 23, 2018
@equalsJeffH equalsJeffH linked a pull request Oct 23, 2018 that will close this issue
@equalsJeffH equalsJeffH self-assigned this May 6, 2019
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 a pull request may close this issue.

5 participants