diff options
author | Tony Lindgren <tony@atomide.com> | 2012-01-24 19:28:08 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-01-26 08:13:11 -0500 |
commit | b9130b776ee481acbc27a7e56d98df75680de369 (patch) | |
tree | b7933b4d3e562e806c3dc61544352e46f35820cb | |
parent | 9e2551e10b5c7ba550849bd9ed519e498cc30e68 (diff) |
pinctrl: add checks for empty function names
This is needed as otherwise we can get the following when
dealing with buggy data in a pinmux driver for
pinmux_search_function:
Unable to handle kernel NULL pointer dereference at virtual
address 00000000
...
PC is at strcmp+0xc/0x34
LR is at pinmux_get+0x350/0x8f4
...
As we need pctldev initialized to call ops->list_functions,
let's initialize it before check_ops calls and pass the
pctldev to the check_ops functions. Do this for both pinmux
and pinconf check_ops functions.
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/pinctrl/core.c | 36 | ||||
-rw-r--r-- | drivers/pinctrl/pinconf.c | 4 | ||||
-rw-r--r-- | drivers/pinctrl/pinconf.h | 4 | ||||
-rw-r--r-- | drivers/pinctrl/pinmux.c | 17 | ||||
-rw-r--r-- | drivers/pinctrl/pinmux.h | 4 |
5 files changed, 41 insertions, 24 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index d9d35fcbfc6b..8fe15cf15ac8 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c | |||
@@ -583,40 +583,40 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, | |||
583 | if (pctldesc->name == NULL) | 583 | if (pctldesc->name == NULL) |
584 | return NULL; | 584 | return NULL; |
585 | 585 | ||
586 | pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL); | ||
587 | if (pctldev == NULL) | ||
588 | return NULL; | ||
589 | |||
590 | /* Initialize pin control device struct */ | ||
591 | pctldev->owner = pctldesc->owner; | ||
592 | pctldev->desc = pctldesc; | ||
593 | pctldev->driver_data = driver_data; | ||
594 | INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); | ||
595 | spin_lock_init(&pctldev->pin_desc_tree_lock); | ||
596 | INIT_LIST_HEAD(&pctldev->gpio_ranges); | ||
597 | mutex_init(&pctldev->gpio_ranges_lock); | ||
598 | pctldev->dev = dev; | ||
599 | |||
586 | /* If we're implementing pinmuxing, check the ops for sanity */ | 600 | /* If we're implementing pinmuxing, check the ops for sanity */ |
587 | if (pctldesc->pmxops) { | 601 | if (pctldesc->pmxops) { |
588 | ret = pinmux_check_ops(pctldesc->pmxops); | 602 | ret = pinmux_check_ops(pctldev); |
589 | if (ret) { | 603 | if (ret) { |
590 | pr_err("%s pinmux ops lacks necessary functions\n", | 604 | pr_err("%s pinmux ops lacks necessary functions\n", |
591 | pctldesc->name); | 605 | pctldesc->name); |
592 | return NULL; | 606 | goto out_err; |
593 | } | 607 | } |
594 | } | 608 | } |
595 | 609 | ||
596 | /* If we're implementing pinconfig, check the ops for sanity */ | 610 | /* If we're implementing pinconfig, check the ops for sanity */ |
597 | if (pctldesc->confops) { | 611 | if (pctldesc->confops) { |
598 | ret = pinconf_check_ops(pctldesc->confops); | 612 | ret = pinconf_check_ops(pctldev); |
599 | if (ret) { | 613 | if (ret) { |
600 | pr_err("%s pin config ops lacks necessary functions\n", | 614 | pr_err("%s pin config ops lacks necessary functions\n", |
601 | pctldesc->name); | 615 | pctldesc->name); |
602 | return NULL; | 616 | goto out_err; |
603 | } | 617 | } |
604 | } | 618 | } |
605 | 619 | ||
606 | pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL); | ||
607 | if (pctldev == NULL) | ||
608 | return NULL; | ||
609 | |||
610 | /* Initialize pin control device struct */ | ||
611 | pctldev->owner = pctldesc->owner; | ||
612 | pctldev->desc = pctldesc; | ||
613 | pctldev->driver_data = driver_data; | ||
614 | INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); | ||
615 | spin_lock_init(&pctldev->pin_desc_tree_lock); | ||
616 | INIT_LIST_HEAD(&pctldev->gpio_ranges); | ||
617 | mutex_init(&pctldev->gpio_ranges_lock); | ||
618 | pctldev->dev = dev; | ||
619 | |||
620 | /* Register all the pins */ | 620 | /* Register all the pins */ |
621 | pr_debug("try to register %d pins on %s...\n", | 621 | pr_debug("try to register %d pins on %s...\n", |
622 | pctldesc->npins, pctldesc->name); | 622 | pctldesc->npins, pctldesc->name); |
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 1892a3794b99..9fb75456824c 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c | |||
@@ -205,8 +205,10 @@ int pin_config_group_set(const char *dev_name, const char *pin_group, | |||
205 | } | 205 | } |
206 | EXPORT_SYMBOL(pin_config_group_set); | 206 | EXPORT_SYMBOL(pin_config_group_set); |
207 | 207 | ||
208 | int pinconf_check_ops(const struct pinconf_ops *ops) | 208 | int pinconf_check_ops(struct pinctrl_dev *pctldev) |
209 | { | 209 | { |
210 | const struct pinconf_ops *ops = pctldev->desc->confops; | ||
211 | |||
210 | /* We must be able to read out pin status */ | 212 | /* We must be able to read out pin status */ |
211 | if (!ops->pin_config_get && !ops->pin_config_group_get) | 213 | if (!ops->pin_config_get && !ops->pin_config_group_get) |
212 | return -EINVAL; | 214 | return -EINVAL; |
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index e7dc6165032a..006b77fa737e 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #ifdef CONFIG_PINCONF | 14 | #ifdef CONFIG_PINCONF |
15 | 15 | ||
16 | int pinconf_check_ops(const struct pinconf_ops *ops); | 16 | int pinconf_check_ops(struct pinctrl_dev *pctldev); |
17 | void pinconf_init_device_debugfs(struct dentry *devroot, | 17 | void pinconf_init_device_debugfs(struct dentry *devroot, |
18 | struct pinctrl_dev *pctldev); | 18 | struct pinctrl_dev *pctldev); |
19 | int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, | 19 | int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, |
@@ -23,7 +23,7 @@ int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin, | |||
23 | 23 | ||
24 | #else | 24 | #else |
25 | 25 | ||
26 | static inline int pinconf_check_ops(const struct pinconf_ops *ops) | 26 | static inline int pinconf_check_ops(struct pinctrl_dev *pctldev) |
27 | { | 27 | { |
28 | return 0; | 28 | return 0; |
29 | } | 29 | } |
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 3ffa9324ed82..7c3193f7a044 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c | |||
@@ -889,8 +889,11 @@ void pinmux_disable(struct pinmux *pmx) | |||
889 | } | 889 | } |
890 | EXPORT_SYMBOL_GPL(pinmux_disable); | 890 | EXPORT_SYMBOL_GPL(pinmux_disable); |
891 | 891 | ||
892 | int pinmux_check_ops(const struct pinmux_ops *ops) | 892 | int pinmux_check_ops(struct pinctrl_dev *pctldev) |
893 | { | 893 | { |
894 | const struct pinmux_ops *ops = pctldev->desc->pmxops; | ||
895 | unsigned selector = 0; | ||
896 | |||
894 | /* Check that we implement required operations */ | 897 | /* Check that we implement required operations */ |
895 | if (!ops->list_functions || | 898 | if (!ops->list_functions || |
896 | !ops->get_function_name || | 899 | !ops->get_function_name || |
@@ -899,6 +902,18 @@ int pinmux_check_ops(const struct pinmux_ops *ops) | |||
899 | !ops->disable) | 902 | !ops->disable) |
900 | return -EINVAL; | 903 | return -EINVAL; |
901 | 904 | ||
905 | /* Check that all functions registered have names */ | ||
906 | while (ops->list_functions(pctldev, selector) >= 0) { | ||
907 | const char *fname = ops->get_function_name(pctldev, | ||
908 | selector); | ||
909 | if (!fname) { | ||
910 | pr_err("pinmux ops has no name for function%u\n", | ||
911 | selector); | ||
912 | return -EINVAL; | ||
913 | } | ||
914 | selector++; | ||
915 | } | ||
916 | |||
902 | return 0; | 917 | return 0; |
903 | } | 918 | } |
904 | 919 | ||
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h index 844500b3331b..97f52223fbc2 100644 --- a/drivers/pinctrl/pinmux.h +++ b/drivers/pinctrl/pinmux.h | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | #ifdef CONFIG_PINMUX | 13 | #ifdef CONFIG_PINMUX |
14 | 14 | ||
15 | int pinmux_check_ops(const struct pinmux_ops *ops); | 15 | int pinmux_check_ops(struct pinctrl_dev *pctldev); |
16 | void pinmux_init_device_debugfs(struct dentry *devroot, | 16 | void pinmux_init_device_debugfs(struct dentry *devroot, |
17 | struct pinctrl_dev *pctldev); | 17 | struct pinctrl_dev *pctldev); |
18 | void pinmux_init_debugfs(struct dentry *subsys_root); | 18 | void pinmux_init_debugfs(struct dentry *subsys_root); |
@@ -21,7 +21,7 @@ void pinmux_unhog_maps(struct pinctrl_dev *pctldev); | |||
21 | 21 | ||
22 | #else | 22 | #else |
23 | 23 | ||
24 | static inline int pinmux_check_ops(const struct pinmux_ops *ops) | 24 | static inline int pinmux_check_ops(struct pinctrl_dev *pctldev) |
25 | { | 25 | { |
26 | return 0; | 26 | return 0; |
27 | } | 27 | } |