driver core patches for 4.11-rc1
Here is the "small" driver core patches for 4.11-rc1. Not much here, some firmware documentation and self-test updates, a debugfs code formatting issue, and a new feature for call_usermodehelper to make it more robust on systems that want to lock it down in a more secure way. All of these have been linux-next for a while now with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWK2jKg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymCEACgozYuqZZ/TUGW0P3xVNi7fbfUWCEAn3nYExrc XgevqeYOSKp2We6X/2JX =aZ+5 -----END PGP SIGNATURE----- Merge tag 'driver-core-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core Pull driver core updates from Greg KH: "Here is the "small" driver core patches for 4.11-rc1. Not much here, some firmware documentation and self-test updates, a debugfs code formatting issue, and a new feature for call_usermodehelper to make it more robust on systems that want to lock it down in a more secure way. All of these have been linux-next for a while now with no reported issues" * tag 'driver-core-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: kernfs: handle null pointers while printing node name and path Introduce STATIC_USERMODEHELPER to mediate call_usermodehelper() Make static usermode helper binaries constant kmod: make usermodehelper path a const string firmware: revamp firmware documentation selftests: firmware: send expected errors to /dev/null selftests: firmware: only modprobe if driver is missing platform: Print the resource range if device failed to claim kref: prefer atomic_inc_not_zero to atomic_add_unless debugfs: improve formatting of debugfs_real_fops()
This commit is contained in:
commit
b2064617c7
38
Documentation/driver-api/firmware/built-in-fw.rst
Normal file
38
Documentation/driver-api/firmware/built-in-fw.rst
Normal file
|
@ -0,0 +1,38 @@
|
|||
=================
|
||||
Built-in firmware
|
||||
=================
|
||||
|
||||
Firmware can be built-in to the kernel, this means building the firmware
|
||||
into vmlinux directly, to enable avoiding having to look for firmware from
|
||||
the filesystem. Instead, firmware can be looked for inside the kernel
|
||||
directly. You can enable built-in firmware using the kernel configuration
|
||||
options:
|
||||
|
||||
* CONFIG_EXTRA_FIRMWARE
|
||||
* CONFIG_EXTRA_FIRMWARE_DIR
|
||||
|
||||
This should not be confused with CONFIG_FIRMWARE_IN_KERNEL, this is for drivers
|
||||
which enables firmware to be built as part of the kernel build process. This
|
||||
option, CONFIG_FIRMWARE_IN_KERNEL, will build all firmware for all drivers
|
||||
enabled which ship its firmware inside the Linux kernel source tree.
|
||||
|
||||
There are a few reasons why you might want to consider building your firmware
|
||||
into the kernel with CONFIG_EXTRA_FIRMWARE though:
|
||||
|
||||
* Speed
|
||||
* Firmware is needed for accessing the boot device, and the user doesn't
|
||||
want to stuff the firmware into the boot initramfs.
|
||||
|
||||
Even if you have these needs there are a few reasons why you may not be
|
||||
able to make use of built-in firmware:
|
||||
|
||||
* Legalese - firmware is non-GPL compatible
|
||||
* Some firmware may be optional
|
||||
* Firmware upgrades are possible, therefore a new firmware would implicate
|
||||
a complete kernel rebuild.
|
||||
* Some firmware files may be really large in size. The remote-proc subsystem
|
||||
is an example subsystem which deals with these sorts of firmware
|
||||
* The firmware may need to be scraped out from some device specific location
|
||||
dynamically, an example is calibration data for for some WiFi chipsets. This
|
||||
calibration data can be unique per sold device.
|
||||
|
16
Documentation/driver-api/firmware/core.rst
Normal file
16
Documentation/driver-api/firmware/core.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
==========================
|
||||
Firmware API core features
|
||||
==========================
|
||||
|
||||
The firmware API has a rich set of core features available. This section
|
||||
documents these features.
|
||||
|
||||
.. toctree::
|
||||
|
||||
fw_search_path
|
||||
built-in-fw
|
||||
firmware_cache
|
||||
direct-fs-lookup
|
||||
fallback-mechanisms
|
||||
lookup-order
|
||||
|
30
Documentation/driver-api/firmware/direct-fs-lookup.rst
Normal file
30
Documentation/driver-api/firmware/direct-fs-lookup.rst
Normal file
|
@ -0,0 +1,30 @@
|
|||
========================
|
||||
Direct filesystem lookup
|
||||
========================
|
||||
|
||||
Direct filesystem lookup is the most common form of firmware lookup performed
|
||||
by the kernel. The kernel looks for the firmware directly on the root
|
||||
filesystem in the paths documented in the section 'Firmware search paths'.
|
||||
The filesystem lookup is implemented in fw_get_filesystem_firmware(), it
|
||||
uses common core kernel file loader facility kernel_read_file_from_path().
|
||||
The max path allowed is PATH_MAX -- currently this is 4096 characters.
|
||||
|
||||
It is recommended you keep /lib/firmware paths on your root filesystem,
|
||||
avoid having a separate partition for them in order to avoid possible
|
||||
races with lookups and avoid uses of the custom fallback mechanisms
|
||||
documented below.
|
||||
|
||||
Firmware and initramfs
|
||||
----------------------
|
||||
|
||||
Drivers which are built-in to the kernel should have the firmware integrated
|
||||
also as part of the initramfs used to boot the kernel given that otherwise
|
||||
a race is possible with loading the driver and the real rootfs not yet being
|
||||
available. Stuffing the firmware into initramfs resolves this race issue,
|
||||
however note that using initrd does not suffice to address the same race.
|
||||
|
||||
There are circumstances that justify not wanting to include firmware into
|
||||
initramfs, such as dealing with large firmware firmware files for the
|
||||
remote-proc subsystem. For such cases using a userspace fallback mechanism
|
||||
is currently the only viable solution as only userspace can know for sure
|
||||
when the real rootfs is ready and mounted.
|
195
Documentation/driver-api/firmware/fallback-mechanisms.rst
Normal file
195
Documentation/driver-api/firmware/fallback-mechanisms.rst
Normal file
|
@ -0,0 +1,195 @@
|
|||
===================
|
||||
Fallback mechanisms
|
||||
===================
|
||||
|
||||
A fallback mechanism is supported to allow to overcome failures to do a direct
|
||||
filesystem lookup on the root filesystem or when the firmware simply cannot be
|
||||
installed for practical reasons on the root filesystem. The kernel
|
||||
configuration options related to supporting the firmware fallback mechanism are:
|
||||
|
||||
* CONFIG_FW_LOADER_USER_HELPER: enables building the firmware fallback
|
||||
mechanism. Most distributions enable this option today. If enabled but
|
||||
CONFIG_FW_LOADER_USER_HELPER_FALLBACK is disabled, only the custom fallback
|
||||
mechanism is available and for the request_firmware_nowait() call.
|
||||
* CONFIG_FW_LOADER_USER_HELPER_FALLBACK: force enables each request to
|
||||
enable the kobject uevent fallback mechanism on all firmware API calls
|
||||
except request_firmware_direct(). Most distributions disable this option
|
||||
today. The call request_firmware_nowait() allows for one alternative
|
||||
fallback mechanism: if this kconfig option is enabled and your second
|
||||
argument to request_firmware_nowait(), uevent, is set to false you are
|
||||
informing the kernel that you have a custom fallback mechanism and it will
|
||||
manually load the firmware. Read below for more details.
|
||||
|
||||
Note that this means when having this configuration:
|
||||
|
||||
CONFIG_FW_LOADER_USER_HELPER=y
|
||||
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n
|
||||
|
||||
the kobject uevent fallback mechanism will never take effect even
|
||||
for request_firmware_nowait() when uevent is set to true.
|
||||
|
||||
Justifying the firmware fallback mechanism
|
||||
==========================================
|
||||
|
||||
Direct filesystem lookups may fail for a variety of reasons. Known reasons for
|
||||
this are worth itemizing and documenting as it justifies the need for the
|
||||
fallback mechanism:
|
||||
|
||||
* Race against access with the root filesystem upon bootup.
|
||||
|
||||
* Races upon resume from suspend. This is resolved by the firmware cache, but
|
||||
the firmware cache is only supported if you use uevents, and its not
|
||||
supported for request_firmware_into_buf().
|
||||
|
||||
* Firmware is not accessible through typical means:
|
||||
* It cannot be installed into the root filesystem
|
||||
* The firmware provides very unique device specific data tailored for
|
||||
the unit gathered with local information. An example is calibration
|
||||
data for WiFi chipsets for mobile devices. This calibration data is
|
||||
not common to all units, but tailored per unit. Such information may
|
||||
be installed on a separate flash partition other than where the root
|
||||
filesystem is provided.
|
||||
|
||||
Types of fallback mechanisms
|
||||
============================
|
||||
|
||||
There are really two fallback mechanisms available using one shared sysfs
|
||||
interface as a loading facility:
|
||||
|
||||
* Kobject uevent fallback mechanism
|
||||
* Custom fallback mechanism
|
||||
|
||||
First lets document the shared sysfs loading facility.
|
||||
|
||||
Firmware sysfs loading facility
|
||||
===============================
|
||||
|
||||
In order to help device drivers upload firmware using a fallback mechanism
|
||||
the firmware infrastructure creates a sysfs interface to enable userspace
|
||||
to load and indicate when firmware is ready. The sysfs directory is created
|
||||
via fw_create_instance(). This call creates a new struct device named after
|
||||
the firmware requested, and establishes it in the device hierarchy by
|
||||
associating the device used to make the request as the device's parent.
|
||||
The sysfs directory's file attributes are defined and controlled through
|
||||
the new device's class (firmare_class) and group (fw_dev_attr_groups).
|
||||
This is actually where the original firmware_class.c file name comes from,
|
||||
as originally the only firmware loading mechanism available was the
|
||||
mechanism we now use as a fallback mechanism.
|
||||
|
||||
To load firmware using the sysfs interface we expose a loading indicator,
|
||||
and a file upload firmware into:
|
||||
|
||||
* /sys/$DEVPATH/loading
|
||||
* /sys/$DEVPATH/data
|
||||
|
||||
To upload firmware you will echo 1 onto the loading file to indicate
|
||||
you are loading firmware. You then cat the firmware into the data file,
|
||||
and you notify the kernel the firmware is ready by echo'ing 0 onto
|
||||
the loading file.
|
||||
|
||||
The firmware device used to help load firmware using sysfs is only created if
|
||||
direct firmware loading fails and if the fallback mechanism is enabled for your
|
||||
firmware request, this is set up with fw_load_from_user_helper(). It is
|
||||
important to re-iterate that no device is created if a direct filesystem lookup
|
||||
succeeded.
|
||||
|
||||
Using::
|
||||
|
||||
echo 1 > /sys/$DEVPATH/loading
|
||||
|
||||
Will clean any previous partial load at once and make the firmware API
|
||||
return an error. When loading firmware the firmware_class grows a buffer
|
||||
for the firmware in PAGE_SIZE increments to hold the image as it comes in.
|
||||
|
||||
firmware_data_read() and firmware_loading_show() are just provided for the
|
||||
test_firmware driver for testing, they are not called in normal use or
|
||||
expected to be used regularly by userspace.
|
||||
|
||||
Firmware kobject uevent fallback mechanism
|
||||
==========================================
|
||||
|
||||
Since a device is created for the sysfs interface to help load firmware as a
|
||||
fallback mechanism userspace can be informed of the addition of the device by
|
||||
relying on kobject uevents. The addition of the device into the device
|
||||
hierarchy means the fallback mechanism for firmware loading has been initiated.
|
||||
For details of implementation refer to _request_firmware_load(), in particular
|
||||
on the use of dev_set_uevent_suppress() and kobject_uevent().
|
||||
|
||||
The kernel's kobject uevent mechanism is implemented in lib/kobject_uevent.c,
|
||||
it issues uevents to userspace. As a supplement to kobject uevents Linux
|
||||
distributions could also enable CONFIG_UEVENT_HELPER_PATH, which makes use of
|
||||
core kernel's usermode helper (UMH) functionality to call out to a userspace
|
||||
helper for kobject uevents. In practice though no standard distribution has
|
||||
ever used the CONFIG_UEVENT_HELPER_PATH. If CONFIG_UEVENT_HELPER_PATH is
|
||||
enabled this binary would be called each time kobject_uevent_env() gets called
|
||||
in the kernel for each kobject uevent triggered.
|
||||
|
||||
Different implementations have been supported in userspace to take advantage of
|
||||
this fallback mechanism. When firmware loading was only possible using the
|
||||
sysfs mechanism the userspace component "hotplug" provided the functionality of
|
||||
monitoring for kobject events. Historically this was superseded be systemd's
|
||||
udev, however firmware loading support was removed from udev as of systemd
|
||||
commit be2ea723b1d0 ("udev: remove userspace firmware loading support")
|
||||
as of v217 on August, 2014. This means most Linux distributions today are
|
||||
not using or taking advantage of the firmware fallback mechanism provided
|
||||
by kobject uevents. This is specially exacerbated due to the fact that most
|
||||
distributions today disable CONFIG_FW_LOADER_USER_HELPER_FALLBACK.
|
||||
|
||||
Refer to do_firmware_uevent() for details of the kobject event variables
|
||||
setup. Variables passwdd with a kobject add event:
|
||||
|
||||
* FIRMWARE=firmware name
|
||||
* TIMEOUT=timeout value
|
||||
* ASYNC=whether or not the API request was asynchronous
|
||||
|
||||
By default DEVPATH is set by the internal kernel kobject infrastructure.
|
||||
Below is an example simple kobject uevent script::
|
||||
|
||||
# Both $DEVPATH and $FIRMWARE are already provided in the environment.
|
||||
MY_FW_DIR=/lib/firmware/
|
||||
echo 1 > /sys/$DEVPATH/loading
|
||||
cat $MY_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
|
||||
echo 0 > /sys/$DEVPATH/loading
|
||||
|
||||
Firmware custom fallback mechanism
|
||||
==================================
|
||||
|
||||
Users of the request_firmware_nowait() call have yet another option available
|
||||
at their disposal: rely on the sysfs fallback mechanism but request that no
|
||||
kobject uevents be issued to userspace. The original logic behind this
|
||||
was that utilities other than udev might be required to lookup firmware
|
||||
in non-traditional paths -- paths outside of the listing documented in the
|
||||
section 'Direct filesystem lookup'. This option is not available to any of
|
||||
the other API calls as uevents are always forced for them.
|
||||
|
||||
Since uevents are only meaningful if the fallback mechanism is enabled
|
||||
in your kernel it would seem odd to enable uevents with kernels that do not
|
||||
have the fallback mechanism enabled in their kernels. Unfortunately we also
|
||||
rely on the uevent flag which can be disabled by request_firmware_nowait() to
|
||||
also setup the firmware cache for firmware requests. As documented above,
|
||||
the firmware cache is only set up if uevent is enabled for an API call.
|
||||
Although this can disable the firmware cache for request_firmware_nowait()
|
||||
calls, users of this API should not use it for the purposes of disabling
|
||||
the cache as that was not the original purpose of the flag. Not setting
|
||||
the uevent flag means you want to opt-in for the firmware fallback mechanism
|
||||
but you want to suppress kobject uevents, as you have a custom solution which
|
||||
will monitor for your device addition into the device hierarchy somehow and
|
||||
load firmware for you through a custom path.
|
||||
|
||||
Firmware fallback timeout
|
||||
=========================
|
||||
|
||||
The firmware fallback mechanism has a timeout. If firmware is not loaded
|
||||
onto the sysfs interface by the timeout value an error is sent to the
|
||||
driver. By default the timeout is set to 60 seconds if uevents are
|
||||
desirable, otherwise MAX_JIFFY_OFFSET is used (max timeout possible).
|
||||
The logic behind using MAX_JIFFY_OFFSET for non-uevents is that a custom
|
||||
solution will have as much time as it needs to load firmware.
|
||||
|
||||
You can customize the firmware timeout by echo'ing your desired timeout into
|
||||
the following file:
|
||||
|
||||
* /sys/class/firmware/timeout
|
||||
|
||||
If you echo 0 into it means MAX_JIFFY_OFFSET will be used. The data type
|
||||
for the timeout is an int.
|
51
Documentation/driver-api/firmware/firmware_cache.rst
Normal file
51
Documentation/driver-api/firmware/firmware_cache.rst
Normal file
|
@ -0,0 +1,51 @@
|
|||
==============
|
||||
Firmware cache
|
||||
==============
|
||||
|
||||
When Linux resumes from suspend some device drivers require firmware lookups to
|
||||
re-initialize devices. During resume there may be a period of time during which
|
||||
firmware lookups are not possible, during this short period of time firmware
|
||||
requests will fail. Time is of essence though, and delaying drivers to wait for
|
||||
the root filesystem for firmware delays user experience with device
|
||||
functionality. In order to support these requirements the firmware
|
||||
infrastructure implements a firmware cache for device drivers for most API
|
||||
calls, automatically behind the scenes.
|
||||
|
||||
The firmware cache makes using certain firmware API calls safe during a device
|
||||
driver's suspend and resume callback. Users of these API calls needn't cache
|
||||
the firmware by themselves for dealing with firmware loss during system resume.
|
||||
|
||||
The firmware cache works by requesting for firmware prior to suspend and
|
||||
caching it in memory. Upon resume device drivers using the firmware API will
|
||||
have access to the firmware immediately, without having to wait for the root
|
||||
filesystem to mount or dealing with possible race issues with lookups as the
|
||||
root filesystem mounts.
|
||||
|
||||
Some implementation details about the firmware cache setup:
|
||||
|
||||
* The firmware cache is setup by adding a devres entry for each device that
|
||||
uses all synchronous call except :c:func:`request_firmware_into_buf`.
|
||||
|
||||
* If an asynchronous call is used the firmware cache is only set up for a
|
||||
device if if the second argument (uevent) to request_firmware_nowait() is
|
||||
true. When uevent is true it requests that a kobject uevent be sent to
|
||||
userspace for the firmware request. For details refer to the Fackback
|
||||
mechanism documented below.
|
||||
|
||||
* If the firmware cache is determined to be needed as per the above two
|
||||
criteria the firmware cache is setup by adding a devres entry for the
|
||||
device making the firmware request.
|
||||
|
||||
* The firmware devres entry is maintained throughout the lifetime of the
|
||||
device. This means that even if you release_firmware() the firmware cache
|
||||
will still be used on resume from suspend.
|
||||
|
||||
* The timeout for the fallback mechanism is temporarily reduced to 10 seconds
|
||||
as the firmware cache is set up during suspend, the timeout is set back to
|
||||
the old value you had configured after the cache is set up.
|
||||
|
||||
* Upon suspend any pending non-uevent firmware requests are killed to avoid
|
||||
stalling the kernel, this is done with kill_requests_without_uevent(). Kernel
|
||||
calls requiring the non-uevent therefore need to implement their own firmware
|
||||
cache mechanism but must not use the firmware API on suspend.
|
||||
|
26
Documentation/driver-api/firmware/fw_search_path.rst
Normal file
26
Documentation/driver-api/firmware/fw_search_path.rst
Normal file
|
@ -0,0 +1,26 @@
|
|||
=====================
|
||||
Firmware search paths
|
||||
=====================
|
||||
|
||||
The following search paths are used to look for firmware on your
|
||||
root filesystem.
|
||||
|
||||
* fw_path_para - module parameter - default is empty so this is ignored
|
||||
* /lib/firmware/updates/UTS_RELEASE/
|
||||
* /lib/firmware/updates/
|
||||
* /lib/firmware/UTS_RELEASE/
|
||||
* /lib/firmware/
|
||||
|
||||
The module parameter ''path'' can be passed to the firmware_class module
|
||||
to activate the first optional custom fw_path_para. The custom path can
|
||||
only be up to 256 characters long. The kernel parameter passed would be:
|
||||
|
||||
* 'firmware_class.path=$CUSTOMIZED_PATH'
|
||||
|
||||
There is an alternative to customize the path at run time after bootup, you
|
||||
can use the file:
|
||||
|
||||
* /sys/module/firmware_class/parameters/path
|
||||
|
||||
You would echo into it your custom path and firmware requested will be
|
||||
searched for there first.
|
16
Documentation/driver-api/firmware/index.rst
Normal file
16
Documentation/driver-api/firmware/index.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
==================
|
||||
Linux Firmware API
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
|
||||
introduction
|
||||
core
|
||||
request_firmware
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
27
Documentation/driver-api/firmware/introduction.rst
Normal file
27
Documentation/driver-api/firmware/introduction.rst
Normal file
|
@ -0,0 +1,27 @@
|
|||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
The firmware API enables kernel code to request files required
|
||||
for functionality from userspace, the uses vary:
|
||||
|
||||
* Microcode for CPU errata
|
||||
* Device driver firmware, required to be loaded onto device
|
||||
microcontrollers
|
||||
* Device driver information data (calibration data, EEPROM overrides),
|
||||
some of which can be completely optional.
|
||||
|
||||
Types of firmware requests
|
||||
==========================
|
||||
|
||||
There are two types of calls:
|
||||
|
||||
* Synchronous
|
||||
* Asynchronous
|
||||
|
||||
Which one you use vary depending on your requirements, the rule of thumb
|
||||
however is you should strive to use the asynchronous APIs unless you also
|
||||
are already using asynchronous initialization mechanisms which will not
|
||||
stall or delay boot. Even if loading firmware does not take a lot of time
|
||||
processing firmware might, and this can still delay boot or initialization,
|
||||
as such mechanisms such as asynchronous probe can help supplement drivers.
|
18
Documentation/driver-api/firmware/lookup-order.rst
Normal file
18
Documentation/driver-api/firmware/lookup-order.rst
Normal file
|
@ -0,0 +1,18 @@
|
|||
=====================
|
||||
Firmware lookup order
|
||||
=====================
|
||||
|
||||
Different functionality is available to enable firmware to be found.
|
||||
Below is chronological order of how firmware will be looked for once
|
||||
a driver issues a firmware API call.
|
||||
|
||||
* The ''Built-in firmware'' is checked first, if the firmware is present we
|
||||
return it immediately
|
||||
* The ''Firmware cache'' is looked at next. If the firmware is found we
|
||||
return it immediately
|
||||
* The ''Direct filesystem lookup'' is performed next, if found we
|
||||
return it immediately
|
||||
* If no firmware has been found and the fallback mechanism was enabled
|
||||
the sysfs interface is created. After this either a kobject uevent
|
||||
is issued or the custom firmware loading is relied upon for firmware
|
||||
loading up to the timeout value.
|
56
Documentation/driver-api/firmware/request_firmware.rst
Normal file
56
Documentation/driver-api/firmware/request_firmware.rst
Normal file
|
@ -0,0 +1,56 @@
|
|||
====================
|
||||
request_firmware API
|
||||
====================
|
||||
|
||||
You would typically load firmware and then load it into your device somehow.
|
||||
The typical firmware work flow is reflected below::
|
||||
|
||||
if(request_firmware(&fw_entry, $FIRMWARE, device) == 0)
|
||||
copy_fw_to_device(fw_entry->data, fw_entry->size);
|
||||
release_firmware(fw_entry);
|
||||
|
||||
Synchronous firmware requests
|
||||
=============================
|
||||
|
||||
Synchronous firmware requests will wait until the firmware is found or until
|
||||
an error is returned.
|
||||
|
||||
request_firmware
|
||||
----------------
|
||||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:functions: request_firmware
|
||||
|
||||
request_firmware_direct
|
||||
-----------------------
|
||||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:functions: request_firmware_direct
|
||||
|
||||
request_firmware_into_buf
|
||||
-------------------------
|
||||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:functions: request_firmware_into_buf
|
||||
|
||||
Asynchronous firmware requests
|
||||
==============================
|
||||
|
||||
Asynchronous firmware requests allow driver code to not have to wait
|
||||
until the firmware or an error is returned. Function callbacks are
|
||||
provided so that when the firmware or an error is found the driver is
|
||||
informed through the callback. request_firmware_nowait() cannot be called
|
||||
in atomic contexts.
|
||||
|
||||
request_firmware_nowait
|
||||
-----------------------
|
||||
.. kernel-doc:: drivers/base/firmware_class.c
|
||||
:functions: request_firmware_nowait
|
||||
|
||||
request firmware API expected driver use
|
||||
========================================
|
||||
|
||||
Once an API call returns you process the firmware and then release the
|
||||
firmware. For example if you used request_firmware() and it returns,
|
||||
the driver has the firmware image accessible in fw_entry->{data,size}.
|
||||
If something went wrong request_firmware() returns non-zero and fw_entry
|
||||
is set to NULL. Once your driver is done with processing the firmware it
|
||||
can call call release_firmware(fw_entry) to release the firmware image
|
||||
and any related resource.
|
|
@ -31,6 +31,7 @@ available subsections can be seen below.
|
|||
vme
|
||||
80211/index
|
||||
uio-howto
|
||||
firmware/index
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
|
||||
request_firmware() hotplug interface:
|
||||
------------------------------------
|
||||
Copyright (C) 2003 Manuel Estrada Sainz
|
||||
|
||||
Why:
|
||||
---
|
||||
|
||||
Today, the most extended way to use firmware in the Linux kernel is linking
|
||||
it statically in a header file. Which has political and technical issues:
|
||||
|
||||
1) Some firmware is not legal to redistribute.
|
||||
2) The firmware occupies memory permanently, even though it often is just
|
||||
used once.
|
||||
3) Some people, like the Debian crowd, don't consider some firmware free
|
||||
enough and remove entire drivers (e.g.: keyspan).
|
||||
|
||||
High level behavior (mixed):
|
||||
============================
|
||||
|
||||
1), kernel(driver):
|
||||
- calls request_firmware(&fw_entry, $FIRMWARE, device)
|
||||
- kernel searches the firmware image with name $FIRMWARE directly
|
||||
in the below search path of root filesystem:
|
||||
User customized search path by module parameter 'path'[1]
|
||||
"/lib/firmware/updates/" UTS_RELEASE,
|
||||
"/lib/firmware/updates",
|
||||
"/lib/firmware/" UTS_RELEASE,
|
||||
"/lib/firmware"
|
||||
- If found, goto 7), else goto 2)
|
||||
|
||||
[1], the 'path' is a string parameter which length should be less
|
||||
than 256, user should pass 'firmware_class.path=$CUSTOMIZED_PATH'
|
||||
if firmware_class is built in kernel(the general situation)
|
||||
|
||||
2), userspace:
|
||||
- /sys/class/firmware/xxx/{loading,data} appear.
|
||||
- hotplug gets called with a firmware identifier in $FIRMWARE
|
||||
and the usual hotplug environment.
|
||||
- hotplug: echo 1 > /sys/class/firmware/xxx/loading
|
||||
|
||||
3), kernel: Discard any previous partial load.
|
||||
|
||||
4), userspace:
|
||||
- hotplug: cat appropriate_firmware_image > \
|
||||
/sys/class/firmware/xxx/data
|
||||
|
||||
5), kernel: grows a buffer in PAGE_SIZE increments to hold the image as it
|
||||
comes in.
|
||||
|
||||
6), userspace:
|
||||
- hotplug: echo 0 > /sys/class/firmware/xxx/loading
|
||||
|
||||
7), kernel: request_firmware() returns and the driver has the firmware
|
||||
image in fw_entry->{data,size}. If something went wrong
|
||||
request_firmware() returns non-zero and fw_entry is set to
|
||||
NULL.
|
||||
|
||||
8), kernel(driver): Driver code calls release_firmware(fw_entry) releasing
|
||||
the firmware image and any related resource.
|
||||
|
||||
High level behavior (driver code):
|
||||
==================================
|
||||
|
||||
if(request_firmware(&fw_entry, $FIRMWARE, device) == 0)
|
||||
copy_fw_to_device(fw_entry->data, fw_entry->size);
|
||||
release_firmware(fw_entry);
|
||||
|
||||
Sample/simple hotplug script:
|
||||
============================
|
||||
|
||||
# Both $DEVPATH and $FIRMWARE are already provided in the environment.
|
||||
|
||||
HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
|
||||
|
||||
echo 1 > /sys/$DEVPATH/loading
|
||||
cat $HOTPLUG_FW_DIR/$FIRMWARE > /sys/$DEVPATH/data
|
||||
echo 0 > /sys/$DEVPATH/loading
|
||||
|
||||
Random notes:
|
||||
============
|
||||
|
||||
- "echo -1 > /sys/class/firmware/xxx/loading" will cancel the load at
|
||||
once and make request_firmware() return with error.
|
||||
|
||||
- firmware_data_read() and firmware_loading_show() are just provided
|
||||
for testing and completeness, they are not called in normal use.
|
||||
|
||||
- There is also /sys/class/firmware/timeout which holds a timeout in
|
||||
seconds for the whole load operation.
|
||||
|
||||
- request_firmware_nowait() is also provided for convenience in
|
||||
user contexts to request firmware asynchronously, but can't be called
|
||||
in atomic contexts.
|
||||
|
||||
|
||||
about in-kernel persistence:
|
||||
---------------------------
|
||||
Under some circumstances, as explained below, it would be interesting to keep
|
||||
firmware images in non-swappable kernel memory or even in the kernel image
|
||||
(probably within initramfs).
|
||||
|
||||
Note that this functionality has not been implemented.
|
||||
|
||||
- Why OPTIONAL in-kernel persistence may be a good idea sometimes:
|
||||
|
||||
- If the device that needs the firmware is needed to access the
|
||||
filesystem. When upon some error the device has to be reset and the
|
||||
firmware reloaded, it won't be possible to get it from userspace.
|
||||
e.g.:
|
||||
- A diskless client with a network card that needs firmware.
|
||||
- The filesystem is stored in a disk behind an scsi device
|
||||
that needs firmware.
|
||||
- Replacing buggy DSDT/SSDT ACPI tables on boot.
|
||||
Note: this would require the persistent objects to be included
|
||||
within the kernel image, probably within initramfs.
|
||||
|
||||
And the same device can be needed to access the filesystem or not depending
|
||||
on the setup, so I think that the choice on what firmware to make
|
||||
persistent should be left to userspace.
|
||||
|
||||
about firmware cache:
|
||||
--------------------
|
||||
After firmware cache mechanism is introduced during system sleep,
|
||||
request_firmware can be called safely inside device's suspend and
|
||||
resume callback, and callers needn't cache the firmware by
|
||||
themselves any more for dealing with firmware loss during system
|
||||
resume.
|
|
@ -406,7 +406,7 @@ int platform_device_add(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (p && insert_resource(p, r)) {
|
||||
dev_err(&pdev->dev, "failed to claim resource %d\n", i);
|
||||
dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r);
|
||||
ret = -EBUSY;
|
||||
goto failed;
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ static inline void wf_notify(int event, void *param)
|
|||
|
||||
static int wf_critical_overtemp(void)
|
||||
{
|
||||
static char * critical_overtemp_path = "/sbin/critical_overtemp";
|
||||
char *argv[] = { critical_overtemp_path, NULL };
|
||||
static char const critical_overtemp_path[] = "/sbin/critical_overtemp";
|
||||
char *argv[] = { (char *)critical_overtemp_path, NULL };
|
||||
static char *envp[] = { "HOME=/",
|
||||
"TERM=linux",
|
||||
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
|
||||
|
|
|
@ -299,7 +299,7 @@ static inline void baycom_int_freq(struct baycom_state *bc)
|
|||
* eppconfig_path should be setable via /proc/sys.
|
||||
*/
|
||||
|
||||
static char eppconfig_path[256] = "/usr/sbin/eppfpga";
|
||||
static char const eppconfig_path[] = "/usr/sbin/eppfpga";
|
||||
|
||||
static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
|
||||
|
||||
|
@ -308,8 +308,12 @@ static int eppconfig(struct baycom_state *bc)
|
|||
{
|
||||
char modearg[256];
|
||||
char portarg[16];
|
||||
char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg,
|
||||
NULL };
|
||||
char *argv[] = {
|
||||
(char *)eppconfig_path,
|
||||
"-s",
|
||||
"-p", portarg,
|
||||
"-m", modearg,
|
||||
NULL };
|
||||
|
||||
/* set up arguments */
|
||||
sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat",
|
||||
|
|
|
@ -98,6 +98,7 @@ static struct completion unload_sem;
|
|||
*/
|
||||
static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
|
||||
{
|
||||
static char const sbin_pnpbios[] = "/sbin/pnpbios";
|
||||
char *argv[3], **envp, *buf, *scratch;
|
||||
int i = 0, value;
|
||||
|
||||
|
@ -112,7 +113,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
|
|||
* integrated into the driver core and use the usual infrastructure
|
||||
* like sysfs and uevents
|
||||
*/
|
||||
argv[0] = "/sbin/pnpbios";
|
||||
argv[0] = (char *)sbin_pnpbios;
|
||||
argv[1] = "dock";
|
||||
argv[2] = NULL;
|
||||
|
||||
|
@ -139,7 +140,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
|
|||
info->location_id, info->serial, info->capabilities);
|
||||
envp[i] = NULL;
|
||||
|
||||
value = call_usermodehelper(argv [0], argv, envp, UMH_WAIT_EXEC);
|
||||
value = call_usermodehelper(sbin_pnpbios, argv, envp, UMH_WAIT_EXEC);
|
||||
kfree(buf);
|
||||
kfree(envp);
|
||||
return 0;
|
||||
|
|
|
@ -44,14 +44,14 @@ static int svc_watchdog_pm_notifier(struct notifier_block *notifier,
|
|||
|
||||
static void greybus_reset(struct work_struct *work)
|
||||
{
|
||||
static char start_path[256] = "/system/bin/start";
|
||||
static char const start_path[] = "/system/bin/start";
|
||||
static char *envp[] = {
|
||||
"HOME=/",
|
||||
"PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin",
|
||||
NULL,
|
||||
};
|
||||
static char *argv[] = {
|
||||
start_path,
|
||||
(char *)start_path,
|
||||
"unipro_reset",
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -268,8 +268,8 @@ void rtl92e_dm_watchdog(struct net_device *dev)
|
|||
static void _rtl92e_dm_check_ac_dc_power(struct net_device *dev)
|
||||
{
|
||||
struct r8192_priv *priv = rtllib_priv(dev);
|
||||
static char *ac_dc_script = "/etc/acpi/wireless-rtl-ac-dc-power.sh";
|
||||
char *argv[] = {ac_dc_script, DRV_NAME, NULL};
|
||||
static char const ac_dc_script[] = "/etc/acpi/wireless-rtl-ac-dc-power.sh";
|
||||
char *argv[] = {(char *)ac_dc_script, DRV_NAME, NULL};
|
||||
static char *envp[] = {"HOME=/",
|
||||
"TERM=linux",
|
||||
"PATH=/usr/bin:/bin",
|
||||
|
@ -1823,7 +1823,7 @@ static void _rtl92e_dm_check_rf_ctrl_gpio(void *data)
|
|||
enum rt_rf_power_state eRfPowerStateToSet;
|
||||
bool bActuallySet = false;
|
||||
char *argv[3];
|
||||
static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh";
|
||||
static char const RadioPowerPath[] = "/etc/acpi/events/RadioPower.sh";
|
||||
static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin",
|
||||
NULL};
|
||||
|
||||
|
@ -1862,7 +1862,7 @@ static void _rtl92e_dm_check_rf_ctrl_gpio(void *data)
|
|||
else
|
||||
argv[1] = "RFON";
|
||||
|
||||
argv[0] = RadioPowerPath;
|
||||
argv[0] = (char *)RadioPowerPath;
|
||||
argv[2] = NULL;
|
||||
call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ static bool kernfs_lockdep(struct kernfs_node *kn)
|
|||
|
||||
static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen)
|
||||
{
|
||||
if (!kn)
|
||||
return strlcpy(buf, "(null)", buflen);
|
||||
|
||||
return strlcpy(buf, kn->parent ? kn->name : "/", buflen);
|
||||
}
|
||||
|
||||
|
@ -110,6 +113,8 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
|
|||
* kn_to: /n1/n2/n3 [depth=3]
|
||||
* result: /../..
|
||||
*
|
||||
* [3] when @kn_to is NULL result will be "(null)"
|
||||
*
|
||||
* Returns the length of the full path. If the full length is equal to or
|
||||
* greater than @buflen, @buf contains the truncated path with the trailing
|
||||
* '\0'. On error, -errno is returned.
|
||||
|
@ -123,6 +128,9 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
|
|||
size_t depth_from, depth_to, len = 0;
|
||||
int i, j;
|
||||
|
||||
if (!kn_to)
|
||||
return strlcpy(buf, "(null)", buflen);
|
||||
|
||||
if (!kn_from)
|
||||
kn_from = kernfs_root(kn_to)->kn;
|
||||
|
||||
|
@ -166,6 +174,8 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
|
|||
* similar to strlcpy(). It returns the length of @kn's name and if @buf
|
||||
* isn't long enough, it's filled upto @buflen-1 and nul terminated.
|
||||
*
|
||||
* Fills buffer with "(null)" if @kn is NULL.
|
||||
*
|
||||
* This function can be called from any context.
|
||||
*/
|
||||
int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
|
||||
|
|
|
@ -614,6 +614,7 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
|
|||
{
|
||||
struct nfs4_client *clp = ls->ls_stid.sc_client;
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
static char const nfsd_recall_failed[] = "/sbin/nfsd-recall-failed";
|
||||
static char *envp[] = {
|
||||
"HOME=/",
|
||||
"TERM=linux",
|
||||
|
@ -629,12 +630,13 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
|
|||
"nfsd: client %s failed to respond to layout recall. "
|
||||
" Fencing..\n", addr_str);
|
||||
|
||||
argv[0] = "/sbin/nfsd-recall-failed";
|
||||
argv[0] = (char *)nfsd_recall_failed;
|
||||
argv[1] = addr_str;
|
||||
argv[2] = ls->ls_file->f_path.mnt->mnt_sb->s_id;
|
||||
argv[3] = NULL;
|
||||
|
||||
error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
|
||||
error = call_usermodehelper(nfsd_recall_failed, argv, envp,
|
||||
UMH_WAIT_PROC);
|
||||
if (error) {
|
||||
printk(KERN_ERR "nfsd: fence failed for client %s: %d!\n",
|
||||
addr_str, error);
|
||||
|
|
|
@ -52,8 +52,7 @@ extern struct srcu_struct debugfs_srcu;
|
|||
* Must only be called under the protection established by
|
||||
* debugfs_use_file_start().
|
||||
*/
|
||||
static inline const struct file_operations *
|
||||
debugfs_real_fops(const struct file *filp)
|
||||
static inline const struct file_operations *debugfs_real_fops(const struct file *filp)
|
||||
__must_hold(&debugfs_srcu)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -56,7 +56,7 @@ struct file;
|
|||
struct subprocess_info {
|
||||
struct work_struct work;
|
||||
struct completion *complete;
|
||||
char *path;
|
||||
const char *path;
|
||||
char **argv;
|
||||
char **envp;
|
||||
int wait;
|
||||
|
@ -67,10 +67,11 @@ struct subprocess_info {
|
|||
};
|
||||
|
||||
extern int
|
||||
call_usermodehelper(char *path, char **argv, char **envp, int wait);
|
||||
call_usermodehelper(const char *path, char **argv, char **envp, int wait);
|
||||
|
||||
extern struct subprocess_info *
|
||||
call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask,
|
||||
call_usermodehelper_setup(const char *path, char **argv, char **envp,
|
||||
gfp_t gfp_mask,
|
||||
int (*init)(struct subprocess_info *info, struct cred *new),
|
||||
void (*cleanup)(struct subprocess_info *), void *data);
|
||||
|
||||
|
|
|
@ -61,19 +61,15 @@ DECLARE_EVENT_CLASS(cgroup,
|
|||
__field( int, id )
|
||||
__field( int, level )
|
||||
__dynamic_array(char, path,
|
||||
cgrp->kn ? cgroup_path(cgrp, NULL, 0) + 1
|
||||
: strlen("(null)"))
|
||||
cgroup_path(cgrp, NULL, 0) + 1)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->root = cgrp->root->hierarchy_id;
|
||||
__entry->id = cgrp->id;
|
||||
__entry->level = cgrp->level;
|
||||
if (cgrp->kn)
|
||||
cgroup_path(cgrp, __get_dynamic_array(path),
|
||||
__get_dynamic_array_len(path));
|
||||
else
|
||||
__assign_str(path, "(null)");
|
||||
cgroup_path(cgrp, __get_dynamic_array(path),
|
||||
__get_dynamic_array_len(path));
|
||||
),
|
||||
|
||||
TP_printk("root=%d id=%d level=%d path=%s",
|
||||
|
@ -119,8 +115,7 @@ DECLARE_EVENT_CLASS(cgroup_migrate,
|
|||
__field( int, dst_id )
|
||||
__field( int, dst_level )
|
||||
__dynamic_array(char, dst_path,
|
||||
dst_cgrp->kn ? cgroup_path(dst_cgrp, NULL, 0) + 1
|
||||
: strlen("(null)"))
|
||||
cgroup_path(dst_cgrp, NULL, 0) + 1)
|
||||
__field( int, pid )
|
||||
__string( comm, task->comm )
|
||||
),
|
||||
|
@ -129,11 +124,8 @@ DECLARE_EVENT_CLASS(cgroup_migrate,
|
|||
__entry->dst_root = dst_cgrp->root->hierarchy_id;
|
||||
__entry->dst_id = dst_cgrp->id;
|
||||
__entry->dst_level = dst_cgrp->level;
|
||||
if (dst_cgrp->kn)
|
||||
cgroup_path(dst_cgrp, __get_dynamic_array(dst_path),
|
||||
__get_dynamic_array_len(dst_path));
|
||||
else
|
||||
__assign_str(dst_path, "(null)");
|
||||
cgroup_path(dst_cgrp, __get_dynamic_array(dst_path),
|
||||
__get_dynamic_array_len(dst_path));
|
||||
__entry->pid = task->pid;
|
||||
__assign_str(comm, task->comm);
|
||||
),
|
||||
|
|
|
@ -516,7 +516,7 @@ static void helper_unlock(void)
|
|||
* Function must be runnable in either a process context or the
|
||||
* context in which call_usermodehelper_exec is called.
|
||||
*/
|
||||
struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
|
||||
struct subprocess_info *call_usermodehelper_setup(const char *path, char **argv,
|
||||
char **envp, gfp_t gfp_mask,
|
||||
int (*init)(struct subprocess_info *info, struct cred *new),
|
||||
void (*cleanup)(struct subprocess_info *info),
|
||||
|
@ -528,7 +528,12 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
|
|||
goto out;
|
||||
|
||||
INIT_WORK(&sub_info->work, call_usermodehelper_exec_work);
|
||||
|
||||
#ifdef CONFIG_STATIC_USERMODEHELPER
|
||||
sub_info->path = CONFIG_STATIC_USERMODEHELPER_PATH;
|
||||
#else
|
||||
sub_info->path = path;
|
||||
#endif
|
||||
sub_info->argv = argv;
|
||||
sub_info->envp = envp;
|
||||
|
||||
|
@ -566,6 +571,15 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
|
|||
retval = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no binary for us to call, then just return and get out of
|
||||
* here. This allows us to set STATIC_USERMODEHELPER_PATH to "" and
|
||||
* disable all call_usermodehelper() calls.
|
||||
*/
|
||||
if (strlen(sub_info->path) == 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Set the completion pointer only if there is a waiter.
|
||||
* This makes it possible to use umh_complete to free
|
||||
|
@ -613,7 +627,7 @@ EXPORT_SYMBOL(call_usermodehelper_exec);
|
|||
* This function is the equivalent to use call_usermodehelper_setup() and
|
||||
* call_usermodehelper_exec().
|
||||
*/
|
||||
int call_usermodehelper(char *path, char **argv, char **envp, int wait)
|
||||
int call_usermodehelper(const char *path, char **argv, char **envp, int wait)
|
||||
{
|
||||
struct subprocess_info *info;
|
||||
gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
|
||||
|
|
|
@ -158,6 +158,41 @@ config HARDENED_USERCOPY_PAGESPAN
|
|||
been removed. This config is intended to be used only while
|
||||
trying to find such users.
|
||||
|
||||
config STATIC_USERMODEHELPER
|
||||
bool "Force all usermode helper calls through a single binary"
|
||||
help
|
||||
By default, the kernel can call many different userspace
|
||||
binary programs through the "usermode helper" kernel
|
||||
interface. Some of these binaries are statically defined
|
||||
either in the kernel code itself, or as a kernel configuration
|
||||
option. However, some of these are dynamically created at
|
||||
runtime, or can be modified after the kernel has started up.
|
||||
To provide an additional layer of security, route all of these
|
||||
calls through a single executable that can not have its name
|
||||
changed.
|
||||
|
||||
Note, it is up to this single binary to then call the relevant
|
||||
"real" usermode helper binary, based on the first argument
|
||||
passed to it. If desired, this program can filter and pick
|
||||
and choose what real programs are called.
|
||||
|
||||
If you wish for all usermode helper programs are to be
|
||||
disabled, choose this option and then set
|
||||
STATIC_USERMODEHELPER_PATH to an empty string.
|
||||
|
||||
config STATIC_USERMODEHELPER_PATH
|
||||
string "Path to the static usermode helper binary"
|
||||
depends on STATIC_USERMODEHELPER
|
||||
default "/sbin/usermode-helper"
|
||||
help
|
||||
The binary called by the kernel when any usermode helper
|
||||
program is wish to be run. The "real" application's name will
|
||||
be in the first argument passed to this program on the command
|
||||
line.
|
||||
|
||||
If you wish for all usermode helper programs to be disabled,
|
||||
specify an empty string here (i.e. "").
|
||||
|
||||
source security/selinux/Kconfig
|
||||
source security/smack/Kconfig
|
||||
source security/tomoyo/Kconfig
|
||||
|
|
|
@ -72,7 +72,7 @@ static void umh_keys_cleanup(struct subprocess_info *info)
|
|||
/*
|
||||
* Call a usermode helper with a specific session keyring.
|
||||
*/
|
||||
static int call_usermodehelper_keys(char *path, char **argv, char **envp,
|
||||
static int call_usermodehelper_keys(const char *path, char **argv, char **envp,
|
||||
struct key *session_keyring, int wait)
|
||||
{
|
||||
struct subprocess_info *info;
|
||||
|
@ -95,6 +95,7 @@ static int call_sbin_request_key(struct key_construction *cons,
|
|||
const char *op,
|
||||
void *aux)
|
||||
{
|
||||
static char const request_key[] = "/sbin/request-key";
|
||||
const struct cred *cred = current_cred();
|
||||
key_serial_t prkey, sskey;
|
||||
struct key *key = cons->key, *authkey = cons->authkey, *keyring,
|
||||
|
@ -161,7 +162,7 @@ static int call_sbin_request_key(struct key_construction *cons,
|
|||
|
||||
/* set up the argument list */
|
||||
i = 0;
|
||||
argv[i++] = "/sbin/request-key";
|
||||
argv[i++] = (char *)request_key;
|
||||
argv[i++] = (char *) op;
|
||||
argv[i++] = key_str;
|
||||
argv[i++] = uid_str;
|
||||
|
@ -172,7 +173,7 @@ static int call_sbin_request_key(struct key_construction *cons,
|
|||
argv[i] = NULL;
|
||||
|
||||
/* do it */
|
||||
ret = call_usermodehelper_keys(argv[0], argv, envp, keyring,
|
||||
ret = call_usermodehelper_keys(request_key, argv, envp, keyring,
|
||||
UMH_WAIT_PROC);
|
||||
kdebug("usermode -> 0x%x", ret);
|
||||
if (ret >= 0) {
|
||||
|
|
|
@ -5,9 +5,24 @@
|
|||
# know so we can be sure we're not accidentally testing the user helper.
|
||||
set -e
|
||||
|
||||
modprobe test_firmware
|
||||
|
||||
DIR=/sys/devices/virtual/misc/test_firmware
|
||||
TEST_DIR=$(dirname $0)
|
||||
|
||||
test_modprobe()
|
||||
{
|
||||
if [ ! -d $DIR ]; then
|
||||
echo "$0: $DIR not present"
|
||||
echo "You must have the following enabled in your kernel:"
|
||||
cat $TEST_DIR/config
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
trap "test_modprobe" EXIT
|
||||
|
||||
if [ ! -d $DIR ]; then
|
||||
modprobe test_firmware
|
||||
fi
|
||||
|
||||
# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/
|
||||
# These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that
|
||||
|
@ -48,18 +63,18 @@ echo "ABCD0123" >"$FW"
|
|||
|
||||
NAME=$(basename "$FW")
|
||||
|
||||
if printf '\000' >"$DIR"/trigger_request; then
|
||||
if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then
|
||||
echo "$0: empty filename should not succeed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if printf '\000' >"$DIR"/trigger_async_request; then
|
||||
if printf '\000' >"$DIR"/trigger_async_request 2> /dev/null; then
|
||||
echo "$0: empty filename should not succeed (async)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Request a firmware that doesn't exist, it should fail.
|
||||
if echo -n "nope-$NAME" >"$DIR"/trigger_request; then
|
||||
if echo -n "nope-$NAME" >"$DIR"/trigger_request 2> /dev/null; then
|
||||
echo "$0: firmware shouldn't have loaded" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
|
Loading…
Reference in a new issue