[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAH2r5mveXNenpP48_8Joer2u1R14-z2-rY03guGZpoc6D9QviA@mail.gmail.com>
Date: Fri, 27 Jun 2025 17:45:58 -0500
From: Steve French <smfrench@...il.com>
To: Pali Rohár <pali@...nel.org>
Cc: Paulo Alcantara <pc@...guebit.org>, Remy Monsen <monsen@...sen.cc>, linux-cifs@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: Re: [PATCH] cifs: Fix lstat() and AT_SYMLINK_NOFOLLOW to work on
broken symlink nodes
Looks like Paulo's fix ("smb: client: fix regression with native SMB
symlinks") which has been in for-next for a while with no issues in
testing etc. does fix the regression.
I did verify that the simple act of creating symlink (e.g. to some UNC
name) on Windows and trying to do an "ls -l" or "stat" or "cp" does
regress without his patch and with his patch behaves as expected (e.g.
if you went to linux and created a symlink to "filethatdoesnotexist"
then with his patch the behavior for stat, cp, cp --no-dereference and
ls -l is the same for bad target on ext4 mounts locally as it is for
bad target on smb3 mount to Windows)
There may be ways to address corner cases in the future - but it does
clearly address the regression, and for those four operations (stat,
cp, cp --no-dereference and ls -l) now behaves as expected when you
have an unresolvable target path of a symlink.
Don't mind discussing a followon patch to address more corner cases
but his patch looks fine and multiple people have tried it and looked
at (not just me) so should be upstream soon
On Fri, Jun 27, 2025 at 4:03 PM Pali Rohár <pali@...nel.org> wrote:
>
> So what would be the next steps here?
>
> On Saturday 21 June 2025 18:52:46 Pali Rohár wrote:
> > On Saturday 21 June 2025 12:38:34 Paulo Alcantara wrote:
> > > Pali Rohár <pali@...nel.org> writes:
> > >
> > > > On Friday 20 June 2025 20:44:37 Paulo Alcantara wrote:
> > > >> Pali Rohár <pali@...nel.org> writes:
> > > >>
> > > >> > Currently Linux SMB client returns EIO for lstat() and AT_SYMLINK_NOFOLLOW
> > > >> > calls on symlink node when the symlink target location is broken or cannot
> > > >> > be read or parsed.
> > > >> >
> > > >> > Fix this problem by relaxing the errors from various locations which parses
> > > >> > information about symlink file node (UNIX SMB1, native SMB2+, NFS-style,
> > > >> > WSL-style) and let readlink() syscall to return EIO when the symlink target
> > > >> > location is not available.
> > > >>
> > > >> Please, don't. We still want those validations for the other types of
> > > >> symlinks.
> > > >
> > > > Well, validation was not removed. Validation is still there, just the
> > > > error is signalled by the readlink() syscall instead of the lstat() or
> > > > AT_SYMLINK_NOFOLLOW syscalls.
> > > >
> > > > My opinion is that the lstat() or AT_SYMLINK_NOFOLLOW should work on
> > > > symlink node independently of where the symlink points (and whether the
> > > > symlink target is valid POSIX path or not). That is because the lstat()
> > > > and AT_SYMLINK_NOFOLLOW says that the symlink target location must not
> > > > be used and must not be resolved.
> > > >
> > > > But still the invalid / incorrect / broken or non-representable symlink
> > > > target path in POSIX notation should be reported as an issue and the
> > > > readlink() is the correct syscall which should report these errors.
> > >
> > > The only issue is breaking existing customer or user applications that
> > > really don't care if cifs.ko could follow those kind of symlinks.
> > >
> > > Samba create symlinks to represent DFS links with targets like
> > > 'msdfs:srv1\share,srv2\share', which are not valid POSIX paths. Does
> > > that mean the filesystem should not allow readlink(2) to succeed just
> > > because it is not a valid POSIX path? Is that what you mean?
> >
> > But this is something totally different thing.
> >
> > Here you are referring to the behavior of Samba server, which interprets
> > symlink node stored on local filesystem named e.g. "link1" pointing to
> > target relative file name 'msdfs:srv1\share,srv2\share' specially.
> >
> > Calling "ln -s 'msdfs:srv1\share,srv2\share' link1" is perfectly fine on
> > the ext4 filesystem. It creates a relative symlink to the specified
> > file.
> >
> > And if you call "echo test > 'msdfs:srv1\share,srv2\share'" then it would
> > world correctly and "cat link1" will print "test".
> >
> > The 'msdfs:srv1\share,srv2\share' is a valid POSIX path and it is stored
> > on the local Linux filesystem. So I do not see anything wrong with it or
> > reason why local filesystem should disallow creating such symlink or why
> > would realink() should fail on such node.
> >
> >
> > That example has nothing with symlinks stored on NTFS-compatible
> > filesystems which has ability to store symlinks pointing to non-POSIX
> > NT object model paths.
> >
> > Here the issue is with symlink target locations which are coming from
> > the remote NT server and are pointing to location which cannot be
> > directly represented by the Linux system. The translation needs to be
> > done in both directions and reversible. Otherwise moving the file or
> > symlink from cifs to ext4 and back would damage the file or symlink.
> >
> > > >> The problem is just that cifs.ko can't handle absolute
> > > >> symlink targets in the form of '\??\UNC\srv\share\foo', while Windows
> > > >> client can. They are still valid symlink targets, but cifs.ko doesn't
> > > >> know how to follow them.
> > > >
> > > > Windows client can represent and follow such symlink because the symlink
> > > > is in the NT style format and Windows kernel uses NT style of paths
> > > > internally. Linux kernel uses POSIX paths and POSIX does not contain any
> > > > GLOBAL?? namespace for NT object hierarchy.
> > > >
> > > > Leaking raw NT object hierarchy from SMB to POSIX userspace via
> > > > readlink() syscall is a bad idea. Applications are really not expecting
> > > > that the readlink() syscall will return NT kernel internals (exported
> > > > over SMB protocol and passed to cifs.ko).
> > > >
> > > > For UNC paths encoded in NT object hierarchy, which is just some subset
> > > > of all possible NT paths, I had an idea that we could convert these
> > > > paths to some format like:
> > > >
> > > > <prefix>/server/share/path...
> > > >
> > > > Where <prefix> would be specified by the string mount option. So user
> > > > could say that wants all UNC symlinks pointing to /mnt/unc/.
> > > >
> > > > And in the same way if user would want to create symlink pointing to
> > > > /mnt/unc/server/share/path... then cifs.ko will transform it into valid
> > > > NT UNC path and create a symlink to this location.
> > >
> > > That's really a terrible idea. The symlink targets in the form of
> > > '\??\UNC\...' could be resolved by cifs.ko. The ones that refer to a
> > > file outside the mounted share, we would set those as automounts.
> >
> > I agree that above is not the best idea, but I wrote at least something
> > as an idea as I do not know how it could be solved in better way.
> >
> > And I do not see how it could be resolved by cifs.ko somehow
> > automatically. I'm not sure to which you refer how it can be resolved by
> > cifs.ko. I understood you message as it could automount another share
> > and do the whole path symlink resolving in cifs.ko.
> >
> > And I think that this is even worse idea than mine. Because that
> > automount means that symlinks pointing outside of the share would start
> > behaving like a mount point. Such thing can cause even a security issues
> > if not used carefully.
> >
> > But moreover there is a big difference between symlink and mount point.
> > Symlinks are not resolved by filesystem itself (but rather by the VFS,
> > to ensure that all access checks are applied) and also moving the
> > symlink between filesystems should not break them. In this idea when the
> > symlink is going to be moved from smb share to e.g. ext4 local fs, then
> > it would stops working (if the path resolved is in the cifs.ko) as
> > ext4.ko would not be able to process special cifs.ko symlinks.
> >
> > > > But this would solve only problem with UNC symlink, not symlinks
> > > > pointing to NT object hierarchy in general.
> > > >
> > > >> The following should do it and then restore old behavior
> > > >>
> > > >> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> > > >> index bb25e77c5540..11d44288e75a 100644
> > > >> --- a/fs/smb/client/reparse.c
> > > >> +++ b/fs/smb/client/reparse.c
> > > >> @@ -875,15 +875,8 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> > > >> abs_path += sizeof("\\DosDevices\\")-1;
> > > >> else if (strstarts(abs_path, "\\GLOBAL??\\"))
> > > >> abs_path += sizeof("\\GLOBAL??\\")-1;
> > > >> - else {
> > > >> - /* Unhandled absolute symlink, points outside of DOS/Win32 */
> > > >> - cifs_dbg(VFS,
> > > >> - "absolute symlink '%s' cannot be converted from NT format "
> > > >> - "because points to unknown target\n",
> > > >> - smb_target);
> > > >> - rc = -EIO;
> > > >> - goto out;
> > > >> - }
> > > >> + else
> > > >> + goto out_unhandled_target;
> > > >>
> > > >> /* Sometimes path separator after \?? is double backslash */
> > > >> if (abs_path[0] == '\\')
> > > >> @@ -910,13 +903,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> > > >> abs_path++;
> > > >> abs_path[0] = drive_letter;
> > > >> } else {
> > > >> - /* Unhandled absolute symlink. Report an error. */
> > > >> - cifs_dbg(VFS,
> > > >> - "absolute symlink '%s' cannot be converted from NT format "
> > > >> - "because points to unknown target\n",
> > > >> - smb_target);
> > > >> - rc = -EIO;
> > > >> - goto out;
> > > >> + goto out_unhandled_target;
> > > >> }
> > > >>
> > > >> abs_path_len = strlen(abs_path)+1;
> > > >> @@ -966,6 +953,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> > > >> * These paths have same format as Linux symlinks, so no
> > > >> * conversion is needed.
> > > >> */
> > > >> +out_unhandled_target:
> > > >> linux_target = smb_target;
> > > >> smb_target = NULL;
> > > >> }
> > > >
> > > > I'm really not sure if removing the messages and error reporting about
> > > > symlinks which cannot be represented in POSIX system is a good idea.
> > >
> > > Those messages are just useless and noisy. Do you think it's useful
> > > printing that message for _every_ symlink when someone is calling
> > > readdir(2) in a directory that contain such files?
> >
> > I though that for any debugging purposes these messages are useful.
> > Now I see that VFS level is printed always, so maybe the FYI level could
> > be better. Or do you really think that it is useless even for debugging?
>
--
Thanks,
Steve
Powered by blists - more mailing lists