qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Hervé Poussineau" <hpoussin@reactos.org>
To: Jan Kiszka <jan.kiszka@siemens.com>
Cc: "qemu-devel@nongnu.org" <qemu-devel@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH v3 2/2] slirp: Implement TFTP Blocksize option
Date: Thu, 13 Sep 2012 21:56:15 +0200	[thread overview]
Message-ID: <50523A5F.3000606@reactos.org> (raw)
In-Reply-To: <50519BCF.2080001@siemens.com>

Jan Kiszka a écrit :
> On 2012-09-13 07:55, Hervé Poussineau wrote:
>> This option is described in RFC 1783. As this is only an optional field,
>> we may ignore it in some situations and handle it in some others.
>>
>> However, MS Windows 2003 PXE boot client requests a block size of the MTU
>> (most of the times 1472 bytes), and doesn't work if the option is not
>> acknowledged (with whatever value).
>>
>> According to the RFC 1783, we cannot acknowledge the option with a bigger
>> value than the requested one.
>>
>> As current implementation is using 512 bytes by block, accept the option
>> with a value of 512 if the option was specified, and don't acknowledge it
>> if it is not present or less than 512 bytes.
>>
>> Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
>> ---
>>  slirp/tftp.c |   42 +++++++++++++++++++++++++++++++++---------
>>  1 file changed, 33 insertions(+), 9 deletions(-)
>>
>> diff --git a/slirp/tftp.c b/slirp/tftp.c
>> index c6a5df2..37b0387 100644
>> --- a/slirp/tftp.c
>> +++ b/slirp/tftp.c
>> @@ -120,13 +120,13 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
>>  }
>>  
>>  static int tftp_send_oack(struct tftp_session *spt,
>> -                          const char *key, uint32_t value,
>> +                          const char *keys[], uint32_t values[], int nb,
>>                            struct tftp_t *recv_tp)
>>  {
>>      struct sockaddr_in saddr, daddr;
>>      struct mbuf *m;
>>      struct tftp_t *tp;
>> -    int n = 0;
>> +    int i, n = 0;
>>  
>>      m = m_get(spt->slirp);
>>  
>> @@ -140,10 +140,12 @@ static int tftp_send_oack(struct tftp_session *spt,
>>      m->m_data += sizeof(struct udpiphdr);
>>  
>>      tp->tp_op = htons(TFTP_OACK);
>> -    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
>> -                  key) + 1;
>> -    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
>> -                  value) + 1;
>> +    for (i = 0; i < nb; i++) {
>> +        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
>> +                      keys[i]) + 1;
>> +        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
>> +                      values[i]) + 1;
>> +    }
>>  
>>      saddr.sin_addr = recv_tp->ip.ip_dst;
>>      saddr.sin_port = recv_tp->udp.uh_dport;
>> @@ -260,6 +262,9 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
>>    int s, k;
>>    size_t prefix_len;
>>    char *req_fname;
>> +  const char *option_name[2];
>> +  uint32_t option_value[2];
>> +  int nb_options = 0;
>>  
>>    /* check if a session already exists and if so terminate it */
>>    s = tftp_session_find(slirp, tp);
>> @@ -337,7 +342,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
>>        return;
>>    }
>>  
>> -  while (k < pktlen) {
>> +  while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) {
>>        const char *key, *value;
>>  
>>        key = &tp->x.tp_buf[k];
>> @@ -364,11 +369,30 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
>>  	      }
>>  	  }
>>  
>> -	  tftp_send_oack(spt, "tsize", tsize, tp);
>> -	  return;
>> +          option_name[nb_options] = "tsize";
>> +          option_value[nb_options] = tsize;
>> +          nb_options++;
>> +      } else if (strcasecmp(key, "blksize") == 0) {
>> +          int blksize = atoi(value);
>> +
>> +          /* If blksize option is bigger than what we will
>> +           * emit, accept the option with our packet size.
>> +           * Otherwise, simply do as we didn't see the option.
>> +           */
>> +          if (blksize >= 512) {
>> +              option_name[nb_options] = "blksize";
>> +              option_value[nb_options] = 512;
>> +              nb_options++;
>> +          }
>>        }
>>    }
>>  
>> +  if (nb_options > 0) {
>> +      assert(nb_options <= ARRAY_SIZE(option_name));
> 
> I think you didn't answer my question: What if the guest sends a bogus
> request with multiple tsize or blksize option entries so that nb_options
> becomes > 2? That would crash QEMU, no? Even worse, that would not
> require a privileged guest process.
> 
> Please explain why I'm wrong or make the code robust.


+  int nb_options = 0;
...
+  while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) {
...
+              option_value[nb_options] = ...
+              nb_options++;
...
+  if (nb_options > 0) {
+      assert(nb_options <= ARRAY_SIZE(option_name));


We're leaving the loop which fills options array if the array is already 
filled (ie nb_options is 2). This won't cause any buffer overflow.
Then, the assert is not needed, but it was only to make things clear, 
and to prevent a potential bug later, if loop code is rewritten/changed.

If guest sends a bogus request with two tsize and one blksize, the two 
tsize answers will fill the options array and the blksize option won't 
be processed, but I don't think it is a big problem.

I hope it will answer your questions.

Hervé

  reply	other threads:[~2012-09-13 19:56 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-13  5:54 [Qemu-devel] [PATCH v3 0/2] slirp: tftp server improvements Hervé Poussineau
2012-09-13  5:55 ` [Qemu-devel] [PATCH v3 1/2] slirp: Handle more than 65535 blocks in TFTP transfers Hervé Poussineau
2012-09-13 10:50   ` Jan Kiszka
2012-09-13  5:55 ` [Qemu-devel] [PATCH v3 2/2] slirp: Implement TFTP Blocksize option Hervé Poussineau
2012-09-13  8:39   ` Jan Kiszka
2012-09-13 19:56     ` Hervé Poussineau [this message]
2012-09-13 22:28       ` Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=50523A5F.3000606@reactos.org \
    --to=hpoussin@reactos.org \
    --cc=jan.kiszka@siemens.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).