diff options
Diffstat (limited to 'fs/smb/client/fs_context.c')
-rw-r--r-- | fs/smb/client/fs_context.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 23dd35a9cefd..7cdce3c6916c 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1242,14 +1242,51 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, cifs_dbg(FYI, "Domain name set\n"); break; case Opt_srcaddr: - if (!cifs_convert_address( - (struct sockaddr *)&ctx->srcaddr, - param->string, strlen(param->string))) { - pr_warn("Could not parse srcaddr: %s\n", - param->string); + { + char *srcaddr_val = param->string; + int i = 0; + + /* check if it's an IP address */ + if (cifs_convert_address((struct sockaddr *)&ctx->srcaddr, + srcaddr_val, strlen(srcaddr_val))) + break; + + while ((srcaddr_val = strsep(¶m->string, ";")) && i < CIFS_MAX_CHANNELS) { + if (!strlen(srcaddr_val)) { + pr_warn("empty value passed to srcaddr=\n"); + continue; + } + + /* else, it's an interface name -- validate it */ + if (!dev_valid_name(srcaddr_val) || + !__dev_get_by_name(&init_net, srcaddr_val)) { + pr_warn("ignoring invalid interface name %s for srcaddr=\n", + srcaddr_val); + continue; + } + + ctx->iface_names[i] = kstrdup(srcaddr_val, GFP_KERNEL); + if (!ctx->iface_names[i]) { + /* cleanup any previously allocated interface name */ + while (--i >= 0) { + if (ctx->iface_names[i]) { + kfree(ctx->iface_names[i]); + ctx->iface_names[i] = NULL; + } + } + goto cifs_parse_mount_err; + } + + i++; + } + + if (i == 0) { + pr_warn("Could not parse srcaddr=: %s\n", param->string); goto cifs_parse_mount_err; } + break; + } case Opt_iocharset: if (strnlen(param->string, 1024) >= 65) { pr_warn("iocharset name too long\n"); @@ -1637,6 +1674,14 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx) ctx->prepath = NULL; kfree(ctx->leaf_fullpath); ctx->leaf_fullpath = NULL; + if (ctx->iface_names[0]) { + int i = 0; + while (ctx->iface_names[i] && i < CIFS_MAX_CHANNELS) { + kfree(ctx->iface_names[i]); + ctx->iface_names[i] = NULL; + i++; + } + } } void |