* [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets
@ 2024-10-06 10:00 Pali Rohár
2024-10-06 10:00 ` [PATCH 1/7] cifs: Add mount option -o reparse=native Pali Rohár
` (7 more replies)
0 siblings, 8 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
This patch series improves choosing reparse format when creating new
special files.
In following table is behavior of creating new special files before
this patch series. In columns are mount options, in rows are file types
and in each cell is reparse format which is created.
-o reparse=default -o reparse=nfs -o reparse=wsl
symlink native native native
socket nfs nfs wsl
fifo nfs nfs wsl
block nfs nfs wsl
char nfs nfs wsl
After this patch series the table looks like:
-o reparse=default -o reparse=nfs -o reparse=wsl -o reparse=native+nfs -o reparse=native+wsl -o reparse=native -o reparse=none
symlink native nfs wsl native native native -disallowed-
socket native nfs wsl native native native -disallowed-
fifo nfs nfs wsl nfs wsl -disallowed- -disallowed-
block nfs nfs wsl nfs wsl -disallowed- -disallowed-
char nfs nfs wsl nfs wsl -disallowed- -disallowed-
The default behavior when no option is specified (which is same as
-o reparse=default) changes only for creating new sockets which are
now created in its native NTFS form with IO_REPARSE_TAG_AF_UNIX reparse
tag.
The nfs and wsl behavior is changed to always create new special files
in its own formats.
There are new options native+nfs and native+wsl which creates by default
in native form (symlinks + sockets) and fallbacks to nfs/wsl for other
types (fifo, char, block). This is probably the most useful for
interoperability. Mount option -o reparse=default is now same as
-o reparse=native+nfs
For completeness there are also new options -o reparse=native which
allows to creating only native types used by Windows applications
(symlinks and sockets) and option -o reparse=none to completely disable
creating new reparse points.
Pali Rohár (7):
cifs: Add mount option -o reparse=native
cifs: Add mount option -o reparse=none
cifs: Add support for creating native Windows sockets
cifs: Add support for creating NFS-style symlinks
cifs: Improve guard for excluding $LXDEV xattr
cifs: Add support for creating WSL-style symlinks
cifs: Validate content of WSL reparse point buffers
fs/smb/client/cifsglob.h | 18 +++-
fs/smb/client/fs_context.c | 16 +++
fs/smb/client/fs_context.h | 4 +
fs/smb/client/reparse.c | 211 +++++++++++++++++++++++++++++++------
fs/smb/client/reparse.h | 2 +
5 files changed, 218 insertions(+), 33 deletions(-)
--
2.20.1
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 1/7] cifs: Add mount option -o reparse=native
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-07 4:28 ` Steve French
2024-10-06 10:00 ` [PATCH 2/7] cifs: Add mount option -o reparse=none Pali Rohár
` (6 subsequent siblings)
7 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
Currently the default option is -o reparse=default which is same as
-o reparse=nfs. Currently mount option -o reparse=nfs does not create
symlink in NFS reparse point style, which is misleading.
Add new -o reparse= options "native", "native+nfs" and "native+wsl" to make
it more clear and allow to choose the expected reparse point types.
"native" would mean to create new special files only with reparse point
tags which are natively supported by SMB or Windows. Types which are not
natively supported cannot be created.
"native+nfs" would mean same as native, but fallback to "nfs" for
unsupported types.
"native+wsl" would mean to fallback to "wsl".
Change also meaning of "nfs" and "wsl" to always create special types with
nfs / wsl style.
And change also the default option to "native+nfs", so the default behavior
stay same as without this change. Without this change were all symlinks
created in native Windows/SMB form and this stay same with this change too.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/cifsglob.h | 15 ++++++++--
fs/smb/client/fs_context.c | 12 ++++++++
fs/smb/client/fs_context.h | 3 ++
fs/smb/client/reparse.c | 58 +++++++++++++++++++++++++++++++-------
fs/smb/client/reparse.h | 2 ++
5 files changed, 77 insertions(+), 13 deletions(-)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 260b553283ef..367f0ac6400d 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -154,14 +154,23 @@ enum securityEnum {
};
enum cifs_reparse_type {
- CIFS_REPARSE_TYPE_NFS,
- CIFS_REPARSE_TYPE_WSL,
- CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS,
+ CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */
+ CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */
+ CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */
+ CIFS_REPARSE_TYPE_NFS, /* nfs for everything */
+ CIFS_REPARSE_TYPE_WSL, /* wsl for everything */
+ CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS,
};
static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type)
{
switch (type) {
+ case CIFS_REPARSE_TYPE_NATIVE:
+ return "native";
+ case CIFS_REPARSE_TYPE_NATIVE_NFS:
+ return "native+nfs";
+ case CIFS_REPARSE_TYPE_NATIVE_WSL:
+ return "native+wsl";
case CIFS_REPARSE_TYPE_NFS:
return "nfs";
case CIFS_REPARSE_TYPE_WSL:
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 22b550860cc8..e5de84912e3d 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -303,6 +303,9 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte
static const match_table_t reparse_flavor_tokens = {
{ Opt_reparse_default, "default" },
+ { Opt_reparse_native, "native" },
+ { Opt_reparse_native_nfs, "native+nfs" },
+ { Opt_reparse_native_wsl, "native+wsl" },
{ Opt_reparse_nfs, "nfs" },
{ Opt_reparse_wsl, "wsl" },
{ Opt_reparse_err, NULL },
@@ -317,6 +320,15 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value,
case Opt_reparse_default:
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
break;
+ case Opt_reparse_native:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE;
+ break;
+ case Opt_reparse_native_nfs:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_NFS;
+ break;
+ case Opt_reparse_native_wsl:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_WSL;
+ break;
case Opt_reparse_nfs:
ctx->reparse_type = CIFS_REPARSE_TYPE_NFS;
break;
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 8dd12498ffd8..1011176ba3b7 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -43,6 +43,9 @@ enum {
enum cifs_reparse_parm {
Opt_reparse_default,
+ Opt_reparse_native,
+ Opt_reparse_native_nfs,
+ Opt_reparse_native_wsl,
Opt_reparse_nfs,
Opt_reparse_wsl,
Opt_reparse_err
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 6e9d914bac41..38fe0a710c65 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -14,6 +14,20 @@
#include "fs_context.h"
#include "reparse.h"
+static int mknod_nfs(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname);
+
+static int mknod_wsl(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname);
+
+static int create_native_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname);
+
static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
const unsigned int xid,
const char *full_path,
@@ -23,6 +37,26 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, const char *symname)
+{
+ struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
+
+ switch (ctx->reparse_type) {
+ case CIFS_REPARSE_TYPE_NATIVE:
+ case CIFS_REPARSE_TYPE_NATIVE_NFS:
+ case CIFS_REPARSE_TYPE_NATIVE_WSL:
+ return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
+ case CIFS_REPARSE_TYPE_NFS:
+ return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
+ case CIFS_REPARSE_TYPE_WSL:
+ return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int create_native_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname)
{
struct reparse_symlink_data_buffer *buf = NULL;
struct cifs_open_info_data data = {};
@@ -363,6 +397,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
case NFS_SPECFILE_SOCK:
dlen = 0;
break;
+ case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */
default:
return -EOPNOTSUPP;
}
@@ -381,7 +416,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
static int mknod_nfs(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname)
{
struct cifs_open_info_data data;
struct reparse_posix_data *p;
@@ -421,6 +457,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_AF_UNIX:
break;
+ case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
default:
return -EOPNOTSUPP;
}
@@ -518,7 +555,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
static int mknod_wsl(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname)
{
struct cifs_open_info_data data;
struct reparse_data_buffer buf;
@@ -563,17 +601,17 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
const char *full_path, umode_t mode, dev_t dev)
{
struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
- int rc = -EOPNOTSUPP;
switch (ctx->reparse_type) {
+ case CIFS_REPARSE_TYPE_NATIVE_NFS:
case CIFS_REPARSE_TYPE_NFS:
- rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
- break;
+ return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
+ case CIFS_REPARSE_TYPE_NATIVE_WSL:
case CIFS_REPARSE_TYPE_WSL:
- rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
- break;
+ return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
+ default:
+ return -EOPNOTSUPP;
}
- return rc;
}
/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
@@ -848,7 +886,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
return rc;
}
-static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
+static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
u32 plen, bool unicode,
struct cifs_sb_info *cifs_sb,
const char *full_path,
@@ -936,7 +974,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
return parse_reparse_posix((struct reparse_posix_data *)buf,
cifs_sb, data);
case IO_REPARSE_TAG_SYMLINK:
- return parse_reparse_symlink(
+ return parse_reparse_native_symlink(
(struct reparse_symlink_data_buffer *)buf,
plen, unicode, cifs_sb, full_path, data);
case IO_REPARSE_TAG_LX_SYMLINK:
diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
index eb6854e65e08..a6bdf20ce1b0 100644
--- a/fs/smb/client/reparse.h
+++ b/fs/smb/client/reparse.h
@@ -61,6 +61,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
static inline u64 reparse_mode_nfs_type(mode_t mode)
{
switch (mode & S_IFMT) {
+ case S_IFLNK: return NFS_SPECFILE_LNK;
case S_IFBLK: return NFS_SPECFILE_BLK;
case S_IFCHR: return NFS_SPECFILE_CHR;
case S_IFIFO: return NFS_SPECFILE_FIFO;
@@ -72,6 +73,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode)
static inline u32 reparse_mode_wsl_tag(mode_t mode)
{
switch (mode & S_IFMT) {
+ case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK;
case S_IFBLK: return IO_REPARSE_TAG_LX_BLK;
case S_IFCHR: return IO_REPARSE_TAG_LX_CHR;
case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 2/7] cifs: Add mount option -o reparse=none
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
2024-10-06 10:00 ` [PATCH 1/7] cifs: Add mount option -o reparse=native Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
` (5 subsequent siblings)
7 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
This new mount option allows to completely disable creating new reparse
points. When -o sfu or -o mfsymlinks is not specified then creating any
special file (fifo, socket, symlink, block and char) will fail with
-EOPNOTSUPP error.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/cifsglob.h | 3 +++
fs/smb/client/fs_context.c | 4 ++++
fs/smb/client/fs_context.h | 1 +
3 files changed, 8 insertions(+)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 367f0ac6400d..7632d2ba5390 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -154,6 +154,7 @@ enum securityEnum {
};
enum cifs_reparse_type {
+ CIFS_REPARSE_TYPE_NONE, /* disable creating new reparse points */
CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */
CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */
CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */
@@ -165,6 +166,8 @@ enum cifs_reparse_type {
static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type)
{
switch (type) {
+ case CIFS_REPARSE_TYPE_NONE:
+ return "none";
case CIFS_REPARSE_TYPE_NATIVE:
return "native";
case CIFS_REPARSE_TYPE_NATIVE_NFS:
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index e5de84912e3d..3e402961cc95 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -303,6 +303,7 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte
static const match_table_t reparse_flavor_tokens = {
{ Opt_reparse_default, "default" },
+ { Opt_reparse_none, "none" },
{ Opt_reparse_native, "native" },
{ Opt_reparse_native_nfs, "native+nfs" },
{ Opt_reparse_native_wsl, "native+wsl" },
@@ -320,6 +321,9 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value,
case Opt_reparse_default:
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
break;
+ case Opt_reparse_none:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_NONE;
+ break;
case Opt_reparse_native:
ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE;
break;
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 1011176ba3b7..5db06de2ed35 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -43,6 +43,7 @@ enum {
enum cifs_reparse_parm {
Opt_reparse_default,
+ Opt_reparse_none,
Opt_reparse_native,
Opt_reparse_native_nfs,
Opt_reparse_native_wsl,
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 3/7] cifs: Add support for creating native Windows sockets
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
2024-10-06 10:00 ` [PATCH 1/7] cifs: Add mount option -o reparse=native Pali Rohár
2024-10-06 10:00 ` [PATCH 2/7] cifs: Add mount option -o reparse=none Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-10 21:47 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
` (4 subsequent siblings)
7 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
Native Windows sockets created by WinSock on Windows 10 April 2018 Update
(version 1803) or Windows Server 2019 (version 1809) or later versions is
reparse point with IO_REPARSE_TAG_AF_UNIX tag, with empty reparse point
data buffer and without any EAs.
Create AF_UNIX sockets in this native format when -o reparse=native or
-o reparse=native+<something> mount option is used.
This change makes AF_UNIX sockets created by Linux CIFS client compatible
with AF_UNIX sockets created by Windows applications on NTFS volumes.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/cifsglob.h | 6 +++---
fs/smb/client/reparse.c | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 7632d2ba5390..570b22d02f7e 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -155,9 +155,9 @@ enum securityEnum {
enum cifs_reparse_type {
CIFS_REPARSE_TYPE_NONE, /* disable creating new reparse points */
- CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */
- CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */
- CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */
+ CIFS_REPARSE_TYPE_NATIVE, /* native symlinks and sockets only, no support for others */
+ CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks/sockets, nfs for fifos/block/char */
+ CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks/sockets, wsl for fifos/block/char */
CIFS_REPARSE_TYPE_NFS, /* nfs for everything */
CIFS_REPARSE_TYPE_WSL, /* wsl for everything */
CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS,
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 38fe0a710c65..f1488f870320 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -379,6 +379,35 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
return 0;
}
+static int create_native_socket(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path)
+{
+ struct cifs_open_info_data data = {
+ .reparse_point = true,
+ .reparse = { .tag = IO_REPARSE_TAG_AF_UNIX, },
+ };
+ struct reparse_data_buffer buf = {
+ .ReparseTag = cpu_to_le32(IO_REPARSE_TAG_AF_UNIX),
+ .ReparseDataLength = 0,
+ };
+ struct kvec iov = {
+ .iov_base = &buf,
+ .iov_len = sizeof(buf),
+ };
+ struct inode *new;
+ int rc;
+
+ new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
+ tcon, full_path, false, &iov, NULL);
+ if (!IS_ERR(new))
+ d_instantiate(dentry, new);
+ else
+ rc = PTR_ERR(new);
+ cifs_free_open_info(&data);
+ return rc;
+}
+
static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
mode_t mode, dev_t dev,
struct kvec *iov)
@@ -602,6 +631,13 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
{
struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
+ if (S_ISSOCK(mode) && (
+ ctx->reparse_type == CIFS_REPARSE_TYPE_NATIVE ||
+ ctx->reparse_type == CIFS_REPARSE_TYPE_NATIVE_NFS ||
+ ctx->reparse_type == CIFS_REPARSE_TYPE_NATIVE_WSL)) {
+ return create_native_socket(xid, inode, dentry, tcon, full_path);
+ }
+
switch (ctx->reparse_type) {
case CIFS_REPARSE_TYPE_NATIVE_NFS:
case CIFS_REPARSE_TYPE_NFS:
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 4/7] cifs: Add support for creating NFS-style symlinks
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
` (2 preceding siblings ...)
2024-10-06 10:00 ` [PATCH 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 5/7] cifs: Improve guard for excluding $LXDEV xattr Pali Rohár
` (3 subsequent siblings)
7 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
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@kernel.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 f1488f870320..41f91613e7f2 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -410,6 +410,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;
@@ -420,13 +422,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;
}
@@ -436,8 +443,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;
@@ -448,21 +453,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,
@@ -472,6 +498,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
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 5/7] cifs: Improve guard for excluding $LXDEV xattr
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
` (3 preceding siblings ...)
2024-10-06 10:00 ` [PATCH 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
` (2 subsequent siblings)
7 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
$LXDEV xattr is for storing block/char device's major and minor number.
Change guard which excludes storing $LXDEV xattr to explicitly filter
everything except block and char device. Current guard is opposite, which
is currently correct but is less-safe. This change is required for adding
support for creating WSL-style symlinks as symlinks also do not use
device's major and minor numbers.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/reparse.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 41f91613e7f2..402eb568f466 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -578,8 +578,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
memset(iov, 0, sizeof(*iov));
- /* Exclude $LXDEV xattr for sockets and fifos */
- if (S_ISSOCK(_mode) || S_ISFIFO(_mode))
+ /* Exclude $LXDEV xattr for non-device files */
+ if (!S_ISBLK(_mode) && !S_ISCHR(_mode))
num_xattrs = ARRAY_SIZE(xattrs) - 1;
else
num_xattrs = ARRAY_SIZE(xattrs);
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 6/7] cifs: Add support for creating WSL-style symlinks
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
` (4 preceding siblings ...)
2024-10-06 10:00 ` [PATCH 5/7] cifs: Improve guard for excluding $LXDEV xattr Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-10 21:50 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 7/7] cifs: Validate content of WSL reparse point buffers Pali Rohár
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
7 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
This change implements support for creating new symlink in WSL-style by
Linux cifs client when -o reparse=wsl mount option is specified. WSL-style
symlink uses reparse point with tag IO_REPARSE_TAG_LX_SYMLINK and symlink
target location is stored in reparse buffer in UTF-8 encoding prefixed by
32-bit flags. Flags bits are unknown, but it was observed that WSL always
sets flags to value 0x02000000. Do same in Linux cifs client.
New symlinks would be created in WSL-style only in case the mount option
-o reparse=wsl is specified, which is not by default. So default CIFS
mounts are not affected by this change.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/reparse.c | 65 +++++++++++++++++++++++++++++++++--------
1 file changed, 53 insertions(+), 12 deletions(-)
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 402eb568f466..6606c40487ae 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -506,9 +506,17 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
return rc;
}
-static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
- mode_t mode, struct kvec *iov)
+static int wsl_set_reparse_buf(struct reparse_data_buffer **buf,
+ mode_t mode, const char *symname,
+ struct cifs_sb_info *cifs_sb,
+ struct kvec *iov)
{
+ struct reparse_wsl_symlink_data_buffer *symlink_buf;
+ __le16 *symname_utf16;
+ int symname_utf16_len;
+ int symname_utf8_maxlen;
+ int symname_utf8_len;
+ size_t buf_len;
u32 tag;
switch ((tag = reparse_mode_wsl_tag(mode))) {
@@ -516,17 +524,45 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_CHR:
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_AF_UNIX:
+ buf_len = sizeof(struct reparse_data_buffer);
+ *buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ break;
+ case IO_REPARSE_TAG_LX_SYMLINK:
+ symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname),
+ &symname_utf16_len,
+ cifs_sb->local_nls,
+ NO_MAP_UNI_RSVD);
+ if (!symname_utf16)
+ return -ENOMEM;
+ symname_utf8_maxlen = symname_utf16_len/2*3;
+ symlink_buf = kzalloc(sizeof(struct reparse_wsl_symlink_data_buffer) +
+ symname_utf8_maxlen, GFP_KERNEL);
+ if (!symlink_buf) {
+ kfree(symname_utf16);
+ return -ENOMEM;
+ }
+ /* Flag 0x02000000 is unknown, but all wsl symlinks have this value */
+ symlink_buf->Flags = cpu_to_le32(0x02000000);
+ /* PathBuffer is in UTF-8 but without trailing null-term byte */
+ symname_utf8_len = utf16s_to_utf8s(symname_utf16, symname_utf16_len/2,
+ UTF16_LITTLE_ENDIAN,
+ symlink_buf->PathBuffer,
+ symname_utf8_maxlen);
+ *buf = (struct reparse_data_buffer *)symlink_buf;
+ buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len;
+ kfree(symname_utf16);
break;
- case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
default:
return -EOPNOTSUPP;
}
- buf->ReparseTag = cpu_to_le32(tag);
- buf->Reserved = 0;
- buf->ReparseDataLength = 0;
- iov->iov_base = buf;
- iov->iov_len = sizeof(*buf);
+ (*buf)->ReparseTag = cpu_to_le32(tag);
+ (*buf)->Reserved = 0;
+ (*buf)->ReparseDataLength = buf_len - sizeof(struct reparse_data_buffer);
+ iov->iov_base = *buf;
+ iov->iov_len = buf_len;
return 0;
}
@@ -618,25 +654,29 @@ static int mknod_wsl(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_data_buffer buf;
+ struct reparse_data_buffer *buf;
struct smb2_create_ea_ctx *cc;
struct inode *new;
unsigned int len;
struct kvec reparse_iov, xattr_iov;
int rc;
- rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov);
+ rc = wsl_set_reparse_buf(&buf, mode, symname, cifs_sb, &reparse_iov);
if (rc)
return rc;
rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov);
- if (rc)
+ if (rc) {
+ kfree(buf);
return rc;
+ }
data = (struct cifs_open_info_data) {
.reparse_point = true,
- .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
+ .reparse = { .tag = le32_to_cpu(buf->ReparseTag), .buf = buf, },
+ .symlink_target = kstrdup(symname, GFP_KERNEL),
};
cc = xattr_iov.iov_base;
@@ -653,6 +693,7 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
rc = PTR_ERR(new);
cifs_free_open_info(&data);
kfree(xattr_iov.iov_base);
+ kfree(buf);
return rc;
}
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 7/7] cifs: Validate content of WSL reparse point buffers
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
` (5 preceding siblings ...)
2024-10-06 10:00 ` [PATCH 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
@ 2024-10-06 10:00 ` Pali Rohár
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
7 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-06 10:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
WSL socket, fifo, char and block devices have empty reparse buffer.
Validate the length of the reparse buffer.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/reparse.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 6606c40487ae..c0d9ba14a60d 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -1093,6 +1093,11 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_LX_CHR:
case IO_REPARSE_TAG_LX_BLK:
+ if (le16_to_cpu(buf->ReparseDataLength) != 0) {
+ cifs_dbg(VFS, "srv returned malformed buffer for reparse point: 0x%08x\n",
+ le32_to_cpu(buf->ReparseTag));
+ return -EIO;
+ }
break;
default:
cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] cifs: Add mount option -o reparse=native
2024-10-06 10:00 ` [PATCH 1/7] cifs: Add mount option -o reparse=native Pali Rohár
@ 2024-10-07 4:28 ` Steve French
2024-10-07 18:36 ` Pali Rohár
0 siblings, 1 reply; 29+ messages in thread
From: Steve French @ 2024-10-07 4:28 UTC (permalink / raw)
To: Pali Rohár
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
This is a good point about how to override the "native" symlink format
when using reparse=nfs (a similar question could come up, if for
security reasons you use "mfsymlinks" for symlinks - ie "client side
symlinks" (which are safer) - but use reparse=nfs for everything else.
But ... there is probably a better way to handle the mount option
for default symlink creation format more clearly (perhaps use of
"nativesymlinks" (default) or "mfsymlinks" if specified, overrides
"reparse=wsl" or "reparse=nfs" for symlink format only. User can
specify "nativesymlinks=no" if they want to use the "reparse=" format
for symlinks. For the sfu case it might be trickier but could fall
back to sfu symlinks if "nativesymlinks=no" or if they fail?!
Thoughts?
On Sun, Oct 6, 2024 at 5:01 AM Pali Rohár <pali@kernel.org> wrote:
>
> Currently the default option is -o reparse=default which is same as
> -o reparse=nfs. Currently mount option -o reparse=nfs does not create
> symlink in NFS reparse point style, which is misleading.
>
> Add new -o reparse= options "native", "native+nfs" and "native+wsl" to make
> it more clear and allow to choose the expected reparse point types.
>
> "native" would mean to create new special files only with reparse point
> tags which are natively supported by SMB or Windows. Types which are not
> natively supported cannot be created.
>
> "native+nfs" would mean same as native, but fallback to "nfs" for
> unsupported types.
>
> "native+wsl" would mean to fallback to "wsl".
>
> Change also meaning of "nfs" and "wsl" to always create special types with
> nfs / wsl style.
>
> And change also the default option to "native+nfs", so the default behavior
> stay same as without this change. Without this change were all symlinks
> created in native Windows/SMB form and this stay same with this change too.
>
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
> fs/smb/client/cifsglob.h | 15 ++++++++--
> fs/smb/client/fs_context.c | 12 ++++++++
> fs/smb/client/fs_context.h | 3 ++
> fs/smb/client/reparse.c | 58 +++++++++++++++++++++++++++++++-------
> fs/smb/client/reparse.h | 2 ++
> 5 files changed, 77 insertions(+), 13 deletions(-)
>
> diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
> index 260b553283ef..367f0ac6400d 100644
> --- a/fs/smb/client/cifsglob.h
> +++ b/fs/smb/client/cifsglob.h
> @@ -154,14 +154,23 @@ enum securityEnum {
> };
>
> enum cifs_reparse_type {
> - CIFS_REPARSE_TYPE_NFS,
> - CIFS_REPARSE_TYPE_WSL,
> - CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS,
> + CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */
> + CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */
> + CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */
> + CIFS_REPARSE_TYPE_NFS, /* nfs for everything */
> + CIFS_REPARSE_TYPE_WSL, /* wsl for everything */
> + CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS,
> };
>
> static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type)
> {
> switch (type) {
> + case CIFS_REPARSE_TYPE_NATIVE:
> + return "native";
> + case CIFS_REPARSE_TYPE_NATIVE_NFS:
> + return "native+nfs";
> + case CIFS_REPARSE_TYPE_NATIVE_WSL:
> + return "native+wsl";
> case CIFS_REPARSE_TYPE_NFS:
> return "nfs";
> case CIFS_REPARSE_TYPE_WSL:
> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
> index 22b550860cc8..e5de84912e3d 100644
> --- a/fs/smb/client/fs_context.c
> +++ b/fs/smb/client/fs_context.c
> @@ -303,6 +303,9 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte
>
> static const match_table_t reparse_flavor_tokens = {
> { Opt_reparse_default, "default" },
> + { Opt_reparse_native, "native" },
> + { Opt_reparse_native_nfs, "native+nfs" },
> + { Opt_reparse_native_wsl, "native+wsl" },
> { Opt_reparse_nfs, "nfs" },
> { Opt_reparse_wsl, "wsl" },
> { Opt_reparse_err, NULL },
> @@ -317,6 +320,15 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value,
> case Opt_reparse_default:
> ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
> break;
> + case Opt_reparse_native:
> + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE;
> + break;
> + case Opt_reparse_native_nfs:
> + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_NFS;
> + break;
> + case Opt_reparse_native_wsl:
> + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_WSL;
> + break;
> case Opt_reparse_nfs:
> ctx->reparse_type = CIFS_REPARSE_TYPE_NFS;
> break;
> diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
> index 8dd12498ffd8..1011176ba3b7 100644
> --- a/fs/smb/client/fs_context.h
> +++ b/fs/smb/client/fs_context.h
> @@ -43,6 +43,9 @@ enum {
>
> enum cifs_reparse_parm {
> Opt_reparse_default,
> + Opt_reparse_native,
> + Opt_reparse_native_nfs,
> + Opt_reparse_native_wsl,
> Opt_reparse_nfs,
> Opt_reparse_wsl,
> Opt_reparse_err
> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> index 6e9d914bac41..38fe0a710c65 100644
> --- a/fs/smb/client/reparse.c
> +++ b/fs/smb/client/reparse.c
> @@ -14,6 +14,20 @@
> #include "fs_context.h"
> #include "reparse.h"
>
> +static int mknod_nfs(unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path, umode_t mode, dev_t dev,
> + const char *symname);
> +
> +static int mknod_wsl(unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path, umode_t mode, dev_t dev,
> + const char *symname);
> +
> +static int create_native_symlink(const unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path, const char *symname);
> +
> static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
> const unsigned int xid,
> const char *full_path,
> @@ -23,6 +37,26 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
> int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
> struct dentry *dentry, struct cifs_tcon *tcon,
> const char *full_path, const char *symname)
> +{
> + struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
> +
> + switch (ctx->reparse_type) {
> + case CIFS_REPARSE_TYPE_NATIVE:
> + case CIFS_REPARSE_TYPE_NATIVE_NFS:
> + case CIFS_REPARSE_TYPE_NATIVE_WSL:
> + return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
> + case CIFS_REPARSE_TYPE_NFS:
> + return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
> + case CIFS_REPARSE_TYPE_WSL:
> + return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
> + default:
> + return -EOPNOTSUPP;
> + }
> +}
> +
> +static int create_native_symlink(const unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path, const char *symname)
> {
> struct reparse_symlink_data_buffer *buf = NULL;
> struct cifs_open_info_data data = {};
> @@ -363,6 +397,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
> case NFS_SPECFILE_SOCK:
> dlen = 0;
> break;
> + case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */
> default:
> return -EOPNOTSUPP;
> }
> @@ -381,7 +416,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
>
> static int mknod_nfs(unsigned int xid, struct inode *inode,
> struct dentry *dentry, struct cifs_tcon *tcon,
> - const char *full_path, umode_t mode, dev_t dev)
> + const char *full_path, umode_t mode, dev_t dev,
> + const char *symname)
> {
> struct cifs_open_info_data data;
> struct reparse_posix_data *p;
> @@ -421,6 +457,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
> case IO_REPARSE_TAG_LX_FIFO:
> case IO_REPARSE_TAG_AF_UNIX:
> break;
> + case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
> default:
> return -EOPNOTSUPP;
> }
> @@ -518,7 +555,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
>
> static int mknod_wsl(unsigned int xid, struct inode *inode,
> struct dentry *dentry, struct cifs_tcon *tcon,
> - const char *full_path, umode_t mode, dev_t dev)
> + const char *full_path, umode_t mode, dev_t dev,
> + const char *symname)
> {
> struct cifs_open_info_data data;
> struct reparse_data_buffer buf;
> @@ -563,17 +601,17 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
> const char *full_path, umode_t mode, dev_t dev)
> {
> struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
> - int rc = -EOPNOTSUPP;
>
> switch (ctx->reparse_type) {
> + case CIFS_REPARSE_TYPE_NATIVE_NFS:
> case CIFS_REPARSE_TYPE_NFS:
> - rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
> - break;
> + return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
> + case CIFS_REPARSE_TYPE_NATIVE_WSL:
> case CIFS_REPARSE_TYPE_WSL:
> - rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
> - break;
> + return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
> + default:
> + return -EOPNOTSUPP;
> }
> - return rc;
> }
>
> /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
> @@ -848,7 +886,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> return rc;
> }
>
> -static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
> +static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
> u32 plen, bool unicode,
> struct cifs_sb_info *cifs_sb,
> const char *full_path,
> @@ -936,7 +974,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
> return parse_reparse_posix((struct reparse_posix_data *)buf,
> cifs_sb, data);
> case IO_REPARSE_TAG_SYMLINK:
> - return parse_reparse_symlink(
> + return parse_reparse_native_symlink(
> (struct reparse_symlink_data_buffer *)buf,
> plen, unicode, cifs_sb, full_path, data);
> case IO_REPARSE_TAG_LX_SYMLINK:
> diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
> index eb6854e65e08..a6bdf20ce1b0 100644
> --- a/fs/smb/client/reparse.h
> +++ b/fs/smb/client/reparse.h
> @@ -61,6 +61,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
> static inline u64 reparse_mode_nfs_type(mode_t mode)
> {
> switch (mode & S_IFMT) {
> + case S_IFLNK: return NFS_SPECFILE_LNK;
> case S_IFBLK: return NFS_SPECFILE_BLK;
> case S_IFCHR: return NFS_SPECFILE_CHR;
> case S_IFIFO: return NFS_SPECFILE_FIFO;
> @@ -72,6 +73,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode)
> static inline u32 reparse_mode_wsl_tag(mode_t mode)
> {
> switch (mode & S_IFMT) {
> + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK;
> case S_IFBLK: return IO_REPARSE_TAG_LX_BLK;
> case S_IFCHR: return IO_REPARSE_TAG_LX_CHR;
> case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
> --
> 2.20.1
>
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] cifs: Add mount option -o reparse=native
2024-10-07 4:28 ` Steve French
@ 2024-10-07 18:36 ` Pali Rohár
[not found] ` <CAH2r5mttO-aDq94QrLQm10xJRGLg=PULqX9fcfoykAweVVO+uQ@mail.gmail.com>
0 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-07 18:36 UTC (permalink / raw)
To: Steve French
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
Currently choosing how new symlinks are created is quite complicated.
Without these patch series, by default new symlinks are created via
native reparse points, even when reparse=nfs or reparse=wsl is
specified. There is no possibility to create a NFS-style or WSL-style
symlink yet, and this patch series address this missing functionality.
When option -o sfu is specified then all new symlinks are created in
SFU-style, independently of -o reparse option. And when -o mfsymlinks is
specified then all new symlinks are created in mf style, independently
of -o reparse and -o sfu options.
This patch series does not change -o sfu and -o mfsymlinks overrides, it
just changes the way how -o reparse is handled.
I think that we have too many mount options which specify ability to
choose symlink format and complicated overrides, which option has higher
priority than other.
What about rather introducing a new option like:
-o symlinkformat=native|nfs|wsl|sfu|mf|unix|none
which explicitly say which format will be chosen when creating a new
symlink?
IIRC in SMB we can create a new symlink via:
- ioctl with native symlink reparse point
- ioctl with nfs reparse point
- ioctl with wsl symlink reparse point
- create sfu system file
- create mf file
- SMB1 unix create symlink command
(have I forgot for something?)
On Sunday 06 October 2024 23:28:29 Steve French wrote:
> This is a good point about how to override the "native" symlink format
> when using reparse=nfs (a similar question could come up, if for
> security reasons you use "mfsymlinks" for symlinks - ie "client side
> symlinks" (which are safer) - but use reparse=nfs for everything else.
> But ... there is probably a better way to handle the mount option
> for default symlink creation format more clearly (perhaps use of
> "nativesymlinks" (default) or "mfsymlinks" if specified, overrides
> "reparse=wsl" or "reparse=nfs" for symlink format only. User can
> specify "nativesymlinks=no" if they want to use the "reparse=" format
> for symlinks. For the sfu case it might be trickier but could fall
> back to sfu symlinks if "nativesymlinks=no" or if they fail?!
> Thoughts?
>
> On Sun, Oct 6, 2024 at 5:01 AM Pali Rohár <pali@kernel.org> wrote:
> >
> > Currently the default option is -o reparse=default which is same as
> > -o reparse=nfs. Currently mount option -o reparse=nfs does not create
> > symlink in NFS reparse point style, which is misleading.
> >
> > Add new -o reparse= options "native", "native+nfs" and "native+wsl" to make
> > it more clear and allow to choose the expected reparse point types.
> >
> > "native" would mean to create new special files only with reparse point
> > tags which are natively supported by SMB or Windows. Types which are not
> > natively supported cannot be created.
> >
> > "native+nfs" would mean same as native, but fallback to "nfs" for
> > unsupported types.
> >
> > "native+wsl" would mean to fallback to "wsl".
> >
> > Change also meaning of "nfs" and "wsl" to always create special types with
> > nfs / wsl style.
> >
> > And change also the default option to "native+nfs", so the default behavior
> > stay same as without this change. Without this change were all symlinks
> > created in native Windows/SMB form and this stay same with this change too.
> >
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > ---
> > fs/smb/client/cifsglob.h | 15 ++++++++--
> > fs/smb/client/fs_context.c | 12 ++++++++
> > fs/smb/client/fs_context.h | 3 ++
> > fs/smb/client/reparse.c | 58 +++++++++++++++++++++++++++++++-------
> > fs/smb/client/reparse.h | 2 ++
> > 5 files changed, 77 insertions(+), 13 deletions(-)
> >
> > diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
> > index 260b553283ef..367f0ac6400d 100644
> > --- a/fs/smb/client/cifsglob.h
> > +++ b/fs/smb/client/cifsglob.h
> > @@ -154,14 +154,23 @@ enum securityEnum {
> > };
> >
> > enum cifs_reparse_type {
> > - CIFS_REPARSE_TYPE_NFS,
> > - CIFS_REPARSE_TYPE_WSL,
> > - CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS,
> > + CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */
> > + CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */
> > + CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */
> > + CIFS_REPARSE_TYPE_NFS, /* nfs for everything */
> > + CIFS_REPARSE_TYPE_WSL, /* wsl for everything */
> > + CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS,
> > };
> >
> > static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type)
> > {
> > switch (type) {
> > + case CIFS_REPARSE_TYPE_NATIVE:
> > + return "native";
> > + case CIFS_REPARSE_TYPE_NATIVE_NFS:
> > + return "native+nfs";
> > + case CIFS_REPARSE_TYPE_NATIVE_WSL:
> > + return "native+wsl";
> > case CIFS_REPARSE_TYPE_NFS:
> > return "nfs";
> > case CIFS_REPARSE_TYPE_WSL:
> > diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
> > index 22b550860cc8..e5de84912e3d 100644
> > --- a/fs/smb/client/fs_context.c
> > +++ b/fs/smb/client/fs_context.c
> > @@ -303,6 +303,9 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte
> >
> > static const match_table_t reparse_flavor_tokens = {
> > { Opt_reparse_default, "default" },
> > + { Opt_reparse_native, "native" },
> > + { Opt_reparse_native_nfs, "native+nfs" },
> > + { Opt_reparse_native_wsl, "native+wsl" },
> > { Opt_reparse_nfs, "nfs" },
> > { Opt_reparse_wsl, "wsl" },
> > { Opt_reparse_err, NULL },
> > @@ -317,6 +320,15 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value,
> > case Opt_reparse_default:
> > ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
> > break;
> > + case Opt_reparse_native:
> > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE;
> > + break;
> > + case Opt_reparse_native_nfs:
> > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_NFS;
> > + break;
> > + case Opt_reparse_native_wsl:
> > + ctx->reparse_type = CIFS_REPARSE_TYPE_NATIVE_WSL;
> > + break;
> > case Opt_reparse_nfs:
> > ctx->reparse_type = CIFS_REPARSE_TYPE_NFS;
> > break;
> > diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
> > index 8dd12498ffd8..1011176ba3b7 100644
> > --- a/fs/smb/client/fs_context.h
> > +++ b/fs/smb/client/fs_context.h
> > @@ -43,6 +43,9 @@ enum {
> >
> > enum cifs_reparse_parm {
> > Opt_reparse_default,
> > + Opt_reparse_native,
> > + Opt_reparse_native_nfs,
> > + Opt_reparse_native_wsl,
> > Opt_reparse_nfs,
> > Opt_reparse_wsl,
> > Opt_reparse_err
> > diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> > index 6e9d914bac41..38fe0a710c65 100644
> > --- a/fs/smb/client/reparse.c
> > +++ b/fs/smb/client/reparse.c
> > @@ -14,6 +14,20 @@
> > #include "fs_context.h"
> > #include "reparse.h"
> >
> > +static int mknod_nfs(unsigned int xid, struct inode *inode,
> > + struct dentry *dentry, struct cifs_tcon *tcon,
> > + const char *full_path, umode_t mode, dev_t dev,
> > + const char *symname);
> > +
> > +static int mknod_wsl(unsigned int xid, struct inode *inode,
> > + struct dentry *dentry, struct cifs_tcon *tcon,
> > + const char *full_path, umode_t mode, dev_t dev,
> > + const char *symname);
> > +
> > +static int create_native_symlink(const unsigned int xid, struct inode *inode,
> > + struct dentry *dentry, struct cifs_tcon *tcon,
> > + const char *full_path, const char *symname);
> > +
> > static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
> > const unsigned int xid,
> > const char *full_path,
> > @@ -23,6 +37,26 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
> > int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
> > struct dentry *dentry, struct cifs_tcon *tcon,
> > const char *full_path, const char *symname)
> > +{
> > + struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
> > +
> > + switch (ctx->reparse_type) {
> > + case CIFS_REPARSE_TYPE_NATIVE:
> > + case CIFS_REPARSE_TYPE_NATIVE_NFS:
> > + case CIFS_REPARSE_TYPE_NATIVE_WSL:
> > + return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
> > + case CIFS_REPARSE_TYPE_NFS:
> > + return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
> > + case CIFS_REPARSE_TYPE_WSL:
> > + return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
> > + default:
> > + return -EOPNOTSUPP;
> > + }
> > +}
> > +
> > +static int create_native_symlink(const unsigned int xid, struct inode *inode,
> > + struct dentry *dentry, struct cifs_tcon *tcon,
> > + const char *full_path, const char *symname)
> > {
> > struct reparse_symlink_data_buffer *buf = NULL;
> > struct cifs_open_info_data data = {};
> > @@ -363,6 +397,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
> > case NFS_SPECFILE_SOCK:
> > dlen = 0;
> > break;
> > + case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */
> > default:
> > return -EOPNOTSUPP;
> > }
> > @@ -381,7 +416,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
> >
> > static int mknod_nfs(unsigned int xid, struct inode *inode,
> > struct dentry *dentry, struct cifs_tcon *tcon,
> > - const char *full_path, umode_t mode, dev_t dev)
> > + const char *full_path, umode_t mode, dev_t dev,
> > + const char *symname)
> > {
> > struct cifs_open_info_data data;
> > struct reparse_posix_data *p;
> > @@ -421,6 +457,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
> > case IO_REPARSE_TAG_LX_FIFO:
> > case IO_REPARSE_TAG_AF_UNIX:
> > break;
> > + case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
> > default:
> > return -EOPNOTSUPP;
> > }
> > @@ -518,7 +555,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
> >
> > static int mknod_wsl(unsigned int xid, struct inode *inode,
> > struct dentry *dentry, struct cifs_tcon *tcon,
> > - const char *full_path, umode_t mode, dev_t dev)
> > + const char *full_path, umode_t mode, dev_t dev,
> > + const char *symname)
> > {
> > struct cifs_open_info_data data;
> > struct reparse_data_buffer buf;
> > @@ -563,17 +601,17 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
> > const char *full_path, umode_t mode, dev_t dev)
> > {
> > struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
> > - int rc = -EOPNOTSUPP;
> >
> > switch (ctx->reparse_type) {
> > + case CIFS_REPARSE_TYPE_NATIVE_NFS:
> > case CIFS_REPARSE_TYPE_NFS:
> > - rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
> > - break;
> > + return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
> > + case CIFS_REPARSE_TYPE_NATIVE_WSL:
> > case CIFS_REPARSE_TYPE_WSL:
> > - rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
> > - break;
> > + return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
> > + default:
> > + return -EOPNOTSUPP;
> > }
> > - return rc;
> > }
> >
> > /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
> > @@ -848,7 +886,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> > return rc;
> > }
> >
> > -static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
> > +static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
> > u32 plen, bool unicode,
> > struct cifs_sb_info *cifs_sb,
> > const char *full_path,
> > @@ -936,7 +974,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
> > return parse_reparse_posix((struct reparse_posix_data *)buf,
> > cifs_sb, data);
> > case IO_REPARSE_TAG_SYMLINK:
> > - return parse_reparse_symlink(
> > + return parse_reparse_native_symlink(
> > (struct reparse_symlink_data_buffer *)buf,
> > plen, unicode, cifs_sb, full_path, data);
> > case IO_REPARSE_TAG_LX_SYMLINK:
> > diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
> > index eb6854e65e08..a6bdf20ce1b0 100644
> > --- a/fs/smb/client/reparse.h
> > +++ b/fs/smb/client/reparse.h
> > @@ -61,6 +61,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
> > static inline u64 reparse_mode_nfs_type(mode_t mode)
> > {
> > switch (mode & S_IFMT) {
> > + case S_IFLNK: return NFS_SPECFILE_LNK;
> > case S_IFBLK: return NFS_SPECFILE_BLK;
> > case S_IFCHR: return NFS_SPECFILE_CHR;
> > case S_IFIFO: return NFS_SPECFILE_FIFO;
> > @@ -72,6 +73,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode)
> > static inline u32 reparse_mode_wsl_tag(mode_t mode)
> > {
> > switch (mode & S_IFMT) {
> > + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK;
> > case S_IFBLK: return IO_REPARSE_TAG_LX_BLK;
> > case S_IFCHR: return IO_REPARSE_TAG_LX_CHR;
> > case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
> > --
> > 2.20.1
> >
> >
>
>
> --
> Thanks,
>
> Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 3/7] cifs: Add support for creating native Windows sockets
2024-10-06 10:00 ` [PATCH 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
@ 2024-10-10 21:47 ` Pali Rohár
0 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-10 21:47 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
On Sunday 06 October 2024 12:00:42 Pali Rohár wrote:
> Native Windows sockets created by WinSock on Windows 10 April 2018 Update
> (version 1803) or Windows Server 2019 (version 1809) or later versions is
> reparse point with IO_REPARSE_TAG_AF_UNIX tag, with empty reparse point
> data buffer and without any EAs.
>
> Create AF_UNIX sockets in this native format when -o reparse=native or
> -o reparse=native+<something> mount option is used.
>
> This change makes AF_UNIX sockets created by Linux CIFS client compatible
> with AF_UNIX sockets created by Windows applications on NTFS volumes.
>
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
> fs/smb/client/cifsglob.h | 6 +++---
> fs/smb/client/reparse.c | 36 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
> index 7632d2ba5390..570b22d02f7e 100644
> --- a/fs/smb/client/cifsglob.h
> +++ b/fs/smb/client/cifsglob.h
> @@ -155,9 +155,9 @@ enum securityEnum {
>
> enum cifs_reparse_type {
> CIFS_REPARSE_TYPE_NONE, /* disable creating new reparse points */
> - CIFS_REPARSE_TYPE_NATIVE, /* native symlinks only */
> - CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks, nfs for others */
> - CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks, wsl for others */
> + CIFS_REPARSE_TYPE_NATIVE, /* native symlinks and sockets only, no support for others */
> + CIFS_REPARSE_TYPE_NATIVE_NFS, /* native for symlinks/sockets, nfs for fifos/block/char */
> + CIFS_REPARSE_TYPE_NATIVE_WSL, /* native for symlinks/sockets, wsl for fifos/block/char */
> CIFS_REPARSE_TYPE_NFS, /* nfs for everything */
> CIFS_REPARSE_TYPE_WSL, /* wsl for everything */
> CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NATIVE_NFS,
> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> index 38fe0a710c65..f1488f870320 100644
> --- a/fs/smb/client/reparse.c
> +++ b/fs/smb/client/reparse.c
> @@ -379,6 +379,35 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
> return 0;
> }
>
> +static int create_native_socket(const unsigned int xid, struct inode *inode,
> + struct dentry *dentry, struct cifs_tcon *tcon,
> + const char *full_path)
> +{
> + struct cifs_open_info_data data = {
> + .reparse_point = true,
> + .reparse = { .tag = IO_REPARSE_TAG_AF_UNIX, },
> + };
> + struct reparse_data_buffer buf = {
> + .ReparseTag = cpu_to_le32(IO_REPARSE_TAG_AF_UNIX),
> + .ReparseDataLength = 0,
Correctly, this should be:
.ReparseDataLength = cpu_to_le16(0),
> + };
> + struct kvec iov = {
> + .iov_base = &buf,
> + .iov_len = sizeof(buf),
> + };
> + struct inode *new;
> + int rc;
Here is missing initialization of rc:
int rc = 0;
> +
> + new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
> + tcon, full_path, false, &iov, NULL);
> + if (!IS_ERR(new))
> + d_instantiate(dentry, new);
> + else
> + rc = PTR_ERR(new);
> + cifs_free_open_info(&data);
> + return rc;
> +}
> +
> static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
> mode_t mode, dev_t dev,
> struct kvec *iov)
> @@ -602,6 +631,13 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
> {
> struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
>
> + if (S_ISSOCK(mode) && (
> + ctx->reparse_type == CIFS_REPARSE_TYPE_NATIVE ||
> + ctx->reparse_type == CIFS_REPARSE_TYPE_NATIVE_NFS ||
> + ctx->reparse_type == CIFS_REPARSE_TYPE_NATIVE_WSL)) {
> + return create_native_socket(xid, inode, dentry, tcon, full_path);
> + }
> +
> switch (ctx->reparse_type) {
> case CIFS_REPARSE_TYPE_NATIVE_NFS:
> case CIFS_REPARSE_TYPE_NFS:
> --
> 2.20.1
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 6/7] cifs: Add support for creating WSL-style symlinks
2024-10-06 10:00 ` [PATCH 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
@ 2024-10-10 21:50 ` Pali Rohár
0 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-10 21:50 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
On Sunday 06 October 2024 12:00:45 Pali Rohár wrote:
> This change implements support for creating new symlink in WSL-style by
> Linux cifs client when -o reparse=wsl mount option is specified. WSL-style
> symlink uses reparse point with tag IO_REPARSE_TAG_LX_SYMLINK and symlink
> target location is stored in reparse buffer in UTF-8 encoding prefixed by
> 32-bit flags. Flags bits are unknown, but it was observed that WSL always
> sets flags to value 0x02000000. Do same in Linux cifs client.
>
> New symlinks would be created in WSL-style only in case the mount option
> -o reparse=wsl is specified, which is not by default. So default CIFS
> mounts are not affected by this change.
>
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
> fs/smb/client/reparse.c | 65 +++++++++++++++++++++++++++++++++--------
> 1 file changed, 53 insertions(+), 12 deletions(-)
>
> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> index 402eb568f466..6606c40487ae 100644
> --- a/fs/smb/client/reparse.c
> +++ b/fs/smb/client/reparse.c
> @@ -506,9 +506,17 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
> return rc;
> }
>
> -static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
> - mode_t mode, struct kvec *iov)
> +static int wsl_set_reparse_buf(struct reparse_data_buffer **buf,
> + mode_t mode, const char *symname,
> + struct cifs_sb_info *cifs_sb,
> + struct kvec *iov)
> {
> + struct reparse_wsl_symlink_data_buffer *symlink_buf;
> + __le16 *symname_utf16;
> + int symname_utf16_len;
> + int symname_utf8_maxlen;
> + int symname_utf8_len;
> + size_t buf_len;
> u32 tag;
>
> switch ((tag = reparse_mode_wsl_tag(mode))) {
> @@ -516,17 +524,45 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
> case IO_REPARSE_TAG_LX_CHR:
> case IO_REPARSE_TAG_LX_FIFO:
> case IO_REPARSE_TAG_AF_UNIX:
> + buf_len = sizeof(struct reparse_data_buffer);
> + *buf = kzalloc(buf_len, GFP_KERNEL);
> + if (!*buf)
> + return -ENOMEM;
> + break;
> + case IO_REPARSE_TAG_LX_SYMLINK:
> + symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname),
> + &symname_utf16_len,
> + cifs_sb->local_nls,
> + NO_MAP_UNI_RSVD);
> + if (!symname_utf16)
> + return -ENOMEM;
> + symname_utf8_maxlen = symname_utf16_len/2*3;
> + symlink_buf = kzalloc(sizeof(struct reparse_wsl_symlink_data_buffer) +
> + symname_utf8_maxlen, GFP_KERNEL);
> + if (!symlink_buf) {
> + kfree(symname_utf16);
> + return -ENOMEM;
> + }
> + /* Flag 0x02000000 is unknown, but all wsl symlinks have this value */
> + symlink_buf->Flags = cpu_to_le32(0x02000000);
> + /* PathBuffer is in UTF-8 but without trailing null-term byte */
> + symname_utf8_len = utf16s_to_utf8s(symname_utf16, symname_utf16_len/2,
> + UTF16_LITTLE_ENDIAN,
> + symlink_buf->PathBuffer,
> + symname_utf8_maxlen);
> + *buf = (struct reparse_data_buffer *)symlink_buf;
> + buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len;
> + kfree(symname_utf16);
> break;
> - case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
> default:
> return -EOPNOTSUPP;
> }
>
> - buf->ReparseTag = cpu_to_le32(tag);
> - buf->Reserved = 0;
> - buf->ReparseDataLength = 0;
> - iov->iov_base = buf;
> - iov->iov_len = sizeof(*buf);
> + (*buf)->ReparseTag = cpu_to_le32(tag);
> + (*buf)->Reserved = 0;
> + (*buf)->ReparseDataLength = buf_len - sizeof(struct reparse_data_buffer);
ReparseDataLength is in little endian, so it should be:
(*buf)->ReparseDataLength = cpu_to_le16(buf_len - sizeof(struct reparse_data_buffer));
> + iov->iov_base = *buf;
> + iov->iov_len = buf_len;
> return 0;
> }
>
> @@ -618,25 +654,29 @@ static int mknod_wsl(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_data_buffer buf;
> + struct reparse_data_buffer *buf;
> struct smb2_create_ea_ctx *cc;
> struct inode *new;
> unsigned int len;
> struct kvec reparse_iov, xattr_iov;
> int rc;
>
> - rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov);
> + rc = wsl_set_reparse_buf(&buf, mode, symname, cifs_sb, &reparse_iov);
> if (rc)
> return rc;
>
> rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov);
> - if (rc)
> + if (rc) {
> + kfree(buf);
> return rc;
> + }
>
> data = (struct cifs_open_info_data) {
> .reparse_point = true,
> - .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
> + .reparse = { .tag = le32_to_cpu(buf->ReparseTag), .buf = buf, },
> + .symlink_target = kstrdup(symname, GFP_KERNEL),
> };
>
> cc = xattr_iov.iov_base;
> @@ -653,6 +693,7 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
> rc = PTR_ERR(new);
> cifs_free_open_info(&data);
> kfree(xattr_iov.iov_base);
> + kfree(buf);
> return rc;
> }
>
> --
> 2.20.1
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] cifs: Add mount option -o reparse=native
[not found] ` <CAH2r5mttO-aDq94QrLQm10xJRGLg=PULqX9fcfoykAweVVO+uQ@mail.gmail.com>
@ 2024-10-10 22:21 ` Steve French
2024-10-10 22:38 ` Pali Rohár
0 siblings, 1 reply; 29+ messages in thread
From: Steve French @ 2024-10-10 22:21 UTC (permalink / raw)
To: Pali Rohár
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
On Thu, Oct 10, 2024 at 5:17 PM Steve French <smfrench@gmail.com> wrote:
>
>
>
> On Mon, Oct 7, 2024 at 1:36 PM Pali Rohár <pali@kernel.org> wrote:
>>
>> Currently choosing how new symlinks are created is quite complicated.
>>
>> Without these patch series, by default new symlinks are created via
>> native reparse points, even when reparse=nfs or reparse=wsl is
>> specified. There is no possibility to create a NFS-style or WSL-style
>> symlink yet, and this patch series address this missing functionality.
>> When option -o sfu is specified then all new symlinks are created in
>> SFU-style, independently of -o reparse option. And when -o mfsymlinks is
>> specified then all new symlinks are created in mf style, independently
>> of -o reparse and -o sfu options.
>>
>> This patch series does not change -o sfu and -o mfsymlinks overrides, it
>> just changes the way how -o reparse is handled.
>>
I lean toward something similar, and more intuitive - do not have
"reparse=" control symlink creation - but instead use another mount
parm (e.g. "symlink=") for that. It would be rarely used - only if
you don't want the default (windows default format too) for server
symlinks or "mfsymlinks" (for client only symlinks):
1) "symlink=" if specified can be set to one of five formats (with the
default being the windows format)
a) "mfsymlinks" (Mac style which is safer for many use cases since
they are "client only" symlinks which the server will never use)
Setting "symlink=mfsymlinks" will have the same effect as just
specifying "mfsymlinks" so won't break anything
b) "default" (or "windows") which uses the default symlink format
when trying to create a new symlink
c) "nfs"
d) "wsl"
e) "sfu"
2) "reparse=" will still control how special files are created (char,
block, fifo, socket) and can be set to:
a) "nfs" (default)
b) or "wsl"
c) If "sfu" set on mount will cause special files to be created
with "sfu" format instead of using reparse points to create
3) reading reparse points will always be supported (unless you want to
add a new parameter "reparse=none" to treat all reparse points as
empty directories)
4) reading special files via the old "sfu" will only be supported if
you mount with "sfu"
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] cifs: Add mount option -o reparse=native
2024-10-10 22:21 ` Steve French
@ 2024-10-10 22:38 ` Pali Rohár
[not found] ` <CAH2r5msEiD05ehJs_a05sP_rX7BkVH-9LZp8Sj6EFbpZA9bfrg@mail.gmail.com>
0 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-10 22:38 UTC (permalink / raw)
To: Steve French
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
On Thursday 10 October 2024 17:21:59 Steve French wrote:
> On Thu, Oct 10, 2024 at 5:17 PM Steve French <smfrench@gmail.com> wrote:
> >
> >
> >
> > On Mon, Oct 7, 2024 at 1:36 PM Pali Rohár <pali@kernel.org> wrote:
> >>
> >> Currently choosing how new symlinks are created is quite complicated.
> >>
> >> Without these patch series, by default new symlinks are created via
> >> native reparse points, even when reparse=nfs or reparse=wsl is
> >> specified. There is no possibility to create a NFS-style or WSL-style
> >> symlink yet, and this patch series address this missing functionality.
> >> When option -o sfu is specified then all new symlinks are created in
> >> SFU-style, independently of -o reparse option. And when -o mfsymlinks is
> >> specified then all new symlinks are created in mf style, independently
> >> of -o reparse and -o sfu options.
> >>
> >> This patch series does not change -o sfu and -o mfsymlinks overrides, it
> >> just changes the way how -o reparse is handled.
> >>
>
> I lean toward something similar, and more intuitive - do not have
> "reparse=" control symlink creation - but instead use another mount
> parm (e.g. "symlink=") for that. It would be rarely used - only if
> you don't want the default (windows default format too) for server
> symlinks or "mfsymlinks" (for client only symlinks):
>
> 1) "symlink=" if specified can be set to one of five formats (with the
> default being the windows format)
> a) "mfsymlinks" (Mac style which is safer for many use cases since
> they are "client only" symlinks which the server will never use)
> Setting "symlink=mfsymlinks" will have the same effect as just
> specifying "mfsymlinks" so won't break anything
> b) "default" (or "windows") which uses the default symlink format
> when trying to create a new symlink
> c) "nfs"
> d) "wsl"
> e) "sfu"
> 2) "reparse=" will still control how special files are created (char,
> block, fifo, socket) and can be set to:
> a) "nfs" (default)
> b) or "wsl"
> c) If "sfu" set on mount will cause special files to be created
> with "sfu" format instead of using reparse points to create
> 3) reading reparse points will always be supported (unless you want to
> add a new parameter "reparse=none" to treat all reparse points as
> empty directories)
> 4) reading special files via the old "sfu" will only be supported if
> you mount with "sfu"
>
>
>
>
> --
> Thanks,
>
> Steve
Ok, and how to handle creating new sockets? For me it makes sense to
create new sockets in "native" AF_UNIX style - compatible with Windows
WinAPI / WinSocks. Should be there also a new parameter?
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/7] cifs: Add mount option -o reparse=native
[not found] ` <CAH2r5msEiD05ehJs_a05sP_rX7BkVH-9LZp8Sj6EFbpZA9bfrg@mail.gmail.com>
@ 2024-10-10 22:44 ` Pali Rohár
0 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-10 22:44 UTC (permalink / raw)
To: Steve French; +Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, CIFS, LKML
On Thursday 10 October 2024 17:42:55 Steve French wrote:
> On Thu, Oct 10, 2024, 5:39 PM Pali Rohár <pali@kernel.org> wrote:
>
> > On Thursday 10 October 2024 17:21:59 Steve French wrote:
> > > On Thu, Oct 10, 2024 at 5:17 PM Steve French <smfrench@gmail.com> wrote:
> > > >
> > > >
> > > >
> > > > On Mon, Oct 7, 2024 at 1:36 PM Pali Rohár <pali@kernel.org> wrote:
> > > >>
> > > >> Currently choosing how new symlinks are created is quite complicated.
> > > >>
> > > >> Without these patch series, by default new symlinks are created via
> > > >> native reparse points, even when reparse=nfs or reparse=wsl is
> > > >> specified. There is no possibility to create a NFS-style or WSL-style
> > > >> symlink yet, and this patch series address this missing functionality.
> > > >> When option -o sfu is specified then all new symlinks are created in
> > > >> SFU-style, independently of -o reparse option. And when -o mfsymlinks
> > is
> > > >> specified then all new symlinks are created in mf style, independently
> > > >> of -o reparse and -o sfu options.
> > > >>
> > > >> This patch series does not change -o sfu and -o mfsymlinks overrides,
> > it
> > > >> just changes the way how -o reparse is handled.
> > > >>
> > >
> > > I lean toward something similar, and more intuitive - do not have
> > > "reparse=" control symlink creation - but instead use another mount
> > > parm (e.g. "symlink=") for that. It would be rarely used - only if
> > > you don't want the default (windows default format too) for server
> > > symlinks or "mfsymlinks" (for client only symlinks):
> > >
> > > 1) "symlink=" if specified can be set to one of five formats (with the
> > > default being the windows format)
> > > a) "mfsymlinks" (Mac style which is safer for many use cases since
> > > they are "client only" symlinks which the server will never use)
> > > Setting "symlink=mfsymlinks" will have the same effect as just
> > > specifying "mfsymlinks" so won't break anything
> > > b) "default" (or "windows") which uses the default symlink format
> > > when trying to create a new symlink
> > > c) "nfs"
> > > d) "wsl"
> > > e) "sfu"
> > > 2) "reparse=" will still control how special files are created (char,
> > > block, fifo, socket) and can be set to:
> > > a) "nfs" (default)
> > > b) or "wsl"
> > > c) If "sfu" set on mount will cause special files to be created
> > > with "sfu" format instead of using reparse points to create
> > > 3) reading reparse points will always be supported (unless you want to
> > > add a new parameter "reparse=none" to treat all reparse points as
> > > empty directories)
> > > 4) reading special files via the old "sfu" will only be supported if
> > > you mount with "sfu"
> > >
> > >
> > >
> > >
> > > --
> > > Thanks,
> > >
> > > Steve
> >
> > Ok, and how to handle creating new sockets? For me it makes sense to
> > create new sockets in "native" AF_UNIX style - compatible with Windows
> > WinAPI / WinSocks. Should be there also a new parameter?
> >
>
> Possibly, but we can decide that later. Aren't sockets typically more
> transient short lives so less likely to cause issues no matter what format
> we use??
>
> >
Yes, they are short lives.
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v2 0/7] Allow to choose symlink and socket type
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
` (6 preceding siblings ...)
2024-10-06 10:00 ` [PATCH 7/7] cifs: Validate content of WSL reparse point buffers Pali Rohár
@ 2024-10-12 8:52 ` Pali Rohár
2024-10-12 8:55 ` [PATCH v2 1/7] cifs: Add mount option -o symlink= for choosing symlink create type Pali Rohár
` (8 more replies)
7 siblings, 9 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:52 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
This patch series improves choosing reparse format when creating new
special files.
Changes since v1:
* Instead of new -o reparse= mount option is now a new -o symlink= mount
option for choosing symlink type during creation, and new option
-o nonativesocket for choosing socket type
Pali Rohár (7):
cifs: Add mount option -o symlink= for choosing symlink create type
cifs: Add mount option -o reparse=none
cifs: Add support for creating native Windows sockets
cifs: Add support for creating NFS-style symlinks
cifs: Improve guard for excluding $LXDEV xattr
cifs: Add support for creating WSL-style symlinks
cifs: Validate content of WSL reparse point buffers
fs/smb/client/cifsfs.c | 4 +
fs/smb/client/cifsglob.h | 36 +++++++
fs/smb/client/connect.c | 4 +
fs/smb/client/fs_context.c | 82 +++++++++++++++
fs/smb/client/fs_context.h | 19 ++++
fs/smb/client/link.c | 60 ++++++++---
fs/smb/client/reparse.c | 201 +++++++++++++++++++++++++++++++------
fs/smb/client/reparse.h | 2 +
8 files changed, 364 insertions(+), 44 deletions(-)
--
2.20.1
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v2 1/7] cifs: Add mount option -o symlink= for choosing symlink create type
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
@ 2024-10-12 8:55 ` Pali Rohár
2024-10-12 8:55 ` [PATCH v2 2/7] cifs: Add mount option -o reparse=none Pali Rohár
` (7 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:55 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
Currently Linux CIFS client creates a new symlink of the first flavor which
is allowed by mount options, parsed in this order: -o (no)mfsymlinks,
-o (no)sfu, -o (no)unix (+ its aliases) and -o reparse=[type].
Introduce a new mount option -o symlink= for explicitly choosing a symlink
flavor. Possible options are:
-o symlink=default - The default behavior, like before this change.
-o symlink=none - Disallow creating a new symlinks
-o symlink=native - Create as native SMB symlink reparse point
-o symlink=unix - Create via SMB1 unix extension command
-o symlink=mfsymlinks - Create as regular file of mfsymlinks format
-o symlink=sfu - Create as regular system file of SFU format
-o symlink=nfs - Create as NFS reparse point
-o symlink=wsl - Create as WSL reparse point
So for example specifying -o sfu,mfsymlinks,symlink=native will allow to
parse symlinks also of SFU and mfsymlinks types (which are disabled by
default unless mount option is explicitly specified), but new symlinks will
be created under native SMB type (which parsing is always enabled).
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/cifsfs.c | 2 ++
fs/smb/client/cifsglob.h | 33 ++++++++++++++++++
fs/smb/client/connect.c | 2 ++
fs/smb/client/fs_context.c | 71 ++++++++++++++++++++++++++++++++++++++
fs/smb/client/fs_context.h | 16 +++++++++
fs/smb/client/link.c | 60 ++++++++++++++++++++++++--------
fs/smb/client/reparse.c | 52 ++++++++++++++++++++++------
fs/smb/client/reparse.h | 2 ++
8 files changed, 214 insertions(+), 24 deletions(-)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 000e1ef3beea..39ec67d9808e 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -689,6 +689,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
cifs_sb->ctx->backupgid));
seq_show_option(s, "reparse",
cifs_reparse_type_str(cifs_sb->ctx->reparse_type));
+ seq_show_option(s, "symlink",
+ cifs_symlink_type_str(get_cifs_symlink_type(cifs_sb)));
seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize);
seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index d5446d652755..f419d20f6c38 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -171,6 +171,39 @@ static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type)
}
}
+enum cifs_symlink_type {
+ CIFS_SYMLINK_TYPE_DEFAULT,
+ CIFS_SYMLINK_TYPE_NONE,
+ CIFS_SYMLINK_TYPE_NATIVE,
+ CIFS_SYMLINK_TYPE_UNIX,
+ CIFS_SYMLINK_TYPE_MFSYMLINKS,
+ CIFS_SYMLINK_TYPE_SFU,
+ CIFS_SYMLINK_TYPE_NFS,
+ CIFS_SYMLINK_TYPE_WSL,
+};
+
+static inline const char *cifs_symlink_type_str(enum cifs_symlink_type type)
+{
+ switch (type) {
+ case CIFS_SYMLINK_TYPE_NONE:
+ return "none";
+ case CIFS_SYMLINK_TYPE_NATIVE:
+ return "native";
+ case CIFS_SYMLINK_TYPE_UNIX:
+ return "unix";
+ case CIFS_SYMLINK_TYPE_MFSYMLINKS:
+ return "mfsymlinks";
+ case CIFS_SYMLINK_TYPE_SFU:
+ return "sfu";
+ case CIFS_SYMLINK_TYPE_NFS:
+ return "nfs";
+ case CIFS_SYMLINK_TYPE_WSL:
+ return "wsl";
+ default:
+ return "unknown";
+ }
+}
+
struct session_key {
unsigned int len;
char *response;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index adf8758847f6..bc5b5100ac09 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -2831,6 +2831,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
return 0;
if (old->ctx->reparse_type != new->ctx->reparse_type)
return 0;
+ if (old->ctx->symlink_type != new->ctx->symlink_type)
+ return 0;
return 1;
}
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index b2a8581c21f7..6bd4a5e61342 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -178,6 +178,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_string("sec", Opt_sec),
fsparam_string("cache", Opt_cache),
fsparam_string("reparse", Opt_reparse),
+ fsparam_string("symlink", Opt_symlink),
fsparam_string("symlinkroot", Opt_symlinkroot),
/* Arguments that should be ignored */
@@ -330,6 +331,55 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value,
return 0;
}
+static const match_table_t symlink_flavor_tokens = {
+ { Opt_symlink_default, "default" },
+ { Opt_symlink_none, "none" },
+ { Opt_symlink_native, "native" },
+ { Opt_symlink_unix, "unix" },
+ { Opt_symlink_mfsymlinks, "mfsymlinks" },
+ { Opt_symlink_sfu, "sfu" },
+ { Opt_symlink_nfs, "nfs" },
+ { Opt_symlink_wsl, "wsl" },
+ { Opt_symlink_err, NULL },
+};
+
+static int parse_symlink_flavor(struct fs_context *fc, char *value,
+ struct smb3_fs_context *ctx)
+{
+ substring_t args[MAX_OPT_ARGS];
+
+ switch (match_token(value, symlink_flavor_tokens, args)) {
+ case Opt_symlink_default:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT;
+ break;
+ case Opt_symlink_none:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_NONE;
+ break;
+ case Opt_symlink_native:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_NATIVE;
+ break;
+ case Opt_symlink_unix:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_UNIX;
+ break;
+ case Opt_symlink_mfsymlinks:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_MFSYMLINKS;
+ break;
+ case Opt_symlink_sfu:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_SFU;
+ break;
+ case Opt_symlink_nfs:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_NFS;
+ break;
+ case Opt_symlink_wsl:
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_WSL;
+ break;
+ default:
+ cifs_errorf(fc, "bad symlink= option: %s\n", value);
+ return 1;
+ }
+ return 0;
+}
+
#define DUP_CTX_STR(field) \
do { \
if (ctx->field) { \
@@ -1620,6 +1670,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
if (parse_reparse_flavor(fc, param->string, ctx))
goto cifs_parse_mount_err;
break;
+ case Opt_symlink:
+ if (parse_symlink_flavor(fc, param->string, ctx))
+ goto cifs_parse_mount_err;
+ break;
case Opt_symlinkroot:
if (param->string[0] != '/') {
cifs_errorf(fc, "symlinkroot mount options must be absolute path\n");
@@ -1650,6 +1704,22 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
return -EINVAL;
}
+enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb)
+{
+ if (cifs_sb->ctx->symlink_type == CIFS_SYMLINK_TYPE_DEFAULT) {
+ if (cifs_sb->ctx->mfsymlinks)
+ return CIFS_SYMLINK_TYPE_MFSYMLINKS;
+ else if (cifs_sb->ctx->sfu_emul)
+ return CIFS_SYMLINK_TYPE_SFU;
+ else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
+ return CIFS_SYMLINK_TYPE_UNIX;
+ else
+ return CIFS_SYMLINK_TYPE_NATIVE;
+ } else {
+ return cifs_sb->ctx->symlink_type;
+ }
+}
+
int smb3_init_fs_context(struct fs_context *fc)
{
struct smb3_fs_context *ctx;
@@ -1726,6 +1796,7 @@ int smb3_init_fs_context(struct fs_context *fc)
ctx->retrans = 1;
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
+ ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT;
/*
* short int override_uid = -1;
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 94db5fdce621..3bcf20495fea 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -48,6 +48,18 @@ enum cifs_reparse_parm {
Opt_reparse_err
};
+enum cifs_symlink_parm {
+ Opt_symlink_default,
+ Opt_symlink_none,
+ Opt_symlink_native,
+ Opt_symlink_unix,
+ Opt_symlink_mfsymlinks,
+ Opt_symlink_sfu,
+ Opt_symlink_nfs,
+ Opt_symlink_wsl,
+ Opt_symlink_err
+};
+
enum cifs_sec_param {
Opt_sec_krb5,
Opt_sec_krb5i,
@@ -157,6 +169,7 @@ enum cifs_param {
Opt_sec,
Opt_cache,
Opt_reparse,
+ Opt_symlink,
Opt_symlinkroot,
/* Mount options to be ignored */
@@ -285,12 +298,15 @@ struct smb3_fs_context {
struct cifs_ses *dfs_root_ses;
bool dfs_automount:1; /* set for dfs automount only */
enum cifs_reparse_type reparse_type;
+ enum cifs_symlink_type symlink_type;
bool dfs_conn:1; /* set for dfs mounts */
char *symlinkroot; /* top level directory for native SMB symlinks in absolute format */
};
extern const struct fs_parameter_spec smb3_fs_parameters[];
+extern enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb);
+
extern int smb3_init_fs_context(struct fs_context *fc);
extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);
extern void smb3_cleanup_fs_context(struct smb3_fs_context *ctx);
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
index 47ddeb7fa111..6e6c09cc5ce7 100644
--- a/fs/smb/client/link.c
+++ b/fs/smb/client/link.c
@@ -18,6 +18,7 @@
#include "cifs_unicode.h"
#include "smb2proto.h"
#include "cifs_ioctl.h"
+#include "fs_context.h"
/*
* M-F Symlink Functions - Begin
@@ -604,22 +605,53 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
cifs_dbg(FYI, "symname is %s\n", symname);
/* BB what if DFS and this volume is on different share? BB */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
- rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
- } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
- rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
- full_path, S_IFLNK, 0, symname);
+ rc = -EOPNOTSUPP;
+ switch (get_cifs_symlink_type(cifs_sb)) {
+ case CIFS_SYMLINK_TYPE_DEFAULT:
+ /* should not happen, get_cifs_symlink_type() resolves the default */
+ break;
+
+ case CIFS_SYMLINK_TYPE_NONE:
+ break;
+
+ case CIFS_SYMLINK_TYPE_UNIX:
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
- } else if (pTcon->unix_ext) {
- rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
- cifs_sb->local_nls,
- cifs_remap(cifs_sb));
+ if (pTcon->unix_ext) {
+ rc = CIFSUnixCreateSymLink(xid, pTcon, full_path,
+ symname,
+ cifs_sb->local_nls,
+ cifs_remap(cifs_sb));
+ }
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
- } else if (server->ops->create_reparse_symlink) {
- rc = server->ops->create_reparse_symlink(xid, inode, direntry,
- pTcon, full_path,
- symname);
- goto symlink_exit;
+ break;
+
+ case CIFS_SYMLINK_TYPE_MFSYMLINKS:
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
+ rc = create_mf_symlink(xid, pTcon, cifs_sb,
+ full_path, symname);
+ }
+ break;
+
+ case CIFS_SYMLINK_TYPE_SFU:
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon,
+ full_path, S_IFLNK,
+ 0, symname);
+ }
+ break;
+
+ case CIFS_SYMLINK_TYPE_NATIVE:
+ case CIFS_SYMLINK_TYPE_NFS:
+ case CIFS_SYMLINK_TYPE_WSL:
+ if (server->ops->create_reparse_symlink) {
+ rc = server->ops->create_reparse_symlink(xid, inode,
+ direntry,
+ pTcon,
+ full_path,
+ symname);
+ goto symlink_exit;
+ }
+ break;
}
if (rc == 0) {
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 99ef9bc88afc..d950c60323e8 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -14,6 +14,20 @@
#include "fs_context.h"
#include "reparse.h"
+static int mknod_nfs(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname);
+
+static int mknod_wsl(unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname);
+
+static int create_native_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname);
+
static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
const unsigned int xid,
const char *full_path,
@@ -23,6 +37,22 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
const char *full_path, const char *symname)
+{
+ switch (get_cifs_symlink_type(CIFS_SB(inode->i_sb))) {
+ case CIFS_SYMLINK_TYPE_NATIVE:
+ return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
+ case CIFS_SYMLINK_TYPE_NFS:
+ return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
+ case CIFS_SYMLINK_TYPE_WSL:
+ return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int create_native_symlink(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path, const char *symname)
{
struct reparse_symlink_data_buffer *buf = NULL;
struct cifs_open_info_data data = {};
@@ -363,6 +393,7 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
case NFS_SPECFILE_SOCK:
dlen = 0;
break;
+ case NFS_SPECFILE_LNK: /* TODO: add support for NFS symlinks */
default:
return -EOPNOTSUPP;
}
@@ -381,7 +412,8 @@ static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
static int mknod_nfs(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname)
{
struct cifs_open_info_data data;
struct reparse_posix_data *p;
@@ -421,6 +453,7 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_AF_UNIX:
break;
+ case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
default:
return -EOPNOTSUPP;
}
@@ -518,7 +551,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
static int mknod_wsl(unsigned int xid, struct inode *inode,
struct dentry *dentry, struct cifs_tcon *tcon,
- const char *full_path, umode_t mode, dev_t dev)
+ const char *full_path, umode_t mode, dev_t dev,
+ const char *symname)
{
struct cifs_open_info_data data;
struct reparse_data_buffer buf;
@@ -563,17 +597,15 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
const char *full_path, umode_t mode, dev_t dev)
{
struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
- int rc = -EOPNOTSUPP;
switch (ctx->reparse_type) {
case CIFS_REPARSE_TYPE_NFS:
- rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev);
- break;
+ return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
case CIFS_REPARSE_TYPE_WSL:
- rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev);
- break;
+ return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
+ default:
+ return -EOPNOTSUPP;
}
- return rc;
}
/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
@@ -848,7 +880,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
return rc;
}
-static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
+static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym,
u32 plen, bool unicode,
struct cifs_sb_info *cifs_sb,
const char *full_path,
@@ -936,7 +968,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
return parse_reparse_posix((struct reparse_posix_data *)buf,
cifs_sb, data);
case IO_REPARSE_TAG_SYMLINK:
- return parse_reparse_symlink(
+ return parse_reparse_native_symlink(
(struct reparse_symlink_data_buffer *)buf,
plen, unicode, cifs_sb, full_path, data);
case IO_REPARSE_TAG_LX_SYMLINK:
diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
index 81b6979bb40b..08579af9b9d7 100644
--- a/fs/smb/client/reparse.h
+++ b/fs/smb/client/reparse.h
@@ -48,6 +48,7 @@ static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
static inline u64 reparse_mode_nfs_type(mode_t mode)
{
switch (mode & S_IFMT) {
+ case S_IFLNK: return NFS_SPECFILE_LNK;
case S_IFBLK: return NFS_SPECFILE_BLK;
case S_IFCHR: return NFS_SPECFILE_CHR;
case S_IFIFO: return NFS_SPECFILE_FIFO;
@@ -59,6 +60,7 @@ static inline u64 reparse_mode_nfs_type(mode_t mode)
static inline u32 reparse_mode_wsl_tag(mode_t mode)
{
switch (mode & S_IFMT) {
+ case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK;
case S_IFBLK: return IO_REPARSE_TAG_LX_BLK;
case S_IFCHR: return IO_REPARSE_TAG_LX_CHR;
case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 2/7] cifs: Add mount option -o reparse=none
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
2024-10-12 8:55 ` [PATCH v2 1/7] cifs: Add mount option -o symlink= for choosing symlink create type Pali Rohár
@ 2024-10-12 8:55 ` Pali Rohár
2024-10-12 8:55 ` [PATCH v2 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
` (6 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:55 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
This new mount option allows to completely disable creating new reparse
points. When -o sfu or -o mfsymlinks or -o symlink= is not specified then
creating any special file (fifo, socket, symlink, block and char) will fail
with -EOPNOTSUPP error.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/cifsglob.h | 3 +++
fs/smb/client/fs_context.c | 8 +++++++-
fs/smb/client/fs_context.h | 1 +
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index f419d20f6c38..dcee43889358 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -154,6 +154,7 @@ enum securityEnum {
};
enum cifs_reparse_type {
+ CIFS_REPARSE_TYPE_NONE,
CIFS_REPARSE_TYPE_NFS,
CIFS_REPARSE_TYPE_WSL,
CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS,
@@ -162,6 +163,8 @@ enum cifs_reparse_type {
static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type)
{
switch (type) {
+ case CIFS_REPARSE_TYPE_NONE:
+ return "none";
case CIFS_REPARSE_TYPE_NFS:
return "nfs";
case CIFS_REPARSE_TYPE_WSL:
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index 6bd4a5e61342..d68db6ac5f73 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -304,6 +304,7 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte
static const match_table_t reparse_flavor_tokens = {
{ Opt_reparse_default, "default" },
+ { Opt_reparse_none, "none" },
{ Opt_reparse_nfs, "nfs" },
{ Opt_reparse_wsl, "wsl" },
{ Opt_reparse_err, NULL },
@@ -318,6 +319,9 @@ static int parse_reparse_flavor(struct fs_context *fc, char *value,
case Opt_reparse_default:
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
break;
+ case Opt_reparse_none:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_NONE;
+ break;
case Opt_reparse_nfs:
ctx->reparse_type = CIFS_REPARSE_TYPE_NFS;
break;
@@ -1713,8 +1717,10 @@ enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb)
return CIFS_SYMLINK_TYPE_SFU;
else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext)
return CIFS_SYMLINK_TYPE_UNIX;
- else
+ else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
return CIFS_SYMLINK_TYPE_NATIVE;
+ else
+ return CIFS_SYMLINK_TYPE_NONE;
} else {
return cifs_sb->ctx->symlink_type;
}
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 3bcf20495fea..5f306f581fd1 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -43,6 +43,7 @@ enum {
enum cifs_reparse_parm {
Opt_reparse_default,
+ Opt_reparse_none,
Opt_reparse_nfs,
Opt_reparse_wsl,
Opt_reparse_err
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 3/7] cifs: Add support for creating native Windows sockets
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
2024-10-12 8:55 ` [PATCH v2 1/7] cifs: Add mount option -o symlink= for choosing symlink create type Pali Rohár
2024-10-12 8:55 ` [PATCH v2 2/7] cifs: Add mount option -o reparse=none Pali Rohár
@ 2024-10-12 8:55 ` Pali Rohár
2024-10-12 8:56 ` [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
` (5 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:55 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
Native Windows sockets created by WinSock on Windows 10 April 2018 Update
(version 1803) or Windows Server 2019 (version 1809) or later versions is
reparse point with IO_REPARSE_TAG_AF_UNIX tag, with empty reparse point
data buffer and without any EAs.
Create AF_UNIX sockets in this native format if -o nonativesocket was not
specified.
This change makes AF_UNIX sockets created by Linux CIFS client compatible
with AF_UNIX sockets created by Windows applications on NTFS volumes.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/cifsfs.c | 2 ++
fs/smb/client/connect.c | 2 ++
fs/smb/client/fs_context.c | 5 +++++
fs/smb/client/fs_context.h | 2 ++
fs/smb/client/reparse.c | 32 ++++++++++++++++++++++++++++++++
5 files changed, 43 insertions(+)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 39ec67d9808e..eb279d5c6bd3 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -689,6 +689,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
cifs_sb->ctx->backupgid));
seq_show_option(s, "reparse",
cifs_reparse_type_str(cifs_sb->ctx->reparse_type));
+ if (cifs_sb->ctx->nonativesocket)
+ seq_puts(s, ",nonativesocket");
seq_show_option(s, "symlink",
cifs_symlink_type_str(get_cifs_symlink_type(cifs_sb)));
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index bc5b5100ac09..3db39f2ef5a8 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -2831,6 +2831,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
return 0;
if (old->ctx->reparse_type != new->ctx->reparse_type)
return 0;
+ if (old->ctx->nonativesocket != new->ctx->nonativesocket)
+ return 0;
if (old->ctx->symlink_type != new->ctx->symlink_type)
return 0;
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index d68db6ac5f73..7f21630885cb 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -178,6 +178,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_string("sec", Opt_sec),
fsparam_string("cache", Opt_cache),
fsparam_string("reparse", Opt_reparse),
+ fsparam_string("nativesocket", Opt_nativesocket),
fsparam_string("symlink", Opt_symlink),
fsparam_string("symlinkroot", Opt_symlinkroot),
@@ -1674,6 +1675,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
if (parse_reparse_flavor(fc, param->string, ctx))
goto cifs_parse_mount_err;
break;
+ case Opt_nativesocket:
+ ctx->nonativesocket = result.negated;
+ break;
case Opt_symlink:
if (parse_symlink_flavor(fc, param->string, ctx))
goto cifs_parse_mount_err;
@@ -1803,6 +1807,7 @@ int smb3_init_fs_context(struct fs_context *fc)
ctx->retrans = 1;
ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT;
+ ctx->nonativesocket = 0;
/*
* short int override_uid = -1;
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 5f306f581fd1..18d39d457145 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -170,6 +170,7 @@ enum cifs_param {
Opt_sec,
Opt_cache,
Opt_reparse,
+ Opt_nativesocket,
Opt_symlink,
Opt_symlinkroot,
@@ -300,6 +301,7 @@ struct smb3_fs_context {
bool dfs_automount:1; /* set for dfs automount only */
enum cifs_reparse_type reparse_type;
enum cifs_symlink_type symlink_type;
+ bool nonativesocket:1;
bool dfs_conn:1; /* set for dfs mounts */
char *symlinkroot; /* top level directory for native SMB symlinks in absolute format */
};
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index d950c60323e8..57320a4c4d79 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -375,6 +375,35 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb,
return 0;
}
+static int create_native_socket(const unsigned int xid, struct inode *inode,
+ struct dentry *dentry, struct cifs_tcon *tcon,
+ const char *full_path)
+{
+ struct cifs_open_info_data data = {
+ .reparse_point = true,
+ .reparse = { .tag = IO_REPARSE_TAG_AF_UNIX, },
+ };
+ struct reparse_data_buffer buf = {
+ .ReparseTag = cpu_to_le32(IO_REPARSE_TAG_AF_UNIX),
+ .ReparseDataLength = cpu_to_le16(0),
+ };
+ struct kvec iov = {
+ .iov_base = &buf,
+ .iov_len = sizeof(buf),
+ };
+ struct inode *new;
+ int rc = 0;
+
+ new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
+ tcon, full_path, false, &iov, NULL);
+ if (!IS_ERR(new))
+ d_instantiate(dentry, new);
+ else
+ rc = PTR_ERR(new);
+ cifs_free_open_info(&data);
+ return rc;
+}
+
static int nfs_set_reparse_buf(struct reparse_posix_data *buf,
mode_t mode, dev_t dev,
struct kvec *iov)
@@ -598,6 +627,9 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
{
struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx;
+ if (S_ISSOCK(mode) && !ctx->nonativesocket && ctx->reparse_type != CIFS_REPARSE_TYPE_NONE)
+ return create_native_socket(xid, inode, dentry, tcon, full_path);
+
switch (ctx->reparse_type) {
case CIFS_REPARSE_TYPE_NFS:
return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
` (2 preceding siblings ...)
2024-10-12 8:55 ` [PATCH v2 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
@ 2024-10-12 8:56 ` Pali Rohár
2024-12-09 18:00 ` Pali Rohár
2024-10-12 8:56 ` [PATCH v2 5/7] cifs: Improve guard for excluding $LXDEV xattr Pali Rohár
` (4 subsequent siblings)
8 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:56 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
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@kernel.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
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 5/7] cifs: Improve guard for excluding $LXDEV xattr
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
` (3 preceding siblings ...)
2024-10-12 8:56 ` [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
@ 2024-10-12 8:56 ` Pali Rohár
2024-10-12 8:56 ` [PATCH v2 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
` (3 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:56 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
$LXDEV xattr is for storing block/char device's major and minor number.
Change guard which excludes storing $LXDEV xattr to explicitly filter
everything except block and char device. Current guard is opposite, which
is currently correct but is less-safe. This change is required for adding
support for creating WSL-style symlinks as symlinks also do not use
device's major and minor numbers.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/reparse.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index cd12704cae0c..50048dccc5ff 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -574,8 +574,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
memset(iov, 0, sizeof(*iov));
- /* Exclude $LXDEV xattr for sockets and fifos */
- if (S_ISSOCK(_mode) || S_ISFIFO(_mode))
+ /* Exclude $LXDEV xattr for non-device files */
+ if (!S_ISBLK(_mode) && !S_ISCHR(_mode))
num_xattrs = ARRAY_SIZE(xattrs) - 1;
else
num_xattrs = ARRAY_SIZE(xattrs);
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 6/7] cifs: Add support for creating WSL-style symlinks
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
` (4 preceding siblings ...)
2024-10-12 8:56 ` [PATCH v2 5/7] cifs: Improve guard for excluding $LXDEV xattr Pali Rohár
@ 2024-10-12 8:56 ` Pali Rohár
2024-10-12 8:56 ` [PATCH v2 7/7] cifs: Validate content of WSL reparse point buffers Pali Rohár
` (2 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:56 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
This change implements support for creating new symlink in WSL-style by
Linux cifs client when -o reparse=wsl mount option is specified. WSL-style
symlink uses reparse point with tag IO_REPARSE_TAG_LX_SYMLINK and symlink
target location is stored in reparse buffer in UTF-8 encoding prefixed by
32-bit flags. Flags bits are unknown, but it was observed that WSL always
sets flags to value 0x02000000. Do same in Linux cifs client.
New symlinks would be created in WSL-style only in case the mount option
-o reparse=wsl is specified, which is not by default. So default CIFS
mounts are not affected by this change.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/reparse.c | 65 +++++++++++++++++++++++++++++++++--------
1 file changed, 53 insertions(+), 12 deletions(-)
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 50048dccc5ff..b9a50eb03522 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -502,9 +502,17 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
return rc;
}
-static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
- mode_t mode, struct kvec *iov)
+static int wsl_set_reparse_buf(struct reparse_data_buffer **buf,
+ mode_t mode, const char *symname,
+ struct cifs_sb_info *cifs_sb,
+ struct kvec *iov)
{
+ struct reparse_wsl_symlink_data_buffer *symlink_buf;
+ __le16 *symname_utf16;
+ int symname_utf16_len;
+ int symname_utf8_maxlen;
+ int symname_utf8_len;
+ size_t buf_len;
u32 tag;
switch ((tag = reparse_mode_wsl_tag(mode))) {
@@ -512,17 +520,45 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_CHR:
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_AF_UNIX:
+ buf_len = sizeof(struct reparse_data_buffer);
+ *buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+ break;
+ case IO_REPARSE_TAG_LX_SYMLINK:
+ symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname),
+ &symname_utf16_len,
+ cifs_sb->local_nls,
+ NO_MAP_UNI_RSVD);
+ if (!symname_utf16)
+ return -ENOMEM;
+ symname_utf8_maxlen = symname_utf16_len/2*3;
+ symlink_buf = kzalloc(sizeof(struct reparse_wsl_symlink_data_buffer) +
+ symname_utf8_maxlen, GFP_KERNEL);
+ if (!symlink_buf) {
+ kfree(symname_utf16);
+ return -ENOMEM;
+ }
+ /* Flag 0x02000000 is unknown, but all wsl symlinks have this value */
+ symlink_buf->Flags = cpu_to_le32(0x02000000);
+ /* PathBuffer is in UTF-8 but without trailing null-term byte */
+ symname_utf8_len = utf16s_to_utf8s(symname_utf16, symname_utf16_len/2,
+ UTF16_LITTLE_ENDIAN,
+ symlink_buf->PathBuffer,
+ symname_utf8_maxlen);
+ *buf = (struct reparse_data_buffer *)symlink_buf;
+ buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len;
+ kfree(symname_utf16);
break;
- case IO_REPARSE_TAG_LX_SYMLINK: /* TODO: add support for WSL symlinks */
default:
return -EOPNOTSUPP;
}
- buf->ReparseTag = cpu_to_le32(tag);
- buf->Reserved = 0;
- buf->ReparseDataLength = 0;
- iov->iov_base = buf;
- iov->iov_len = sizeof(*buf);
+ (*buf)->ReparseTag = cpu_to_le32(tag);
+ (*buf)->Reserved = 0;
+ (*buf)->ReparseDataLength = cpu_to_le16(buf_len - sizeof(struct reparse_data_buffer));
+ iov->iov_base = *buf;
+ iov->iov_len = buf_len;
return 0;
}
@@ -614,25 +650,29 @@ static int mknod_wsl(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_data_buffer buf;
+ struct reparse_data_buffer *buf;
struct smb2_create_ea_ctx *cc;
struct inode *new;
unsigned int len;
struct kvec reparse_iov, xattr_iov;
int rc;
- rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov);
+ rc = wsl_set_reparse_buf(&buf, mode, symname, cifs_sb, &reparse_iov);
if (rc)
return rc;
rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov);
- if (rc)
+ if (rc) {
+ kfree(buf);
return rc;
+ }
data = (struct cifs_open_info_data) {
.reparse_point = true,
- .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
+ .reparse = { .tag = le32_to_cpu(buf->ReparseTag), .buf = buf, },
+ .symlink_target = kstrdup(symname, GFP_KERNEL),
};
cc = xattr_iov.iov_base;
@@ -649,6 +689,7 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
rc = PTR_ERR(new);
cifs_free_open_info(&data);
kfree(xattr_iov.iov_base);
+ kfree(buf);
return rc;
}
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 7/7] cifs: Validate content of WSL reparse point buffers
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
` (5 preceding siblings ...)
2024-10-12 8:56 ` [PATCH v2 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
@ 2024-10-12 8:56 ` Pali Rohár
[not found] ` <CAH2r5mtGqqM35Cy5k9NN=X05rTZPk-adhb7LgoV8PGNVL9P6FQ@mail.gmail.com>
2024-10-28 10:13 ` Pali Rohár
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-12 8:56 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
WSL socket, fifo, char and block devices have empty reparse buffer.
Validate the length of the reparse buffer.
Signed-off-by: Pali Rohár <pali@kernel.org>
---
fs/smb/client/reparse.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index b9a50eb03522..3de91331c96c 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -1083,6 +1083,11 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
case IO_REPARSE_TAG_LX_FIFO:
case IO_REPARSE_TAG_LX_CHR:
case IO_REPARSE_TAG_LX_BLK:
+ if (le16_to_cpu(buf->ReparseDataLength) != 0) {
+ cifs_dbg(VFS, "srv returned malformed buffer for reparse point: 0x%08x\n",
+ le32_to_cpu(buf->ReparseTag));
+ return -EIO;
+ }
break;
default:
cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
--
2.20.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Fwd: [PATCH v2 0/7] Allow to choose symlink and socket type
[not found] ` <CAH2r5mtGqqM35Cy5k9NN=X05rTZPk-adhb7LgoV8PGNVL9P6FQ@mail.gmail.com>
@ 2024-10-13 4:19 ` Steve French
2024-10-13 8:59 ` Pali Rohár
2024-10-13 13:38 ` Pali Rohár
2 siblings, 0 replies; 29+ messages in thread
From: Steve French @ 2024-10-13 4:19 UTC (permalink / raw)
To: CIFS, LKML
after doing more experiments with native windows symlinks (and how
difficult it is to get permission to set them over the wire to
Windows), was wondering if we should allow fall back strategy if
creating windows style symlinks fails with STATUS_PRIVILEGE_NOT_HELD
then we should try NFS reparse point symlink. Any opinions?
On Sat, Oct 12, 2024 at 3:53 AM Pali Rohár <pali@kernel.org> wrote:
>
> This patch series improves choosing reparse format when creating new
> special files.
>
> Changes since v1:
> * Instead of new -o reparse= mount option is now a new -o symlink= mount
> option for choosing symlink type during creation, and new option
> -o nonativesocket for choosing socket type
>
> Pali Rohár (7):
> cifs: Add mount option -o symlink= for choosing symlink create type
> cifs: Add mount option -o reparse=none
> cifs: Add support for creating native Windows sockets
> cifs: Add support for creating NFS-style symlinks
> cifs: Improve guard for excluding $LXDEV xattr
> cifs: Add support for creating WSL-style symlinks
> cifs: Validate content of WSL reparse point buffers
>
> fs/smb/client/cifsfs.c | 4 +
> fs/smb/client/cifsglob.h | 36 +++++++
> fs/smb/client/connect.c | 4 +
> fs/smb/client/fs_context.c | 82 +++++++++++++++
> fs/smb/client/fs_context.h | 19 ++++
> fs/smb/client/link.c | 60 ++++++++---
> fs/smb/client/reparse.c | 201 +++++++++++++++++++++++++++++++------
> fs/smb/client/reparse.h | 2 +
> 8 files changed, 364 insertions(+), 44 deletions(-)
>
> --
> 2.20.1
>
>
--
Thanks,
Steve
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 0/7] Allow to choose symlink and socket type
[not found] ` <CAH2r5mtGqqM35Cy5k9NN=X05rTZPk-adhb7LgoV8PGNVL9P6FQ@mail.gmail.com>
2024-10-13 4:19 ` Fwd: [PATCH v2 0/7] Allow to choose symlink and socket type Steve French
@ 2024-10-13 8:59 ` Pali Rohár
2024-10-13 13:38 ` Pali Rohár
2 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-13 8:59 UTC (permalink / raw)
To: Steve French
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
Well, if server explicitly disallow user to create symlink due to
missing permissions, I am not sure if it is a good idea to obey it by
creating symlink in format unsupported by the server...
On Saturday 12 October 2024 23:18:13 Steve French wrote:
> after doing more experiments with native windows symlinks (and how
> difficult it is to get permission to set them over the wire to Windows),
> was wondering if we should allow fall back strategy if creating windows
> style symlinks fails with STATUS_PRIVILEGE_NOT_HELD then we should try NFS
> reparse point symlink. Any opinions?
>
> On Sat, Oct 12, 2024 at 3:53 AM Pali Rohár <pali@kernel.org> wrote:
>
> > This patch series improves choosing reparse format when creating new
> > special files.
> >
> > Changes since v1:
> > * Instead of new -o reparse= mount option is now a new -o symlink= mount
> > option for choosing symlink type during creation, and new option
> > -o nonativesocket for choosing socket type
> >
> > Pali Rohár (7):
> > cifs: Add mount option -o symlink= for choosing symlink create type
> > cifs: Add mount option -o reparse=none
> > cifs: Add support for creating native Windows sockets
> > cifs: Add support for creating NFS-style symlinks
> > cifs: Improve guard for excluding $LXDEV xattr
> > cifs: Add support for creating WSL-style symlinks
> > cifs: Validate content of WSL reparse point buffers
> >
> > fs/smb/client/cifsfs.c | 4 +
> > fs/smb/client/cifsglob.h | 36 +++++++
> > fs/smb/client/connect.c | 4 +
> > fs/smb/client/fs_context.c | 82 +++++++++++++++
> > fs/smb/client/fs_context.h | 19 ++++
> > fs/smb/client/link.c | 60 ++++++++---
> > fs/smb/client/reparse.c | 201 +++++++++++++++++++++++++++++++------
> > fs/smb/client/reparse.h | 2 +
> > 8 files changed, 364 insertions(+), 44 deletions(-)
> >
> > --
> > 2.20.1
> >
> >
> >
>
> --
> Thanks,
>
> Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 0/7] Allow to choose symlink and socket type
[not found] ` <CAH2r5mtGqqM35Cy5k9NN=X05rTZPk-adhb7LgoV8PGNVL9P6FQ@mail.gmail.com>
2024-10-13 4:19 ` Fwd: [PATCH v2 0/7] Allow to choose symlink and socket type Steve French
2024-10-13 8:59 ` Pali Rohár
@ 2024-10-13 13:38 ` Pali Rohár
2024-10-14 9:32 ` Pali Rohár
2 siblings, 1 reply; 29+ messages in thread
From: Pali Rohár @ 2024-10-13 13:38 UTC (permalink / raw)
To: Steve French
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
Anyway, I think that the create symlink privilege is needed to create
any reparse point, so fallback to NFS reparse point would not help.
On Saturday 12 October 2024 23:18:13 Steve French wrote:
> after doing more experiments with native windows symlinks (and how
> difficult it is to get permission to set them over the wire to Windows),
> was wondering if we should allow fall back strategy if creating windows
> style symlinks fails with STATUS_PRIVILEGE_NOT_HELD then we should try NFS
> reparse point symlink. Any opinions?
>
> On Sat, Oct 12, 2024 at 3:53 AM Pali Rohár <pali@kernel.org> wrote:
>
> > This patch series improves choosing reparse format when creating new
> > special files.
> >
> > Changes since v1:
> > * Instead of new -o reparse= mount option is now a new -o symlink= mount
> > option for choosing symlink type during creation, and new option
> > -o nonativesocket for choosing socket type
> >
> > Pali Rohár (7):
> > cifs: Add mount option -o symlink= for choosing symlink create type
> > cifs: Add mount option -o reparse=none
> > cifs: Add support for creating native Windows sockets
> > cifs: Add support for creating NFS-style symlinks
> > cifs: Improve guard for excluding $LXDEV xattr
> > cifs: Add support for creating WSL-style symlinks
> > cifs: Validate content of WSL reparse point buffers
> >
> > fs/smb/client/cifsfs.c | 4 +
> > fs/smb/client/cifsglob.h | 36 +++++++
> > fs/smb/client/connect.c | 4 +
> > fs/smb/client/fs_context.c | 82 +++++++++++++++
> > fs/smb/client/fs_context.h | 19 ++++
> > fs/smb/client/link.c | 60 ++++++++---
> > fs/smb/client/reparse.c | 201 +++++++++++++++++++++++++++++++------
> > fs/smb/client/reparse.h | 2 +
> > 8 files changed, 364 insertions(+), 44 deletions(-)
> >
> > --
> > 2.20.1
> >
> >
> >
>
> --
> Thanks,
>
> Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 0/7] Allow to choose symlink and socket type
2024-10-13 13:38 ` Pali Rohár
@ 2024-10-14 9:32 ` Pali Rohár
0 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-14 9:32 UTC (permalink / raw)
To: Steve French
Cc: Steve French, Paulo Alcantara, Ronnie Sahlberg, linux-cifs,
linux-kernel
Now I found this statement in FSCTL_SET_REPARSE_POINT documentation:
https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-fsctl_set_reparse_point
"FSCTL_SET_REPARSE_POINT IOCTL - Sets a reparse point on a file or directory."
"The calling process must have the SE_CREATE_SYMBOLIC_LINK_NAME privilege."
On Sunday 13 October 2024 15:38:27 Pali Rohár wrote:
> Anyway, I think that the create symlink privilege is needed to create
> any reparse point, so fallback to NFS reparse point would not help.
>
> On Saturday 12 October 2024 23:18:13 Steve French wrote:
> > after doing more experiments with native windows symlinks (and how
> > difficult it is to get permission to set them over the wire to Windows),
> > was wondering if we should allow fall back strategy if creating windows
> > style symlinks fails with STATUS_PRIVILEGE_NOT_HELD then we should try NFS
> > reparse point symlink. Any opinions?
> >
> > On Sat, Oct 12, 2024 at 3:53 AM Pali Rohár <pali@kernel.org> wrote:
> >
> > > This patch series improves choosing reparse format when creating new
> > > special files.
> > >
> > > Changes since v1:
> > > * Instead of new -o reparse= mount option is now a new -o symlink= mount
> > > option for choosing symlink type during creation, and new option
> > > -o nonativesocket for choosing socket type
> > >
> > > Pali Rohár (7):
> > > cifs: Add mount option -o symlink= for choosing symlink create type
> > > cifs: Add mount option -o reparse=none
> > > cifs: Add support for creating native Windows sockets
> > > cifs: Add support for creating NFS-style symlinks
> > > cifs: Improve guard for excluding $LXDEV xattr
> > > cifs: Add support for creating WSL-style symlinks
> > > cifs: Validate content of WSL reparse point buffers
> > >
> > > fs/smb/client/cifsfs.c | 4 +
> > > fs/smb/client/cifsglob.h | 36 +++++++
> > > fs/smb/client/connect.c | 4 +
> > > fs/smb/client/fs_context.c | 82 +++++++++++++++
> > > fs/smb/client/fs_context.h | 19 ++++
> > > fs/smb/client/link.c | 60 ++++++++---
> > > fs/smb/client/reparse.c | 201 +++++++++++++++++++++++++++++++------
> > > fs/smb/client/reparse.h | 2 +
> > > 8 files changed, 364 insertions(+), 44 deletions(-)
> > >
> > > --
> > > 2.20.1
> > >
> > >
> > >
> >
> > --
> > Thanks,
> >
> > Steve
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 0/7] Allow to choose symlink and socket type
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
` (7 preceding siblings ...)
[not found] ` <CAH2r5mtGqqM35Cy5k9NN=X05rTZPk-adhb7LgoV8PGNVL9P6FQ@mail.gmail.com>
@ 2024-10-28 10:13 ` Pali Rohár
8 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-10-28 10:13 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
Any opinion about this v2? Is it better now?
On Saturday 12 October 2024 10:52:45 Pali Rohár wrote:
> This patch series improves choosing reparse format when creating new
> special files.
>
> Changes since v1:
> * Instead of new -o reparse= mount option is now a new -o symlink= mount
> option for choosing symlink type during creation, and new option
> -o nonativesocket for choosing socket type
>
> Pali Rohár (7):
> cifs: Add mount option -o symlink= for choosing symlink create type
> cifs: Add mount option -o reparse=none
> cifs: Add support for creating native Windows sockets
> cifs: Add support for creating NFS-style symlinks
> cifs: Improve guard for excluding $LXDEV xattr
> cifs: Add support for creating WSL-style symlinks
> cifs: Validate content of WSL reparse point buffers
>
> fs/smb/client/cifsfs.c | 4 +
> fs/smb/client/cifsglob.h | 36 +++++++
> fs/smb/client/connect.c | 4 +
> fs/smb/client/fs_context.c | 82 +++++++++++++++
> fs/smb/client/fs_context.h | 19 ++++
> fs/smb/client/link.c | 60 ++++++++---
> fs/smb/client/reparse.c | 201 +++++++++++++++++++++++++++++++------
> fs/smb/client/reparse.h | 2 +
> 8 files changed, 364 insertions(+), 44 deletions(-)
>
> --
> 2.20.1
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks
2024-10-12 8:56 ` [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
@ 2024-12-09 18:00 ` Pali Rohár
0 siblings, 0 replies; 29+ messages in thread
From: Pali Rohár @ 2024-12-09 18:00 UTC (permalink / raw)
To: Steve French, Paulo Alcantara, Ronnie Sahlberg; +Cc: linux-cifs, linux-kernel
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@kernel.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;
^ permalink raw reply related [flat|nested] 29+ messages in thread
end of thread, other threads:[~2024-12-09 18:01 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-06 10:00 [PATCH 0/7] cifs: Improve mount option -o reparse and support for native Windows sockets Pali Rohár
2024-10-06 10:00 ` [PATCH 1/7] cifs: Add mount option -o reparse=native Pali Rohár
2024-10-07 4:28 ` Steve French
2024-10-07 18:36 ` Pali Rohár
[not found] ` <CAH2r5mttO-aDq94QrLQm10xJRGLg=PULqX9fcfoykAweVVO+uQ@mail.gmail.com>
2024-10-10 22:21 ` Steve French
2024-10-10 22:38 ` Pali Rohár
[not found] ` <CAH2r5msEiD05ehJs_a05sP_rX7BkVH-9LZp8Sj6EFbpZA9bfrg@mail.gmail.com>
2024-10-10 22:44 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 2/7] cifs: Add mount option -o reparse=none Pali Rohár
2024-10-06 10:00 ` [PATCH 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
2024-10-10 21:47 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
2024-10-06 10:00 ` [PATCH 5/7] cifs: Improve guard for excluding $LXDEV xattr Pali Rohár
2024-10-06 10:00 ` [PATCH 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
2024-10-10 21:50 ` Pali Rohár
2024-10-06 10:00 ` [PATCH 7/7] cifs: Validate content of WSL reparse point buffers Pali Rohár
2024-10-12 8:52 ` [PATCH v2 0/7] Allow to choose symlink and socket type Pali Rohár
2024-10-12 8:55 ` [PATCH v2 1/7] cifs: Add mount option -o symlink= for choosing symlink create type Pali Rohár
2024-10-12 8:55 ` [PATCH v2 2/7] cifs: Add mount option -o reparse=none Pali Rohár
2024-10-12 8:55 ` [PATCH v2 3/7] cifs: Add support for creating native Windows sockets Pali Rohár
2024-10-12 8:56 ` [PATCH v2 4/7] cifs: Add support for creating NFS-style symlinks Pali Rohár
2024-12-09 18:00 ` Pali Rohár
2024-10-12 8:56 ` [PATCH v2 5/7] cifs: Improve guard for excluding $LXDEV xattr Pali Rohár
2024-10-12 8:56 ` [PATCH v2 6/7] cifs: Add support for creating WSL-style symlinks Pali Rohár
2024-10-12 8:56 ` [PATCH v2 7/7] cifs: Validate content of WSL reparse point buffers Pali Rohár
[not found] ` <CAH2r5mtGqqM35Cy5k9NN=X05rTZPk-adhb7LgoV8PGNVL9P6FQ@mail.gmail.com>
2024-10-13 4:19 ` Fwd: [PATCH v2 0/7] Allow to choose symlink and socket type Steve French
2024-10-13 8:59 ` Pali Rohár
2024-10-13 13:38 ` Pali Rohár
2024-10-14 9:32 ` Pali Rohár
2024-10-28 10:13 ` Pali Rohár
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox