2023-11-16 19:16:22

by Kees Cook

[permalink] [raw]
Subject: [PATCH] scsi: zfcp: Replace strlcpy() with strscpy()

strlcpy() reads the entire source buffer first. This read may exceed
the destination size limit. This is both inefficient and can lead
to linear read overflows if a source string is not NUL-terminated[1].
Additionally, it returns the size of the source string, not the
resulting size of the destination string. In an effort to remove strlcpy()
completely[2], replace strlcpy() here with strscpy().

Be explicitly robust in the face of truncation, which should be an
impossible state.

Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1]
Link: https://github.com/KSPP/linux/issues/89 [2]
Cc: Steffen Maier <[email protected]>
Cc: Benjamin Block <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Cc: Alexander Gordeev <[email protected]>
Cc: Christian Borntraeger <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Azeem Shaikh <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/s390/scsi/zfcp_fc.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 4f0d0e55f0d4..1a29f10767fc 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -900,8 +900,15 @@ static void zfcp_fc_rspn(struct zfcp_adapter *adapter,
zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID,
FC_SYMBOLIC_NAME_SIZE);
hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost));
- len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
- FC_SYMBOLIC_NAME_SIZE);
+ len = strscpy(rspn_req->name, fc_host_symbolic_name(shost),
+ sizeof(rspn_req->name));
+ /*
+ * It should be impossible for this to truncate, as
+ * sizeof(rspn_req->name) is equal to max size of
+ * fc_host_symbolic_name(shost), but check anyway.
+ */
+ if (len < 0)
+ len = sizeof(rspn_req->name) - 1;
rspn_req->rspn.fr_name_len = len;

sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req));
--
2.34.1


2023-11-17 18:20:42

by Alexander Gordeev

[permalink] [raw]
Subject: Re: [PATCH] scsi: zfcp: Replace strlcpy() with strscpy()

On Thu, Nov 16, 2023 at 11:14:35AM -0800, Kees Cook wrote:

Hi Kees,

> diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
> index 4f0d0e55f0d4..1a29f10767fc 100644
> --- a/drivers/s390/scsi/zfcp_fc.c
> +++ b/drivers/s390/scsi/zfcp_fc.c
> @@ -900,8 +900,15 @@ static void zfcp_fc_rspn(struct zfcp_adapter *adapter,
> zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID,
> FC_SYMBOLIC_NAME_SIZE);
> hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost));
> - len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
> - FC_SYMBOLIC_NAME_SIZE);
> + len = strscpy(rspn_req->name, fc_host_symbolic_name(shost),
> + sizeof(rspn_req->name));

Could you please explain why do you copy to rspn_req->name instead
of rspn_req->rspn.fr_name?

> + /*
> + * It should be impossible for this to truncate, as
> + * sizeof(rspn_req->name) is equal to max size of
> + * fc_host_symbolic_name(shost), but check anyway.
> + */
> + if (len < 0)
> + len = sizeof(rspn_req->name) - 1;
> rspn_req->rspn.fr_name_len = len;
>
> sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req));

Thanks!

2023-11-19 12:39:26

by Alexander Gordeev

[permalink] [raw]
Subject: Re: [PATCH] scsi: zfcp: Replace strlcpy() with strscpy()

On Fri, Nov 17, 2023 at 07:19:48PM +0100, Alexander Gordeev wrote:
> > @@ -900,8 +900,15 @@ static void zfcp_fc_rspn(struct zfcp_adapter *adapter,
> > zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID,
> > FC_SYMBOLIC_NAME_SIZE);
> > hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost));
> > - len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
> > - FC_SYMBOLIC_NAME_SIZE);
> > + len = strscpy(rspn_req->name, fc_host_symbolic_name(shost),
> > + sizeof(rspn_req->name));
>
> Could you please explain why do you copy to rspn_req->name instead
> of rspn_req->rspn.fr_name?

Please, ignore this (stupid Friday evening) quesiton.

Although the use of sizeof() is right thing, FC_SYMBOLIC_NAME_SIZE
is so ubiquotous in this source that it probably makes sense to
address in a separate cleanup.

@Steffen, @Benjamin, could you please comment in this and below?

> > + /*
> > + * It should be impossible for this to truncate, as
> > + * sizeof(rspn_req->name) is equal to max size of
> > + * fc_host_symbolic_name(shost), but check anyway.
> > + */
> > + if (len < 0)
> > + len = sizeof(rspn_req->name) - 1;

Not sure if this check is really needed. It could have been done
for strlcpy() also, but as you say - should not ever happen.

> > rspn_req->rspn.fr_name_len = len;
> >
> > sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req));

Thanks!

2023-11-20 12:41:25

by Benjamin Block

[permalink] [raw]
Subject: Re: [PATCH] scsi: zfcp: Replace strlcpy() with strscpy()

Hey Kees,

thanks for the patch.

can you please send this patch to linux-scsi and CC the SCSI Maintainers
(Martin and James) instead (having linux-s390 on CC is fine)? zFCP doesn't go
via s390, being a SCSI driver.

On Thu, Nov 16, 2023 at 11:14:35AM -0800, Kees Cook wrote:
> strlcpy() reads the entire source buffer first. This read may exceed
> the destination size limit. This is both inefficient and can lead
> to linear read overflows if a source string is not NUL-terminated[1].
> Additionally, it returns the size of the source string, not the
> resulting size of the destination string. In an effort to remove strlcpy()
> completely[2], replace strlcpy() here with strscpy().
>
> Be explicitly robust in the face of truncation, which should be an
> impossible state.
>
> Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [1]
> Link: https://github.com/KSPP/linux/issues/89 [2]
> Cc: Steffen Maier <[email protected]>
> Cc: Benjamin Block <[email protected]>
> Cc: Heiko Carstens <[email protected]>
> Cc: Vasily Gorbik <[email protected]>
> Cc: Alexander Gordeev <[email protected]>
> Cc: Christian Borntraeger <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Azeem Shaikh <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> drivers/s390/scsi/zfcp_fc.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
> index 4f0d0e55f0d4..1a29f10767fc 100644
> --- a/drivers/s390/scsi/zfcp_fc.c
> +++ b/drivers/s390/scsi/zfcp_fc.c
> @@ -900,8 +900,15 @@ static void zfcp_fc_rspn(struct zfcp_adapter *adapter,
> zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID,
> FC_SYMBOLIC_NAME_SIZE);
> hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost));
> - len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost),
> - FC_SYMBOLIC_NAME_SIZE);
> + len = strscpy(rspn_req->name, fc_host_symbolic_name(shost),
> + sizeof(rspn_req->name));

This is corrct.

> + /*
> + * It should be impossible for this to truncate, as
> + * sizeof(rspn_req->name) is equal to max size of
> + * fc_host_symbolic_name(shost), but check anyway.
> + */
> + if (len < 0)
> + len = sizeof(rspn_req->name) - 1;

I'd rather have a compile-time check, whether the array sizes of
`rspn_req->name` and `fc_host_symbolic_name(shost)` run out of sync, or
against our expectations.

Something like:

len = strscpy(rspn_req->name, fc_host_symbolic_name(shost),
sizeof(rspn_req->name));
BUILD_BUG_ON(sizeof(rspn_req->name) !=
sizeof(fc_host_symbolic_name(shost)) ||
sizeof(rspn_req->name) !=
1 << sizeof(rspn_req->rspn.fr_name_len) * 8);
rspn_req->rspn.fr_name_len = len;

Then the last assignment should also be correct; and if something changes -
unexpectedly, because this follows a FC standard - we need to adapt the code
anyway I'd think.

Or am I missing something?

> rspn_req->rspn.fr_name_len = len;
>
> sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req));
> --
> 2.34.1
>

--
Best Regards, Benjamin Block / Linux on IBM Z Kernel Development
IBM Deutschland Research & Development GmbH / https://www.ibm.com/privacy
Vors. Aufs.-R.: Gregor Pillen / Gesch?ftsf?hrung: David Faller
Sitz der Ges.: B?blingen / Registergericht: AmtsG Stuttgart, HRB 243294