Re: usb: gadget: nokia: convert to new interface of f_phonet

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

 



Hello Dan Carpenter,

Thank you for your comments.

W dniu 13.12.2013 12:22, Dan Carpenter pisze:
Hello Andrzej Pietrasiewicz,

The patch 83167f12da05: "usb: gadget: nokia: convert to new interface
of f_phonet" from May 23, 2013, leads to the following Smatch
warnings:

drivers/usb/gadget/nokia.c:209 nokia_bind_config() error: potential NULL dereference 'f_obex2'.
drivers/usb/gadget/nokia.c:211 nokia_bind_config() error: potential NULL dereference 'f_obex1'.
drivers/usb/gadget/nokia.c:213 nokia_bind_config() error: potential NULL dereference 'f_phonet'.

Let me walk you throug the code for the first warning.

drivers/usb/gadget/nokia.c
    115  static struct usb_function_instance *fi_acm;
    116  static struct usb_function_instance *fi_ecm;
    117  static struct usb_function_instance *fi_obex1;
    118  static struct usb_function_instance *fi_obex2;
    119  static struct usb_function_instance *fi_phonet;
    120
    121  static int __init nokia_bind_config(struct usb_configuration *c)
    122  {
    123          struct usb_function *f_acm;
    124          struct usb_function *f_phonet = NULL;
    125          struct usb_function *f_obex1 = NULL;
    126          struct usb_function *f_ecm;
    127          struct usb_function *f_obex2 = NULL;
    128          int status = 0;
    129          int obex1_stat = 0;
    130          int obex2_stat = 0;
    131          int phonet_stat = 0;

We need to trace three variables to understand the first warning
message: fi_obex2, f_obex2, and obex2_stat.

Lets start with the assumption that "fi_obex2" is an error pointer at
the start of the function.
f_obex2 is NULL.
obex2_stat is zero.

    132
    133          if (!IS_ERR(fi_phonet)) {
    134                  f_phonet = usb_get_function(fi_phonet);
    135                  if (IS_ERR(f_phonet))
    136                          pr_debug("could not get phonet function\n");
    137          }
    138
    139          if (!IS_ERR(fi_obex1)) {
    140                  f_obex1 = usb_get_function(fi_obex1);
    141                  if (IS_ERR(f_obex1))
    142                          pr_debug("could not get obex function 0\n");

It's funny that the human readable messages start counting from zero as
in "obex function 0" and "obex function 1" but the computer code starts
counting from 1 as in "fi_obex1" and "fi_obex2".  Normally you would
expect it to be the other way around.  Also this is not consistent with
the rest of the driver.

    143          }
    144
    145          if (!IS_ERR(fi_obex2)) {
    146                  f_obex2 = usb_get_function(fi_obex2);
    147                  if (IS_ERR(f_obex2))
    148                          pr_debug("could not get obex function 1\n");
    149          }

fi_obex2 is an error pointer.
f_obex2 is NULL.
obex2_stat is zero.

    150
    151          f_acm = usb_get_function(fi_acm);
    152          if (IS_ERR(f_acm)) {
    153                  status = PTR_ERR(f_acm);
    154                  goto err_get_acm;
    155          }
    156
    157          f_ecm = usb_get_function(fi_ecm);
    158          if (IS_ERR(f_ecm)) {
    159                  status = PTR_ERR(f_ecm);
    160                  goto err_get_ecm;
    161          }
    162
    163          if (!IS_ERR_OR_NULL(f_phonet)) {
    164                  phonet_stat = usb_add_function(c, f_phonet);
    165                  if (phonet_stat)
    166                          pr_debug("could not add phonet function\n");
    167          }
    168
    169          if (!IS_ERR_OR_NULL(f_obex1)) {
    170                  obex1_stat = usb_add_function(c, f_obex1);
    171                  if (obex1_stat)
    172                          pr_debug("could not add obex function 0\n");
    173          }
    174
    175          if (!IS_ERR_OR_NULL(f_obex2)) {
    176                  obex2_stat = usb_add_function(c, f_obex2);
    177                  if (obex2_stat)
    178                          pr_debug("could not add obex function 1\n");
    179          }

f_obex2 is NULL so the condition is false.
obex2_stat is zero.

    180
    181          status = usb_add_function(c, f_acm);
    182          if (status)
    183                  goto err_conf;

Let's assume we hit this goto.

    184
    185          status = usb_add_function(c, f_ecm);
    186          if (status) {
    187                  pr_debug("could not bind ecm config %d\n", status);
    188                  goto err_ecm;
    189          }
    190          if (c == &nokia_config_500ma_driver) {
    191                  f_acm_cfg1 = f_acm;
    192                  f_ecm_cfg1 = f_ecm;
    193                  f_phonet_cfg1 = f_phonet;
    194                  f_obex1_cfg1 = f_obex1;
    195                  f_obex2_cfg1 = f_obex2;
    196          } else {
    197                  f_acm_cfg2 = f_acm;
    198                  f_ecm_cfg2 = f_ecm;
    199                  f_phonet_cfg2 = f_phonet;
    200                  f_obex1_cfg2 = f_obex1;
    201                  f_obex2_cfg2 = f_obex2;

Btw, we are assigning an ERR_PTR to the global here.  It means we need
to constantly check it, which the code does, but it's messy.  The driver
would be cleaner if we never did this.

    202          }
    203
    204          return status;

Just "return 0" here to make it more obvious that we are returning zero.

    205  err_ecm:
    206          usb_remove_function(c, f_acm);
    207  err_conf:
    208          if (!obex2_stat)
    209                  usb_remove_function(c, f_obex2);

obex2_stat is zero.
f_obex2 is NULL.
This causes a NULL dereference.

We could initialize obex2_stat to -1 instead of 0 which would fix the
NULL deref

I'd choose this approach.

but the real problem is that this code is quite messy.

Please see below.


We should be clearing the ERR_PTRs right away if we aren't going to use
the values.

		f_obex1 = usb_get_function(fi_obex1);
		if (IS_ERR(f_obex1)) {
			pr_debug("could not get obex function 0\n");
			f_obex1 = NULL;
		}

I'm not very familiar with this hardware, why is it not an error when
the usb_get_function() and usb_add_function() calls fail?


The driver is not hardware-related; it is isolated from the hardware by the
udc-core layer.

The point here is that this is a legacy gadget (not using configfs), and
this behaviour follows the original design of this gadget: some USB functions
it provides are optional. Which means that even if they cannot be successfully
found (usb_get_function() fails) the gadget should still bind with reduced
functionality.
    210          if (!obex1_stat)
    211                  usb_remove_function(c, f_obex1);
    212          if (!phonet_stat)
    213                  usb_remove_function(c, f_phonet);
    214          usb_put_function(f_ecm);
    215  err_get_ecm:
    216          usb_put_function(f_acm);
    217  err_get_acm:
    218          if (!IS_ERR_OR_NULL(f_obex2))
    219                  usb_put_function(f_obex2);
    220          if (!IS_ERR_OR_NULL(f_obex1))
    221                  usb_put_function(f_obex1);
    222          if (!IS_ERR_OR_NULL(f_phonet))
    223                  usb_put_function(f_phonet);
    224          return status;
    225  }

regards,
dan carpenter



Thanks,

Andrzej Pietrasiewicz
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux