FAILED: patch "[PATCH] HID: prodikeys: validate fixed-format MIDI reports" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 0ff37294c41bd925258893310398bc2b45fcd4a7
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026110446-amnesty-outsmart-92b6@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 0ff37294c41bd925258893310398bc2b45fcd4a7 Mon Sep 17 00:00:00 2001
From: Jiale Yao <[email protected]>
Date: Thu, 24 Sep 2026 22:44:11 +0800
Subject: [PATCH] HID: prodikeys: validate fixed-format MIDI reports
The HID core invokes raw_event callbacks before validating the report length. Prodikeys reports 0x01 and 0x04 are passed to handlers that always read bytes one through three, regardless of the supplied size. A truncated report can therefore cause an out-of-bounds read.
Require four bytes for the two fixed-format reports. Keep report 0x03 on its existing variable-length path, which derives the number of note pairs from size and only accesses complete pairs.
Commit 47669bec44fe ("HID: asus: refactor the two workqueues and init sequence") added the same kind of raw_event length validation to hid-asus.
drivers/hid/hid-prodikeys.c +6 -1
@@ -772,8 +772,13 @@ static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,if (report->id == data[0 ])switch (report->id) {case 0x01 :/* midi keys (qwerty)*/ -case 0x03 :/* midi keyboard (musical)*/ case 0x04 :/* extra/midi keys (qwerty)*/ +if (size <4 ) +break ; + ret =pcmidi_handle_report (pm, report->id, + data, size); +break ; +case 0x03 :/* midi keyboard (musical)*/ ret =pcmidi_handle_report (pm, report->id, data, size);break ;
Sasha Levin
maintainerPATCH 1/2 HID: hid-prodikeys: remove struct pk_device
From: "Jiri Slaby (SUSE)" <[email protected]>
[ Upstream commit 16d0e1d469cc16aefa8ef745e926eda473a9b221 ]
First, quirks was unused in struct pk_device.
And I see no reason for this additional level of indirection. struct pcmidi_snd is far enough for the driver. Unless I am missing something?
So drop struct pk_device and convert all the users to use struct pcmidi_snd directly. No need for doubled kmalloc+kfrees now.
Found by https://github.com/jirislaby/clang-struct.
Stable-dep-of: 0ff37294c41b ("HID: prodikeys: validate fixed-format MIDI reports")
--- drivers/hid/hid-prodikeys.c | 113 +++++++++++++----------------------- 1 file changed, 40 insertions(+), 73 deletions(-)
drivers/hid/hid-prodikeys.c +40 -73
@@ -32,13 +32,6 @@struct pcmidi_snd ; -struct pk_device { -unsigned long quirks; - -struct hid_device *hdev; -struct pcmidi_snd *pm;/* pcmidi device context */ -}; -struct pcmidi_sustain {unsigned long in_use;struct pcmidi_snd *pm;
@@ -50,7 +43,7 @@ struct pcmidi_sustain {#define PCMIDI_SUSTAINED_MAX 32struct pcmidi_snd { -struct pk_device *pk; +struct hid_device *hdev;unsigned short ifnum;struct hid_report *pcmidi_report6;struct input_dev *input_ep82;
@@ -100,11 +93,11 @@ static ssize_t show_channel(struct device *dev, struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev); -dbg_hid ("pcmidi sysfs read channel=%u\n" , pk->pm->midi_channel); +dbg_hid ("pcmidi sysfs read channel=%u\n" , pm->midi_channel); -return sprintf (buf,"%u (min:%u, max:%u)\n" , pk->pm->midi_channel, +return sprintf (buf,"%u (min:%u, max:%u)\n" , pm->midi_channel,PCMIDI_CHANNEL_MIN ,PCMIDI_CHANNEL_MAX ); }
@@ -113,13 +106,13 @@ static ssize_t store_channel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hid_device *hdev = to_hid_device(dev); -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev);unsigned channel =0 ;if (sscanf (buf,"%u" , &channel) >0 && channel <=PCMIDI_CHANNEL_MAX ) {dbg_hid ("pcmidi sysfs write channel=%u\n" , channel); - pk->pm->midi_channel = channel; + pm->midi_channel = channel;return strlen (buf); }return -EINVAL ;
@@ -137,11 +130,11 @@ static ssize_t show_sustain(struct device *dev, struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev); -dbg_hid ("pcmidi sysfs read sustain=%u\n" , pk->pm->midi_sustain); +dbg_hid ("pcmidi sysfs read sustain=%u\n" , pm->midi_sustain); -return sprintf (buf,"%u (off:%u, max:%u (ms))\n" , pk->pm->midi_sustain, +return sprintf (buf,"%u (off:%u, max:%u (ms))\n" , pm->midi_sustain,PCMIDI_SUSTAIN_MIN ,PCMIDI_SUSTAIN_MAX ); }
@@ -150,15 +143,14 @@ static ssize_t store_sustain(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hid_device *hdev = to_hid_device(dev); -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev);unsigned sustain =0 ;if (sscanf (buf,"%u" , &sustain) >0 && sustain <=PCMIDI_SUSTAIN_MAX ) {dbg_hid ("pcmidi sysfs write sustain=%u\n" , sustain); - pk->pm->midi_sustain = sustain; - pk->pm->midi_sustain_mode = - (0 == sustain || !pk->pm->midi_mode) ?0 :1 ; + pm->midi_sustain = sustain; + pm->midi_sustain_mode = (0 == sustain || !pm->midi_mode) ?0 :1 ;return strlen (buf); }return -EINVAL ;
@@ -176,11 +168,11 @@ static ssize_t show_octave(struct device *dev, struct device_attribute *attr, char *buf) { struct hid_device *hdev = to_hid_device(dev); -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev); -dbg_hid ("pcmidi sysfs read octave=%d\n" , pk->pm->midi_octave); +dbg_hid ("pcmidi sysfs read octave=%d\n" , pm->midi_octave); -return sprintf (buf,"%d (min:%d, max:%d)\n" , pk->pm->midi_octave, +return sprintf (buf,"%d (min:%d, max:%d)\n" , pm->midi_octave,PCMIDI_OCTAVE_MIN ,PCMIDI_OCTAVE_MAX ); }
@@ -189,14 +181,14 @@ static ssize_t store_octave(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hid_device *hdev = to_hid_device(dev); -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev);int octave =0 ;if (sscanf (buf,"%d" , &octave) >0 && octave >=PCMIDI_OCTAVE_MIN && octave <=PCMIDI_OCTAVE_MAX ) {dbg_hid ("pcmidi sysfs write octave=%d\n" , octave); - pk->pm->midi_octave = octave; + pm->midi_octave = octave;return strlen (buf); }return -EINVAL ;
@@ -270,7 +262,7 @@ static void stop_sustain_timers(struct pcmidi_snd *pm)static int pcmidi_get_output_report (struct pcmidi_snd *pm) { -struct hid_device *hdev = pm->pk->hdev; +struct hid_device *hdev = pm->hdev;struct hid_report *report; list_for_each_entry(report,
@@ -295,7 +287,7 @@ static int pcmidi_get_output_report(struct pcmidi_snd *pm)static void pcmidi_submit_output_report (struct pcmidi_snd *pm,int state) { -struct hid_device *hdev = pm->pk->hdev; +struct hid_device *hdev = pm->hdev;struct hid_report *report = pm->pcmidi_report6; report->field[0 ]->value[0 ] =0x01 ; report->field[0 ]->value[1 ] = state;
@@ -626,7 +618,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)/* Setup sound card */ - err =snd_card_new (&pm->pk->hdev->dev, index[dev], id[dev], + err =snd_card_new (&pm->hdev->dev, index[dev], id[dev],THIS_MODULE ,0 , &card);if (err <0 ) {pk_error ("failed to create pc-midi sound card\n" );
@@ -664,7 +656,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm) &pcmidi_in_ops);/* create sysfs variables */ - err =device_create_file (&pm->pk->hdev->dev, + err =device_create_file (&pm->hdev->dev, sysfs_device_attr_channel);if (err <0 ) { pk_error("failed to create sysfs attribute channel: error %d\n",
@@ -672,7 +664,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm) goto fail; } - err =device_create_file (&pm->pk->hdev->dev, + err =device_create_file (&pm->hdev->dev, sysfs_device_attr_sustain);if (err <0 ) { pk_error("failed to create sysfs attribute sustain: error %d\n",
@@ -680,7 +672,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm) goto fail_attr_sustain; } - err =device_create_file (&pm->pk->hdev->dev, + err =device_create_file (&pm->hdev->dev, sysfs_device_attr_octave);if (err <0 ) { pk_error("failed to create sysfs attribute octave: error %d\n",
@@ -710,11 +702,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm) fail_register:stop_sustain_timers (pm); -device_remove_file (&pm->pk->hdev->dev, sysfs_device_attr_octave); +device_remove_file (&pm->hdev->dev, sysfs_device_attr_octave); fail_attr_octave: -device_remove_file (&pm->pk->hdev->dev, sysfs_device_attr_sustain); +device_remove_file (&pm->hdev->dev, sysfs_device_attr_sustain); fail_attr_sustain: -device_remove_file (&pm->pk->hdev->dev, sysfs_device_attr_channel); +device_remove_file (&pm->hdev->dev, sysfs_device_attr_channel); fail:if (pm->card) {snd_card_free (pm->card);
@@ -728,12 +720,9 @@ static int pcmidi_snd_terminate(struct pcmidi_snd *pm)if (pm->card) {stop_sustain_timers (pm); -device_remove_file (&pm->pk->hdev->dev, - sysfs_device_attr_channel); -device_remove_file (&pm->pk->hdev->dev, - sysfs_device_attr_sustain); -device_remove_file (&pm->pk->hdev->dev, - sysfs_device_attr_octave); +device_remove_file (&pm->hdev->dev, sysfs_device_attr_channel); +device_remove_file (&pm->hdev->dev, sysfs_device_attr_sustain); +device_remove_file (&pm->hdev->dev, sysfs_device_attr_octave);snd_card_disconnect (pm->card);snd_card_free_when_closed (pm->card);
@@ -763,10 +752,7 @@ static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - struct pk_device *pk = hid_get_drvdata(hdev); -struct pcmidi_snd *pm; - - pm = pk->pm; + struct pcmidi_snd *pm = hid_get_drvdata(hdev);if (HID_UP_MSVENDOR == (usage->hid &HID_USAGE_PAGE ) &&1 == pm->ifnum) {
@@ -781,16 +767,16 @@ static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,static int pk_raw_event (struct hid_device *hdev,struct hid_report *report,u8 *data,int size) { -struct pk_device *pk =hid_get_drvdata (hdev); +struct pcmidi_snd *pm =hid_get_drvdata (hdev);int ret =0 ; -if (1 == pk->pm->ifnum) { +if (1 == pm->ifnum) {if (report->id == data[0 ])switch (report->id) {case 0x01 :/* midi keys (qwerty)*/ case 0x03 :/* midi keyboard (musical)*/ case 0x04 :/* extra/midi keys (qwerty)*/ - ret =pcmidi_handle_report (pk->pm, + ret =pcmidi_handle_report (pm, report->id, data, size);break ; }
@@ -805,8 +791,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)struct usb_interface *intf;unsigned short ifnum;unsigned long quirks = id->driver_data; -struct pk_device *pk; -struct pcmidi_snd *pm =NULL ; +struct pcmidi_snd *pm;if (!hid_is_usb (hdev))return -EINVAL ;
@@ -814,26 +799,16 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id) intf =to_usb_interface (hdev->dev.parent); ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - pk =kzalloc (sizeof (*pk),GFP_KERNEL ); -if (pk ==NULL ) { -hid_err (hdev,"can't alloc descriptor\n" ); -return -ENOMEM ; - } - - pk->hdev = hdev; - pm =kzalloc (sizeof (*pm),GFP_KERNEL );if (pm ==NULL ) {hid_err (hdev,"can't alloc descriptor\n" ); - ret = -ENOMEM ; - goto err_free_pk; +return -ENOMEM ; } - pm->pk = pk; - pk->pm = pm; + pm->hdev = hdev; pm->ifnum = ifnum; -hid_set_drvdata (hdev, pk); +hid_set_drvdata (hdev, pm); ret =hid_parse (hdev);if (ret) {
@@ -860,26 +835,18 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)hid_hw_stop (hdev); err_free:kfree (pm); -err_free_pk: -kfree (pk);return ret; }static void pk_remove (struct hid_device *hdev) { -struct pk_device *pk =hid_get_drvdata (hdev); -struct pcmidi_snd *pm; - - pm = pk->pm; -if (pm) { -pcmidi_snd_terminate (pm); -kfree (pm); - } +struct pcmidi_snd *pm =hid_get_drvdata (hdev); +pcmidi_snd_terminate (pm);hid_hw_stop (hdev); -kfree (pk); +kfree (pm); }static const struct hid_device_id pk_devices[] = {
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 HID: prodikeys: validate fixed-format MIDI reports
From: Jiale Yao <[email protected]>
[ Upstream commit 0ff37294c41bd925258893310398bc2b45fcd4a7 ]
The HID core invokes raw_event callbacks before validating the report length. Prodikeys reports 0x01 and 0x04 are passed to handlers that always read bytes one through three, regardless of the supplied size. A truncated report can therefore cause an out-of-bounds read.
Require four bytes for the two fixed-format reports. Keep report 0x03 on its existing variable-length path, which derives the number of note pairs from size and only accesses complete pairs.
Commit 47669bec44fe ("HID: asus: refactor the two workqueues and init sequence") added the same kind of raw_event length validation to hid-asus.
--- drivers/hid/hid-prodikeys.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/hid/hid-prodikeys.c +6 -1
@@ -774,8 +774,13 @@ static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,if (report->id == data[0 ])switch (report->id) {case 0x01 :/* midi keys (qwerty)*/ -case 0x03 :/* midi keyboard (musical)*/ case 0x04 :/* extra/midi keys (qwerty)*/ +if (size <4 ) +break ; + ret =pcmidi_handle_report (pm, report->id, + data, size); +break ; +case 0x03 :/* midi keyboard (musical)*/ ret =pcmidi_handle_report (pm, report->id, data, size);break ;
Signature · 1 line
2.53.0