History

Merge tag 'for-linus-7.3-1' of https://github.com/cminyard/linux-ipmi

Pull ipmi updates from Corey Minyard: "Several cleanup on error fixes and a missing RCU wait and proper validation on a received message in one place. The biggest change is the initialization of the driver can be done asynchronously on a work queue. That saves significant boot time" * tag 'for-linus-7.3-1' of https://github.com/cminyard/linux-ipmi: ipmi: Fix use-after-free of cmd_rcvr in _ipmi_destroy_user() ipmi:msghandler: Cancel work cleanly on an error ipmi:si: Add async init to ipmi_si char: ipmi: use named initializers for acpi_device_id ipmi: Fix leak in __ipmi_bmc_register ipmi: Remove all sysfs files on registration failure ipmi: si: Fix NULL pointer dereference after failed registration ipmi: ipmb: validate write message length

Linus Torvalds committed 2 months ago

Commit 4cc4cc32 parents 548e7bc 05ec76c6 files · +86 −24Browse files

Unified · Split

6 files
  1. drivers/char/ipmi/Kconfig +9 −0
  2. drivers/char/ipmi/ipmb_dev_int.c +5 −4
  3. drivers/char/ipmi/ipmi_msghandler.c +5 −0
  4. drivers/char/ipmi/ipmi_si_intf.c +63 −16
  5. drivers/char/ipmi/ipmi_si_platform.c +2 −2
  6. drivers/char/ipmi/ipmi_ssif.c +2 −2
drivers/char/ipmi/Kconfig+9−0
@@ -67,6 +67,15 @@ config IPMI_SI · 66 unmodified lines
67 Currently, only KCS and SMIC are supported. If67 Currently, only KCS and SMIC are supported. If
68 you are using IPMI, you should probably say "y" here.68 you are using IPMI, you should probably say "y" here.
69 69
70config IPMI_SI_ASYNC_INIT
71 bool 'Asynchronous initialization of IPMI System Interface'
72 depends on IPMI_SI
73 default n
74 help
75 Offloads individual SMI inits. It speeds up the boot time.
76 It also introduces a very small risk that something else might fail
77 if it depends on synchronous IPMI init.
78
70config IPMI_SSIF79config IPMI_SSIF
71 tristate 'IPMI SMBus handler (SSIF)'80 tristate 'IPMI SMBus handler (SSIF)'
72 depends on I2C81 depends on I2C
drivers/char/ipmi/ipmb_dev_int.c+5−4
@@ -141,13 +141,14 @@ static ssize_t ipmb_write(struct file *file, const char __user *buf, · 140 unmodified lines
141 u8 msg[MAX_MSG_LEN];141 u8 msg[MAX_MSG_LEN];
142 ssize_t ret;142 ssize_t ret;
143 143
144 if (count > sizeof(msg))144 if (!count || count > sizeof(msg))
145 return -EINVAL;145 return -EINVAL;
146 146
147 if (copy_from_user(&msg, buf, count))147 if (copy_from_user(&msg, buf, count))
148 return -EFAULT;148 return -EFAULT;
149 149
150 if (count < msg[0])150 if (msg[IPMB_MSG_LEN_IDX] < IPMB_REQUEST_LEN_MIN ||
151 count < (size_t)msg[IPMB_MSG_LEN_IDX] + 1)
151 return -EINVAL;152 return -EINVAL;
152 153
153 rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);154 rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);
@@ -360,8 +361,8 @@ MODULE_DEVICE_TABLE(i2c, ipmb_id); · 206 unmodified lines
360 361
361#ifdef CONFIG_ACPI362#ifdef CONFIG_ACPI
362static const struct acpi_device_id acpi_ipmb_id[] = {363static const struct acpi_device_id acpi_ipmb_id[] = {
363 { "IPMB0001", 0 },364 { .id = "IPMB0001" },
364 {},365 { }
365};366};
366MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);367MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id);
367#endif368#endif
drivers/char/ipmi/ipmi_msghandler.c+5−0
@@ -1391,6 +1391,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user) · 1390 unmodified lines
1391 }1391 }
1392 }1392 }
1393 mutex_unlock(&intf->cmd_rcvrs_mutex);1393 mutex_unlock(&intf->cmd_rcvrs_mutex);
1394 synchronize_rcu();
1394 while (rcvrs) {1395 while (rcvrs) {
1395 rcvr = rcvrs;1396 rcvr = rcvrs;
1396 rcvrs = rcvr->next;1397 rcvrs = rcvr->next;
@@ -3301,6 +3302,7 @@ out_list_del: · 1904 unmodified lines
3301 list_del(&intf->bmc_link);3302 list_del(&intf->bmc_link);
3302 mutex_unlock(&bmc->dyn_mutex);3303 mutex_unlock(&bmc->dyn_mutex);
3303 intf->bmc = &intf->tmp_bmc;3304 intf->bmc = &intf->tmp_bmc;
3305 ida_free(&ipmi_bmc_ida, bmc->pdev.id);
3304 put_device(&bmc->pdev.dev);3306 put_device(&bmc->pdev.dev);
3305 goto out;3307 goto out;
3306}3308}
@@ -3740,6 +3742,7 @@ int ipmi_add_smi(struct module *owner, · 433 unmodified lines
3740 sysfs_attr_init(&intf->maintenance_mode_devattr.attr);3742 sysfs_attr_init(&intf->maintenance_mode_devattr.attr);
3741 rv = device_create_file(intf->si_dev, &intf->maintenance_mode_devattr);3743 rv = device_create_file(intf->si_dev, &intf->maintenance_mode_devattr);
3742 if (rv) {3744 if (rv) {
3745 device_remove_file(intf->si_dev, &intf->nr_msgs_devattr);
3743 device_remove_file(intf->si_dev, &intf->nr_users_devattr);3746 device_remove_file(intf->si_dev, &intf->nr_users_devattr);
3744 goto out_err_bmc_reg;3747 goto out_err_bmc_reg;
3745 }3748 }
@@ -3757,12 +3760,14 @@ int ipmi_add_smi(struct module *owner, · 11 unmodified lines
3757 out_err_bmc_reg:3760 out_err_bmc_reg:
3758 ipmi_bmc_unregister(intf);3761 ipmi_bmc_unregister(intf);
3759 out_err_started:3762 out_err_started:
3763 intf->in_shutdown = true;
3760 if (intf->handlers->shutdown)3764 if (intf->handlers->shutdown)
3761 intf->handlers->shutdown(intf->send_info);3765 intf->handlers->shutdown(intf->send_info);
3762 out_err:3766 out_err:
3763 list_del(&intf->link);3767 list_del(&intf->link);
3764 mutex_unlock(&ipmi_interfaces_mutex);3768 mutex_unlock(&ipmi_interfaces_mutex);
3765 mutex_unlock(&smi_watchers_mutex);3769 mutex_unlock(&smi_watchers_mutex);
3770 cancel_work_sync(&intf->smi_work);
3766 kref_put(&intf->refcount, intf_free);3771 kref_put(&intf->refcount, intf_free);
3767 3772
3768 return rv;3773 return rv;
drivers/char/ipmi/ipmi_si_intf.c+63−16
@@ -39,6 +39,7 @@ · 38 unmodified lines
39#include <linux/rcupdate.h>39#include <linux/rcupdate.h>
40#include <linux/ipmi.h>40#include <linux/ipmi.h>
41#include <linux/ipmi_smi.h>41#include <linux/ipmi_smi.h>
42#include <linux/workqueue.h>
42#include "ipmi_si.h"43#include "ipmi_si.h"
43#include "ipmi_si_sm.h"44#include "ipmi_si_sm.h"
44#include <linux/string.h>45#include <linux/string.h>
@@ -252,6 +253,8 @@ struct smi_info { · 207 unmodified lines
252 253
253 struct task_struct *thread;254 struct task_struct *thread;
254 255
256 struct work_struct init_work;
257
255 struct list_head link;258 struct list_head link;
256};259};
257 260
@@ -272,6 +275,7 @@ static bool unload_when_empty = true; · 14 unmodified lines
272static int try_smi_init(struct smi_info *smi);275static int try_smi_init(struct smi_info *smi);
273static void cleanup_one_si(struct smi_info *smi_info);276static void cleanup_one_si(struct smi_info *smi_info);
274static void cleanup_ipmi_si(void);277static void cleanup_ipmi_si(void);
278static void smi_init_work_fn(struct work_struct *work);
275 279
276#ifdef DEBUG_TIMING280#ifdef DEBUG_TIMING
277void debug_timestamp(struct smi_info *smi_info, char *msg)281void debug_timestamp(struct smi_info *smi_info, char *msg)
@@ -1970,6 +1974,7 @@ int ipmi_si_add_smi(struct si_sm_io *io) · 1692 unmodified lines
1970 if (!new_smi)1974 if (!new_smi)
1971 return -ENOMEM;1975 return -ENOMEM;
1972 spin_lock_init(&new_smi->si_lock);1976 spin_lock_init(&new_smi->si_lock);
1977 INIT_WORK(&new_smi->init_work, smi_init_work_fn);
1973 1978
1974 new_smi->io = *io;1979 new_smi->io = *io;
1975 1980
@@ -1982,7 +1987,12 @@ int ipmi_si_add_smi(struct si_sm_io *io) · 6 unmodified lines
1982 dev_info(dup->io.dev,1987 dev_info(dup->io.dev,
1983 "Removing SMBIOS-specified %s state machine in favor of ACPI\n",1988 "Removing SMBIOS-specified %s state machine in favor of ACPI\n",
1984 si_to_str[new_smi->io.si_info->type]);1989 si_to_str[new_smi->io.si_info->type]);
1990 list_del(&dup->link);
1991 mutex_unlock(&smi_infos_lock);
1992
1985 cleanup_one_si(dup);1993 cleanup_one_si(dup);
1994
1995 mutex_lock(&smi_infos_lock);
1986 } else {1996 } else {
1987 dev_info(new_smi->io.dev,1997 dev_info(new_smi->io.dev,
1988 "%s-specified %s state machine: duplicate\n",1998 "%s-specified %s state machine: duplicate\n",
@@ -2000,8 +2010,12 @@ int ipmi_si_add_smi(struct si_sm_io *io) · 11 unmodified lines
2000 2010
2001 list_add_tail(&new_smi->link, &smi_infos);2011 list_add_tail(&new_smi->link, &smi_infos);
2002 2012
2003 if (initialized)2013 if (initialized) {
2004 rv = try_smi_init(new_smi);2014 if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
2015 queue_work(system_dfl_wq, &new_smi->init_work);
2016 else
2017 rv = try_smi_init(new_smi);
2018 }
2005out_err:2019out_err:
2006 mutex_unlock(&smi_infos_lock);2020 mutex_unlock(&smi_infos_lock);
2007 return rv;2021 return rv;
@@ -2174,6 +2188,15 @@ static bool __init ipmi_smi_info_same(struct smi_info *e1, struct smi_info *e2) · 166 unmodified lines
2174 e1->io.addr_data == e2->io.addr_data);2188 e1->io.addr_data == e2->io.addr_data);
2175}2189}
2176 2190
2191static void smi_init_work_fn(struct work_struct *work)
2192{
2193 struct smi_info *smi = container_of(work, struct smi_info, init_work);
2194
2195 mutex_lock(&smi_infos_lock);
2196 try_smi_init(smi);
2197 mutex_unlock(&smi_infos_lock);
2198}
2199
2177static int __init init_ipmi_si(void)2200static int __init init_ipmi_si(void)
2178{2201{
2179 struct smi_info *e, *e2;2202 struct smi_info *e, *e2;
@@ -2219,8 +2242,12 @@ static int __init init_ipmi_si(void) · 39 unmodified lines
2219 break;2242 break;
2220 }2243 }
2221 }2244 }
2222 if (!dup)2245 if (!dup) {
2223 try_smi_init(e);2246 if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
2247 queue_work(system_unbound_wq, &e->init_work);
2248 else
2249 try_smi_init(e);
2250 }
2224 }2251 }
2225 2252
2226 /*2253 /*
@@ -2253,8 +2280,12 @@ static int __init init_ipmi_si(void) · 26 unmodified lines
2253 break;2280 break;
2254 }2281 }
2255 }2282 }
2256 if (!dup)2283 if (!dup) {
2257 try_smi_init(e);2284 if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
2285 queue_work(system_unbound_wq, &e->init_work);
2286 else
2287 try_smi_init(e);
2288 }
2258 }2289 }
2259 2290
2260 initialized = true;2291 initialized = true;
@@ -2344,31 +2375,36 @@ static void shutdown_smi(void *send_info) · 83 unmodified lines
2344}2375}
2345 2376
2346/*2377/*
2347 * Must be called with smi_infos_lock held, to serialize the2378 * Must be called with smi_info unlinked from smi_infos and smi_infos_lock released.
2348 * smi_info->intf check.
2349 */2379 */
2350static void cleanup_one_si(struct smi_info *smi_info)2380static void cleanup_one_si(struct smi_info *smi_info)
2351{2381{
2352 if (!smi_info)2382 if (!smi_info)
2353 return;2383 return;
2354 2384
2355 list_del(&smi_info->link);2385 if (IS_ENABLED(CONFIG_IPMI_SI_ASYNC_INIT))
2386 cancel_work_sync(&smi_info->init_work);
2387
2356 ipmi_unregister_smi(smi_info->intf);2388 ipmi_unregister_smi(smi_info->intf);
2357 kfree(smi_info);2389 kfree(smi_info);
2358}2390}
2359 2391
2360void ipmi_si_remove_by_dev(struct device *dev)2392void ipmi_si_remove_by_dev(struct device *dev)
2361{2393{
2362 struct smi_info *e;2394 struct smi_info *e = NULL, *tmp;
2363 2395
2364 mutex_lock(&smi_infos_lock);2396 mutex_lock(&smi_infos_lock);
2365 list_for_each_entry(e, &smi_infos, link) {2397 list_for_each_entry(tmp, &smi_infos, link) {
2366 if (e->io.dev == dev) {2398 if (tmp->io.dev == dev) {
2367 cleanup_one_si(e);2399 e = tmp;
2400 list_del(&e->link);
2368 break;2401 break;
2369 }2402 }
2370 }2403 }
2371 mutex_unlock(&smi_infos_lock);2404 mutex_unlock(&smi_infos_lock);
2405
2406 if (e)
2407 cleanup_one_si(e);
2372}2408}
2373 2409
2374struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,2410struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
@@ -2377,6 +2413,7 @@ struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, · 2 unmodified lines
2377 /* remove */2413 /* remove */
2378 struct smi_info *e, *tmp_e;2414 struct smi_info *e, *tmp_e;
2379 struct device *dev = NULL;2415 struct device *dev = NULL;
2416 LIST_HEAD(to_clean);
2380 2417
2381 mutex_lock(&smi_infos_lock);2418 mutex_lock(&smi_infos_lock);
2382 list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {2419 list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
@@ -2386,17 +2423,23 @@ struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, · 3 unmodified lines
2386 continue;2423 continue;
2387 if (e->io.addr_data == addr) {2424 if (e->io.addr_data == addr) {
2388 dev = get_device(e->io.dev);2425 dev = get_device(e->io.dev);
2389 cleanup_one_si(e);2426 list_move_tail(&e->link, &to_clean);
2390 }2427 }
2391 }2428 }
2392 mutex_unlock(&smi_infos_lock);2429 mutex_unlock(&smi_infos_lock);
2393 2430
2431 list_for_each_entry_safe(e, tmp_e, &to_clean, link) {
2432 list_del(&e->link);
2433 cleanup_one_si(e);
2434 }
2435
2394 return dev;2436 return dev;
2395}2437}
2396 2438
2397static void cleanup_ipmi_si(void)2439static void cleanup_ipmi_si(void)
2398{2440{
2399 struct smi_info *e, *tmp_e;2441 struct smi_info *e, *tmp_e;
2442 LIST_HEAD(to_clean);
2400 2443
2401 if (!initialized)2444 if (!initialized)
2402 return;2445 return;
@@ -2410,10 +2453,14 @@ static void cleanup_ipmi_si(void) · 7 unmodified lines
2410 ipmi_si_platform_shutdown();2453 ipmi_si_platform_shutdown();
2411 2454
2412 mutex_lock(&smi_infos_lock);2455 mutex_lock(&smi_infos_lock);
2413 list_for_each_entry_safe(e, tmp_e, &smi_infos, link)2456 list_splice_init(&smi_infos, &to_clean);
2414 cleanup_one_si(e);
2415 mutex_unlock(&smi_infos_lock);2457 mutex_unlock(&smi_infos_lock);
2416 2458
2459 list_for_each_entry_safe(e, tmp_e, &to_clean, link) {
2460 list_del(&e->link);
2461 cleanup_one_si(e);
2462 }
2463
2417 ipmi_si_hardcode_exit();2464 ipmi_si_hardcode_exit();
2418 ipmi_si_hotmod_exit();2465 ipmi_si_hotmod_exit();
2419}2466}
drivers/char/ipmi/ipmi_si_platform.c+2−2
@@ -387,8 +387,8 @@ static int acpi_ipmi_probe(struct platform_device *pdev) · 386 unmodified lines
387}387}
388 388
389static const struct acpi_device_id acpi_ipmi_match[] = {389static const struct acpi_device_id acpi_ipmi_match[] = {
390 { "IPI0001", 0 },390 { .id = "IPI0001" },
391 { },391 { }
392};392};
393MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match);393MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match);
394#else394#else
drivers/char/ipmi/ipmi_ssif.c+2−2
@@ -2057,8 +2057,8 @@ static unsigned short *ssif_address_list(void) · 2056 unmodified lines
2057 2057
2058#ifdef CONFIG_ACPI2058#ifdef CONFIG_ACPI
2059static const struct acpi_device_id ssif_acpi_match[] = {2059static const struct acpi_device_id ssif_acpi_match[] = {
2060 { "IPI0001", 0 },2060 { .id = "IPI0001" },
2061 { },2061 { }
2062};2062};
2063MODULE_DEVICE_TABLE(acpi, ssif_acpi_match);2063MODULE_DEVICE_TABLE(acpi, ssif_acpi_match);
2064#endif2064#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t