вторник, 14 января 2020 г.

using devm_kcalloc unchecked result in linux kernel

Part I
This time I add references to linux kernel github - although I ran my naive code analyzer on version 4.18 - all found bugs have long and happy life in current source tree

gb_generate_enum_strings in drivers/staging/greybus/audio_topology.c:
strings = devm_kcalloc(gb->dev, items, sizeof(char *), GFP_KERNEL);
data = gbenum->names;

for (i = 0; i < items; i++) {
  strings[i] = (const char *)data;


rt2880_pinmux_pins in drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c:  
p->func[i]->pins = devm_kcalloc(p->dev,
                p->func[i]->pin_count,
                sizeof(int),
                GFP_KERNEL);
for (j = 0; j < p->func[i]->pin_count; j++)
  p->func[i]->pins[j] = p->func[i]->pin_first + j;


Using unchecked result from devm_kmalloc_array:
ti_sci_scan_clocks_from_fw in drivers/clk/keystone/sci-clk.c:
tmp_clks = devm_kmalloc_array(dev, max_clks + 64,
                  sizeof(sci_clk),
                  GFP_KERNEL);
memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk));


Doubtful case (I think is has delayed effects bcs no checks for ports field) - function mscc_ocelot_probe in drivers/net/ethernet/mscc/ocelot_board.c
ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
                     sizeof(struct ocelot_port *), GFP_KERNEL);

понедельник, 13 января 2020 г.

using devm_kzalloc unchecked result in linux kernel 4.18

Managed Device Resource (described in Documentation/driver-model/devres.txt) is witty technique for lazy developers. Unfortunately it does not exempt from the need to check results. I decided to see if there are such places in linux kernel (which can lead to null address dereference). Right way to do it is use Static Analyzer like clang, coverity or PVS Studio. But I am too lazy so I wrote simple and naive perl script and run it on linux kernel 4.18 source tree. It found 56 cases (from total 4173 where devm_kzalloc was used) - not too much for manual checking. So lets see what we have

impd1_probe in arch/arm/mach-integrator/impd1.c:
            lookup = devm_kzalloc(&dev->dev,
                          sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup),
                          GFP_KERNEL);
            chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL);
            mmciname = kasprintf(GFP_KERNEL, "lm%x:00700", dev->id);
            lookup->dev_id = mmciname;



st_sensors_of_probe in drivers/iio/common/st_sensors/st_sensors_core.c (still not fixed):
    pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
    if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2))
        pdata->drdy_int_pin = (u8) val;
    else
        pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;

    pdata->open_drain = of_property_read_bool(np, "drive-open-drain");



sm501_register_gpio_i2c_instance in drivers/mfd/sm501.c:
    lookup = devm_kzalloc(&pdev->dev,
                  sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup),
                  GFP_KERNEL);
    lookup->dev_id = "i2c-gpio";
    if (iic->pin_sda < 32)
        lookup->table[0].chip_label = "SM501-LOW";
    else
        lookup->table[0].chip_label = "SM501-HIGH";
    lookup->table[0].chip_hwnum = iic->pin_sda % 32;
    lookup->table[0].con_id = NULL;
    lookup->table[0].idx = 0;
    lookup->table[0].flags = GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN;


rt2880_pinmux_index in drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c (still not fixed):
            f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL);
            f[c]->groups[0] = i;


rt2880_pinmux_probe in drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c

        range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL);
        range->name = name = (char *) &range[1];
        sprintf(name, "pio");
        range->npins = __be32_to_cpu(*ngpio);
        range->base = __be32_to_cpu(*gpiobase);
        range->pin_base = range->base;





rt5514_spi_pcm_probe in sound/soc/codecs/rt5514-spi.c:
    rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp),
            GFP_KERNEL);

    rt5514_dsp->dev = &rt5514_spi->dev;
    mutex_init(&rt5514_dsp->dma_lock);



rt5663_parse_dp in sound/soc/codecs/rt5663.c (still not fixed):
        rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL);
        device_property_read_u32_array(dev,
            "realtek,impedance_sensing_table",
            (u32 *)rt5663->imp_table, table_size);



perl script used to find this bugs:

пятница, 3 января 2020 г.

typos in "Linux Device Drivers Development"

I decided in retirement to fill the gaps in my education, so now I reading book "Linux Device Drivers Development" and noticed lots of annoying typos in code samples

page 65:
/* some where */
spinlock_t my_spinlock;
spin_lock_init(my_spinlock);
static irqreturn_t my_irq_handler(int irq, void *data)
{
 unsigned long status, flags;
 spin_lock_irqsave(&my_spinlock, flags);
 status = access_shared_resources();
 spin_unlock_irqrestore(&gpio->slock, flags); // wut? &
my_spinlock
 return IRQ_HANDLED;
}


page 103-104:
struct my_data {
 int my_int_var;
 struct tasklet_struct the_tasklet;
 int dma_request;
};


static irqreturn_t my_irq_handler(int irq, void *dev_id)
{
  struct my_data *md = dev_id;
  /* Let's schedule our tasklet */
  tasklet_schedule(&md.dma_tasklet); // wut? &md->
the_tasklet
  return IRQ_HANDLED;
}

 
page 127:
/* Move the cursor ten time, relative from the beginning of the file */
if (lseek(fd, 7, SEEK_SET) < 0)
return 1;


An so on. Seems that code samples looks like Frankenstein ripped from some random kernel places