summaryrefslogtreecommitdiff
path: root/drivers/char/ipmi/ipmi_msghandler.c
AgeCommit message (Collapse)AuthorFilesLines
2020-09-18ipmi: msghandler: Fix a signedness bugDan Carpenter1-1/+1
The type for the completion codes should be unsigned char instead of char. If it is declared as a normal char then the conditions in __get_device_id() are impossible because the IPMI_DEVICE_IN_FW_UPDATE_ERR error codes are higher than 127. drivers/char/ipmi/ipmi_msghandler.c:2449 __get_device_id() warn: impossible condition '(bmc->cc == 209) => ((-128)-127 == 209)' Fixes: f8910ffa81b0 ("ipmi:msghandler: retry to get device id on an error") Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Message-Id: <20200918142756.GB909725@mwanda> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-09-16ipmi: add retry in try_get_dev_id()Xianting Tian1-2/+0
Use a retry machanism to give the BMC more opportunities to correctly respond when we receive specific completion codes. This is similar to what is done in __get_device_id(). Signed-off-by: Xianting Tian <tian.xianting@h3c.com> Message-Id: <20200916062129.26129-1-tian.xianting@h3c.com> [Moved GET_DEVICE_ID_MAX_RETRY to include/linux/ipmi.h, reworded some text.] Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-09-15ipmi:msghandler: retry to get device id on an errorXianting Tian1-4/+25
We fail to get the BMCS's device id with low probability when loading the ipmi driver and it causes BMC device registration failed. When this issue occurs we got below kernel prints: [Wed Sep 9 19:52:03 2020] ipmi_si IPI0001:00: IPMI message handler: device id demangle failed: -22 [Wed Sep 9 19:52:03 2020] IPMI BT: using default values [Wed Sep 9 19:52:03 2020] IPMI BT: req2rsp=5 secs retries=2 [Wed Sep 9 19:52:03 2020] ipmi_si IPI0001:00: Unable to get the device id: -5 [Wed Sep 9 19:52:04 2020] ipmi_si IPI0001:00: Unable to register device: error -5 When this issue happens, we want to manually unload the driver and try to load it again, but it can't be unloaded by 'rmmod' as it is already 'in use'. We add a print in handle_one_recv_msg(), when this issue happens, the msg we received is "Recv: 1c 01 d5", which means the data_len is 1, data[0] is 0xd5 (completion code), which means "bmc cannot execute command. Command, or request parameter(s), not supported in present state". Debug code: static int handle_one_recv_msg(struct ipmi_smi *intf, struct ipmi_smi_msg *msg) { printk("Recv: %*ph\n", msg->rsp_size, msg->rsp); ... ... } Then in ipmi_demangle_device_id(), it returned '-EINVAL' as 'data_len < 7' and 'data[0] != 0'. We created this patch to retry the get device id when this error happens. We reproduced this issue again and the retry succeed on the first retry, we finally got the correct msg and then all is ok: Recv: 1c 01 00 01 81 05 84 02 af db 07 00 01 00 b9 00 10 00 So use a retry machanism in this patch to give bmc more opportunity to correctly response kernel when we received specific completion codes. Signed-off-by: Xianting Tian <tian.xianting@h3c.com> Message-Id: <20200915071817.4484-1-tian.xianting@h3c.com> [Cleaned up the verbage a bit in the header and prints.] Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-09-15ipmi: Reset response handler when failing to send the commandMarkus Boehme1-1/+3
When failing to send a command we don't expect a response. Clear the `null_user_handler` like is done in the success path. Signed-off-by: Markus Boehme <markubo@amazon.com> Message-Id: <1599495937-10654-1-git-send-email-markubo@amazon.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-09-03ipmi: add a newline when printing parameter 'panic_op' by sysfsXiongfeng Wang1-4/+4
When I cat ipmi_msghandler parameter 'panic_op' by sysfs, it displays as follows. It's better to add a newline for easy reading. root@(none):/# cat /sys/module/ipmi_msghandler/parameters/panic_op noneroot@(none):/# Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com> Message-Id: <1599130873-2402-1-git-send-email-wangxiongfeng2@huawei.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-08-18char: ipmi: convert tasklets to use new tasklet_setup() APIAllen Pais1-7/+6
In preparation for unconditionally passing the struct tasklet_struct pointer to all tasklet callbacks, switch to using the new tasklet_setup() and from_tasklet() to pass the tasklet pointer explicitly. Signed-off-by: Romain Perier <romain.perier@gmail.com> Signed-off-by: Allen Pais <allen.lkml@gmail.com> Message-Id: <20200817091617.28119-3-allen.cryptic@gmail.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-07-20ipmi: remve duplicate code in __ipmi_bmc_register()Jing Xiangfeng1-2/+0
__ipmi_bmc_register() jumps to the label 'out_free_my_dev_name' in an error path. So we can remove duplicate code in the if (rv). Signed-off-by: Jing Xiangfeng <jingxiangfeng@huawei.com> Message-Id: <20200720080838.148737-1-jingxiangfeng@huawei.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-05-18ipmi: Replace guid_copy() with import_guid() where it makes senseAndy Shevchenko1-1/+1
There is a specific API to treat raw data as GUID, i.e. import_guid(). Use it instead of guid_copy() with explicit casting. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Message-Id: <20200422130348.38749-1-andriy.shevchenko@linux.intel.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-05-18ipmi: use vzalloc instead of kmalloc for user creationFeng Tang1-3/+4
We met mulitple times of failure of staring bmc-watchdog, due to the runtime memory allocation failure of order 4. bmc-watchdog: page allocation failure: order:4, mode:0x40cc0(GFP_KERNEL|__GFP_COMP), nodemask=(null),cpuset=/,mems_allowed=0-1 CPU: 1 PID: 2571 Comm: bmc-watchdog Not tainted 5.5.0-00045-g7d6bb61d6188c #1 Hardware name: Intel Corporation S2600WFT/S2600WFT, BIOS SE5C620.86B.00.01.0015.110720180833 11/07/2018 Call Trace: dump_stack+0x66/0x8b warn_alloc+0xfe/0x160 __alloc_pages_slowpath+0xd3e/0xd80 __alloc_pages_nodemask+0x2f0/0x340 kmalloc_order+0x18/0x70 kmalloc_order_trace+0x1d/0xb0 ipmi_create_user+0x55/0x2c0 [ipmi_msghandler] ipmi_open+0x72/0x110 [ipmi_devintf] chrdev_open+0xcb/0x1e0 do_dentry_open+0x1ce/0x380 path_openat+0x305/0x14f0 do_filp_open+0x9b/0x110 do_sys_open+0x1bd/0x250 do_syscall_64+0x5b/0x1f0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Using vzalloc/vfree for creating ipmi_user heals the problem Thanks to Stephen Rothwell for finding the vmalloc.h inclusion issue. Signed-off-by: Feng Tang <feng.tang@intel.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-04-03ipmi: fix hung processes in __get_guid()Wen Yang1-2/+2
The wait_event() function is used to detect command completion. When send_guid_cmd() returns an error, smi_send() has not been called to send data. Therefore, wait_event() should not be used on the error path, otherwise it will cause the following warning: [ 1361.588808] systemd-udevd D 0 1501 1436 0x00000004 [ 1361.588813] ffff883f4b1298c0 0000000000000000 ffff883f4b188000 ffff887f7e3d9f40 [ 1361.677952] ffff887f64bd4280 ffffc90037297a68 ffffffff8173ca3b ffffc90000000010 [ 1361.767077] 00ffc90037297ad0 ffff887f7e3d9f40 0000000000000286 ffff883f4b188000 [ 1361.856199] Call Trace: [ 1361.885578] [<ffffffff8173ca3b>] ? __schedule+0x23b/0x780 [ 1361.951406] [<ffffffff8173cfb6>] schedule+0x36/0x80 [ 1362.010979] [<ffffffffa071f178>] get_guid+0x118/0x150 [ipmi_msghandler] [ 1362.091281] [<ffffffff810d5350>] ? prepare_to_wait_event+0x100/0x100 [ 1362.168533] [<ffffffffa071f755>] ipmi_register_smi+0x405/0x940 [ipmi_msghandler] [ 1362.258337] [<ffffffffa0230ae9>] try_smi_init+0x529/0x950 [ipmi_si] [ 1362.334521] [<ffffffffa022f350>] ? std_irq_setup+0xd0/0xd0 [ipmi_si] [ 1362.411701] [<ffffffffa0232bd2>] init_ipmi_si+0x492/0x9e0 [ipmi_si] [ 1362.487917] [<ffffffffa0232740>] ? ipmi_pci_probe+0x280/0x280 [ipmi_si] [ 1362.568219] [<ffffffff810021a0>] do_one_initcall+0x50/0x180 [ 1362.636109] [<ffffffff812231b2>] ? kmem_cache_alloc_trace+0x142/0x190 [ 1362.714330] [<ffffffff811b2ae1>] do_init_module+0x5f/0x200 [ 1362.781208] [<ffffffff81123ca8>] load_module+0x1898/0x1de0 [ 1362.848069] [<ffffffff811202e0>] ? __symbol_put+0x60/0x60 [ 1362.913886] [<ffffffff8130696b>] ? security_kernel_post_read_file+0x6b/0x80 [ 1362.998514] [<ffffffff81124465>] SYSC_finit_module+0xe5/0x120 [ 1363.068463] [<ffffffff81124465>] ? SYSC_finit_module+0xe5/0x120 [ 1363.140513] [<ffffffff811244be>] SyS_finit_module+0xe/0x10 [ 1363.207364] [<ffffffff81003c04>] do_syscall_64+0x74/0x180 Fixes: 50c812b2b951 ("[PATCH] ipmi: add full sysfs support") Signed-off-by: Wen Yang <wenyang@linux.alibaba.com> Cc: Corey Minyard <minyard@acm.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: openipmi-developer@lists.sourceforge.net Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org # 2.6.17- Message-Id: <20200403090408.58745-1-wenyang@linux.alibaba.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2020-03-12drivers: char: ipmi: ipmi_msghandler: Pass lockdep expression to RCU listsAmol Grover1-4/+10
intf->cmd_rcvrs is traversed with list_for_each_entry_rcu outside an RCU read-side critical section but under the protection of intf->cmd_rcvrs_mutex. ipmi_interfaces is traversed using list_for_each_entry_rcu outside an RCU read-side critical section but under the protection of ipmi_interfaces_mutex. Hence, add the corresponding lockdep expression to the list traversal primitive to silence false-positive lockdep warnings, and harden RCU lists. Add macro for the corresponding lockdep expression to make the code clean and concise. Signed-off-by: Amol Grover <frextrite@gmail.com> Message-Id: <20200117132521.31020-1-frextrite@gmail.com> Acked-by: Paul E. McKenney <paulmck@kernel.org> Tested-by: John Garry <john.garry@huawei.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-10-22ipmi: Fix memory leak in __ipmi_bmc_registerNavid Emamdoost1-1/+4
In the impelementation of __ipmi_bmc_register() the allocated memory for bmc should be released in case ida_simple_get() fails. Fixes: 68e7e50f195f ("ipmi: Don't use BMC product/dev ids in the BMC name") Signed-off-by: Navid Emamdoost <navid.emamdoost@gmail.com> Message-Id: <20191021200649.1511-1-navid.emamdoost@gmail.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-10-22ipmi: use %*ph to print small bufferAndy Shevchenko1-23/+4
Use %*ph format to print small buffer as hex string. The change is safe since the specifier can handle up to 64 bytes and taking into account the buffer size of 100 bytes on stack the function has never been used to dump more than 32 bytes. Note, this also avoids potential buffer overflow if the length of the input buffer is bigger. This completely eliminates ipmi_debug_msg() in favour of Dynamic Debug. Signed-off-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Message-Id: <20191011155036.36748-1-andriy.shevchenko@linux.intel.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-10-22ipmi: Don't allow device module unload when in useCorey Minyard1-7/+16
If something has the IPMI driver open, don't allow the device module to be unloaded. Before it would unload and the user would get errors on use. This change is made on user request, and it makes it consistent with the I2C driver, which has the same behavior. It does change things a little bit with respect to kernel users. If the ACPI or IPMI watchdog (or any other kernel user) has created a user, then the device module cannot be unloaded. Before it could be unloaded, This does not affect hot-plug. If the device goes away (it's on something removable that is removed or is hot-removed via sysfs) then it still behaves as it did before. Reported-by: tony camuso <tcamuso@redhat.com> Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: tony camuso <tcamuso@redhat.com>
2019-08-22ipmi: move message error checking to avoid deadlockTony Camuso1-57/+57
V1->V2: in handle_one_rcv_msg, if data_size > 2, set requeue to zero and goto out instead of calling ipmi_free_msg. Kosuke Tatsukawa <tatsu@ab.jp.nec.com> In the source stack trace below, function set_need_watch tries to take out the same si_lock that was taken earlier by ipmi_thread. ipmi_thread() [drivers/char/ipmi/ipmi_si_intf.c:995] smi_event_handler() [drivers/char/ipmi/ipmi_si_intf.c:765] handle_transaction_done() [drivers/char/ipmi/ipmi_si_intf.c:555] deliver_recv_msg() [drivers/char/ipmi/ipmi_si_intf.c:283] ipmi_smi_msg_received() [drivers/char/ipmi/ipmi_msghandler.c:4503] intf_err_seq() [drivers/char/ipmi/ipmi_msghandler.c:1149] smi_remove_watch() [drivers/char/ipmi/ipmi_msghandler.c:999] set_need_watch() [drivers/char/ipmi/ipmi_si_intf.c:1066] Upstream commit e1891cffd4c4896a899337a243273f0e23c028df adds code to ipmi_smi_msg_received() to call smi_remove_watch() via intf_err_seq() and this seems to be causing the deadlock. commit e1891cffd4c4896a899337a243273f0e23c028df Author: Corey Minyard <cminyard@mvista.com> Date: Wed Oct 24 15:17:04 2018 -0500 ipmi: Make the smi watcher be disabled immediately when not needed The fix is to put all messages in the queue and move the message checking code out of ipmi_smi_msg_received and into handle_one_recv_msg, which processes the message checking after ipmi_thread releases its locks. Additionally,Kosuke Tatsukawa <tatsu@ab.jp.nec.com> reported that handle_new_recv_msgs calls ipmi_free_msg when handle_one_rcv_msg returns zero, so that the call to ipmi_free_msg in handle_one_rcv_msg introduced another panic when "ipmitool sensor list" was run in a loop. He submitted this part of the patch. +free_msg: + requeue = 0; + goto out; Reported by: Osamu Samukawa <osa-samukawa@tg.jp.nec.com> Characterized by: Kosuke Tatsukawa <tatsu@ab.jp.nec.com> Signed-off-by: Tony Camuso <tcamuso@redhat.com> Fixes: e1891cffd4c4 ("ipmi: Make the smi watcher be disabled immediately when not needed") Cc: stable@vger.kernel.org # 5.1 Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-08-16ipmi: Free receive messages when in an oopsCorey Minyard1-2/+5
If the driver handles a response in an oops, it was just ignoring the message. However, the IPMI watchdog timer was counting on the free happening to know when panic-time messages were complete. So free it in all cases. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-06-24driver_find_device: Unify the match function with class_find_device()Suzuki K Poulose1-4/+4
The driver_find_device() accepts a match function pointer to filter the devices for lookup, similar to bus/class_find_device(). However, there is a minor difference in the prototype for the match parameter for driver_find_device() with the now unified version accepted by {bus/class}_find_device(), where it doesn't accept a "const" qualifier for the data argument. This prevents us from reusing the generic match functions for driver_find_device(). For this reason, change the prototype of the driver_find_device() to make the "match" parameter in line with {bus/class}_find_device() and adjust its callers to use the const qualifier. Also, we could now promote the "data" parameter to const as we pass it down as a const parameter to the match functions. Cc: Corey Minyard <minyard@acm.org> Cc: Russell King <linux@armlinux.org.uk> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: "Rafael J. Wysocki" <rafael@kernel.org> Cc: Will Deacon <will.deacon@arm.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: Peter Oberparleiter <oberpar@linux.ibm.com> Cc: Sebastian Ott <sebott@linux.ibm.com> Cc: David Airlie <airlied@linux.ie> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Nehal Shah <nehal-bakulchandra.shah@amd.com> Cc: Shyam Sundar S K <shyam-sundar.s-k@amd.com> Cc: Lee Jones <lee.jones@linaro.org> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-04-17ipmi: avoid atomic_inc in exit functionArnd Bergmann1-1/+1
This causes a link failure on ARM in certain configurations, when we reference each atomic operation from .alt.smp.init in order to patch out atomics on non-SMP systems: `.exit.text' referenced in section `.alt.smp.init' of drivers/char/ipmi/ipmi_msghandler.o: defined in discarded section `.exit.text' of drivers/char/ipmi/ipmi_msghandler.o In this case, we can trivially replace the atomic_inc() with an atomic_set() that has the same effect and does not require a fixup. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Message-Id: <20190415155509.3565087-1-arnd@arndb.de> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-04-17ipmi: Make ipmi_interfaces_srcu variable staticYueHaibing1-1/+1
Fix sparse warning: drivers/char/ipmi/ipmi_msghandler.c:635:20: warning: symbol 'ipmi_interfaces_srcu' was not declared. Should it be static? Signed-off-by: YueHaibing <yuehaibing@huawei.com> Message-Id: <20190320133505.21984-1-yuehaibing@huawei.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-04-17ipmi: fix sleep-in-atomic in free_user at cleanup SRCU user->release_barrierCorey Minyard1-2/+17
free_user() could be called in atomic context. This patch pushed the free operation off into a workqueue. Example: BUG: sleeping function called from invalid context at kernel/workqueue.c:2856 in_atomic(): 1, irqs_disabled(): 0, pid: 177, name: ksoftirqd/27 CPU: 27 PID: 177 Comm: ksoftirqd/27 Not tainted 4.19.25-3 #1 Hardware name: AIC 1S-HV26-08/MB-DPSB04-06, BIOS IVYBV060 10/21/2015 Call Trace: dump_stack+0x5c/0x7b ___might_sleep+0xec/0x110 __flush_work+0x48/0x1f0 ? try_to_del_timer_sync+0x4d/0x80 _cleanup_srcu_struct+0x104/0x140 free_user+0x18/0x30 [ipmi_msghandler] ipmi_free_recv_msg+0x3a/0x50 [ipmi_msghandler] deliver_response+0xbd/0xd0 [ipmi_msghandler] deliver_local_response+0xe/0x30 [ipmi_msghandler] handle_one_recv_msg+0x163/0xc80 [ipmi_msghandler] ? dequeue_entity+0xa0/0x960 handle_new_recv_msgs+0x15c/0x1f0 [ipmi_msghandler] tasklet_action_common.isra.22+0x103/0x120 __do_softirq+0xf8/0x2d7 run_ksoftirqd+0x26/0x50 smpboot_thread_fn+0x11d/0x1e0 kthread+0x103/0x140 ? sort_range+0x20/0x20 ? kthread_destroy_worker+0x40/0x40 ret_from_fork+0x1f/0x40 Fixes: 77f8269606bf ("ipmi: fix use-after-free of user->release_barrier.rda") Reported-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru> Signed-off-by: Corey Minyard <cminyard@mvista.com> Cc: stable@vger.kernel.org # 5.0 Cc: Yang Yingliang <yangyingliang@huawei.com>
2019-02-09ipmi: Use dedicated API for copying a UUIDAndy Shevchenko1-1/+1
Use guid_copy() instead of memcpy() to hide guid_t implementation details and to show we expect guid_t in a raw buffer. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-02-09ipmi: Use defined constant for UUID representationAndy Shevchenko1-4/+4
Instead of magic number use pre-defined constant for UUID binary and string representations. While here, drop the implementation details of guid_t type. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> [Also converted a "17" in the error string to UUID_SIZE + 1] Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-02-09ipmi: Make the smi watcher be disabled immediately when not neededCorey Minyard1-74/+90
The code to tell the lower layer to enable or disable watching for certain things was lazy in disabling, it waited until a timer tick to see if a disable was necessary. Not a really big deal, but it could be improved. Modify the code to enable and disable watching immediately and don't do it from the background timer any more. Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: Kamlakant Patel <kamlakant.patel@cavium.com>
2019-02-09ipmi: Fix how the lower layers are told to watch for messagesCorey Minyard1-34/+85
The IPMI driver has a mechanism to tell the lower layers it needs to watch for messages, commands, and watchdogs (so it doesn't needlessly poll). However, it needed some extensions, it needed a way to tell what is being waited for so it could set the timeout appropriately. The update to the lower layer was also being done once a second at best because it was done in the main timeout handler. However, if a command is sent and a response message is coming back, it needed to be started immediately. So modify the code to update immediately if it needs to be enabled. Disable is still lazy. Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: Kamlakant Patel <kamlakant.patel@cavium.com>
2019-01-23ipmi: Don't initialize anything in the core until something uses itCorey Minyard1-63/+80
The IPMI driver was recently modified to use SRCU, but it turns out this uses a chunk of percpu memory, even if IPMI is never used. So modify thing to on initialize on the first use. There was already code to sort of handle this for handling init races, so piggy back on top of that, and simplify it in the process. Signed-off-by: Corey Minyard <cminyard@mvista.com> Reported-by: Tejun Heo <tj@kernel.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: stable@vger.kernel.org # 4.18
2019-01-23ipmi: fix use-after-free of user->release_barrier.rdaYang Yingliang1-1/+1
When we do the following test, we got oops in ipmi_msghandler driver while((1)) do service ipmievd restart & service ipmievd restart done --------------------------------------------------------------- [ 294.230186] Unable to handle kernel paging request at virtual address 0000803fea6ea008 [ 294.230188] Mem abort info: [ 294.230190] ESR = 0x96000004 [ 294.230191] Exception class = DABT (current EL), IL = 32 bits [ 294.230193] SET = 0, FnV = 0 [ 294.230194] EA = 0, S1PTW = 0 [ 294.230195] Data abort info: [ 294.230196] ISV = 0, ISS = 0x00000004 [ 294.230197] CM = 0, WnR = 0 [ 294.230199] user pgtable: 4k pages, 48-bit VAs, pgdp = 00000000a1c1b75a [ 294.230201] [0000803fea6ea008] pgd=0000000000000000 [ 294.230204] Internal error: Oops: 96000004 [#1] SMP [ 294.235211] Modules linked in: nls_utf8 isofs rpcrdma ib_iser ib_srpt target_core_mod ib_srp scsi_transport_srp ib_ipoib rdma_ucm ib_umad rdma_cm ib_cm iw_cm dm_mirror dm_region_hash dm_log dm_mod aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce sha2_ce ses sha256_arm64 sha1_ce hibmc_drm hisi_sas_v2_hw enclosure sg hisi_sas_main sbsa_gwdt ip_tables mlx5_ib ib_uverbs marvell ib_core mlx5_core ixgbe ipmi_si mdio hns_dsaf ipmi_devintf ipmi_msghandler hns_enet_drv hns_mdio [ 294.277745] CPU: 3 PID: 0 Comm: swapper/3 Kdump: loaded Not tainted 5.0.0-rc2+ #113 [ 294.285511] Hardware name: Huawei TaiShan 2280 /BC11SPCD, BIOS 1.37 11/21/2017 [ 294.292835] pstate: 80000005 (Nzcv daif -PAN -UAO) [ 294.297695] pc : __srcu_read_lock+0x38/0x58 [ 294.301940] lr : acquire_ipmi_user+0x2c/0x70 [ipmi_msghandler] [ 294.307853] sp : ffff00001001bc80 [ 294.311208] x29: ffff00001001bc80 x28: ffff0000117e5000 [ 294.316594] x27: 0000000000000000 x26: dead000000000100 [ 294.321980] x25: dead000000000200 x24: ffff803f6bd06800 [ 294.327366] x23: 0000000000000000 x22: 0000000000000000 [ 294.332752] x21: ffff00001001bd04 x20: ffff80df33d19018 [ 294.338137] x19: ffff80df33d19018 x18: 0000000000000000 [ 294.343523] x17: 0000000000000000 x16: 0000000000000000 [ 294.348908] x15: 0000000000000000 x14: 0000000000000002 [ 294.354293] x13: 0000000000000000 x12: 0000000000000000 [ 294.359679] x11: 0000000000000000 x10: 0000000000100000 [ 294.365065] x9 : 0000000000000000 x8 : 0000000000000004 [ 294.370451] x7 : 0000000000000000 x6 : ffff80df34558678 [ 294.375836] x5 : 000000000000000c x4 : 0000000000000000 [ 294.381221] x3 : 0000000000000001 x2 : 0000803fea6ea000 [ 294.386607] x1 : 0000803fea6ea008 x0 : 0000000000000001 [ 294.391994] Process swapper/3 (pid: 0, stack limit = 0x0000000083087293) [ 294.398791] Call trace: [ 294.401266] __srcu_read_lock+0x38/0x58 [ 294.405154] acquire_ipmi_user+0x2c/0x70 [ipmi_msghandler] [ 294.410716] deliver_response+0x80/0xf8 [ipmi_msghandler] [ 294.416189] deliver_local_response+0x28/0x68 [ipmi_msghandler] [ 294.422193] handle_one_recv_msg+0x158/0xcf8 [ipmi_msghandler] [ 294.432050] handle_new_recv_msgs+0xc0/0x210 [ipmi_msghandler] [ 294.441984] smi_recv_tasklet+0x8c/0x158 [ipmi_msghandler] [ 294.451618] tasklet_action_common.isra.5+0x88/0x138 [ 294.460661] tasklet_action+0x2c/0x38 [ 294.468191] __do_softirq+0x120/0x2f8 [ 294.475561] irq_exit+0x134/0x140 [ 294.482445] __handle_domain_irq+0x6c/0xc0 [ 294.489954] gic_handle_irq+0xb8/0x178 [ 294.497037] el1_irq+0xb0/0x140 [ 294.503381] arch_cpu_idle+0x34/0x1a8 [ 294.510096] do_idle+0x1d4/0x290 [ 294.516322] cpu_startup_entry+0x28/0x30 [ 294.523230] secondary_start_kernel+0x184/0x1d0 [ 294.530657] Code: d538d082 d2800023 8b010c81 8b020021 (c85f7c25) [ 294.539746] ---[ end trace 8a7a880dee570b29 ]--- [ 294.547341] Kernel panic - not syncing: Fatal exception in interrupt [ 294.556837] SMP: stopping secondary CPUs [ 294.563996] Kernel Offset: disabled [ 294.570515] CPU features: 0x002,21006008 [ 294.577638] Memory Limit: none [ 294.587178] Starting crashdump kernel... [ 294.594314] Bye! Because the user->release_barrier.rda is freed in ipmi_destroy_user(), but the refcount is not zero, when acquire_ipmi_user() uses user->release_barrier.rda in __srcu_read_lock(), it causes oops. Fix this by calling cleanup_srcu_struct() when the refcount is zero. Fixes: e86ee2d44b44 ("ipmi: Rework locking and shutdown for hot remove") Cc: stable@vger.kernel.org # 4.18 Signed-off-by: Yang Yingliang <yangyingliang@huawei.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-01-23ipmi: Prevent use-after-free in deliver_responseFred Klassen1-1/+1
Some IPMI modules (e.g. ibmpex_msg_handler()) will have ipmi_usr_hdlr handlers that call ipmi_free_recv_msg() directly. This will essentially kfree(msg), leading to use-after-free. This does not happen in the ipmi_devintf module, which will queue the message and run ipmi_free_recv_msg() later. BUG: KASAN: use-after-free in deliver_response+0x12f/0x1b0 Read of size 8 at addr ffff888a7bf20018 by task ksoftirqd/3/27 CPU: 3 PID: 27 Comm: ksoftirqd/3 Tainted: G O 4.19.11-amd64-ani99-debug #12.0.1.601133+pv Hardware name: AppNeta r1000/X11SPW-TF, BIOS 2.1a-AP 09/17/2018 Call Trace: dump_stack+0x92/0xeb print_address_description+0x73/0x290 kasan_report+0x258/0x380 deliver_response+0x12f/0x1b0 ? ipmi_free_recv_msg+0x50/0x50 deliver_local_response+0xe/0x50 handle_one_recv_msg+0x37a/0x21d0 handle_new_recv_msgs+0x1ce/0x440 ... Allocated by task 9885: kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc_trace+0x116/0x290 ipmi_alloc_recv_msg+0x28/0x70 i_ipmi_request+0xb4a/0x1640 ipmi_request_settime+0x1b8/0x1e0 ... Freed by task 27: __kasan_slab_free+0x12e/0x180 kfree+0xe9/0x280 deliver_response+0x122/0x1b0 deliver_local_response+0xe/0x50 handle_one_recv_msg+0x37a/0x21d0 handle_new_recv_msgs+0x1ce/0x440 tasklet_action_common.isra.19+0xc4/0x250 __do_softirq+0x11f/0x51f Fixes: e86ee2d44b44 ("ipmi: Rework locking and shutdown for hot remove") Cc: stable@vger.kernel.org # 4.18 Signed-off-by: Fred Klassen <fklassen@appneta.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2019-01-23ipmi: msghandler: Fix potential Spectre v1 vulnerabilitiesGustavo A. R. Silva1-8/+18
channel and addr->channel are indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. These issues were detected with the help of Smatch: drivers/char/ipmi/ipmi_msghandler.c:1381 ipmi_set_my_address() warn: potential spectre issue 'user->intf->addrinfo' [w] (local cap) drivers/char/ipmi/ipmi_msghandler.c:1401 ipmi_get_my_address() warn: potential spectre issue 'user->intf->addrinfo' [r] (local cap) drivers/char/ipmi/ipmi_msghandler.c:1421 ipmi_set_my_LUN() warn: potential spectre issue 'user->intf->addrinfo' [w] (local cap) drivers/char/ipmi/ipmi_msghandler.c:1441 ipmi_get_my_LUN() warn: potential spectre issue 'user->intf->addrinfo' [r] (local cap) drivers/char/ipmi/ipmi_msghandler.c:2260 check_addr() warn: potential spectre issue 'intf->addrinfo' [r] (local cap) Fix this by sanitizing channel and addr->channel before using them to index user->intf->addrinfo and intf->addrinfo, correspondingly. Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://lore.kernel.org/lkml/20180423164740.GY17484@dhcp22.suse.cz/ Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-09-18ipmi: fix return value of ipmi_set_my_LUNYueHaibing1-1/+1
Fixes gcc '-Wunused-but-set-variable' warning: drivers/char/ipmi/ipmi_msghandler.c: In function 'ipmi_set_my_LUN': drivers/char/ipmi/ipmi_msghandler.c:1335:13: warning: variable 'rv' set but not used [-Wunused-but-set-variable] int index, rv = 0; 'rv' should be the correct return value. Fixes: 048f7c3e352e ("ipmi: Properly release srcu locks on error conditions") Signed-off-by: YueHaibing <yuehaibing@huawei.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-09-18ipmi: msghandler: Add and use pr_fmt and dev_fmt, remove PFXJoe Perches1-27/+24
Standardize the prefixing of output messages using the pr_fmt and dev_fmt mechanisms instead of a separate #define PFX Miscellanea: o Because this message prefix is very long, use a non-standard define of #define pr_fmt(fmt) "%s" fmt, "IPMI message handler: " which removes ~170 bytes of object code in an x86-64 defconfig with ipmi (with even more object code reduction on 32 bit compilations) Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-08-31ipmi: Rework SMI registration failureCorey Minyard1-23/+30
There were certain situations where ipmi_register_smi() would return a failure, but the interface would still be registered and would need to be unregistered. This is obviously a bad design and resulted in an oops in certain failure cases. If the interface is started up in ipmi_register_smi(), then an error occurs, shut down the interface there so the cleanup can be done properly. Fix the various smi users, too. Signed-off-by: Corey Minyard <cminyard@mvista.com> Reported-by: Justin Ernst <justin.ernst@hpe.com> Tested-by: Justin Ernst <justin.ernst@hpe.com> Cc: Andrew Banman <abanman@hpe.com> Cc: Russ Anderson <russ.anderson@hpe.com> Cc: <stable@vger.kernel.org> # 4.18.x
2018-05-24ipmi: Properly release srcu locks on error conditionsCorey Minyard1-18/+25
When SRCU was added for handling hotplug, some error conditions were not handled properly. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-05-09ipmi: Remove the proc interfaceCorey Minyard1-264/+0
It has been deprecated long enough, get rid of it. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: ipmi_unregister_smi() cannot fail, have it return voidCorey Minyard1-3/+1
Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Remove condition on interface shutdownCorey Minyard1-2/+1
Now that the interfaces have shutdown handlers, this no longer needs to be conditional. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Rework locking and shutdown for hot removeCorey Minyard1-210/+280
To handle hot remove of interfaces, a lot of rework had to be done to the locking. Several things were switched over to srcu and shutdown for users and interfaces was added for cleaner shutdown. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Fix some counter issuesCorey Minyard1-31/+45
Counters would not be pegged properly on some errors. Have deliver_response() return an error so the counters can be incremented properly. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Change ipmi_smi_t to struct ipmi_smi *Corey Minyard1-87/+91
Get rid of this coding style violation in the user files. Include files will come later. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Rename ipmi_user_t to struct ipmi_user *Corey Minyard1-27/+27
Get rid of that non-compliance in the user files. Include files will come later. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Clean up some style issues in the message handlerCorey Minyard1-48/+35
Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Break up i_ipmi_requestCorey Minyard1-310/+344
It was huge, and easily broken into pieces. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Clean up some debug codeCorey Minyard1-33/+25
Replace ifdefs in the code with a simple function. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Add a panic handler for IPMI usersCorey Minyard1-110/+104
Users of the IPMI code had their own panic handlers, but the order was not necessarily right, the base IPMI code would need to handle the panic first, and the user had no way to know if the IPMI interface could run at panic time. Add a panic handler to the user interface, it is called if non-NULL and the interface the user is on is capable of panic handling. It also cleans up the panic log handling a bit to reuse the existing interface loop in the main panic handler. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Add a maintenance mode for IPMB messagesCorey Minyard1-0/+28
If you send a command to another BMC that might take some extra time, increase the timeouts temporarily. Signed-off-by: Corey Minyard <cminyard@mvista.com>
2018-04-18ipmi: Add a way to tune some timeoutsCorey Minyard1-32/+48
By default the retry timeout is 1 second. Allow that to be modified, primarily for slow operations, like firmware writes. Also, the timeout was driven by a 1 second timer, so 1 second really meant between 0 and 1 second. Set the default to 2 seconds so it means between 1 and 2 seconds. Also allow the time the interface automatically stays in mainenance mode to be modified from it's default 30 seconds. Also consolidate some of the timeout and retry setup. Signed-off-by: Corey Minyard <cminyard@mvista.com> more
2018-02-27ipmi: Add or fix SPDX-License-Identifier in all filesCorey Minyard1-21/+1
And get rid of the license text that is no longer necessary. Signed-off-by: Corey Minyard <cminyard@mvista.com> Cc: Kees Cook <keescook@chromium.org> Cc: Alistair Popple <alistair@popple.id.au> Cc: Jeremy Kerr <jk@ozlabs.org> Cc: Joel Stanley <joel@jms.id.au> Cc: Rocky Craig <rocky.craig@hp.com>
2018-02-01Merge tag 'driver-core-4.16-rc1' of ↵Linus Torvalds1-9/+8
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is the set of "big" driver core patches for 4.16-rc1. The majority of the work here is in the firmware subsystem, with reworks to try to attempt to make the code easier to handle in the long run, but no functional change. There's also some tree-wide sysfs attribute fixups with lots of acks from the various subsystem maintainers, as well as a handful of other normal fixes and changes. And finally, some license cleanups for the driver core and sysfs code. All have been in linux-next for a while with no reported issues" * tag 'driver-core-4.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (48 commits) device property: Define type of PROPERTY_ENRTY_*() macros device property: Reuse property_entry_free_data() device property: Move property_entry_free_data() upper firmware: Fix up docs referring to FIRMWARE_IN_KERNEL firmware: Drop FIRMWARE_IN_KERNEL Kconfig option USB: serial: keyspan: Drop firmware Kconfig options sysfs: remove DEBUG defines sysfs: use SPDX identifiers drivers: base: add coredump driver ops sysfs: add attribute specification for /sysfs/devices/.../coredump test_firmware: fix missing unlock on error in config_num_requests_store() test_firmware: make local symbol test_fw_config static sysfs: turn WARN() into pr_warn() firmware: Fix a typo in fallback-mechanisms.rst treewide: Use DEVICE_ATTR_WO treewide: Use DEVICE_ATTR_RO treewide: Use DEVICE_ATTR_RW sysfs.h: Use octal permissions component: add debugfs support bus: simple-pm-bus: convert bool SIMPLE_PM_BUS to tristate ...
2018-01-09treewide: Use DEVICE_ATTR_ROJoe Perches1-9/+8
Convert DEVICE_ATTR uses to DEVICE_ATTR_RO where possible. Done with perl script: $ git grep -w --name-only DEVICE_ATTR | \ xargs perl -i -e 'local $/; while (<>) { s/\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?(?:\s*S_IRUGO\s*|\s*0444\s*)\)?\s*,\s*\1_show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(\1)/g; print;}' Signed-off-by: Joe Perches <joe@perches.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Robert Jarzmik <robert.jarzmik@free.fr> Acked-by: Sagi Grimberg <sagi@grimberg.me> Acked-by: Zhang Rui <rui.zhang@intel.com> Acked-by: Harald Freudenberger <freude@linux.vnet.ibm.com> Acked-by: Jani Nikula <jani.nikula@intel.com> Acked-by: Corey Minyard <cminyard@mvista.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-01-08ipmi: use correct string lengthXiongfeng Wang1-1/+1
gcc-8 reports drivers/char/ipmi/ipmi_msghandler.c: In function 'panic_op_write_handler': ./include/linux/string.h:245:9: warning: '__builtin_strncpy' specified bound 16 equals destination size [-Wstringop-truncation] drivers/char/ipmi/ipmi_watchdog.c: In function 'set_param_str': ./include/linux/string.h:245:9: warning: '__builtin_strncpy' specified bound 16 equals destination size [-Wstringop-truncation] We need one less byte or call strlcpy() to make it a nul-terminated string. Signed-off-by: Xiongfeng Wang <xiongfeng.wang@linaro.org> Signed-off-by: Corey Minyard <cminyard@mvista.com>
2017-11-21treewide: setup_timer() -> timer_setup()Kees Cook1-2/+2
This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org>