2012/4/1 Arne Redlich <arne.redlich@xxxxxxxxxxxxxx>: > 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@xxxxxxxxxxxxxx> > --- > 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. Any thoughts / feedback on this one? Thanks, Arne > 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); > + > + 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@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html