I started writing a Smatch check to look for:

        skb->len - foo

where foo might be more than skb->len.  I don't know this code well
enough to say what the rules are exactly.  I chose a fairly suspect
bit of code to use as an example to get some feedback.

Hello Marius B. Kotsbak,

The patch d40261236e8e: "net/usb: Add Samsung Kalmia driver for
Samsung GT-B3730" from Jun 12, 2011, leads to the following static
checker warning:

        drivers/net/usb/kalmia.c:281 kalmia_rx_fixup()
        warn: this assumes skb->len is at least 12 bytes

drivers/net/usb/kalmia.c
   245          /* incomplete header? */
   246          if (skb->len < KALMIA_HEADER_LENGTH)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We verify that it is at least 6.

   247                  return 0;
   248  
   249          do {

This is a do while (skb->len) loop.  Shouldn't the check for invalid
skb->len be inside the loop?

   250                  struct sk_buff *skb2 = NULL;
   251                  u8 *header_start;
   252                  u16 usb_packet_length, ether_packet_length;
   253                  int is_last;
   254  
   255                  header_start = skb->data;
   256  
   257                  if (unlikely(header_start[0] != 0x57 || header_start[1] 
!= 0x44)) {
   258                          if (!memcmp(header_start, 
EXPECTED_UNKNOWN_HEADER_1,
   259                                  sizeof(EXPECTED_UNKNOWN_HEADER_1)) || 
!memcmp(
   260                                  header_start, EXPECTED_UNKNOWN_HEADER_2,
   261                                  sizeof(EXPECTED_UNKNOWN_HEADER_2))) {
   262                                  netdev_dbg(dev->net,
   263                                          "Received expected unknown 
frame header: %6phC. Package length: %i\n",
   264                                          header_start,
   265                                          skb->len - 
KALMIA_HEADER_LENGTH);
   266                          }
   267                          else {
   268                                  netdev_err(dev->net,
   269                                          "Received unknown frame header: 
%6phC. Package length: %i\n",
   270                                          header_start,
   271                                          skb->len - 
KALMIA_HEADER_LENGTH);
   272                                  return 0;
   273                          }
   274                  }
   275                  else
   276                          netdev_dbg(dev->net,
   277                                  "Received header: %6phC. Package 
length: %i\n",
   278                                  header_start, skb->len - 
KALMIA_HEADER_LENGTH);
   279  
   280                  /* subtract start header and end header */
   281                  usb_packet_length = skb->len - (2 * 
KALMIA_HEADER_LENGTH);
                        
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We could end up with usb_packet_length is a negative number truncated
to a largish u16.  Positive obviously.

   282                  ether_packet_length = 
get_unaligned_le16(&header_start[2]);
   283                  skb_pull(skb, KALMIA_HEADER_LENGTH);
   284  
   285                  /* Some small packets misses end marker */
   286                  if (usb_packet_length < ether_packet_length) {

This condition is not true because usb_packet_length is largish.

   287                          ether_packet_length = usb_packet_length
   288                                  + KALMIA_HEADER_LENGTH;
   289                          is_last = true;
   290                  }
   291                  else {
   292                          netdev_dbg(dev->net, "Correct package length 
#%i", i
   293                                  + 1);
   294  

regards,
dan carpenter
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to