diff mbox series

ksmbd: Use unsafe_memcpy() for ntlm_negotiate

Message ID 20240814235635.7998-1-linkinjeon@kernel.org (mailing list archive)
State New, archived
Headers show
Series ksmbd: Use unsafe_memcpy() for ntlm_negotiate | expand

Commit Message

Namjae Jeon Aug. 14, 2024, 11:56 p.m. UTC
rsp buffer is allocatged larger than spnego_blob from
smb2_allocate_rsp_buf().

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
---
 fs/smb/server/smb2pdu.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Comments

Steve French Aug. 15, 2024, 3:14 a.m. UTC | #1
This fixed the 'field spanning write' warnings for me.

merged into ksmbd-for-next



On Wed, Aug 14, 2024 at 6:56 PM Namjae Jeon <linkinjeon@kernel.org> wrote:
>
> rsp buffer is allocatged larger than spnego_blob from
> smb2_allocate_rsp_buf().
>
> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
> ---
>  fs/smb/server/smb2pdu.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> index 2df1354288e6..3f4c56a10a86 100644
> --- a/fs/smb/server/smb2pdu.c
> +++ b/fs/smb/server/smb2pdu.c
> @@ -1370,7 +1370,8 @@ static int ntlm_negotiate(struct ksmbd_work *work,
>         }
>
>         sz = le16_to_cpu(rsp->SecurityBufferOffset);
> -       memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> +       unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len,
> +                       /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
>         rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
>
>  out:
> @@ -1453,7 +1454,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,
>                         return -ENOMEM;
>
>                 sz = le16_to_cpu(rsp->SecurityBufferOffset);
> -               memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> +               unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob,
> +                               spnego_blob_len,
> +                               /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
>                 rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
>                 kfree(spnego_blob);
>         }
> --
> 2.25.1
>
Kees Cook Sept. 22, 2024, 11:12 p.m. UTC | #2
On Thu, Aug 15, 2024 at 08:56:35AM +0900, Namjae Jeon wrote:
> rsp buffer is allocatged larger than spnego_blob from
> smb2_allocate_rsp_buf().
> 
> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
> ---
>  fs/smb/server/smb2pdu.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> index 2df1354288e6..3f4c56a10a86 100644
> --- a/fs/smb/server/smb2pdu.c
> +++ b/fs/smb/server/smb2pdu.c
> @@ -1370,7 +1370,8 @@ static int ntlm_negotiate(struct ksmbd_work *work,
>  	}
>  
>  	sz = le16_to_cpu(rsp->SecurityBufferOffset);
> -	memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> +	unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len,
> +			/* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
>  	rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
>  
>  out:
> @@ -1453,7 +1454,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,
>  			return -ENOMEM;
>  
>  		sz = le16_to_cpu(rsp->SecurityBufferOffset);
> -		memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> +		unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob,
> +				spnego_blob_len,
> +				/* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
>  		rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
>  		kfree(spnego_blob);
>  	}

Ew, please fix these properly instead of continuing to lie to the compiler
about the struct member sizes. :P

The above, &rsp->hdr.ProtocolId, addresses a single __le32 member, and
then tries to go past the end of it (i.e. "sz" is larger than 4). The
struct layout therefore indicates to memcpy that you have no bytes left
to write ("size 0" in the warning).

It looks to me like you want to be calculating an offset into
rsp->Buffer instead? Try:

	sz = le16_to_cpu(rsp->SecurityBufferOffset) -
		offsetof(*typeof(rsp), Buffer);
	memcpy(&rsp->Buffer[sz], ...)

BTW, what is validating that this:

        sz = le16_to_cpu(rsp->SecurityBufferOffset);
        chgblob =
                (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz);

is within the original data buffer? Shouldn't something check that:
	 sz > offsetof(*typeof(rsp), Buffer)
and
	sz <= ...size of the buffer... (maybe that happened already earlier)
Namjae Jeon Sept. 23, 2024, 12:12 a.m. UTC | #3
On Mon, Sep 23, 2024 at 8:12 AM Kees Cook <kees@kernel.org> wrote:
>
> On Thu, Aug 15, 2024 at 08:56:35AM +0900, Namjae Jeon wrote:
> > rsp buffer is allocatged larger than spnego_blob from
> > smb2_allocate_rsp_buf().
> >
> > Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
> > ---
> >  fs/smb/server/smb2pdu.c | 7 +++++--
> >  1 file changed, 5 insertions(+), 2 deletions(-)
> >
> > diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> > index 2df1354288e6..3f4c56a10a86 100644
> > --- a/fs/smb/server/smb2pdu.c
> > +++ b/fs/smb/server/smb2pdu.c
> > @@ -1370,7 +1370,8 @@ static int ntlm_negotiate(struct ksmbd_work *work,
> >       }
> >
> >       sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > -     memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> > +     unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len,
> > +                     /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
> >       rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
> >
> >  out:
> > @@ -1453,7 +1454,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,
> >                       return -ENOMEM;
> >
> >               sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > -             memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> > +             unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob,
> > +                             spnego_blob_len,
> > +                             /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
> >               rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
> >               kfree(spnego_blob);
> >       }
>
> Ew, please fix these properly instead of continuing to lie to the compiler
> about the struct member sizes. :P
I have fully checked that this warning is a false alarm.
>
> The above, &rsp->hdr.ProtocolId, addresses a single __le32 member, and
> then tries to go past the end of it (i.e. "sz" is larger than 4). The
> struct layout therefore indicates to memcpy that you have no bytes left
> to write ("size 0" in the warning).
>
> It looks to me like you want to be calculating an offset into
> rsp->Buffer instead? Try:
>
>         sz = le16_to_cpu(rsp->SecurityBufferOffset) -
>                 offsetof(*typeof(rsp), Buffer);
>         memcpy(&rsp->Buffer[sz], ...)
SecurityBufferOffset is fixed to the value 72 and it points to ->Buffer.
So memcpy(&rsp->Buffer[0], ...)
>
> BTW, what is validating that this:
>
>         sz = le16_to_cpu(rsp->SecurityBufferOffset);
>         chgblob =
>                 (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz);
>
> is within the original data buffer? Shouldn't something check that:
>          sz > offsetof(*typeof(rsp), Buffer)
> and
>         sz <= ...size of the buffer... (maybe that happened already earlier)
SecurityBufferOffset is fixed to the value 72. It is set in smb2_sess_setup().

int smb2_sess_setup(struct ksmbd_work *work)
...
        rsp->StructureSize = cpu_to_le16(9);
        rsp->SessionFlags = 0;
        rsp->SecurityBufferOffset = cpu_to_le16(72);
        rsp->SecurityBufferLength = 0;

So sz and offsetof(*typeof(rsp), Buffer) will be same.
and rsp buffer size is at least 448 bytes,  That's enough space to
contain a chgblob(48) or spnego_blob(249).

Thanks.
>
> --
> Kees Cook
Kees Cook Sept. 23, 2024, 12:27 a.m. UTC | #4
On Mon, Sep 23, 2024 at 09:12:31AM +0900, Namjae Jeon wrote:
> On Mon, Sep 23, 2024 at 8:12 AM Kees Cook <kees@kernel.org> wrote:
> >
> > On Thu, Aug 15, 2024 at 08:56:35AM +0900, Namjae Jeon wrote:
> > > rsp buffer is allocatged larger than spnego_blob from
> > > smb2_allocate_rsp_buf().
> > >
> > > Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
> > > ---
> > >  fs/smb/server/smb2pdu.c | 7 +++++--
> > >  1 file changed, 5 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> > > index 2df1354288e6..3f4c56a10a86 100644
> > > --- a/fs/smb/server/smb2pdu.c
> > > +++ b/fs/smb/server/smb2pdu.c
> > > @@ -1370,7 +1370,8 @@ static int ntlm_negotiate(struct ksmbd_work *work,
> > >       }
> > >
> > >       sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > > -     memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> > > +     unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len,
> > > +                     /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
> > >       rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
> > >
> > >  out:
> > > @@ -1453,7 +1454,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,
> > >                       return -ENOMEM;
> > >
> > >               sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > > -             memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> > > +             unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob,
> > > +                             spnego_blob_len,
> > > +                             /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
> > >               rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
> > >               kfree(spnego_blob);
> > >       }
> >
> > Ew, please fix these properly instead of continuing to lie to the compiler
> > about the struct member sizes. :P
> I have fully checked that this warning is a false alarm.
> >
> > The above, &rsp->hdr.ProtocolId, addresses a single __le32 member, and
> > then tries to go past the end of it (i.e. "sz" is larger than 4). The
> > struct layout therefore indicates to memcpy that you have no bytes left
> > to write ("size 0" in the warning).
> >
> > It looks to me like you want to be calculating an offset into
> > rsp->Buffer instead? Try:
> >
> >         sz = le16_to_cpu(rsp->SecurityBufferOffset) -
> >                 offsetof(*typeof(rsp), Buffer);
> >         memcpy(&rsp->Buffer[sz], ...)
> SecurityBufferOffset is fixed to the value 72 and it points to ->Buffer.
> So memcpy(&rsp->Buffer[0], ...)
> >
> > BTW, what is validating that this:
> >
> >         sz = le16_to_cpu(rsp->SecurityBufferOffset);
> >         chgblob =
> >                 (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz);
> >
> > is within the original data buffer? Shouldn't something check that:
> >          sz > offsetof(*typeof(rsp), Buffer)
> > and
> >         sz <= ...size of the buffer... (maybe that happened already earlier)
> SecurityBufferOffset is fixed to the value 72. It is set in smb2_sess_setup().
> 
> int smb2_sess_setup(struct ksmbd_work *work)
> ...
>         rsp->StructureSize = cpu_to_le16(9);
>         rsp->SessionFlags = 0;
>         rsp->SecurityBufferOffset = cpu_to_le16(72);
>         rsp->SecurityBufferLength = 0;
> 
> So sz and offsetof(*typeof(rsp), Buffer) will be same.
> and rsp buffer size is at least 448 bytes,  That's enough space to
> contain a chgblob(48) or spnego_blob(249).

Okay, in that case, please just use:

	memcpy(rsp->Buffer, ...)

and the "unsafe" usage can be removed. :)
Namjae Jeon Sept. 23, 2024, 12:32 a.m. UTC | #5
On Mon, Sep 23, 2024 at 9:27 AM Kees Cook <kees@kernel.org> wrote:
>
> On Mon, Sep 23, 2024 at 09:12:31AM +0900, Namjae Jeon wrote:
> > On Mon, Sep 23, 2024 at 8:12 AM Kees Cook <kees@kernel.org> wrote:
> > >
> > > On Thu, Aug 15, 2024 at 08:56:35AM +0900, Namjae Jeon wrote:
> > > > rsp buffer is allocatged larger than spnego_blob from
> > > > smb2_allocate_rsp_buf().
> > > >
> > > > Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
> > > > ---
> > > >  fs/smb/server/smb2pdu.c | 7 +++++--
> > > >  1 file changed, 5 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> > > > index 2df1354288e6..3f4c56a10a86 100644
> > > > --- a/fs/smb/server/smb2pdu.c
> > > > +++ b/fs/smb/server/smb2pdu.c
> > > > @@ -1370,7 +1370,8 @@ static int ntlm_negotiate(struct ksmbd_work *work,
> > > >       }
> > > >
> > > >       sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > > > -     memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> > > > +     unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len,
> > > > +                     /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
> > > >       rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
> > > >
> > > >  out:
> > > > @@ -1453,7 +1454,9 @@ static int ntlm_authenticate(struct ksmbd_work *work,
> > > >                       return -ENOMEM;
> > > >
> > > >               sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > > > -             memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
> > > > +             unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob,
> > > > +                             spnego_blob_len,
> > > > +                             /* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
> > > >               rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
> > > >               kfree(spnego_blob);
> > > >       }
> > >
> > > Ew, please fix these properly instead of continuing to lie to the compiler
> > > about the struct member sizes. :P
> > I have fully checked that this warning is a false alarm.
> > >
> > > The above, &rsp->hdr.ProtocolId, addresses a single __le32 member, and
> > > then tries to go past the end of it (i.e. "sz" is larger than 4). The
> > > struct layout therefore indicates to memcpy that you have no bytes left
> > > to write ("size 0" in the warning).
> > >
> > > It looks to me like you want to be calculating an offset into
> > > rsp->Buffer instead? Try:
> > >
> > >         sz = le16_to_cpu(rsp->SecurityBufferOffset) -
> > >                 offsetof(*typeof(rsp), Buffer);
> > >         memcpy(&rsp->Buffer[sz], ...)
> > SecurityBufferOffset is fixed to the value 72 and it points to ->Buffer.
> > So memcpy(&rsp->Buffer[0], ...)
> > >
> > > BTW, what is validating that this:
> > >
> > >         sz = le16_to_cpu(rsp->SecurityBufferOffset);
> > >         chgblob =
> > >                 (struct challenge_message *)((char *)&rsp->hdr.ProtocolId + sz);
> > >
> > > is within the original data buffer? Shouldn't something check that:
> > >          sz > offsetof(*typeof(rsp), Buffer)
> > > and
> > >         sz <= ...size of the buffer... (maybe that happened already earlier)
> > SecurityBufferOffset is fixed to the value 72. It is set in smb2_sess_setup().
> >
> > int smb2_sess_setup(struct ksmbd_work *work)
> > ...
> >         rsp->StructureSize = cpu_to_le16(9);
> >         rsp->SessionFlags = 0;
> >         rsp->SecurityBufferOffset = cpu_to_le16(72);
> >         rsp->SecurityBufferLength = 0;
> >
> > So sz and offsetof(*typeof(rsp), Buffer) will be same.
> > and rsp buffer size is at least 448 bytes,  That's enough space to
> > contain a chgblob(48) or spnego_blob(249).
>
> Okay, in that case, please just use:
>
>         memcpy(rsp->Buffer, ...)
>
> and the "unsafe" usage can be removed. :)
Okay, I will update it:)

Thanks!
>
> --
> Kees Cook
diff mbox series

Patch

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 2df1354288e6..3f4c56a10a86 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1370,7 +1370,8 @@  static int ntlm_negotiate(struct ksmbd_work *work,
 	}
 
 	sz = le16_to_cpu(rsp->SecurityBufferOffset);
-	memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
+	unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len,
+			/* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
 	rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
 
 out:
@@ -1453,7 +1454,9 @@  static int ntlm_authenticate(struct ksmbd_work *work,
 			return -ENOMEM;
 
 		sz = le16_to_cpu(rsp->SecurityBufferOffset);
-		memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob, spnego_blob_len);
+		unsafe_memcpy((char *)&rsp->hdr.ProtocolId + sz, spnego_blob,
+				spnego_blob_len,
+				/* alloc is larger than blob, see smb2_allocate_rsp_buf() */);
 		rsp->SecurityBufferLength = cpu_to_le16(spnego_blob_len);
 		kfree(spnego_blob);
 	}