diff mbox series

[6/7] cifs: Validate content of native symlink

Message ID 20240929185053.10554-7-pali@kernel.org (mailing list archive)
State New, archived
Headers show
Series cifs: Improve support for native SMB symlinks | expand

Commit Message

Pali Rohár Sept. 29, 2024, 6:50 p.m. UTC
Check that buffer does not contain UTF-16 null codepoint
because Linux cannot process symlink with null byte.

Signed-off-by: Pali Rohár <pali@kernel.org>
---
 fs/smb/client/reparse.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

Comments

Steve French Sept. 29, 2024, 9:48 p.m. UTC | #1
Is there any easy way to create such a symlink (with null in it)?

On Sun, Sep 29, 2024 at 1:51 PM Pali Rohár <pali@kernel.org> wrote:
>
> Check that buffer does not contain UTF-16 null codepoint
> because Linux cannot process symlink with null byte.
>
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
>  fs/smb/client/reparse.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> index 5a738f65b190..ca4f96c43508 100644
> --- a/fs/smb/client/reparse.c
> +++ b/fs/smb/client/reparse.c
> @@ -509,6 +509,16 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
>         int rc;
>         int i;
>
> +       /*
> +        * Check that buffer does not contain UTF-16 null codepoint
> +        * because Linux cannot process symlink with null byte.
> +        */
> +       if (unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) {
> +               cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
> +               rc = -EIO;
> +               goto out;
> +       }
> +
>         smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls);
>         if (!smb_target) {
>                 rc = -ENOMEM;
> --
> 2.20.1
>
>
Pali Rohár Sept. 29, 2024, 10:19 p.m. UTC | #2
I think that via pike it could be possible or via windows application
running locally (to create reparse point manually with prepared buffer
with such content). I will check it later.

Just a side note: Windows NT kernel allows for object names any
characters except backslash. For object names is not used nul-term
string, but rather string with explicit length. So even a null character
is a valid in a object name. NT NTFS driver has for file names more
restrictions and null is not valid. But it does not mean that somebody
can write own filesystem which allows null bytes in file names...
And this design of explicit lengths is also in SMB, so NT kernel may
export nul characters in symlink path buffers...

On Sunday 29 September 2024 16:48:46 Steve French wrote:
> Is there any easy way to create such a symlink (with null in it)?
> 
> On Sun, Sep 29, 2024 at 1:51 PM Pali Rohár <pali@kernel.org> wrote:
> >
> > Check that buffer does not contain UTF-16 null codepoint
> > because Linux cannot process symlink with null byte.
> >
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > ---
> >  fs/smb/client/reparse.c | 10 ++++++++++
> >  1 file changed, 10 insertions(+)
> >
> > diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> > index 5a738f65b190..ca4f96c43508 100644
> > --- a/fs/smb/client/reparse.c
> > +++ b/fs/smb/client/reparse.c
> > @@ -509,6 +509,16 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> >         int rc;
> >         int i;
> >
> > +       /*
> > +        * Check that buffer does not contain UTF-16 null codepoint
> > +        * because Linux cannot process symlink with null byte.
> > +        */
> > +       if (unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) {
> > +               cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
> > +               rc = -EIO;
> > +               goto out;
> > +       }
> > +
> >         smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls);
> >         if (!smb_target) {
> >                 rc = -ENOMEM;
> > --
> > 2.20.1
> >
> >
> 
> 
> -- 
> Thanks,
> 
> Steve
Pali Rohár Sept. 30, 2024, 8 p.m. UTC | #3
Now I tested it. FSCTL_SET_REPARSE_POINT ioctl call on Windows accepts
also symlink path with zero characters. In attachment I'm sending simple
program which creates Windows relative symlink and accepts binary target
path via \xFF sequence. You can compile it with gcc/mingw option -municode.
So calling "set_reparse_symlink.exe symlink file\x00file" creates new
symlink which points to target path "file<nul>file".

On Monday 30 September 2024 00:19:08 Pali Rohár wrote:
> I think that via pike it could be possible or via windows application
> running locally (to create reparse point manually with prepared buffer
> with such content). I will check it later.
> 
> Just a side note: Windows NT kernel allows for object names any
> characters except backslash. For object names is not used nul-term
> string, but rather string with explicit length. So even a null character
> is a valid in a object name. NT NTFS driver has for file names more
> restrictions and null is not valid. But it does not mean that somebody
> can write own filesystem which allows null bytes in file names...
> And this design of explicit lengths is also in SMB, so NT kernel may
> export nul characters in symlink path buffers...
> 
> On Sunday 29 September 2024 16:48:46 Steve French wrote:
> > Is there any easy way to create such a symlink (with null in it)?
> > 
> > On Sun, Sep 29, 2024 at 1:51 PM Pali Rohár <pali@kernel.org> wrote:
> > >
> > > Check that buffer does not contain UTF-16 null codepoint
> > > because Linux cannot process symlink with null byte.
> > >
> > > Signed-off-by: Pali Rohár <pali@kernel.org>
> > > ---
> > >  fs/smb/client/reparse.c | 10 ++++++++++
> > >  1 file changed, 10 insertions(+)
> > >
> > > diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> > > index 5a738f65b190..ca4f96c43508 100644
> > > --- a/fs/smb/client/reparse.c
> > > +++ b/fs/smb/client/reparse.c
> > > @@ -509,6 +509,16 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
> > >         int rc;
> > >         int i;
> > >
> > > +       /*
> > > +        * Check that buffer does not contain UTF-16 null codepoint
> > > +        * because Linux cannot process symlink with null byte.
> > > +        */
> > > +       if (unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) {
> > > +               cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
> > > +               rc = -EIO;
> > > +               goto out;
> > > +       }
> > > +
> > >         smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls);
> > >         if (!smb_target) {
> > >                 rc = -ENOMEM;
> > > --
> > > 2.20.1
> > >
> > >
> > 
> > 
> > -- 
> > Thanks,
> > 
> > Steve
diff mbox series

Patch

diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index 5a738f65b190..ca4f96c43508 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -509,6 +509,16 @@  int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
 	int rc;
 	int i;
 
+	/*
+	 * Check that buffer does not contain UTF-16 null codepoint
+	 * because Linux cannot process symlink with null byte.
+	 */
+	if (unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) {
+		cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
+		rc = -EIO;
+		goto out;
+	}
+
 	smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls);
 	if (!smb_target) {
 		rc = -ENOMEM;