7.1.4-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 273/518 HID: multitouch: fix out-of-bounds bit access on mt_io_flags
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Trung Nguyen <[email protected]>
commit 8813b0612275cc61fe9e6603d0ee019247ade6be upstream.
mt_io_flags is a single unsigned long, but mt_process_slot(), mt_release_pending_palms() and mt_release_contacts() use it as a per-slot bitmap indexed by the slot number. That slot number is only bounded by td->maxcontacts, which is taken from the device's ContactCountMaximum feature report and can be up to 255, not by BITS_PER_LONG.
As a result, a multitouch device that advertises a large contact count makes set_bit()/clear_bit() operate past the mt_io_flags word and corrupt the adjacent members of struct mt_device. The sticky-fingers release timer is the easiest way to reach this. mt_release_contacts() runs
for (i = 0; i < mt->num_slots; i++) clear_bit(i, &td->mt_io_flags);
with num_slots == maxcontacts. For maxcontacts around 250 the loop clears the bits that overlap td->applications.next, zeroing that list head, and the list_for_each_entry() that immediately follows then dereferences NULL. The kernel panics from timer (softirq) context. On a KASAN build this shows up as a general protection fault in mt_release_contacts() with a null-ptr-deref at offset 0x58, which is offsetof(struct mt_application, num_received).
The state is reachable from an untrusted USB or Bluetooth HID multitouch device; no local privileges are required.
Store the per-slot active state in a separately allocated bitmap sized for maxcontacts, the same pattern already used for pending_palm_slots, and keep only MT_IO_FLAGS_RUNNING in mt_io_flags. The two "mt_io_flags & MT_IO_SLOTS_MASK" arming checks become bitmap_empty(td->active_slots, td->maxcontacts).
Move MT_IO_FLAGS_RUNNING back to bit 0. It was bumped to bit 32 by the same commit to leave the low byte for the slot bits; with the slot bits gone it fits in bit 0 again, which also keeps it within the unsigned long on 32-bit.
--- drivers/hid/hid-multitouch.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
drivers/hid/hid-multitouch.c +20 -12
@@ -31,6 +31,7 @@* [1] https://gitlab.freedesktop.org/libevdev/hid-tools */ +#include <linux/bitmap.h> #include <linux/bits.h> #include <linux/device.h> #include <linux/hid.h>
@@ -97,8 +98,7 @@ enum report_mode { TOUCHPAD_REPORT_ALL = TOUCHPAD_REPORT_BUTTONS | TOUCHPAD_REPORT_CONTACTS, }; -#define MT_IO_SLOTS_MASK GENMASK(7, 0)/* reserve first 8 bits for slot tracking */ -#define MT_IO_FLAGS_RUNNING 32 +#define MT_IO_FLAGS_RUNNING 0static const bool mtrue = true;/* default for true */ static const bool mfalse;/* default for false */
@@ -174,10 +174,9 @@ struct mt_device {struct timer_list release_timer;/* to release sticky fingers */ struct hid_haptic_device *haptic;/* haptic related configuration */ struct hid_device *hdev;/* hid_device we're attached to */ -unsigned long mt_io_flags;/* mt flags (MT_IO_FLAGS_RUNNING) -* first 8 bits are reserved for keeping the slot -* states, this is fine because we only support up -* to 250 slots (MT_MAX_MAXCONTACT) +unsigned long mt_io_flags;/* mt flags (MT_IO_FLAGS_RUNNING) */ +unsigned long *active_slots;/* bitmap of slots with an active +* contact, sized for maxcontacts */ __u8 inputmode_value;/* InputMode HID feature value */ __u8 maxcontacts;
@@ -1033,7 +1032,7 @@ static void mt_release_pending_palms(strfor_each_set_bit (slotnum, app->pending_palm_slots, td->maxcontacts) {clear_bit (slotnum, app->pending_palm_slots); -clear_bit (slotnum, &td->mt_io_flags); +clear_bit (slotnum, td->active_slots);input_mt_slot (input, slotnum);input_mt_report_slot_inactive (input);
@@ -1244,9 +1243,9 @@ static int mt_process_slot(struct mt_devinput_event (input,EV_ABS ,ABS_MT_TOUCH_MAJOR , major);input_event (input,EV_ABS ,ABS_MT_TOUCH_MINOR , minor); -set_bit (slotnum, &td->mt_io_flags); +set_bit (slotnum, td->active_slots); }else { -clear_bit (slotnum, &td->mt_io_flags); +clear_bit (slotnum, td->active_slots); }return 0 ;
@@ -1381,7 +1380,7 @@ static void mt_touch_report(struct hid_d* defect. */ if (app->quirks &MT_QUIRK_STICKY_FINGERS ) { -if (td->mt_io_flags &MT_IO_SLOTS_MASK ) +if (!bitmap_empty (td->active_slots, td->maxcontacts))mod_timer (&td->release_timer, jiffies +msecs_to_jiffies (100 ));else
@@ -1440,6 +1439,15 @@ static int mt_touch_input_configured(strif (td->is_pressurepad)__set_bit (INPUT_PROP_PRESSUREPAD , input->propbit); +if (!td->active_slots) { + td->active_slots =devm_kcalloc (&td->hdev->dev, +BITS_TO_LONGS (td->maxcontacts), +sizeof (long ), +GFP_KERNEL ); +if (!td->active_slots) +return -ENOMEM ; + } + app->pending_palm_slots = devm_kcalloc(&hi->input->dev, BITS_TO_LONGS(td->maxcontacts), sizeof(long),
@@ -1917,7 +1925,7 @@ static void mt_release_contacts(struct hfor (i =0 ; i < mt->num_slots; i++) {input_mt_slot (input_dev, i);input_mt_report_slot_inactive (input_dev); -clear_bit (i, &td->mt_io_flags); +clear_bit (i, td->active_slots); }input_mt_sync_frame (input_dev);input_sync (input_dev);
@@ -1940,7 +1948,7 @@ static void mt_expired_timeout(struct ti*/ if (test_and_set_bit_lock (MT_IO_FLAGS_RUNNING , &td->mt_io_flags))return ; -if (td->mt_io_flags &MT_IO_SLOTS_MASK ) +if (!bitmap_empty (td->active_slots, td->maxcontacts))mt_release_contacts (hdev);clear_bit_unlock (MT_IO_FLAGS_RUNNING , &td->mt_io_flags); }
Greg Kroah-Hartman
maintainerPATCH 274/518 HID: appleir: fix UAF on pending key_up_timer in remove()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manish Khadka <[email protected]>
commit 75fe87e19d8aff81eb2c64d15d244ab8da4de945 upstream.
appleir_remove() runs hid_hw_stop() before timer_delete_sync(). hid_hw_stop() synchronously unregisters the HID input device via hid_disconnect() -> hidinput_disconnect() -> input_unregister_device(), which drops the last reference and frees the underlying input_dev when no userspace handle holds it open.
key_up_tick() reads appleir->input_dev and calls input_report_key() / input_sync() on it. The timer is armed from appleir_raw_event() with a HZ/8 (~125 ms) timeout on every keydown and key-repeat report. If a key was pressed shortly before the device is disconnected, the timer can fire after hid_hw_stop() has freed input_dev but before the teardown drains it.
A simple reorder is not sufficient. Putting the timer drain first still leaves a window where a USB URB completion (raw_event) running during hid_hw_stop() can call mod_timer() and re-arm the timer, which then fires after hidinput_disconnect() has freed input_dev. The same URB-completion window also lets raw_event() reach key_up(), key_down() and battery_flat() directly, all of which dereference appleir->input_dev.
Introduce a 'removing' flag on struct appleir, gated by the existing spinlock. appleir_remove() sets the flag under the lock and then shuts down the timer with timer_shutdown_sync(), which both drains any in-flight callback and permanently disables further mod_timer() calls. appleir_raw_event() and key_up_tick() bail out early if the flag is set, so no path can arm or run the timer, or dereference appleir->input_dev, after remove() has started tearing down.
The keyrepeat and flatbattery branches of appleir_raw_event() previously called into the input layer without holding the spinlock; take it now so the flag check is well-defined. This incidentally closes a pre-existing read-side race on appleir->current_key in the keyrepeat branch.
This bug is structurally a sibling of commit 4db2af929279 ("HID:
appletb-kbd: fix UAF in inactivity-timer cleanup path") and has been present since the driver was introduced.
--- drivers/hid/hid-appleir.c | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-)
drivers/hid/hid-appleir.c +35 -10
@@ -109,9 +109,10 @@ struct appleir {struct hid_device *hid;unsigned short keymap[ARRAY_SIZE (appleir_key_table)];struct timer_list key_up_timer;/* timer for key up */ -spinlock_t lock;/* protects .current_key */ +spinlock_t lock;/* protects .current_key, .removing */ int current_key;/* the currently pressed key */ int prev_key_idx;/* key index in a 2 packets message */ +bool removing;/* set during teardown; gates input_dev access */ };static int get_key (int data)
@@ -172,7 +173,7 @@ static void key_up_tick(struct timer_lisunsigned long flags;spin_lock_irqsave (&appleir->lock, flags); -if (appleir->current_key) { +if (!appleir->removing && appleir->current_key) {key_up (hid, appleir, appleir->current_key); appleir->current_key =0 ; }
@@ -195,6 +196,10 @@ static int appleir_raw_event(struct hid_int index;spin_lock_irqsave (&appleir->lock, flags); +if (appleir->removing) { +spin_unlock_irqrestore (&appleir->lock, flags); + goto out; + }/* * If we already have a key down, take it up before marking * this one down
@@ -229,17 +234,25 @@ static int appleir_raw_event(struct hid_ appleir->prev_key_idx =0 ;if (!memcmp (data, keyrepeat,sizeof (keyrepeat))) { -key_down (hid, appleir, appleir->current_key); -/* -* Remote doesn't do key up, either pull them up, in the test -* above, or here set a timer which pulls them up after 1/8 s -*/ -mod_timer (&appleir->key_up_timer, jiffies +HZ /8 ); +spin_lock_irqsave (&appleir->lock, flags); +if (!appleir->removing) { +key_down (hid, appleir, appleir->current_key); +/* +* Remote doesn't do key up, either pull them up, in +* the test above, or here set a timer which pulls them +* up after 1/8 s +*/ +mod_timer (&appleir->key_up_timer, jiffies +HZ /8 ); + } +spin_unlock_irqrestore (&appleir->lock, flags); goto out; }if (!memcmp (data, flatbattery,sizeof (flatbattery))) { -battery_flat (appleir); +spin_lock_irqsave (&appleir->lock, flags); +if (!appleir->removing) +battery_flat (appleir); +spin_unlock_irqrestore (&appleir->lock, flags);/* Fall through */ }
@@ -318,8 +331,20 @@ fail:static void appleir_remove (struct hid_device *hid) {struct appleir *appleir =hid_get_drvdata (hid); +unsigned long flags; + +/* +* Mark the driver as tearing down so that any concurrent raw_event +* (e.g. from a USB URB completion that hid_hw_stop() has not yet +* killed) and the key_up_timer softirq stop touching input_dev +* before hid_hw_stop() frees it via hidinput_disconnect(). +*/ +spin_lock_irqsave (&appleir->lock, flags); + appleir->removing = true; +spin_unlock_irqrestore (&appleir->lock, flags); + +timer_shutdown_sync (&appleir->key_up_timer);hid_hw_stop (hid); -timer_delete_sync (&appleir->key_up_timer); }static const struct hid_device_id appleir_devices[] = {
Greg Kroah-Hartman
maintainerPATCH 275/518 HID: lg-g15: cancel pending work on remove to fix a use-after-free
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit 7705b4140d188ce22656f6e541ae7ef834c7e11a upstream.
lg_g15_data is allocated with devm and holds a work item. The report handlers schedule that work straight from device input. lg_g15_event() and lg_g15_v2_event() do it on the backlight cycle key, and lg_g510_leds_event() does it too. The worker dereferences the lg_g15_data back through container_of.
The driver had no remove callback and never cancelled the work. So if a report scheduled the work and the keyboard was then unplugged, devres freed lg_g15_data while the work was still pending or running, and the worker touched freed memory. This is a use-after-free. It is reachable as a race on device unplug.
Add a remove callback that cancels the work before devres frees the state. g15->work is only initialized for the models that schedule it (G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so guard the cancel on g15->work.func to avoid cancelling a work that was never set up. The g15 NULL test mirrors the one already in lg_g15_raw_event().
--- drivers/hid/hid-lg-g15.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/hid/hid-lg-g15.c +16 -0
@@ -1374,11 +1374,27 @@ static const struct hid_device_id lg_g15 };MODULE_DEVICE_TABLE (hid, lg_g15_devices); +static void lg_g15_remove (struct hid_device *hdev) +{ +struct lg_g15_data *g15 =hid_get_drvdata (hdev); + +/* +* g15->work is only initialized for the models that schedule it +* (G15, G15 v2, G510). The G13 and Z-10 leave it zeroed, so only +* cancel it when it was set up. +*/ +if (g15 && g15->work.func) +cancel_work_sync (&g15->work); + +hid_hw_stop (hdev); +} +static struct hid_driver lg_g15_driver = { .name ="lg-g15" , .id_table = lg_g15_devices, .raw_event = lg_g15_raw_event, .probe = lg_g15_probe, + .remove = lg_g15_remove, };module_hid_driver (lg_g15_driver);
Greg Kroah-Hartman
maintainerPATCH 276/518 HID: sensor-hub: Add sensor_hub_input_attr_read_values() for multi-byte reads
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Pandruvada <[email protected]>
commit f784fcea450617055d2d12eec5b2f6e0e38bf878 upstream.
sensor_hub_input_attr_get_raw_value() is limited to returning a single 32-bit value, which is insufficient for sensors that report data larger than 32 bits, such as a quaternion with four s16 elements.
Add sensor_hub_input_attr_read_values() that accepts a caller-provided buffer and accumulates incoming data until the buffer is full. The two paths are distinguished in sensor_hub_raw_event() by pending.max_raw_size being non-zero, preserving backward compatibility.
--- drivers/hid/hid-sensor-hub.c | 77 +++++++++++++++++++++++++++++++++++++---- include/linux/hid-sensor-hub.h | 25 +++++++++++++ 2 files changed, 96 insertions(+), 6 deletions(-)
drivers/hid/hid-sensor-hub.c +71 -6
@@ -286,6 +286,54 @@ done_proc: }EXPORT_SYMBOL_GPL (sensor_hub_get_feature); +int sensor_hub_input_attr_read_values (struct hid_sensor_hub_device *hsdev, +u32 usage_id,u32 attr_usage_id, +u32 report_id, +enum sensor_hub_read_flags flag, +u32 buffer_size,u8 *buffer) +{ +struct sensor_hub_data *data =hid_get_drvdata (hsdev->hdev); +struct hid_report *report; +unsigned long flags; +long cycles; +int ret; + + report =sensor_hub_report (report_id, hsdev->hdev,HID_INPUT_REPORT ); +if (!report) +return -EINVAL ; + +mutex_lock (hsdev->mutex_ptr); +if (flag ==SENSOR_HUB_SYNC ) { +memset (&hsdev->pending,0 ,sizeof (hsdev->pending)); +init_completion (&hsdev->pending.ready); + hsdev->pending.usage_id = usage_id; + hsdev->pending.attr_usage_id = attr_usage_id; + hsdev->pending.max_raw_size = buffer_size; + hsdev->pending.raw_data = buffer; + +spin_lock_irqsave (&data->lock, flags); + hsdev->pending.status = true; +spin_unlock_irqrestore (&data->lock, flags); + } +mutex_lock (&data->mutex); +hid_hw_request (hsdev->hdev, report,HID_REQ_GET_REPORT ); +mutex_unlock (&data->mutex); + ret =0 ; +if (flag ==SENSOR_HUB_SYNC ) { + cycles =wait_for_completion_interruptible_timeout (&hsdev->pending.ready, +HZ *5 ); +if (cycles ==0 ) + ret = -ETIMEDOUT ; +else if (cycles <0 ) + ret = cycles; + + hsdev->pending.status = false; + } +mutex_unlock (hsdev->mutex_ptr); + +return ret; +} +EXPORT_SYMBOL_GPL (sensor_hub_input_attr_read_values); int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, u32 usage_id,
@@ -478,6 +526,8 @@ static int sensor_hub_raw_event(struct hstruct hid_collection *collection =NULL ;void *priv =NULL ;struct hid_sensor_hub_device *hsdev =NULL ; +u32 copy_size; +u32 avail;hid_dbg (hdev,"sensor_hub_raw_event report id:0x%x size:%d type:%d\n" , report->id, size, report->type);
@@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct h hsdev->pending.attr_usage_id == report->field[i]->logical)) {hid_dbg (hdev,"data was pending ...\n" ); - hsdev->pending.raw_data =kmemdup (ptr, sz,GFP_ATOMIC ); -if (hsdev->pending.raw_data) - hsdev->pending.raw_size = sz; -else - hsdev->pending.raw_size =0 ; -complete (&hsdev->pending.ready); +if (hsdev->pending.max_raw_size) { +if (hsdev->pending.index < hsdev->pending.max_raw_size) { + avail = hsdev->pending.max_raw_size - hsdev->pending.index; + copy_size =clamp (sz,0U , avail); + +memcpy (hsdev->pending.raw_data + hsdev->pending.index, + ptr, copy_size); + hsdev->pending.index += copy_size; +if (hsdev->pending.index >= hsdev->pending.max_raw_size) { + hsdev->pending.raw_size = hsdev->pending.index; +complete (&hsdev->pending.ready); + } + } + }else { + hsdev->pending.raw_data =kmemdup (ptr, sz,GFP_ATOMIC ); +if (hsdev->pending.raw_data) + hsdev->pending.raw_size = sz; +else + hsdev->pending.raw_size =0 ; +complete (&hsdev->pending.ready); + } }if (callback->capture_sample) {if (report->field[i]->logical)
include/linux/hid-sensor-hub.h +25 -0
@@ -43,6 +43,8 @@ struct hid_sensor_hub_attribute_info {* @attr_usage_id: Usage Id of a field, e.g. X-axis for a gyro. * @raw_size: Response size for a read request. * @raw_data: Place holder for received response. +* @index: Current write index into raw_data for multi-byte reads. +* @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads. */ struct sensor_hub_pending {bool status;
@@ -51,6 +53,8 @@ struct sensor_hub_pending {u32 attr_usage_id;int raw_size;u8 *raw_data; +u32 index; +u32 max_raw_size; };/**
@@ -184,6 +188,27 @@ int sensor_hub_input_attr_get_raw_value( );/** +* sensor_hub_input_attr_read_values() - Synchronous multi-byte read request +* @hsdev: Hub device instance. +* @usage_id: Attribute usage id of parent physical device as per spec +* @attr_usage_id: Attribute usage id as per spec +* @report_id: Report id to look for +* @flag: Synchronous or asynchronous read +* @buffer_size: Size of the buffer in bytes +* @buffer: Buffer to store the read data +* +* Issues a synchronous or asynchronous read request for an input attribute, +* accumulating data into the provided buffer until it is full. +* Return: 0 on success, -ETIMEDOUT if the device did not respond, or a +* negative error code. +*/ +int sensor_hub_input_attr_read_values (struct hid_sensor_hub_device *hsdev, +u32 usage_id,u32 attr_usage_id, +u32 report_id, +enum sensor_hub_read_flags flag, +u32 buffer_size,u8 *buffer); + +/** * sensor_hub_set_feature() - Feature set request * @hsdev: Hub device instance. * @report_id: Report id to look for
Greg Kroah-Hartman
maintainerPATCH 277/518 hfs/hfsplus: fix u32 overflow in check_and_correct_requested_length
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 966cb76fb2857a4242cab6ea2ea17acf818a3da7 upstream.
check_and_correct_requested_length() compares (off + len) against node_size using u32 arithmetic. When the caller passes a large len value (e.g. from an underflowed subtraction in hfs_brec_remove()), off + len can wrap past 2^32 and produce a small result, causing the bounds check to pass when it should fail.
For example, with off=14 and len=0xFFFFFFF2 (underflowed from data_off - keyoffset - size in hfs_brec_remove), off + len wraps to 6, which is less than a typical node_size of 512, so the check passes and the subsequent memmove reads ~4GB past the node buffer.
Fix this by widening the addition to u64 before comparing against node_size. This prevents the u32 wrap while keeping the logic straightforward.
--- fs/hfs/bnode.c | 2 +- fs/hfsplus/hfsplus_fs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
fs/hfs/bnode.c +1 -1
@@ -41,7 +41,7 @@ u32 check_and_correct_requested_length(s node_size = node->tree->node_size; -if ((off + len) > node_size) { +if ((u64 )off + len > node_size) {u32 new_len = node_size - off; pr_err("requested length has been corrected: "
fs/hfsplus/hfsplus_fs.h +1 -1
@@ -600,7 +600,7 @@ u32 check_and_correct_requested_length(s node_size = node->tree->node_size; -if ((off + len) > node_size) { +if ((u64 )off + len > node_size) {u32 new_len = node_size - off; pr_err("requested length has been corrected: "
Greg Kroah-Hartman
maintainerPATCH 278/518 hfs/hfsplus: zero-initialize buffer in hfs_bnode_read
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit d67aadee19ffdf3cc8520c5a4f4d5b2916d30baf upstream.
hfs_bnode_read() can return early without writing to the output buffer when is_bnode_offset_valid() fails or when check_and_correct_requested_ length() corrects the length to zero. Callers such as hfs_bnode_read_ u16() and hfs_bnode_read_u8() pass stack-allocated buffers and use the result unconditionally, leading to KMSAN uninit-value reports.
Rather than initializing at each individual call site, zero the buffer at the start of hfs_bnode_read() before any validation checks. This ensures all callers in both hfs and hfsplus get a deterministic zero value regardless of which early-return path is taken.
--- fs/hfs/bnode.c | 2 ++ fs/hfsplus/bnode.c | 2 ++ 2 files changed, 4 insertions(+)
fs/hfs/bnode.c +2 -0
@@ -64,6 +64,8 @@ void hfs_bnode_read(struct hfs_bnode *nou32 bytes_read;u32 bytes_to_read; +memset (buf,0 , len); +if (!is_bnode_offset_valid (node, off))return ;
fs/hfsplus/bnode.c +2 -0
@@ -25,6 +25,8 @@ void hfs_bnode_read(struct hfs_bnode *nostruct page **pagep;u32 l; +memset (buf,0 , len); +if (!is_bnode_offset_valid (node, off))return ;
Greg Kroah-Hartman
maintainerPATCH 279/518 nilfs2: reject CLEAN_SEGMENTS ioctl with out-of-range segment numbers
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
commit 0e7a690fe435f8d5ea3feb7c1d8d73ba7e8b8aa9 upstream.
Syzbot reported a hung task in nilfs_transaction_begin() where multiple tasks performing chmod() on a nilfs2 mount blocked for over 143 seconds waiting to acquire ns_segctor_sem for read:
INFO: task syz.0.17:5918 blocked for more than 143 seconds. Call Trace: schedule+0x164/0x360 rwsem_down_read_slowpath+0x6d9/0x940 down_read+0x99/0x2e0 nilfs_transaction_begin+0x364/0x710 fs/nilfs2/segment.c:221 nilfs_setattr+0x124/0x2c0 fs/nilfs2/inode.c:921 notify_change+0xc1a/0xf40 chmod_common+0x273/0x4a0 do_fchmodat+0x12d/0x230
The writer holding ns_segctor_sem was a concurrent NILFS_IOCTL_CLEAN_SEGMENTS caller, stuck inside printk while emitting per-element warnings from nilfs_sufile_updatev():
__nilfs_msg+0x373/0x450 fs/nilfs2/super.c:78 nilfs_sufile_updatev+0x21c/0x6d0 fs/nilfs2/sufile.c:186 nilfs_sufile_freev fs/nilfs2/sufile.h:93 [inline] nilfs_free_segments fs/nilfs2/segment.c:1140 [inline] nilfs_segctor_collect_blocks fs/nilfs2/segment.c:1261 [inline] nilfs_segctor_do_construct+0x1f55/0x76c0 nilfs_clean_segments+0x3bd/0xa50 nilfs_ioctl_clean_segments fs/nilfs2/ioctl.c:922 [inline] nilfs_ioctl+0x261f/0x2780
The root cause is that user-supplied segment numbers are not validated before nilfs_clean_segments() begins doing work; the range check on each segnum is performed deep inside the call chain by nilfs_sufile_updatev(), which emits a nilfs_warn() per invalid entry while still holding the segctor lock and the sufile mi_sem. Under load (repeated invocations across multiple mounts saturating the global printk path), the cumulative printk latency keeps ns_segctor_sem held long enough to trip the hung_task watchdog, blocking concurrent operations such as chmod() that need ns_segctor_sem for read.
Fix by validating the contents of kbufs[4] in nilfs_clean_segments() immediately after acquiring ns_segctor_sem via nilfs_transaction_lock(). Holding ns_segctor_sem serializes the check against nilfs_ioctl_resize(), which can modify ns_nsegments, so the validation uses a consistent value. Out-of-range segment numbers are rejected with -EINVAL before any segment-cleaning work begins, so the bad entries never reach the per-element diagnostic path inside nilfs_sufile_updatev().
--- fs/nilfs2/segment.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
fs/nilfs2/segment.c +22 -0
@@ -2512,12 +2512,33 @@ int nilfs_clean_segments(struct super_blstruct nilfs_sc_info *sci = nilfs->ns_writer;struct nilfs_transaction_info ti;int err; +size_t i, nfreesegs = argv[4 ].v_nmembs; +__u64 *segnumv = kbufs[4 ];if (unlikely (!sci))return -EROFS ;nilfs_transaction_lock (sb, &ti,1 ); +/* +* Validate segment numbers under ns_segctor_sem (held for write +* by nilfs_transaction_lock above) so the check is serialized +* against nilfs_ioctl_resize(), which can modify ns_nsegments. +* Rejecting bad input here, before any segment-cleaning work +* begins, avoids the per-element diagnostic path inside +* nilfs_sufile_updatev() that would otherwise run under this +* same lock and stall concurrent readers. +*/ +for (i =0 ; i < nfreesegs; i++) { +if (segnumv[i] >= nilfs->ns_nsegments) { +nilfs_err (sb, +"Segment number %llu to be freed is out of range" , + (unsigned long long )segnumv[i]); + err = -EINVAL ; + goto bail_unlock; + } + } + err =nilfs_mdt_save_to_shadow_map (nilfs->ns_dat);if (unlikely (err)) goto out_unlock;
@@ -2558,6 +2579,7 @@ int nilfs_clean_segments(struct super_bl sci->sc_freesegs =NULL ; sci->sc_nfreesegs =0 ;nilfs_mdt_clear_shadow_map (nilfs->ns_dat); + bail_unlock:nilfs_transaction_unlock (sb);return err; }
Greg Kroah-Hartman
maintainerPATCH 280/518 media: mtk-jpeg: cancel workqueue on release for supported platforms only
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Louis-Alexis Eyraud <[email protected]>
commit b1845a227fda37b2fe5327df3ca0015d7e290235 upstream.
Since a recent fix the mtk_jpeg_release function cancels any pending or running work present in the driver workqueue using cancel_work_sync function.
Currently, only the multicore based variants use this workqueue and they have the jpeg_worker platform data field initialized with a workqueue callback function. For the others, this field value remain NULL by default.
The cancel_work_sync function is unconditionally called in mtk_jpeg_release function, even for the variants that do not use the workqueue. This call generates a WARN_ON print in __flush_work because the workqueue callback function presence check fails in __flush_work function (used by cancel_work_sync).
So, to avoid these warnings, call cancel_work_sync only if a workqueue callback is defined in platform data.
--- drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +2 -1
@@ -1202,7 +1202,8 @@ static int mtk_jpeg_release(struct filestruct mtk_jpeg_dev *jpeg =video_drvdata (file);struct mtk_jpeg_ctx *ctx =mtk_jpeg_file_to_ctx (file); -cancel_work_sync (&ctx->jpeg_work); +if (jpeg->variant->jpeg_worker) +cancel_work_sync (&ctx->jpeg_work);mutex_lock (&jpeg->lock);v4l2_m2m_ctx_release (ctx->fh.m2m_ctx);v4l2_ctrl_handler_free (&ctx->ctrl_hdl);
Greg Kroah-Hartman
maintainerPATCH 281/518 serial: 8250_mid: Disable DMA for selected platforms
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
commit b1b4efea05a56c0995e4702a86d6624b4fdff32f upstream.
In accordance with Errata (specification updates)
HSUART May Stop Functioning when DMA is Active.
- Denverton document #572409, rev 3.4, DNV60
- Ice Lake Xeon D document #714070, ICXD65
- Snowridge document #731931, SNR44
For a quick fix just disable the respective callbacks during the device probe. Depending on the future development we might remove them completely.
--- drivers/tty/serial/8250/8250_mid.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/tty/serial/8250/8250_mid.c +11 -2
@@ -10,6 +10,7 @@#include <linux/module.h> #include <linux/pci.h> #include <linux/rational.h> +#include <linux/util_macros.h> #include <linux/dma/hsu.h>
@@ -368,8 +369,16 @@ static const struct mid8250_board dnv_bo .freq = 133333333, .base_baud = 115200, .bar = 1, - .setup = dnv_setup, - .exit = dnv_exit, +/* +* Errata: +* HSUART May Stop Functioning when DMA is Active. +* +* - Denverton document #572409, rev 3.4, DNV60 +* - Ice Lake Xeon D document #714070, ICXD65 +* - Snowridge document #731931, SNR44 +*/ + .setup = PTR_IF(false, dnv_setup), + .exit = PTR_IF(false, dnv_exit), };static const struct pci_device_id pci_ids[] = {
Greg Kroah-Hartman
maintainerPATCH 282/518 xfs: use null daddr for unset first bad log block
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
commit cc9af5e461ea5f6e37738f3f1e41c45a9b7f45d6 upstream.
xlog_do_recovery_pass() may return before setting first_bad. The caller must distinguish that case from an error at a valid log block, including block zero after the log wraps.
Initialize first_bad to XFS_BUF_DADDR_NULL and test it explicitly before treating the error as a torn write.
--- fs/xfs/xfs_log_recover.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/xfs/xfs_log_recover.c +3 -3
@@ -1028,7 +1028,7 @@ xlog_verify_head( {struct xlog_rec_header *tmp_rhead;char *tmp_buffer; -xfs_daddr_t first_bad; +xfs_daddr_t first_bad =XFS_BUF_DADDR_NULL ;xfs_daddr_t tmp_rhead_blk;int found;int error;
@@ -1057,7 +1057,8 @@ xlog_verify_head(*/ error =xlog_do_recovery_pass (log, *head_blk, tmp_rhead_blk,XLOG_RECOVER_CRCPASS , &first_bad); -if ((error == -EFSBADCRC || error == -EFSCORRUPTED ) && first_bad) { +if ((error == -EFSBADCRC || error == -EFSCORRUPTED ) && + first_bad !=XFS_BUF_DADDR_NULL ) {/* * We've hit a potential torn write. Reset the error and warn * about it.
@@ -3575,4 +3576,3 @@ xlog_recover_cancel(if (xlog_recovery_needed (log))xlog_recover_cancel_intents (log); } -
Greg Kroah-Hartman
maintainerPATCH 283/518 xfs: release dquot buffer after dqflush failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yingjie Gao <[email protected]>
commit 0c1b3a823a22af623d55f225fe2ac7e8b9052821 upstream.
xfs_qm_dqpurge() gets a locked buffer from xfs_dquot_use_attached_buf(). If xfs_qm_dqflush() fails, the error path skips xfs_buf_relse() and then calls xfs_dquot_detach_buf(), which tries to lock the same buffer again.
Release the buffer after xfs_qm_dqflush() returns so the error path drops the caller hold and unlocks the buffer before the dquot is detached, matching the other dqflush callers.
--- fs/xfs/xfs_qm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/xfs/xfs_qm.c +2 -3
@@ -166,10 +166,9 @@ xfs_qm_dqpurge(* does it on success. */ error =xfs_qm_dqflush (dqp, bp); -if (!error) { +if (!error) error =xfs_bwrite (bp); -xfs_buf_relse (bp); - } +xfs_buf_relse (bp);xfs_dqflock (dqp); }xfs_dquot_detach_buf (dqp);
Greg Kroah-Hartman
maintainerPATCH 284/518 xfs: pass back updated nb from xfs_growfs_compute_deltas
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
commit 4cb6e89a3d901d4da515977e55f9a9a779238660 upstream.
xfs_growfs_compute_deltas can update nb for corner cases like a number of blocks that would create a less the minimal sized AG, or running past the max AG limit. Pass back the calculated value to the caller, as it relies on to calculate the new number of perag structures.
Note that the grown file system size is not affected by this miscalculation as it uses the passed back delta value.
--- fs/xfs/libxfs/xfs_ag.c | 10 +++++----- fs/xfs/libxfs/xfs_ag.h | 2 +- fs/xfs/xfs_fsops.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-)
fs/xfs/libxfs/xfs_ag.c +5 -5
@@ -866,7 +866,7 @@ xfs_ag_shrink_space(void xfs_growfs_compute_deltas (struct xfs_mount *mp, -xfs_rfsblock_t nb, +xfs_rfsblock_t *nb,int64_t *deltap,xfs_agnumber_t *nagcountp) {
@@ -874,19 +874,19 @@ xfs_growfs_compute_deltas(int64_t delta;xfs_agnumber_t nagcount; - nb_div = nb; + nb_div = *nb; nb_mod =do_div (nb_div, mp->m_sb.sb_agblocks);if (nb_mod && nb_mod >=XFS_MIN_AG_BLOCKS ) nb_div++;else if (nb_mod) - nb = nb_div * mp->m_sb.sb_agblocks; + *nb = nb_div * mp->m_sb.sb_agblocks;if (nb_div >XFS_MAX_AGNUMBER +1 ) { nb_div =XFS_MAX_AGNUMBER +1 ; - nb = nb_div * mp->m_sb.sb_agblocks; + *nb = nb_div * mp->m_sb.sb_agblocks; } nagcount = nb_div; - delta = nb - mp->m_sb.sb_dblocks; + delta = *nb - mp->m_sb.sb_dblocks; *deltap = delta; *nagcountp = nagcount; }
fs/xfs/libxfs/xfs_ag.h +1 -1
@@ -330,7 +330,7 @@ int xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id);int xfs_ag_shrink_space (struct xfs_perag *pag,struct xfs_trans **tpp,xfs_extlen_t delta);void -xfs_growfs_compute_deltas (struct xfs_mount *mp,xfs_rfsblock_t nb, +xfs_growfs_compute_deltas (struct xfs_mount *mp,xfs_rfsblock_t *nb,int64_t *deltap,xfs_agnumber_t *nagcountp);int xfs_ag_extend_space (struct xfs_perag *pag,struct xfs_trans *tp,xfs_extlen_t len);
fs/xfs/xfs_fsops.c +1 -1
@@ -124,7 +124,7 @@ xfs_growfs_data_private( mp->m_sb.sb_rextsize);if (error)return error; -xfs_growfs_compute_deltas (mp, nb, &delta, &nagcount); +xfs_growfs_compute_deltas (mp, &nb, &delta, &nagcount);/* * Reject filesystems with a single AG because they are not
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 285/518 xfs: only log freed extents for the current RTG in zoned growfs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
commit 44cccefe65749821d9a13523c8b763bf1262ef73 upstream.
Otherwise a power fail or crash during growfs could lead to an elevated sb_rblocks counter.
Note that the step function is much simpler compared to the classic RT allocator as zoned RT sections must be aligned to real time group boundaries.
--- fs/xfs/xfs_rtalloc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
fs/xfs/xfs_rtalloc.c +4 -4
@@ -890,8 +890,7 @@ xfs_growfs_rt_sb_fields(static int xfs_growfs_rt_zoned ( -struct xfs_rtgroup *rtg, -xfs_rfsblock_t nrblocks) +struct xfs_rtgroup *rtg) {struct xfs_mount *mp =rtg_mount (rtg);struct xfs_mount *nmp;
@@ -903,7 +902,8 @@ xfs_growfs_rt_zoned(* Calculate new sb and mount fields for this round. Also ensure the * rtg_extents value is uptodate as the rtbitmap code relies on it. */ - nmp =xfs_growfs_rt_alloc_fake_mount (mp, nrblocks, + nmp =xfs_growfs_rt_alloc_fake_mount (mp, +xfs_rtgs_to_rfsbs (mp,rtg_rgno (rtg) +1 ), mp->m_sb.sb_rextsize);if (!nmp)return -ENOMEM ;
@@ -1218,7 +1218,7 @@ xfs_growfs_rtg( }if (xfs_has_zoned (mp)) { - error =xfs_growfs_rt_zoned (rtg, nrblocks); + error =xfs_growfs_rt_zoned (rtg); goto out_rele; }
Greg Kroah-Hartman
maintainerPATCH 286/518 xfs: initialize iomap->flags earlier in xfs_bmbt_to_iomap
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <[email protected]>
commit 327e58826eb72f8bae9419cf1a4e722b57c85694 upstream.
Otherwise we lose the IOMAP_IOEND_BOUNDARY assingment for writes to the first block in a realtime group, and could cause incorrect merges for such writes.
--- fs/xfs/xfs_iomap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_iomap.c +1 -1
@@ -113,6 +113,7 @@ xfs_bmbt_to_iomap(return xfs_alert_fsblock_zero (ip, imap); } + iomap->flags = iomap_flags;if (imap->br_startblock ==HOLESTARTBLOCK ) { iomap->addr =IOMAP_NULL_ADDR ; iomap->type =IOMAP_HOLE ;
@@ -143,7 +144,6 @@ xfs_bmbt_to_iomap( } iomap->offset =XFS_FSB_TO_B (mp, imap->br_startoff); iomap->length =XFS_FSB_TO_B (mp, imap->br_blockcount); - iomap->flags = iomap_flags;if (mapping_flags &IOMAP_DAX ) { iomap->dax_dev = target->bt_daxdev; }else {
Greg Kroah-Hartman
maintainerPATCH 287/518 xfs: fix unreachable BIGTIME check in dquot flush validation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Nepomnyashih <[email protected]>
commit 03866d130ed33ab68cc7faaf4bf2c4abef96d42e upstream.
The dqp->q_id == 0 check inside the XFS_DQTYPE_BIGTIME block is unreachable because root dquots return successfully earlier. Reject root dquots with XFS_DQTYPE_BIGTIME before that early return, preserving the intended validation and removing the unreachable condition.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- fs/xfs/xfs_dquot.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
fs/xfs/xfs_dquot.c +8 -8
@@ -1216,6 +1216,14 @@ xfs_qm_dqflush_check( type != XFS_DQTYPE_PROJ)return __this_address; +/* bigtime flag should never be set on root dquots */ +if (dqp->q_type &XFS_DQTYPE_BIGTIME ) { +if (!xfs_has_bigtime (dqp->q_mount)) +return __this_address; +if (dqp->q_id ==0 ) +return __this_address; + } +if (dqp->q_id ==0 )return NULL ;
@@ -1231,14 +1239,6 @@ xfs_qm_dqflush_check( !dqp->q_rtb.timer)return __this_address; -/* bigtime flag should never be set on root dquots */ -if (dqp->q_type &XFS_DQTYPE_BIGTIME ) { -if (!xfs_has_bigtime (dqp->q_mount)) -return __this_address; -if (dqp->q_id ==0 ) -return __this_address; - } -return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 288/518 xfs: fix pointer arithmetic error on 32-bit systems
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Darrick J. Wong <[email protected]>
commit 84eec3f7fc73144d1a230c9e8ad92721e37dcaab upstream.
The translation of the old XFS_BMBT_KEY_ADDR macro into a static function is not correct on 32-bit systems because the sizeof() argument went from being a xfs_bmbt_key_t (i.e. a struct) to a (struct xfs_bmbt_key *) (i.e. a pointer to the same struct). On 64-bit systems this turns out ok because they are the same size, but on 32-bit systems this is catastrophic because they are not the same size. So far there have been no complaints, most likely because the xfs developers urge against running it on 32-bit systems. But this needs fixing asap.
--- fs/xfs/libxfs/xfs_bmap_btree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/libxfs/xfs_bmap_btree.h +1 -1
@@ -89,7 +89,7 @@ xfs_bmbt_key_addr( {return (struct xfs_bmbt_key *) ((char *)block +xfs_bmbt_block_len (mp) + - (index -1 ) *sizeof (struct xfs_bmbt_key *)); + (index -1 ) *sizeof (struct xfs_bmbt_key )); } static inline xfs_bmbt_ptr_t *
Greg Kroah-Hartman
maintainerPATCH 289/518 xfs: fix exchmaps reservation limit check
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yingjie Gao <[email protected]>
commit 0a5213bbff62b51c7d4999ac8c7e11ea57d00d45 upstream.
xfs_exchmaps_estimate_overhead() adds the bmbt and rmapbt overhead to a local resblks variable, but the final UINT_MAX check still tests req->resblks. That is the reservation value from before the overhead was added.
The computed value is stored back in req->resblks and later passed to xfs_trans_alloc(), whose block reservation argument is unsigned int. Check the computed reservation so the existing limit applies to the value that will be used.
--- fs/xfs/libxfs/xfs_exchmaps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/libxfs/xfs_exchmaps.c +1 -1
@@ -711,7 +711,7 @@ xfs_exchmaps_estimate_overhead(return -ENOSPC ;/* Can't actually reserve more than UINT_MAX blocks. */ -if (req->resblks >UINT_MAX ) +if (resblks >UINT_MAX )return -ENOSPC ; req->resblks = resblks;
Greg Kroah-Hartman
maintainerPATCH 290/518 xfs: fix memory leak in xfs_dqinode_metadir_create()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit 45de375b25060edf46e20abb36521ba530336ceb upstream.
If xfs_metadir_create() fails in xfs_dqinode_metadir_create(), the current code returns directly, leaking the allocated update and transaction state. If the subsequent commit fails, the caller-owned inode reference is left behind.
Fix this memory leak by routing the create failure path through xfs_metadir_cancel(). For both create and commit failures, finish and release any inode returned to the caller, mirroring the unwind pattern in xfs_metadir_mkdir().
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. Runtime validation used kprobe fault injection during mount -o uquota on a metadir XFS image. Injecting xfs_metadir_create() reproduced the old active-update path that left mount stuck later in mount setup; after this change, the same injection reported cancel_hits=1 and irele_hits=1. Injecting xfs_metadir_commit() exercised the old inode-reference leak path; after this change, it reported irele_hits=1.
--- fs/xfs/libxfs/xfs_dquot_buf.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_dquot_buf.c +12 -2
@@ -436,17 +436,27 @@ xfs_dqinode_metadir_create( error =xfs_metadir_create (&upd,S_IFREG );if (error) -return error; + goto out_cancel;xfs_trans_log_inode (upd.tp, upd.ip,XFS_ILOG_CORE ); error =xfs_metadir_commit (&upd);if (error) -return error; + goto out_irele;xfs_finish_inode_setup (upd.ip); *ipp = upd.ip;return 0 ; + +out_cancel: +xfs_metadir_cancel (&upd, error); +out_irele: +/* Have to finish setting up the inode to ensure it's deleted. */ +if (upd.ip) { +xfs_finish_inode_setup (upd.ip); +xfs_irele (upd.ip); + } +return error; }#ifndef __KERNEL__
Greg Kroah-Hartman
maintainerPATCH 291/518 bpf: Reject fragmented frames in devmap
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhao Zhang <[email protected]>
commit aa496720618f1a6054f1c870bf10b4f6c99bf656 upstream.
Devmap broadcast redirects clone the packet for all but the last destination.
For native XDP, that clone path copies only the linear xdp_frame data, while fragmented frames keep skb_shared_info in tailroom outside the linear area. Cloning such a frame leaves XDP_FLAGS_HAS_FRAGS set but without valid frag metadata, and the later free path can interpret uninitialized tail data as skb_shared_info, leading to an out-of-bounds access during frame return.
Reject fragmented native XDP frames in dev_map_enqueue_clone().
Add the same restriction to the generic XDP clone path in dev_map_redirect_clone(). Generic XDP represents fragmented packets as nonlinear skbs, and rejecting them here keeps clone-based broadcast support aligned between native and generic XDP.
--- kernel/bpf/devmap.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/bpf/devmap.c +7 -0
@@ -581,6 +581,10 @@ static int dev_map_enqueue_clone(struct {struct xdp_frame *nxdpf; +/* Frags live outside the linear frame and cannot be cloned safely. */ +if (unlikely (xdp_frame_has_frags (xdpf))) +return -EOPNOTSUPP ; + nxdpf =xdpf_clone (xdpf);if (!nxdpf)return -ENOMEM ;
@@ -726,6 +730,9 @@ static int dev_map_redirect_clone(structstruct sk_buff *nskb;int err; +if (unlikely (skb_is_nonlinear (skb))) +return -EOPNOTSUPP ; + nskb =skb_clone (skb,GFP_ATOMIC );if (!nskb)return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 292/518 bpf: Restore sysctl new-value from 1 to 0
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit 2566c3b24219c5b30e35205cba029ff34ff7c78b upstream.
Commit 4e63acdff864 ("bpf: Introduce bpf_sysctl_{get,set}_new_value helpers") changed the success return value to 0, but failed to update the corresponding check in __cgroup_bpf_run_filter_sysctl(). Since bpf_prog_run_array_cg() now returns 0 on success, the legacy ret == 1 condition is never satisfied. As a result, the modified value is ignored, and bpf_sysctl_set_new_value() fails to replace the write buffer.
Fix this by checking for a return value of 0 instead, so cgroup/sysctl programs can correctly replace the pending sysctl buffer.
This bug was discovered during a manual code review. Tested via a cgroup/sysctl BPF reproducer overriding writes to a target sysctl. Pre-fix, bpf_sysctl_set_new_value("foo") was silently ignored: the write returned 8192 and the value remained "600". Post-fix, the BPF replacement buffer properly propagates: the write returns 3 and the value updates to "foo".
--- kernel/bpf/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/cgroup.c +1 -1
@@ -1935,7 +1935,7 @@ int __cgroup_bpf_run_filter_sysctl(struckfree (ctx.cur_val); -if (ret ==1 && ctx.new_updated) { +if (!ret && ctx.new_updated) {kvfree (*buf); *buf = ctx.new_val; *pcount = ctx.new_len;
Greg Kroah-Hartman
maintainerPATCH 293/518 bpf: Validate BTF repeated field counts before expansion
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Moses <[email protected]>
commit b9452b594fd3aecbfd4aa0a6a1f741330a37dab7 upstream.
btf_parse_struct_metas() walks user-supplied BTF during BPF_BTF_LOAD, and btf_repeat_fields() expands repeatable fields from array elements into the fixed BTF_FIELDS_MAX scratch array used by btf_parse_fields().
The remaining-capacity check performs the expanded field count calculation in u32. A malformed BTF can wrap that calculation, causing the check to pass even when the expanded field count exceeds the scratch array capacity. The following memcpy() can then write past the end of the array.
Use checked addition and multiplication before copying repeated fields and reject impossible counts.
--- kernel/bpf/btf.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
kernel/bpf/btf.c +4 -5
@@ -3668,7 +3668,7 @@ end:static int btf_repeat_fields (struct btf_field_info *info,int info_cnt,u32 field_cnt,u32 repeat_cnt,u32 elem_size) { -u32 i, j; +u32 i, j, total_cnt, total_repeats;u32 cur;/* Ensure not repeating fields that should not be repeated. */
@@ -3686,10 +3686,9 @@ static int btf_repeat_fields(struct btf_ } } -/* The type of struct size or variable size is u32, -* so the multiplication will not overflow. -*/ -if (field_cnt * (repeat_cnt +1 ) > info_cnt) +if (check_add_overflow (repeat_cnt,1 , &total_repeats) || +check_mul_overflow (field_cnt, total_repeats, &total_cnt) || + total_cnt > (u32 )info_cnt)return -E2BIG ; cur = field_cnt;
Greg Kroah-Hartman
maintainerPATCH 294/518 bpf: Keep dynamic inner array lookups nullable
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuoqi Gui <[email protected]>
commit 53040a81ae57cdca8af8ac36fe4e661730cf7c6b upstream.
An ARRAY_OF_MAPS can use an array created with BPF_F_INNER_MAP as its inner map template. A concrete inner array with a different max_entries value can then replace the template.
After a successful outer map lookup, the verifier represents the resulting map pointer using the inner map template. Const-key lookup nullness elision consequently uses the template max_entries even though the runtime helper uses the concrete inner map max_entries.
Do not elide lookup result nullness for maps marked with BPF_F_INNER_MAP, because the template max_entries does not prove that the key is in bounds for the concrete runtime map.
--- kernel/bpf/verifier.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
kernel/bpf/verifier.c +9 -6
@@ -8471,7 +8471,7 @@ static int get_constant_map_key(struct breturn 0 ; } -static bool can_elide_value_nullness (enum bpf_map_type type); +static bool can_elide_value_nullness (const struct bpf_map *map); static int check_func_arg(struct bpf_verifier_env *env, u32 arg, struct bpf_call_arg_meta *meta,
@@ -8621,7 +8621,7 @@ skip_type_check: err =check_helper_mem_access (env, regno, key_size,BPF_READ , false,NULL );if (err)return err; -if (can_elide_value_nullness (meta->map.ptr->map_type)) { +if (can_elide_value_nullness (meta->map.ptr)) { err =get_constant_map_key (env, reg, key_size, &meta->const_map_key);if (err <0 ) { meta->const_map_key =-1 ;
@@ -10221,13 +10221,16 @@ static void update_loop_inline_state(str state->callback_subprogno == subprogno); } -/* Returns whether or not the given map type can potentially elide +/* Returns whether or not the given map can potentially elide * lookup return value nullness check. This is possible if the key * is statically known. */ -static bool can_elide_value_nullness (enum bpf_map_type type) +static bool can_elide_value_nullness (const struct bpf_map *map) { -switch (type) { +if (map->map_flags &BPF_F_INNER_MAP ) +return false; + +switch (map->map_type) {case BPF_MAP_TYPE_ARRAY :case BPF_MAP_TYPE_PERCPU_ARRAY :return true;
@@ -10589,7 +10592,7 @@ static int check_helper_call(struct bpf_ }if (func_id == BPF_FUNC_map_lookup_elem && -can_elide_value_nullness (meta.map.ptr->map_type) && +can_elide_value_nullness (meta.map.ptr) && meta.const_map_key >=0 && meta.const_map_key < meta.map.ptr->max_entries) ret_flag &= ~PTR_MAYBE_NULL ;
Greg Kroah-Hartman
maintainerPATCH 295/518 bpf: Allow LPM map access from sleepable BPF programs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vlad Poenaru <[email protected]>
commit 2f884d371fafea137afea504d49ee4a7c8d7985b upstream.
trie_lookup_elem() annotates its rcu_dereference_check() walks with only rcu_read_lock_bh_held(). Because rcu_dereference_check(p, c) resolves to "c || rcu_read_lock_held()", this passes for XDP/NAPI and classic RCU readers but fails for sleepable BPF programs, which enter via __bpf_prog_enter_sleepable() and hold only rcu_read_lock_trace().
trie_update_elem() and trie_delete_elem() have the same problem in a different form: they walk the trie with plain rcu_dereference(), which asserts rcu_read_lock_held() unconditionally. Both are reachable from sleepable BPF programs via the bpf_map_update_elem / bpf_map_delete_elem helpers, and from the syscall path under classic rcu_read_lock(). In the writer paths the trie is actually protected by trie->lock (an rqspinlock taken across the walk); we never relied on the RCU read-side lock to keep nodes alive there.
A sleepable LSM hook that ends up touching an LPM trie therefore triggers lockdep on debug kernels:
=============================
WARNING: suspicious RCU usage
7.1.0-... Tainted: G E
-----------------------------
kernel/bpf/lpm_trie.c:249 suspicious rcu_dereference_check() usage! 1 lock held by net_tests/540:
#0: (rcu_tasks_trace_srcu_struct){....}-{0:0},
at: __bpf_prog_enter_sleepable+0x26/0x280 Call Trace: dump_stack_lvl lockdep_rcu_suspicious trie_lookup_elem bpf_prog_..._enforce_security_socket_connect bpf_trampoline_... security_socket_connect __sys_connect do_syscall_64
This is lockdep-only -- no UAF, since Tasks Trace RCU does serialize against the trie's reclaim path -- but it spams the console once per distinct callsite on every debug kernel running a sleepable BPF LSM that touches an LPM trie, which is increasingly common.
For the lookup path, switch the rcu_dereference_check() annotation from rcu_read_lock_bh_held() to bpf_rcu_lock_held(), which accepts all three contexts (classic, BH, Tasks Trace). Other map types already follow this convention.
For trie_update_elem() and trie_delete_elem(), annotate the walks as rcu_dereference_protected(*p, 1) -- matching trie_free() in the same file -- since trie->lock is held across the walk. rqspinlock has no lockdep_map, so the predicate degenerates to '1' rather than lockdep_is_held(&trie->lock); the protection is real but not machine-verifiable. trie_get_next_key() also uses bare rcu_dereference() but is reachable only from the BPF syscall, which holds classic rcu_read_lock() before dispatching, so it is left untouched.
--- kernel/bpf/lpm_trie.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/bpf/lpm_trie.c +4 -4
@@ -246,7 +246,7 @@ static void *trie_lookup_elem(struct bpf/* Start walking the trie from the root node ... */ -for (node =rcu_dereference_check (trie->root,rcu_read_lock_bh_held ()); +for (node =rcu_dereference_check (trie->root,bpf_rcu_lock_held ()); node;) {unsigned int next_bit;size_t matchlen;
@@ -280,7 +280,7 @@ static void *trie_lookup_elem(struct bpf*/ next_bit =extract_bit (key->data, node->prefixlen); node =rcu_dereference_check (node->child[next_bit], -rcu_read_lock_bh_held ()); +bpf_rcu_lock_held ()); }if (!found)
@@ -359,7 +359,7 @@ static long trie_update_elem(struct bpf_*/ slot = &trie->root; -while ((node =rcu_dereference (*slot))) { +while ((node =rcu_dereference_protected (*slot,1 ))) { matchlen =longest_prefix_match (trie, node, key); if (node->prefixlen != matchlen ||
@@ -482,7 +482,7 @@ static long trie_delete_elem(struct bpf_ trim = &trie->root; trim2 = trim; parent =NULL ; -while ((node =rcu_dereference (*trim))) { +while ((node =rcu_dereference_protected (*trim,1 ))) { matchlen =longest_prefix_match (trie, node, key); if (node->prefixlen != matchlen ||
Greg Kroah-Hartman
maintainerPATCH 296/518 net: usb: kalmia: bound RX frame length in kalmia_rx_fixup()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit 47b6bcef6e679593d2e86e04ee72c46a4e2f7139 upstream.
kalmia_rx_fixup() computes usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH) as a u16, guarded only by a pre-loop check that skb->len is at least KALMIA_HEADER_LENGTH, which is 6. A device can deliver a short bulk-IN frame with skb->len in the 6 to 11 range, or leave a short trailing remainder on a later loop iteration. Either case underflows usb_packet_length to about 65530.
That bypasses the usb_packet_length < ether_packet_length truncation path. The device-supplied ether_packet_length, a le16 up to 65535 read from header_start[2], then drives a memcmp() and the following skb_trim() and skb_pull() past the end of the rx buffer. The rx buffer is hard_mtu * 10, which is 14000 bytes. That is an out of bounds read.
Require both the start and end framing headers to be present before subtracting them, on every loop iteration.
--- drivers/net/usb/kalmia.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/usb/kalmia.c +8 -0
@@ -276,6 +276,14 @@ kalmia_rx_fixup(struct usbnet *dev, stru"Received header: %6phC. Package length: %i\n" , header_start, skb->len - KALMIA_HEADER_LENGTH); +/* both framing headers must be present before we subtract +* them, otherwise usb_packet_length underflows and the +* device-supplied ether_packet_length drives an out of bounds +* access below +*/ +if (skb->len <2 *KALMIA_HEADER_LENGTH ) +return 0 ; +/* subtract start header and end header */ usb_packet_length = skb->len - (2 *KALMIA_HEADER_LENGTH ); ether_packet_length =get_unaligned_le16 (&header_start[2 ]);
Greg Kroah-Hartman
maintainerPATCH 297/518 Revert "usb: typec: mux: avoid duplicated mux switches"
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jens Glathe <[email protected]>
commit f576c75f95a52c71b30167d7efb6d47148f9c279 upstream.
This reverts commit b145c3f29d62f71cc9d2d714e2d4ae4c8d3f863d.
The deduplication logic appears to cause issues with separate SBU muxes. The mode-switch call on these (like gpio-sbu-mux) never appeared, so no successful mode-switch happened. The more high-end Parade PS883X redrivers are not affected due to being retimer-switch. The revert fixes dp altmode mode-switch for both.
Tested on:
Lenovo Thinkbook 16 G7 QOY
Lenovo Ideapad 5 2in1 14Q8X9
Microsoft Windows Dev Kit 2023 (Blackrock)
Lenovo Thinkpad T14s G6
--- drivers/usb/typec/mux.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/usb/typec/mux.c +1 -12
@@ -275,9 +275,7 @@ static int mux_fwnode_match(struct device *dev, const void *fwnode)static void *typec_mux_match (const struct fwnode_handle *fwnode,const char *id,void *data) { -struct typec_mux_dev **mux_devs = data;struct device *dev; -int i;/* * Device graph (OF graph) does not give any means to identify the
@@ -293,14 +291,6 @@ static void *typec_mux_match(const struct fwnode_handle *fwnode, dev =class_find_device (&typec_mux_class,NULL , fwnode, mux_fwnode_match); -/* Skip duplicates */ -for (i =0 ; i <TYPEC_MUX_MAX_DEVS ; i++) -if (to_typec_mux_dev (dev) == mux_devs[i]) { -put_device (dev); -return NULL ; - } - -return dev ?to_typec_mux_dev (dev) :ERR_PTR (-EPROBE_DEFER ); }
@@ -326,8 +316,7 @@ struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode)return ERR_PTR (-ENOMEM ); count =fwnode_connection_find_matches (fwnode,"mode-switch" , - (void **)mux_devs, - typec_mux_match, +NULL , typec_mux_match, (void **)mux_devs,ARRAY_SIZE (mux_devs));if (count <=0 ) {
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 298/518 usb: cdc_acm: Add quirk for Uniden BC125AT scanner
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jared Baldridge <[email protected]>
commit 6eba58568f6cc3ff8515a00b05e258d8cfb72b72 upstream.
Uniden BC125AT radio scanner has a USB interface which fails to work with the cdc_acm driver:
usb 1-1: new full-speed USB device number 2 using uhci_hcd cdc_acm 1-1:1.0: Zero length descriptor references cdc_acm 1-1:1.0: probe with driver cdc_acm failed with error -22
usbcore: registered new interface driver cdc_acm
Adding the NO_UNION_NORMAL quirk for the device fixes the issue:
usb 1-1: new full-speed USB device number 2 using uhci_hcd cdc_acm 1-1:1.0: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
lsusb -v of the device:
Bus 001 Device 002: ID 1965:0017 Uniden Corporation BC125AT Negotiated speed: Full Speed (12Mbps)
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications bDeviceSubClass 0 [unknown] bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x1965 Uniden Corporation idProduct 0x0017 BC125AT bcdDevice 0.01 iManufacturer 1 Uniden America Corp. iProduct 2 BC125AT iSerial 3 0001 bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0030
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x87 EP 7 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 10
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0 [unknown]
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Status: 0x0000
(Bus Powered)
--- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/class/cdc-acm.c +3 -0
@@ -1810,6 +1810,9 @@ static const struct usb_device_id acm_id { USB_DEVICE(0x1901, 0x0006), /* GE Healthcare Patient Monitor UI Controller */ .driver_info =DISABLE_ECHO ,/* DISABLE ECHO in termios flag */ }, + { USB_DEVICE(0x1965, 0x0017), /* Uniden BC125AT */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ },
Greg Kroah-Hartman
maintainerPATCH 299/518 usb: cdnsp: fix stream context array leak in cdnsp_alloc_stream_info()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 3348f444a4ce43dd5c2d1aa41634cb6eff33aa64 upstream.
cdnsp_alloc_stream_info() allocates stream_info->stream_ctx_array with cdnsp_alloc_stream_ctx(). If a later stream ring allocation or stream mapping update fails, the error path frees the allocated stream rings and stream_rings array, but leaves stream_ctx_array allocated.
Free the stream context array before falling through to the stream_rings cleanup path.
--- drivers/usb/cdns3/cdnsp-mem.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/cdns3/cdnsp-mem.c +2 -0
@@ -631,6 +631,8 @@ cleanup_rings: } } +cdnsp_free_stream_ctx (pdev, pep); + cleanup_stream_rings:kfree (pep->stream_info.stream_rings);
Greg Kroah-Hartman
maintainerPATCH 300/518 USB: core: add USB_QUIRK_NO_LPM for VIA Labs USB 2.0 hub
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rodrigo Lugathe da Conceição Alves <[email protected]>
commit bd728c3d9b1cc0bb0fda6a7055c5c8b55d7477b2 upstream.
The VIA Labs, Inc. USB 2.0 hub controller (2109:2817), found in a KVM switch, fails to enumerate high-power devices during cold boot and system restart.
Applying the kernel parameter
usbcore.quirks=2109:2817:k
resolves the issue.
Enumeration failure log:
usb 1-1.2.3: device descriptor read/64, error -32 usb 1-1.2.3: Device not responding to setup address. usb 1-1.2.3: device not accepting address 11, error -71 usb 1-1.2-port3: unable to enumerate USB device
Add USB_QUIRK_NO_LPM for this device.
--- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/core/quirks.c +3 -0
@@ -576,6 +576,9 @@ static const struct usb_device_id usb_qu/* VLI disk */ { USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM }, + /* VIA Labs, Inc. USB2.0 Hub */ + { USB_DEVICE(0x2109, 0x2817), .driver_info = USB_QUIRK_NO_LPM }, + /* Raydium Touchscreen */ { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM },
Greg Kroah-Hartman
maintainerPATCH 301/518 usb: dwc3: fix dwc3_readl() and dwc3_writel() calls in dwc3_ulpi_setup()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ben Dooks <[email protected]>
commit e0f844d9d74200d311c6438a0f04270834ba5365 upstream.
The dwc3_ulpi_setup() calls the register read and write calls with dwc3->regs when both these calls take the dwc3 structure directly.
Chnage these two calls to fix the following sparse warning, and possibly a nasty bug in the dwc3_ulpi_setup() code:
drivers/usb/dwc3/core.c:796:45: warning: incorrect type in argument 1 (different address spaces)drivers/usb/dwc3/core.c:796:45: expected struct dwc3 *dwcdrivers/usb/dwc3/core.c:796:45: got void [noderef] __iomem *regsdrivers/usb/dwc3/core.c:798:40: warning: incorrect type in argument 1 (different address spaces)drivers/usb/dwc3/core.c:798:40: expected struct dwc3 *dwcdrivers/usb/dwc3/core.c:798:40: got void [noderef] __iomem *regs
--- drivers/usb/dwc3/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/dwc3/core.c +2 -2
@@ -793,9 +793,9 @@ static void dwc3_ulpi_setup(struct dwc3if (dwc->enable_usb2_transceiver_delay) {for (index =0 ; index < dwc->num_usb2_ports; index++) { - reg =dwc3_readl (dwc->regs,DWC3_GUSB2PHYCFG (index)); + reg =dwc3_readl (dwc,DWC3_GUSB2PHYCFG (index)); reg |=DWC3_GUSB2PHYCFG_XCVRDLY ; -dwc3_writel (dwc->regs,DWC3_GUSB2PHYCFG (index), reg); +dwc3_writel (dwc,DWC3_GUSB2PHYCFG (index), reg); } } }
Greg Kroah-Hartman
maintainerPATCH 302/518 usb: dwc3: meson-g12a: fix refcount leak in dwc3_meson_g12a_resume()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit 692c354bef03b77b30e57e61934da502c8a12d45 upstream.
If dwc3_meson_g12a_resume() succeeds in calling reset_control_reset(), an internal triggered_count reference is acquired. If any later step fails (usb_init, phy_init, phy_power_on, regulator_enable, or usb_post_init), the function returns the error without rearming the reset control. This leaks the reference and leaves the reset control in a triggered state, causing future reset_control_reset() calls to incorrectly return early as if already reset.
Add an error path that calls reset_control_rearm() to balance the reference before returning the error.
--- drivers/usb/dwc3/dwc3-meson-g12a.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
drivers/usb/dwc3/dwc3-meson-g12a.c +9 -5
@@ -907,35 +907,39 @@ static int __maybe_unused dwc3_meson_g12 ret = priv->drvdata->usb_init (priv);if (ret) -return ret; + goto err_rearm;/* Init PHYs */ for (i =0 ; i <PHY_COUNT ; ++i) { ret =phy_init (priv->phys[i]);if (ret) -return ret; + goto err_rearm; }/* Set PHY Power */ for (i =0 ; i <PHY_COUNT ; ++i) { ret =phy_power_on (priv->phys[i]);if (ret) -return ret; + goto err_rearm; }if (priv->vbus && priv->otg_phy_mode ==PHY_MODE_USB_HOST ) { ret =regulator_enable (priv->vbus);if (ret) -return ret; + goto err_rearm; }if (priv->drvdata->usb_post_init) { ret = priv->drvdata->usb_post_init (priv);if (ret) -return ret; + goto err_rearm; }return 0 ; + +err_rearm: +reset_control_rearm (priv->reset); +return ret; }static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
Greg Kroah-Hartman
maintainerPATCH 303/518 usb: free iso schedules on failed submit
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawei Feng <[email protected]>
commit b9399d25fbb34a05bbe76eeedd730f62ff2670e9 upstream.
EHCI and FOTG210 isochronous submits build an ehci_iso_sched before linking the URB to the endpoint queue, and keep the staged schedule in urb->hcpriv until iso_stream_schedule() and the link helpers consume it. If the controller is no longer accessible, or usb_hcd_link_urb_to_ep() fails, submit jumps to done_not_linked before that handoff happens and leaks the staged schedule still attached to urb->hcpriv.
Free the staged schedule from done_not_linked when submit fails before the URB is linked and clear urb->hcpriv after the free.
The bug was first flagged by an experimental analysis tool we are developing for kernel memory-management bugs while analyzing v6.13-rc1. The tool is still under development and is not yet publicly available. Manual inspection confirms that the bug is still present in v7.1.1.
An x86_64 allyesconfig build showed no new warnings. As we do not have an EHCI host controller with a USB isochronous device to test with, no runtime testing was able to be performed.
--- drivers/usb/fotg210/fotg210-hcd.c | 6 ++++-- drivers/usb/host/ehci-sched.c | 11 +++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-)
drivers/usb/fotg210/fotg210-hcd.c +4 -2
@@ -4267,8 +4267,6 @@ static int iso_stream_schedule(struct foreturn 0 ; fail: -iso_sched_free (stream, sched); - urb->hcpriv =NULL ;return status; }
@@ -4562,6 +4560,10 @@ static int itd_submit(struct fotg210_hcdelse usb_hcd_unlink_urb_from_ep (fotg210_to_hcd (fotg210), urb); done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&fotg210->lock, flags); done:return status;
drivers/usb/host/ehci-sched.c +9 -2
@@ -1623,6 +1623,7 @@ iso_stream_schedule( status =1 ;/* and give it back immediately */ iso_sched_free (stream, sched); sched =NULL ; + urb->hcpriv =NULL ; } } urb->error_count = skip / period;
@@ -1653,8 +1654,6 @@ iso_stream_schedule(return status; fail: -iso_sched_free (stream, sched); - urb->hcpriv =NULL ;return status; }
@@ -1966,6 +1965,10 @@ static int itd_submit(struct ehci_hcd *eusb_hcd_unlink_urb_from_ep (ehci_to_hcd (ehci), urb); } done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&ehci->lock, flags); done:return status;
@@ -2343,6 +2346,10 @@ static int sitd_submit(struct ehci_hcd *usb_hcd_unlink_urb_from_ep (ehci_to_hcd (ehci), urb); } done_not_linked: +if (status <0 ) { +iso_sched_free (stream, urb->hcpriv); + urb->hcpriv =NULL ; + }spin_unlock_irqrestore (&ehci->lock, flags); done:return status;
Greg Kroah-Hartman
maintainerPATCH 304/518 usb: gadget: composite: fix dead empty check in the USB_DT_OTG handler
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit f8f680609c2b3ab795ffcd6f21585b6dfc46d395 upstream.
The OTG branch of composite_setup() falls back to the first configuration when none is selected:
if (cdev->config) config = cdev->config; else config = list_first_entry(&cdev->configs, struct usb_configuration, list); if (!config) goto done; ... memcpy(req->buf, config->descriptors[0], value);
list_first_entry() never returns NULL. On an empty list it returns container_of() of the list head. So the "if (!config)" check is dead.
When cdev->configs is empty, config points at the head inside struct usb_composite_dev. config->descriptors[0] reads whatever sits at that offset. The memcpy copies up to w_length bytes of it into the response buffer.
cdev->configs can be empty in two cases. One is a teardown race on gadget unbind with a control transfer in flight. The other is a driver that sets is_otg before it adds a config. A reproducer that holds cdev->configs empty triggers a KASAN fault in this branch.
Use list_first_entry_or_null() so the existing check does its job.
--- drivers/usb/gadget/composite.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/usb/gadget/composite.c +3 -2
@@ -1863,9 +1863,10 @@ composite_setup(struct usb_gadget *gadgeif (cdev->config) config = cdev->config;else - config =list_first_entry ( + config =list_first_entry_or_null ( &cdev->configs, - struct usb_configuration, list); + struct usb_configuration, + list);if (!config) goto done;
Greg Kroah-Hartman
maintainerPATCH 305/518 usb: gadget: udc: Fix use-after-free in gadget_match_driver
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jimmy Hu <[email protected]>
commit 67e511d2989eb1c8c588b599ce2fcc6bb8e6f7ea upstream.
The udc structure acts as the management structure for the gadget, but their lifecycles are decoupled. A race condition exists where usb_del_gadget() frees the udc memory (e.g., via mode-switch work) while gadget_match_driver() concurrently accesses the freed udc memory (e.g., via configfs), causing a Use-After-Free (UAF) that triggers a NULL pointer dereference when the freed memory is zeroed:
[39430.908615][ T1171] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 [39430.911397][ T1171] pc : __pi_strcmp+0x20/0x140 [39430.911441][ T1171] lr : gadget_match_driver+0x34/0x60 ... [39430.911890][ T1171] usb_gadget_register_driver_owner+0x50/0xf8 [39430.911910][ T1171] gadget_dev_desc_UDC_store+0xf4/0x140 [39430.931308][ T1171] configfs_write_iter+0xec/0x134
[39430.957058][ T1171] Workqueue: events_freezable __dwc3_set_mode [39430.957287][ T1171] dwc3_gadget_exit+0x34/0x8c [39430.957304][ T1171] __dwc3_set_mode+0xc0/0x664
Fix this by ensuring the udc structure remains allocated until the gadget is released. To achieve this, introduce a new usb_gadget_release() routine to the core. When the gadget is added, usb_add_gadget() stores the gadget's release routine in the udc structure and takes a reference to the udc. When the gadget is released, usb_gadget_release() drops the reference to the udc and then calls the gadget's release routine.
--- drivers/usb/gadget/udc/core.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-)
drivers/usb/gadget/udc/core.c +28 -1
@@ -31,8 +31,9 @@ static const struct bus_type gadget_bus_/** * struct usb_udc - describes one usb device controller * @driver: the gadget driver pointer. For use by the class code -* @dev: the child device to the actual controller * @gadget: the gadget. For use by the class code +* @gadget_release: the gadget's release routine +* @dev: the child device to the actual controller * @list: for use by the udc class driver * @vbus: for udcs who care about vbus status, this value is real vbus status; * for udcs who do not care about vbus status, this value is always true
@@ -53,6 +54,7 @@ static const struct bus_type gadget_bus_struct usb_udc {struct usb_gadget_driver *driver;struct usb_gadget *gadget; +void (*gadget_release)(struct device *dev);struct device dev;struct list_head list;bool vbus;
@@ -1357,6 +1359,17 @@ static void usb_udc_nop_release(struct ddev_vdbg (dev,"%s\n" , __func__); } +static void usb_gadget_release (struct device *dev) +{ +struct usb_gadget *gadget =dev_to_usb_gadget (dev); +struct usb_udc *udc = gadget->udc; +/* Cache the gadget's release routine to prevent UAF */ +void (*release)(struct device *dev) = udc->gadget_release; + +put_device (&udc->dev); +release (dev); +} +/** * usb_initialize_gadget - initialize a gadget and its embedded struct device * @parent: the parent device to this udc. Usually the controller driver's
@@ -1413,6 +1426,14 @@ int usb_add_gadget(struct usb_gadget *gamutex_init (&udc->connect_lock); udc->started = false; +/* +* Align decoupled lifecycles: take a UDC reference to ensure it +* remains allocated until the gadget is released, requiring an +* override of the gadget's release routine to drop it. +*/ + udc->gadget_release = gadget->dev.release; + gadget->dev.release = usb_gadget_release; +get_device (&udc->dev);mutex_lock (&udc_lock);list_add_tail (&udc->list, &udc_list);
@@ -1457,6 +1478,12 @@ int usb_add_gadget(struct usb_gadget *gamutex_lock (&udc_lock);list_del (&udc->list);mutex_unlock (&udc_lock); +/* +* Revert the override and drop the UDC reference to prevent +* leaking the UDC if the gadget was statically allocated. +*/ + gadget->dev.release = udc->gadget_release; +put_device (&udc->dev); err_put_udc:put_device (&udc->dev);
Greg Kroah-Hartman
maintainerPATCH 306/518 usb: gadget: f_printer: take kref only for successful open
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 30adce93d5c4a5a1ec29d9249e3fdfcc391d406b upstream.
printer_open() returns -EBUSY when the character device is already open, but it increments dev->kref regardless of the return value. VFS does not call ->release() for a failed open, so every rejected second open permanently leaks one reference.
Move kref_get() into the successful-open branch.
--- drivers/usb/gadget/function/f_printer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/gadget/function/f_printer.c +1 -2
@@ -363,12 +363,11 @@ printer_open(struct inode *inode, struct ret =0 ;/* Change the printer status to show that it's on-line. */ dev->printer_status |=PRINTER_SELECTED ; +kref_get (&dev->kref); }spin_unlock_irqrestore (&dev->lock, flags); -kref_get (&dev->kref); -return ret; }
Greg Kroah-Hartman
maintainerPATCH 307/518 USB: idmouse: fix use-after-free on disconnect race
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit ff002c153f9722caece3983cc23dc4d9d4652cb4 upstream.
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
--- drivers/usb/misc/idmouse.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-)
drivers/usb/misc/idmouse.c +22 -23
@@ -63,6 +63,7 @@ MODULE_DEVICE_TABLE(usb, idmouse_table);/* structure to hold all of our device specific stuff */ struct usb_idmouse { +struct kref kref;struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */
@@ -209,8 +210,10 @@ static int idmouse_resume(struct usb_intreturn 0 ; } -static inline void idmouse_delete (struct usb_idmouse *dev) +static inline void idmouse_delete (struct kref *kref) { + struct usb_idmouse *dev = container_of(kref, struct usb_idmouse, kref); +kfree (dev->bulk_in_buffer);kfree (dev); }
@@ -254,6 +257,8 @@ static int idmouse_open(struct inode *in/* increment our usage count for the driver */ ++dev->open; +kref_get (&dev->kref); +/* save our object in the file's private structure */ file->private_data = dev;
@@ -277,16 +282,11 @@ static int idmouse_release(struct inode/* lock our device */ mutex_lock (&dev->lock); - --dev->open; +mutex_unlock (&dev->lock); + +kref_put (&dev->kref, idmouse_delete); -if (!dev->present) { -/* the device was unplugged before the file was released */ -mutex_unlock (&dev->lock); -idmouse_delete (dev); - }else { -mutex_unlock (&dev->lock); - }return 0 ; }
@@ -334,6 +334,7 @@ static int idmouse_probe(struct usb_inteif (dev ==NULL )return -ENOMEM ; +kref_init (&dev->kref);mutex_init (&dev->lock); dev->udev = udev; dev->interface = interface;
@@ -342,8 +343,7 @@ static int idmouse_probe(struct usb_inte result =usb_find_bulk_in_endpoint (iface_desc, &endpoint);if (result) {dev_err (&interface->dev,"Unable to find bulk-in endpoint.\n" ); -idmouse_delete (dev); -return result; + goto err_put_kref; } dev->orig_bi_size =usb_endpoint_maxp (endpoint);
@@ -351,8 +351,8 @@ static int idmouse_probe(struct usb_inte dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer =kmalloc (IMGSIZE + dev->bulk_in_size,GFP_KERNEL );if (!dev->bulk_in_buffer) { -idmouse_delete (dev); -return -ENOMEM ; + result = -ENOMEM ; + goto err_put_kref; }/* allow device read, write and ioctl */
@@ -364,14 +364,18 @@ static int idmouse_probe(struct usb_inteif (result) {/* something prevented us from registering this device */ dev_err (&interface->dev,"Unable to allocate minor number.\n" ); -idmouse_delete (dev); -return result; + goto err_put_kref; }/* be noisy */ dev_info (&interface->dev,"%s now attached\n" ,DRIVER_DESC );return 0 ; + +err_put_kref: +kref_put (&dev->kref, idmouse_delete); + +return result; }static void idmouse_disconnect (struct usb_interface *interface)
@@ -387,14 +391,9 @@ static void idmouse_disconnect(struct us/* prevent device read, write and ioctl */ dev->present =0 ; -/* if the device is opened, idmouse_release will clean this up */ -if (!dev->open) { -mutex_unlock (&dev->lock); -idmouse_delete (dev); - }else { -/* unlock */ -mutex_unlock (&dev->lock); - } +mutex_unlock (&dev->lock); + +kref_put (&dev->kref, idmouse_delete);dev_info (&interface->dev,"disconnected\n" ); }
Greg Kroah-Hartman
maintainerPATCH 308/518 USB: ldusb: fix use-after-free on disconnect race
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 19bdfc7b3c179331eafa423d87e1336f43bbfeb8 upstream.
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
--- drivers/usb/misc/ldusb.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-)
drivers/usb/misc/ldusb.c +18 -20
@@ -150,6 +150,7 @@ MODULE_PARM_DESC(min_interrupt_out_inter/* Structure to hold all of our device specific stuff */ struct ld_usb { +struct kref kref;struct mutex mutex;/* locks this structure */ struct usb_interface *intf;/* save off the usb interface pointer */ unsigned long disconnected:1 ;
@@ -201,8 +202,10 @@ static void ld_usb_abort_transfers(struc/* * ld_usb_delete */ -static void ld_usb_delete (struct ld_usb *dev) +static void ld_usb_delete (struct kref *kref) { + struct ld_usb *dev = container_of(kref, struct ld_usb, kref); +/* free data structures */ usb_free_urb (dev->interrupt_in_urb);usb_free_urb (dev->interrupt_out_urb);
@@ -355,6 +358,8 @@ static int ld_usb_open(struct inode *ino goto unlock_exit; } +kref_get (&dev->kref); +/* save device in the file's private structure */ file->private_data = dev;
@@ -381,17 +386,8 @@ static int ld_usb_release(struct inode *mutex_lock (&dev->mutex); -if (dev->open_count !=1 ) { - retval = -ENODEV ; +if (dev->disconnected) goto unlock_exit; - } -if (dev->disconnected) { -/* the device was unplugged before the file was released */ -mutex_unlock (&dev->mutex); -/* unlock here as ld_usb_delete frees dev */ -ld_usb_delete (dev); - goto exit; - }/* wait until write transfer is finished */ if (dev->interrupt_out_busy)
@@ -401,7 +397,7 @@ static int ld_usb_release(struct inode * unlock_exit:mutex_unlock (&dev->mutex); - +kref_put (&dev->kref, ld_usb_delete); exit:return retval; }
@@ -659,6 +655,8 @@ static int ld_usb_probe(struct usb_inter dev =kzalloc_obj (*dev);if (!dev) goto exit; + +kref_init (&dev->kref);mutex_init (&dev->mutex);spin_lock_init (&dev->rbsl); dev->intf = intf;
@@ -740,7 +738,7 @@ exit:return retval; error: -ld_usb_delete (dev); +kref_put (&dev->kref, ld_usb_delete);return retval; }
@@ -768,18 +766,18 @@ static void ld_usb_disconnect(struct usbmutex_lock (&dev->mutex); -/* if the device is not opened, then we clean up right now */ -if (!dev->open_count) { -mutex_unlock (&dev->mutex); -ld_usb_delete (dev); - }else { - dev->disconnected =1 ; + dev->disconnected =1 ; + +if (dev->open_count) {/* wake up pollers */ wake_up_interruptible_all (&dev->read_wait);wake_up_interruptible_all (&dev->write_wait); -mutex_unlock (&dev->mutex); } +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, ld_usb_delete); +dev_info (&intf->dev,"LD USB Device #%d now disconnected\n" , (minor -USB_LD_MINOR_BASE )); }
Greg Kroah-Hartman
maintainerPATCH 309/518 USB: iowarrior: fix use-after-free on disconnect
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit bc0e4f16c44e50daa0b1ea729934baa3b4815dee upstream.
Submitted write URBs are not stopped on close() and therefore need to be stopped unconditionally on disconnect() to avoid use-after-free in the completion handler.
--- drivers/usb/misc/iowarrior.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/misc/iowarrior.c +3 -1
@@ -905,13 +905,15 @@ static void iowarrior_disconnect(struct/* prevent device read, write and ioctl */ dev->present =0 ; +/* write urbs are not stopped on close() so kill unconditionally */ +usb_kill_anchored_urbs (&dev->submitted); +if (dev->opened) {/* There is a process that holds a filedescriptor to the device , so we only shutdown read-/write-ops going on. Deleting the device is postponed until close() was called. */ usb_kill_urb (dev->int_in_urb); -usb_kill_anchored_urbs (&dev->submitted);wake_up_interruptible (&dev->read_wait);wake_up_interruptible (&dev->write_wait);mutex_unlock (&dev->mutex);
Greg Kroah-Hartman
maintainerPATCH 310/518 USB: iowarrior: fix use-after-free on disconnect race
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit c602254ba4c10f60a73cd99d147874f86a3f485c upstream.
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
--- drivers/usb/misc/iowarrior.c | 57 ++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 33 deletions(-)
drivers/usb/misc/iowarrior.c +24 -33
@@ -72,6 +72,7 @@ static struct usb_driver iowarrior_drive/* Structure to hold all of our device specific stuff */ struct iowarrior { +struct kref kref;struct mutex mutex;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */
@@ -240,8 +241,10 @@ static void iowarrior_write_callback(str/* * iowarrior_delete */ -static inline void iowarrior_delete (struct iowarrior *dev) +static inline void iowarrior_delete (struct kref *kref) { + struct iowarrior *dev = container_of(kref, struct iowarrior, kref); +kfree (dev->int_in_buffer);usb_free_urb (dev->int_in_urb);kfree (dev->read_queue);
@@ -637,6 +640,9 @@ static int iowarrior_open(struct inode * }/* increment our usage count for the driver */ ++dev->opened; + +kref_get (&dev->kref); +/* save our object in the file's private structure */ file->private_data = dev; retval =0 ;
@@ -652,7 +658,6 @@ out:static int iowarrior_release (struct inode *inode,struct file *file) {struct iowarrior *dev; -int retval =0 ; dev = file->private_data;if (!dev)
@@ -660,29 +665,18 @@ static int iowarrior_release(struct inod/* lock our device */ mutex_lock (&dev->mutex); + dev->opened =0 ;/* we're closing now */ -if (dev->opened <=0 ) { - retval = -ENODEV ;/* close called more than once */ -mutex_unlock (&dev->mutex); - }else { - dev->opened =0 ;/* we're closing now */ - retval =0 ; -if (dev->present) { -/* -The device is still connected so we only shutdown -pending read-/write-ops. -*/ -usb_kill_urb (dev->int_in_urb); -wake_up_interruptible (&dev->read_wait); -wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* The device was unplugged, cleanup resources */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); - } +if (dev->present) { +usb_kill_urb (dev->int_in_urb); +wake_up_interruptible (&dev->read_wait); +wake_up_interruptible (&dev->write_wait); } -return retval; +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); + +return 0 ; }static __poll_t iowarrior_poll (struct file *file,poll_table * wait)
@@ -767,6 +761,7 @@ static int iowarrior_probe(struct usb_inif (!dev)return retval; +kref_init (&dev->kref);mutex_init (&dev->mutex);atomic_set (&dev->intr_idx,0 );
@@ -885,7 +880,8 @@ static int iowarrior_probe(struct usb_inreturn retval; error: -iowarrior_delete (dev); +kref_put (&dev->kref, iowarrior_delete); +return retval; }
@@ -909,19 +905,14 @@ static void iowarrior_disconnect(structusb_kill_anchored_urbs (&dev->submitted);if (dev->opened) { -/* There is a process that holds a filedescriptor to the device , -so we only shutdown read-/write-ops going on. -Deleting the device is postponed until close() was called. -*/ usb_kill_urb (dev->int_in_urb);wake_up_interruptible (&dev->read_wait);wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* no process is using the device, cleanup now */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); } + +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); }/* usb specific object needed to register this driver with the usb subsystem */
Greg Kroah-Hartman
maintainerPATCH 311/518 USB: quirks: add NO_LPM for the Samsung T5 EVO Portable SSD
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erich E. Hoover <[email protected]>
commit fc591787785b9709a0bb65a7df3ba2537d611c47 upstream.
The Samsung T5 EVO Portable SSD (04e8:6200) exhibit two forms of link instability when USB Link Power Management is enabled:
1. The units fail to initialize properly on first detection, resulting in a lockup in the drive where it must be power cycled or the kernel will not recognize the presence of the device.
2. If used for sustained operations (small amounts of continuous data are transferred to the unit) then the unit will "hiccup" after roughly 8 hours of use and will disconnect and reconnect. This has a certain probability of triggering the first issue, but also causes mount points to become invalid since the device gets issued a new letter.
--- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/usb/core/quirks.c +3 -0
@@ -296,6 +296,9 @@ static const struct usb_device_id usb_qu/* CarrolTouch 4500U */ { USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Samsung T5 EVO Portable SSD */ + { USB_DEVICE(0x04e8, 0x6200), .driver_info = USB_QUIRK_NO_LPM }, + /* Samsung Android phone modem - ID conflict with SPH-I500 */ { USB_DEVICE(0x04e8, 0x6601), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
Greg Kroah-Hartman
maintainerPATCH 312/518 USB: legousbtower: fix use-after-free on disconnect race
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 62fc8eb1b1481051f7bab4aa93d79809053dd09f upstream.
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
--- drivers/usb/misc/legousbtower.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-)
drivers/usb/misc/legousbtower.c +19 -18
@@ -185,6 +185,7 @@ MODULE_DEVICE_TABLE(usb, tower_table);/* Structure to hold all of our device specific stuff */ struct lego_usb_tower { +struct kref kref;struct mutex lock;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ unsigned char minor;/* the starting minor number for this device */
@@ -220,7 +221,6 @@ struct lego_usb_tower {/* local function prototypes */ static ssize_t tower_read (struct file *file,char __user *buffer,size_t count,loff_t *ppos);static ssize_t tower_write (struct file *file,const char __user *buffer,size_t count,loff_t *ppos); -static inline void tower_delete (struct lego_usb_tower *dev);static int tower_open (struct inode *inode,struct file *file);static int tower_release (struct inode *inode,struct file *file);static __poll_t tower_poll (struct file *file,poll_table *wait);
@@ -286,8 +286,10 @@ static inline void lego_usb_tower_debug_/* * tower_delete */ -static inline void tower_delete (struct lego_usb_tower *dev) +static inline void tower_delete (struct kref *kref) { + struct lego_usb_tower *dev = container_of(kref, struct lego_usb_tower, kref); +/* free data structures */ usb_free_urb (dev->interrupt_in_urb);usb_free_urb (dev->interrupt_out_urb);
@@ -381,6 +383,8 @@ static int tower_open(struct inode *inod dev->open_count =1 ; +kref_get (&dev->kref); + unlock_exit:mutex_unlock (&dev->lock);
@@ -404,14 +408,8 @@ static int tower_release(struct inode *imutex_lock (&dev->lock); -if (dev->disconnected) { -/* the device was unplugged before the file was released */ - -/* unlock here as tower_delete frees dev */ -mutex_unlock (&dev->lock); -tower_delete (dev); - goto exit; - } +if (dev->disconnected) + goto out_unlock;/* wait until write transfer is finished */ if (dev->interrupt_out_busy) {
@@ -425,7 +423,9 @@ static int tower_release(struct inode *i dev->open_count =0 ; +out_unlock:mutex_unlock (&dev->lock); +kref_put (&dev->kref, tower_delete); exit:return retval; }
@@ -752,6 +752,7 @@ static int tower_probe(struct usb_interfif (!dev) goto exit; +kref_init (&dev->kref);mutex_init (&dev->lock); dev->udev =usb_get_dev (udev);spin_lock_init (&dev->read_buffer_lock);
@@ -828,7 +829,7 @@ exit:return retval; error: -tower_delete (dev); +kref_put (&dev->kref, tower_delete);return retval; }
@@ -856,18 +857,18 @@ static void tower_disconnect(struct usb_mutex_lock (&dev->lock); -/* if the device is not opened, then we clean up right now */ -if (!dev->open_count) { -mutex_unlock (&dev->lock); -tower_delete (dev); - }else { - dev->disconnected =1 ; + dev->disconnected =1 ; + +if (dev->open_count) {/* wake up pollers */ wake_up_interruptible_all (&dev->read_wait);wake_up_interruptible_all (&dev->write_wait); -mutex_unlock (&dev->lock); } +mutex_unlock (&dev->lock); + +kref_put (&dev->kref, tower_delete); +dev_info (&interface->dev,"LEGO USB Tower #%d now disconnected\n" , (minor -LEGO_USB_TOWER_MINOR_BASE )); }
Greg Kroah-Hartman
maintainerPATCH 313/518 usb: sl811-hcd: disable controller wakeup on remove
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 4e8ba83ac4d311992e6a4c21de5dd705010df06e upstream.
sl811h_probe() enables the HCD controller device as a wakeup source after usb_add_hcd() succeeds, but sl811h_remove() removes the HCD and releases the driver resources without disabling that wakeup source.
Disable controller wakeup after usb_remove_hcd() and before usb_put_hcd() so the wakeup source object is detached while the controller device pointer is still available.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/host/sl811-hcd.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/host/sl811-hcd.c +1 -0
@@ -1591,6 +1591,7 @@ sl811h_remove(struct platform_device *deremove_debug_file (sl811);usb_remove_hcd (hcd); +device_wakeup_disable (hcd->self.controller);/* some platforms may use IORESOURCE_IO */ res =platform_get_resource (dev,IORESOURCE_MEM ,1 );
Greg Kroah-Hartman
maintainerPATCH 314/518 USB: storage: include US_FL_NO_SAME in quirks mask
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 2c00e09e3f9f06f8434f5ea2ee6179ce46692ee6 upstream.
usb_stor_adjust_quirks() parses the usb-storage.quirks module parameter into a new flag set and then applies it with the quirk mask to override built-in flags.
The mask is meant to cover the flags that can be overridden by the module parameter. The 'k' quirk character sets US_FL_NO_SAME, but US_FL_NO_SAME is not included in the mask.
As a result, the module parameter can set US_FL_NO_SAME, but it cannot clear a built-in US_FL_NO_SAME flag by providing an override entry that omits 'k'.
Add US_FL_NO_SAME to the mask so that the module parameter can override it in the same way as the other supported flags.
--- drivers/usb/storage/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/storage/usb.c +1 -1
@@ -570,7 +570,7 @@ void usb_stor_adjust_quirks(struct usb_dUS_FL_INITIAL_READ10 |US_FL_WRITE_CACHE |US_FL_NO_ATA_1X |US_FL_NO_REPORT_OPCODES |US_FL_MAX_SECTORS_240 |US_FL_NO_REPORT_LUNS | - US_FL_ALWAYS_SYNC); + US_FL_ALWAYS_SYNC | US_FL_NO_SAME); p = quirks;while (*p) {
Greg Kroah-Hartman
maintainerPATCH 315/518 usb: misc: usbio: bound bulk IN response length to the received transfer
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: HE WEI (ギカク) <[email protected]>
commit 8c6314489550fa81d41723a0ff33f655b5b6c7b6 upstream.
usbio_bulk_msg() copies bpkt_len = le16_to_cpu(bpkt->len) bytes out of the bulk IN buffer (usbio->rxbuf, allocated with size usbio->rxbuf_len) into the caller's buffer. bpkt_len is fully controlled by the device and is only checked against ibuf_len; ibuf_len in turn is checked against usbio->txbuf_len, not against rxbuf_len:
if ((obuf_len > (usbio->txbuf_len - sizeof(*bpkt))) || (ibuf_len > (usbio->txbuf_len - sizeof(*bpkt)))) return -EMSGSIZE;
txbuf_len and rxbuf_len are taken independently from the bulk OUT and bulk IN endpoint wMaxPacketSize in usbio_probe(). A malicious or malfunctioning device that advertises a large bulk OUT endpoint and a small bulk IN endpoint (e.g. by claiming one of the quirk-free IDs such as the Lattice NX33U, 0x2ac1:0x20cb) therefore makes ibuf_len, and hence the device-supplied bpkt_len, exceed rxbuf_len. memcpy() then reads up to txbuf_len - rxbuf_len bytes past the end of the rxbuf slab object. The over-read bytes are handed back to the i2c layer and on to user space through i2c-dev, disclosing adjacent slab memory; with KASAN this is reported as a slab-out-of-bounds read.
The number of bytes actually received is already known: act equals the URB actual_length and is bounded by rxbuf_len. Reject any response that claims more payload than was received, mirroring the existing "act < sizeof(*bpkt)" check just above.
The control path (usbio_ctrl_msg()) is not affected: it uses a single buffer (ctrlbuf) for both directions, so its analogous copy can never leave the allocation.
Found by code review. The out-of-bounds read was confirmed under AddressSanitizer with a faithful userspace model of usbio_bulk_msg()'s receive path (an rxbuf_len-sized buffer, the same act/ibuf_len/bpkt_len checks and the memcpy). A USB raw-gadget + dummy_hcd reproducer is also available.
--- drivers/usb/misc/usbio.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/misc/usbio.c +4 -0
@@ -344,6 +344,10 @@ read:if (ibuf_len < bpkt_len)return -ENOSPC ; +/* The device must not claim more payload than it actually sent. */ +if (bpkt_len > act -sizeof (*bpkt)) +return -EPROTO ; +memcpy (ibuf, bpkt->data, bpkt_len);return bpkt_len;
Greg Kroah-Hartman
maintainerPATCH 316/518 USB: misc: uss720: unregister parport on probe failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit b4ecbdc4f8830f5586c4a5cfc384c00f20f8f8b3 upstream.
uss720_probe() registers a parport before reading the 1284 register used to detect unsupported Belkin F5U002 adapters. If get_1284_register() fails, the error path drops the driver private data and the USB device reference, but leaves the parport device registered.
Leaving the port registered is more than a private allocation leak:parport_register_port() has already reserved a parport number and registered the parport bus device, while pp->private_data still points at the private data that the common error path is about to release.
Undo the pre-announce registration in the get_1284_register() failure branch before jumping to the common private-data cleanup path. Clear priv->pp first, matching the disconnect path and avoiding a stale pointer in the private data.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/misc/uss720.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/usb/misc/uss720.c +4 -1
@@ -732,8 +732,11 @@ static int uss720_probe(struct usb_inter* here. */ ret =get_1284_register (pp,0 , ®,GFP_KERNEL );dev_dbg (&intf->dev,"reg: %7ph\n" , priv->reg); -if (ret <0 ) +if (ret <0 ) { + priv->pp =NULL ; +parport_del_port (pp); goto probe_abort; + } ret =usb_find_last_int_in_endpoint (interface, &epd);if (!ret) {
Greg Kroah-Hartman
maintainerPATCH 317/518 usb: mtu3: unmap request DMA on queue failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 0bddda5a11665c210339de76d27ebbd1a2e0b43c upstream.
mtu3_gadget_queue() maps the request before checking whether the QMU GPD ring can accept another transfer. the request is returned with -EAGAIN before it is linked on the endpoint request list if mtu3_prepare_transfer() fails.
Normal completion and dequeue paths unmap requests from mtu3_req_complete(), but this error path never reaches that helper, so the DMA mapping is left active. Unmap the request before returning from the failed queue path.
--- drivers/usb/mtu3/mtu3_gadget.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/mtu3/mtu3_gadget.c +1 -0
@@ -305,6 +305,7 @@ static int mtu3_gadget_queue(struct usb_if (mtu3_prepare_transfer (mep)) { ret = -EAGAIN ; +usb_gadget_unmap_request (&mtu->g, req, mep->is_in); goto error; }
Greg Kroah-Hartman
maintainerPATCH 318/518 USB: serial: keyspan_pda: fix information leak
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 6bfc8d01ac4068eced509f8fc74d0cd205e4dcec upstream.
The write() callback is supposed to return the number of characters accepted or a negative errno. Since the addition of write fifo support the keyspan_pda implementation will however return the number characters submitted to the device if the write urb is not already in use. If this number is larger than the number of characters passed to write(), the line discipline continues writing data from beyond the tty write buffer.
Fix the information leak by making sure that keyspan_pda_write_start() returns zero on success as intended.
--- drivers/usb/serial/keyspan_pda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/serial/keyspan_pda.c +1 -1
@@ -518,7 +518,7 @@ static int keyspan_pda_write_start(strucif (count == room)schedule_work (&priv->unthrottle_work); -return count; +return 0 ; }static void keyspan_pda_write_bulk_callback (struct urb *urb)
Greg Kroah-Hartman
maintainerPATCH 319/518 USB: serial: option: add Telit Cinterion FE990D50 compositions
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Porcedda <[email protected]>
commit b33ab1dd80f5c1742f49eb6ec7b337c5ffcf3d32 upstream.
Add support for Telit Cinterion FE990D50 compositions:
0x990: RNDIS + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (AT) +
tty (diag) + ADPL + adb
T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=0990 Rev=06.06 S: Manufacturer=Telit Cinterion S: Product=FE990 S: SerialNumber=90b6a3ed C: #Ifs=10 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=ef(misc ) Sub=04 Prot=01 Driver=rndis_host E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 9 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
0x991: rmnet + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (AT) +
tty (diag) + ADPL + adb
T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 9 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=0991 Rev=06.06 S: Manufacturer=Telit Cinterion S: Product=FE990 S: SerialNumber=90b6a3ed C: #Ifs= 9 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=(none) E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 6 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
0x992: MBIM + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (AT) +
tty (diag) + ADPL + adb
T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 12 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=0992 Rev=06.06 S: Manufacturer=Telit Cinterion S: Product=FE990 S: SerialNumber=90b6a3ed C: #Ifs=10 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 9 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
0x993: ECM + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (AT) +
tty (diag) + ADPL + adb
T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 15 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=0993 Rev=06.06 S: Manufacturer=Telit Cinterion S: Product=FE990 S: SerialNumber=90b6a3ed C: #Ifs=10 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=06 Prot=00 Driver=cdc_ether E: Ad=82(I) Atr=03(Int.) MxPS= 16 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 9 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/usb/serial/option.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/usb/serial/option.c +16 -0
@@ -1326,6 +1326,22 @@ static const struct usb_device_id option { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x30), /* Telit FE990D50 (RNDIS) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0990, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x30), /* Telit FE990D50 (rmnet) */ + .driver_info = NCTRL(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0991, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x30), /* Telit FE990D50 (MBIM) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0992, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x30), /* Telit FE990D50 (ECM) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x0993, 0xff, 0xff, 0x60) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1031, 0xff), /* Telit LE910C1-EUX */ .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff), /* Telit LE910C1-EUX (ECM) */
Greg Kroah-Hartman
maintainerPATCH 320/518 USB: serial: digi_acceleport: fix broken rx after throttle
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 83a3dfc018943b05b6daf3a6f891833e1aabfa1f upstream.
If the port is closed while throttled, the read urb is never resubmitted and the port will not receive any further data until the device is reconnected (or the driver is rebound).
Clear the throttle flags and submit the urb if needed when opening the port.
--- drivers/usb/serial/digi_acceleport.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/usb/serial/digi_acceleport.c +16 -0
@@ -1071,6 +1071,7 @@ static int digi_open(struct tty_struct *unsigned char buf[32 ];struct digi_port *priv =usb_get_serial_port_data (port);struct ktermios not_termios; +int throttled;/* be sure the device is started up */ if (digi_startup_device (port->serial) !=0 )
@@ -1098,6 +1099,21 @@ static int digi_open(struct tty_struct * not_termios.c_iflag = ~tty->termios.c_iflag;digi_set_termios (tty, port, ¬_termios); } + +spin_lock_irq (&priv->dp_port_lock); + throttled = priv->dp_throttle_restart; + priv->dp_throttled =0 ; + priv->dp_throttle_restart =0 ; +spin_unlock_irq (&priv->dp_port_lock); + +if (throttled) { + ret =usb_submit_urb (port->read_urb,GFP_KERNEL ); +if (ret) { +dev_err (&port->dev,"failed to submit read urb: %d\n" , ret); +return ret; + } + } +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 321/518 USB: serial: digi_acceleport: fix hard lockup on disconnect
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 5c1ea24b53bf3bfb859f0a05573997487975da23 upstream.
If submitting the OOB write urb fails persistently (e.g if the device is being disconnected) the driver would loop indefinitely with interrupts disabled.
Check for urb submission errors when sending OOB commands to avoid hanging if, for example, open(), set_termios() or close() races with a physical disconnect.
This is issue was flagged by Sashiko when reviewing an unrelated change to the driver.
--- drivers/usb/serial/digi_acceleport.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/usb/serial/digi_acceleport.c +7 -5
@@ -394,12 +394,14 @@ static int digi_write_oob_command(struct len &= ~3 ;memcpy (oob_port->write_urb->transfer_buffer, buf, len); oob_port->write_urb->transfer_buffer_length = len; + ret =usb_submit_urb (oob_port->write_urb,GFP_ATOMIC ); -if (ret ==0 ) { - oob_priv->dp_write_urb_in_use =1 ; - count -= len; - buf += len; - } +if (ret) +break ; + + oob_priv->dp_write_urb_in_use =1 ; + count -= len; + buf += len; }spin_unlock_irqrestore (&oob_priv->dp_port_lock, flags);if (ret)
Greg Kroah-Hartman
maintainerPATCH 322/518 USB: serial: digi_acceleport: fix write buffer corruption
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 24ca1fea8f2753bf33e1d458ec1ae5d9b7796a65 upstream.
The digi_write_inb_command() is supposed to wait for the write urb to become available or return an error, but instead it updates the transfer buffer and tries to resubmit the urb on timeout.
To make things worse, for commands like break control where no timeout is used, the driver would corrupt the urb immediately due to a broken jiffies comparison (on 32-bit machines this takes five minutes of uptime to trigger due to INITIAL_JIFFIES).
Fix this by adding the missing return on timeout and waiting indefinitely when no timeout has been specified as intended.
This issue was (sort of) flagged by Sashiko when reviewing an unrelated change to the driver.
--- drivers/usb/serial/digi_acceleport.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/usb/serial/digi_acceleport.c +10 -5
@@ -431,20 +431,22 @@ static int digi_write_inb_command(structint len;struct digi_port *priv =usb_get_serial_port_data (port);unsigned char *data = port->write_urb->transfer_buffer; +unsigned long expire;unsigned long flags;dev_dbg (&port->dev,"digi_write_inb_command: TOP: port=%d, count=%d\n" , priv->dp_port_num, count);if (timeout) - timeout += jiffies; -else - timeout =ULONG_MAX ; + expire = jiffies + timeout;spin_lock_irqsave (&priv->dp_port_lock, flags);while (count >0 && ret ==0 ) { -while (priv->dp_write_urb_in_use && -time_before (jiffies, timeout)) { +while (priv->dp_write_urb_in_use) { +if (timeout &&time_after (jiffies, expire)) { + ret = -ETIMEDOUT ; +break ; + }cond_wait_interruptible_timeout_irqrestore ( &priv->write_wait,DIGI_RETRY_TIMEOUT , &priv->dp_port_lock, flags);
@@ -453,6 +455,9 @@ static int digi_write_inb_command(structspin_lock_irqsave (&priv->dp_port_lock, flags); } +if (ret) +break ; +/* len must be a multiple of 4 and small enough to */ /* guarantee the write will send buffered data first, */ /* so commands are in order with data and not split */
Greg Kroah-Hartman
maintainerPATCH 323/518 USB: ulpi: fix memory leak on registration failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 8af6812795869a66e9b26044f455b13deecdb69c upstream.
The allocated device name is never freed on early ULPI device registration failures.
Fix this by initialising the device structure earlier and releasing the initial reference whenever registration fails.
--- drivers/usb/common/ulpi.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-)
drivers/usb/common/ulpi.c +10 -13
@@ -281,28 +281,24 @@ static int ulpi_register(struct device * ulpi->dev.parent = dev;/* needed early for ops */ ulpi->dev.bus = &ulpi_bus; ulpi->dev.type = &ulpi_dev_type; + +device_initialize (&ulpi->dev); +dev_set_name (&ulpi->dev,"%s.ulpi" ,dev_name (dev));ACPI_COMPANION_SET (&ulpi->dev,ACPI_COMPANION (dev)); ret =ulpi_of_register (ulpi); -if (ret) { -kfree (ulpi); +if (ret)return ret; - } ret =ulpi_read_id (ulpi); -if (ret) { -of_node_put (ulpi->dev.of_node); -kfree (ulpi); +if (ret)return ret; - } - ret =device_register (&ulpi->dev); -if (ret) { -put_device (&ulpi->dev); + ret =device_add (&ulpi->dev); +if (ret)return ret; - } root =debugfs_create_dir (dev_name (&ulpi->dev), ulpi_root);debugfs_create_file ("regs" ,0444 , root, ulpi, &ulpi_regs_fops);
@@ -334,9 +330,10 @@ struct ulpi *ulpi_register_interface(str ulpi->ops = ops; ret =ulpi_register (dev, ulpi); -if (ret) +if (ret) { +put_device (&ulpi->dev);return ERR_PTR (ret); - + }return ulpi; }
Greg Kroah-Hartman
maintainerPATCH 324/518 USB: usb-storage: ene_ub6250: restore media-ready check
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 5fc3f333c001f1e308bbcdeecdec0d054d24338b upstream.
Commit 1892bf90677a ("USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c") converted the media status fields from bitfields to bit masks.
The original ene_transport() test called ene_init() only when neither media type was ready:
!(sd_ready || ms_ready)
The converted test became:
!sd_ready || ms_ready
This is not equivalent. Restore the original semantics by testing that both ready bits are clear before calling ene_init().
--- drivers/usb/storage/ene_ub6250.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/storage/ene_ub6250.c +2 -1
@@ -2305,7 +2305,8 @@ static int ene_transport(struct scsi_cmn/*US_DEBUG(usb_stor_show_command(us, srb)); */ scsi_set_resid (srb,0 ); -if (unlikely (!(info->SD_Status & SD_Ready) || (info->MS_Status & MS_Ready))) +if (unlikely (!(info->SD_Status & SD_Ready) && + !(info->MS_Status & MS_Ready))) result =ene_init (us);if (result ==USB_STOR_XFER_GOOD ) { result =USB_STOR_TRANSPORT_ERROR ;
Greg Kroah-Hartman
maintainerPATCH 325/518 usbip: tools: support SuperSpeedPlus devices
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
commit 195e667c8719480c320cd48ac0fbf1cb81d6ffe0 upstream.
USB devices running at SuperSpeedPlus report "10000" or "20000" in their sysfs speed attribute. usbip currently maps only "5000" to USB_SPEED_SUPER, so a SuperSpeedPlus device is imported as USB_SPEED_UNKNOWN.
The attach request is then rejected by vhci_hcd:
vhci_hcd: Failed attach request for unsupported USB speed: UNKNOWN
Map the SuperSpeedPlus sysfs speed values to USB_SPEED_SUPER_PLUS, use the SuperSpeed VHCI hub for SuperSpeedPlus devices, and recognize the gadget current_speed string used by the kernel.
--- tools/usb/usbip/libsrc/usbip_common.c | 2 ++ tools/usb/usbip/libsrc/usbip_device_driver.c | 4 ++++ tools/usb/usbip/libsrc/vhci_driver.c | 1 + 3 files changed, 7 insertions(+)
tools/usb/usbip/libsrc/usbip_common.c +2 -0
@@ -29,6 +29,8 @@ static const struct speed_string speed_s { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, + { USB_SPEED_SUPER_PLUS, "10000", "Super Speed Plus(10000Mbps)" }, + { USB_SPEED_SUPER_PLUS, "20000", "Super Speed Plus(20000Mbps)" }, { 0, NULL, NULL } };
tools/usb/usbip/libsrc/usbip_device_driver.c +4 -0
@@ -57,6 +57,10 @@ static struct { .speed = USB_SPEED_SUPER, .name = "super-speed", }, + { + .speed = USB_SPEED_SUPER_PLUS, + .name = "super-speed-plus", + }, }; static
tools/usb/usbip/libsrc/vhci_driver.c +1 -0
@@ -338,6 +338,7 @@ int usbip_vhci_get_free_port(uint32_t spswitch (speed) {case USB_SPEED_SUPER : +case USB_SPEED_SUPER_PLUS :if (vhci_driver->idev[i].hub !=HUB_SPEED_SUPER )continue ;break ;
Greg Kroah-Hartman
maintainerPATCH 326/518 usbip: vudc: fix NULL deref in vep_dequeue()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sam Day <[email protected]>
commit c5371e0b91b24159a3ebaa61e70b0980bcf03c0a upstream.
vep_alloc_request() wasn't initializing vrequest->udc, so cancellations on the FunctionFS AIO path were arriving in vep_dequeue without a valid UDC reference.
Since vrequest->udc is never actually properly used anywhere, we opt to remove it, and update vep_dequeue to obtain a reference to the udc with ep_to_vudc(), consistent with the other vep_ ops.
AFAICT this bug has existed for ~10 years. Seems that nobody has really stressed the FunctionFS AIO path on usbip's vudc.
I tested this fix in a QEMU aarch64 guest driving FunctionFS endpoints via AIO. Before the fix, running usbip attach from the host would cause the guest to oops with the following backtrace:
Call trace: vep_dequeue+0x1c/0xe4 (P) usb_ep_dequeue+0x14/0x20 ffs_aio_cancel+0x24/0x34 __arm64_sys_io_cancel+0xb0/0x124 do_el0_svc+0x68/0x100 el0_svc+0x18/0x5c el0t_64_sync_handler+0x98/0xdc el0t_64_sync+0x154/0x158
--- drivers/usb/usbip/vudc.h | 1 - drivers/usb/usbip/vudc_dev.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-)
drivers/usb/usbip/vudc.h +0 -1
@@ -38,7 +38,6 @@ struct vep {struct vrequest {struct usb_request req; -struct vudc *udc;struct list_head req_entry;/* Request queue */ };
drivers/usb/usbip/vudc_dev.c +1 -3
@@ -333,7 +333,6 @@ static int vep_queue(struct usb_ep *_ep,static int vep_dequeue (struct usb_ep *_ep,struct usb_request *_req) {struct vep *ep; -struct vrequest *req;struct vudc *udc;struct vrequest *lst;unsigned long flags;
@@ -343,8 +342,7 @@ static int vep_dequeue(struct usb_ep *_ereturn ret; ep =to_vep (_ep); - req =to_vrequest (_req); - udc = req->udc; + udc =ep_to_vudc (ep);if (!udc->driver)return -ESHUTDOWN ;
Greg Kroah-Hartman
maintainerPATCH 327/518 usb: typec: anx7411: use devm_pm_runtime_enable()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 0ef7cc27da8b9e315a4a5a665c68c44206f5e559 upstream.
anx7411_i2c_probe() enables runtime PM before returning successfully, but anx7411_i2c_remove() tears down the Type-C partner state, workqueue, dummy I2C device, mux, switch and port without disabling runtime PM.
Use devm_pm_runtime_enable() so runtime PM is disabled automatically on driver detach. Since devres action registration can fail, route that failure through the existing probe unwind path.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/usb/typec/anx7411.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/usb/typec/anx7411.c +3 -1
@@ -1537,7 +1537,9 @@ static int anx7411_i2c_probe(struct i2c_if (anx7411_typec_check_connection (plat))dev_err (dev,"check status\n" ); -pm_runtime_enable (dev); + ret =devm_pm_runtime_enable (dev); +if (ret) + goto free_wq;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 328/518 usb: typec: class: drop PD lookup reference
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit 43ae2f90b70cda374c487c1639a01d0f14e5d583 upstream.
usb_power_delivery_find() wraps class_find_device_by_name(). That helper returns a device reference that must be released by the caller.
select_usb_power_delivery_store() only needs this reference while calling the pd_set callback. Drop it once the callback returns. Otherwise the sysfs write can pin the selected USB Power Delivery object and prevent it from being released on unregister.
--- drivers/usb/typec/class.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/typec/class.c +1 -0
@@ -1619,6 +1619,7 @@ static ssize_t select_usb_power_deliveryreturn -EINVAL ; ret = port->ops->pd_set (port, pd); +put_device (&pd->dev);if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 329/518 usb: typec: ps883x: Fix DP+USB3 configuration
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit b229b22b0a945d52dee887c856991ad08744d08e upstream.
Commit 6bebd9b77726 ("usb: typec: ps883x: Rework ps883x_set()") introduced two regressions:
1. The CONN_STATUS_0_USB_3_1_CONNECTED bit is mistakenly written to the wrong configuration register (cfg1 instead of cfg0). This breaks USB3 when using USB3+DP adapters.
2. The switch-case fallthrough block is inverted: Currently, TYPEC_DP_STATE_C (DP-only) inherits the USB3 configuration, while TYPEC_DP_STATE_D (DP+USB3) is missing the necessary DP sink flags.
Fix these by writing the USB3 bit to the correct register and swapping the case statement order so both states get their correct bits assigned.
--- drivers/usb/typec/mux/ps883x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/usb/typec/mux/ps883x.c +3 -3
@@ -118,12 +118,12 @@ static int ps883x_set(struct ps883x_retiCONN_STATUS_1_DP_HPD_LEVEL ;switch (state->mode) { +case TYPEC_DP_STATE_D : + cfg0 |=CONN_STATUS_0_USB_3_1_CONNECTED ; + fallthrough;case TYPEC_DP_STATE_C : cfg1 |=CONN_STATUS_1_DP_SINK_REQUESTED |CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D ; - fallthrough; -case TYPEC_DP_STATE_D : - cfg1 |=CONN_STATUS_0_USB_3_1_CONNECTED ;break ;default :/* MODE_E */ break ;
Greg Kroah-Hartman
maintainerPATCH 330/518 usb: typec: tcpm: Fix VDM type for Enter Mode commands
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Yan <[email protected]>
commit 9cff680e47632b7723cb19f9c5e63669063c3417 upstream.
VDO() second parameter is VDM type (bit 15): 1 for SVDM, 0 for UVDM. Using 'vdo ? 2 : 1' corrupts SVID low bit when vdo is non-NULL (2 << 15 = BIT(16)). Enter Mode is always SVDM, hardcode to 1.
--- drivers/usb/typec/tcpm/tcpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/typec/tcpm/tcpm.c +2 -2
@@ -3088,7 +3088,7 @@ static int tcpm_altmode_enter(struct typif (svdm_version <0 )return svdm_version; - header =VDO (altmode->svid, vdo ?2 :1 , svdm_version,CMD_ENTER_MODE ); + header =VDO (altmode->svid,1 , svdm_version,CMD_ENTER_MODE ); header |=VDO_OPOS (altmode->mode);return tcpm_queue_vdm_unlocked (port, header, vdo, vdo ?1 :0 ,TCPC_TX_SOP );
@@ -3136,7 +3136,7 @@ static int tcpm_cable_altmode_enter(struif (svdm_version <0 )return svdm_version; - header =VDO (altmode->svid, vdo ?2 :1 , svdm_version,CMD_ENTER_MODE ); + header =VDO (altmode->svid,1 , svdm_version,CMD_ENTER_MODE ); header |=VDO_OPOS (altmode->mode);return tcpm_queue_vdm_unlocked (port, header, vdo, vdo ?1 :0 ,TCPC_TX_SOP_PRIME );
Greg Kroah-Hartman
maintainerPATCH 331/518 usb: typec: tcpm: Validate SVID index in svdm_consume_modes()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Badhri Jagan Sridharan <[email protected]>
commit 7b681dd5fbf60b24a13c14661e5b7735759fb491 upstream.
In svdm_consume_modes(), the SVID value is read from pmdata->svids using pmdata->svid_index as an array index without bounds validation:
paltmode->svid = pmdata->svids[pmdata->svid_index];
If pmdata->svid_index is driven beyond SVID_DISCOVERY_MAX (16), it results in an out-of-bounds read of the pmdata->svids array. Because pd_mode_data is embedded inside struct tcpm_port, indexing past svids reads into adjacent fields. In particular:
- At index 16, it reads the altmodes count.
- At index 18 and beyond, it reads into altmode_desc[], which contains partner-supplied SVDM Discovery Modes VDOs.
By injecting a chosen SVID into altmode_desc[0].vdo and driving svid_index to 20, the partner can force paltmode->svid to be loaded with an arbitrary, partner- chosen SVID, which is then registered via typec_partner_register_altmode().
Fix this by validating that pmdata->svid_index is non-negative and strictly less than pmdata->nsvids before accessing the pmdata->svids array inside svdm_consume_modes().
--- drivers/usb/typec/tcpm/tcpm.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/usb/typec/tcpm/tcpm.c +5 -0
@@ -2000,6 +2000,11 @@ static void svdm_consume_modes(struct tcreturn ; } +if (pmdata->svid_index <0 || pmdata->svid_index >= pmdata->nsvids) { +tcpm_log (port,"Invalid SVID index %d" , pmdata->svid_index); +return ; + } +for (i =1 ; i < cnt; i++) {if (pmdata->altmodes >=ALTMODE_DISCOVERY_MAX ) {/* Already logged in svdm_consume_svids() */
Greg Kroah-Hartman
maintainerPATCH 332/518 usb: typec: ucsi: Invert DisplayPort role assignment
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrei Kuchynski <[email protected]>
commit d092d7edf8faefa3e27b9fc7f0e7904b06c833a2 upstream.
The existing implementation assigned these flags backwards, configuring the partner's DisplayPort role to match the port's role instead of complementing it.
This prevents proper configuration during DP altmode activation, often causing pin_assignment to remain 0 in dp_altmode_configure() and resulting in VDM negotiation failures:
[ 583.328246] typec port1.1: VDM 0xff01a150 failed
Additionally, the fix ensures that the pin_assignment sysfs attribute displays the correct values.
--- drivers/usb/typec/ucsi/displayport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/typec/ucsi/displayport.c +2 -2
@@ -166,12 +166,12 @@ static int ucsi_displayport_status_updat* that Multi-function is preferred. */ if (DP_CAP_CAPABILITY (cap) &DP_CAP_UFP_D ) { - dp->data.status |=DP_STATUS_CON_UFP_D ; + dp->data.status |=DP_STATUS_CON_DFP_D ;if (DP_CAP_UFP_D_PIN_ASSIGN (cap) &BIT (DP_PIN_ASSIGN_D )) dp->data.status |=DP_STATUS_PREFER_MULTI_FUNC ; }else { - dp->data.status |=DP_STATUS_CON_DFP_D ; + dp->data.status |=DP_STATUS_CON_UFP_D ;if (DP_CAP_DFP_D_PIN_ASSIGN (cap) &BIT (DP_PIN_ASSIGN_D )) dp->data.status |=DP_STATUS_PREFER_MULTI_FUNC ;
Greg Kroah-Hartman
maintainerPATCH 333/518 usb: typec: ucsi: Pass full DP config payload in SET_NEW_CAM for DP alt mode
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Madhu M <[email protected]>
commit 735a461d060d4eeb2f9732aba1295bc32a3982e2 upstream.
In the UCSI Specification Revision 3.1 RC1, bits 32-63 of the SET_NEW_CAM command hold the 32-bit Alternate Mode Specific (AMSpecific) field.
For DisplayPort Alternate Mode, this field must contain the full 32-bit DisplayPort configuration VDO payload that the OPM wants the connector to operate in, rather than just the pin assignment value. This AMSpecific value follows the DisplayPort Configurations defined in the DisplayPort Alt Mode on USB Type-C Specification v2.1a, Table 5-13: SOP DisplayPort Configurations.
--- drivers/usb/typec/ucsi/displayport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/usb/typec/ucsi/displayport.c +1 -2
@@ -185,13 +185,12 @@ static int ucsi_displayport_status_updatstatic int ucsi_displayport_configure (struct ucsi_dp *dp) { -u32 pins =DP_CONF_GET_PIN_ASSIGN (dp->data.conf);u64 command;if (!dp->override)return 0 ; - command =UCSI_CMD_SET_NEW_CAM (dp->con->num,1 , dp->offset, pins); + command =UCSI_CMD_SET_NEW_CAM (dp->con->num,1 , dp->offset, dp->data.conf);return ucsi_send_command (dp->con->ucsi, command,NULL ,0 ); }
Greg Kroah-Hartman
maintainerPATCH 334/518 usb: typec: ucsi: ccg: Fix use-after-free of ucsi on remove
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 1f0bdc2884b67de337215079bba166df0cdf4ac5 upstream.
The threaded IRQ handler ccg_irq_handler() calls ucsi_notify_common(), which on a connector-change event calls ucsi_connector_change() and schedules connector work. In ucsi_ccg_remove(), ucsi_destroy() frees uc->ucsi (kfree) before free_irq() is called, so a handler invocation already in flight may access the freed object after ucsi_destroy().
CPU 0 (remove) | CPU 1 (threaded IRQ)
ucsi_destroy(uc->ucsi) | ccg_irq_handler()
kfree(ucsi) // FREE | ucsi_notify_common(uc->ucsi) // USEMove free_irq() before ucsi_destroy() in the remove path. It is kept after ucsi_unregister(): ucsi_unregister() cancels connector work whose handler issues GET_CONNECTOR_STATUS through ucsi_send_command_common(), which waits for a completion that is signalled from the IRQ handler, so the IRQ must stay active until that work has been cancelled.
The probe error path already orders free_irq() before ucsi_destroy().
This bug was found by static analysis.
--- drivers/usb/typec/ucsi/ucsi_ccg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/ucsi/ucsi_ccg.c +1 -1
@@ -1519,8 +1519,8 @@ static void ucsi_ccg_remove(struct i2c_ccancel_work_sync (&uc->work);pm_runtime_disable (uc->dev);ucsi_unregister (uc->ucsi); -ucsi_destroy (uc->ucsi);free_irq (uc->irq, uc); +ucsi_destroy (uc->ucsi); }static const struct of_device_id ucsi_ccg_of_match_table[] = {
Greg Kroah-Hartman
maintainerPATCH 335/518 usb: typec: ucsi: cancel pending work on system suspend
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Menzel <[email protected]>
commit 7c4a234bd31a64a8dbd0140dc812da592c5e0787 upstream.
On a Dell XPS 13 9360 (BIOS 2.21.0), entering system suspend (deep/S3) races a pending UCSI connector-change worker against the ACPI EC teardown. The worker evaluates the UCSI _DSM (GET_CONNECTOR_STATUS), whose AML accesses the Embedded Controller. By that point the ACPI EC has already been stopped for suspend, so the EC address space handler rejects the access with AE_BAD_PARAMETER, aborting the AML and failing the connector query:
[22314.689495] ACPI: EC: interrupt blocked
[22314.711981] ACPI: PM: Preparing to enter system sleep state S3
[22314.743260] ACPI: EC: event blocked
[22314.743265] ACPI: EC: EC stopped
[22314.743267] ACPI: PM: Saving platform NVS memory
[22314.744241] ACPI Error: AE_BAD_PARAMETER, Returned by Handler for [EmbeddedControl] (20260408/evregion-303)
[22314.744432] ACPI Error: Aborting method \_SB.PCI0.LPCB.ECDV.ECW1 due to previous error (AE_BAD_PARAMETER) (20260408/psparse-543)
[22314.744673] ACPI Error: Aborting method \ECWB due to previous error (AE_BAD_PARAMETER) (20260408/psparse-543)
[22314.745201] ACPI Error: Aborting method \_SB.UBTC._DSM due to previous error (AE_BAD_PARAMETER) (20260408/psparse-543)
[22314.745394] ACPI: \_SB_.UBTC: failed to evaluate _DSM c298836f-a47c-e411-ad36-631042b5008f rev:1 func:1 (0x1001)
[22314.745414] ucsi_acpi USBC000:00: ucsi_acpi_dsm: failed to evaluate _DSM 1
[22314.745424] ucsi_acpi USBC000:00: ucsi_handle_connector_change: GET_CONNECTOR_STATUS failed (-5)ucsi_acpi implements a resume callback but no suspend callback, so nothing cancels the connector-change work before the firmware/EC is torn down.
Add a ucsi_suspend() core helper that cancels the pending init and connector-change work, and wire it into ucsi_acpi's PM ops. The connector state is re-read on resume by ucsi_resume(), so cancelling the work loses nothing.
--- drivers/usb/typec/ucsi/ucsi.c | 20 ++++++++++++++++++++ drivers/usb/typec/ucsi/ucsi.h | 1 + drivers/usb/typec/ucsi/ucsi_acpi.c | 10 +++++++++- 3 files changed, 30 insertions(+), 1 deletion(-)
drivers/usb/typec/ucsi/ucsi.c +20 -0
@@ -1978,6 +1978,26 @@ static void ucsi_resume_work(struct work } } +int ucsi_suspend (struct ucsi *ucsi) +{ +int i; + +/* +* Cancel pending work so it cannot access the firmware after the ACPI +* EC is stopped for suspend; state is re-read on resume. +*/ +cancel_delayed_work_sync (&ucsi->work); + +if (!ucsi->connector) +return 0 ; + +for (i =0 ; i < ucsi->cap.num_connectors; i++) +cancel_work_sync (&ucsi->connector[i].work); + +return 0 ; +} +EXPORT_SYMBOL_GPL (ucsi_suspend); +int ucsi_resume (struct ucsi *ucsi) {if (ucsi->connector)
drivers/usb/typec/ucsi/ucsi.h +1 -0
@@ -566,6 +566,7 @@ int ucsi_send_command(struct ucsi *ucsi, void *retval, size_t size);void ucsi_altmode_update_active (struct ucsi_connector *con); +int ucsi_suspend (struct ucsi *ucsi);int ucsi_resume (struct ucsi *ucsi);void ucsi_notify_common (struct ucsi *ucsi,u32 cci);
drivers/usb/typec/ucsi/ucsi_acpi.c +9 -1
@@ -245,6 +245,13 @@ static void ucsi_acpi_remove(struct plat ucsi_acpi_notify); } +static int ucsi_acpi_suspend (struct device *dev) +{ +struct ucsi_acpi *ua =dev_get_drvdata (dev); + +return ucsi_suspend (ua->ucsi); +} +static int ucsi_acpi_resume (struct device *dev) {struct ucsi_acpi *ua =dev_get_drvdata (dev);
@@ -252,7 +259,8 @@ static int ucsi_acpi_resume(struct devicreturn ucsi_resume (ua->ucsi); } -static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, NULL, ucsi_acpi_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, ucsi_acpi_suspend, + ucsi_acpi_resume);static const struct acpi_device_id ucsi_acpi_match[] = { {"PNP0CA0" ,0 },
Greg Kroah-Hartman
maintainerPATCH 336/518 usb: gadget: f_fs: initialize reset_work at allocation time
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tyler Baker <[email protected]>
commit 3137b243c93982fe3460335e12f9247739766e10 upstream.
ffs_fs_kill_sb() unconditionally calls cancel_work_sync() on ffs->reset_work when a functionfs instance is unmounted:
ffs_data_reset(ffs); cancel_work_sync(&ffs->reset_work);
However ffs->reset_work is only ever initialized via INIT_WORK() in ffs_func_set_alt() and ffs_func_disable(), and only on the FFS_DEACTIVATED path. That state is reached solely by ffs_data_closed() when the instance is mounted with the "no_disconnect" option, so for the common case (no "no_disconnect", or mounted and unmounted without ever being deactivated) reset_work is never initialized.
ffs_data_new() allocates the ffs_data with kzalloc_obj() and does not initialize reset_work, and ffs_data_reset()/ffs_data_clear() do not touch it either, so reset_work.func is left NULL. cancel_work_sync() on such a work then trips the WARN_ON(!work->func) guard in __flush_work():
WARNING: kernel/workqueue.c:4301 at __flush_work+0x330/0x360, CPU#3: umount Call trace: __flush_work cancel_work_sync ffs_fs_kill_sb [usb_f_fs] deactivate_locked_super deactivate_super cleanup_mnt __cleanup_mnt task_work_run exit_to_user_mode_loop el0_svc
On older kernels cancel_work_sync() on a zero-initialized work struct was a silent no-op, which hid the missing initialization.
Initialize reset_work once in ffs_data_new() so it is always valid for the lifetime of the ffs_data, and drop the now-redundant INIT_WORK() calls from the two deactivation paths.
--- drivers/usb/gadget/function/f_fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/gadget/function/f_fs.c +2 -2
@@ -288,6 +288,7 @@ static int ffs_acquire_dev(const char *dstatic void ffs_release_dev (struct ffs_dev *ffs_dev);static int ffs_ready (struct ffs_data *ffs);static void ffs_closed (struct ffs_data *ffs); +static void ffs_reset_work (struct work_struct *work);/* Misc helper functions ****************************************************/
@@ -2221,6 +2222,7 @@ static struct ffs_data *ffs_data_new(coninit_waitqueue_head (&ffs->ev.waitq);init_waitqueue_head (&ffs->wait);init_completion (&ffs->ep0req_completion); +INIT_WORK (&ffs->reset_work, ffs_reset_work);/* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall =1 ;
@@ -3775,7 +3777,6 @@ static int ffs_func_set_alt(struct usb_fif (ffs->state ==FFS_DEACTIVATED ) { ffs->state =FFS_CLOSING ;spin_unlock_irqrestore (&ffs->eps_lock, flags); -INIT_WORK (&ffs->reset_work, ffs_reset_work);schedule_work (&ffs->reset_work);return -ENODEV ; }
@@ -3806,7 +3807,6 @@ static void ffs_func_disable(struct usb_if (ffs->state ==FFS_DEACTIVATED ) { ffs->state =FFS_CLOSING ;spin_unlock_irqrestore (&ffs->eps_lock, flags); -INIT_WORK (&ffs->reset_work, ffs_reset_work);schedule_work (&ffs->reset_work);return ; }
Greg Kroah-Hartman
maintainerPATCH 337/518 usb: gadget: f_fs: Fix DMA fence leak
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Cercueil <[email protected]>
commit baa6b6068a3f2bf2ed525a1cb37975905dadc658 upstream.
In ffs_dmabuf_transfer(), a ffs_dma_fence object is kmalloc'd, with the underlying dma_fence later initialized by dma_fence_init(), which sets its kref counter to 1. Then, dma_resv_add_fence() gets a second reference, and a pointer to the ffs_dma_fence is passed as the usb_request's "context" field.
The dma-resv mechanism will manage the second reference, but the first reference is never properly released; the ffs_dmabuf_cleanup() function decreases the reference count, but only to balance with the reference grab in ffs_dmabuf_signal_done().
The code will then slowly leak memory as more ffs_dma_fence objects are created without being ever freed.
Address this issue by transferring ownership of the fence to the DMA reservation object, by calling dma_fence_put() right after dma_resv_add_fence(). The ffs_dma_fence then gets properly discarded after being signalled.
--- drivers/usb/gadget/function/f_fs.c | 1 + 1 file changed, 1 insertion(+)
drivers/usb/gadget/function/f_fs.c +1 -0
@@ -1705,6 +1705,7 @@ static int ffs_dmabuf_transfer(struct fi resv_dir = epfile->in ?DMA_RESV_USAGE_READ :DMA_RESV_USAGE_WRITE ;dma_resv_add_fence (dmabuf->resv, &fence->base, resv_dir); +dma_fence_put (&fence->base);dma_resv_unlock (dmabuf->resv);/* Now that the dma_fence is in place, queue the transfer. */
Greg Kroah-Hartman
maintainerPATCH 338/518 usb: gadget: f_fs: Initialize epfile->in early to fix endpoint direction checks
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Neill Kapron <[email protected]>
commit 82cfd4739011bdc7e87b5d585703427e89ddfaa5 upstream.
When parsing endpoint descriptors, ffs_data_got_descs() generates the eps_addrmap which contains the endpoint direction. However, epfile->in was previously only populated in ffs_func_eps_enable() which executes upon USB host connection. As a result, early userspace ioctls like FUNCTIONFS_DMABUF_ATTACH that run before the host connects would see epfile->in as 0, leading to incorrect DMA directions.
By moving the initialization to ffs_epfiles_create(), epfile->in is accurate before userspace opens the endpoint files.
--- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_fs.c +1 -1
@@ -2367,6 +2367,7 @@ static int ffs_epfiles_create(struct ffssprintf (epfile->name,"ep%02x" , ffs->eps_addrmap[i]); else sprintf(epfile->name, "ep%u", i); + epfile->in = (ffs->eps_addrmap[i] &USB_ENDPOINT_DIR_MASK ) ?1 :0 ; err =ffs_sb_create_file (ffs->sb, epfile->name, epfile, &ffs_epfile_operations);if (err) {
@@ -2456,7 +2457,6 @@ static int ffs_func_eps_enable(struct ff ret =usb_ep_enable (ep->ep);if (!ret) { epfile->ep = ep; - epfile->in =usb_endpoint_dir_in (ep->ep->desc); epfile->isoc =usb_endpoint_xfer_isoc (ep->ep->desc); }else {break ;
Greg Kroah-Hartman
maintainerPATCH 339/518 usb: gadget: f_fs: Tie read_buffer lifetime to ffs_epfile
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Neill Kapron <[email protected]>
commit 8bdcf96eb135aebacac319667f87db034fb38406 upstream.
Currently, ffs_epfile_release unconditionally frees the endpoint's read_buffer when a file descriptor is closed. If userspace explicitly opens the endpoint multiple times and closes one, the read_buffer is destroyed. This can lead to silent data loss if other file descriptors are still actively reading from the endpoint.
By tying the lifetime of the read_buffer to the ffs_epfile structure itself (which is destroyed when the functionfs instance is torn down in ffs_epfiles_destroy), we eliminate the brittle dependency on open/release calls while correctly matching the conceptual lifetime of unread data on the hardware endpoint.
--- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_fs.c +1 -1
@@ -1375,7 +1375,6 @@ ffs_epfile_release(struct inode *inode,mutex_unlock (&epfile->dmabufs_mutex); -__ffs_epfile_read_buffer_free (epfile);ffs_data_closed (epfile->ffs);return 0 ;
@@ -2393,6 +2392,7 @@ static void ffs_epfiles_destroy(struct sfor (; count; --count, ++epfile) {BUG_ON (mutex_is_locked (&epfile->mutex)); +__ffs_epfile_read_buffer_free (epfile);simple_remove_by_name (root, epfile->name, clear_one); }
Greg Kroah-Hartman
maintainerPATCH 340/518 block: skip sync_blockdev() on surprise removal in bdev_mark_dead()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Shi <[email protected]>
commit 49f06cff50a4ccf3b7a1a662ceb892b3b21a527a upstream.
bdev_mark_dead()'s @surprise == true means the device is already gone. The filesystem callback fs_bdev_mark_dead() honours this and skips sync_filesystem(), but the bare block device path (no ->mark_dead op) lost its !surprise guard when the holder ->mark_dead callback was wired up (see Fixes), and now calls sync_blockdev() unconditionally, which can hang forever waiting on writeback that can no longer complete.
syzkaller hit this via nvme_reset_work()'s "I/O queues lost" path:nvme_mark_namespaces_dead() -> blk_mark_disk_dead() -> bdev_mark_dead(bdev, true) -> sync_blockdev() blocks in folio_wait_writeback(), wedging the reset worker and every task waiting on it.
Skip the sync on surprise removal, matching fs_bdev_mark_dead(); invalidate_bdev() still runs. Orderly removal (surprise == false) is unchanged.
Found by FuzzNvme(Syzkaller with FEMU fuzzing framework).
--- block/bdev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
block/bdev.c +7 -1
@@ -1245,7 +1245,13 @@ void bdev_mark_dead(struct block_device bdev->bd_holder_ops->mark_dead (bdev, surprise); else {mutex_unlock (&bdev->bd_holder_lock); -sync_blockdev (bdev); +/* +* On surprise removal the device is already gone; syncing is +* futile and can hang forever waiting on I/O that will never +* complete. Match fs_bdev_mark_dead(), which also skips it. +*/ +if (!surprise) +sync_blockdev (bdev); }invalidate_bdev (bdev);
Greg Kroah-Hartman
maintainerPATCH 341/518 wifi: mt76: mt7921/mt7925: fix NULL dereference in CSA beacon
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arjan van de Ven <[email protected]>
[ Upstream commit 351dd7d2c80d23e56dcce6faa4e62bea5b0877c7 ]
This patch is based on a BUG as reported by Bongani Hlope at
https://lore.kernel.org/all/[email protected]/
When a channel-switch announcement (CSA) beacon is received, cfg80211 queues a wiphy work item that eventually calls mt7921_channel_switch_rx_beacon(). If the station disconnects (or the channel context is otherwise torn down) between the time the work is queued and the time it runs, the driver's dev->new_ctx pointer can already have been cleared to NULL. mt7921_channel_switch_rx_beacon() then dereferences new_ctx unconditionally, triggering a NULL pointer dereference at address 0x0:
BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: 0010:mt7921_channel_switch_rx_beacon+0x1f/0x100 [mt7921_common]
The same missing guard exists in mt7925_channel_switch_rx_beacon(), which shares the same code pattern introduced by the same commit.
Add an early-return NULL check for dev->new_ctx in both mt7921_channel_switch_rx_beacon() and mt7925_channel_switch_rx_beacon(). When new_ctx is NULL there is no pending channel switch to process, so returning immediately is the correct and safe action.
Oops-Analysis: http://oops.fenrus.org/reports/lkml/[email protected]/report.html
--- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7925/main.c | 3 +++ 2 files changed, 6 insertions(+)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +3 -0
@@ -1508,6 +1508,9 @@ static void mt7921_channel_switch_rx_beacon(struct ieee80211_hw *hw,struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;u16 beacon_interval = vif->bss_conf.beacon_int; +if (!dev->new_ctx) +return ; +if (cfg80211_chandef_identical (&chsw->chandef, &dev->new_ctx->def) && chsw->count) {
drivers/net/wireless/mediatek/mt76/mt7925/main.c +3 -0
@@ -2403,6 +2403,9 @@ static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,if (ieee80211_vif_is_mld (vif))return ; +if (!dev->new_ctx) +return ; + beacon_interval = vif->bss_conf.beacon_int; if (cfg80211_chandef_identical(&chsw->chandef,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 342/518 udf: validate free block extents against the partition length
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 5f0419457f89dce1a3f1c8e62a3adf2f39ab8168 upstream.
udf_free_blocks() checks the logical block number and count against the partition length, but drops the extent offset from that final bound. A crafted extent can pass the guard while logicalBlockNum + offset + count points past the partition, which later indexes past the space bitmap array.
A single ftruncate(2) on a file backed by such an extent reliably panics the kernel. This is a local availability issue. On desktop systems where UDisks/polkit allows the active user to mount removable UDF media without CAP_SYS_ADMIN, an unprivileged local user can supply the crafted filesystem and trigger the panic by truncating a writable file on it. Systems that require root or CAP_SYS_ADMIN to mount the image have a higher prerequisite.
No confidentiality or integrity impact is claimed: the reproduced primitive is an out-of-bounds read of a bitmap pointer slot followed by a kernel panic.
Use the already computed logicalBlockNum + offset + count value for the partition length check. Also make load_block_bitmap() reject an out-of-range block group before indexing s_block_bitmap[], so corrupted callers cannot walk past the flexible array.
--- fs/udf/balloc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/udf/balloc.c +3 -2
@@ -82,8 +82,9 @@ static int load_block_bitmap(struct supeint nr_groups = bitmap->s_nr_groups;if (block_group >= nr_groups) { -udf_debug ("block_group (%u) > nr_groups (%d)\n" , +udf_debug ("block_group (%u) >= nr_groups (%d)\n" , block_group, nr_groups); +return -EFSCORRUPTED ; }if (bitmap->s_block_bitmap[block_group]) {
@@ -662,7 +663,7 @@ void udf_free_blocks(struct super_blockif (check_add_overflow (bloc->logicalBlockNum, offset, &blk) ||check_add_overflow (blk, count, &blk) || - bloc->logicalBlockNum + count > map->s_partition_len) { + blk > map->s_partition_len) { udf_debug("Invalid request to free blocks: (%d, %u), off %u, " "len %u, partition len %u\n", partition, bloc->logicalBlockNum, offset, count,
Greg Kroah-Hartman
maintainerPATCH 343/518 udf: validate VAT header length against the VAT inode size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit d8202786b3d75125c84ebc4de6d946f92fde0ee8 upstream.
udf_load_vat() takes the virtual partition's start offset straight from the on-disk VAT 2.0 header without checking it against the VAT inode size:
map->s_type_specific.s_virtual.s_start_offset = le16_to_cpu(vat20->lengthHeader); map->s_type_specific.s_virtual.s_num_entries = (sbi->s_vat_inode->i_size - map->s_type_specific.s_virtual.s_start_offset) >> 2;
lengthHeader is a fully attacker-controlled 16-bit value. If it exceeds the VAT inode size, the s_num_entries subtraction underflows to a huge count, which defeats the "block > s_num_entries" bound in udf_get_pblock_virt15(); and on the ICB-inline path that function reads
((__le32 *)(iinfo->i_data + s_start_offset))[block]
so a large s_start_offset indexes past the inode's in-ICB data. Mounting a crafted UDF image with a virtual (VAT) partition then triggers an out-of-bounds read.
Reject a VAT whose header length does not leave room for at least one entry within the VAT inode.
--- fs/udf/super.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/udf/super.c +8 -0
@@ -1263,6 +1263,14 @@ static int udf_load_vat(struct super_blo map->s_type_specific.s_virtual.s_start_offset =le16_to_cpu (vat20->lengthHeader); +if (map->s_type_specific.s_virtual.s_start_offset + > sbi->s_vat_inode->i_size) { +udf_err (sb,"Corrupted VAT header length %u (VAT inode size %lld)\n" , + map->s_type_specific.s_virtual.s_start_offset, + sbi->s_vat_inode->i_size); +brelse (bh); +return -EFSCORRUPTED ; + } map->s_type_specific.s_virtual.s_num_entries = (sbi->s_vat_inode->i_size - map->s_type_specific.s_virtual.
Greg Kroah-Hartman
maintainerPATCH 344/518 udf: validate sparing table length as an entry count, not a byte count
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 3ec997bd5508e9b25210b5bbec89031629cdb093 upstream.
udf_load_sparable_map() accepts a sparing table when
sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > sb->s_blocksize
is false, i.e. it treats reallocationTableLen as a number of BYTES that must fit in the block. But the table is walked as an array of 8-byte sparingEntry elements:
for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
struct sparingEntry *entry = &st->mapEntry[i];
... entry->origLocation ...
}in udf_get_pblock_spar15() and udf_relocate_blocks(). A reallocationTableLen of N therefore passes the check whenever sizeof(*st) + N <= blocksize, yet the consumers index sizeof(*st) + N * sizeof(struct sparingEntry) bytes -- up to ~8x the block. On a crafted UDF image this is an out-of-bounds read in udf_get_pblock_spar15(); udf_relocate_blocks() additionally feeds the same length to udf_update_tag(), whose crc_itu_t() reads far past the block, and its memmove() through st->mapEntry[] is an out-of-bounds write.
Validate reallocationTableLen as the entry count it is, with struct_size().
--- fs/udf/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/udf/super.c +2 -1
@@ -1426,7 +1426,8 @@ static int udf_load_sparable_map(structif (ident !=0 ||strncmp (st->sparingIdent.ident,UDF_ID_SPARING ,strlen (UDF_ID_SPARING )) || -sizeof (*st) +le16_to_cpu (st->reallocationTableLen) > +struct_size (st, mapEntry, +le16_to_cpu (st->reallocationTableLen)) > sb->s_blocksize) {brelse (bh);continue ;
Greg Kroah-Hartman
maintainerPATCH 345/518 hwrng: jh7110 - fix refcount leak in starfive_trng_read()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 8d13f7a8450206e3f820cdb26e33e91d181071b4 upstream.
The starfive_trng_read() function acquires a runtime PM reference via pm_runtime_get_sync() but fails to release it on two error paths. If starfive_trng_wait_idle() or starfive_trng_cmd() returns an error, the function exits without calling pm_runtime_put_sync_autosuspend(), leaving the runtime PM usage counter permanently elevated and preventing the device from entering runtime suspend.
Refactor the function to use a unified error path that calls pm_runtime_put_sync_autosuspend() before returning.
--- drivers/char/hw_random/jh7110-trng.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/char/hw_random/jh7110-trng.c +8 -5
@@ -256,19 +256,22 @@ static int starfive_trng_read(struct hwrif (wait) { ret =starfive_trng_wait_idle (trng); -if (ret) -return -ETIMEDOUT ; +if (ret) { + ret = -ETIMEDOUT ; + goto out_put; + } } ret =starfive_trng_cmd (trng,STARFIVE_CTRL_GENE_RANDNUM , wait);if (ret) -return ret; + goto out_put;memcpy_fromio (buf, trng->base +STARFIVE_RAND0 , max); + ret = max; +out_put:pm_runtime_put_sync_autosuspend (trng->dev); - -return max; +return ret; }static int starfive_trng_probe (struct platform_device *pdev)
Greg Kroah-Hartman
maintainerPATCH 346/518 crypto: atmel-sha204a - drop hwrng quality reduction for ATSHA204A
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit ea5e57cc97185329dcc5ebdcaae7e1500bf0ad0b upstream.
Commit 8006aff15516 ("crypto: atmel-sha204a - Set hwrng quality to lowest possible") reduced the hwrng quality to 1 based on a review by Bill Cox [1]. However, despite its title, the review only tested the ATSHA204, not the ATSHA204A.
In the same thread, Atmel engineer Landon Cox wrote "this behavior has been eliminated entirely"[2] in the ATSHA204A and "this problem does not affect the ATECC108 or the ATECC108A (or the ATSHA204A)"[3].
According to the official ATSHA204A datasheet [4], the device contains a high-quality hardware RNG that combines its output with an internal seed value stored in EEPROM or SRAM to generate random numbers. The device also implements all security functions using SHA-256, and the driver uses the chip's Random command in seed-update mode.
Keep 'quality = 1' for ATSHA204, but drop the explicit hwrng quality reduction for ATSHA204A and fall back to the hwrng core default.
[1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html
[2] https://www.metzdowd.com/pipermail/cryptography/2014-December/023852.html
[3] https://www.metzdowd.com/pipermail/cryptography/2014-December/023886.html
[4] https://ww1.microchip.com/downloads/en/DeviceDoc/ATSHA204A-Data-Sheet-40002025A.pdf
--- drivers/crypto/atmel-sha204a.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/crypto/atmel-sha204a.c +12 -7
@@ -19,6 +19,12 @@#include <linux/workqueue.h> #include "atmel-i2c.h" +/* +* According to review by Bill Cox [1], the ATSHA204 has very low entropy. +* [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html +*/ +static const unsigned short atsha204_quality =1 ; +static void atmel_sha204a_rng_done (struct atmel_i2c_work_data *work_data,void *areq,int status) {
@@ -158,6 +164,7 @@ static const struct attribute_group atmestatic int atmel_sha204a_probe (struct i2c_client *client) {struct atmel_i2c_client_priv *i2c_priv; +const unsigned short *quality;int ret; ret =atmel_i2c_probe (client);
@@ -171,11 +178,9 @@ static int atmel_sha204a_probe(struct i2 i2c_priv->hwrng.name =dev_name (&client->dev); i2c_priv->hwrng.read = atmel_sha204a_rng_read; -/* -* According to review by Bill Cox [1], this HWRNG has very low entropy. -* [1] https://www.metzdowd.com/pipermail/cryptography/2014-December/023858.html -*/ - i2c_priv->hwrng.quality =1 ; + quality =i2c_get_match_data (client); +if (quality) + i2c_priv->hwrng.quality = *quality; ret =devm_hwrng_register (&client->dev, &i2c_priv->hwrng);if (ret)
@@ -203,14 +208,14 @@ static void atmel_sha204a_remove(struct }static const struct of_device_id atmel_sha204a_dt_ids[]__maybe_unused = { - { .compatible ="atmel,atsha204" , }, + { .compatible ="atmel,atsha204" , .data = &atsha204_quality }, { .compatible ="atmel,atsha204a" , }, {/* sentinel */ } };MODULE_DEVICE_TABLE (of, atmel_sha204a_dt_ids);static const struct i2c_device_id atmel_sha204a_id[] = { - {"atsha204" }, + {"atsha204" , (kernel_ulong_t)&atsha204_quality }, {"atsha204a" }, {/* sentinel */ } };
Greg Kroah-Hartman
maintainerPATCH 347/518 crypto: atmel-sha204a - fail on hwrng registration error in probe path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 49e05bb00f2e8168695f7af4d694c39e1423e8a2 upstream.
Commit 13909a0c8897 ("crypto: atmel-sha204a - provide the otp content") overwrote the hwrng registration return value when creating the sysfs group, which allowed atmel_sha204a_probe() to succeed even if devm_hwrng_register() failed.
Return immediately when devm_hwrng_register() fails, and report both hwrng and sysfs registration errors with dev_err(). Adjust the sysfs error log message for consistency.
--- drivers/crypto/atmel-sha204a.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/crypto/atmel-sha204a.c +5 -3
@@ -183,12 +183,14 @@ static int atmel_sha204a_probe(struct i2 i2c_priv->hwrng.quality = *quality; ret =devm_hwrng_register (&client->dev, &i2c_priv->hwrng); -if (ret) -dev_warn (&client->dev,"failed to register RNG (%d)\n" , ret); +if (ret) { +dev_err (&client->dev,"failed to register RNG (%d)\n" , ret); +return ret; + } ret =sysfs_create_group (&client->dev.kobj, &atmel_sha204a_groups);if (ret) { -dev_err (&client->dev,"failed to register sysfs entry\n" ); +dev_err (&client->dev,"failed to create sysfs group (%d)\n" , ret);return ret; }
Greg Kroah-Hartman
maintainerPATCH 348/518 nvme: target: rdma: fix ndev refcount leak on queue connect
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit badc53620fe813b3a9f727ef9526f98567c2c898 upstream.
nvmet_rdma_queue_connect() calls nvmet_rdma_find_get_device() which acquires a reference on the returned ndev via kref_get(). On the path where the host queue backlog is exceeded and the function returns NVME_SC_CONNECT_CTRL_BUSY, reference of ndev is not released, leaking the kref.
Fix this by adding a goto to the existing put_device label before the early return.
--- drivers/nvme/target/rdma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/nvme/target/rdma.c +4 -2
@@ -1598,8 +1598,10 @@ static int nvmet_rdma_queue_connect(stru pending++; }mutex_unlock (&nvmet_rdma_queue_mutex); -if (pending >NVMET_RDMA_BACKLOG ) -return NVME_SC_CONNECT_CTRL_BUSY ; +if (pending >NVMET_RDMA_BACKLOG ) { + ret =NVME_SC_CONNECT_CTRL_BUSY ; + goto put_device; + } } ret =nvmet_rdma_cm_accept (cm_id, queue, &event->param.conn);
Greg Kroah-Hartman
maintainerPATCH 349/518 block: partitions: fix of_node refcount leak in of_partition()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 148cd4873115feb266c002d4d4618ea7f14342d9 upstream.
of_partition() calls of_node_get() on the parent device node at the beginning of the function, storing the reference in 'partitions_np'. This reference is leaked in two paths:
1. The compatibility check at the top of the function returns 0 without releasing partitions_np when the node exists but is not "fixed-partitions" compatible.
2. The function returns 1 at the end after successfully processing all partitions without releasing partitions_np.
Fix both leaks by adding of_node_put(partitions_np) on each path.
--- block/partitions/of.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
block/partitions/of.c +4 -1
@@ -74,8 +74,10 @@ int of_partition(struct parsed_partitionstruct device_node *partitions_np =of_node_get (ddev->of_node);if (!partitions_np || - !of_device_is_compatible (partitions_np,"fixed-partitions" )) + !of_device_is_compatible (partitions_np,"fixed-partitions" )) { +of_node_put (partitions_np);return 0 ; + } slot =1 ;/* Validate parition offset and size */
@@ -104,5 +106,6 @@ int of_partition(struct parsed_partitionseq_buf_puts (&state->pp_buf,"\n" ); +of_node_put (partitions_np);return 1 ; }
Greg Kroah-Hartman
maintainerPATCH 350/518 dm-ioctl: report an error if a device has no table
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit 457e32348d606a77f9b20e25e989734189834c07 upstream.
When we send a message to a device that has no table, the return code was not set. The code would return "2", which is not considered a valid return value.
--- drivers/md/dm-ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/md/dm-ioctl.c +4 -1
@@ -1816,8 +1816,11 @@ static int target_message(struct file *f goto out_argv; table =dm_get_live_table (md, &srcu_idx); -if (!table) +if (!table) { +DMERR ("The device has no table." ); + r = -EINVAL ; goto out_table; + }if (dm_deleting_md (md)) { r = -ENXIO ;
Greg Kroah-Hartman
maintainerPATCH 351/518 nvme-multipath: set BIO_REMAPPED on bios remapped to per-path namespace disks
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Achkinazi, Igor <[email protected]>
commit 88bac2c1a72b8f4f71e9845699aa872df04e5850 upstream.
When nvme_ns_head_submit_bio() remaps a bio from the multipath head to a per-path namespace, bio_set_dev() clears BIO_REMAPPED. The remapped bio is then resubmitted through submit_bio_noacct() which calls bio_check_eod() because BIO_REMAPPED is not set.
This races with nvme_ns_remove() which zeroes the per-path capacity before synchronize_srcu():
CPU 0 (IO submission)
---------------------
srcu_read_lock()
nvme_find_path() -> ns
[NVME_NS_READY is set]
CPU 1 (namespace removal)
-------------------------
clear_bit(NVME_NS_READY)
set_capacity(ns->disk, 0)
synchronize_srcu() <- blocks
CPU 0 (IO submission)
---------------------
bio_set_dev(bio, ns->disk->part0)
[clears BIO_REMAPPED]
submit_bio_noacct(bio)
-> bio_check_eod() sees capacity=0
-> bio fails with IO errorThe SRCU read lock prevents synchronize_srcu() from completing, but does not prevent set_capacity(0) from executing. The bio fails the EOD check before it reaches the NVMe driver, so nvme_failover_req() never gets a chance to redirect it to another path of multipath. IO errors are reported to the application despite another path being available.
On older kernels (before commit 0b64682e78f7 "block: skip unnecessary checks for split bio"), the same race was also reachable through split remainders resubmitted via submit_bio_noacct().
Fix this by setting BIO_REMAPPED after bio_set_dev() in nvme_ns_head_submit_bio(). This skips bio_check_eod() on the per-path device; the EOD check already passed on the multipath head.
NVMe per-path namespace devices are always whole disks (bd_partno=0), so the blk_partition_remap() skip also gated by BIO_REMAPPED is a no-op. The flag does not persist across failover and cannot go stale if the namespace geometry changes between attempts: nvme_failover_req() calls bio_set_dev() to redirect the bio back to the multipath head, which clears BIO_REMAPPED. When nvme_requeue_work() resubmits through submit_bio_noacct(), bio_check_eod() runs normally against the current capacity.
Same approach as commit 3a905c37c351 ("block: skip bio_check_eod for partition-remapped bios").
--- drivers/nvme/host/multipath.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/nvme/host/multipath.c +6 -0
@@ -511,6 +511,12 @@ static void nvme_ns_head_submit_bio(stru ns =nvme_find_path (head);if (likely (ns)) {bio_set_dev (bio, ns->disk->part0); +/* +* Use BIO_REMAPPED to skip bio_check_eod() when this bio +* enters submit_bio_noacct() for the per-path device. The EOD +* check already passed on the multipath head. +*/ +bio_set_flag (bio,BIO_REMAPPED ); bio->bi_opf |=REQ_NVME_MPATH ;trace_block_bio_remap (bio,disk_devt (ns->head->disk), bio->bi_iter.bi_sector);
Greg Kroah-Hartman
maintainerPATCH 352/518 nvmet: fix pre-auth out-of-bounds heap read in Discovery Get Log Page
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 53cd102a7a56079b11b897835bd9b94c14e6322c upstream.
nvmet_execute_disc_get_log_page() validates only the dword alignment of the host-supplied Log Page Offset (lpo). The 64-bit offset is then added to a small kzalloc'd buffer that holds the discovery log page and the result is passed straight to nvmet_copy_to_sgl(), which memcpy()s data_len bytes out to the host with no source-side bound check:
u64 offset = nvmet_get_log_page_offset(req->cmd); /* 64-bit host */
size_t data_len = nvmet_get_log_page_len(req->cmd); /* 32-bit host */
...
if (offset & 0x3) { ... } /* only check */
...
alloc_len = sizeof(*hdr) + entry_size * discovery_log_entries(req);
buffer = kzalloc(alloc_len, GFP_KERNEL);
...
status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);The Discovery controller is unauthenticated -- nvmet_host_allowed() returns true unconditionally for the discovery subsystem -- so the call is reachable pre-authentication by any TCP/RDMA/FC peer that can reach the nvmet target. With a discovery log page of ~1 KiB, an attacker requesting up to 4 KiB starting at offset == alloc_len reads the next slab page out and gets its content returned over the fabric (an empirical run on a default nvmet-tcp loopback target leaked 81 canonical kernel pointers in one Get Log Page response). Pointing the offset at unmapped kernel memory faults the in-kernel memcpy and crashes (or panics, on panic_on_oops=1) the target host instead.
The attacker-controlled source-side offset pattern "nvmet_copy_to_sgl(req, 0, buffer + ATTACKER_OFFSET, ...)" is unique to nvmet_execute_disc_get_log_page in the entire nvmet codebase: every other Get Log Page handler in admin-cmd.c either ignores lpo (and silently starts every response at offset 0) or tracks a local destination offset with a fixed source pointer.
Validate the host-supplied offset against the log page size, cap the copy length to what is actually available, and zero-fill any remainder of the host transfer buffer. The zero-fill matches the existing short-response pattern in nvmet_execute_get_log_changed_ns() (admin-cmd.c) and prevents leaking transport SGL contents when the host asks for more bytes than the log page contains.
--- drivers/nvme/target/discovery.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
drivers/nvme/target/discovery.c +22 -1
@@ -166,6 +166,7 @@ static void nvmet_execute_disc_get_log_pu64 offset =nvmet_get_log_page_offset (req->cmd);size_t data_len =nvmet_get_log_page_len (req->cmd);size_t alloc_len; +size_t copy_len;struct nvmet_subsys_link *p;struct nvmet_port *r;u32 numrec =0 ;
@@ -242,7 +243,27 @@ static void nvmet_execute_disc_get_log_pup_read (&nvmet_config_sem); - status =nvmet_copy_to_sgl (req,0 , buffer + offset, data_len); +/* +* Validate the host-supplied log page offset before copying out. +* Without this check, the host controls a 64-bit byte offset into +* a small kzalloc'd buffer: a value past the log page lets the +* subsequent memcpy read adjacent kernel heap, and a value aimed +* at unmapped kernel memory faults the in-kernel copy and crashes +* the target host. The Discovery controller is unauthenticated, +* so the bug is reachable from any reachable fabric peer. +*/ +if (offset > alloc_len) { + req->error_loc = + offsetof(struct nvme_get_log_page_command , lpo); + status =NVME_SC_INVALID_FIELD |NVME_STATUS_DNR ; + goto out_free_buffer; + } + + copy_len =min_t (size_t, data_len, alloc_len - offset); + status =nvmet_copy_to_sgl (req,0 , buffer + offset, copy_len); +if (!status && copy_len < data_len) + status =nvmet_zero_sgl (req, copy_len, data_len - copy_len); +out_free_buffer:kfree (buffer); out:nvmet_req_complete (req, status);
Greg Kroah-Hartman
maintainerPATCH 353/518 btrfs: fix false IO failure after falling back to buffered write
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit 66ff4d366e7eb4d31813d2acabf3af512ce03aa5 upstream.
[BUG]
The test case generic/362 will fail with "nodatasum" mount option (*):
MOUNT_OPTIONS -- -o nodatasum /dev/mapper/test-scratch1 /mnt/scratch
# generic/362 0s ... - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad) # --- tests/generic/362.out 2024-08-24 15:31:37.200000000 +0930 # +++ /home/adam/xfstests/results//generic/362.out.bad 2026-05-27 10:21:17.574771567 +0930 # @@ -1,2 +1,3 @@ # QA output created by 362 # +First write failed: Input/output error # Silence is golden # ...
*: If the test case has been executed before with default data checksum, the failure will not reproduce. Need the following fix to make it reliably reproducible:
https://lore.kernel.org/linux-btrfs/[email protected]/
[CAUSE]
Inside __iomap_dio_rw(), the -EFAULT/-ENOTBLK error is not directly returned. Thus we never got an error pointer from __iomap_dio_rw().
The call chain looks like this:
btrfs_direct_write()
|- btrfs_dio_write()
|- __iomap_dio_rw()
| |- iomap_iter()
| | |- btrfs_dio_iomap_begin()
| | Now an ordered extent is allocated for the 4K write.
| |
| |- iomi.status = iomap_dio_iter()
| | Where iomap_dio_iter() returned -EFAULT.
| |
| |- ret = iomap_iter()
| | |- btrfs_dio_iomap_end()
| | | |- btrfs_finish_ordered_extent(uptodate = false)
| | | | |- can_finish_ordered_extent()
| | | | |- btrfs_mark_ordered_extent_error()
| | | | |- mapping_set_error()
| | | | Now the address space is marked error.
| | | | return -ENOTBLK
| | |- return -ENOTBLK
| |- if (ret == -ENOTBLK) { ret = 0; }
| Now the return value is reset to 0.
| Thus no error pointer will be returned.
|
|- ret = iomap_dio_complete()
| Since no byte is submitted, @ret is 0.
|
|- Fallback to buffered IO
| And the buffered write finished without error
|
|- filemap_fdatawait_range() |- filemap_check_errors()
The previous error is recorded, thus an error is returned
However the buffered write is properly submitted and finished, the error is from the btrfs_finish_ordered_extent() call with @uptodate = false.
[FIX]
When a short dio write happened, any range that is submitted will have btrfs_extract_ordered_extent() to be called, thus the submitted range will always have an OE just covering the submitted range.
The remaining OE range is never submitted, thus they should be treated as truncated, not an error. So that we can properly reclaim and not insert an unnecessary file extent item, without marking the mapping as error.
Extract a helper, btrfs_mark_ordered_extent_truncated(), and utilize that helper to mark the direct IO ordered extent as truncated, so it won't cause failure for the later buffered fallback.
[REASON FOR NO FIXES TAG]
The bug itself is pretty old, at commit f85781fb505e ("btrfs: switch to iomap for direct IO") we're already passing @uptodate=false finishing the OE.
But at that time OE with IOERR won't call mapping_set_error(), so it's not exposed.
Later commit d61bec08b904 ("btrfs: mark ordered extent and inode with error if we fail to finish") finally exposed the bug, but that commit is doing a correct job, not the root cause.
Anyway the bug is very old, dating back to 5.1x days, thus only CC to stable.
--- fs/btrfs/direct-io.c | 17 ++++++++++++++--- fs/btrfs/inode.c | 6 +----- fs/btrfs/ordered-data.c | 12 ++++++++++++ fs/btrfs/ordered-data.h | 2 ++ 4 files changed, 29 insertions(+), 8 deletions(-)
fs/btrfs/direct-io.c +14 -3
@@ -624,12 +624,23 @@ static int btrfs_dio_iomap_end(struct inif (submitted < length) { pos += submitted; length -= submitted; -if (write) +if (write) { +/* +* We have a short write, if there is any range +* that is submitted properly, that part will have +* its own OE split from the original one. +* +* So for the OE at dio_data->ordered, it's the part +* that is not submitted, and should be marked +* as fully truncated. +*/ +btrfs_mark_ordered_extent_truncated (dio_data->ordered,0 );btrfs_finish_ordered_extent (dio_data->ordered, - pos, length, false); -else + pos, length, true); + }else {btrfs_unlock_dio_extent (&BTRFS_I (inode)->io_tree, pos, pos + length -1 ,NULL ); + } ret = -ENOTBLK ; }if (write) {
fs/btrfs/inode.c +1 -5
@@ -7776,11 +7776,7 @@ static void btrfs_invalidate_folio(strucEXTENT_LOCKED |EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, &cached_state); -spin_lock (&inode->ordered_tree_lock); -set_bit (BTRFS_ORDERED_TRUNCATED , &ordered->flags); - ordered->truncated_len =min (ordered->truncated_len, - cur - ordered->file_offset); -spin_unlock (&inode->ordered_tree_lock); +btrfs_mark_ordered_extent_truncated (ordered, cur - ordered->file_offset);/* * If the ordered extent has finished, we're safe to delete all
fs/btrfs/ordered-data.c +12 -0
@@ -357,6 +357,18 @@ void btrfs_mark_ordered_extent_error(strmapping_set_error (ordered->inode->vfs_inode.i_mapping, -EIO ); } +void btrfs_mark_ordered_extent_truncated (struct btrfs_ordered_extent *ordered, +u64 truncate_len) +{ +struct btrfs_inode *inode = ordered->inode; + +ASSERT (truncate_len <= ordered->num_bytes); +spin_lock (&inode->ordered_tree_lock); +set_bit (BTRFS_ORDERED_TRUNCATED , &ordered->flags); + ordered->truncated_len =min (ordered->truncated_len, truncate_len); +spin_unlock (&inode->ordered_tree_lock); +} +static void finish_ordered_fn (struct btrfs_work *work) {struct btrfs_ordered_extent *ordered_extent;
fs/btrfs/ordered-data.h +2 -0
@@ -226,6 +226,8 @@ bool btrfs_try_lock_ordered_range(structstruct btrfs_ordered_extent *btrfs_split_ordered_extent (struct btrfs_ordered_extent *ordered,u64 len);void btrfs_mark_ordered_extent_error (struct btrfs_ordered_extent *ordered); +void btrfs_mark_ordered_extent_truncated (struct btrfs_ordered_extent *ordered, +u64 truncate_len);int __init ordered_data_init (void );void __cold ordered_data_exit (void );
Greg Kroah-Hartman
maintainerPATCH 354/518 nvmet-auth: validate reply message payload bounds against transfer length
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tianchu Chen <[email protected]>
commit 3a413ece2504c70aa34a20be4dafec04e8c741f9 upstream.
nvmet_auth_reply() accesses the variable-length rval[] array using attacker-controlled hl (hash length) and dhvlen (DH value length) fields without verifying they fit within the allocated buffer of tl bytes.
A malicious NVMe-oF initiator can craft a DHCHAP_REPLY message with a small transfer length but large hl/dhvlen values, causing out-of-bounds heap reads when the target processes the DH public key (rval + 2*hl) or performs the host response memcmp.
With DH authentication configured, the OOB pointer is passed directly to sg_init_one() and read by crypto_kpp_compute_shared_secret(), reaching up to 526 bytes past the buffer. This is exploitable pre-authentication.
Add bounds validation ensuring sizeof(*data) + 2*hl + dhvlen <= tl before any access to the variable-length fields.
Discovered by Atuin - Automated Vulnerability Discovery Engine.
--- drivers/nvme/target/fabrics-cmd-auth.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/nvme/target/fabrics-cmd-auth.c +12 -3
@@ -132,13 +132,22 @@ static u8 nvmet_auth_negotiate(struct nvreturn 0 ; } -static u8 nvmet_auth_reply (struct nvmet_req *req,void *d) +static u8 nvmet_auth_reply (struct nvmet_req *req,void *d,u32 tl) {struct nvmet_ctrl *ctrl = req->sq->ctrl;struct nvmf_auth_dhchap_reply_data *data = d; -u16 dhvlen =le16_to_cpu (data->dhvlen); +u16 dhvlen;u8 *response; +if (tl <sizeof (*data)) +return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; + + dhvlen =le16_to_cpu (data->dhvlen); + +/* Validate that hl and dhvlen fit within the transfer length */ +if (sizeof (*data) +2 * (size_t )data->hl + dhvlen > tl) +return NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD ; +pr_debug ("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %u\n" , __func__, ctrl->cntlid, req->sq->qid, data->hl, data->cvalid, dhvlen);
@@ -338,7 +347,7 @@ void nvmet_execute_auth_send(struct nvmeswitch (data->auth_id) {case NVME_AUTH_DHCHAP_MESSAGE_REPLY : - dhchap_status =nvmet_auth_reply (req, d); + dhchap_status =nvmet_auth_reply (req, d, tl);if (dhchap_status ==0 ) req->sq->dhchap_step =NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1 ;
Greg Kroah-Hartman
maintainerPATCH 355/518 btrfs: check and set EXTENT_DELALLOC_NEW before clearing EXTENT_DELALLOC
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit 95ee2231896d5f2a31760411429075a99d6045a7 upstream.
[WARNING]
When running test cases with injected errors or shutdown, e.g. generic/388 or generic/475, there is a chance that the following kernel warning is triggered:
BTRFS info (device dm-2): first mount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff BTRFS info (device dm-2): using crc32c checksum algorithm
BTRFS info (device dm-2): checking UUID tree
BTRFS info (device dm-2): turning on async discard
BTRFS info (device dm-2): enabling free space tree
BTRFS critical (device dm-2 state E): emergency shutdown
------------[ cut here ]------------ WARNING: extent_io.c:1742 at extent_writepage_io+0x437/0x520 [btrfs], CPU#2: kworker/u43:2/651591 CPU: 2 UID: 0 PID: 651591 Comm: kworker/u43:2 Tainted: G W OE 7.0.0-rc6-custom+ #365 PREEMPT(full) 5804053f02137e627472d94b5128cc9fcb110e88 RIP: 0010:extent_writepage_io+0x437/0x520 [btrfs] Call Trace: <TASK> extent_write_cache_pages+0x2a5/0x820 [btrfs 70299925d0856939e93b17d480651713b3cbba58] btrfs_writepages+0x74/0x130 [btrfs 70299925d0856939e93b17d480651713b3cbba58] do_writepages+0xd0/0x160 __writeback_single_inode+0x42/0x340 writeback_sb_inodes+0x22d/0x580 wb_writeback+0xc6/0x360 wb_workfn+0xbd/0x470 process_one_work+0x198/0x3b0 worker_thread+0x1c8/0x330 kthread+0xee/0x120 ret_from_fork+0x2a6/0x330 ret_from_fork_asm+0x11/0x20 </TASK> ---[ end trace 0000000000000000 ]--- BTRFS error (device dm-2 state E): root 5 ino 259 folio 1323008 is marked dirty without notifying the fs BTRFS error (device dm-2 state E): failed to submit blocks, root=5 inode=259 folio=1323008 submit_bitmap=0: -117 BTRFS info (device dm-2 state E): last unmount of filesystem d8a19a28-3232-4809-b0df-38df83e71bff
[CAUSE]
Inside btrfs we have the following pattern in several locations, for example inside btrfs_dirty_folio():
btrfs_clear_extent_bit(&inode->io_tree, start_pos, end_of_last_block, EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, cached); ret = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, extra_bits, cached); if (ret) return ret;
However btrfs_set_extent_delalloc() can return IO errors other than -ENOMEM through the following callchain:
btrfs_set_extent_delalloc()
\- btrfs_find_new_delalloc_bytes()
\- btrfs_get_extent()
\- btrfs_lookup_file_extent()
\- btrfs_search_slot()When such IO error happened, the previous btrfs_clear_extent_bit() has cleared the EXTENT_DELALLOC for the range, and we're expecting btrfs_set_extent_delalloc() to re-set EXTENT_DELALLOC.
But since btrfs_set_extent_delalloc() failed before btrfs_set_extent_bit(), EXTENT_DELALLOC flag is no longer present.
And if the folio range is dirty before entering btrfs_set_extent_delalloc(), we got a dirty folio but no EXTENT_DELALLOC flag now.
Then we hit the folio writeback:
extent_writepage()
|- writepage_delalloc() | No ordered extent is created, as there is no EXTENT_DELALLOC set | for the folio range. | This also means the folio has no ordered flag set. | |- extent_writepage_io()
\- if (unlikely(!folio_test_ordered(folio))
Now we hit the warning.
[FIX]
Introduce a new helper, btrfs_reset_extent_delalloc() to replace the currently open-coded btrfs_clear_extent_bit() + btrfs_set_extent_delalloc() combination.
Instead of calling btrfs_clear_extent_bit() first, update EXTENT_DELALLOC_NEW first, as that part can fail due to metadata IO, meanwhile btrfs_clear_extent_bit() and btrfs_set_extent_bit() won't return any error but retry memory allocation until succeeded.
This allows us to fail early without clearing EXTENT_DELALLOC bit, so even if that new btrfs_reset_extent_delalloc() failed before touching EXTENT_DELALLOC, the existing dirty range will still have their old EXTENT_DELALLOC flag present, thus avoid the warning.
--- fs/btrfs/btrfs_inode.h | 2 + fs/btrfs/file.c | 25 ++------------------ fs/btrfs/inode.c | 61 +++++++++++++++++++++++++++++++++++++++++++------ fs/btrfs/reflink.c | 4 --- 4 files changed, 60 insertions(+), 32 deletions(-)
fs/btrfs/btrfs_inode.h +2 -0
@@ -569,6 +569,8 @@ int btrfs_start_delalloc_roots(struct btint btrfs_set_extent_delalloc (struct btrfs_inode *inode,u64 start,u64 end,unsigned int extra_bits,struct extent_state **cached_state); +int btrfs_reset_extent_delalloc (struct btrfs_inode *inode,u64 start,u64 end, +unsigned int extra_bits,struct extent_state **cached_state);struct btrfs_new_inode_args {/* Input */
fs/btrfs/file.c +3 -22
@@ -93,16 +93,8 @@ int btrfs_dirty_folio(struct btrfs_inode end_of_last_block = start_pos + num_bytes -1 ; -/* -* The pages may have already been dirty, clear out old accounting so -* we can set things up properly -*/ -btrfs_clear_extent_bit (&inode->io_tree, start_pos, end_of_last_block, -EXTENT_DELALLOC |EXTENT_DO_ACCOUNTING |EXTENT_DEFRAG , - cached); - - ret =btrfs_set_extent_delalloc (inode, start_pos, end_of_last_block, - extra_bits, cached); + ret =btrfs_reset_extent_delalloc (inode, start_pos, end_of_last_block, + extra_bits, cached);if (ret)return ret;
@@ -1966,18 +1958,7 @@ again: } } -/* -* page_mkwrite gets called when the page is firstly dirtied after it's -* faulted in, but write(2) could also dirty a page and set delalloc -* bits, thus in this case for space account reason, we still need to -* clear any delalloc bits within this page range since we have to -* reserve data&meta space before lock_page() (see above comments). -*/ -btrfs_clear_extent_bit (io_tree, page_start, end, -EXTENT_DELALLOC |EXTENT_DO_ACCOUNTING | -EXTENT_DEFRAG , &cached_state); - - ret =btrfs_set_extent_delalloc (inode, page_start, end,0 , &cached_state); + ret =btrfs_reset_extent_delalloc (inode, page_start, end,0 , &cached_state);if (ret <0 ) {btrfs_unlock_extent (io_tree, page_start, page_end, &cached_state); goto out_unlock;
fs/btrfs/inode.c +54 -7
79 lines not on this page · raw message
fs/btrfs/reflink.c +1 -3
@@ -94,9 +94,7 @@ static int copy_inline_to_page(struct btif (ret <0 ) goto out_unlock; -btrfs_clear_extent_bit (&inode->io_tree, file_offset, range_end, -EXTENT_DELALLOC |EXTENT_DO_ACCOUNTING |EXTENT_DEFRAG ,NULL ); - ret =btrfs_set_extent_delalloc (inode, file_offset, range_end,0 ,NULL ); + ret =btrfs_reset_extent_delalloc (inode, file_offset, range_end,0 ,NULL );if (ret) goto out_unlock;
Greg Kroah-Hartman
maintainerPATCH 356/518 btrfs: do not trim a device which is not writeable
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit 1b1937eb08f51319bf71575484cde2b8c517aedc upstream.
[BUG]
There is a bug report that btrfs/242 can randomly fail with the following NULL pointer dereference:
run fstests btrfs/242 at 2026-06-01 10:25:08
BTRFS: device fsid d4d7f234-487c-4787-88e4-47a8b68c9874 devid 1 transid 9 /dev/sdc (8:32) scanned by mount (122609) BTRFS info (device sdc): first mount of filesystem d4d7f234-487c-4787-88e4-47a8b68c9874
BTRFS info (device sdc): using crc32c checksum algorithm
BTRFS warning (device sdc): devid 2 uuid fbe72d72-3272-482d-80fb-ab88ed398192 is missing
BTRFS warning (device sdc): devid 2 uuid fbe72d72-3272-482d-80fb-ab88ed398192 is missing
BTRFS info (device sdc): allowing degraded mounts
BTRFS info (device sdc): turning on async discard
BTRFS info (device sdc): enabling free space tree
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000018 user pgtable: 4k pages, 48-bit VAs, pgdp=000000013fd6b000 CPU: 4 UID: 0 PID: 122625 Comm: fstrim Not tainted 7.0.10-2-default #1 PREEMPT(full) openSUSE Tumbleweed e9a5f6b24978fba3bf015a992f865837fdfff3dd Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20250812-19.fc42 08/12/2025 pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--) pc : btrfs_trim_fs+0x34c/0xa00 [btrfs] lr : btrfs_trim_fs+0x1f0/0xa00 [btrfs] Call trace: btrfs_trim_fs+0x34c/0xa00 [btrfs f02c1d570ceea621c69d302ba75dd61868083840] (P) btrfs_ioctl_fitrim+0xe8/0x178 [btrfs f02c1d570ceea621c69d302ba75dd61868083840] btrfs_ioctl+0xdd4/0x2bd8 [btrfs f02c1d570ceea621c69d302ba75dd61868083840] __arm64_sys_ioctl+0xac/0x108 invoke_syscall.constprop.0+0x5c/0xd0 el0_svc_common.constprop.0+0x40/0xf0 do_el0_svc+0x24/0x40 el0_svc+0x40/0x1d0 el0t_64_sync_handler+0xa0/0xe8 el0t_64_sync+0x1b0/0x1b8 Code: 17ffff83 f94017e0 f9002be0 f9402ea0 (f9400c00) ---[ end trace 0000000000000000 ]---
Also the reporter is very kind to test the following ASSERT() added to btrfs_trim_free_extents_throttle():
ASSERT(device->bdev, "devid=%llu path=%s dev_state=0x%lx\n", device->devid, btrfs_dev_name(device), device->dev_state);
And it shows the following output:
assertion failed: device->bdev, in extent-tree.c:6630 (devid=2 path=/dev/sdd dev_state=0x82)
Which means the device->bdev is NULL, and the dev_state is BTRFS_DEV_STATE_IN_FS_METADATA | BTRFS_DEV_STATE_ITEM_FOUND, without BTRFS_DEV_STATE_WRITEABLE flag set.
[CAUSE]
The pc points to the following call chain:
btrfs_trim_fs()
|- btrfs_trim_free_extents()
|- btrfs_trim_free_extents_throttle()
|- bdev_max_discard_sectors(device->bdev)So the NULL pointer dereference is caused by device->bdev being NULL.
This looks impossible by a quick glance, as just before calling btrfs_trim_free_extents_throttle(), we have skipped any device that has BTRFS_DEV_STATE_MISSING flag set.
However in this particular case, there is a window where the missing device is later re-scanned, causing btrfs to remove the BTRFS_DEV_STATE_MISSING flag:
btrfs_control_ioctl()
|- btrfs_scan_one_device()
|- device_list_add()
|- rcu_assign_pointer(device->name, name);
| This updates the missing device's path to the new good path.
|
|- clear_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)
This removes the BTRFS_DEV_STATE_MISSING flag.This allows the missing device to re-appear and clear the BTRFS_DEV_STATE_MISSING flag. However the device still does not have the BTRFS_DEV_STATE_WRITEABLE flag set, nor is its bdev pointer updated.
The bdev pointer remains NULL, triggering the crash later.
[FIX]
This is a big de-synchronization between BTRFS_DEV_STATE_MISSING and device->bdev pointer, and shows a gap in btrfs's re-appearing-device handling.
The proper handling of re-appearing device will need quite some extra work, which is out of the context of this small fix.
Thankfully the regular bbio submission path has already handled it well by checking if the device->bdev is NULL before submitting.
So here we just fix the crash by checking if the device is writeable and has a bdev pointer before calling bdev_max_discard_sectors().
--- fs/btrfs/extent-tree.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
fs/btrfs/extent-tree.c +8 -4
@@ -6613,12 +6613,16 @@ static int btrfs_trim_free_extents_throt *trimmed =0 ; -/* Discard not supported = nothing to do. */ -if (!bdev_max_discard_sectors (device->bdev)) +/* +* The caller only filters out MISSING devices, but a device that was +* missing at mount and later rescanned has MISSING cleared while bdev +* is still NULL and WRITEABLE is still unset. Skip those here. +*/ +if (!test_bit (BTRFS_DEV_STATE_WRITEABLE , &device->dev_state) || !device->bdev)return 0 ; -/* Not writable = nothing to do. */ -if (!test_bit (BTRFS_DEV_STATE_WRITEABLE , &device->dev_state)) +/* Discard not supported = nothing to do. */ +if (!bdev_max_discard_sectors (device->bdev))return 0 ;/* No free space = nothing to do. */
Greg Kroah-Hartman
maintainerPATCH 357/518 partitions: aix: bound the pp_count scan to the ppe array
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 2dc0bfd2fe355fb930de63c2f2eb8ced8570c579 upstream.
aix_partition() reads the physical volume descriptor into a fixed-size struct pvd and then scans its physical-partition-extent array:
int numpps = be16_to_cpu(pvd->pp_count);
...
for (i = 0; i < numpps; i += 1) {
struct ppe *p = pvd->ppe + i;
...
lp_ix = be16_to_cpu(p->lp_ix);pvd points at a single kmalloc()'d struct pvd whose ppe[] member holds a fixed ARRAY_SIZE(pvd->ppe) (1016) entries, but the loop runs up to the on-disk pp_count. pp_count is an unvalidated __be16 read straight from the descriptor, so a crafted AIX image with pp_count larger than 1016 drives the loop to read pvd->ppe[i] past the end of the allocation (up to 65535 entries, ~2 MB out of bounds).
The partition scan runs without mounting anything, when a block device with a crafted AIX/IBM partition table appears (an attacker-supplied image attached with losetup -P, or a device auto-scanned by udev), via msdos_partition() -> aix_partition().
Clamp the scan to the number of entries the ppe[] array can hold.
--- block/partitions/aix.c | 9 +++++++++ 1 file changed, 9 insertions(+)
block/partitions/aix.c +9 -0
@@ -226,6 +226,15 @@ int aix_partition(struct parsed_partitioint next_lp_ix =1 ;int lp_ix; +/* +* pvd was read into a fixed-size struct pvd whose ppe[] array +* holds ARRAY_SIZE(pvd->ppe) entries. pp_count is an +* unvalidated on-disk __be16, so clamp the scan to the array +* size to avoid walking past the allocation. +*/ +if (numpps >ARRAY_SIZE (pvd->ppe)) + numpps =ARRAY_SIZE (pvd->ppe); +for (i =0 ; i < numpps; i +=1 ) {struct ppe *p = pvd->ppe + i;unsigned int lv_ix;
Greg Kroah-Hartman
maintainerPATCH 358/518 btrfs: fix incorrect buffered IO fallback for append direct writes
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo <[email protected]>
commit ff66fe6662330226b3f486014c375538d91c44aa upstream.
[BUG]
With the previous bug of short direct writes fixed, test case generic/362 (*) still fails with the following error with nodatasum mount option:
# generic/362 0s ... - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad) # - output mismatch (see /home/adam/xfstests/results//generic/362.out.bad) # --- tests/generic/362.out 2024-08-24 15:31:37.200000000 +0930 # +++ /home/adam/xfstests/results//generic/362.out.bad 2026-05-27 10:13:09.072485767 +0930 # @@ -1,2 +1,3 @@ # QA output created by 362 # +Wrong file size after first write, got 8192 expected 4096 # Silence is golden # ...
*: If the test case has been executed before with default data checksum, the failure will not reproduce. Need the following fix to make it reliably reproducible:
https://lore.kernel.org/linux-btrfs/[email protected]/
[CAUSE]
Inside btrfs_dio_iomap_begin() for a direct write, we increase the isize if it's beyond the current isize.
But if the direct io finished short, we do not revert the isize to the previous value nor to the short write end.
Then if we need to fall back to buffered writes, and the write has IOCB_APPEND flag, then the buffered write will be positioned at the incorrect isize.
The call chain looks like this:
btrfs_direct_write(pos=0, length=4K)
|- __iomap_dio_rw()
| |- iomap_iter()
| | |- btrfs_dio_iomap_begin()
| | |- btrfs_get_blocks_direct_write()
| | |- i_size_write()
| | Which updates the isize to the write end (4K).
| |
| |- iomap_dio_iter()
| | Failed with -EFAULT on the first page.
| |
| |- iomap_iter()
| | |- btrfs_dio_iomap_end()
| | Detects a short write, return -ENOTBLK
| |- if (ret == -ENOTBLK) { ret = 0;}
| Which resets the return value.
|
|- ret = iomap_dio_complet()
| Which returns 0.
|
|- btrfs_buffered_write(iocb, from); |- generic_write_checks()
|- iocb->ki_pos = i_size_read()
Which is still the new size (4K), other than the original isize 0.
[FIX]
Introduce the following btrfs_dio_data members:
- old_isize
- updated_isize
If the direct write has enlarged the isize.
Then if we got a short write, and btrfs_dio_data::updated_isize is set, revert to the correct isize based on old_isize and current file position.
And here we call i_size_write() without holding an extent lock, which is a very special case that we're safe to do:
- Only a single writer can be enlarging isize Enlarging isize will take the exclusive inode lock.
- Buffered readers need to wait for the OE we're holding Buffered readers will lock extent and wait for OE of the folio range. Sometimes we can skip the OE wait, but since all page cache is invalidated, the OE wait can not be skipped.
But I do not think this is the most elegant solution, nor covers all cases. E.g. if the bio is submitted but IO failed, we are unable to do the revert.
I believe the more elegant one would be extend the EXTENT_DIO_LOCKED lifespan for direct writes, so that we can update the isize when a write beyond EOF finished successfully.
However that change is too huge for a small bug fix. So only implement the minimal partial fix for now.
[REASON FOR NO FIXES TAG]
The bug is again very old, before commit f85781fb505e ("btrfs: switch to iomap for direct IO") we are already increasing isize without a proper rollback for short writes.
Thus only a CC to stable.
--- fs/btrfs/direct-io.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)
fs/btrfs/direct-io.c +42 -1
@@ -15,10 +15,12 @@struct btrfs_dio_data {ssize_t submitted; +loff_t old_isize;struct extent_changeset *data_reserved;struct btrfs_ordered_extent *ordered;bool data_space_reserved;bool nocow_done; +bool updated_isize; };struct btrfs_dio_private {
@@ -228,6 +230,7 @@ static int btrfs_get_blocks_direct_writebool space_reserved = false;u64 len = *lenp;u64 prev_len; +loff_t old_isize;int ret =0 ;/*
@@ -341,8 +344,14 @@ static int btrfs_get_blocks_direct_write* Need to update the i_size under the extent lock so buffered * readers will get the updated i_size when we unlock. */ -if (start + len >i_size_read (inode)) + old_isize =i_size_read (inode); +if (start + len > old_isize) { +if (!dio_data->updated_isize) { + dio_data->old_isize = old_isize; + dio_data->updated_isize = true; + }i_size_write (inode, start + len); + } out:if (ret && space_reserved) {btrfs_delalloc_release_extents (BTRFS_I (inode), len);
@@ -626,6 +635,38 @@ static int btrfs_dio_iomap_end(struct in length -= submitted;if (write) {/* +* Got a short write and have updated the isize, need to +* revert the isize change. +* +* Normally we need to update isize with extent lock hold, +* but we're safe due to the following factors: +* +* - Only a single writer can be enlarging isize +* Enlarging isize will take the exclusive inode lock. +* +* - Buffered readers need to wait for the OE we're holding +* Buffered readers will lock extent and wait for OE +* of the folio range, and since page cache is invalidated +* the OE wait can not be skipped. +* +* So here we are safe to revert the isize before +* finishing the OE, and no reader of the remaining range +* can see the enlarged size. +* +* TODO: Extend the DIO_LOCKED lifespan for direct writes, +* and only enlarge isize after a successful write. +*/ +if (dio_data->updated_isize) { +u64 new_isize; + +if (submitted ==0 ) + new_isize = dio_data->old_isize; +else + new_isize =max (dio_data->old_isize, pos); +i_size_write (inode, new_isize); + dio_data->updated_isize = false; + } +/* * We have a short write, if there is any range * that is submitted properly, that part will have * its own OE split from the original one.
Greg Kroah-Hartman
maintainerPATCH 359/518 isofs: bound Rock Ridge symlink components to the SL record
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 5fa1d6a5ec2356d2107dead614437c66fa7138b1 upstream.
get_symlink_chunk() and the SL handling in parse_rock_ridge_inode_internal() walk the variable-length components of a Rock Ridge "SL" (symbolic link) record. Each component is a two-byte header (flags, len) followed by len bytes of text, so it occupies slp->len + 2 bytes. Both loops read slp->len and advance to the next component, and get_symlink_chunk() additionally does memcpy(rpnt, slp->text, slp->len), but neither checks that the component lies within the SL record before dereferencing it.
A crafted SL record whose component declares a len that runs past the record (rr->len) therefore triggers an out-of-bounds read of up to 255 bytes. When the record sits at the tail of its backing buffer - for example a small kmalloc()ed continuation block reached through a CE record - the read crosses the allocation; get_symlink_chunk() then copies the out-of-bounds bytes into the symlink body returned to user space by readlink(), disclosing adjacent kernel memory.
ISO 9660 images are routinely mounted from untrusted removable media - desktop environments auto-mount them (e.g. via udisks2) without CAP_SYS_ADMIN - so the record contents are attacker-controlled.
Reject any component that does not fit in the remaining record bytes before using it. In get_symlink_chunk() return NULL, like the existing output-buffer (plimit) checks, so a malformed record makes readlink() fail with -EIO rather than silently returning a truncated target; in parse_rock_ridge_inode_internal() stop the inode-size walk.
--- fs/isofs/rock.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/isofs/rock.c +11 -0
@@ -466,6 +466,9 @@ repeat: inode->i_size = symlink_len;while (slen >1 ) { rootflag =0 ; +/* keep the component within the SL record */ +if (slp->len +2 > slen) + goto eio;switch (slp->flags & ~1 ) {case 0 : inode->i_size +=
@@ -621,6 +624,14 @@ static char *get_symlink_chunk(char *rpn slp = &rr->u.SL.link;while (slen >1 ) { rootflag =0 ; +/* +* A component is slp->len + 2 bytes (a two-byte header plus +* len bytes of text). If it does not fit in the bytes left in +* the SL record the record is malformed: fail like the plimit +* checks below so readlink() returns -EIO, not a truncated path. +*/ +if (slp->len +2 > slen) +return NULL ;switch (slp->flags & ~1 ) {case 0 :if (slp->len > plimit - rpnt)
Greg Kroah-Hartman
maintainerPATCH 360/518 crypto: af_alg - Remove zero-copy support from skcipher and aead
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit ffdd2bc378953b525aca61902534e753f1f8e734 upstream.
The zero-copy support is one of the riskiest aspects of AF_ALG. It allows userspace to request cryptographic operations directly on pagecache pages of files like the 'su' binary. It also allows userspace to concurrently modify the memory which is being operated on, a recipe for TOCTOU vulnerabilities.
While zero-copy support is more valuable in other areas of the kernel like the frequently used networking and file I/O code, it has far less value in AF_ALG, which is a niche UAPI. AF_ALG primarily just exists for backwards compatibility with a small set of userspace programs such as 'iwd' that haven't yet been fixed to use userspace crypto code.
Originally AF_ALG was intended to be used to access hardware crypto accelerators. However, it isn't an efficient interface for that anyway, and it turned out to be rarely used in this way in practice.
Thus, the risks of the zero-copy support in AF_ALG vastly outweigh its benefits. Let's just remove it.
This commit removes it from the "skcipher" and "aead" algorithm types. "hash" will be handled separately.
This is a soft break, not a hard break. Even after this commit, it still works to use splice() or sendfile() to transfer data to an AF_ALG request socket from a pipe or any file, respectively. What changes is just that the kernel now makes an internal, stable copy of the data before doing the crypto operation. So performance is slightly reduced, but the UAPI isn't broken. And, very importantly, it's much safer.
Tested with libkcapi/test.sh. All its test cases still pass. I also verified that this would have prevented the copy.fail exploit as well. I also used a custom test program to verify that sendfile() still works.
--- Documentation/crypto/userspace-if.rst | 31 +------------- crypto/af_alg.c | 71 +++++++++++----------------------- crypto/algif_aead.c | 8 +-- 3 files changed, 32 insertions(+), 78 deletions(-)
Documentation/crypto/userspace-if.rst +4 -27
@@ -327,33 +327,10 @@ CRYPTO_USER_API_RNG_CAVP option: Zero-Copy Interface ------------------- -In addition to the send/write/read/recv system call family, the AF_ALG -interface can be accessed with the zero-copy interface of -splice/vmsplice. As the name indicates, the kernel tries to avoid a copy -operation into kernel space. - -The zero-copy operation requires data to be aligned at the page -boundary. Non-aligned data can be used as well, but may require more -operations of the kernel which would defeat the speed gains obtained -from the zero-copy interface. - -The system-inherent limit for the size of one zero-copy operation is 16 -pages. If more data is to be sent to AF_ALG, user space must slice the -input into segments with a maximum size of 16 pages. - -Zero-copy can be used with the following code example (a complete -working example is provided with libkcapi): - -:: - - int pipes[2]; - - pipe(pipes); - /* input data in iov */ - vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT); - /* opfd is the file descriptor returned from accept() system call */ - splice(pipes[0], NULL, opfd, NULL, ret, 0); - read(opfd, out, outlen); +AF_ALG used to have zero-copy support, but it was removed due to it being a +frequent source of vulnerabilities. For backwards compatibility the splice() +and sendfile() system calls are still supported, but the kernel will make an +internal copy of the data before passing it to the crypto code. Setsockopt Interface
crypto/af_alg.c +24 -47
91 lines not on this page · raw message
crypto/algif_aead.c +4 -4
@@ -9,10 +9,10 @@* The following concept of the memory management is used: * * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is -* filled by user space with the data submitted via sendmsg (maybe with -* MSG_SPLICE_PAGES). Filling up the TX SGL does not cause a crypto operation -* -- the data will only be tracked by the kernel. Upon receipt of one recvmsg -* call, the caller must provide a buffer which is tracked with the RX SGL. +* filled by user space with the data submitted via sendmsg. Filling up the TX +* SGL does not cause a crypto operation -- the data will only be tracked by the +* kernel. Upon receipt of one recvmsg call, the caller must provide a buffer +* which is tracked with the RX SGL. * * During the processing of the recvmsg operation, the cipher request is * allocated and prepared. As part of the recvmsg operation, the processed
Greg Kroah-Hartman
maintainerPATCH 361/518 crypto: caam - use print_hex_dump_devel to guard key hex dumps
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 3f57657b6ea23f933371f2c2846322f441773cee upstream.
Use print_hex_dump_devel() for dumping sensitive key material in *_setkey() and gen_split_key() to avoid leaking secrets at runtime when CONFIG_DYNAMIC_DEBUG is enabled.
--- drivers/crypto/caam/caamalg.c | 12 ++++++------ drivers/crypto/caam/caamalg_qi.c | 12 ++++++------ drivers/crypto/caam/caamhash.c | 4 ++-- drivers/crypto/caam/key_gen.c | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-)
drivers/crypto/caam/caamalg.c +6 -6
@@ -603,7 +603,7 @@ static int aead_setkey(struct crypto_aeadev_dbg (jrdev,"keylen %d enckeylen %d authkeylen %d\n" , keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );/*
@@ -639,7 +639,7 @@ static int aead_setkey(struct crypto_aeadma_sync_single_for_device (jrdev, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); - print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , ctx->key, ctx->adata.keylen_pad + keys.enckeylen,1 );
@@ -680,7 +680,7 @@ static int gcm_setkey(struct crypto_aeadif (err)return err; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -701,7 +701,7 @@ static int rfc4106_setkey(struct crypto_if (err)return err; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -727,7 +727,7 @@ static int rfc4543_setkey(struct crypto_if (err)return err; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -754,7 +754,7 @@ static int skcipher_setkey(struct cryptou32 *desc;const bool is_rfc3686 = alg->caam.rfc3686; - print_hex_dump_debug("key in @"__stringify(__LINE__)": ", + print_hex_dump_devel("key in @"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );/* Here keylen is actual key length */
drivers/crypto/caam/caamalg_qi.c +6 -6
@@ -212,7 +212,7 @@ static int aead_setkey(struct crypto_aeadev_dbg (jrdev,"keylen %d enckeylen %d authkeylen %d\n" , keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );/*
@@ -248,7 +248,7 @@ static int aead_setkey(struct crypto_aea ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); - print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , ctx->key, ctx->adata.keylen_pad + keys.enckeylen,1 );
@@ -371,7 +371,7 @@ static int gcm_setkey(struct crypto_aeadif (ret)return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -475,7 +475,7 @@ static int rfc4106_setkey(struct crypto_if (ret)return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -581,7 +581,7 @@ static int rfc4543_setkey(struct crypto_if (ret)return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -631,7 +631,7 @@ static int skcipher_setkey(struct cryptoconst bool is_rfc3686 = alg->caam.rfc3686;int ret =0 ; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 ); ctx->cdata.keylen = keylen;
drivers/crypto/caam/caamhash.c +2 -2
@@ -505,7 +505,7 @@ static int axcbc_setkey(struct crypto_ah DMA_TO_DEVICE); ctx->adata.keylen = keylen; - print_hex_dump_debug("axcbc ctx.key@" __stringify(__LINE__)" : ", + print_hex_dump_devel("axcbc ctx.key@" __stringify(__LINE__)" : ",DUMP_PREFIX_ADDRESS ,16 ,4 , ctx->key, keylen,1 );return axcbc_set_sh_desc (ahash);
@@ -525,7 +525,7 @@ static int acmac_setkey(struct crypto_ah ctx->adata.key_virt = key; ctx->adata.keylen = keylen; - print_hex_dump_debug("acmac ctx.key@" __stringify(__LINE__)" : ", + print_hex_dump_devel("acmac ctx.key@" __stringify(__LINE__)" : ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );return acmac_set_sh_desc (ahash);
drivers/crypto/caam/key_gen.c +2 -2
@@ -58,7 +58,7 @@ int gen_split_key(struct device *jrdev,dev_dbg (jrdev,"split keylen %d split keylen padded %d\n" , adata->keylen, adata->keylen_pad); - print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key_in, keylen,1 );if (local_max > max_keylen)
@@ -113,7 +113,7 @@ int gen_split_key(struct device *jrdev,wait_for_completion (&result.completion); ret = result.err; - print_hex_dump_debug("ctx.key@"__stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key_out, adata->keylen_pad,1 ); }
Greg Kroah-Hartman
maintainerPATCH 362/518 crypto: caam - use print_hex_dump_devel to guard key hex dumps again
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit 8005dc808bcce7d6cc2ae015a3cde1683bee602d upstream.
Use print_hex_dump_devel() for dumping sensitive key material in *_setkey() to avoid leaking secrets at runtime when CONFIG_DYNAMIC_DEBUG is enabled.
--- drivers/crypto/caam/caamalg_qi2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/crypto/caam/caamalg_qi2.c +6 -6
@@ -301,7 +301,7 @@ static int aead_setkey(struct crypto_aeadev_dbg (dev,"keylen %d enckeylen %d authkeylen %d\n" , keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 ); ctx->adata.keylen = keys.authkeylen;
@@ -315,7 +315,7 @@ static int aead_setkey(struct crypto_aeamemcpy (ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen);dma_sync_single_for_device (dev, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, ctx->dir); - print_hex_dump_debug("ctx.key@" __stringify(__LINE__)": ", + print_hex_dump_devel("ctx.key@" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , ctx->key, ctx->adata.keylen_pad + keys.enckeylen,1 );
@@ -732,7 +732,7 @@ static int gcm_setkey(struct crypto_aead ret =aes_check_keylen (keylen);if (ret)return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -828,7 +828,7 @@ static int rfc4106_setkey(struct crypto_if (ret)return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -927,7 +927,7 @@ static int rfc4543_setkey(struct crypto_if (ret)return ret; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 );memcpy (ctx->key, key, keylen);
@@ -955,7 +955,7 @@ static int skcipher_setkey(struct cryptou32 *desc;const bool is_rfc3686 = alg->caam.rfc3686; - print_hex_dump_debug("key in @" __stringify(__LINE__)": ", + print_hex_dump_devel("key in @" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, keylen,1 ); ctx->cdata.keylen = keylen;
Greg Kroah-Hartman
maintainerPATCH 363/518 crypto: chacha20poly1305 - validate poly1305 template argument
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiaonan Zhao <[email protected]>
commit 265b861bece38318b8e0fc8fac0643d4ef906d31 upstream.
chachapoly_create() still accepts the compatibility poly1305 parameter in the template name, but it assumes the second template argument is always present and immediately passes it to strcmp().
When the argument is missing, crypto_attr_alg_name() returns an error pointer. Check for that before comparing the name so malformed template instantiations fail with an error instead of dereferencing the error pointer in strcmp().
This matches the surrounding Crypto API template pattern where crypto_attr_alg_name() results are validated before string-specific use.
--- crypto/chacha20poly1305.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
crypto/chacha20poly1305.c +9 -2
@@ -375,6 +375,7 @@ static int chachapoly_create(struct crypstruct aead_instance *inst;struct chachapoly_instance_ctx *ctx;struct skcipher_alg_common *chacha; +const char *poly_name;int err;if (ivsize >CHACHAPOLY_IV_SIZE )
@@ -396,9 +397,15 @@ static int chachapoly_create(struct cryp goto err_free_inst; chacha =crypto_spawn_skcipher_alg_common (&ctx->chacha); + poly_name =crypto_attr_alg_name (tb[2 ]); +if (IS_ERR (poly_name)) { + err =PTR_ERR (poly_name); + goto err_free_inst; + } + err = -EINVAL ; -if (strcmp (crypto_attr_alg_name (tb[2 ]),"poly1305" ) && -strcmp (crypto_attr_alg_name (tb[2 ]),"poly1305-generic" )) +if (strcmp (poly_name,"poly1305" ) && +strcmp (poly_name,"poly1305-generic" )) goto err_free_inst;/* Need 16-byte IV size, including Initial Block Counter value */ if (chacha->ivsize !=CHACHA_IV_SIZE )
Greg Kroah-Hartman
maintainerPATCH 364/518 crypto: crypto4xx - Remove insecure and unused rng_alg
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 7811ec9e973d2c9e465083699f0c8240b98cb8c4 upstream.
Remove crypto4xx_rng, as it is insecure and unused:
- It has only a 64-bit security strength, which is highly inadequate. This can be seen by the fact that crypto4xx_hw_init() seeds it with only 64 bits of entropy, and the fact that the original commit mentions that it implements ANSI X9.17 Annex C.
Another issue was that this driver didn't implement the crypto_rng API correctly, as crypto4xx_prng_generate() didn't return 0 on success.
- No user of this code is known. It's usable only theoretically via the "rng" algorithm type of AF_ALG. But userspace actually just uses the actual Linux RNG (/dev/random etc) instead. And rng_algs don't contribute entropy to the actual Linux RNG either. (This may have been confused with hwrng, which does contribute entropy.)
--- drivers/crypto/Kconfig | 1 drivers/crypto/amcc/crypto4xx_core.c | 88 -------------------------------- drivers/crypto/amcc/crypto4xx_core.h | 4 - drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ---- 4 files changed, 104 deletions(-)
drivers/crypto/Kconfig +0 -1
@@ -301,7 +301,6 @@ config CRYPTO_DEV_PPC4XX select CRYPTO_CCM select CRYPTO_CTR select CRYPTO_GCM - select CRYPTO_RNG select CRYPTO_SKCIPHER help This option allows you to have support for AMCC crypto acceleration.
drivers/crypto/amcc/crypto4xx_core.c +0 -88
127 lines not on this page · raw message
drivers/crypto/amcc/crypto4xx_core.h +0 -4
@@ -14,10 +14,8 @@#define __CRYPTO4XX_CORE_H__#include <linux/ratelimit.h> -#include <linux/mutex.h> #include <linux/scatterlist.h> #include <crypto/internal/aead.h> -#include <crypto/internal/rng.h> #include <crypto/internal/skcipher.h> #include "crypto4xx_reg_def.h" #include "crypto4xx_sa.h"
@@ -111,7 +109,6 @@ struct crypto4xx_core_device {u32 irq;struct tasklet_struct tasklet;spinlock_t lock; -struct mutex rng_lock; };struct crypto4xx_ctx {
@@ -135,7 +132,6 @@ struct crypto4xx_alg_common {union {struct skcipher_alg cipher;struct aead_alg aead; -struct rng_alg rng; } u; };
drivers/crypto/amcc/crypto4xx_reg_def.h +0 -11
@@ -90,20 +90,9 @@#define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8#define CRYPTO4XX_ENDIAN_CFG 0x000600d8 -#define CRYPTO4XX_PRNG_STAT 0x00070000 -#define CRYPTO4XX_PRNG_STAT_BUSY 0x1#define CRYPTO4XX_PRNG_CTRL 0x00070004#define CRYPTO4XX_PRNG_SEED_L 0x00070008#define CRYPTO4XX_PRNG_SEED_H 0x0007000c - -#define CRYPTO4XX_PRNG_RES_0 0x00070020 -#define CRYPTO4XX_PRNG_RES_1 0x00070024 -#define CRYPTO4XX_PRNG_RES_2 0x00070028 -#define CRYPTO4XX_PRNG_RES_3 0x0007002C - -#define CRYPTO4XX_PRNG_LFSR_L 0x00070030 -#define CRYPTO4XX_PRNG_LFSR_H 0x00070034 -/* * Initialize CRYPTO ENGINE registers, and memory bases. */
Greg Kroah-Hartman
maintainerPATCH 365/518 crypto: ecc - Fix carry overflow in vli multiplication
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anastasia Tishchenko <[email protected]>
commit 27b536a2ec8e2f85a0380c2d13c9ecbc7aaab406 upstream.
The carry flag calculation fails when r01.m_high is saturated (0xFFFFFFFFFFFFFFFF) and addition of lower bits overflows.
The condition (r01.m_high < product.m_high) doesn't handle the case where r01.m_high == product.m_high and an additional carry exists from lower-bit overflow.
When commit 3c4b23901a0c ("crypto: ecdh - Add ECDH software support") introduced crypto/ecc.c, it split the muladd() function in the micro-ecc library into separate mul_64_64() and add_128_128() helpers. It seems the check got lost in translation.
Add proper handling for this boundary by accounting for the carry from the lower addition.
--- crypto/ecc.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
crypto/ecc.c +20 -11
@@ -393,14 +393,26 @@ static uint128_t mul_64_64(u64 left, u64return result; } -static uint128_t add_128_128 (uint128_t a,uint128_t b) +/* Calculate addition with overflow checking. Returns true on wrap-around, +* false otherwise. +*/ +static bool check_add_128_128_overflow (uint128_t *result,uint128_t a, +uint128_t b) { -uint128_t result; +bool carry; - result.m_low = a.m_low + b.m_low; - result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); + result->m_low = a.m_low + b.m_low; + carry = (result->m_low < a.m_low); -return result; + result->m_high = a.m_high + b.m_high + carry; + +/* Using constant-time bitwise arithmetic to prevent timing +* side-channels. +*/ + carry = (result->m_high < a.m_high) | + ((result->m_high == a.m_high) & carry); + +return carry; } static void vli_mult(u64 *result, const u64 *left, const u64 *right,
@@ -425,9 +437,7 @@ static void vli_mult(u64 *result, constuint128_t product; product =mul_64_64 (left[i], right[k - i]); - - r01 =add_128_128 (r01, product); - r2 += (r01.m_high < product.m_high); + r2 +=check_add_128_128_overflow (&r01, r01, product); } result[k] = r01.m_low;
@@ -450,7 +460,7 @@ static void vli_umult(u64 *result, constuint128_t product; product =mul_64_64 (left[k], right); - r01 =add_128_128 (r01, product); +check_add_128_128_overflow (&r01, r01, product);/* no carry */ result[k] = r01.m_low; r01.m_low = r01.m_high;
@@ -487,8 +497,7 @@ static void vli_square(u64 *result, cons product.m_low <<=1 ; } - r01 =add_128_128 (r01, product); - r2 += (r01.m_high < product.m_high); + r2 +=check_add_128_128_overflow (&r01, r01, product); } result[k] = r01.m_low;
Greg Kroah-Hartman
maintainerPATCH 366/518 crypto: hisi-trng - Remove crypto_rng interface
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 216a7795ec210bdabd5dad42323eee70bbfc8d90 upstream.
drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through two completely separate interfaces, crypto_rng and hwrng. However, the implementation of this is buggy because it permits generation operations from these interfaces to run concurrently with each other, accessing the same registers. That is, hisi_trng_generate() synchronizes with itself but not with hisi_trng_read(). This results in potential repetition of output from the RNG, output of non-random values, etc.
Fortunately, there's actually no point in hardware RNG drivers implementing the crypto_rng interface. It's not actually used by anything besides the "rng" algorithm type of AF_ALG, which in turn is not actually used in practice. Other crypto_rng hardware drivers are likewise being phased out, leaving just the hwrng support.
Thus, remove it to simplify the code and avoid conflict (and confusion) with the hwrng interface which is the one that actually matters.
--- drivers/crypto/hisilicon/Kconfig | 1 drivers/crypto/hisilicon/trng/trng.c | 296 ----------------------------------- 2 files changed, 2 insertions(+), 295 deletions(-)
drivers/crypto/hisilicon/Kconfig +0 -1
@@ -80,6 +80,5 @@ config CRYPTO_DEV_HISI_TRNG tristate "Support for HISI TRNG Driver" depends on ARM64 && ACPI select HW_RANDOM - select CRYPTO_RNG help Support for HiSilicon TRNG Driver.
drivers/crypto/hisilicon/trng/trng.c +2 -294
353 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 367/518 crypto: pcrypt - restore callback for non-parallel fallback
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruijie Li <[email protected]>
commit ed459fe319376e876de433d12b6c6772e612ca36 upstream.
pcrypt installs pcrypt_aead_done() on the child AEAD request before trying to submit it through padata. If padata_do_parallel() returns -EBUSY, pcrypt falls back to calling the child AEAD directly.
That fallback must not keep the padata completion callback. Otherwise an asynchronous completion runs pcrypt_aead_done() even though the request was never enrolled in padata.
Restore the original request callback and callback data before calling the child AEAD directly. This keeps the fallback path aligned with a direct AEAD request while leaving the parallel path unchanged.
--- crypto/pcrypt.c | 4 ++++ 1 file changed, 4 insertions(+)
crypto/pcrypt.c +4 -0
@@ -122,6 +122,8 @@ static int pcrypt_aead_encrypt(struct aereturn -EINPROGRESS ;if (err == -EBUSY ) {/* try non-parallel mode */ +aead_request_set_callback (creq, flags, req->base.complete, + req->base.data);return crypto_aead_encrypt (creq); }
@@ -173,6 +175,8 @@ static int pcrypt_aead_decrypt(struct aereturn -EINPROGRESS ;if (err == -EBUSY ) {/* try non-parallel mode */ +aead_request_set_callback (creq, flags, req->base.complete, + req->base.data);return crypto_aead_decrypt (creq); }
Greg Kroah-Hartman
maintainerPATCH 368/518 crypto: tegra - fix refcount leak in tegra_se_host1x_submit()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 6ea0ce3a19f9c37a014099e2b0a46b27fa164564 upstream.
The timeout error path in tegra_se_host1x_submit() returns without calling host1x_job_put(), while all other paths (success, submit error, pin error) properly release the job reference through the job_put label. Since host1x_job_alloc() initializes the reference count and host1x_job_put() is required to drop it, omitting it on timeout causes a permanent refcount leak.
Fix this by redirecting the timeout return to the existing job_put label, ensuring the job reference and any associated syncpt references are consistently released.
--- drivers/crypto/tegra/tegra-se-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/tegra/tegra-se-main.c +1 -1
@@ -180,7 +180,7 @@ int tegra_se_host1x_submit(struct tegra_ MAX_SCHEDULE_TIMEOUT, NULL);if (ret) {dev_err (se->dev,"host1x job timed out\n" ); -return ret; + goto job_put; }host1x_job_put (job);
Greg Kroah-Hartman
maintainerPATCH 369/518 crypto: loongson - Select CRYPTO_RNG
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 4c600ab0d8cfc9d75b92f3426dbcb2ad85eac91d upstream.
This driver registers a rng_alg, so it requires CRYPTO_RNG.
--- drivers/crypto/loongson/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/crypto/loongson/Kconfig +1 -0
@@ -1,5 +1,6 @@ config CRYPTO_DEV_LOONGSON_RNG tristate "Support for Loongson RNG Driver" depends on MFD_LOONGSON_SE + select CRYPTO_RNG help Support for Loongson RNG Driver.
Greg Kroah-Hartman
maintainerPATCH 370/518 crypto: loongson - Remove broken and unused loongson-rng
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit af3d1bb9a09daf928fc3f173689fb7904d6a6d4f upstream.
The loongson-rng rng_alg has several vulnerabilities, including not providing forward security, and a use-after-free bug due to the use of wait_for_completion_interruptible().
Meanwhile, the rng_alg framework doesn't really have any purpose in the first place other than to access the software algorithms crypto/drbg.c and crypto/jitterentropy.c. Hardware-specific rng_algs have no in-kernel user, and unlike hwrng there's no feed into the actual Linux RNG. As such, there's really no point to this code. There are of course other rng_alg drivers that are similarly unused, but they're similarly in the process of being phased out, e.g.
https://lore.kernel.org/r/[email protected] and
https://lore.kernel.org/r/[email protected]
Given that, there's no point in fixing forward these vulnerabilities, and it makes much more sense to simply roll back the addition of this driver. If this platform provides TRNG (not PRNG) functionality, it could make sense to add a hwrng driver, but it would be quite different.
--- MAINTAINERS | 1 arch/loongarch/configs/loongson32_defconfig | 1 arch/loongarch/configs/loongson64_defconfig | 1 drivers/crypto/Kconfig | 1 drivers/crypto/Makefile | 1 drivers/crypto/loongson/Kconfig | 6 drivers/crypto/loongson/Makefile | 1 drivers/crypto/loongson/loongson-rng.c | 209 ---------------------------- 8 files changed, 221 deletions(-) delete mode 100644 drivers/crypto/loongson/Kconfig delete mode 100644 drivers/crypto/loongson/Makefile delete mode 100644 drivers/crypto/loongson/loongson-rng.c
MAINTAINERS +0 -1
@@ -15087,7 +15087,6 @@ M: Qunqin Zhao <[email protected]> L: [email protected] S: Maintained F: drivers/char/tpm/tpm_loongson.c -F: drivers/crypto/loongson/ F: drivers/mfd/loongson-se.c F: include/linux/mfd/loongson-se.h
arch/loongarch/configs/loongson32_defconfig +0 -1
@@ -1091,7 +1091,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m CONFIG_CRYPTO_DEV_VIRTIO=m -CONFIG_CRYPTO_DEV_LOONGSON_RNG=m CONFIG_DMA_CMA=y CONFIG_CMA_SIZE_MBYTES=0 CONFIG_PRINTK_TIME=y
arch/loongarch/configs/loongson64_defconfig +0 -1
@@ -1124,7 +1124,6 @@ CONFIG_CRYPTO_USER_API_SKCIPHER=m CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m CONFIG_CRYPTO_DEV_VIRTIO=m -CONFIG_CRYPTO_DEV_LOONGSON_RNG=m CONFIG_DMA_CMA=y CONFIG_DMA_NUMA_CMA=y CONFIG_CMA_SIZE_MBYTES=0
drivers/crypto/Kconfig +0 -1
@@ -845,7 +845,6 @@ config CRYPTO_DEV_CCREE If unsure say Y. source "drivers/crypto/hisilicon/Kconfig" -source "drivers/crypto/loongson/Kconfig" source "drivers/crypto/amlogic/Kconfig"
drivers/crypto/Makefile +0 -1
@@ -43,7 +43,6 @@ obj-y += inside-secure/ obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/ obj-y += xilinx/ obj-y += hisilicon/ -obj-y += loongson/ obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/ obj-y += intel/ obj-y += starfive/
drivers/crypto/loongson/Kconfig deleted +0 -6
@@ -1,6 +0,0 @@ -config CRYPTO_DEV_LOONGSON_RNG - tristate "Support for Loongson RNG Driver" - depends on MFD_LOONGSON_SE - select CRYPTO_RNG - help - Support for Loongson RNG Driver.
drivers/crypto/loongson/Makefile deleted +0 -1
@@ -1 +0,0 @@ -obj-$(CONFIG_CRYPTO_DEV_LOONGSON_RNG) += loongson-rng.o
drivers/crypto/loongson/loongson-rng.c deleted +0 -209
209 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 371/518 crypto: ccp - Do not initialize SNP for SEV ioctls
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tycho Andersen (AMD) <[email protected]>
commit fb1758e74b8061aacfbce7bbb7a7cc650537e167 upstream.
Sashiko notes:
Quoted 5 lines
if SEV initialization fails and KVM is actively running normal VMs, could a userspace process trigger this code path via
/dev/sevioctls (e.g.,SEV_PDH_GEN) and zero outMSR_VM_HSAVE_PAglobally? Would the next VMRUN execution for an active VM trigger a general protection fault and crash the host?
sev_move_to_init_state() is called for ioctls requiring only SEV firmware:SEV_PEK_GEN, SEV_PDH_GEN, SEV_PEK_CSR, SEV_PEK_CERT_IMPORT, and SEV_PDH_CERT_EXPORT. After the firmware command, it does SEV_SHUTDOWN on the SEV firmware. Since these commands do not require SNP to be initialized, skip it by calling __sev_platform_init_locked() which only initializes the SEV firmware. This way SNP is not Initialized at all, and HSAVE_PA is not cleared.
The previous code saved any SEV initialization firmware error to init_args.error and then threw it away and hardcoded the return value of INVALID_PLATFORM_STATE regardless of the real firmware error. This patch changes it to surface the underlying error, which is hopefully both more useful and doesn't cause any problems.
Note that it is still safe to call __sev_firmware_shutdown() directly: it calls __sev_snp_shutdown_locked(), which skips SNP shutdown if SNP was not initialized.
--- drivers/crypto/ccp/sev-dev.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/crypto/ccp/sev-dev.c +2 -5
@@ -1716,14 +1716,11 @@ static int sev_get_platform_state(int *sstatic int sev_move_to_init_state (struct sev_issue_cmd *argp,bool *shutdown_required) { -struct sev_platform_init_args init_args = {0 };int rc; - rc =_sev_platform_init_locked (&init_args); -if (rc) { - argp->error =SEV_RET_INVALID_PLATFORM_STATE ; + rc =__sev_platform_init_locked (&argp->error); +if (rc)return rc; - } *shutdown_required = true;
Greg Kroah-Hartman
maintainerPATCH 372/518 crypto: ccp - Do not initialize SNP for ioctl(SNP_COMMIT)
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tycho Andersen (AMD) <[email protected]>
commit 5a1364da2f04217a36e2fdfa2db4ee025b383a20 upstream.
Sashiko notes:
Quoted 5 lines
if SEV initialization fails and KVM is actively running normal VMs, could a userspace process trigger this code path via
/dev/sevioctls (e.g.,SEV_PDH_GEN) and zero outMSR_VM_HSAVE_PAglobally? Would the next VMRUN execution for an active VM trigger a general protection fault and crash the host?
The SNP_COMMIT command does not require the firmware to be in any particular state. Skip initializing it if it was previously uninitialized.
The SEV-SNP firmware specification doc 56860 does not mention SNP_COMMIT in Table 5 as a command that is allowed in the UNINIT state, but it is in fact allowed and a future documentation update will reflect that.
--- drivers/crypto/ccp/sev-dev.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-)
drivers/crypto/ccp/sev-dev.c +1 -12
@@ -2437,24 +2437,13 @@ cleanup:static int sev_ioctl_do_snp_commit (struct sev_issue_cmd *argp) { -struct sev_device *sev = psp_master->sev_data;struct sev_data_snp_commit buf; -bool shutdown_required = false; -int ret, error; - -if (!sev->snp_initialized) { - ret =snp_move_to_init_state (argp, &shutdown_required); -if (ret) -return ret; - } +int ret; buf.len =sizeof (buf); ret =__sev_do_cmd_locked (SEV_CMD_SNP_COMMIT , &buf, &argp->error); -if (shutdown_required) -__sev_snp_shutdown_locked (&error, false); -return ret; }
Greg Kroah-Hartman
maintainerPATCH 373/518 crypto: ccp - Do not initialize SNP for ioctl(SNP_VLEK_LOAD)
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tycho Andersen (AMD) <[email protected]>
commit f91e9dbb5845d1e5abf1028e6df57dcf61583e1b upstream.
Sashiko notes:
Quoted 5 lines
if SEV initialization fails and KVM is actively running normal VMs, could a userspace process trigger this code path via
/dev/sevioctls (e.g.,SEV_PDH_GEN) and zero outMSR_VM_HSAVE_PAglobally? Would the next VMRUN execution for an active VM trigger a general protection fault and crash the host?
The SEV firmware docs for SNP_VLEK_LOAD note:
Quoted 1 line
On
SNP_SHUTDOWN, the VLEK is deleted.
That is, the initialization/shutdown wrapper here is pointless, because the firmware immediately throws away the key anyway. Instead, refuse to do anything if SNP has not been previously initialized.
This is an ABI break: before, this was a no-op and almost certainly a mistake by userspace, and now it returns -ENODEV. ABI compatibility could be maintained here by simply returning 0 in the check instead.
--- drivers/crypto/ccp/sev-dev.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-)
drivers/crypto/ccp/sev-dev.c +4 -13
@@ -2481,9 +2481,8 @@ static int sev_ioctl_do_snp_vlek_load(st {struct sev_device *sev = psp_master->sev_data;struct sev_user_data_snp_vlek_load input; -bool shutdown_required = false; -int ret, error;void *blob; +int ret;if (!argp->data)return -EINVAL ;
@@ -2491,6 +2490,9 @@ static int sev_ioctl_do_snp_vlek_load(stif (!writable)return -EPERM ; +if (!sev->snp_initialized) +return -ENODEV ; +if (copy_from_user (&input,u64_to_user_ptr (argp->data),sizeof (input)))return -EFAULT ;
@@ -2504,18 +2506,7 @@ static int sev_ioctl_do_snp_vlek_load(st input.vlek_wrapped_address =__psp_pa (blob); -if (!sev->snp_initialized) { - ret =snp_move_to_init_state (argp, &shutdown_required); -if (ret) - goto cleanup; - } - ret =__sev_do_cmd_locked (SEV_CMD_SNP_VLEK_LOAD , &input, &argp->error); - -if (shutdown_required) -__sev_snp_shutdown_locked (&error, false); - -cleanup:kfree (blob);return ret;
Greg Kroah-Hartman
maintainerPATCH 374/518 crypto: ccp - Do not initialize SNP for ioctl(SNP_CONFIG)
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tycho Andersen (AMD) <[email protected]>
commit 08f0e65e784c4b20e6e620dd4f68d8636073a3d2 upstream.
Sashiko notes:
Quoted 5 lines
if SEV initialization fails and KVM is actively running normal VMs, could a userspace process trigger this code path via
/dev/sevioctls (e.g.,SEV_PDH_GEN) and zero outMSR_VM_HSAVE_PAglobally? Would the next VMRUN execution for an active VM trigger a general protection fault and crash the host?
Refuse to re-try initialization if SNP is not already initialized for SNP_CONFIG.
This is technically an ABI break: before if SNP initialization failed it could be transparently retriggered by this ioctl, and if no VMs were running, everything worked fine. Hopefully this is enough of a corner case that nobody will notice, but someone does, there are a few options:
* do something like symbol_get() for kvm and refuse to initialize if KVM is loaded
* check each cpu's HSAVE_PA for non-zero data before re-initializing
* once initialization has failed, continue to refuse to initialize until the ccp module is unloaded
--- drivers/crypto/ccp/sev-dev.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-)
drivers/crypto/ccp/sev-dev.c +4 -29
@@ -1727,21 +1727,6 @@ static int sev_move_to_init_state(structreturn 0 ; } -static int snp_move_to_init_state (struct sev_issue_cmd *argp,bool *shutdown_required) -{ -int error, rc; - - rc =__sev_snp_init_locked (&error,0 ); -if (rc) { - argp->error =SEV_RET_INVALID_PLATFORM_STATE ; -return rc; - } - - *shutdown_required = true; - -return 0 ; -} -static int sev_ioctl_do_reset (struct sev_issue_cmd *argp,bool writable) {int state, rc;
@@ -2451,8 +2436,6 @@ static int sev_ioctl_do_snp_set_config(s {struct sev_device *sev = psp_master->sev_data;struct sev_user_data_snp_config config; -bool shutdown_required = false; -int ret, error;if (!argp->data)return -EINVAL ;
@@ -2460,21 +2443,13 @@ static int sev_ioctl_do_snp_set_config(sif (!writable)return -EPERM ; +if (!sev->snp_initialized) +return -ENODEV ; +if (copy_from_user (&config, (void __user *)argp->data,sizeof (config)))return -EFAULT ; -if (!sev->snp_initialized) { - ret =snp_move_to_init_state (argp, &shutdown_required); -if (ret) -return ret; - } - - ret =__sev_do_cmd_locked (SEV_CMD_SNP_CONFIG , &config, &argp->error); - -if (shutdown_required) -__sev_snp_shutdown_locked (&error, false); - -return ret; +return __sev_do_cmd_locked (SEV_CMD_SNP_CONFIG , &config, &argp->error); }static int sev_ioctl_do_snp_vlek_load (struct sev_issue_cmd *argp,bool writable)
Greg Kroah-Hartman
maintainerPATCH 375/518 crypto: drbg - Fix returning success on failure in CTR_DRBG
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 39a31ad9e2a5ed7e9c9c6f711dca96c8c8f5f26b upstream.
drbg_ctr_generate() sometimes returns success when it fails, leaving the output buffer uninitialized. Fix it.
--- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
crypto/drbg.c +1 -1
@@ -377,7 +377,7 @@ static int drbg_ctr_generate(struct drbgif (addtl && !list_empty (addtl)) { ret =drbg_ctr_update (drbg, addtl,2 );if (ret) -return 0 ; +return ret; }/* 10.2.1.5.2 step 4.1 */
Greg Kroah-Hartman
maintainerPATCH 376/518 crypto: drbg - Fix misaligned writes in CTR_DRBG and HASH_DRBG
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit ddc4dedb9ba3c8eecbc8c050fffd46d1b7e75c21 upstream.
drbg_cpu_to_be32() is being used to do a plain write to a byte array, which doesn't have any alignment guarantee. This can cause a misaligned write. Replace it with the correct function, put_unaligned_be32().
--- crypto/df_sp80090a.c | 7 ++++--- crypto/drbg.c | 3 ++- include/crypto/internal/drbg.h | 18 ------------------ 3 files changed, 6 insertions(+), 22 deletions(-)
crypto/df_sp80090a.c +4 -3
@@ -10,6 +10,7 @@#include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> +#include <linux/unaligned.h> #include <crypto/aes.h> #include <crypto/df_sp80090a.h> #include <crypto/internal/drbg.h>
@@ -141,10 +142,10 @@ int crypto_drbg_ctr_df(struct aes_enckey/* 10.4.2 step 2 -- calculate the entire length of all input data */ list_for_each_entry (seed, seedlist, list) inputlen += seed->len; -drbg_cpu_to_be32 (inputlen, &L_N [0 ]); +put_unaligned_be32 (inputlen, &L_N [0 ]);/* 10.4.2 step 3 */ -drbg_cpu_to_be32 (bytes_to_return, &L_N [4 ]); +put_unaligned_be32 (bytes_to_return, &L_N [4 ]);/* 10.4.2 step 5: length is L_N, input_string, one byte, padding */ padlen = (inputlen +sizeof (L_N ) +1 ) % (blocklen_bytes);
@@ -175,7 +176,7 @@ int crypto_drbg_ctr_df(struct aes_enckey* holds zeros after allocation -- even the increment of i * is irrelevant as the increment remains within length of i */ -drbg_cpu_to_be32 (i, iv); +put_unaligned_be32 (i, iv);/* 10.4.2 step 9.2 -- BCC and concatenation with temp */ drbg_ctr_bcc (aeskey, temp + templen,K , &bcc_list, blocklen_bytes, keylen);
crypto/drbg.c +2 -1
@@ -103,6 +103,7 @@#include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/string_choices.h> +#include <linux/unaligned.h> /*************************************************************** * Backend cipher definitions available to DRBG
@@ -601,7 +602,7 @@ static int drbg_hash_df(struct drbg_stat/* 10.4.1 step 3 */ input[0 ] =1 ; -drbg_cpu_to_be32 ((outlen *8 ), &input[1 ]); +put_unaligned_be32 (outlen *8 , &input[1 ]);/* 10.4.1 step 4.1 -- concatenation of data for input into hash */ drbg_string_fill (&data, input,5 );
include/crypto/internal/drbg.h +0 -18
@@ -10,24 +10,6 @@#define _INTERNAL_DRBG_H/* -* Convert an integer into a byte representation of this integer. -* The byte representation is big-endian -* -* @val value to be converted -* @buf buffer holding the converted integer -- caller must ensure that -* buffer size is at least 32 bit -*/ -static inline void drbg_cpu_to_be32 (__u32 val,unsigned char *buf) -{ -struct s { -__be32 conv; - }; -struct s *conversion = (struct s *)buf; - - conversion->conv =cpu_to_be32 (val); -} - -/* * Concatenation Helper and string operation helper * * SP800-90A requires the concatenation of different data. To avoid copying
Greg Kroah-Hartman
maintainerPATCH 377/518 crypto: drbg - Fix ineffective sanity check
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 040ad83b0e8aa065fd2fc641cacba8491a8b186d upstream.
Fix drbg_healthcheck_sanity() to correctly check the return value of drbg_generate(). drbg_generate() returns 0 on success, or a negative errno value on failure. drbg_healthcheck_sanity() incorrectly assumed that it returned a positive value on success.
This didn't make the sanity check fail, but it made it ineffective.
--- crypto/drbg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
crypto/drbg.c +4 -5
@@ -1737,7 +1737,6 @@ static int drbg_kcapi_seed(struct crypto*/ static inline int __init drbg_healthcheck_sanity (void ) { -int len =0 ;#define OUTBUFLEN 16unsigned char buf[OUTBUFLEN ];struct drbg_state *drbg =NULL ;
@@ -1782,11 +1781,11 @@ static inline int __init drbg_healthchec max_request_bytes =drbg_max_request_bytes (drbg);drbg_string_fill (&addtl, buf, max_addtllen +1 );/* overflow addtllen with additional info string */ - len =drbg_generate (drbg, buf,OUTBUFLEN , &addtl); -BUG_ON (0 < len); + ret =drbg_generate (drbg, buf,OUTBUFLEN , &addtl); +BUG_ON (ret ==0 );/* overflow max_bits */ - len =drbg_generate (drbg, buf, (max_request_bytes +1 ),NULL ); -BUG_ON (0 < len); + ret =drbg_generate (drbg, buf, max_request_bytes +1 ,NULL ); +BUG_ON (ret ==0 );/* overflow max addtllen with personalization string */ ret =drbg_seed (drbg, &addtl, false);
Greg Kroah-Hartman
maintainerPATCH 378/518 crypto: drbg - Fix drbg_max_addtl() on 64-bit kernels
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 6f49f00c981bbb9ef602966f19bfdbef46b681d2 upstream.
On 64-bit kernels, drbg_max_addtl() returns 2**35 bytes. That's too large, for two reasons:
1. SP800-90A says the maximum limit is 2**35 *bits*, not 2**35 bytes. So the implemented limit has confused bits and bytes.
2. When drbg_kcapi_hash() calls crypto_shash_update() on the additional information string, the length is implicitly cast to 'unsigned int'. That truncates the additional information string to U32_MAX bytes.
Fix the maximum additional information string length to always be U32_MAX - 1, causing an error to be returned for any longer lengths.
--- include/crypto/drbg.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-)
include/crypto/drbg.h +7 -11
@@ -148,19 +148,15 @@ static inline size_t drbg_max_request_byreturn (1 <<16 ); } +/* +* SP800-90A allows implementations to support additional info / personalization +* strings of up to 2**35 bits. Implementations can have a smaller maximum. We +* use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a +* size_t, allowing drbg_healthcheck_sanity() to verify its enforcement. +*/ static inline size_t drbg_max_addtl (struct drbg_state *drbg) { -/* SP800-90A requires 2**35 bytes additional info str / pers str */ -#if (__BITS_PER_LONG ==32 ) -/* -* SP800-90A allows smaller maximum numbers to be returned -- we -* return SIZE_MAX - 1 to allow the verification of the enforcement -* of this value in drbg_healthcheck_sanity. -*/ -return (SIZE_MAX -1 ); -#else -return (1UL <<35 ); -#endif +return U32_MAX -1 ; }static inline size_t drbg_max_requests (struct drbg_state *drbg)
Greg Kroah-Hartman
maintainerPATCH 379/518 crypto: drbg - Fix the fips_enabled priority boost
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit a8a1f93080efc83a9ff8452954429ae379e9e614 upstream.
When fips_enabled=1, it seems to have been intended for one of the algorithms defined in crypto/drbg.c to be the highest priority "stdrng" algorithm, so that it is what is used by "stdrng" users.
However, the code only boosts the priority to 400, which is less than the priority 500 used in drivers/crypto/caam/caamprng.c. Thus, the CAAM RNG could be used instead.
Fix this by boosting the priority by 2000 instead of 200.
--- crypto/drbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
crypto/drbg.c +1 -1
@@ -1832,7 +1832,7 @@ static inline void __init drbg_fill_arra* it is selected. */ if (fips_enabled) - alg->base.cra_priority +=200 ; + alg->base.cra_priority +=2000 ; alg->base.cra_ctxsize =sizeof (struct drbg_state ); alg->base.cra_module =THIS_MODULE ;
Greg Kroah-Hartman
maintainerPATCH 380/518 crypto: qat - centralize bus master enable
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit e5712ff82947dd02d118cee119ed36cec671d814 upstream.
QAT driver currently toggles PCI bus mastering in multiple places (probe paths, and reset callbacks). This makes BME state depend on call ordering and on what PCI command bits were captured in saved PCI config state.
Make BME control explicit and deterministic:
- remove pci_set_master() from device-specific probe paths
- add adf_set_bme() and call it from adf_dev_init() so BME is enabled at one point before device bring-up
- drop redundant pci_set_master() and pci_clear_master from adf_aer.c and rely on the unified init path for BME enablement
This is in preparation for adding reset_prepare() and reset_done() hooks. In the PCI reset callback flow, the PCI core saves and restores device configuration state around reset_prepare() and reset_done(). This change is needed to ensure that we are able to properly shutdown or reinitialize the device post sysfs triggered resets.
--- drivers/crypto/intel/qat/qat_420xx/adf_drv.c | 2 -- drivers/crypto/intel/qat/qat_4xxx/adf_drv.c | 2 -- drivers/crypto/intel/qat/qat_6xxx/adf_drv.c | 2 -- drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c62x/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_common/adf_aer.c | 10 +++++++--- drivers/crypto/intel/qat/qat_common/adf_common_drv.h | 1 + drivers/crypto/intel/qat/qat_common/adf_init.c | 2 ++ drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c | 1 - drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c | 1 - 12 files changed, 10 insertions(+), 15 deletions(-)
drivers/crypto/intel/qat/qat_420xx/adf_drv.c +0 -2
@@ -146,8 +146,6 @@ static int adf_probe(struct pci_dev *pde } } -pci_set_master (pdev); -if (pci_save_state (pdev)) {dev_err (&pdev->dev,"Failed to save pci state.\n" ); ret = -ENOMEM ;
drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +0 -2
@@ -148,8 +148,6 @@ static int adf_probe(struct pci_dev *pde } } -pci_set_master (pdev); -if (pci_save_state (pdev)) {dev_err (&pdev->dev,"Failed to save pci state.\n" ); ret = -ENOMEM ;
drivers/crypto/intel/qat/qat_6xxx/adf_drv.c +0 -2
@@ -189,8 +189,6 @@ static int adf_probe(struct pci_dev *pde } } -pci_set_master (pdev); -/* * The PCI config space is saved at this point and will be restored * after a Function Level Reset (FLR) as the FLR does not completely
drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +0 -1
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pde goto out_err_free_reg; } } -pci_set_master (pdev);if (pci_save_state (pdev)) {dev_err (&pdev->dev,"Failed to save pci state\n" );
drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c +0 -1
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pde goto out_err_free_reg; } } -pci_set_master (pdev);/* Completion for VF2PF request/response message exchange */ init_completion (&accel_dev->vf.msg_received);
drivers/crypto/intel/qat/qat_c62x/adf_drv.c +0 -1
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pde goto out_err_free_reg; } } -pci_set_master (pdev);if (pci_save_state (pdev)) {dev_err (&pdev->dev,"Failed to save pci state\n" );
drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c +0 -1
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pde goto out_err_free_reg; } } -pci_set_master (pdev);/* Completion for VF2PF request/response message exchange */ init_completion (&accel_dev->vf.msg_received);
drivers/crypto/intel/qat/qat_common/adf_aer.c +7 -3
@@ -41,7 +41,6 @@ static pci_ers_result_t adf_error_detectadf_error_notifier (accel_dev);adf_pf2vf_notify_fatal_error (accel_dev);adf_dev_restarting_notify (accel_dev); -pci_clear_master (pdev);adf_dev_down (accel_dev);return PCI_ERS_RESULT_NEED_RESET ;
@@ -106,6 +105,13 @@ void adf_dev_restore(struct adf_accel_de } } +void adf_set_bme (struct adf_accel_dev *accel_dev) +{ +struct pci_dev *pdev =accel_to_pci_dev (accel_dev); + +pci_set_master (pdev); +} +static void adf_device_sriov_worker (struct work_struct *work) { struct adf_sriov_dev_data *sriov_data =
@@ -198,8 +204,6 @@ static pci_ers_result_t adf_slot_reset(sreturn PCI_ERS_RESULT_DISCONNECT ; } -if (!pdev->is_busmaster) -pci_set_master (pdev);pci_restore_state (pdev); res =adf_dev_up (accel_dev, false);if (res && res != -EALREADY )
drivers/crypto/intel/qat/qat_common/adf_common_drv.h +1 -0
@@ -84,6 +84,7 @@ extern const struct pci_error_handlers avoid adf_reset_sbr (struct adf_accel_dev *accel_dev);void adf_reset_flr (struct adf_accel_dev *accel_dev);void adf_dev_restore (struct adf_accel_dev *accel_dev); +void adf_set_bme (struct adf_accel_dev *accel_dev);int adf_init_aer (void );void adf_exit_aer (void );int adf_init_arb (struct adf_accel_dev *accel_dev);
drivers/crypto/intel/qat/qat_common/adf_init.c +2 -0
@@ -74,6 +74,8 @@ static int adf_dev_init(struct adf_accelreturn -EFAULT ; } +adf_set_bme (accel_dev); +if (!test_bit (ADF_STATUS_CONFIGURED , &accel_dev->status) && !accel_dev->is_vf) {dev_err (&GET_DEV (accel_dev),"Device not configured\n" );
drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +0 -1
@@ -167,7 +167,6 @@ static int adf_probe(struct pci_dev *pde goto out_err_free_reg; } } -pci_set_master (pdev);if (pci_save_state (pdev)) {dev_err (&pdev->dev,"Failed to save pci state\n" );
drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c +0 -1
@@ -163,7 +163,6 @@ static int adf_probe(struct pci_dev *pde goto out_err_free_reg; } } -pci_set_master (pdev);/* Completion for VF2PF request/response message exchange */ init_completion (&accel_dev->vf.msg_received);
Greg Kroah-Hartman
maintainerPATCH 381/518 crypto: qat - fix restarting state leak on allocation failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 7d3ed20f7e46b3e991936fedd7a28f3ff4aec8d2 upstream.
In adf_dev_aer_schedule_reset(), ADF_STATUS_RESTARTING is set before allocating reset_data. If the allocation fails, the function returns -ENOMEM without queuing reset work, so nothing ever clears the bit. This leaves the device permanently stuck in the restarting state, causing all subsequent reset attempts to be silently skipped.
Fix this by using test_and_set_bit() to atomically claim the RESTARTING state, preventing duplicate reset scheduling races under concurrent fatal error reporting. If the subsequent allocation fails, clear the bit to restore clean state so future reset attempts can proceed.
--- drivers/crypto/intel/qat/qat_common/adf_aer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/crypto/intel/qat/qat_common/adf_aer.c +4 -3
@@ -162,13 +162,14 @@ static int adf_dev_aer_schedule_reset(ststruct adf_reset_dev_data *reset_data;if (!adf_dev_started (accel_dev) || -test_bit (ADF_STATUS_RESTARTING , &accel_dev->status)) +test_and_set_bit (ADF_STATUS_RESTARTING , &accel_dev->status))return 0 ; -set_bit (ADF_STATUS_RESTARTING , &accel_dev->status); reset_data =kzalloc_obj (*reset_data); -if (!reset_data) +if (!reset_data) { +clear_bit (ADF_STATUS_RESTARTING , &accel_dev->status);return -ENOMEM ; + } reset_data->accel_dev = accel_dev;init_completion (&reset_data->compl); reset_data->mode = mode;
Greg Kroah-Hartman
maintainerPATCH 382/518 crypto: qat - handle sysfs-triggered reset callbacks
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 4627ef7019bc532f992c0723e881811ce12f0a02 upstream.
A reset requested through /sys/bus/pci/devices/.../reset invokes the driver reset_prepare() and reset_done() callbacks. The QAT driver does not implement those callbacks today, so the reset proceeds without quiescing the device or bringing it back up afterward, which leaves the device unusable.
Hook reset_prepare() and reset_done() into adf_err_handler so the common shutdown and recovery flow also runs for reset. Skip device quiesce if the device is already in a down state.
--- drivers/crypto/intel/qat/qat_common/adf_aer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/crypto/intel/qat/qat_common/adf_aer.c +12 -0
@@ -223,10 +223,22 @@ static void adf_resume(struct pci_dev *pdev_info (&pdev->dev,"Device is up and running\n" ); } +static void adf_reset_prepare (struct pci_dev *pdev) +{ +reset_prepare (pdev); +} + +static void adf_reset_done (struct pci_dev *pdev) +{ +reset_done (pdev); +} +const struct pci_error_handlers adf_err_handler = { .error_detected = adf_error_detected, .slot_reset = adf_slot_reset, .resume = adf_resume, + .reset_prepare = adf_reset_prepare, + .reset_done = adf_reset_done, };EXPORT_SYMBOL_GPL (adf_err_handler);
Greg Kroah-Hartman
maintainerPATCH 383/518 crypto: qat - keep VFs enabled during reset
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 57518500053987672050dc2f7bf8a774d5d52fd9 upstream.
When a reset is triggered via sysfs, the PCI core invokes the reset_prepare() callback while holding pci_dev_lock(), which includes the PCI configuration space access semaphore. If reset_prepare() calls adf_dev_down(), the call chain adf_dev_stop() -> adf_disable_sriov() -> pci_disable_sriov() attempts to acquire the same semaphore, resulting in a deadlock.
Avoid this by skipping pci_disable_sriov() when ADF_STATUS_RESTARTING is set. During reset the PCI topology is preserved, so VF devices remain valid and enumerated across the reset. VF notification and the quiesce handshake via adf_pf2vf_notify_restarting() are still performed unconditionally so that VFs stop submitting work before the PF shuts down.
Correspondingly, skip pci_enable_sriov() in adf_enable_sriov() when VFs are already present, since their PCI devices were preserved from before the restart.
This is in preparation for adding reset_prepare() and reset_done() callbacks in adf_aer.c.
--- drivers/crypto/intel/qat/qat_common/adf_sriov.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/crypto/intel/qat/qat_common/adf_sriov.c +11 -1
@@ -91,6 +91,10 @@ static int adf_enable_sriov(struct adf_a/* Enable VF to PF interrupts for all VFs */ adf_enable_all_vf2pf_interrupts (accel_dev, totalvfs); +/* Do not enable SR-IOV if already enabled */ +if (pci_num_vf (pdev)) +return 0 ; +/* * Due to the hardware design, when SR-IOV and the ring arbiter * are enabled all the VFs supported in hardware must be enabled in
@@ -260,7 +264,13 @@ void adf_disable_sriov(struct adf_accel_adf_pf2vf_notify_restarting (accel_dev);adf_pf2vf_wait_for_restarting_complete (accel_dev); -pci_disable_sriov (accel_to_pci_dev (accel_dev)); +/* +* When the device is restarting, preserve VF PCI devices across +* the reset by skipping pci_disable_sriov(). VFs are notified to +* quiesce regardless so the PF can safely shut down. +*/ +if (!test_bit (ADF_STATUS_RESTARTING , &accel_dev->status)) +pci_disable_sriov (accel_to_pci_dev (accel_dev));/* Block VF2PF work and disable VF to PF interrupts */ adf_disable_all_vf2pf_interrupts (accel_dev);
Greg Kroah-Hartman
maintainerPATCH 384/518 crypto: qat - notify fatal error before AER reset preparation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 6931835f2fdd0cb9b1c7791748d7e67d0749056a upstream.
Send fatal error notifications to subsystems and VFs as soon as AER error detection starts, before entering the reset preparation shutdown sequence.
This reduces notification latency and ensures peers are informed immediately on fatal detection, rather than after restart-state setup and arbitration teardown.
--- drivers/crypto/intel/qat/qat_common/adf_aer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/intel/qat/qat_common/adf_aer.c +2 -2
@@ -33,13 +33,13 @@ static pci_ers_result_t adf_error_detectreturn PCI_ERS_RESULT_DISCONNECT ; } +adf_error_notifier (accel_dev); +adf_pf2vf_notify_fatal_error (accel_dev);set_bit (ADF_STATUS_RESTARTING , &accel_dev->status);if (accel_dev->hw_device->exit_arb) {dev_dbg (&pdev->dev,"Disabling arbitration\n" ); accel_dev->hw_device->exit_arb (accel_dev); } -adf_error_notifier (accel_dev); -adf_pf2vf_notify_fatal_error (accel_dev);adf_dev_restarting_notify (accel_dev);adf_dev_down (accel_dev);
Greg Kroah-Hartman
maintainerPATCH 385/518 crypto: qat - protect service table iterations with service_lock
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 5c6f845e77ec35f9b7b047cc8f9789bf397cdd3e upstream.
The service_table list is protected by service_lock when entries are added or removed (in adf_service_add() and adf_service_remove()), but several functions iterate over the list without holding this lock.
A concurrent adf_service_register() or adf_service_unregister() call could modify the list during traversal, leading to list corruption or a use-after-free.
Fix this by holding service_lock across all list_for_each_entry() iterations of service_table in adf_dev_init(), adf_dev_start(), adf_dev_stop(), adf_dev_shutdown(), adf_dev_restarting_notify(), adf_dev_restarted_notify(), and adf_error_notifier().
The lock ordering is safe: callers of the static helpers (adf_dev_up() and adf_dev_down()) acquire state_lock before service_lock, and no event_hld callback or service_lock holder ever acquires state_lock in the reverse order.
--- drivers/crypto/intel/qat/qat_common/adf_init.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/crypto/intel/qat/qat_common/adf_init.c +16 -0
@@ -155,15 +155,18 @@ static int adf_dev_init(struct adf_accel* This is to facilitate any ordering dependencies between services * prior to starting any of the accelerators. */ +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (service->event_hld (accel_dev,ADF_EVENT_INIT )) {dev_err (&GET_DEV (accel_dev),"Failed to initialise service %s\n" , service->name); +mutex_unlock (&service_lock);return -EFAULT ; }set_bit (accel_dev->accel_id, service->init_status); } +mutex_unlock (&service_lock);return 0 ; }
@@ -233,15 +236,18 @@ static int adf_dev_start(struct adf_acceif (ret && ret != -EOPNOTSUPP )return ret; +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (service->event_hld (accel_dev,ADF_EVENT_START )) {dev_err (&GET_DEV (accel_dev),"Failed to start service %s\n" , service->name); +mutex_unlock (&service_lock);return -EFAULT ; }set_bit (accel_dev->accel_id, service->start_status); } +mutex_unlock (&service_lock);clear_bit (ADF_STATUS_STARTING , &accel_dev->status);set_bit (ADF_STATUS_STARTED , &accel_dev->status);
@@ -315,6 +321,7 @@ static void adf_dev_stop(struct adf_acceqat_comp_algs_unregister (hw_data->accel_capabilities_ext_mask);clear_bit (ADF_STATUS_COMP_ALGS_REGISTERED , &accel_dev->status); +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (!test_bit (accel_dev->accel_id, service->start_status))continue ;
@@ -326,6 +333,7 @@ static void adf_dev_stop(struct adf_acceclear_bit (accel_dev->accel_id, service->start_status); } } +mutex_unlock (&service_lock);if (hw_data->stop_timer) hw_data->stop_timer (accel_dev);
@@ -375,6 +383,7 @@ static void adf_dev_shutdown(struct adf_ &accel_dev->status); } +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (!test_bit (accel_dev->accel_id, service->init_status))continue ;
@@ -385,6 +394,7 @@ static void adf_dev_shutdown(struct adf_else clear_bit (accel_dev->accel_id, service->init_status); } +mutex_unlock (&service_lock);adf_rl_exit (accel_dev);
@@ -419,12 +429,14 @@ int adf_dev_restarting_notify(struct adf {struct service_hndl *service; +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (service->event_hld (accel_dev,ADF_EVENT_RESTARTING ))dev_err (&GET_DEV (accel_dev),"Failed to restart service %s.\n" , service->name); } +mutex_unlock (&service_lock);return 0 ; }
@@ -432,12 +444,14 @@ int adf_dev_restarted_notify(struct adf_ {struct service_hndl *service; +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (service->event_hld (accel_dev,ADF_EVENT_RESTARTED ))dev_err (&GET_DEV (accel_dev),"Failed to restart service %s.\n" , service->name); } +mutex_unlock (&service_lock);return 0 ; }
@@ -445,12 +459,14 @@ void adf_error_notifier(struct adf_accel {struct service_hndl *service; +mutex_lock (&service_lock);list_for_each_entry (service, &service_table, list) {if (service->event_hld (accel_dev,ADF_EVENT_FATAL_ERROR ))dev_err (&GET_DEV (accel_dev),"Failed to send error event to %s.\n" , service->name); } +mutex_unlock (&service_lock); }int adf_dev_down (struct adf_accel_dev *accel_dev)
Greg Kroah-Hartman
maintainerPATCH 386/518 crypto: qat - skip restart for down devices
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 9676657117b79f88c22875680c36d7da84b75eca upstream.
Skip the shutdown and restart flow when adf_slot_reset() is entered for a device that is already down. In that case, leave ADF_STATUS_RESTARTING clear and let adf_slot_reset() restore PCI function state without calling adf_dev_up(), re-enabling SR-IOV, or sending restarted notifications.
This is in preparation for adding reset_prepare() and reset_done() callbacks in adf_aer.c.
--- drivers/crypto/intel/qat/qat_common/adf_aer.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/crypto/intel/qat/qat_common/adf_aer.c +8 -0
@@ -33,6 +33,9 @@ static pci_ers_result_t adf_error_detectreturn PCI_ERS_RESULT_DISCONNECT ; } +if (!adf_dev_started (accel_dev)) +return PCI_ERS_RESULT_CAN_RECOVER ; +adf_error_notifier (accel_dev);adf_pf2vf_notify_fatal_error (accel_dev);set_bit (ADF_STATUS_RESTARTING , &accel_dev->status);
@@ -205,6 +208,9 @@ static pci_ers_result_t adf_slot_reset(sreturn PCI_ERS_RESULT_DISCONNECT ; } +if (!adf_devmgr_in_reset (accel_dev)) + goto reset_complete; +pci_restore_state (pdev); res =adf_dev_up (accel_dev, false);if (res && res != -EALREADY )
@@ -214,6 +220,8 @@ static pci_ers_result_t adf_slot_reset(sadf_pf2vf_notify_restarted (accel_dev);adf_dev_restarted_notify (accel_dev);clear_bit (ADF_STATUS_RESTARTING , &accel_dev->status); + +reset_complete:return PCI_ERS_RESULT_RECOVERED ; }
Greg Kroah-Hartman
maintainerPATCH 387/518 crypto: qat - validate RSA CRT component lengths
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Giovanni Cabiddu <[email protected]>
commit b3ac78756588059729b9195fcc9f4b37d54057a5 upstream.
The generic RSA key parser (rsa_helper.c) bounds each CRT component (p, q, dp, dq, qinv) by the modulus size n_sz, but qat_rsa_setkey_crt() allocates half-size DMA buffers (key_sz / 2) and right-aligns each component with:
memcpy(dst + half_key_sz - len, src, len)
When a CRT component is larger than half_key_sz the subtraction underflows and memcpy writes past the DMA buffer, causing memory corruption.
Add a len > half_key_sz check next to the existing !len check for each of the five CRT components so the driver falls back to the non-CRT path instead of writing out of bounds.
--- drivers/crypto/intel/qat/qat_common/qat_asym_algs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/crypto/intel/qat/qat_common/qat_asym_algs.c +5 -5
@@ -1085,7 +1085,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->p; len = rsa_key->p_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto err; ctx->p =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_p,GFP_KERNEL );if (!ctx->p)
@@ -1096,7 +1096,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->q; len = rsa_key->q_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_p; ctx->q =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_q,GFP_KERNEL );if (!ctx->q)
@@ -1107,7 +1107,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->dp; len = rsa_key->dp_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_q; ctx->dp =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_dp,GFP_KERNEL );
@@ -1119,7 +1119,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->dq; len = rsa_key->dq_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_dp; ctx->dq =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_dq,GFP_KERNEL );
@@ -1131,7 +1131,7 @@ static void qat_rsa_setkey_crt(struct qa ptr = rsa_key->qinv; len = rsa_key->qinv_sz;qat_rsa_drop_leading_zeros (&ptr, &len); -if (!len) +if (!len || len > half_key_sz) goto free_dq; ctx->qinv =dma_alloc_coherent (dev, half_key_sz, &ctx->dma_qinv,GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 388/518 crypto: qat - factor out AER reset helpers
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahsan Atta <[email protected]>
commit 56707afb92fee371c0f2e04332c9aa03cdb89793 upstream.
Move the shutdown and recovery sequences out of adf_error_detected() and adf_slot_reset() into reset_prepare() and reset_done() helpers.
This makes the AER recovery path easier to follow and prepares the common reset flow for reuse by additional PCI reset callbacks without duplicating the logic.
No functional change intended.
--- drivers/crypto/intel/qat/qat_common/adf_aer.c | 86 ++++++++++++++++---------- 1 file changed, 53 insertions(+), 33 deletions(-)
drivers/crypto/intel/qat/qat_common/adf_aer.c +53 -33
@@ -17,27 +17,18 @@ struct adf_fatal_error_data {static struct workqueue_struct *device_reset_wq;static struct workqueue_struct *device_sriov_wq; -static pci_ers_result_t adf_error_detected (struct pci_dev *pdev, -pci_channel_state_t state) +static pci_ers_result_t reset_prepare (struct pci_dev *pdev) {struct adf_accel_dev *accel_dev =adf_devmgr_pci_to_accel_dev (pdev); -dev_info (&pdev->dev,"Acceleration driver hardware error detected.\n" );if (!accel_dev) {dev_err (&pdev->dev,"Can't find acceleration device\n" );return PCI_ERS_RESULT_DISCONNECT ; } -if (state == pci_channel_io_perm_failure) { -dev_err (&pdev->dev,"Can't recover from device error\n" ); -return PCI_ERS_RESULT_DISCONNECT ; - } -if (!adf_dev_started (accel_dev))return PCI_ERS_RESULT_CAN_RECOVER ; -adf_error_notifier (accel_dev); -adf_pf2vf_notify_fatal_error (accel_dev);set_bit (ADF_STATUS_RESTARTING , &accel_dev->status);if (accel_dev->hw_device->exit_arb) {dev_dbg (&pdev->dev,"Disabling arbitration\n" );
@@ -49,6 +40,57 @@ static pci_ers_result_t adf_error_detectreturn PCI_ERS_RESULT_NEED_RESET ; } +static pci_ers_result_t reset_done (struct pci_dev *pdev) +{ +struct adf_accel_dev *accel_dev =adf_devmgr_pci_to_accel_dev (pdev); +int res; + +if (!accel_dev) { +dev_err (&pdev->dev,"Can't find acceleration device\n" ); +return PCI_ERS_RESULT_DISCONNECT ; + } + +if (!adf_devmgr_in_reset (accel_dev)) + goto reset_complete; + +pci_restore_state (pdev); + res =adf_dev_up (accel_dev, false); +if (res && res != -EALREADY ) +return PCI_ERS_RESULT_DISCONNECT ; + +adf_reenable_sriov (accel_dev); +adf_pf2vf_notify_restarted (accel_dev); +adf_dev_restarted_notify (accel_dev); +clear_bit (ADF_STATUS_RESTARTING , &accel_dev->status); + +reset_complete: +dev_info (&pdev->dev,"Device reset completed successfully\n" ); + +return PCI_ERS_RESULT_RECOVERED ; +} + +static pci_ers_result_t adf_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) +{ +struct adf_accel_dev *accel_dev =adf_devmgr_pci_to_accel_dev (pdev); + +dev_info (&pdev->dev,"Acceleration driver hardware error detected.\n" ); +if (!accel_dev) { +dev_err (&pdev->dev,"Can't find acceleration device\n" ); +return PCI_ERS_RESULT_DISCONNECT ; + } + +if (state == pci_channel_io_perm_failure) { +dev_err (&pdev->dev,"Can't recover from device error\n" ); +return PCI_ERS_RESULT_DISCONNECT ; + } + +adf_error_notifier (accel_dev); +adf_pf2vf_notify_fatal_error (accel_dev); + +return reset_prepare (pdev); +} +/* reset dev data */ struct adf_reset_dev_data {int mode;
@@ -200,29 +242,7 @@ static int adf_dev_aer_schedule_reset(ststatic pci_ers_result_t adf_slot_reset (struct pci_dev *pdev) { -struct adf_accel_dev *accel_dev =adf_devmgr_pci_to_accel_dev (pdev); -int res =0 ; - -if (!accel_dev) { -pr_err ("QAT: Can't find acceleration device\n" ); -return PCI_ERS_RESULT_DISCONNECT ; - } - -if (!adf_devmgr_in_reset (accel_dev)) - goto reset_complete; - -pci_restore_state (pdev); - res =adf_dev_up (accel_dev, false); -if (res && res != -EALREADY ) -return PCI_ERS_RESULT_DISCONNECT ; - -adf_reenable_sriov (accel_dev); -adf_pf2vf_notify_restarted (accel_dev); -adf_dev_restarted_notify (accel_dev); -clear_bit (ADF_STATUS_RESTARTING , &accel_dev->status); - -reset_complete: -return PCI_ERS_RESULT_RECOVERED ; +return reset_done (pdev); }static void adf_resume (struct pci_dev *pdev)
Greg Kroah-Hartman
maintainerPATCH 389/518 crypto: talitos - use dma_sync_single_for_cpu() before reading descriptor header
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit e17ff3d6ff907dc8406261e8fd3e1fc8a908f0f6 upstream.
In order to know if a descriptor has been processed by the device, the driver polls the FIFO to see if DESC_HDR_DONE is set on a descriptor header to confirm completion.
The current code does not make sure that the CPU gets up to date data before reading the descriptor.
Fix this by calling dma_sync_single_for_cpu() before reading memory written by the device.
--- drivers/crypto/talitos.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)
drivers/crypto/talitos.c +20 -8
@@ -322,19 +322,31 @@ static int talitos_submit(struct devicereturn -EINPROGRESS ; } -static __be32 get_request_hdr (struct talitos_request *request,bool is_sec1) +static __be32 get_request_hdr (struct device *dev, +struct talitos_request *request,bool is_sec1) {struct talitos_edesc *edesc; -if (!is_sec1) +if (!is_sec1) { +dma_sync_single_for_cpu (dev, request->dma_desc, +TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); +return request->desc->hdr; + } -if (!request->desc->next_desc) +if (!request->desc->next_desc) { +dma_sync_single_for_cpu (dev, request->dma_desc, +TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL );return request->desc->hdr1; - - edesc = container_of(request->desc, struct talitos_edesc, desc); - -return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))->hdr1; + }else { +dma_sync_single_for_cpu (dev, +be32_to_cpu (request->desc->next_desc), +TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); + edesc = container_of(request->desc, struct talitos_edesc, desc); + +return ((struct talitos_desc *)(edesc->buf + edesc->dma_len)) + ->hdr1; + } }/*
@@ -358,7 +370,7 @@ static void flush_channel(struct device/* descriptors with their done bits set don't get the error */ rmb (); - hdr =get_request_hdr (request, is_sec1); + hdr =get_request_hdr (dev, request, is_sec1);if ((hdr &DESC_HDR_DONE ) ==DESC_HDR_DONE ) status =0 ;
Greg Kroah-Hartman
maintainerPATCH 390/518 crypto: talitos - add chaining of arbitrary number of descriptor for the SEC1
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit f126384ed55279c3b676f89d5ab547b8de8df782 upstream.
The SEC1 hardware can process a chain of descriptors without host intervention. Only the hash implementation currently use this feature, but with a chain of at most 2 descriptors added in commit 37b5e8897eb5 ("crypto: talitos - chain in buffered data for ahash on SEC1").
Add supports for chaining an arbitrary number of descriptors in a chain.
Adapt the ahash implementation to make it compatible.
--- drivers/crypto/talitos.c | 180 +++++++++++++++++++++++++++++++---------------- drivers/crypto/talitos.h | 2 2 files changed, 124 insertions(+), 58 deletions(-)
drivers/crypto/talitos.c +122 -58
@@ -273,7 +273,10 @@ static int talitos_submit(struct device void *context, int error), void *context) { + struct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc);struct talitos_private *priv =dev_get_drvdata (dev); +dma_addr_t dma_desc, prev_dma_desc; +struct talitos_edesc *prev_edesc =NULL ;struct talitos_request *request;unsigned long flags;int head;
@@ -292,10 +295,31 @@ static int talitos_submit(struct device/* map descriptor and save caller data */ if (is_sec1) { - desc->hdr1 = desc->hdr; - request->dma_desc =dma_map_single (dev, &desc->hdr1, +while (edesc) { + edesc->desc.hdr1 = edesc->desc.hdr; + + dma_desc =dma_map_single (dev, &edesc->desc.hdr1, +TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + +if (!prev_edesc) { + request->dma_desc = dma_desc; + goto next; + } + +/* Chain in any previous descriptors. */ + + prev_edesc->desc.next_desc =cpu_to_be32 (dma_desc); + +dma_sync_single_for_device (dev, prev_dma_desc,TALITOS_DESC_SIZE , -DMA_BIDIRECTIONAL ); +DMA_TO_DEVICE ); + +next: + prev_edesc = edesc; + prev_dma_desc = dma_desc; + edesc = edesc->next_desc; + } }else { request->dma_desc = dma_map_single(dev, desc, TALITOS_DESC_SIZE,
@@ -326,6 +350,7 @@ static __be32 get_request_hdr(struct dev struct talitos_request *request, bool is_sec1) {struct talitos_edesc *edesc; +dma_addr_t dma_desc;if (!is_sec1) { dma_sync_single_for_cpu(dev, request->dma_desc,
@@ -334,19 +359,17 @@ static __be32 get_request_hdr(struct devreturn request->desc->hdr; } -if (!request->desc->next_desc) { -dma_sync_single_for_cpu (dev, request->dma_desc, -TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); -return request->desc->hdr1; - }else { -dma_sync_single_for_cpu (dev, -be32_to_cpu (request->desc->next_desc), -TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); - edesc = container_of(request->desc, struct talitos_edesc, desc); - -return ((struct talitos_desc *)(edesc->buf + edesc->dma_len)) - ->hdr1; + edesc = container_of(request->desc, struct talitos_edesc, desc); + dma_desc = request->dma_desc; +while (edesc->next_desc) { + dma_desc =be32_to_cpu (edesc->desc.next_desc); + edesc = edesc->next_desc; } + +dma_sync_single_for_cpu (dev, dma_desc,TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + +return edesc->desc.hdr1; }/*
@@ -356,6 +379,7 @@ static void flush_channel(struct device {struct talitos_private *priv =dev_get_drvdata (dev);struct talitos_request *request, saved_req; +struct talitos_edesc *edesc;unsigned long flags;int tail, status;bool is_sec1 =has_ftr_sec1 (priv);
@@ -380,9 +404,22 @@ static void flush_channel(struct deviceelse status = error; -dma_unmap_single (dev, request->dma_desc, -TALITOS_DESC_SIZE , -DMA_BIDIRECTIONAL ); +if (is_sec1) { +dma_unmap_single (dev, request->dma_desc, +TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); + edesc =container_of (request->desc, + struct talitos_edesc, desc); +while (edesc->next_desc) { +dma_unmap_single ( + dev,be32_to_cpu (edesc->desc.next_desc), +TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); + edesc = edesc->next_desc; + } + }else { +dma_unmap_single (dev, request->dma_desc, +TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + }/* copy entries so we can call callback outside lock */ saved_req.desc = request->desc;
@@ -477,8 +514,12 @@ DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CHstatic __be32 current_desc_hdr (struct device *dev,int ch) {struct talitos_private *priv =dev_get_drvdata (dev); +bool is_sec1 =has_ftr_sec1 (priv); +struct talitos_request *request; +struct talitos_edesc *edesc;int tail, iter;dma_addr_t cur_desc; +__be32 hdr =0 ; cur_desc = ((u64 )in_be32 (priv->chan[ch].reg +TALITOS_CDPR )) <<32 ; cur_desc |=in_be32 (priv->chan[ch].reg +TALITOS_CDPR_LO );
@@ -489,27 +530,35 @@ static __be32 current_desc_hdr(struct de } tail = priv->chan[ch].tail; - iter = tail; -while (priv->chan[ch].fifo[iter].dma_desc != cur_desc && - priv->chan[ch].fifo[iter].desc->next_desc !=cpu_to_be32 (cur_desc)) { - iter = (iter +1 ) & (priv->fifo_len -1 ); -if (iter == tail) { -dev_err (dev,"couldn't locate current descriptor\n" ); -return 0 ; +do { + request = &priv->chan[ch].fifo[iter]; + +if (request->dma_desc == cur_desc) { + hdr = request->desc->hdr; + }else if (is_sec1) { + edesc =container_of (request->desc, + struct talitos_edesc, desc); +while (edesc->next_desc) { +if (edesc->desc.next_desc == +cpu_to_be32 (cur_desc)) { + hdr = edesc->next_desc->desc.hdr1; +break ; + } + edesc = edesc->next_desc; + } } - } -if (priv->chan[ch].fifo[iter].desc->next_desc ==cpu_to_be32 (cur_desc)) { -struct talitos_edesc *edesc; +if (hdr) +break ; - edesc =container_of (priv->chan[ch].fifo[iter].desc, - struct talitos_edesc, desc); -return ((struct talitos_desc *) - (edesc->buf + edesc->dma_len))->hdr; - } + iter = (iter +1 ) & (priv->fifo_len -1 ); + }while (iter != tail); + +if (!hdr) +dev_err (dev,"couldn't locate current descriptor\n" ); -return priv->chan[ch].fifo[iter].desc->hdr; +return hdr; }/*
@@ -1408,10 +1457,6 @@ static struct talitos_edesc *talitos_ede dma_len =0 ; } alloc_len += icv_stashing ? authsize :0 ; - -/* if its a ahash, add space for a second desc next to the first one */ -if (is_sec1 && !dst) - alloc_len +=sizeof (struct talitos_desc ); alloc_len += ivsize; edesc =kmalloc (ALIGN (alloc_len,dma_get_cache_alignment ()), flags);
@@ -1427,6 +1472,7 @@ static struct talitos_edesc *talitos_ede edesc->dst_nents = dst_nents; edesc->iv_dma = iv_dma; edesc->dma_len = dma_len; + edesc->next_desc =NULL ;if (dma_len) edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0], edesc->dma_len,
@@ -1727,8 +1773,10 @@ static void common_nonsnoop_hash_unmap(sstruct talitos_private *priv =dev_get_drvdata (dev);bool is_sec1 =has_ftr_sec1 (priv);struct talitos_desc *desc = &edesc->desc; -struct talitos_desc *desc2 = (struct talitos_desc *) - (edesc->buf + edesc->dma_len); +struct talitos_desc *desc2; + +if (desc->next_desc) + desc2 = &edesc->next_desc->desc;unmap_single_talitos_ptr (dev, &desc->ptr[5 ],DMA_FROM_DEVICE ); if (desc->next_desc &&
@@ -1756,10 +1804,17 @@ static void common_nonsnoop_hash_unmap(sif (edesc->dma_len)dma_unmap_single (dev, edesc->dma_link_tbl, edesc->dma_len,DMA_BIDIRECTIONAL ); +} -if (desc->next_desc) -dma_unmap_single (dev,be32_to_cpu (desc->next_desc), -TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); +static void free_edesc_list_from (struct talitos_edesc *edesc) +{ +struct talitos_edesc *next; + +while (edesc) { + next = edesc->next_desc; +kfree (edesc); + edesc = next; + } } static void ahash_done(struct device *dev,
@@ -1778,7 +1833,7 @@ static void ahash_done(struct device *de }common_nonsnoop_hash_unmap (dev, edesc, areq); -kfree (edesc); +free_edesc_list_from (edesc);if (err) {ahash_request_complete (areq, err);
@@ -1894,14 +1949,23 @@ static int common_nonsnoop_hash(struct ttalitos_handle_buggy_hash (ctx, edesc, &desc->ptr[3 ]);if (is_sec1 && req_ctx->nbuf && length) { -struct talitos_desc *desc2 = (struct talitos_desc *) - (edesc->buf + edesc->dma_len); -dma_addr_t next_desc; +struct talitos_edesc *edesc2; +struct talitos_desc *desc2; + + edesc2 =kzalloc (sizeof (*edesc2), + areq->base.flags &CRYPTO_TFM_REQ_MAY_SLEEP ? +GFP_KERNEL : +GFP_ATOMIC ); +if (!edesc2) { + ret = -ENOMEM ; + goto err; + } + edesc->next_desc = edesc2; + + desc2 = &edesc2->desc; -memset (desc2,0 ,sizeof (*desc2)); desc2->hdr = desc->hdr; desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT ; - desc2->hdr1 = desc2->hdr; desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD ; desc->hdr |=DESC_HDR_MODE0_MDEU_CONT ; desc->hdr &= ~DESC_HDR_DONE_NOTIFY ;
@@ -1925,21 +1989,21 @@ static int common_nonsnoop_hash(struct t req_ctx->hw_context_size, req_ctx->hw_context, DMA_FROM_DEVICE); - - next_desc =dma_map_single (dev, &desc2->hdr1,TALITOS_DESC_SIZE , -DMA_BIDIRECTIONAL ); - desc->next_desc =cpu_to_be32 (next_desc); }if (sync_needed)dma_sync_single_for_device (dev, edesc->dma_link_tbl, edesc->dma_len,DMA_BIDIRECTIONAL ); - ret =talitos_submit (dev, ctx->ch, desc, callback, areq); -if (ret != -EINPROGRESS ) { -common_nonsnoop_hash_unmap (dev, edesc, areq); -kfree (edesc); - } + ret =talitos_submit (dev, ctx->ch, desc, callback, + areq); +if (ret != -EINPROGRESS ) + goto err; + +return -EINPROGRESS ; +err: +common_nonsnoop_hash_unmap (dev, edesc, areq); +kfree (edesc);return ret; }
drivers/crypto/talitos.h +2 -0
@@ -49,6 +49,7 @@ struct talitos_desc {* @iv_dma: dma address of iv for checking continuity and link table * @dma_len: length of dma mapped link_tbl space * @dma_link_tbl: bus physical address of link_tbl/buf +* @next_desc: next descriptor * @desc: h/w descriptor * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2) * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
@@ -63,6 +64,7 @@ struct talitos_edesc {dma_addr_t iv_dma;int dma_len;dma_addr_t dma_link_tbl; +struct talitos_edesc *next_desc;struct talitos_desc desc;union { DECLARE_FLEX_ARRAY(struct talitos_ptr, link_tbl);
Greg Kroah-Hartman
maintainerPATCH 391/518 crypto: talitos - move dma unmapping code in flush_channel() into a standalone dma_unmap_request() function
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit 4d9b0b7415b9e79a3d54d18b5ff230974ea78740 upstream.
Previously added code to flush_channel() in order to unmap an entire descriptor.
Move that code into a standalone function to improve readability.
--- drivers/crypto/talitos.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-)
drivers/crypto/talitos.c +22 -17
@@ -372,6 +372,27 @@ static __be32 get_request_hdr(struct devreturn edesc->desc.hdr1; } +static void dma_unmap_request (struct device *dev, +struct talitos_request *request,bool is_sec1) +{ +struct talitos_edesc *edesc; + +if (is_sec1) { +dma_unmap_single (dev, request->dma_desc,TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + edesc = container_of(request->desc, struct talitos_edesc, desc); +while (edesc->next_desc) { +dma_unmap_single (dev, +be32_to_cpu (edesc->desc.next_desc), +TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); + edesc = edesc->next_desc; + } + }else { +dma_unmap_single (dev, request->dma_desc,TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + } +} +/* * process what was done, notify callback of error if not */
@@ -379,7 +400,6 @@ static void flush_channel(struct device {struct talitos_private *priv =dev_get_drvdata (dev);struct talitos_request *request, saved_req; -struct talitos_edesc *edesc;unsigned long flags;int tail, status;bool is_sec1 =has_ftr_sec1 (priv);
@@ -404,22 +424,7 @@ static void flush_channel(struct deviceelse status = error; -if (is_sec1) { -dma_unmap_single (dev, request->dma_desc, -TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); - edesc =container_of (request->desc, - struct talitos_edesc, desc); -while (edesc->next_desc) { -dma_unmap_single ( - dev,be32_to_cpu (edesc->desc.next_desc), -TALITOS_DESC_SIZE ,DMA_BIDIRECTIONAL ); - edesc = edesc->next_desc; - } - }else { -dma_unmap_single (dev, request->dma_desc, -TALITOS_DESC_SIZE , -DMA_BIDIRECTIONAL ); - } +dma_unmap_request (dev, request, is_sec1);/* copy entries so we can call callback outside lock */ saved_req.desc = request->desc;
Greg Kroah-Hartman
maintainerPATCH 392/518 crypto: talitos - move dma mapping code in talitos_submit() into a standalone dma_map_request() function
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit 5c0aa8cad7745505297103f05dda3fa06e8ac670 upstream.
Previously added code to talitos_submit() in order to map an entire descriptor chain.
Move that code into a standalone function to improve readability.
--- drivers/crypto/talitos.c | 75 +++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 34 deletions(-)
drivers/crypto/talitos.c +41 -34
@@ -255,6 +255,46 @@ static int init_device(struct device *dereturn 0 ; } +static void dma_map_request (struct device *dev,struct talitos_request *request, +struct talitos_desc *desc,bool is_sec1) +{ +struct talitos_edesc *edesc = + container_of(desc, struct talitos_edesc, desc); +dma_addr_t dma_desc, prev_dma_desc; +struct talitos_edesc *prev_edesc =NULL ; + +if (is_sec1) { +while (edesc) { + edesc->desc.hdr1 = edesc->desc.hdr; + + dma_desc =dma_map_single (dev, &edesc->desc.hdr1, +TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + +if (!prev_edesc) { + request->dma_desc = dma_desc; + goto next; + } + +/* Chain in any previous descriptors. */ + + prev_edesc->desc.next_desc =cpu_to_be32 (dma_desc); + +dma_sync_single_for_device (dev, prev_dma_desc, +TALITOS_DESC_SIZE , +DMA_TO_DEVICE ); + +next: + prev_edesc = edesc; + prev_dma_desc = dma_desc; + edesc = edesc->next_desc; + } + }else { + request->dma_desc =dma_map_single (dev, desc,TALITOS_DESC_SIZE , +DMA_BIDIRECTIONAL ); + } +} +/** * talitos_submit - submits a descriptor to the device for processing * @dev: the SEC device to be used
@@ -273,10 +313,7 @@ static int talitos_submit(struct device void *context, int error), void *context) { - struct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc); struct talitos_private *priv = dev_get_drvdata(dev); -dma_addr_t dma_desc, prev_dma_desc; -struct talitos_edesc *prev_edesc =NULL ;struct talitos_request *request;unsigned long flags;int head;
@@ -294,37 +331,7 @@ static int talitos_submit(struct device request = &priv->chan[ch].fifo[head];/* map descriptor and save caller data */ -if (is_sec1) { -while (edesc) { - edesc->desc.hdr1 = edesc->desc.hdr; - - dma_desc =dma_map_single (dev, &edesc->desc.hdr1, -TALITOS_DESC_SIZE , -DMA_BIDIRECTIONAL ); - -if (!prev_edesc) { - request->dma_desc = dma_desc; - goto next; - } - -/* Chain in any previous descriptors. */ - - prev_edesc->desc.next_desc =cpu_to_be32 (dma_desc); - -dma_sync_single_for_device (dev, prev_dma_desc, -TALITOS_DESC_SIZE , -DMA_TO_DEVICE ); - -next: - prev_edesc = edesc; - prev_dma_desc = dma_desc; - edesc = edesc->next_desc; - } - }else { - request->dma_desc =dma_map_single (dev, desc, -TALITOS_DESC_SIZE , -DMA_BIDIRECTIONAL ); - } +dma_map_request (dev, request, desc, is_sec1); request->callback = callback; request->context = context;
Greg Kroah-Hartman
maintainerPATCH 393/518 crypto: talitos - move code in current_desc_hdr() into a standalone function
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit f8713d9e6091755dd30f7f1cfa25f8440cddf81b upstream.
Previously added code in current_desc_hdr() in order to add support for searching an offending descriptor inside a descriptor chain.
Move that code into a standalone function to improve readability.
--- drivers/crypto/talitos.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-)
drivers/crypto/talitos.c +19 -16
@@ -520,6 +520,24 @@ DEF_TALITOS2_DONE(ch0, TALITOS2_ISR_CH_0 DEF_TALITOS2_DONE(ch0_2, TALITOS2_ISR_CH_0_2_DONE) DEF_TALITOS2_DONE(ch1_3, TALITOS2_ISR_CH_1_3_DONE) +static __be32 search_desc_hdr_in_request (struct talitos_request *request, +dma_addr_t cur_desc,bool is_sec1) +{ +struct talitos_edesc *edesc; + +if (request->dma_desc == cur_desc) { +return request->desc->hdr; + }else if (is_sec1) { + edesc = container_of(request->desc, struct talitos_edesc, desc); +while (edesc->next_desc) { +if (edesc->desc.next_desc ==cpu_to_be32 (cur_desc)) +return edesc->next_desc->desc.hdr1; + edesc = edesc->next_desc; + } + } +return 0 ; +} +/* * locate current (offending) descriptor */
@@ -528,7 +546,6 @@ static __be32 current_desc_hdr(struct destruct talitos_private *priv =dev_get_drvdata (dev);bool is_sec1 =has_ftr_sec1 (priv);struct talitos_request *request; -struct talitos_edesc *edesc;int tail, iter;dma_addr_t cur_desc;__be32 hdr =0 ;
@@ -546,21 +563,7 @@ static __be32 current_desc_hdr(struct de do { request = &priv->chan[ch].fifo[iter]; - if (request->dma_desc == cur_desc) { - hdr = request->desc->hdr; - } else if (is_sec1) { - edesc = container_of(request->desc, - struct talitos_edesc, desc); - while (edesc->next_desc) { - if (edesc->desc.next_desc == - cpu_to_be32(cur_desc)) { - hdr = edesc->next_desc->desc.hdr1; - break; - } - edesc = edesc->next_desc; - } - } - + hdr = search_desc_hdr_in_request(request, cur_desc, is_sec1); if (hdr) break;
Greg Kroah-Hartman
maintainerPATCH 394/518 crypto: talitos/hash - prepare SEC1 descriptor chaining, remove additional descriptor
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit 59b5d899e33701665f18abe6bebf987427876e3e upstream.
Currently, when SEC1 has buffered data (nbuf != 0), the ahash code creates an additional descriptor on the fly inside common_nonsnoop_hash() to handle the remainder of the data. This approach is incompatible with the arbitrary-length descriptor chaining that follows.
Remove the "additional descriptor" logic from common_nonsnoop_hash() and common_nonsnoop_hash_unmap().
Also remove the nbytes adjustment for SEC1 in ahash_edesc_alloc() that subtracted nbuf.
--- drivers/crypto/talitos.c | 101 ++--------------------------------------------- 1 file changed, 6 insertions(+), 95 deletions(-)
drivers/crypto/talitos.c +6 -95
@@ -1788,15 +1788,9 @@ static void common_nonsnoop_hash_unmap(sstruct talitos_private *priv =dev_get_drvdata (dev);bool is_sec1 =has_ftr_sec1 (priv);struct talitos_desc *desc = &edesc->desc; -struct talitos_desc *desc2; - -if (desc->next_desc) - desc2 = &edesc->next_desc->desc;unmap_single_talitos_ptr (dev, &desc->ptr[5 ],DMA_FROM_DEVICE ); -if (desc->next_desc && - desc->ptr[5 ].ptr != desc2->ptr[5 ].ptr) -unmap_single_talitos_ptr (dev, &desc2->ptr[5 ],DMA_FROM_DEVICE ); +if (req_ctx->last_desc)memcpy (areq->result, req_ctx->hw_context,crypto_ahash_digestsize (tfm));
@@ -1808,13 +1802,6 @@ static void common_nonsnoop_hash_unmap(sif (from_talitos_ptr_len (&desc->ptr[1 ], is_sec1))unmap_single_talitos_ptr (dev, &desc->ptr[1 ],DMA_TO_DEVICE ); -else if (desc->next_desc) -unmap_single_talitos_ptr (dev, &desc2->ptr[1 ], -DMA_TO_DEVICE ); - -if (is_sec1 && req_ctx->nbuf) -unmap_single_talitos_ptr (dev, &desc->ptr[3 ], -DMA_TO_DEVICE );if (edesc->dma_len) dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
@@ -1922,9 +1909,6 @@ static int common_nonsnoop_hash(struct tto_talitos_ptr (&desc->ptr[2 ], ctx->dma_key, ctx->keylen, is_sec1); -if (is_sec1 && req_ctx->nbuf) - length -= req_ctx->nbuf; - sg_count = edesc->src_nents ?:1 ;if (is_sec1 && sg_count >1 )sg_copy_to_buffer (req_ctx->psrc, sg_count, edesc->buf, length);
@@ -1934,16 +1918,10 @@ static int common_nonsnoop_hash(struct t/* * data in */ -if (is_sec1 && req_ctx->nbuf) { -map_single_talitos_ptr (dev, &desc->ptr[3 ], req_ctx->nbuf, - req_ctx->buf[req_ctx->buf_idx], -DMA_TO_DEVICE ); - }else { - sg_count =talitos_sg_map (dev, req_ctx->psrc, length, edesc, - &desc->ptr[3 ], sg_count,0 ,0 ); -if (sg_count >1 ) - sync_needed = true; - } + sg_count =talitos_sg_map (dev, req_ctx->psrc, length, edesc, + &desc->ptr[3 ], sg_count,0 ,0 ); +if (sg_count >1 ) + sync_needed = true;/* fifth DWORD empty */
@@ -1963,49 +1941,6 @@ static int common_nonsnoop_hash(struct tif (is_sec1 &&from_talitos_ptr_len (&desc->ptr[3 ], true) ==0 )talitos_handle_buggy_hash (ctx, edesc, &desc->ptr[3 ]); -if (is_sec1 && req_ctx->nbuf && length) { -struct talitos_edesc *edesc2; -struct talitos_desc *desc2; - - edesc2 =kzalloc (sizeof (*edesc2), - areq->base.flags &CRYPTO_TFM_REQ_MAY_SLEEP ? -GFP_KERNEL : -GFP_ATOMIC ); -if (!edesc2) { - ret = -ENOMEM ; - goto err; - } - edesc->next_desc = edesc2; - - desc2 = &edesc2->desc; - - desc2->hdr = desc->hdr; - desc2->hdr &= ~DESC_HDR_MODE0_MDEU_INIT ; - desc->hdr &= ~DESC_HDR_MODE0_MDEU_PAD ; - desc->hdr |=DESC_HDR_MODE0_MDEU_CONT ; - desc->hdr &= ~DESC_HDR_DONE_NOTIFY ; - -if (desc->ptr[1 ].ptr) -copy_talitos_ptr (&desc2->ptr[1 ], &desc->ptr[1 ], - is_sec1); -else -map_single_talitos_ptr_nosync (dev, &desc2->ptr[1 ], - req_ctx->hw_context_size, - req_ctx->hw_context, -DMA_TO_DEVICE ); -copy_talitos_ptr (&desc2->ptr[2 ], &desc->ptr[2 ], is_sec1); - sg_count =talitos_sg_map (dev, req_ctx->psrc, length, edesc, - &desc2->ptr[3 ], sg_count,0 ,0 ); -if (sg_count >1 ) - sync_needed = true; -copy_talitos_ptr (&desc2->ptr[5 ], &desc->ptr[5 ], is_sec1); -if (req_ctx->last_desc) -map_single_talitos_ptr_nosync (dev, &desc->ptr[5 ], - req_ctx->hw_context_size, - req_ctx->hw_context, -DMA_FROM_DEVICE ); - } -if (sync_needed)dma_sync_single_for_device (dev, edesc->dma_link_tbl, edesc->dma_len,DMA_BIDIRECTIONAL );
@@ -2028,11 +1963,6 @@ static struct talitos_edesc *ahash_edescstruct crypto_ahash *tfm =crypto_ahash_reqtfm (areq);struct talitos_ctx *ctx =crypto_ahash_ctx (tfm);struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); -struct talitos_private *priv =dev_get_drvdata (ctx->dev); -bool is_sec1 =has_ftr_sec1 (priv); - -if (is_sec1) - nbytes -= req_ctx->nbuf;return talitos_edesc_alloc (ctx->dev, req_ctx->psrc,NULL ,NULL ,0 , nbytes,0 ,0 ,0 , areq->base.flags, false);
@@ -2051,8 +1981,6 @@ static int ahash_process_req_one(structunsigned int nsg;int nents;struct device *dev = ctx->dev; -struct talitos_private *priv =dev_get_drvdata (dev); -bool is_sec1 =has_ftr_sec1 (priv);u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
@@ -2084,30 +2012,13 @@ static int ahash_process_req_one(struct }/* Chain in any previously buffered data */ -if (!is_sec1 && req_ctx->nbuf) { +if (req_ctx->nbuf) { nsg = (req_ctx->nbuf < nbytes_to_hash) ?2 :1 ;sg_init_table (req_ctx->bufsl, nsg);sg_set_buf (req_ctx->bufsl, ctx_buf, req_ctx->nbuf);if (nsg >1 )sg_chain (req_ctx->bufsl,2 , req_ctx->request_sl); req_ctx->psrc = req_ctx->bufsl; - }else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) { -int offset; - -if (nbytes_to_hash > blocksize) - offset = blocksize - req_ctx->nbuf; -else - offset = nbytes_to_hash - req_ctx->nbuf; - nents =sg_nents_for_len (req_ctx->request_sl, offset); -if (nents <0 ) { -dev_err (dev,"Invalid number of src SG.\n" ); -return nents; - } -sg_copy_to_buffer (req_ctx->request_sl, nents, - ctx_buf + req_ctx->nbuf, offset); - req_ctx->nbuf += offset; - req_ctx->psrc =scatterwalk_ffwd (req_ctx->bufsl, req_ctx->request_sl, - offset); }else req_ctx->psrc = req_ctx->request_sl;
Greg Kroah-Hartman
maintainerPATCH 395/518 crypto: talitos/hash - use descriptor chaining for SEC1 instead of workqueue
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit f1ede6d95d8ad3b32c6a552d2baab805bd00fc38 upstream.
Rework the SEC1 ahash implementation to build a chain of hardware descriptors, replacing the previous approach of submitting one descriptor at a time via a workqueue, introduced by commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation").
Introduce ahash_process_req_prepare() which iterates over the request data, allocating enough descriptors to cover the entire ahash request. The new fields (bufsl, src, first, last) are added to talitos_edesc for this purpose.
common_nonsnoop_hash() no longer calls talitos_submit(); it only maps and sets up the descriptor. Submission is now done by the caller after the chain is built.
ahash_free_desc_list_from() takes over calling common_nonsnoop_hash_unmap() for each descriptor during cleanup.
Compared to the workqueue based solution, request are slightly faster since there is no more scheduling latency induced by the workqueue, and only one interrupt is generated by the device at the end of a chain.
Commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation") :
$ /usr/libexec/libkcapi/sha256sum ./test_5M.bin 013c5609d63c... ./test_5M.bin real 0m 0.41s user 0m 0.01s sys 0m 0.07s
Now :
$ /usr/libexec/libkcapi/sha256sum ./test_5M.bin 013c5609d63c... ./test_5M.bin real 0m 0.33s user 0m 0.01s sys 0m 0.20s
Tested on a system with an MPC885 SoC featuring the SEC1 Lite.
The increase in sys time is due to the fact that commit 37b5e8897eb5 ("crypto: talitos - chain in buffered data for ahash on SEC1") can no longer be applied.
--- drivers/crypto/talitos.c | 168 +++++++++++++++++++++++++++++------------------ drivers/crypto/talitos.h | 10 ++ 2 files changed, 115 insertions(+), 63 deletions(-)
drivers/crypto/talitos.c +105 -63
@@ -1791,12 +1791,12 @@ static void common_nonsnoop_hash_unmap(sunmap_single_talitos_ptr (dev, &desc->ptr[5 ],DMA_FROM_DEVICE ); -if (req_ctx->last_desc) +if (edesc->last && req_ctx->last_request)memcpy (areq->result, req_ctx->hw_context,crypto_ahash_digestsize (tfm)); -if (req_ctx->psrc) -talitos_sg_unmap (dev, edesc, req_ctx->psrc,NULL ,0 ,0 ); +if (edesc->src) +talitos_sg_unmap (dev, edesc, edesc->src,NULL ,0 ,0 );/* When using hashctx-in, must unmap it. */ if (from_talitos_ptr_len (&desc->ptr[1 ], is_sec1))
@@ -1808,12 +1808,14 @@ static void common_nonsnoop_hash_unmap(s DMA_BIDIRECTIONAL); } -static void free_edesc_list_from (struct talitos_edesc *edesc) +static void free_edesc_list_from (struct ahash_request *areq,struct talitos_edesc *edesc) { +struct talitos_ctx *ctx =crypto_ahash_ctx (crypto_ahash_reqtfm (areq));struct talitos_edesc *next;while (edesc) { next = edesc->next_desc; +common_nonsnoop_hash_unmap (ctx->dev, edesc, areq);kfree (edesc); edesc = next; }
@@ -1828,19 +1830,18 @@ static void ahash_done(struct device *de container_of(desc, struct talitos_edesc, desc);struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); +if (!req_ctx->last_desc && req_ctx->to_hash_later) {/* Position any partial block for next update/final/finup */ req_ctx->buf_idx = (req_ctx->buf_idx +1 ) &1 ; req_ctx->nbuf = req_ctx->to_hash_later; } -common_nonsnoop_hash_unmap (dev, edesc, areq); -free_edesc_list_from (edesc); +free_edesc_list_from (areq, edesc); -if (err) { -ahash_request_complete (areq, err); -return ; - } +ahash_request_complete (areq, err); + +return ; req_ctx->remaining_ahash_request_bytes -= req_ctx->current_ahash_request_bytes;
@@ -1874,18 +1875,15 @@ static void talitos_handle_buggy_hash(st (char *)padded_hash, DMA_TO_DEVICE); } -static int common_nonsnoop_hash (struct talitos_edesc *edesc, -struct ahash_request *areq,unsigned int length, -void (*callback) (struct device *dev, -struct talitos_desc *desc, -void *context,int error)) +static void common_nonsnoop_hash (struct talitos_edesc *edesc, +struct ahash_request *areq, +unsigned int length) {struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq);struct talitos_ctx *ctx =crypto_ahash_ctx (tfm);struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq);struct device *dev = ctx->dev;struct talitos_desc *desc = &edesc->desc; -int ret;bool sync_needed = false;struct talitos_private *priv =dev_get_drvdata (dev);bool is_sec1 =has_ftr_sec1 (priv);
@@ -1894,7 +1892,7 @@ static int common_nonsnoop_hash(struct t/* first DWORD empty */ /* hash context in */ -if (!req_ctx->first_desc || req_ctx->swinit) { +if (!edesc->first || !req_ctx->first_desc || req_ctx->swinit) { map_single_talitos_ptr_nosync(dev, &desc->ptr[1], req_ctx->hw_context_size, req_ctx->hw_context,
@@ -1911,22 +1909,22 @@ static int common_nonsnoop_hash(struct t sg_count = edesc->src_nents ?:1 ;if (is_sec1 && sg_count >1 ) -sg_copy_to_buffer (req_ctx->psrc, sg_count, edesc->buf, length); +sg_copy_to_buffer (edesc->src, sg_count, edesc->buf, length);else if (length) - sg_count =dma_map_sg (dev, req_ctx->psrc, sg_count, -DMA_TO_DEVICE ); + sg_count =dma_map_sg (dev, edesc->src, sg_count,DMA_TO_DEVICE ); +/* * data in */ - sg_count =talitos_sg_map (dev, req_ctx->psrc, length, edesc, - &desc->ptr[3 ], sg_count,0 ,0 ); + sg_count =talitos_sg_map (dev, edesc->src, length, edesc, &desc->ptr[3 ], + sg_count,0 ,0 );if (sg_count >1 ) sync_needed = true;/* fifth DWORD empty */ /* hash/HMAC out -or- hash context out */ -if (req_ctx->last_desc) +if (edesc->last && req_ctx->last_request)map_single_talitos_ptr (dev, &desc->ptr[5 ],crypto_ahash_digestsize (tfm), req_ctx->hw_context,DMA_FROM_DEVICE );
@@ -1944,30 +1942,89 @@ static int common_nonsnoop_hash(struct tif (sync_needed)dma_sync_single_for_device (dev, edesc->dma_link_tbl, edesc->dma_len,DMA_BIDIRECTIONAL ); - - ret =talitos_submit (dev, ctx->ch, desc, callback, - areq); -if (ret != -EINPROGRESS ) - goto err; - -return -EINPROGRESS ; -err: -common_nonsnoop_hash_unmap (dev, edesc, areq); -kfree (edesc); -return ret; }static struct talitos_edesc *ahash_edesc_alloc (struct ahash_request *areq, +struct scatterlist *src,unsigned int nbytes) {struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq);struct talitos_ctx *ctx =crypto_ahash_ctx (tfm); -struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); -return talitos_edesc_alloc (ctx->dev, req_ctx->psrc,NULL ,NULL ,0 , +return talitos_edesc_alloc (ctx->dev, src,NULL ,NULL ,0 , nbytes,0 ,0 ,0 , areq->base.flags, false); } +static struct talitos_edesc * +ahash_process_req_prepare (struct ahash_request *areq,unsigned int nbytes, +unsigned int blocksize,bool is_sec1) +{ +struct talitos_ctx *ctx =crypto_ahash_ctx (crypto_ahash_reqtfm (areq)); +struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); +struct talitos_edesc *first =NULL , *prev_edesc =NULL , *edesc; +size_t desc_max = is_sec1 ?TALITOS1_MAX_DATA_LEN :SIZE_MAX ; +struct scatterlist tmp[2 ]; +size_t to_hash_this_desc; +struct scatterlist *src; +size_t offset =0 ; + +do { + src =scatterwalk_ffwd (tmp, req_ctx->psrc, offset); + + to_hash_this_desc = +min (nbytes,ALIGN_DOWN (desc_max, blocksize)); + +/* Allocate extended descriptor */ + edesc =ahash_edesc_alloc (areq, src, to_hash_this_desc); +if (IS_ERR (edesc)) { +if (first) +free_edesc_list_from (areq, first); +return edesc; + } + + edesc->src = +scatterwalk_ffwd (edesc->bufsl, req_ctx->psrc, offset); + edesc->desc.hdr = ctx->desc_hdr_template; + edesc->first = offset ==0 ; + edesc->last = nbytes - to_hash_this_desc ==0 ; + +/* On last one, request SEC to pad; otherwise continue */ +if (req_ctx->last_request && edesc->last) + edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_PAD ; +else + edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_CONT ; + +/* request SEC to INIT hash. */ +if (req_ctx->first_desc && edesc->first && !req_ctx->swinit) + edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_INIT ; + +/* +* When the tfm context has a keylen, it's an HMAC. +* A first or last (ie. not middle) descriptor must request HMAC. +*/ +if (ctx->keylen && ((req_ctx->first_desc && edesc->first) || + (req_ctx->last_request && edesc->last))) + edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_HMAC ; + +/* clear the DN bit */ +if (is_sec1 && !edesc->last) + edesc->desc.hdr &= ~DESC_HDR_DONE_NOTIFY ; + +common_nonsnoop_hash (edesc, areq, to_hash_this_desc); + + offset += to_hash_this_desc; + nbytes -= to_hash_this_desc; + +if (!prev_edesc) + first = edesc; +else + prev_edesc->next_desc = edesc; + prev_edesc = edesc; + }while (nbytes); + +return first; +} +static int ahash_process_req_one (struct ahash_request *areq,unsigned int nbytes) {struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq);
@@ -1976,14 +2033,16 @@ static int ahash_process_req_one(structstruct talitos_edesc *edesc;unsigned int blocksize =crypto_tfm_alg_blocksize (crypto_ahash_tfm (tfm)); +bool is_sec1 =has_ftr_sec1 (dev_get_drvdata (ctx->dev));unsigned int nbytes_to_hash;unsigned int to_hash_later;unsigned int nsg;int nents;struct device *dev = ctx->dev;u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx]; +int ret; -if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) { +if (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) {/* Buffer up to one whole block */ nents =sg_nents_for_len (req_ctx->request_sl, nbytes);if (nents <0 ) {
@@ -2000,7 +2059,7 @@ static int ahash_process_req_one(struct nbytes_to_hash = nbytes + req_ctx->nbuf; to_hash_later = nbytes_to_hash & (blocksize -1 ); -if (req_ctx->last_desc) +if (req_ctx->last_request) to_hash_later =0 ;else if (to_hash_later)/* There is a partial block. Hash the full block(s) now */
@@ -2035,30 +2094,16 @@ static int ahash_process_req_one(struct } req_ctx->to_hash_later = to_hash_later; -/* Allocate extended descriptor */ - edesc =ahash_edesc_alloc (req_ctx->areq, nbytes_to_hash); + edesc =ahash_process_req_prepare (areq, nbytes_to_hash, blocksize, + is_sec1);if (IS_ERR (edesc))return PTR_ERR (edesc); - edesc->desc.hdr = ctx->desc_hdr_template; - -/* On last one, request SEC to pad; otherwise continue */ -if (req_ctx->last_desc) - edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_PAD ; -else - edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_CONT ; - -/* request SEC to INIT hash. */ -if (req_ctx->first_desc && !req_ctx->swinit) - edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_INIT ; - -/* When the tfm context has a keylen, it's an HMAC. -* A first or last (ie. not middle) descriptor must request HMAC. -*/ -if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc)) - edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_HMAC ; + ret =talitos_submit (dev, ctx->ch, &edesc->desc, ahash_done, areq); +if (ret != -EINPROGRESS ) +free_edesc_list_from (areq, edesc); -return common_nonsnoop_hash (edesc, req_ctx->areq, nbytes_to_hash, ahash_done); +return ret; }static void sec1_ahash_process_remaining (struct work_struct *work)
@@ -2102,16 +2147,13 @@ static int ahash_process_req(struct ahas req_ctx->remaining_ahash_request_bytes = nbytes;if (is_sec1) { -if (nbytes >TALITOS1_MAX_DATA_LEN ) - nbytes =TALITOS1_MAX_DATA_LEN ; -else if (req_ctx->last_request) +if (req_ctx->last_request) req_ctx->last_desc =1 ; } req_ctx->current_ahash_request_bytes = nbytes; -return ahash_process_req_one (req_ctx->areq, - req_ctx->current_ahash_request_bytes); +return ahash_process_req_one (req_ctx->areq, nbytes); }static int ahash_init (struct ahash_request *areq)
drivers/crypto/talitos.h +10 -0
@@ -44,6 +44,11 @@ struct talitos_desc {/* * talitos_edesc - s/w-extended descriptor +* @bufsl: scatterlist buffer +* @src: pointer to input scatterlist +* @first: first descriptor of a chain +* @last: last descriptor of a chain +* * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist * @iv_dma: dma address of iv for checking continuity and link table
@@ -59,6 +64,11 @@ struct talitos_desc {* of link_tbl data */ struct talitos_edesc { +struct scatterlist bufsl[2 ]; +struct scatterlist *src; +int first; +int last; +int src_nents;int dst_nents;dma_addr_t iv_dma;
Greg Kroah-Hartman
maintainerPATCH 396/518 crypto: talitos/hash - drop workqueue mechanism for SEC1
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit be4802afb1700534e48cb776d0d1e772c27de130 upstream.
Now that SEC1 hash uses hardware descriptor chaining instead of a workqueue to process requests exceeding TALITOS1_MAX_DATA_LEN, the workqueue code is no longer needed.
Remove sec1_ahash_process_remaining(), the related fields from talitos_ahash_req_ctx (request_bufsl, areq, request_sl, remaining_ahash_request_bytes, current_ahash_request_bytes, sec1_ahash_process_remaining), the dead code in ahash_done(), and simplify ahash_process_req() to call ahash_process_req_one() directly with the original areq->src and areq->nbytes.
--- drivers/crypto/talitos.c | 80 ++++------------------------------------------- 1 file changed, 7 insertions(+), 73 deletions(-)
drivers/crypto/talitos.c +7 -73
@@ -12,7 +12,6 @@* All rights reserved. */ -#include <linux/workqueue.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mod_devicetable.h>
@@ -952,13 +951,6 @@ struct talitos_ahash_req_ctx {unsigned int nbuf;struct scatterlist bufsl[2 ];struct scatterlist *psrc; - -struct scatterlist request_bufsl[2 ]; -struct ahash_request *areq; -struct scatterlist *request_sl; -unsigned int remaining_ahash_request_bytes; -unsigned int current_ahash_request_bytes; -struct work_struct sec1_ahash_process_remaining; };struct talitos_export_state {
@@ -1840,18 +1832,6 @@ static void ahash_done(struct device *defree_edesc_list_from (areq, edesc);ahash_request_complete (areq, err); - -return ; - - req_ctx->remaining_ahash_request_bytes -= - req_ctx->current_ahash_request_bytes; - -if (!req_ctx->remaining_ahash_request_bytes) { -ahash_request_complete (areq,0 ); -return ; - } - -schedule_work (&req_ctx->sec1_ahash_process_remaining); }/*
@@ -2044,12 +2024,12 @@ static int ahash_process_req_one(structif (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) {/* Buffer up to one whole block */ - nents =sg_nents_for_len (req_ctx->request_sl, nbytes); + nents =sg_nents_for_len (areq->src, nbytes);if (nents <0 ) {dev_err (dev,"Invalid number of src SG.\n" );return nents; } -sg_copy_to_buffer (req_ctx->request_sl, nents, +sg_copy_to_buffer (areq->src, nents, ctx_buf + req_ctx->nbuf, nbytes); req_ctx->nbuf += nbytes;return 0 ;
@@ -2076,18 +2056,18 @@ static int ahash_process_req_one(structsg_init_table (req_ctx->bufsl, nsg);sg_set_buf (req_ctx->bufsl, ctx_buf, req_ctx->nbuf);if (nsg >1 ) -sg_chain (req_ctx->bufsl,2 , req_ctx->request_sl); +sg_chain (req_ctx->bufsl,2 , areq->src); req_ctx->psrc = req_ctx->bufsl; }else - req_ctx->psrc = req_ctx->request_sl; + req_ctx->psrc = areq->src;if (to_hash_later) { - nents =sg_nents_for_len (req_ctx->request_sl, nbytes); + nents =sg_nents_for_len (areq->src, nbytes);if (nents <0 ) {dev_err (dev,"Invalid number of src SG.\n" );return nents; } -sg_pcopy_to_buffer (req_ctx->request_sl, nents, +sg_pcopy_to_buffer (areq->src, nents, req_ctx->buf[(req_ctx->buf_idx +1 ) &1 ], to_hash_later, nbytes - to_hash_later);
@@ -2106,54 +2086,9 @@ static int ahash_process_req_one(structreturn ret; } -static void sec1_ahash_process_remaining (struct work_struct *work) -{ -struct talitos_ahash_req_ctx *req_ctx = - container_of(work, struct talitos_ahash_req_ctx, - sec1_ahash_process_remaining); -int err =0 ; - - req_ctx->request_sl =scatterwalk_ffwd (req_ctx->request_bufsl, - req_ctx->request_sl,TALITOS1_MAX_DATA_LEN ); - -if (req_ctx->remaining_ahash_request_bytes >TALITOS1_MAX_DATA_LEN ) - req_ctx->current_ahash_request_bytes =TALITOS1_MAX_DATA_LEN ; -else { - req_ctx->current_ahash_request_bytes = - req_ctx->remaining_ahash_request_bytes; - -if (req_ctx->last_request) - req_ctx->last_desc =1 ; - } - - err =ahash_process_req_one (req_ctx->areq, - req_ctx->current_ahash_request_bytes); - -if (err != -EINPROGRESS ) -ahash_request_complete (req_ctx->areq, err); -} -static int ahash_process_req (struct ahash_request *areq,unsigned int nbytes) { -struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq); -struct talitos_ctx *ctx =crypto_ahash_ctx (tfm); -struct device *dev = ctx->dev; -struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); -struct talitos_private *priv =dev_get_drvdata (dev); -bool is_sec1 =has_ftr_sec1 (priv); - - req_ctx->areq = areq; - req_ctx->request_sl = areq->src; - req_ctx->remaining_ahash_request_bytes = nbytes; - -if (is_sec1) { -if (req_ctx->last_request) - req_ctx->last_desc =1 ; - } - - req_ctx->current_ahash_request_bytes = nbytes; - -return ahash_process_req_one (req_ctx->areq, nbytes); +return ahash_process_req_one (areq, nbytes); }static int ahash_init (struct ahash_request *areq)
@@ -2176,7 +2111,6 @@ static int ahash_init(struct ahash_reque req_ctx->hw_context_size = size; req_ctx->last_request =0 ; req_ctx->last_desc =0 ; -INIT_WORK (&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining); dma =dma_map_single (dev, req_ctx->hw_context, req_ctx->hw_context_size,DMA_TO_DEVICE );
Greg Kroah-Hartman
maintainerPATCH 397/518 crypto: talitos/hash - rename first_desc/last_desc to first_request/last_request
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit 8bcf00671400ac3b3a4cc3011e6c1496dbd880fd upstream.
In talitos_ahash_req_ctx and talitos_export_state, the fields first_desc and last_desc describe request-level (not descriptor-level) state. Rename them to first_request and last_request for clarity. last_desc is also removed from talitos_ahash_req_ctx as it is no longer used.
--- drivers/crypto/talitos.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-)
drivers/crypto/talitos.c +13 -16
@@ -944,8 +944,7 @@ struct talitos_ahash_req_ctx {u8 buf[2 ][HASH_MAX_BLOCK_SIZE ];int buf_idx;unsigned int swinit; -unsigned int first_desc; -unsigned int last_desc; +unsigned int first_request;unsigned int last_request;unsigned int to_hash_later;unsigned int nbuf;
@@ -957,8 +956,8 @@ struct talitos_export_state {u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE /sizeof (u32)];u8 buf[HASH_MAX_BLOCK_SIZE ];unsigned int swinit; -unsigned int first_desc; -unsigned int last_desc; +unsigned int first_request; +unsigned int last_request;unsigned int to_hash_later;unsigned int nbuf; };
@@ -1822,8 +1821,7 @@ static void ahash_done(struct device *de container_of(desc, struct talitos_edesc, desc);struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); - -if (!req_ctx->last_desc && req_ctx->to_hash_later) { +if (!req_ctx->last_request && req_ctx->to_hash_later) {/* Position any partial block for next update/final/finup */ req_ctx->buf_idx = (req_ctx->buf_idx +1 ) &1 ; req_ctx->nbuf = req_ctx->to_hash_later;
@@ -1872,7 +1870,7 @@ static void common_nonsnoop_hash(struct/* first DWORD empty */ /* hash context in */ -if (!edesc->first || !req_ctx->first_desc || req_ctx->swinit) { +if (!edesc->first || !req_ctx->first_request || req_ctx->swinit) { map_single_talitos_ptr_nosync(dev, &desc->ptr[1], req_ctx->hw_context_size, req_ctx->hw_context,
@@ -1880,7 +1878,7 @@ static void common_nonsnoop_hash(struct req_ctx->swinit =0 ; }/* Indicate next op is not the first. */ - req_ctx->first_desc =0 ; + req_ctx->first_request =0 ;/* HMAC key */ if (ctx->keylen)
@@ -1975,14 +1973,14 @@ ahash_process_req_prepare(struct ahash_r edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_CONT ;/* request SEC to INIT hash. */ -if (req_ctx->first_desc && edesc->first && !req_ctx->swinit) +if (req_ctx->first_request && edesc->first && !req_ctx->swinit) edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_INIT ;/* * When the tfm context has a keylen, it's an HMAC. * A first or last (ie. not middle) descriptor must request HMAC. */ -if (ctx->keylen && ((req_ctx->first_desc && edesc->first) || +if (ctx->keylen && ((req_ctx->first_request && edesc->first) || (req_ctx->last_request && edesc->last))) edesc->desc.hdr |=DESC_HDR_MODE0_MDEU_HMAC ;
@@ -2103,14 +2101,13 @@ static int ahash_init(struct ahash_reque/* Initialize the context */ req_ctx->buf_idx =0 ; req_ctx->nbuf =0 ; - req_ctx->first_desc =1 ;/* first_desc indicates h/w must init its context */ + req_ctx->first_request =1 ; req_ctx->swinit =0 ;/* assume h/w init of context */ size = (crypto_ahash_digestsize (tfm) <=SHA256_DIGEST_SIZE ) ?TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256 :TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512 ; req_ctx->hw_context_size = size; req_ctx->last_request =0 ; - req_ctx->last_desc =0 ; dma =dma_map_single (dev, req_ctx->hw_context, req_ctx->hw_context_size,DMA_TO_DEVICE );
@@ -2202,8 +2199,8 @@ static int ahash_export(struct ahash_req req_ctx->hw_context_size);memcpy (export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf); export->swinit = req_ctx->swinit; - export->first_desc = req_ctx->first_desc; - export->last_desc = req_ctx->last_desc; + export->first_request = req_ctx->first_request; + export->last_request = req_ctx->last_request; export->to_hash_later = req_ctx->to_hash_later; export->nbuf = req_ctx->nbuf;
@@ -2228,8 +2225,8 @@ static int ahash_import(struct ahash_reqmemcpy (req_ctx->hw_context, export->hw_context, size);memcpy (req_ctx->buf[0 ], export->buf, export->nbuf); req_ctx->swinit = export->swinit; - req_ctx->first_desc = export->first_desc; - req_ctx->last_desc = export->last_desc; + req_ctx->first_request = export->first_request; + req_ctx->last_request = export->last_request; req_ctx->to_hash_later = export->to_hash_later; req_ctx->nbuf = export->nbuf;
Greg Kroah-Hartman
maintainerPATCH 398/518 crypto: talitos/hash - remove useless wrapper
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit 907ae6088c82c9abae2d26477fddd60df6ad003b upstream.
ahash_process_req() was a wrapper used in commit 655ef638a2bc ("crypto:
talitos - fix SEC1 32k ahash request limitation"). Rename ahash_process_req_one() to ahash_process_req() and remove the wrapper.
--- drivers/crypto/talitos.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/crypto/talitos.c +1 -6
@@ -2003,7 +2003,7 @@ ahash_process_req_prepare(struct ahash_rreturn first; } -static int ahash_process_req_one (struct ahash_request *areq,unsigned int nbytes) +static int ahash_process_req (struct ahash_request *areq,unsigned int nbytes) {struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq);struct talitos_ctx *ctx =crypto_ahash_ctx (tfm);
@@ -2084,11 +2084,6 @@ static int ahash_process_req_one(structreturn ret; } -static int ahash_process_req (struct ahash_request *areq,unsigned int nbytes) -{ -return ahash_process_req_one (areq, nbytes); -} -static int ahash_init (struct ahash_request *areq) {struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq);
Greg Kroah-Hartman
maintainerPATCH 399/518 crypto: talitos/hash - fix SEC2 64k - 1 ahash request limitation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Louvel <[email protected]>
commit 6e12daff6ec125102a6fdcafc5aa7199f7ce8933 upstream.
The problem described in commit 655ef638a2bc ("crypto: talitos - fix SEC1 32k ahash request limitation") also apply for the SEC2 hardware, but with a limitation of 64k - 1 bytes.
Split ahash_done() into SEC1 and SEC2 paths: SEC1 continues to free the whole descriptor list at once, while SEC2 now iterates through descriptors one by one, submitting the next only after the previous completes, which is required since SEC2 cannot chain descriptors in hardware.
--- drivers/crypto/talitos.c | 49 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-)
drivers/crypto/talitos.c +40 -9
@@ -1820,16 +1820,46 @@ static void ahash_done(struct device *destruct talitos_edesc *edesc = container_of(desc, struct talitos_edesc, desc);struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq); +struct crypto_ahash *tfm =crypto_ahash_reqtfm (areq); +bool is_sec1 =has_ftr_sec1 (dev_get_drvdata (dev)); +struct talitos_ctx *ctx =crypto_ahash_ctx (tfm); +struct talitos_edesc *next; -if (!req_ctx->last_request && req_ctx->to_hash_later) { -/* Position any partial block for next update/final/finup */ - req_ctx->buf_idx = (req_ctx->buf_idx +1 ) &1 ; - req_ctx->nbuf = req_ctx->to_hash_later; +if (is_sec1) { +if (!req_ctx->last_request && req_ctx->to_hash_later) { +/* Position any partial block for next update/final/finup */ + req_ctx->buf_idx = (req_ctx->buf_idx +1 ) &1 ; + req_ctx->nbuf = req_ctx->to_hash_later; + } + +free_edesc_list_from (areq, edesc); +ahash_request_complete (areq, err); + }else { + next = edesc->next_desc; + +common_nonsnoop_hash_unmap (dev, edesc, areq); +kfree (edesc); + +if (err) + goto out; + +if (next) { + err =talitos_submit (dev, ctx->ch, &next->desc, + ahash_done, areq); +if (err != -EINPROGRESS ) + goto out; +return ; + } +out: +if (!req_ctx->last_request && req_ctx->to_hash_later) { +/* Position any partial block for next update/final/finup */ + req_ctx->buf_idx = (req_ctx->buf_idx +1 ) &1 ; + req_ctx->nbuf = req_ctx->to_hash_later; + } +if (err && next) +free_edesc_list_from (areq, next); +ahash_request_complete (areq, err); } - -free_edesc_list_from (areq, edesc); - -ahash_request_complete (areq, err); }/*
@@ -1940,7 +1970,8 @@ ahash_process_req_prepare(struct ahash_rstruct talitos_ctx *ctx =crypto_ahash_ctx (crypto_ahash_reqtfm (areq));struct talitos_ahash_req_ctx *req_ctx =ahash_request_ctx (areq);struct talitos_edesc *first =NULL , *prev_edesc =NULL , *edesc; -size_t desc_max = is_sec1 ?TALITOS1_MAX_DATA_LEN :SIZE_MAX ; +size_t desc_max = is_sec1 ?TALITOS1_MAX_DATA_LEN : +TALITOS2_MAX_DATA_LEN ;struct scatterlist tmp[2 ];size_t to_hash_this_desc;struct scatterlist *src;
Greg Kroah-Hartman
maintainerPATCH 400/518 arm64: fpsimd: Fix type mismatch in sme_{save,load}_state()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
commit 247bd153905085c18ff9006cca1ccb96dfd18e7f upstream.
The sme_save_state() and sme_load_state() functions take a 32-bit int argument that describes whether to save/restore ZT0. Their assembly implementations consume the entire 64-bit register containing this 32-bit value, and will attempt to save/restore ZT0 if any bit of that 64-bit register is non-zero.
Per the AAPCS64 parameter passing rules, the callee is responsible for any necessary widening, and the upper 32-bits are permitted to contain arbitrary values. If the upper 32 bits are non-zero, this could result in an unexpected attempt to save/restore ZT0, and consequently could lead to unexpected traps/undefs/faults.
In practice compilers are very unlikely to generate code where the upper 32-bits would be non-zero, but they are permitted to do so.
Fix this by only consuming the low 32 bits of the register, and update comments accordingly.
--- arch/arm64/kernel/entry-fpsimd.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/kernel/entry-fpsimd.S +4 -4
@@ -103,13 +103,13 @@ SYM_FUNC_END(sme_set_vq) * Save the ZA and ZT state * * x0 - pointer to buffer for state - * x1 - number of ZT registers to save + * w1 - number of ZT registers to save */ SYM_FUNC_START(sme_save_state) _sme_rdsvl 2, 1 // x2 = VL/8 sme_save_za 0, x2, 12 // Leaves x0 pointing to the end of ZA - cbz x1, 1f + cbz w1, 1f _str_zt 0 1: ret
@@ -119,13 +119,13 @@ SYM_FUNC_END(sme_save_state) * Load the ZA and ZT state * * x0 - pointer to buffer for state - * x1 - number of ZT registers to save + * w1 - number of ZT registers to save */ SYM_FUNC_START(sme_load_state) _sme_rdsvl 2, 1 // x2 = VL/8 sme_load_za 0, x2, 12 // Leaves x0 pointing to the end of ZA - cbz x1, 1f + cbz w1, 1f _ldr_zt 0 1: ret
Greg Kroah-Hartman
maintainerPATCH 401/518 spi: fsl-lpspi: replace dmaengine_terminate_all() with dmaengine_terminate_sync()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Song <[email protected]>
commit e703ce47691b967fe9b4057fb1d062273211afa9 upstream.
dmaengine_terminate_all() has been deprecated, so replace it with dmaengine_terminate_sync().
--- drivers/spi/spi-fsl-lpspi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/spi/spi-fsl-lpspi.c +9 -9
@@ -647,7 +647,7 @@ static int fsl_lpspi_dma_transfer(struct tx->sgl, tx->nents,DMA_MEM_TO_DEV , DMA_PREP_INTERRUPT | DMA_CTRL_ACK);if (!desc_tx) { -dmaengine_terminate_all (controller->dma_tx); +dmaengine_terminate_sync (controller->dma_tx);return -EINVAL ; }
@@ -668,8 +668,8 @@ static int fsl_lpspi_dma_transfer(struct transfer_timeout);if (!time_left) {dev_err (fsl_lpspi->dev,"I/O Error in DMA TX\n" ); -dmaengine_terminate_all (controller->dma_tx); -dmaengine_terminate_all (controller->dma_rx); +dmaengine_terminate_sync (controller->dma_tx); +dmaengine_terminate_sync (controller->dma_rx);fsl_lpspi_reset (fsl_lpspi);return -ETIMEDOUT ; }
@@ -678,8 +678,8 @@ static int fsl_lpspi_dma_transfer(struct transfer_timeout);if (!time_left) {dev_err (fsl_lpspi->dev,"I/O Error in DMA RX\n" ); -dmaengine_terminate_all (controller->dma_tx); -dmaengine_terminate_all (controller->dma_rx); +dmaengine_terminate_sync (controller->dma_tx); +dmaengine_terminate_sync (controller->dma_rx);fsl_lpspi_reset (fsl_lpspi);return -ETIMEDOUT ; }
@@ -688,8 +688,8 @@ static int fsl_lpspi_dma_transfer(struct fsl_lpspi->target_aborted) {dev_dbg (fsl_lpspi->dev,"I/O Error in DMA TX interrupted\n" ); -dmaengine_terminate_all (controller->dma_tx); -dmaengine_terminate_all (controller->dma_rx); +dmaengine_terminate_sync (controller->dma_tx); +dmaengine_terminate_sync (controller->dma_rx);fsl_lpspi_reset (fsl_lpspi);return -EINTR ; }
@@ -698,8 +698,8 @@ static int fsl_lpspi_dma_transfer(struct fsl_lpspi->target_aborted) {dev_dbg (fsl_lpspi->dev,"I/O Error in DMA RX interrupted\n" ); -dmaengine_terminate_all (controller->dma_tx); -dmaengine_terminate_all (controller->dma_rx); +dmaengine_terminate_sync (controller->dma_tx); +dmaengine_terminate_sync (controller->dma_rx);fsl_lpspi_reset (fsl_lpspi);return -EINTR ; }
Greg Kroah-Hartman
maintainerPATCH 402/518 spi: fsl-lpspi: terminate the RX channel on TX prepare failure path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Song <[email protected]>
commit 01980b5da56e573d62798d0ff6c86bcaa2b22cbe upstream.
When dmaengine_prep_slave_sg() fails for the TX channel, the error path terminates the TX DMA channel but leaves the RX channel running. Since the RX channel was already submitted and issued prior to preparing the TX descriptor, returning -EINVAL causes the SPI core to unmap the DMA buffers while the RX DMA engine continues writing to them, leading to potential memory corruption or use-after-free.
Terminate the RX channel before returning on the TX prepare failure path.
--- drivers/spi/spi-fsl-lpspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-fsl-lpspi.c +1 -1
@@ -647,7 +647,7 @@ static int fsl_lpspi_dma_transfer(struct tx->sgl, tx->nents,DMA_MEM_TO_DEV , DMA_PREP_INTERRUPT | DMA_CTRL_ACK);if (!desc_tx) { -dmaengine_terminate_sync (controller->dma_tx); +dmaengine_terminate_sync (controller->dma_rx);return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 403/518 x86/mm: Fix freeing of PMD-sized vmemmap pages
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand (Arm) <[email protected]>
commit 39406c05f8f150f1685839acd38ffdd69ff92031 upstream.
Commit bf9e4e30f353 ("x86/mm: use pagetable_free()"), switched from freeing non-boot page tables through __free_pages() to pagetable_free().
However, the function is also called to free vmemmap pages.
Given that vmemmap pages are not page tables, already the page_ptdesc(page) is wrong. But worse, pagetable_free() calls:
__free_pages(page, compound_order(page));
Since vmemmap pages are not compound pages (see vmemmap_alloc_block()) -- except for HVO, which doesn't apply here -- only first page of a PMD-sized vmemmap page is freed, leaking the other ones.
Fix it by properly decoupling pagetable and vmemmap freeing. free_pagetable() no longer has to mess with SECTION_INFO, as only the vmemmap is marked like that in register_page_bootmem_memmap().
The indentation in remove_pmd_table() is messed up. Fix that while touching it.
Bootmem info handling will soon be fixed up. For now, handle it similar to free_pagetable(), just avoiding the ifdef.
[ dhansen: changelog munging. More imperative voice ]
--- arch/x86/mm/init_64.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-)
arch/x86/mm/init_64.c +26 -14
@@ -1014,7 +1014,7 @@ static void __meminit free_pagetable(str#ifdef CONFIG_HAVE_BOOTMEM_INFO_NODE enum bootmem_type type =bootmem_type (page); -if (type ==SECTION_INFO || type ==MIX_SECTION_INFO ) { +if (type ==MIX_SECTION_INFO ) {while (nr_pages--)put_page_bootmem (page++); }else {
@@ -1028,13 +1028,24 @@ static void __meminit free_pagetable(str } } -static void __meminit free_hugepage_table (struct page *page, +static void __meminit free_vmemmap_pages (struct page *page,unsigned int order,struct vmem_altmap *altmap) { -if (altmap) -vmem_altmap_free (altmap,PMD_SIZE /PAGE_SIZE ); -else -free_pagetable (page,get_order (PMD_SIZE )); +unsigned long nr_pages =1u << order; + +if (altmap) { +vmem_altmap_free (altmap, nr_pages); + }else if (PageReserved (page)) { +if (IS_ENABLED (CONFIG_HAVE_BOOTMEM_INFO_NODE ) && +bootmem_type (page) ==SECTION_INFO ) { +while (nr_pages--) +put_page_bootmem (page++); + }else { +free_reserved_pages (page, nr_pages); + } + }else { +__free_pages (page, order); + } }static void __meminit free_pte_table (pte_t *pte_start,pmd_t *pmd)
@@ -1118,7 +1129,8 @@ remove_pte_table(pte_t *pte_start, unsigreturn ;if (!direct) -free_pagetable (pte_page (*pte),0 ); +/* We never populate base pages from the altmap. */ +free_vmemmap_pages (pte_page (*pte),0 ,NULL );spin_lock (&init_mm.page_table_lock);pte_clear (&init_mm, addr, pte);
@@ -1153,19 +1165,19 @@ remove_pmd_table(pmd_t *pmd_start, unsigif (IS_ALIGNED (addr,PMD_SIZE ) &&IS_ALIGNED (next,PMD_SIZE )) {if (!direct) -free_hugepage_table (pmd_page (*pmd), - altmap); +free_vmemmap_pages (pmd_page (*pmd), +PMD_ORDER , altmap);spin_lock (&init_mm.page_table_lock);pmd_clear (pmd);spin_unlock (&init_mm.page_table_lock); pages++; }else if (vmemmap_pmd_is_unused (addr, next)) { -free_hugepage_table (pmd_page (*pmd), - altmap); -spin_lock (&init_mm.page_table_lock); -pmd_clear (pmd); -spin_unlock (&init_mm.page_table_lock); +free_vmemmap_pages (pmd_page (*pmd),PMD_ORDER , + altmap); +spin_lock (&init_mm.page_table_lock); +pmd_clear (pmd); +spin_unlock (&init_mm.page_table_lock); }continue ; }
Greg Kroah-Hartman
maintainerPATCH 404/518 EDAC/i10nm: Dont fail probing if ADXL is missing
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasily Khoruzhick <[email protected]>
commit e360a6d65bb46c527a5909430a31d640cdd5036e upstream.
ADXL is not present in Coreboot- or Slimbootloader-based BIOSes and as result, the driver fails to probe there.
Since commit 2738c69a8813 ("EDAC/i10nm: Add driver decoder for Ice Lake and Tremont CPUs"), i10nm_edac supports driver decoder. Switch to driver decoding when ADXL is not present.
--- drivers/edac/i10nm_base.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/edac/i10nm_base.c +11 -3
@@ -79,6 +79,7 @@ static struct res_config *res_cfg;static int retry_rd_err_log;static int decoding_via_mca;static bool mem_cfg_2lm; +static bool no_adxl;static struct reg_rrl icx_reg_rrl_ddr = { .set_num =2 ,
@@ -1222,8 +1223,14 @@ static int __init i10nm_init(void) } rc =skx_adxl_get (); -if (rc) - goto fail; +if (rc) { +/* Decoding errors via MCA banks for 2LM isn't supported yet */ +if (rc != -ENODEV || mem_cfg_2lm) + goto fail; +i10nm_printk (KERN_INFO ,"ADXL not found, falling back to MCA-based decoding.\n" ); + no_adxl = true; + decoding_via_mca = true; + }opstate_init ();mce_register_decode_chain (&i10nm_mce_dec);
@@ -1257,7 +1264,8 @@ static void __exit i10nm_exit(void)skx_teardown_debug ();mce_unregister_decode_chain (&i10nm_mce_dec); -skx_adxl_put (); +if (!no_adxl) +skx_adxl_put ();skx_remove (); }
Greg Kroah-Hartman
maintainerPATCH 405/518 watchdog: apple: Add "apple,t8103-wdt" compatible
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Janne Grunau <[email protected]>
commit 14ca4868886f2188401fe06cd7bf01a330b3fb99 upstream.
After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,wdt" anymore [1]. Use "apple,t8103-wdt" as base compatible as it is the SoC the driver and bindings were written for.
[1]: https://lore.kernel.org/asahi/[email protected]/
--- drivers/watchdog/apple_wdt.c | 1 + 1 file changed, 1 insertion(+)
drivers/watchdog/apple_wdt.c +1 -0
@@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct devi static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume);static const struct of_device_id apple_wdt_of_match[] = { + { .compatible ="apple,t8103-wdt" }, { .compatible ="apple,wdt" }, {}, };