Commit f0768ebd authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

NFS: Introduce nfs4_validate_mount_options



Refactor NFSv4 mount processing to break out mount data validation
in the same way it's broken out in the NFSv2/v3 mount path.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 5df36e78
Loading
Loading
Loading
Loading
+89 −64
Original line number Diff line number Diff line
@@ -813,6 +813,89 @@ static void nfs4_fill_super(struct super_block *sb)
	nfs_initialise_sb(sb);
}

/*
 * Validate NFSv4 mount options
 */
static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
				    const char *dev_name,
				    struct sockaddr_in *addr,
				    rpc_authflavor_t *authflavour,
				    char **hostname,
				    char **mntpath,
				    char **ip_addr)
{
	struct nfs4_mount_data *data = *options;
	char *c;

	if (data == NULL)
		goto out_no_data;

	switch (data->version) {
	case 1:
		if (data->host_addrlen != sizeof(*addr))
			goto out_no_address;
		if (copy_from_user(addr, data->host_addr, sizeof(*addr)))
			return -EFAULT;
		if (addr->sin_port == 0)
			addr->sin_port = htons(NFS_PORT);
		if (!nfs_verify_server_address((struct sockaddr *) addr))
			goto out_no_address;

		switch (data->auth_flavourlen) {
		case 0:
			*authflavour = RPC_AUTH_UNIX;
			break;
		case 1:
			if (copy_from_user(authflavour, data->auth_flavours,
					   sizeof(*authflavour)))
				return -EFAULT;
			break;
		default:
			goto out_inval_auth;
		}

		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
		if (IS_ERR(c))
			return PTR_ERR(c);
		*hostname = c;

		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
		if (IS_ERR(c))
			return PTR_ERR(c);
		*mntpath = c;
		dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath);

		c = strndup_user(data->client_addr.data, 16);
		if (IS_ERR(c))
			return PTR_ERR(c);
		*ip_addr = c;

		break;
	default:
		goto out_bad_version;
	}

	return 0;

out_no_data:
	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
	return -EINVAL;

out_inval_auth:
	dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
		 data->auth_flavourlen);
	return -EINVAL;

out_no_address:
	dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
	return -EINVAL;

out_bad_version:
	dfprintk(MOUNT, "NFS4: bad nfs_mount_data version %d\n",
		 data->version);
	return -EINVAL;
}

/*
 * Get the superblock for an NFS4 mountpoint
 */
@@ -826,68 +909,14 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
	rpc_authflavor_t authflavour;
	struct nfs_fh mntfh;
	struct dentry *mntroot;
	char *p, *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
	char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
	int error;

	if (data == NULL) {
		dprintk("%s: missing data argument\n", __FUNCTION__);
		return -EINVAL;
	}
	if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
		dprintk("%s: bad mount version\n", __FUNCTION__);
		return -EINVAL;
	}

	/* We now require that the mount process passes the remote address */
	if (data->host_addrlen != sizeof(addr))
		return -EINVAL;

	if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
		return -EFAULT;

	if (!nfs_verify_server_address((struct sockaddr *) &addr)) {
		dprintk("%s: mount program didn't pass remote IP address!\n",
				__FUNCTION__);
		return -EINVAL;
	}

	/* RFC3530: The default port for NFS is 2049 */
	if (addr.sin_port == 0)
		addr.sin_port = htons(NFS_PORT);

	/* Grab the authentication type */
	authflavour = RPC_AUTH_UNIX;
	if (data->auth_flavourlen != 0) {
		if (data->auth_flavourlen != 1) {
			dprintk("%s: Invalid number of RPC auth flavours %d.\n",
					__FUNCTION__, data->auth_flavourlen);
			error = -EINVAL;
			goto out;
		}

		if (copy_from_user(&authflavour, data->auth_flavours,
				   sizeof(authflavour))) {
			error = -EFAULT;
	/* Validate the mount data */
	error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour,
					 &hostname, &mntpath, &ip_addr);
	if (error < 0)
		goto out;
		}
	}

	p = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
	if (IS_ERR(p))
		goto out_err;
	hostname = p;

	p = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
	if (IS_ERR(p))
		goto out_err;
	mntpath = p;

	dprintk("MNTPATH: %s\n", mntpath);

	p = strndup_user(data->client_addr.data, 16);
	if (IS_ERR(p))
		goto out_err;
	ip_addr = p;

	/* Get a volume representation */
	server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
@@ -932,10 +961,6 @@ out:
	kfree(hostname);
	return error;

out_err:
	error = PTR_ERR(p);
	goto out;

out_free:
	nfs_free_server(server);
	goto out;