Setting sin_zero to 0 in struct sockaddr_in

I was looking at the Linux DHCP source code today which recently had a security advisory posted on it.   I looked at the patched version – without looking at the patch, and could not find any striking vulnerabilities.

I did however come across code that did something like this.

struct sockaddr_in sin;
sin.sin_family = PF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = addr;

ret = sendto(...(struct sockaddr *)&sin...);

What it didn’t do was clear the sin_zero field in sockaddr_in to zero. This is a bug. I see it occur occasionaly.  This bug can cause undefined behaviour in applications.  In practice, I’ve seen functions such as sendto or recvfrom fail randomly because of lack of clearing sin_zero.  The intermittant nature of the error probably occured becuase I was using the stack for sockaddr_in, and often sockaddr_in was automatically set to zero, but occasionaly was not depending on the application in question.

 Firstly, what is sin_zero, and why should we care about it.


struct sockaddr_in
{
  sa_family_t    sin_family;   
  in_port_t      sin_port;     
  struct in_addr sin_addr;     

  unsigned char  __pad[__SOCK_SIZE__ - sizeof(short int)
                        - sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero        __pad

That is from Windows cygwin /usr/include/cygwin/in.h.  The include file to use that is portable is /usr/include/in.h

Most of the net code does not use sockaddr_in, it uses sockaddr.  When you use a function like sendto, you must explicitly cast sockaddr_in, or whatever address your using, to sockaddr.  sockaddr_in is the same size as sockaddr, but internally the sizes are the same because of a slight hack.

 That hack is sin_zero.  Really the length of useful data in sockaddr_in is shorter than sockaddr.  But the difference is padded in sockaddr_in using a small buffer; that buffer is sin_zero. 

On some architectures, it wont cause any problems not clearing sin_zero.  But on other architectures it might.  Its required by specification to clear sin_zero, so you must do this if you intend your code to be bug free for now and in the future.

There are two ways of clearing sin_zero.


memset(&sin, 0, sizeof(sin));
sin.sin_family = ...;
sin.sin_addr = ...;
sin.sin_port = ...;

or

sin.sin_family = ...;
sin.sin_addr = ...;
sin.sin_port = ...;
memset(&sin.sin_zero, 0, sizeof(sin.sin_zero));

I prefer the later because in my view it performs slightly faster due to the fact that it doesnt set data to zero which then later gets reassigned.
I have seen people use a hardcoded figure of 8 for sizeof(sin.sin_zero). I believe this is also incorrect, and not as portable; for example, if a possible extention of sockaddr occurs in the future.  This probably will never occur, and some might argue that using 8 is ok, but in my opinion it is just nicer style.

5 responses to “Setting sin_zero to 0 in struct sockaddr_in

  1. What is sin_zero used for? I’ve seen it, but never used it.

  2. Chizl, comon. He just explained it🙂 sin_zero is used so struct sockaddr and sockaddr_in looks like the same from outside. Internally sockaddr_in is much smaller than sockaddr. Setting the rest of the bits to zero makes it look like they are the same.

  3. Ups. Sorry. My name is Slot. Not chizl. Sorry for that.

  4. Strange behavior can only occur if the filed actually has a use. If the field is not used, there is no need to clear. As for the comment about performance when clearing, surely it is better as a general rule to clear the containing structure so that you always “get it all” – instead of revisiting each time a new field is added.

  5. I agree with you about use the sizeof(sin.sin_zero) and I don’t like when a person use a constant value and then said but it works!.

    In my case I prefer to use:

    bzero(&addr, sizeof(addr));

    cheers.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s