2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

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>
This commit is contained in:
Tony Lindgren 2012-01-24 16:28:08 -08:00 committed by Linus Walleij
parent 9e2551e10b
commit b9130b776e
5 changed files with 43 additions and 26 deletions

View File

@ -583,26 +583,6 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
if (pctldesc->name == NULL) if (pctldesc->name == NULL)
return NULL; return NULL;
/* If we're implementing pinmuxing, check the ops for sanity */
if (pctldesc->pmxops) {
ret = pinmux_check_ops(pctldesc->pmxops);
if (ret) {
pr_err("%s pinmux ops lacks necessary functions\n",
pctldesc->name);
return NULL;
}
}
/* If we're implementing pinconfig, check the ops for sanity */
if (pctldesc->confops) {
ret = pinconf_check_ops(pctldesc->confops);
if (ret) {
pr_err("%s pin config ops lacks necessary functions\n",
pctldesc->name);
return NULL;
}
}
pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL); pctldev = kzalloc(sizeof(struct pinctrl_dev), GFP_KERNEL);
if (pctldev == NULL) if (pctldev == NULL)
return NULL; return NULL;
@ -617,6 +597,26 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
mutex_init(&pctldev->gpio_ranges_lock); mutex_init(&pctldev->gpio_ranges_lock);
pctldev->dev = dev; pctldev->dev = dev;
/* If we're implementing pinmuxing, check the ops for sanity */
if (pctldesc->pmxops) {
ret = pinmux_check_ops(pctldev);
if (ret) {
pr_err("%s pinmux ops lacks necessary functions\n",
pctldesc->name);
goto out_err;
}
}
/* If we're implementing pinconfig, check the ops for sanity */
if (pctldesc->confops) {
ret = pinconf_check_ops(pctldev);
if (ret) {
pr_err("%s pin config ops lacks necessary functions\n",
pctldesc->name);
goto out_err;
}
}
/* Register all the pins */ /* Register all the pins */
pr_debug("try to register %d pins on %s...\n", pr_debug("try to register %d pins on %s...\n",
pctldesc->npins, pctldesc->name); pctldesc->npins, pctldesc->name);

View File

@ -205,8 +205,10 @@ int pin_config_group_set(const char *dev_name, const char *pin_group,
} }
EXPORT_SYMBOL(pin_config_group_set); EXPORT_SYMBOL(pin_config_group_set);
int pinconf_check_ops(const struct pinconf_ops *ops) int pinconf_check_ops(struct pinctrl_dev *pctldev)
{ {
const struct pinconf_ops *ops = pctldev->desc->confops;
/* We must be able to read out pin status */ /* We must be able to read out pin status */
if (!ops->pin_config_get && !ops->pin_config_group_get) if (!ops->pin_config_get && !ops->pin_config_group_get)
return -EINVAL; return -EINVAL;

View File

@ -13,7 +13,7 @@
#ifdef CONFIG_PINCONF #ifdef CONFIG_PINCONF
int pinconf_check_ops(const struct pinconf_ops *ops); int pinconf_check_ops(struct pinctrl_dev *pctldev);
void pinconf_init_device_debugfs(struct dentry *devroot, void pinconf_init_device_debugfs(struct dentry *devroot,
struct pinctrl_dev *pctldev); struct pinctrl_dev *pctldev);
int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, 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,
#else #else
static inline int pinconf_check_ops(const struct pinconf_ops *ops) static inline int pinconf_check_ops(struct pinctrl_dev *pctldev)
{ {
return 0; return 0;
} }

View File

@ -889,8 +889,11 @@ void pinmux_disable(struct pinmux *pmx)
} }
EXPORT_SYMBOL_GPL(pinmux_disable); EXPORT_SYMBOL_GPL(pinmux_disable);
int pinmux_check_ops(const struct pinmux_ops *ops) int pinmux_check_ops(struct pinctrl_dev *pctldev)
{ {
const struct pinmux_ops *ops = pctldev->desc->pmxops;
unsigned selector = 0;
/* Check that we implement required operations */ /* Check that we implement required operations */
if (!ops->list_functions || if (!ops->list_functions ||
!ops->get_function_name || !ops->get_function_name ||
@ -899,6 +902,18 @@ int pinmux_check_ops(const struct pinmux_ops *ops)
!ops->disable) !ops->disable)
return -EINVAL; return -EINVAL;
/* Check that all functions registered have names */
while (ops->list_functions(pctldev, selector) >= 0) {
const char *fname = ops->get_function_name(pctldev,
selector);
if (!fname) {
pr_err("pinmux ops has no name for function%u\n",
selector);
return -EINVAL;
}
selector++;
}
return 0; return 0;
} }

View File

@ -12,7 +12,7 @@
*/ */
#ifdef CONFIG_PINMUX #ifdef CONFIG_PINMUX
int pinmux_check_ops(const struct pinmux_ops *ops); int pinmux_check_ops(struct pinctrl_dev *pctldev);
void pinmux_init_device_debugfs(struct dentry *devroot, void pinmux_init_device_debugfs(struct dentry *devroot,
struct pinctrl_dev *pctldev); struct pinctrl_dev *pctldev);
void pinmux_init_debugfs(struct dentry *subsys_root); void pinmux_init_debugfs(struct dentry *subsys_root);
@ -21,7 +21,7 @@ void pinmux_unhog_maps(struct pinctrl_dev *pctldev);
#else #else
static inline int pinmux_check_ops(const struct pinmux_ops *ops) static inline int pinmux_check_ops(struct pinctrl_dev *pctldev)
{ {
return 0; return 0;
} }