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

Implemented winsock info import/export #3216

Closed
wants to merge 3 commits into from

Conversation

weltling
Copy link
Contributor

This is a technique analogue to SCM_RIGHTS already available in implementations based on BSD sockets. The exported information is to be used to create a duplicate descriptor of the same network socket in another or same process. Any socket created that way can be safely closed. The actual socket is closed when all the duplicated sockets are. Note, that it only works for network sockets.

The advantage of this method over creating separate sockets using SO_REUSEADDR is, that all the duplicates have a common backlog. The API is very platform specific, thus separate functions are required.

Thanks.

@weltling
Copy link
Contributor Author

@bwoebi could you check, please?

Thanks

php_error_docref(NULL, E_WARNING, "Unable to export WSA protocol info [0x%08lx]: %s", err, buf);
}

RETURN_NULL();
Copy link
Member

Choose a reason for hiding this comment

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

Why does this return null rather than false (like the error case above)?


RETVAL_STR((ret));

zend_string_free(ret);
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this freeing the string that was just returned?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ohh, my bad. It's just an assignment there. Fixing.

php_error_docref(NULL, E_WARNING, "Faled to base64 decode protocol info");
RETURN_NULL();
}
memmove(&wi, ZSTR_VAL(zsinfo), ZSTR_LEN(zsinfo));
Copy link
Member

Choose a reason for hiding this comment

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

This needs to check that the string length matches the structure size beforehand.

What is the reason for using memmove over memcpy here? The structures can't overlap.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Usually memmove is safer, whereby here it's not relevant, just a habit of mine. Indeed I also miss here the length check on the supplied info len. Thanks for the comments, will tidy all that up.

RETURN_NULL();
}
memmove(&wi, ZSTR_VAL(zsinfo), ZSTR_LEN(zsinfo));
zend_string_free(zsinfo);
Copy link
Member

Choose a reason for hiding this comment

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

As this is not performance-critical code, zend_string_release is safer.


zsinfo = php_base64_decode(info, info_len);
if (!zsinfo) {
php_error_docref(NULL, E_WARNING, "Faled to base64 decode protocol info");
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: "Failed"

Copy link
Contributor Author

@weltling weltling Apr 13, 2018

Choose a reason for hiding this comment

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

Fixed, thanks :)

however it is unlikely to ever make sense to have it editable within
a script. The struct is suited very well and has same size under both
64- and 32-bit. */
ret = php_base64_encode((const char *)&wi, sizeof(wi));
Copy link
Member

Choose a reason for hiding this comment

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

Is there any particular need to serialize it at all? it's just simple binary data

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had it in the first variant. Basically can be done that way, but it can be weird especially when the binary data has '\0' bytes. Fe in case some output needs to be checked in tests, etc. No big deal either way otherwise.

Thanks.

Copy link
Member

Choose a reason for hiding this comment

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

I'm quite leery about directly exposing (whether encoded or not) such a structure. There's quite a lot of information in there (https://msdn.microsoft.com/en-us/library/windows/desktop/ms741675(v=vs.85).aspx) and it's not immediately obvious to me that nothing bad could happen if the user were to manually modify/construct it before calling the import function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The concern is understandable, of course. The default security mechanism applies, when another process imports the socket. It is for sure possible to craft a WSAPROTOCOL_INFO struct.

The default security also applies, see DACLs https://msdn.microsoft.com/de-de/library/windows/desktop/aa446597(v=vs.85).aspx . Fe it is not possible use a socket created under another account, until it is explicitly set ACLs to be allowed. Or it is not possible to duplicate a socket that is not shared (didn't call WSADuplicateSocket). In general, it is hard to do harm to unrelated parts of the system, fe like "stealing" a socket from some another process, on a properly configured system. Same actually when some invalid data gets imported. In this regard, sockets using SO_REUSEADDR are a far more insecure solution.

Another approach were to use shared memory. This however introduces another implication by a need to synchronize access. AFAIR Bob was also OK to go by shared memory.

Another approach i could think of were to track the exported structure internally and introduce an extra function that encapsulates the sending process. This introduces a couple of other implications, but is in general doable.

What would you say?

Thanks.

@bwoebi
Copy link
Member

bwoebi commented Apr 13, 2018

Overall, I like the implementation - seems like it should also work properly in conjunction with socket_export_stream() and is flexible enough for most needs :-)

Thanks a lot for working on it!

@weltling
Copy link
Contributor Author

@bwoebi great! Lets wait for more comments, otherwise I'd intend to merge this somewhen next week.

Thanks for the checks everyone!

@weltling
Copy link
Contributor Author

I've now reimplemented to use shared memory mechanism. It requires an additional step for parent to wait for child's ok before releasing the memory segment, thus required an additional function. Otherwise there's no change to the suggested API, the parent will produce an identifier and send it to the child, the child will read the data structure from SHM. That way, the structure is not accessible directly in the scripts, so the import function can't be abused with a crafted data.

I've got an example echo server implementation https://gist.github.com/weltling/0d78544fa3b4c1342027229aaf7ae43c. It's a bit too big for a test, however :)

Thanks.

RETURN_FALSE;
}

seg_name_len = snprintf(seg_name, sizeof(seg_name)-1, "php_wsa_for_%u", SOCKETS_G(wsa_child_count)++);
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be better to directly zend_strpprintf to a zend_string here, as this is needed as a zend_string in two places below anyway.

@nikic
Copy link
Member

nikic commented Apr 26, 2018

Not really familiar with what this is about, someone like @bwoebi should review.

@weltling
Copy link
Contributor Author

@nikic thanks for the checks, moved to strpprintf. OFC it'd be nice to hear yet from @bwoebi :) Could you please check, Bob?

In any case, this way it's ensured no untrusted data would go through the import function, though need one more synchronization step to not to waste the spent memory. Actually could make both ways work, but i think the more secure way like this one should be preferred.

Thanks.

@weltling
Copy link
Contributor Author

weltling commented May 4, 2018

@bwoebi ping :)

@bwoebi
Copy link
Member

bwoebi commented May 15, 2018

Looks good to me generally - I'd appreciate a merge :-)

@weltling
Copy link
Contributor Author

Merged as 9d4da80. Thanks everyone!

@weltling weltling closed this May 19, 2018
@weltling weltling deleted the wsaprotocol_info branch May 29, 2018 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants