Re: [PATCH 4/7] ksmbd: check strictly data area in ksmbd_smb2_check_message()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2021-09-25 19:27 GMT+09:00, Hyunchul Lee <hyc.lee@xxxxxxxxx>:
> Looks good to me.
> Acked-by: Hyunchul Lee <hyc.lee@xxxxxxxxx>
>
> 2021년 9월 24일 (금) 오전 11:13, Namjae Jeon <linkinjeon@xxxxxxxxxx>님이 작성:
>>
>> When invalid data offset and data length in request,
>> ksmbd_smb2_check_message check strictly and doesn't allow to process such
>> requests.
>>
>> Cc: Tom Talpey <tom@xxxxxxxxxx>
>> Cc: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
>> Cc: Ralph Böhme <slow@xxxxxxxxx>
>> Cc: Steve French <smfrench@xxxxxxxxx>
>> Cc: Hyunchul Lee <hyc.lee@xxxxxxxxx>
>> Cc: Sergey Senozhatsky <senozhatsky@xxxxxxxxxxxx>
>> Signed-off-by: Namjae Jeon <linkinjeon@xxxxxxxxxx>
>> ---
>>  fs/ksmbd/smb2misc.c | 83 ++++++++++++++++++++-------------------------
>>  1 file changed, 37 insertions(+), 46 deletions(-)
>>
>> diff --git a/fs/ksmbd/smb2misc.c b/fs/ksmbd/smb2misc.c
>> index 9aa46bb3e10d..697285e47522 100644
>> --- a/fs/ksmbd/smb2misc.c
>> +++ b/fs/ksmbd/smb2misc.c
>> @@ -83,15 +83,18 @@ static const bool
>> has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
>>   * Returns the pointer to the beginning of the data area. Length of the
>> data
>
> Do we need to change this comment about the return value?
Will update it on next version.
> Looks good to me except this.
> Acked-by: Hyunchul Lee <hyc.lee@xxxxxxxxx>
Thanks!
>
>
>>   * area and the offset to it (from the beginning of the smb are also
>> returned.
>>   */
>> -static char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr
>> *hdr)
>> +static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
>> +                                 struct smb2_hdr *hdr)
>>  {
>> +       int ret = 0;
>> +
>>         *off = 0;
>>         *len = 0;
>>
>>         /* error reqeusts do not have data area */
>>         if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED
>> &&
>>             (((struct smb2_err_rsp *)hdr)->StructureSize) ==
>> SMB2_ERROR_STRUCTURE_SIZE2_LE)
>> -               return NULL;
>> +               return ret;
>>
>>         /*
>>          * Following commands have data areas so we have to get the
>> location
>> @@ -165,69 +168,52 @@ static char *smb2_get_data_area_len(int *off, int
>> *len, struct smb2_hdr *hdr)
>>         case SMB2_IOCTL:
>>                 *off = le32_to_cpu(((struct smb2_ioctl_req
>> *)hdr)->InputOffset);
>>                 *len = le32_to_cpu(((struct smb2_ioctl_req
>> *)hdr)->InputCount);
>> -
>>                 break;
>>         default:
>>                 ksmbd_debug(SMB, "no length check for command\n");
>>                 break;
>>         }
>>
>> -       /*
>> -        * Invalid length or offset probably means data area is invalid,
>> but
>> -        * we have little choice but to ignore the data area in this
>> case.
>> -        */
>>         if (*off > 4096) {
>> -               ksmbd_debug(SMB, "offset %d too large, data area
>> ignored\n",
>> -                           *off);
>> -               *len = 0;
>> -               *off = 0;
>> -       } else if (*off < 0) {
>> -               ksmbd_debug(SMB,
>> -                           "negative offset %d to data invalid ignore
>> data area\n",
>> -                           *off);
>> -               *off = 0;
>> -               *len = 0;
>> -       } else if (*len < 0) {
>> -               ksmbd_debug(SMB,
>> -                           "negative data length %d invalid, data area
>> ignored\n",
>> -                           *len);
>> -               *len = 0;
>> -       } else if (*len > 128 * 1024) {
>> -               ksmbd_debug(SMB, "data area larger than 128K: %d\n",
>> *len);
>> -               *len = 0;
>> +               ksmbd_debug(SMB, "offset %d too large\n", *off);
>> +               ret = -EINVAL;
>> +       } else if ((u64)*off + *len > MAX_STREAM_PROT_LEN) {
>> +               ksmbd_debug(SMB, "Request is larger than maximum stream
>> protocol length(%u): %llu\n",
>> +                           MAX_STREAM_PROT_LEN, (u64)*off + *len);
>> +               ret = -EINVAL;
>>         }
>>
>> -       /* return pointer to beginning of data area, ie offset from SMB
>> start */
>> -       if ((*off != 0) && (*len != 0))
>> -               return (char *)hdr + *off;
>> -       else
>> -               return NULL;
>> +       return ret;
>>  }
>>
>>  /*
>>   * Calculate the size of the SMB message based on the fixed header
>>   * portion, the number of word parameters and the data portion of the
>> message.
>>   */
>> -static unsigned int smb2_calc_size(void *buf)
>> +static int smb2_calc_size(void *buf, unsigned int *len)
>>  {
>>         struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
>>         struct smb2_hdr *hdr = &pdu->hdr;
>> -       int offset; /* the offset from the beginning of SMB to data area
>> */
>> -       int data_length; /* the length of the variable length data area
>> */
>> +       unsigned int offset; /* the offset from the beginning of SMB to
>> data area */
>> +       unsigned int data_length; /* the length of the variable length
>> data area */
>> +       int ret;
>> +
>>         /* Structure Size has already been checked to make sure it is 64
>> */
>> -       int len = le16_to_cpu(hdr->StructureSize);
>> +       *len = le16_to_cpu(hdr->StructureSize);
>>
>>         /*
>>          * StructureSize2, ie length of fixed parameter area has already
>>          * been checked to make sure it is the correct length.
>>          */
>> -       len += le16_to_cpu(pdu->StructureSize2);
>> +       *len += le16_to_cpu(pdu->StructureSize2);
>>
>>         if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
>>                 goto calc_size_exit;
>>
>> -       smb2_get_data_area_len(&offset, &data_length, hdr);
>> -       ksmbd_debug(SMB, "SMB2 data length %d offset %d\n", data_length,
>> +       ret = smb2_get_data_area_len(&offset, &data_length, hdr);
>> +       if (ret)
>> +               return ret;
>> +       ksmbd_debug(SMB, "SMB2 data length %u offset %u\n", data_length,
>>                     offset);
>>
>>         if (data_length > 0) {
>> @@ -237,16 +223,19 @@ static unsigned int smb2_calc_size(void *buf)
>>                  * for some commands, typically those with odd
>> StructureSize,
>>                  * so we must add one to the calculation.
>>                  */
>> -               if (offset + 1 < len)
>> +               if (offset + 1 < *len) {
>>                         ksmbd_debug(SMB,
>> -                                   "data area offset %d overlaps SMB2
>> header %d\n",
>> -                                   offset + 1, len);
>> -               else
>> -                       len = offset + data_length;
>> +                                   "data area offset %d overlaps SMB2
>> header %u\n",
>> +                                   offset + 1, *len);
>> +                       return -EINVAL;
>> +               }
>> +
>> +               *len = offset + data_length;
>>         }
>> +
>>  calc_size_exit:
>> -       ksmbd_debug(SMB, "SMB2 len %d\n", len);
>> -       return len;
>> +       ksmbd_debug(SMB, "SMB2 len %u\n", *len);
>> +       return 0;
>>  }
>>
>>  static inline int smb2_query_info_req_len(struct smb2_query_info_req *h)
>> @@ -391,9 +380,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work
>> *work)
>>                 return 1;
>>         }
>>
>> -       clc_len = smb2_calc_size(hdr);
>> +       if (smb2_calc_size(hdr, &clc_len))
>> +               return 1;
>> +
>>         if (len != clc_len) {
>> -               /* server can return one byte more due to implied bcc[0]
>> */
>> +               /* client can return one byte more due to implied bcc[0]
>> */
>>                 if (clc_len == len + 1)
>>                         return 0;
>>
>> --
>> 2.25.1
>>
>
>
> --
> Thanks,
> Hyunchul
>




[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux