Make cifs_convert_address() take a const src pointer and a length so that all the strlen() calls in their can be cut out and to make it unnecessary to modify the src string. Also return the data length from dns_resolve_server_name_to_ip() so that a strlen() can be cut out of cifs_compose_mount_options() too. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- fs/cifs/cifs_dfs_ref.c | 5 ++--- fs/cifs/cifsproto.h | 4 ++-- fs/cifs/connect.c | 1 + fs/cifs/dns_resolve.c | 20 +++++++++----------- fs/cifs/netmisc.c | 45 ++++++++++++++++++++++++--------------------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ac19a6f..37543e8 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -141,7 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, } rc = dns_resolve_server_name_to_ip(*devname, &srvIP); - if (rc != 0) { + if (rc < 0) { cERROR(1, "%s: Failed to resolve server part of %s to IP: %d", __func__, *devname, rc); goto compose_mount_options_err; @@ -150,8 +150,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, * assuming that we have 'unc=' and 'ip=' in * the original sb_mountdata */ - md_len = strlen(sb_mountdata) + strlen(srvIP) + - strlen(ref->node_name) + 12; + md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; mountdata = kzalloc(md_len+1, GFP_KERNEL); if (mountdata == NULL) { rc = -ENOMEM; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 2eaebbd..1f54508 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -86,8 +86,8 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server); -extern int cifs_convert_address(struct sockaddr *dst, char *src); -extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src, +extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); +extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, unsigned short int port); extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); extern void header_assemble(struct smb_hdr *, char /* command */ , diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 399b601..7a78b49 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1538,6 +1538,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) if (volume_info->UNCip && volume_info->UNC) { rc = cifs_fill_sockaddr((struct sockaddr *)&addr, volume_info->UNCip, + strlen(volume_info->UNCip), volume_info->port); if (!rc) { /* we failed translating address */ diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index ff6fa2f..8de3b98 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c @@ -40,11 +40,11 @@ static const struct cred *dns_resolver_cache; * 0 - name is not IP */ static int -is_ip(char *name) +is_ip(const char *name, int len) { struct sockaddr_storage ss; - return cifs_convert_address((struct sockaddr *)&ss, name); + return cifs_convert_address((struct sockaddr *)&ss, name, len); } static int @@ -54,6 +54,10 @@ dns_resolver_instantiate(struct key *key, const void *data, int rc = 0; char *ip; + /* make sure this looks like an address */ + if (!is_ip(data, datalen)) + return -EINVAL; + ip = kmalloc(datalen + 1, GFP_KERNEL); if (!ip) return -ENOMEM; @@ -61,12 +65,6 @@ dns_resolver_instantiate(struct key *key, const void *data, memcpy(ip, data, datalen); ip[datalen] = '\0'; - /* make sure this looks like an address */ - if (!is_ip(ip)) { - kfree(ip); - return -EINVAL; - } - key->type_data.x[0] = datalen; key->payload.data = ip; @@ -93,7 +91,7 @@ struct key_type key_type_dns_resolver = { * unc - server UNC * output: * *ip_addr - pointer to server ip, caller responcible for freeing it. - * return 0 on success + * return the length of the returned string on success */ int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) @@ -131,7 +129,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) memcpy(name, unc+2, len); name[len] = 0; - if (is_ip(name)) { + if (is_ip(name, len)) { cFYI(1, "%s: it is IP, skipping dns upcall: %s", __func__, name); data = name; @@ -164,7 +162,7 @@ skip_upcall: name, *ip_addr ); - rc = 0; + rc = len; } else { rc = -ENOMEM; } diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 3489468..b7f5975 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -139,17 +139,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { * Returns 0 on failure. */ static int -cifs_inet_pton(const int address_family, const char *cp, void *dst) +cifs_inet_pton(const int address_family, const char *cp, int len, void *dst) { int ret = 0; /* calculate length by finding first slash or NULL */ if (address_family == AF_INET) - ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); + ret = in4_pton(cp, len, dst, '\\', NULL); else if (address_family == AF_INET6) - ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); + ret = in6_pton(cp, len, dst , '\\', NULL); - cFYI(DBG2, "address conversion returned %d for %s", ret, cp); + cFYI(DBG2, "address conversion returned %d for %*.*s", + ret, len, len, cp); if (ret > 0) ret = 1; return ret; @@ -164,37 +165,39 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) * Returns 0 on failure. */ int -cifs_convert_address(struct sockaddr *dst, char *src) +cifs_convert_address(struct sockaddr *dst, const char *src, int len) { - int rc; - char *pct, *endp; + int rc, alen, slen; + const char *pct; + char *endp, scope_id[13]; struct sockaddr_in *s4 = (struct sockaddr_in *) dst; struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; /* IPv4 address */ - if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) { + if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) { s4->sin_family = AF_INET; return 1; } - /* temporarily terminate string */ - pct = strchr(src, '%'); - if (pct) - *pct = '\0'; - - rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr); - - /* repair temp termination (if any) and make pct point to scopeid */ - if (pct) - *pct++ = '%'; + /* attempt to exclude the scope ID from the address part */ + pct = memchr(src, '%', len); + alen = pct ? pct - src : len; + rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr); if (!rc) return rc; s6->sin6_family = AF_INET6; if (pct) { + /* grab the scope ID */ + slen = len - (alen + 1); + if (slen <= 0 || slen > 12) + return 0; + memcpy(scope_id, pct + 1, slen); + scope_id[slen] = '\0'; + s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); - if (!*pct || *endp) + if (endp != scope_id + slen) return 0; } @@ -202,10 +205,10 @@ cifs_convert_address(struct sockaddr *dst, char *src) } int -cifs_fill_sockaddr(struct sockaddr *dst, char *src, +cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, const unsigned short int port) { - if (!cifs_convert_address(dst, src)) + if (!cifs_convert_address(dst, src, len)) return 0; switch (dst->sa_family) { -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html