-
Notifications
You must be signed in to change notification settings - Fork 7.7k
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
Conversation
@bwoebi could you check, please? Thanks |
ext/sockets/sockets.c
Outdated
php_error_docref(NULL, E_WARNING, "Unable to export WSA protocol info [0x%08lx]: %s", err, buf); | ||
} | ||
|
||
RETURN_NULL(); |
There was a problem hiding this comment.
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)?
ext/sockets/sockets.c
Outdated
|
||
RETVAL_STR((ret)); | ||
|
||
zend_string_free(ret); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
ext/sockets/sockets.c
Outdated
php_error_docref(NULL, E_WARNING, "Faled to base64 decode protocol info"); | ||
RETURN_NULL(); | ||
} | ||
memmove(&wi, ZSTR_VAL(zsinfo), ZSTR_LEN(zsinfo)); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
ext/sockets/sockets.c
Outdated
RETURN_NULL(); | ||
} | ||
memmove(&wi, ZSTR_VAL(zsinfo), ZSTR_LEN(zsinfo)); | ||
zend_string_free(zsinfo); |
There was a problem hiding this comment.
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.
ext/sockets/sockets.c
Outdated
|
||
zsinfo = php_base64_decode(info, info_len); | ||
if (!zsinfo) { | ||
php_error_docref(NULL, E_WARNING, "Faled to base64 decode protocol info"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "Failed"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, thanks :)
ext/sockets/sockets.c
Outdated
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)); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 DACL
s 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 ACL
s 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.
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! |
@bwoebi great! Lets wait for more comments, otherwise I'd intend to merge this somewhen next week. Thanks for the checks everyone! |
d34f8d0
to
f126702
Compare
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. |
ext/sockets/sockets.c
Outdated
RETURN_FALSE; | ||
} | ||
|
||
seg_name_len = snprintf(seg_name, sizeof(seg_name)-1, "php_wsa_for_%u", SOCKETS_G(wsa_child_count)++); |
There was a problem hiding this comment.
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.
Not really familiar with what this is about, someone like @bwoebi should review. |
@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. |
@bwoebi ping :) |
Looks good to me generally - I'd appreciate a merge :-) |
Merged as 9d4da80. Thanks everyone! |
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.