-
Notifications
You must be signed in to change notification settings - Fork 1.5k
net: socket: Introduce net_clear_sinzero() #370
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
net: socket: Introduce net_clear_sinzero() #370
Conversation
In IPv4, sin_zero field exits in sockaddr_in for padding and should be set to zero. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
| return -EOPNOTSUPP; | ||
| } | ||
|
|
||
| return psock->s_sockif->si_getpeername(psock, addr, addrlen); |
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.
Can we zero out the whole addr before call si_getpeername/si_getsockename/si_accept/si_recvfrom?
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.
@xiaoxiang781216 Do you mean that if (add != NULL && addrlen > 0), then memset(addr, 0, addrlen) ?
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.
Yes, something like this, but we need check each implementation don't overwrite the unused field with the random bit again.
| * | ||
| ****************************************************************************/ | ||
|
|
||
| #ifdef CONFIG_NET_IPv4 |
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.
It doesn't make sense to just clear IPv4 address, we should clear all unused field to zero for all address family, otherwise the similiar error will report again and again.
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.
@xiaoxiang781216 In my understanding, padding field only exists in sockaddr_in (i.e. IPv4 family). So that's why I added ifdef CONFIG_NET_IPv4.
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.
BSD socket is a general interface, many protocol build on top of it: IPv4, IPv6, Unix domain, Bluetooth etc. Each protocol define his own address repsentation, and then may add the padding field like IPv4. We have to find a general solution.
@patacongo I thought it's the application's responsibility to clear sin_zero. But as long as I checked Linux kernel, it clears in the network stack. (perhaps to accept network applications having an wrong manner?) |
For input addresses, the form of the address parameter will be "FAR const struct sockaddr *addr" and the application must set the sin_zero field. These are read-only for the OS and must never be modified by the OS. For example when a struct sockaddr_in is passed to sendto(). These may not be written to under any circumstances (and may even lie in ROM). If Linux is modifying read-only values, it is screwed up. We do not want duplicate such errors in the this OS. For output addresses, the form form of the address parameter will be "FAR struct sockaddr *addr). In that case, the OS must also set the sin_zero field before returning, I really dislike this solution. I think that the sin_zero field should always be set where ever sin_port and sin_addr is set. You chould not have to check anyhting in those cases just memset() the field. There should not be any centralizing logic to retroactively sets sin_zero. I am closing this PR because I think it is not correct. It is difficult to understand the logic completely form just looking at the differences, and it may be correct if it is applied ONLY to output addresses. However, even in that case. I do not believe that it is the correct way to implement the zeroing. That should be done when sin_port and sin_addr are set. |
|
Let me be clearer. Whenever logic within the OS inializes a sockaddr_in structure, the code sequence should always be modified to set sin_zero() like: There should be no centralized logic to try to set sin_zero in some other place. If the sockaddr_in structure is not created by the OS, it must never modify it. |
|
@patacongo does it make sense that we call memset on the whole addr before call si_getpeername/si_getsockename/si_accept/si_recvfrom? |
I dislike that solution too. It is a ugly hack. We should do it right. sin_zerio is not different then any other field in sockadd_in. The clean, easily unstandable way is: Let's not take ugly shortcuts. But having said that, it is not as ugly as the original proposal. It is just not as straightforward. |
|
People on the internet are saying that leaving the sin_zero field is causing some kinds of issues. I don't know how that could be unless the sin_zero actually contains values in some cases. Is there there some use case where sin_zero would not be zero (for example, some protocol-specific usage). |
|
The problem is that: |
|
But the memset of the whole structure would be wasteful for IPv6 addresses.
The distinction between IPv4 and IPv6 is made at a lower level than accept/getsockname/getpeername/recvfrom. At that lower level, the IPv4 specific code and always assume that sin_zero is present. If sin_port and sin_addr are set then you know that sin_zero can be set too.. always. For example: accept->psock_accept->inet_accept->tcp_psock_accept then the address is initialized like: The memset of sin_zero belongs between lines 119 and 120. Easy and perfect! sin_zero should be initialized at the very, very lowest level at the same time that sin_port and sin_addr are initialize. That is the simplest and can never fail. I have not looked at every case, but I believe that all reduce to this simplest, most straight-forward, monst maintainable, most understanable solution. |
|
Yes, this is what I want to say: |
|
Okay so I did the work and checked out where all IPv4 sockadd_in structures are initialed. There are many, many more than just accept/getsockname/getpeername/recvfrom . I added memset(sin_zero, 0, sizeof(sin_zero)); to each of them and create pr377. |
Ignorinig the read-only 'const' would be a violation of C principles. We should not do that. I think it would be legal to test if sin_zero is all zero and, if not, return an error. That is correct, but would probably annoy a lot of people. |
|
One thing we could do it if matters enough to you is to make a copy of socketadd_in input then clear the sin_zero field in the copy. I don't recommend this for embedded systems but this is most likely what Linux is doing. Linux never accesses any user pointers without going though severl security layers so, for Linux, is it simpler to copy input argument (if they are not large) rather than go through the security measures on every access. If there are no security macros in the code you are looking at, you can be assured that linux is modifying a copy of the user input, not the actual user input itself. That should never be done for a const input. |
|
AFAIK nothing in the NuttX network stack cares about the content of sin_zero. There would be nothing gained for NuttX by clearing that field for input sockaddr_in values. |
Summary
Impact
Testing