summaryrefslogtreecommitdiff
path: root/fs/smb/client/fs_context.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/fs_context.c')
-rw-r--r--fs/smb/client/fs_context.c55
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(&param->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