| From jlayton@redhat.com Mon Feb 2 15:10:37 2009 |
| From: Jeff Layton <jlayton@redhat.com> |
| Date: Thu, 22 Jan 2009 10:35:13 -0500 |
| Subject: cifs: make sure we allocate enough storage for socket address |
| To: stable@kernel.org |
| Message-ID: <1232638513-9022-1-git-send-email-jlayton@redhat.com> |
| |
| From: Jeff Layton <jlayton@redhat.com> |
| |
| commit a9ac49d303f967be0dabd97cb722c4a13109c6c2 upstream. |
| |
| cifs_mount declares a struct sockaddr on the stack and then casts it |
| to the proper address type. The storage allocated is fine for ipv4, |
| but is too small for ipv6 addresses. Declare it as |
| "struct sockaddr_storage" instead of struct sockaddr". |
| |
| This bug was manifesting itself as oopses and address corruption when |
| mounting IPv6 addresses. |
| |
| Signed-off-by: Jeff Layton <jlayton@redhat.com> |
| Tested-by: Stefan Bader <stefan.bader@canonical.com> |
| Signed-off-by: Steve French <sfrench@us.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/cifs/connect.c | 18 +++++++++--------- |
| 1 file changed, 9 insertions(+), 9 deletions(-) |
| |
| --- a/fs/cifs/connect.c |
| +++ b/fs/cifs/connect.c |
| @@ -1349,7 +1349,7 @@ cifs_parse_mount_options(char *options, |
| } |
| |
| static struct TCP_Server_Info * |
| -cifs_find_tcp_session(struct sockaddr *addr) |
| +cifs_find_tcp_session(struct sockaddr_storage *addr) |
| { |
| struct list_head *tmp; |
| struct TCP_Server_Info *server; |
| @@ -1369,11 +1369,11 @@ cifs_find_tcp_session(struct sockaddr *a |
| if (server->tcpStatus == CifsNew) |
| continue; |
| |
| - if (addr->sa_family == AF_INET && |
| + if (addr->ss_family == AF_INET && |
| (addr4->sin_addr.s_addr != |
| server->addr.sockAddr.sin_addr.s_addr)) |
| continue; |
| - else if (addr->sa_family == AF_INET6 && |
| + else if (addr->ss_family == AF_INET6 && |
| memcmp(&server->addr.sockAddr6.sin6_addr, |
| &addr6->sin6_addr, sizeof(addr6->sin6_addr))) |
| continue; |
| @@ -2027,7 +2027,7 @@ cifs_mount(struct super_block *sb, struc |
| int rc = 0; |
| int xid; |
| struct socket *csocket = NULL; |
| - struct sockaddr addr; |
| + struct sockaddr_storage addr; |
| struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; |
| struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; |
| struct smb_vol volume_info; |
| @@ -2039,7 +2039,7 @@ cifs_mount(struct super_block *sb, struc |
| |
| /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ |
| |
| - memset(&addr, 0, sizeof(struct sockaddr)); |
| + memset(&addr, 0, sizeof(struct sockaddr_storage)); |
| memset(&volume_info, 0, sizeof(struct smb_vol)); |
| if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { |
| rc = -EINVAL; |
| @@ -2069,9 +2069,9 @@ cifs_mount(struct super_block *sb, struc |
| rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, |
| &sin_server6->sin6_addr.in6_u); |
| if (rc > 0) |
| - addr.sa_family = AF_INET6; |
| + addr.ss_family = AF_INET6; |
| } else { |
| - addr.sa_family = AF_INET; |
| + addr.ss_family = AF_INET; |
| } |
| |
| if (rc <= 0) { |
| @@ -2113,7 +2113,7 @@ cifs_mount(struct super_block *sb, struc |
| |
| srvTcp = cifs_find_tcp_session(&addr); |
| if (!srvTcp) { /* create socket */ |
| - if (addr.sa_family == AF_INET6) { |
| + if (addr.ss_family == AF_INET6) { |
| cFYI(1, ("attempting ipv6 connect")); |
| /* BB should we allow ipv6 on port 139? */ |
| /* other OS never observed in Wild doing 139 with v6 */ |
| @@ -2144,7 +2144,7 @@ cifs_mount(struct super_block *sb, struc |
| } else { |
| srvTcp->noblocksnd = volume_info.noblocksnd; |
| srvTcp->noautotune = volume_info.noautotune; |
| - if (addr.sa_family == AF_INET6) |
| + if (addr.ss_family == AF_INET6) |
| memcpy(&srvTcp->addr.sockAddr6, sin_server6, |
| sizeof(struct sockaddr_in6)); |
| else |