[stgt] [PATCH] Fix PR OUT with REGISTER AND MOVE service action
FUJITA Tomonori
fujita.tomonori at lab.ntt.co.jp
Tue Apr 17 05:32:11 CEST 2012
Sorry for the delay
On Sun, 01 Apr 2012 21:24:16 +0200
Arne Redlich <arne.redlich at googlemail.com> wrote:
> spc_pr_register_and_move() suffers from a number of problems:
> * the offsets for the TRANSPORTID PARAMETER DATA LENGTH (addlen) and the
> TransportID are wrong
> * invalid input data (TransportID length restrictions imposed by the spec) is not
> sufficiently checked
> * TransportIDs are compared using strncmp() which does not work with transports
> other than iSCSI
> .
>
> Signed-off-by: Arne Redlich <arne.redlich at googlemail.com>
> ---
> Tomo, list,
>
> This one is completely and utterly untested besides having the compiler's blessing, so please
> review and test carefully.
> It addresses the aforementioned issues within the framework of the current code, but I think in
> the long run this (and related code) would greatly benefit from using types instead of magic constants
> for the handling of SCSI commands.
>
> Cheers,
> Arne
>
> usr/spc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
> 1 files changed, 44 insertions(+), 6 deletions(-)
>
> diff --git a/usr/spc.c b/usr/spc.c
> index 93aa062..2a71508 100644
> --- a/usr/spc.c
> +++ b/usr/spc.c
> @@ -19,6 +19,7 @@
> * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> * 02110-1301 USA
> */
> +#include <assert.h>
> #include <errno.h>
> #include <inttypes.h>
> #include <stdio.h>
> @@ -1360,16 +1361,17 @@ static int spc_pr_register_and_move(int host_no, struct scsi_cmd *cmd)
> char *buf;
> uint8_t unreg;
> uint64_t res_key, sa_res_key;
> - uint32_t addlen, idlen;
> + uint32_t addlen, idlen, outlen;
> struct registration *reg, *dst;
> - uint16_t len = 24;
> + const uint16_t len = 24; /* otherwise we can't get at addlen */
> int (*id)(int, uint64_t, char *, int);
> char tpid[300]; /* large enough? */
>
> if (get_unaligned_be16(cmd->scb + 7) < len)
> goto sense;
>
> - if (scsi_get_out_length(cmd) < len)
> + outlen = scsi_get_out_length(cmd);
> + if (outlen < len)
> goto sense;
>
> buf = scsi_get_out_buffer(cmd);
> @@ -1382,7 +1384,24 @@ static int spc_pr_register_and_move(int host_no, struct scsi_cmd *cmd)
> res_key = get_unaligned_be64(buf);
> sa_res_key = get_unaligned_be64(buf + 8);
>
> - addlen = get_unaligned_be32(buf + 24);
> + addlen = get_unaligned_be32(buf + 20);
> +
> + /*
> + * SPC-4r02, 6.12.4:
> + * "The TRANSPORTID DESCRIPTOR LENGTH field specifies the number of bytes of
> + * the TransportID that follows, shall be a minimum of 24 bytes, and shall
> + * be a multiple of 4. [...]
> + * The command shall be terminated with CHECK CONDITION status [...]
> + * a) If the value in the parameter list length field in the CDB does
> + * not include all of the parameter list bytes specified by the
> + * TRANSPORTID PARAMETER DATA LENGTH field; or
> + * b) If the value in the TRANSPORTID PARAMETER DATA LENGTH field
> + * results in the truncation of a TransportID."
> + *
> + * See below for (b).
> + */
> + if (addlen < 24 || addlen % 4 != 0 || outlen - len < addlen)
> + goto sense;
>
> reg = lookup_registration_by_nexus(cmd->dev, cmd->it_nexus);
> if (!reg) {
> @@ -1413,9 +1432,28 @@ found:
> if (id) {
> memset(tpid, 0, sizeof(tpid));
> idlen = id(cmd->dev->tgt->tid, dst->nexus_id, tpid, sizeof(tpid));
> - if (addlen) {
> - if (strncmp(tpid, buf + 28, strlen(tpid)))
> + if (idlen <= 0)
> + goto sense;
> +
> + assert(idlen % 4 == 0);
> + assert(idlen >= 24);
Have you confirmed that iscsi_transportid() returns a valid id?
> + if (addlen < idlen)
> + goto sense;
> + else {
> + size_t i;
> +
> + if (memcmp(tpid, buf + len, idlen))
> goto sense;
> + /*
> + * the transport ID could be padded with an arbitrary
> + * (as long as it's padded to a 4 byte boundary, but we
> + * checked for that already) amount of \0's, or is that
> + * ruled out by SPC-x?
> + */
> + for (i = idlen; i < addlen - idlen; i++)
> + if (buf[len + i] != '\0')
> + goto sense;
> }
> }
>
> --
> 1.7.9.1
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe stgt" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the stgt
mailing list