lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20241209180058.7w2ytnmgg34xnsci@pali>
Date: Mon, 9 Dec 2024 19:00:58 +0100
From: Pali Rohár <pali@...nel.org>
To: Steve French <sfrench@...ba.org>, Paulo Alcantara <pc@...guebit.com>,
	Ronnie Sahlberg <ronniesahlberg@...il.com>
Cc: linux-cifs@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks

On Saturday 12 October 2024 10:56:01 Pali Rohár wrote:
> CIFS client is currently able to parse NFS-style symlinks, but is not able
> to create them. This functionality is useful when the mounted SMB share is
> used also by Windows NFS server (on Windows Server 2012 or new). It allows
> interop of symlinks between SMB share mounted by Linux CIFS client and same
> export from Windows NFS server mounted by some NFS client.
> 
> New symlinks would be created in NFS-style only in case the mount option
> -o reparse=nfs is specified, which is not by default. So default CIFS
> mounts are not affected by this change.
> 
> Signed-off-by: Pali Rohár <pali@...nel.org>
> ---
>  fs/smb/client/reparse.c | 47 ++++++++++++++++++++++++++++++++++-------
>  1 file changed, 39 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> index 57320a4c4d79..cd12704cae0c 100644
> --- a/fs/smb/client/reparse.c
> +++ b/fs/smb/client/reparse.c
> @@ -406,6 +406,8 @@ static int create_native_socket(const unsigned int xid, struct inode *inode,
>  
>  static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
>  			       mode_t mode, dev_t dev,
> +			       __le16 *symname_utf16,
> +			       int symname_utf16_len,
>  			       struct kvec *iov)
>  {
>  	u64 type;
> @@ -416,13 +418,18 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
>  	switch ((type = reparse_mode_nfs_type(mode))) {
>  	case NFS_SPECFILE_BLK:
>  	case NFS_SPECFILE_CHR:
> -		dlen = sizeof(__le64);
> +		dlen = 2 * sizeof(__le32);
> +		((__le32 *)buf->DataBuffer)[0] = MAJOR(dev);
> +		((__le32 *)buf->DataBuffer)[1] = MINOR(dev);
> +		break;
> +	case NFS_SPECFILE_LNK:
> +		dlen = symname_utf16_len;
> +		memcpy(buf->DataBuffer, symname_utf16, symname_utf16_len);
>  		break;
>  	case NFS_SPECFILE_FIFO:
>  	case NFS_SPECFILE_SOCK:
>  		dlen = 0;
>  		break;
> -	case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */
>  	default:
>  		return -EOPNOTSUPP;
>  	}
> @@ -432,8 +439,6 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
>  	buf->InodeType = cpu_to_le64(type);
>  	buf->ReparseDataLength = cpu_to_le16(len + dlen -
>  					     sizeof(struct reparse_data_buffer));
> -	*(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MINOR(dev) << 32) |
> -						 MAJOR(dev));
>  	iov->iov_base = buf;
>  	iov->iov_len = len + dlen;
>  	return 0;
> @@ -444,21 +449,42 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
>  		     const char *full_path, umode_t mode, dev_t dev,
>  		     const char *symname)
>  {
> +	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
>  	struct cifs_open_info_data data;
> -	struct reparse_posix_data *p;
> +	struct reparse_posix_data *p = NULL;
> +	__le16 *symname_utf16 = NULL;
> +	int symname_utf16_len = 0;
>  	struct inode *new;
>  	struct kvec iov;
>  	__u8 buf[sizeof(*p) + sizeof(__le64)];
>  	int rc;
>  
> -	p = (struct reparse_posix_data *)buf;
> -	rc = nfs_set_reparse_buf(p, mode, dev, &iov);
> +	if (S_ISLNK(mode)) {
> +		symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname),
> +						      &symname_utf16_len,
> +						      cifs_sb->local_nls,
> +						      NO_MAP_UNI_RSVD);
> +		if (!symname_utf16) {
> +			rc = -ENOMEM;
> +			goto out;
> +		}
> +		symname_utf16_len -= 2; /* symlink is without trailing wide-nul */
> +		p = kzalloc(sizeof(*p) + symname_utf16_len, GFP_KERNEL);
> +		if (!p) {
> +			rc = -ENOMEM;
> +			goto out;
> +		}
> +	} else {
> +		p = (struct reparse_posix_data *)buf;
> +	}
> +	rc = nfs_set_reparse_buf(p, mode, dev, symname_utf16, symname_utf16_len, &iov);
>  	if (rc)
> -		return rc;
> +		goto out;
>  
>  	data = (struct cifs_open_info_data) {
>  		.reparse_point = true,
>  		.reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, },
> +		.symlink_target = kstrdup(symname, GFP_KERNEL),
>  	};
>  
>  	new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
> @@ -468,6 +494,11 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
>  	else
>  		rc = PTR_ERR(new);
>  	cifs_free_open_info(&data);
> +out:
> +	if (S_ISLNK(mode)) {
> +		kfree(symname_utf16);
> +		kfree(p);
> +	}
>  	return rc;
>  }
>  
> -- 
> 2.20.1
> 

This change also needs fixup for big endian systems:

    fixup! cifs: Add support for creating NFS-style symlinks

diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index af08e5918adb..c2569347d746 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -419,8 +419,8 @@ static int nfs_set_reparse_buf(struct reparse_nfs_data_buffer *buf,
 	case NFS_SPECFILE_BLK:
 	case NFS_SPECFILE_CHR:
 		dlen = 2 * sizeof(__le32);
-		((__le32 *)buf->DataBuffer)[0] = MAJOR(dev);
-		((__le32 *)buf->DataBuffer)[1] = MINOR(dev);
+		((__le32 *)buf->DataBuffer)[0] = cpu_to_le32(MAJOR(dev));
+		((__le32 *)buf->DataBuffer)[1] = cpu_to_le32(MINOR(dev));
 		break;
 	case NFS_SPECFILE_LNK:
 		dlen = symname_utf16_len;

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ