gpio: potential null dereference
Subsystems (2)
PATCH 1/1 gpio: potential null dereference
Smatch found a potential null dereference in gpio_setup_irq(). The "pdesc" variable is allocated with idr_find() that can return NULL. If gpio_setup_irq() is called with 0 as gpio_flags and "pdesc" is null, it would OOPs here.
drivers/gpio/gpiolib.c +2 -1
@@ -416,7 +416,8 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,return 0 ; free_sd: -sysfs_put (pdesc->value_sd); +if (pdesc) +sysfs_put (pdesc->value_sd); free_id:idr_remove (&pdesc_idr, id); desc->flags &=GPIO_FLAGS_MASK ;
Quoted 4 lines · Dan Carpenter
Smatch found a potential null dereference in
gpio_setup_irq(). The "pdesc" variable is allocated withidr_find()that can return NULL. Ifgpio_setup_irq()is called with 0 asgpio_flagsand "pdesc" is null, it would OOPs here.
idr_find() doesn't allocate, idr_get_new_above() does. Assuming idr_find() never fails for an id if idr_get_new_above() successfully allocated that id, I don't think we can reach that line with pdesc being NULL:
- There are two gotos leading to free_sd
- #2 is after a block that allocates pdesc
- #1 is in an if (!gpio_flags) block
- We exit early if ((desc->flags & GPIO_TRIGGER_MASK) = gpio_flags)
- Therefore (desc->flags & GPIO_TRIGGER_MASK) must be != 0 to reach #1
- Trigger flags are added to desc->flags only after we have successfully allocated pdesc (i.e. right before return 0)
- We start off with no trigger flags set
Daniel
Signature · 10 lines
Dipl.-Math. Daniel Glöckner, emlix GmbH, http://www.emlix.com Fon +49 551 30664-0, Fax -11, Bahnhofsallee 1b, 37081 Göttingen, Germany Sitz der Gesellschaft: Göttingen, Amtsgericht Göttingen HR B 3160 Geschäftsführung: Dr. Uwe Kracke, Ust-IdNr.: DE 205 198 055 emlix - your embedded linux partner -- To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 11 lines · On Tue, 27 Apr 2010 01:05:15 +0200 Daniel Gl__ckner <[email protected]> wrote:
Quoted 4 lines · Dan Carpenter
Smatch found a potential null dereference in
gpio_setup_irq(). The "pdesc" variable is allocated withidr_find()that can return NULL. Ifgpio_setup_irq()is called with 0 asgpio_flagsand "pdesc" is null, it would OOPs here.
idr_find()doesn't allocate,idr_get_new_above()does. Assumingidr_find()never fails for an id ifidr_get_new_above()successfully allocated that id, I don't think we can reach that line with pdesc being NULL:
Quoted 9 lines
- There are two gotos leading to
free_sd
- #2 is after a block that allocates pdesc
- #1 is in an if (!gpio_flags) block
- We exit early if ((desc->flags&GPIO_TRIGGER_MASK) =gpio_flags)
- Therefore (desc->flags&GPIO_TRIGGER_MASK) must be != 0 to reach #1
- Trigger flags are added todesc->flagsonly after we have successfully allocated pdesc (i.e. right before return 0)
- We start off with no trigger flags set
heh, thanks. I figured that something like that might be going on but couldn't be bothered picking through it all.
That being said, the above sequence of steps is awfully (and unusually) intricate and is hence hard to preserve and could get broken at some future time.
Quoted 11 lines · Daniel Glöckner
Quoted 4 lines · Dan Carpenter
Smatch found a potential null dereference in
gpio_setup_irq(). The "pdesc" variable is allocated withidr_find()that can return NULL. Ifgpio_setup_irq()is called with 0 asgpio_flagsand "pdesc" is null, it would OOPs here.
idr_find()doesn't allocate,idr_get_new_above()does. Assumingidr_find()never fails for an id ifidr_get_new_above()successfully allocated that id, I don't think we can reach that line with pdesc being NULL:
Quoted 9 lines
- There are two gotos leading to
free_sd
- #2 is after a block that allocates pdesc
- #1 is in an if (!gpio_flags) block
- We exit early if ((desc->flags&GPIO_TRIGGER_MASK) =gpio_flags)
- Therefore (desc->flags&GPIO_TRIGGER_MASK) must be != 0 to reach #1
- Trigger flags are added todesc->flagsonly after we have successfully allocated pdesc (i.e. right before return 0)
- We start off with no trigger flags set
Are you sure? If we know that the call to idr_find() returns a valid pointer we could remove a lot of error handling code...
drivers/gpio/gpiolib.c +1 -49
@@ -330,14 +330,6 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)return IRQ_HANDLED ; } -static void gpio_notify_sysfs (struct work_struct *work) -{ -struct poll_desc *pdesc; - - pdesc = container_of(work, struct poll_desc, work); -sysfs_notify_dirent (pdesc->value_sd); -} -static int gpio_setup_irq (struct gpio_desc *desc,struct device *dev,unsigned long gpio_flags) {
@@ -353,14 +345,10 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,return -EIO ; id = desc->flags >>PDESC_ID_SHIFT ; +/* idr_find() always returns a valid pointer here */ pdesc =idr_find (&pdesc_idr, id); -if (pdesc) { -free_irq (irq, &pdesc->work); -cancel_work_sync (&pdesc->work); - } desc->flags &= ~GPIO_TRIGGER_MASK ; -if (!gpio_flags) { ret =0 ; goto free_sd;
@@ -374,39 +362,6 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, irq_flags |=test_bit (FLAG_ACTIVE_LOW , &desc->flags) ?IRQF_TRIGGER_FALLING :IRQF_TRIGGER_RISING ; -if (!pdesc) { - pdesc =kmalloc (sizeof (*pdesc),GFP_KERNEL ); -if (!pdesc) { - ret = -ENOMEM ; - goto err_out; - } - -do { - ret = -ENOMEM ; -if (idr_pre_get (&pdesc_idr,GFP_KERNEL )) - ret =idr_get_new_above (&pdesc_idr, - pdesc,1 , &id); - }while (ret = -EAGAIN ); - -if (ret) - goto free_mem; - - desc->flags &=GPIO_FLAGS_MASK ; - desc->flags |= (unsigned long )id <<PDESC_ID_SHIFT ; - -if (desc->flags >>PDESC_ID_SHIFT != id) { - ret = -ERANGE ; - goto free_id; - } - - pdesc->value_sd =sysfs_get_dirent (dev->kobj.sd,"value" ); -if (!pdesc->value_sd) { - ret = -ENODEV ; - goto free_id; - } -INIT_WORK (&pdesc->work, gpio_notify_sysfs); - } - ret =request_irq (irq, gpio_sysfs_irq, irq_flags,"gpiolib" , &pdesc->work);if (ret)
@@ -417,12 +372,9 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, free_sd:sysfs_put (pdesc->value_sd); -free_id:idr_remove (&pdesc_idr, id); desc->flags &=GPIO_FLAGS_MASK ; -free_mem:kfree (pdesc); -err_out:return ret; }
--
To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 21 lines · Dan Carpenter
Quoted 10 lines · Daniel Glöckner
Quoted 4 lines · Dan Carpenter
Smatch found a potential null dereference in
gpio_setup_irq(). The "pdesc" variable is allocated withidr_find()that can return NULL. Ifgpio_setup_irq()is called with 0 asgpio_flagsand "pdesc" is null, it would OOPs here.
idr_find()doesn't allocate,idr_get_new_above()does. Assumingidr_find()never fails for an id ifidr_get_new_above()successfully allocated that id, I don't think we can reach that line with pdesc being NULL:Quoted 9 lines
- There are two gotos leading to
free_sd
- #2 is after a block that allocates pdesc
- #1 is in an if (!gpio_flags) block
- We exit early if ((desc->flags&GPIO_TRIGGER_MASK) =gpio_flags)
- Therefore (desc->flags&GPIO_TRIGGER_MASK) must be != 0 to reach #1
- Trigger flags are added todesc->flagsonly after we have successfully allocated pdesc (i.e. right before return 0)
- We start off with no trigger flags set
Quoted 2 lines
Are you sure? If we know that the call to
idr_find()returns a valid pointer we could remove a lot of error handling code...
It returns a valid pointer iff (desc->flags & GPIO_TRIGGER_MASK).
When !(desc->flags & GPIO_TRIGGER_MASK) it returns NULL and everything gets allocated (unless !gpio_flags as well). What you wanted to remove is the allocation code, not error handling code. It is always run when the trigger is set from "none" to something else.
Daniel
Signature · 10 lines
Dipl.-Math. Daniel Glöckner, emlix GmbH, http://www.emlix.com Fon +49 551 30664-0, Fax -11, Bahnhofsallee 1b, 37081 Göttingen, Germany Sitz der Gesellschaft: Göttingen, Amtsgericht Göttingen HR B 3160 Geschäftsführer: Dr. Uwe Kracke, Ust-IdNr.: DE 205 198 055 emlix - your embedded linux partner -- To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 5 lines · Daniel Glöckner
It returns a valid pointer iff (
desc->flags&GPIO_TRIGGER_MASK).When !(desc->flags &
GPIO_TRIGGER_MASK) it returns NULL and everything gets allocated (unless !gpio_flags as well). What you wanted to remove is the allocation code, not error handling code.
No no. I don't want to remove anything. I'm happy with the code as is now that you've explained it to me. :)
regards,
dan carpenter
Quoted 5 lines
It is always run when
the trigger is set from "none" to something else.Daniel
--
To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html