Age | Commit message (Collapse) | Author |
|
During code inspection, I found an use-after-free possibility during unloading
ipmi_si in the polling mode.
If start_new_msg() is called after kthread_stop(), the function will try to
wake up non-existing kthread using the dangling pointer.
Possible scenario is when a new internal message is generated after
ipmi_unregister_smi()[*1] and remains after stop_timer_and_thread()
in clenaup_one_si() [*2].
Use-after-free could occur as follows depending on BMC replies.
cleanup_one_si
=> ipmi_unregister_smi
[*1]
=> stop_timer_and_thread
=> kthread_stop(smi_info->thread)
[*2]
=> poll
=> smi_event_handler
=> start_new_msg
=> if (smi_info->thread)
wake_up_process(smi_info->thread) <== use-after-free!!
Although currently it seems no such message is generated in the polling mode,
some changes might introduce that in thefuture. For example in the interrupt
mode, disable_si_irq() does that at [*2].
So let's prevent such a critical issue possibility now.
Signed-off-by: Yamazaki Masamitsu <m-yamazaki@ah.jp.nec.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Cleanup of platform devices created by the IPMI driver was not
being done correctly and could result in a memory leak. So
create a local boolean to know how to clean up those platform
devices.
Reported-by: David Binderman <dcb314@hotmail.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Pull IPMI fixes from Corey Minyard.
* tag 'for-linus-4.15-2' of git://github.com/cminyard/linux-ipmi:
ipmi_si: fix crash on parisc
ipmi_si: Fix oops with PCI devices
ipmi: Stop timers before cleaning up the module
|
|
System may crash after unloading ipmi_si.ko module
because a timer may remain and fire after the module cleaned up resources.
cleanup_one_si() contains the following processing.
/*
* Make sure that interrupts, the timer and the thread are
* stopped and will not run again.
*/
if (to_clean->irq_cleanup)
to_clean->irq_cleanup(to_clean);
wait_for_timer_and_thread(to_clean);
/*
* Timeouts are stopped, now make sure the interrupts are off
* in the BMC. Note that timers and CPU interrupts are off,
* so no need for locks.
*/
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
schedule_timeout_uninterruptible(1);
}
si_state changes as following in the while loop calling poll(to_clean).
SI_GETTING_MESSAGES
=> SI_CHECKING_ENABLES
=> SI_SETTING_ENABLES
=> SI_GETTING_EVENTS
=> SI_NORMAL
As written in the code comments above,
timers are expected to stop before the polling loop and not to run again.
But the timer is set again in the following process
when si_state becomes SI_SETTING_ENABLES.
=> poll
=> smi_event_handler
=> handle_transaction_done
// smi_info->si_state == SI_SETTING_ENABLES
=> start_getting_events
=> start_new_msg
=> smi_mod_timer
=> mod_timer
As a result, before the timer set in start_new_msg() expires,
the polling loop may see si_state becoming SI_NORMAL
and the module clean-up finishes.
For example, hard LOCKUP and panic occurred as following.
smi_timeout was called after smi_event_handler,
kcs_event and hangs at port_inb()
trying to access I/O port after release.
[exception RIP: port_inb+19]
RIP: ffffffffc0473053 RSP: ffff88069fdc3d80 RFLAGS: 00000006
RAX: ffff8806800f8e00 RBX: ffff880682bd9400 RCX: 0000000000000000
RDX: 0000000000000ca3 RSI: 0000000000000ca3 RDI: ffff8806800f8e40
RBP: ffff88069fdc3d80 R8: ffffffff81d86dfc R9: ffffffff81e36426
R10: 00000000000509f0 R11: 0000000000100000 R12: 0000000000]:000000
R13: 0000000000000000 R14: 0000000000000246 R15: ffff8806800f8e00
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0000
--- <NMI exception stack> ---
To fix the problem I defined a flag, timer_can_start,
as member of struct smi_info.
The flag is enabled immediately after initializing the timer
and disabled immediately before waiting for timer deletion.
Fixes: 0cfec916e86d ("ipmi: Start the timer and thread on internal msgs")
Signed-off-by: Yamazaki Masamitsu <m-yamazaki@ah.jp.nec.com>
[Adjusted for recent changes in the driver.]
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
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>
|
|
try_smi_init()
Omit an extra message for a memory allocation failure in this function.
This issue was detected by using the Coccinelle software.
Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
The error exit path omits kfree'ing the allocated new_smi, causing a memory
leak. Fix this by kfree'ing new_smi.
Detected by CoverityScan, CID#14582571 ("Resource Leak")
Fixes: 7e030d6dff71 ("ipmi: Prefer ACPI system interfaces over SMBIOS ones")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Rework the DMI probe function to be a generic platform probe, and
then rework the DMI code (and a few other things) to use the more
generic information. This is so other things can declare platform
IPMI devices.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
So we can remove it later.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Create a device attribute for everything we show in proc, getting
ready for removing the proc stuff.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
It's only used in one place now, so it's overkill.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Stephen Rothwell <sfr@canb.auug.org.au> fixed an issue with the
include files
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Stephen Rothwell <sfr@canb.auug.org.au> fixed an issue with the
include files
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Instead of allocating the smi_info structure, filling in the I/O
info, and passing it to ipmi_si_add_smi(), just pass the I/O
info in the io structure and let ipmi_si_add_smi() allocate
the smi_info structure.
This required redoing the way the remove functions for some
device interfaces worked, a new function named
ipmi_si_remove_by_dev() allows the device to be passed in and
detected instead of using driver data, which couldn't be
filled out easily othersize.
After this the platform handling should be decoupled from the
smi_info structure and that handling can be pulled out to its
own files.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Where it belongs, and getting ready for pulling the platform
handling into its own file.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
So the platform code can do it without having to access the
smi info, getting ready for pulling the platform handling
section to their own files.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
That's where it belongs, and we are getting ready for moving the
platform handling out of the main ipmi_si_intf.c file.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Getting ready for moving the platform-specific stuff into their
own files.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
It's no longer used, dynamic device id handling is in place now.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Currently, ipmi_demagle_device_id requires a full response buffer in its
data argument. This means we can't use it to parse a response in a
struct ipmi_recv_msg, which has the netfn and cmd as separate bytes.
This change alters the definition and users of ipmi_demangle_device_id
to use a split netfn, cmd and data buffer, so it can be used with
non-sequential responses.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Fixed the ipmi_ssif.c and ipmi_si_intf.c changes to use data from the
response, not the data from the message, when passing info to the
ipmi_demangle_device_id() function.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
The recent changes to add SMBIOS (DMI) IPMI interfaces as platform
devices caused DMI to be selected before ACPI, causing ACPI type
of operations to not work.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
The function ipmi_get_info_from_resources is local to the source and
does not need to be in global scope, so make it static. Add in
newline to function declaration to make it checkpatch warning clean.
Cleans up sparse warnings:
symbol 'ipmi_get_info_from_resources' was not declared. Should it
be static?
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
When ipmi is probed via ACPI, the boot log shows
[ 17.945139] ipmi_si IPI0001:00: probing via device tree
[ 17.950369] ipmi_si IPI0001:00: ipmi_si: probing via ACPI
[ 17.955795] ipmi_si IPI0001:00: [io 0x00e4-0x3fff] regsize 1 spacing 1 irq 0
[ 17.962932] ipmi_si: Adding ACPI-specified bt state machine
which "ipmi_si IPI0001:00: probing via device tree" is misleading
with a ACPI HID "IPI0001" but probing via DT.
Eliminate this misleading print info by checking of_node is valid
or not before calling of_ipmi_probe().
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Additionally add a MODULE_DEVICE_TABLE entry so that udev
can load the driver automatically.
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
Pull IPMI updates from Corey Minyard:
"Some small fixes for IPMI, and one medium sized changed.
The medium sized change is adding a platform device for IPMI entries
in the DMI table. Otherwise there is no auto loading for IPMI devices
if they are only in the DMI table"
* tag 'for-linus-4.13-v2' of git://github.com/cminyard/linux-ipmi:
ipmi:ssif: Add missing unlock in error branch
char: ipmi: constify bmc_dev_attr_group and bmc_device_type
ipmi:ssif: Check dev before setting drvdata
ipmi: Convert DMI handling over to a platform device
ipmi: Create a platform device for a DMI-specified IPMI interface
ipmi: use rcu lock around call to intf->handlers->sender()
ipmi:ssif: Use i2c_adapter_id instead of adapter->nr
ipmi: Use the proper default value for register size in ACPI
ipmi_ssif: remove redundant null check on array client->adapter->name
ipmi/watchdog: fix watchdog timeout set on reboot
ipmi_ssif: unlock on allocation failure
|
|
Now that the IPMI DMI code creates a platform device for IPMI devices
in the firmware, use that instead of handling all the DMI work
in the IPMI drivers themselves.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: Andy Lutomirski <luto@kernel.org>
|
|
It's the proper value, so there's no effect, but just to be proper,
use the right value.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull hw lockdown support from David Howells:
"Annotation of module parameters that configure hardware resources
including ioports, iomem addresses, irq lines and dma channels.
This allows a future patch to prohibit the use of such module
parameters to prevent that hardware from being abused to gain access
to the running kernel image as part of locking the kernel down under
UEFI secure boot conditions.
Annotations are made by changing:
module_param(n, t, p)
module_param_named(n, v, t, p)
module_param_array(n, t, m, p)
to:
module_param_hw(n, t, hwtype, p)
module_param_hw_named(n, v, t, hwtype, p)
module_param_hw_array(n, t, hwtype, m, p)
where the module parameter refers to a hardware setting
hwtype specifies the type of the resource being configured. This can
be one of:
ioport Module parameter configures an I/O port
iomem Module parameter configures an I/O mem address
ioport_or_iomem Module parameter could be either (runtime set)
irq Module parameter configures an I/O port
dma Module parameter configures a DMA channel
dma_addr Module parameter configures a DMA buffer address
other Module parameter configures some other value
Note that the hwtype is compile checked, but not currently stored (the
lockdown code probably won't require it). It is, however, there for
future use.
A bonus is that the hwtype can also be used for grepping.
The intention is for the kernel to ignore or reject attempts to set
annotated module parameters if lockdown is enabled. This applies to
options passed on the boot command line, passed to insmod/modprobe or
direct twiddling in /sys/module/ parameter files.
The module initialisation then needs to handle the parameter not being
set, by (1) giving an error, (2) probing for a value or (3) using a
reasonable default.
What I can't do is just reject a module out of hand because it may
take a hardware setting in the module parameters. Some important
modules, some ipmi stuff for instance, both probe for hardware and
allow hardware to be manually specified; if the driver is aborts with
any error, you don't get any ipmi hardware.
Further, trying to do this entirely in the module initialisation code
doesn't protect against sysfs twiddling.
[!] Note that in and of itself, this series of patches should have no
effect on the the size of the kernel or code execution - that is
left to a patch in the next series to effect. It does mark
annotated kernel parameters with a KERNEL_PARAM_FL_HWPARAM flag in
an already existing field"
* tag 'hwparam-20170420' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: (38 commits)
Annotate hardware config module parameters in sound/pci/
Annotate hardware config module parameters in sound/oss/
Annotate hardware config module parameters in sound/isa/
Annotate hardware config module parameters in sound/drivers/
Annotate hardware config module parameters in fs/pstore/
Annotate hardware config module parameters in drivers/watchdog/
Annotate hardware config module parameters in drivers/video/
Annotate hardware config module parameters in drivers/tty/
Annotate hardware config module parameters in drivers/staging/vme/
Annotate hardware config module parameters in drivers/staging/speakup/
Annotate hardware config module parameters in drivers/staging/media/
Annotate hardware config module parameters in drivers/scsi/
Annotate hardware config module parameters in drivers/pcmcia/
Annotate hardware config module parameters in drivers/pci/hotplug/
Annotate hardware config module parameters in drivers/parport/
Annotate hardware config module parameters in drivers/net/wireless/
Annotate hardware config module parameters in drivers/net/wan/
Annotate hardware config module parameters in drivers/net/irda/
Annotate hardware config module parameters in drivers/net/hamradio/
Annotate hardware config module parameters in drivers/net/ethernet/
...
|
|
When the kernel is running in secure boot mode, we lock down the kernel to
prevent userspace from modifying the running kernel image. Whilst this
includes prohibiting access to things like /dev/mem, it must also prevent
access by means of configuring driver modules in such a way as to cause a
device to access or modify the kernel image.
To this end, annotate module_param* statements that refer to hardware
configuration and indicate for future reference what type of parameter they
specify. The parameter parser in the core sees this information and can
skip such parameters with an error message if the kernel is locked down.
The module initialisation then runs as normal, but just sees whatever the
default values for those parameters is.
Note that we do still need to do the module initialisation because some
drivers have viable defaults set in case parameters aren't specified and
some drivers support automatic configuration (e.g. PNP or PCI) in addition
to manually coded parameters.
This patch annotates drivers in drivers/char/ipmi/.
Suggested-by: Alan Cox <gnomes@lxorguk.ukuu.org.uk>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Corey Minyard <cminyard@mvista.com>
cc: openipmi-developer@lists.sourceforge.net
|
|
Commit 1abf71e moved the creation of new_smi->dev to earlier in the init
sequence in order to provide infrastructure for log printing.
However, the init_name was created with a hard-coded value of zero. This
presents a problem in systems with more than one interface, producing a
call trace in dmesg.
To correct the problem, simply use smi_num instead of the hard-coded
value of zero.
Tested on a lenovo x3950.
Signed-off-by: Tony Camuso <tcamuso@redhat.com>
There was actually a more general problem, the platform device wasn't
being set correctly, either, and there was a possible (though extremely
unlikely) race on smi_num. Add locks to clean up the race and use the
proper value for the platform device, too.
Tested on qemu in various configurations.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
When added by ACPI, the information does not contain the slave address
of the BMC. However, that information is available from SMBIOS. So
if we add a device that doesn't have a slave address, look at the other
devices that are duplicate interfaces and see if they have a slave
address.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Convert them to pr_xxx or dev_xxx.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Some logs are printed out early using smi->dev, but on a platform device
that is not created until later. So move the creation of that device
structure earlier in the sequence so it can be used for printing.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Tested-by: Corentin Labbe <clabbe.montjoie@gmail.com>
|
|
Commit d9b7e4f717a1 ("ipmi: Periodically check to see if irqs and
messages are set right") to verify the contents of global events.
However, the wrong function was being called in some cases, checking
for messages, not events.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Tested-by: Jason DiPietro <J.DiPietro@F5.com>
|
|
Parameter trydefaults=1 causes the ipmi_init to initialize ipmi through
the legacy port io space that was designated for ipmi. Architectures
that do not map legacy port io can panic when trydefaults=1.
Rather than implement build-time conditional exceptions for each
architecture that does not map legacy port io, we have removed legacy
port io from the driver.
Parameter 'trydefaults' has been removed. Attempts to use it hereafter
will evoke the "Unknown symbol in module, or unknown parameter" message.
The patch was built against a number of architectures and tested for
regressions and functionality on x86_64 and ARM64.
Signed-off-by: Tony Camuso <tcamuso@redhat.com>
Removed the config entry and the address source entry for default,
since neither were used any more.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Commit d61a3ead2680 ("[PATCH] IPMI: reserve I/O ports separately")
changed the way I/O ports were reserved and includes this comment in
log:
Some BIOSes reserve disjoint I/O regions in their ACPI tables for the IPMI
controller. This causes problems when trying to register the entire I/O
region. Therefore we must register each I/O port separately.
There is a similar problem with memio regions on an arm64 platform
(AMD Seattle). Where I see:
ipmi message handler version 39.2
ipmi_si AMDI0300:00: probing via device tree
ipmi_si AMDI0300:00: ipmi_si: probing via ACPI
ipmi_si AMDI0300:00: [mem 0xe0010000] regsize 1 spacing 4 irq 23
ipmi_si: Adding ACPI-specified kcs state machine
IPMI System Interface driver.
ipmi_si: Trying ACPI-specified kcs state machine at mem \
address 0xe0010000, slave address 0x0, irq 23
ipmi_si: Could not set up I/O space
The problem is that the ACPI core registers disjoint regions for the
platform device:
e0010000-e0010000 : AMDI0300:00
e0010004-e0010004 : AMDI0300:00
and the ipmi_si driver tries to register one region e0010000-e0010004.
Based on a patch from Mark Salter <msalter@redhat.com>, who also wrote
all the above text.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Tested-by: Mark Salter <msalter@redhat.com>
|
|
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Extend the tryacpi module parameter to turn off acpi_ipmi_probe such
that hard-coded options (type, ports, address, etc.) have complete
control over the smi_info data structures setup by the driver.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Under some circumstances, the IPMI state machine could return
a call without delay option but the driver would still do a long
delay because the result wasn't checked. Instead of calling
the state machine after transaction done, just go back to the
top of the processing to start over.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Several were tryacpi instead of their actual values.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
Enclosing '#include <linux/acpi.h>' within '#ifdef CONFIG_ACPI' is
unnecessary, since it has its own conditional compile for CONFIG_ACPI.
Commit 0fbcf4af7c83 ("ipmi: Convert the IPMI SI ACPI handling to a
platform device") exposed this as a problem for platforms that do not
support ACPI when it introduced a call to ACPI_PTR() macro outside of
the CONFIG_ACPI conditional compile. This would have been perfectly
acceptable if acpi.h were not conditionally excluded for the non-acpi
platform, because the conditional compile within acpi.h defines
ACPI_PTR() to return NULL when compiled for non acpi platforms.
Signed-off-by: Tony Camuso <tcamuso@redhat.com>
Fixed commit reference in header to conform to standard.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
We call cleanup_one_si from ipmi_pci_remove, which calls ->addr_source_cleanup,
which gets set to point to ipmi_pci_cleanup, which does a pci_disable_device.
On return from this, we do a second pci_disable_device, which
results in the trace below.
ipmi_si 0000:00:16.0: disabling already-disabled device
Call Trace:
[<ffffffff818ce54c>] dump_stack+0x45/0x57
[<ffffffff810525f7>] warn_slowpath_common+0x97/0xe0
[<ffffffff810526f6>] warn_slowpath_fmt+0x46/0x50
[<ffffffff81497ca1>] pci_disable_device+0xb1/0xc0
[<ffffffffa00851a5>] ipmi_pci_remove+0x25/0x30 [ipmi_si]
[<ffffffff8149a696>] pci_device_remove+0x46/0xc0
[<ffffffff8156801f>] __device_release_driver+0x7f/0xf0
[<ffffffff81568978>] driver_detach+0xb8/0xc0
[<ffffffff81567e50>] bus_remove_driver+0x50/0xa0
[<ffffffff8156914e>] driver_unregister+0x2e/0x60
[<ffffffff8149a3e5>] pci_unregister_driver+0x25/0x90
[<ffffffffa0085804>] cleanup_ipmi_si+0xd4/0xf0 [ipmi_si]
[<ffffffff810c727a>] SyS_delete_module+0x12a/0x200
[<ffffffff818d4d72>] system_call_fastpath+0x12/0x17
Signed-off-by: Dave Jones <dsj@fb.com>
|
|
Lots of char arrays could be set as const since they contain only literal
char arrays.
We could in the same time make const some struct members who are pointer
to those const char arrays.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|
|
We encountered a panic on boot in ipmi_si on a dell per320 due to an
uninitialized timer as follows.
static int smi_start_processing(void *send_info,
ipmi_smi_t intf)
{
/* Try to claim any interrupts. */
if (new_smi->irq_setup)
new_smi->irq_setup(new_smi);
--> IRQ arrives here and irq handler tries to modify uninitialized timer
which triggers BUG_ON(!timer->function) in __mod_timer().
Call Trace:
<IRQ>
[<ffffffffa0532617>] start_new_msg+0x47/0x80 [ipmi_si]
[<ffffffffa053269e>] start_check_enables+0x4e/0x60 [ipmi_si]
[<ffffffffa0532bd8>] smi_event_handler+0x1e8/0x640 [ipmi_si]
[<ffffffff810f5584>] ? __rcu_process_callbacks+0x54/0x350
[<ffffffffa053327c>] si_irq_handler+0x3c/0x60 [ipmi_si]
[<ffffffff810efaf0>] handle_IRQ_event+0x60/0x170
[<ffffffff810f245e>] handle_edge_irq+0xde/0x180
[<ffffffff8100fc59>] handle_irq+0x49/0xa0
[<ffffffff8154643c>] do_IRQ+0x6c/0xf0
[<ffffffff8100ba53>] ret_from_intr+0x0/0x11
/* Set up the timer that drives the interface. */
setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
The following patch fixes the problem.
To: Openipmi-developer@lists.sourceforge.net
To: Corey Minyard <minyard@acm.org>
CC: linux-kernel@vger.kernel.org
Signed-off-by: Jan Stancek <jstancek@redhat.com>
Signed-off-by: Tony Camuso <tcamuso@redhat.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Cc: stable@vger.kernel.org # Applies cleanly to 3.10-, needs small rework before
|
|
The policy for drivers is to have MODULE_DEVICE_TABLE() just after the
struct used in it. For clarity.
Suggested-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Luis de Bethencourt <luisbg@osg.samsung.com>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
|