From: Sasha Levin Date: Tue, 18 Feb 2025 12:30:05 +0000 (-0500) Subject: Fixes for 6.6 X-Git-Tag: v6.1.129~50^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0978cc6dd3e987e62664dc377d83a9db33a42fb5;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.6 Signed-off-by: Sasha Levin --- diff --git a/queue-6.6/arp-use-rcu-protection-in-arp_xmit.patch b/queue-6.6/arp-use-rcu-protection-in-arp_xmit.patch new file mode 100644 index 0000000000..70d78b9c70 --- /dev/null +++ b/queue-6.6/arp-use-rcu-protection-in-arp_xmit.patch @@ -0,0 +1,45 @@ +From a4373a52c02c78578e1f41a621e5297f376afd73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Feb 2025 13:58:36 +0000 +Subject: arp: use RCU protection in arp_xmit() + +From: Eric Dumazet + +[ Upstream commit a42b69f692165ec39db42d595f4f65a4c8f42e44 ] + +arp_xmit() can be called without RTNL or RCU protection. + +Use RCU protection to avoid potential UAF. + +Fixes: 29a26a568038 ("netfilter: Pass struct net into the netfilter hooks") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250207135841.1948589-5-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/arp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c +index 0d0d725b46ad0..02776453bf97a 100644 +--- a/net/ipv4/arp.c ++++ b/net/ipv4/arp.c +@@ -658,10 +658,12 @@ static int arp_xmit_finish(struct net *net, struct sock *sk, struct sk_buff *skb + */ + void arp_xmit(struct sk_buff *skb) + { ++ rcu_read_lock(); + /* Send it off, maybe filter it using firewalling first. */ + NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, +- dev_net(skb->dev), NULL, skb, NULL, skb->dev, ++ dev_net_rcu(skb->dev), NULL, skb, NULL, skb->dev, + arp_xmit_finish); ++ rcu_read_unlock(); + } + EXPORT_SYMBOL(arp_xmit); + +-- +2.39.5 + diff --git a/queue-6.6/clocksource-use-migrate_disable-to-avoid-calling-get.patch b/queue-6.6/clocksource-use-migrate_disable-to-avoid-calling-get.patch new file mode 100644 index 0000000000..21227673bf --- /dev/null +++ b/queue-6.6/clocksource-use-migrate_disable-to-avoid-calling-get.patch @@ -0,0 +1,82 @@ +From f4b49af215b2381b38525bc1225c90c5e29806f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jan 2025 12:33:23 -0500 +Subject: clocksource: Use migrate_disable() to avoid calling get_random_u32() + in atomic context + +From: Waiman Long + +[ Upstream commit 6bb05a33337b2c842373857b63de5c9bf1ae2a09 ] + +The following bug report happened with a PREEMPT_RT kernel: + + BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 + in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 2012, name: kwatchdog + preempt_count: 1, expected: 0 + RCU nest depth: 0, expected: 0 + get_random_u32+0x4f/0x110 + clocksource_verify_choose_cpus+0xab/0x1a0 + clocksource_verify_percpu.part.0+0x6b/0x330 + clocksource_watchdog_kthread+0x193/0x1a0 + +It is due to the fact that clocksource_verify_choose_cpus() is invoked with +preemption disabled. This function invokes get_random_u32() to obtain +random numbers for choosing CPUs. The batched_entropy_32 local lock and/or +the base_crng.lock spinlock in driver/char/random.c will be acquired during +the call. In PREEMPT_RT kernel, they are both sleeping locks and so cannot +be acquired in atomic context. + +Fix this problem by using migrate_disable() to allow smp_processor_id() to +be reliably used without introducing atomic context. preempt_disable() is +then called after clocksource_verify_choose_cpus() but before the +clocksource measurement is being run to avoid introducing unexpected +latency. + +Fixes: 7560c02bdffb ("clocksource: Check per-CPU clock synchronization when marked unstable") +Suggested-by: Sebastian Andrzej Siewior +Signed-off-by: Waiman Long +Signed-off-by: Thomas Gleixner +Reviewed-by: Paul E. McKenney +Reviewed-by: Sebastian Andrzej Siewior +Link: https://lore.kernel.org/all/20250131173323.891943-2-longman@redhat.com +Signed-off-by: Sasha Levin +--- + kernel/time/clocksource.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index 6b5b7c9c14732..3130f24daf597 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -351,10 +351,10 @@ void clocksource_verify_percpu(struct clocksource *cs) + cpumask_clear(&cpus_ahead); + cpumask_clear(&cpus_behind); + cpus_read_lock(); +- preempt_disable(); ++ migrate_disable(); + clocksource_verify_choose_cpus(); + if (cpumask_empty(&cpus_chosen)) { +- preempt_enable(); ++ migrate_enable(); + cpus_read_unlock(); + pr_warn("Not enough CPUs to check clocksource '%s'.\n", cs->name); + return; +@@ -362,6 +362,7 @@ void clocksource_verify_percpu(struct clocksource *cs) + testcpu = smp_processor_id(); + pr_info("Checking clocksource %s synchronization from CPU %d to CPUs %*pbl.\n", + cs->name, testcpu, cpumask_pr_args(&cpus_chosen)); ++ preempt_disable(); + for_each_cpu(cpu, &cpus_chosen) { + if (cpu == testcpu) + continue; +@@ -381,6 +382,7 @@ void clocksource_verify_percpu(struct clocksource *cs) + cs_nsec_min = cs_nsec; + } + preempt_enable(); ++ migrate_enable(); + cpus_read_unlock(); + if (!cpumask_empty(&cpus_ahead)) + pr_warn(" CPUs %*pbl ahead of CPU %d for clocksource %s.\n", +-- +2.39.5 + diff --git a/queue-6.6/clocksource-use-pr_info-for-checking-clocksource-syn.patch b/queue-6.6/clocksource-use-pr_info-for-checking-clocksource-syn.patch new file mode 100644 index 0000000000..b944f8ac02 --- /dev/null +++ b/queue-6.6/clocksource-use-pr_info-for-checking-clocksource-syn.patch @@ -0,0 +1,45 @@ +From b28dd542264fa90d8c0988eeac61f7ceba087a80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jan 2025 20:54:41 -0500 +Subject: clocksource: Use pr_info() for "Checking clocksource synchronization" + message + +From: Waiman Long + +[ Upstream commit 1f566840a82982141f94086061927a90e79440e5 ] + +The "Checking clocksource synchronization" message is normally printed +when clocksource_verify_percpu() is called for a given clocksource if +both the CLOCK_SOURCE_UNSTABLE and CLOCK_SOURCE_VERIFY_PERCPU flags +are set. + +It is an informational message and so pr_info() is the correct choice. + +Signed-off-by: Waiman Long +Signed-off-by: Thomas Gleixner +Reviewed-by: Paul E. McKenney +Acked-by: John Stultz +Link: https://lore.kernel.org/all/20250125015442.3740588-1-longman@redhat.com +Stable-dep-of: 6bb05a33337b ("clocksource: Use migrate_disable() to avoid calling get_random_u32() in atomic context") +Signed-off-by: Sasha Levin +--- + kernel/time/clocksource.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index aa864999dc21b..6b5b7c9c14732 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -360,7 +360,8 @@ void clocksource_verify_percpu(struct clocksource *cs) + return; + } + testcpu = smp_processor_id(); +- pr_warn("Checking clocksource %s synchronization from CPU %d to CPUs %*pbl.\n", cs->name, testcpu, cpumask_pr_args(&cpus_chosen)); ++ pr_info("Checking clocksource %s synchronization from CPU %d to CPUs %*pbl.\n", ++ cs->name, testcpu, cpumask_pr_args(&cpus_chosen)); + for_each_cpu(cpu, &cpus_chosen) { + if (cpu == testcpu) + continue; +-- +2.39.5 + diff --git a/queue-6.6/flow_dissector-use-rcu-protection-to-fetch-dev_net.patch b/queue-6.6/flow_dissector-use-rcu-protection-to-fetch-dev_net.patch new file mode 100644 index 0000000000..486d5dcd30 --- /dev/null +++ b/queue-6.6/flow_dissector-use-rcu-protection-to-fetch-dev_net.patch @@ -0,0 +1,81 @@ +From 8335e45f7d639dec74d53ee96a1ab33d7cf6f737 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:17 +0000 +Subject: flow_dissector: use RCU protection to fetch dev_net() + +From: Eric Dumazet + +[ Upstream commit afec62cd0a4191cde6dd3a75382be4d51a38ce9b ] + +__skb_flow_dissect() can be called from arbitrary contexts. + +It must extend its RCU protection section to include +the call to dev_net(), which can become dev_net_rcu(). + +This makes sure the net structure can not disappear under us. + +Fixes: 9b52e3f267a6 ("flow_dissector: handle no-skb use case") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250205155120.1676781-10-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/flow_dissector.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index b22d20cc417b2..00a5c41c1831d 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -1084,10 +1084,12 @@ bool __skb_flow_dissect(const struct net *net, + FLOW_DISSECTOR_KEY_BASIC, + target_container); + ++ rcu_read_lock(); ++ + if (skb) { + if (!net) { + if (skb->dev) +- net = dev_net(skb->dev); ++ net = dev_net_rcu(skb->dev); + else if (skb->sk) + net = sock_net(skb->sk); + } +@@ -1098,7 +1100,6 @@ bool __skb_flow_dissect(const struct net *net, + enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR; + struct bpf_prog_array *run_array; + +- rcu_read_lock(); + run_array = rcu_dereference(init_net.bpf.run_array[type]); + if (!run_array) + run_array = rcu_dereference(net->bpf.run_array[type]); +@@ -1126,17 +1127,17 @@ bool __skb_flow_dissect(const struct net *net, + prog = READ_ONCE(run_array->items[0].prog); + result = bpf_flow_dissect(prog, &ctx, n_proto, nhoff, + hlen, flags); +- if (result == BPF_FLOW_DISSECTOR_CONTINUE) +- goto dissect_continue; +- __skb_flow_bpf_to_target(&flow_keys, flow_dissector, +- target_container); +- rcu_read_unlock(); +- return result == BPF_OK; ++ if (result != BPF_FLOW_DISSECTOR_CONTINUE) { ++ __skb_flow_bpf_to_target(&flow_keys, flow_dissector, ++ target_container); ++ rcu_read_unlock(); ++ return result == BPF_OK; ++ } + } +-dissect_continue: +- rcu_read_unlock(); + } + ++ rcu_read_unlock(); ++ + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_ETH_ADDRS)) { + struct ethhdr *eth = eth_hdr(skb); +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-add-deck-imu-support.patch b/queue-6.6/hid-hid-steam-add-deck-imu-support.patch new file mode 100644 index 0000000000..96d5424c09 --- /dev/null +++ b/queue-6.6/hid-hid-steam-add-deck-imu-support.patch @@ -0,0 +1,286 @@ +From 985feefa48ba4b5652d705192fca2f19e97672ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Apr 2024 12:34:18 +0000 +Subject: HID: hid-steam: Add Deck IMU support + +From: Max Maisel + +[ Upstream commit 3347e1654f24dbbd357ea4e3c0d8dcc12d8586c7 ] + +The Deck's controller features an accelerometer and gyroscope which +send their measurement values by default in the main HID input report. +Expose both sensors to userspace through a separate evdev node as it +is done by the hid-nintendo and hid-playstation drivers. + +Signed-off-by: Max Maisel +Reviewed-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 155 +++++++++++++++++++++++++++++++++++++--- + 1 file changed, 147 insertions(+), 8 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 59b46163bc526..29a0e1f395339 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -66,6 +66,14 @@ static LIST_HEAD(steam_devices); + #define STEAM_DECK_TRIGGER_RESOLUTION 5461 + /* Joystick runs are about 5 mm and 32768 units */ + #define STEAM_DECK_JOYSTICK_RESOLUTION 6553 ++/* Accelerometer has 16 bit resolution and a range of +/- 2g */ ++#define STEAM_DECK_ACCEL_RES_PER_G 16384 ++#define STEAM_DECK_ACCEL_RANGE 32768 ++#define STEAM_DECK_ACCEL_FUZZ 32 ++/* Gyroscope has 16 bit resolution and a range of +/- 2000 dps */ ++#define STEAM_DECK_GYRO_RES_PER_DPS 16 ++#define STEAM_DECK_GYRO_RANGE 32768 ++#define STEAM_DECK_GYRO_FUZZ 1 + + #define STEAM_PAD_FUZZ 256 + +@@ -288,6 +296,7 @@ struct steam_device { + struct mutex report_mutex; + bool client_opened; + struct input_dev __rcu *input; ++ struct input_dev __rcu *sensors; + unsigned long quirks; + struct work_struct work_connect; + bool connected; +@@ -302,6 +311,7 @@ struct steam_device { + struct work_struct rumble_work; + u16 rumble_left; + u16 rumble_right; ++ unsigned int sensor_timestamp_us; + }; + + static int steam_recv_report(struct steam_device *steam, +@@ -824,6 +834,74 @@ static int steam_input_register(struct steam_device *steam) + return ret; + } + ++static int steam_sensors_register(struct steam_device *steam) ++{ ++ struct hid_device *hdev = steam->hdev; ++ struct input_dev *sensors; ++ int ret; ++ ++ if (!(steam->quirks & STEAM_QUIRK_DECK)) ++ return 0; ++ ++ rcu_read_lock(); ++ sensors = rcu_dereference(steam->sensors); ++ rcu_read_unlock(); ++ if (sensors) { ++ dbg_hid("%s: already connected\n", __func__); ++ return 0; ++ } ++ ++ sensors = input_allocate_device(); ++ if (!sensors) ++ return -ENOMEM; ++ ++ input_set_drvdata(sensors, steam); ++ sensors->dev.parent = &hdev->dev; ++ ++ sensors->name = "Steam Deck Motion Sensors"; ++ sensors->phys = hdev->phys; ++ sensors->uniq = steam->serial_no; ++ sensors->id.bustype = hdev->bus; ++ sensors->id.vendor = hdev->vendor; ++ sensors->id.product = hdev->product; ++ sensors->id.version = hdev->version; ++ ++ __set_bit(INPUT_PROP_ACCELEROMETER, sensors->propbit); ++ __set_bit(EV_MSC, sensors->evbit); ++ __set_bit(MSC_TIMESTAMP, sensors->mscbit); ++ ++ input_set_abs_params(sensors, ABS_X, -STEAM_DECK_ACCEL_RANGE, ++ STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0); ++ input_set_abs_params(sensors, ABS_Y, -STEAM_DECK_ACCEL_RANGE, ++ STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0); ++ input_set_abs_params(sensors, ABS_Z, -STEAM_DECK_ACCEL_RANGE, ++ STEAM_DECK_ACCEL_RANGE, STEAM_DECK_ACCEL_FUZZ, 0); ++ input_abs_set_res(sensors, ABS_X, STEAM_DECK_ACCEL_RES_PER_G); ++ input_abs_set_res(sensors, ABS_Y, STEAM_DECK_ACCEL_RES_PER_G); ++ input_abs_set_res(sensors, ABS_Z, STEAM_DECK_ACCEL_RES_PER_G); ++ ++ input_set_abs_params(sensors, ABS_RX, -STEAM_DECK_GYRO_RANGE, ++ STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0); ++ input_set_abs_params(sensors, ABS_RY, -STEAM_DECK_GYRO_RANGE, ++ STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0); ++ input_set_abs_params(sensors, ABS_RZ, -STEAM_DECK_GYRO_RANGE, ++ STEAM_DECK_GYRO_RANGE, STEAM_DECK_GYRO_FUZZ, 0); ++ input_abs_set_res(sensors, ABS_RX, STEAM_DECK_GYRO_RES_PER_DPS); ++ input_abs_set_res(sensors, ABS_RY, STEAM_DECK_GYRO_RES_PER_DPS); ++ input_abs_set_res(sensors, ABS_RZ, STEAM_DECK_GYRO_RES_PER_DPS); ++ ++ ret = input_register_device(sensors); ++ if (ret) ++ goto sensors_register_fail; ++ ++ rcu_assign_pointer(steam->sensors, sensors); ++ return 0; ++ ++sensors_register_fail: ++ input_free_device(sensors); ++ return ret; ++} ++ + static void steam_input_unregister(struct steam_device *steam) + { + struct input_dev *input; +@@ -837,6 +915,24 @@ static void steam_input_unregister(struct steam_device *steam) + input_unregister_device(input); + } + ++static void steam_sensors_unregister(struct steam_device *steam) ++{ ++ struct input_dev *sensors; ++ ++ if (!(steam->quirks & STEAM_QUIRK_DECK)) ++ return; ++ ++ rcu_read_lock(); ++ sensors = rcu_dereference(steam->sensors); ++ rcu_read_unlock(); ++ ++ if (!sensors) ++ return; ++ RCU_INIT_POINTER(steam->sensors, NULL); ++ synchronize_rcu(); ++ input_unregister_device(sensors); ++} ++ + static void steam_battery_unregister(struct steam_device *steam) + { + struct power_supply *battery; +@@ -889,18 +985,28 @@ static int steam_register(struct steam_device *steam) + spin_lock_irqsave(&steam->lock, flags); + client_opened = steam->client_opened; + spin_unlock_irqrestore(&steam->lock, flags); ++ + if (!client_opened) { + steam_set_lizard_mode(steam, lizard_mode); + ret = steam_input_register(steam); +- } else +- ret = 0; ++ if (ret != 0) ++ goto steam_register_input_fail; ++ ret = steam_sensors_register(steam); ++ if (ret != 0) ++ goto steam_register_sensors_fail; ++ } ++ return 0; + ++steam_register_sensors_fail: ++ steam_input_unregister(steam); ++steam_register_input_fail: + return ret; + } + + static void steam_unregister(struct steam_device *steam) + { + steam_battery_unregister(steam); ++ steam_sensors_unregister(steam); + steam_input_unregister(steam); + if (steam->serial_no[0]) { + hid_info(steam->hdev, "Steam Controller '%s' disconnected", +@@ -1009,6 +1115,7 @@ static int steam_client_ll_open(struct hid_device *hdev) + steam->client_opened = true; + spin_unlock_irqrestore(&steam->lock, flags); + ++ steam_sensors_unregister(steam); + steam_input_unregister(steam); + + return 0; +@@ -1029,6 +1136,7 @@ static void steam_client_ll_close(struct hid_device *hdev) + if (connected) { + steam_set_lizard_mode(steam, lizard_mode); + steam_input_register(steam); ++ steam_sensors_register(steam); + } + } + +@@ -1120,6 +1228,7 @@ static int steam_probe(struct hid_device *hdev, + INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb); + INIT_LIST_HEAD(&steam->list); + INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); ++ steam->sensor_timestamp_us = 0; + + /* + * With the real steam controller interface, do not connect hidraw. +@@ -1379,12 +1488,12 @@ static void steam_do_input_event(struct steam_device *steam, + * 18-19 | s16 | ABS_HAT0Y | left-pad Y value + * 20-21 | s16 | ABS_HAT1X | right-pad X value + * 22-23 | s16 | ABS_HAT1Y | right-pad Y value +- * 24-25 | s16 | -- | accelerometer X value +- * 26-27 | s16 | -- | accelerometer Y value +- * 28-29 | s16 | -- | accelerometer Z value +- * 30-31 | s16 | -- | gyro X value +- * 32-33 | s16 | -- | gyro Y value +- * 34-35 | s16 | -- | gyro Z value ++ * 24-25 | s16 | IMU ABS_X | accelerometer X value ++ * 26-27 | s16 | IMU ABS_Z | accelerometer Y value ++ * 28-29 | s16 | IMU ABS_Y | accelerometer Z value ++ * 30-31 | s16 | IMU ABS_RX | gyro X value ++ * 32-33 | s16 | IMU ABS_RZ | gyro Y value ++ * 34-35 | s16 | IMU ABS_RY | gyro Z value + * 36-37 | s16 | -- | quaternion W value + * 38-39 | s16 | -- | quaternion X value + * 40-41 | s16 | -- | quaternion Y value +@@ -1545,6 +1654,32 @@ static void steam_do_deck_input_event(struct steam_device *steam, + input_sync(input); + } + ++static void steam_do_deck_sensors_event(struct steam_device *steam, ++ struct input_dev *sensors, u8 *data) ++{ ++ /* ++ * The deck input report is received every 4 ms on average, ++ * with a jitter of +/- 4 ms even though the USB descriptor claims ++ * that it uses 1 kHz. ++ * Since the HID report does not include a sensor timestamp, ++ * use a fixed increment here. ++ */ ++ steam->sensor_timestamp_us += 4000; ++ ++ if (!steam->gamepad_mode) ++ return; ++ ++ input_event(sensors, EV_MSC, MSC_TIMESTAMP, steam->sensor_timestamp_us); ++ input_report_abs(sensors, ABS_X, steam_le16(data + 24)); ++ input_report_abs(sensors, ABS_Z, -steam_le16(data + 26)); ++ input_report_abs(sensors, ABS_Y, steam_le16(data + 28)); ++ input_report_abs(sensors, ABS_RX, steam_le16(data + 30)); ++ input_report_abs(sensors, ABS_RZ, -steam_le16(data + 32)); ++ input_report_abs(sensors, ABS_RY, steam_le16(data + 34)); ++ ++ input_sync(sensors); ++} ++ + /* + * The size for this message payload is 11. + * The known values are: +@@ -1582,6 +1717,7 @@ static int steam_raw_event(struct hid_device *hdev, + { + struct steam_device *steam = hid_get_drvdata(hdev); + struct input_dev *input; ++ struct input_dev *sensors; + struct power_supply *battery; + + if (!steam) +@@ -1627,6 +1763,9 @@ static int steam_raw_event(struct hid_device *hdev, + input = rcu_dereference(steam->input); + if (likely(input)) + steam_do_deck_input_event(steam, input, data); ++ sensors = rcu_dereference(steam->sensors); ++ if (likely(sensors)) ++ steam_do_deck_sensors_event(steam, sensors, data); + rcu_read_unlock(); + break; + case ID_CONTROLLER_WIRELESS: +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-add-gamepad-only-mode-switched-to-by-h.patch b/queue-6.6/hid-hid-steam-add-gamepad-only-mode-switched-to-by-h.patch new file mode 100644 index 0000000000..fe03bfdc32 --- /dev/null +++ b/queue-6.6/hid-hid-steam-add-gamepad-only-mode-switched-to-by-h.patch @@ -0,0 +1,222 @@ +From 327baaefb2fef1b920ba1500e5b53d2a664b6d4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 19:38:37 -0800 +Subject: HID: hid-steam: Add gamepad-only mode switched to by holding options + +From: Vicki Pfau + +[ Upstream commit cd438e57dd05b077f4e87c1567beafb2377b6d6b ] + +This commit adds a hotkey to switch between "gamepad" mode (mouse and keyboard +disabled) and "desktop" mode (gamepad disabled) by holding down the options +button (mapped here as the start button). This mirrors the behavior of the +official Steam client. + +This also adds and uses a function for generating haptic pulses, as Steam also +does when engaging this hotkey. + +Signed-off-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 113 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 103 insertions(+), 10 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 991db5acf5ddb..2f87026f01de1 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -273,6 +273,11 @@ enum { + TRACKPAD_GESTURE_KEYBOARD, + }; + ++/* Pad identifiers for the deck */ ++#define STEAM_PAD_LEFT 0 ++#define STEAM_PAD_RIGHT 1 ++#define STEAM_PAD_BOTH 2 ++ + /* Other random constants */ + #define STEAM_SERIAL_LEN 10 + +@@ -291,6 +296,9 @@ struct steam_device { + struct power_supply __rcu *battery; + u8 battery_charge; + u16 voltage; ++ struct delayed_work mode_switch; ++ bool did_mode_switch; ++ bool gamepad_mode; + struct work_struct rumble_work; + u16 rumble_left; + u16 rumble_right; +@@ -459,6 +467,37 @@ static inline int steam_request_conn_status(struct steam_device *steam) + return ret; + } + ++/* ++ * Send a haptic pulse to the trackpads ++ * Duration and interval are measured in microseconds, count is the number ++ * of pulses to send for duration time with interval microseconds between them ++ * and gain is measured in decibels, ranging from -24 to +6 ++ */ ++static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad, ++ u16 duration, u16 interval, u16 count, u8 gain) ++{ ++ int ret; ++ u8 report[10] = {ID_TRIGGER_HAPTIC_PULSE, 8}; ++ ++ /* Left and right are swapped on this report for legacy reasons */ ++ if (pad < STEAM_PAD_BOTH) ++ pad ^= 1; ++ ++ report[2] = pad; ++ report[3] = duration & 0xFF; ++ report[4] = duration >> 8; ++ report[5] = interval & 0xFF; ++ report[6] = interval >> 8; ++ report[7] = count & 0xFF; ++ report[8] = count >> 8; ++ report[9] = gain; ++ ++ mutex_lock(&steam->report_mutex); ++ ret = steam_send_report(steam, report, sizeof(report)); ++ mutex_unlock(&steam->report_mutex); ++ return ret; ++} ++ + static inline int steam_haptic_rumble(struct steam_device *steam, + u16 intensity, u16 left_speed, u16 right_speed, + u8 left_gain, u8 right_gain) +@@ -504,6 +543,9 @@ static int steam_play_effect(struct input_dev *dev, void *data, + + static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + { ++ if (steam->gamepad_mode) ++ enable = false; ++ + if (enable) { + mutex_lock(&steam->report_mutex); + /* enable esc, enter, cursors */ +@@ -541,11 +583,18 @@ static int steam_input_open(struct input_dev *dev) + unsigned long flags; + bool set_lizard_mode; + +- spin_lock_irqsave(&steam->lock, flags); +- set_lizard_mode = !steam->client_opened && lizard_mode; +- spin_unlock_irqrestore(&steam->lock, flags); +- if (set_lizard_mode) +- steam_set_lizard_mode(steam, false); ++ /* ++ * Disabling lizard mode automatically is only done on the Steam ++ * Controller. On the Steam Deck, this is toggled manually by holding ++ * the options button instead, handled by steam_mode_switch_cb. ++ */ ++ if (!(steam->quirks & STEAM_QUIRK_DECK)) { ++ spin_lock_irqsave(&steam->lock, flags); ++ set_lizard_mode = !steam->client_opened && lizard_mode; ++ spin_unlock_irqrestore(&steam->lock, flags); ++ if (set_lizard_mode) ++ steam_set_lizard_mode(steam, false); ++ } + + return 0; + } +@@ -556,11 +605,13 @@ static void steam_input_close(struct input_dev *dev) + unsigned long flags; + bool set_lizard_mode; + +- spin_lock_irqsave(&steam->lock, flags); +- set_lizard_mode = !steam->client_opened && lizard_mode; +- spin_unlock_irqrestore(&steam->lock, flags); +- if (set_lizard_mode) +- steam_set_lizard_mode(steam, true); ++ if (!(steam->quirks & STEAM_QUIRK_DECK)) { ++ spin_lock_irqsave(&steam->lock, flags); ++ set_lizard_mode = !steam->client_opened && lizard_mode; ++ spin_unlock_irqrestore(&steam->lock, flags); ++ if (set_lizard_mode) ++ steam_set_lizard_mode(steam, true); ++ } + } + + static enum power_supply_property steam_battery_props[] = { +@@ -885,6 +936,34 @@ static void steam_work_connect_cb(struct work_struct *work) + } + } + ++static void steam_mode_switch_cb(struct work_struct *work) ++{ ++ struct steam_device *steam = container_of(to_delayed_work(work), ++ struct steam_device, mode_switch); ++ unsigned long flags; ++ bool client_opened; ++ steam->gamepad_mode = !steam->gamepad_mode; ++ if (!lizard_mode) ++ return; ++ ++ if (steam->gamepad_mode) ++ steam_set_lizard_mode(steam, false); ++ else { ++ spin_lock_irqsave(&steam->lock, flags); ++ client_opened = steam->client_opened; ++ spin_unlock_irqrestore(&steam->lock, flags); ++ if (!client_opened) ++ steam_set_lizard_mode(steam, lizard_mode); ++ } ++ ++ steam_haptic_pulse(steam, STEAM_PAD_RIGHT, 0x190, 0, 1, 0); ++ if (steam->gamepad_mode) { ++ steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x14D, 0x14D, 0x2D, 0); ++ } else { ++ steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x1F4, 0x1F4, 0x1E, 0); ++ } ++} ++ + static bool steam_is_valve_interface(struct hid_device *hdev) + { + struct hid_report_enum *rep_enum; +@@ -1039,6 +1118,7 @@ static int steam_probe(struct hid_device *hdev, + mutex_init(&steam->report_mutex); + steam->quirks = id->driver_data; + INIT_WORK(&steam->work_connect, steam_work_connect_cb); ++ INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb); + INIT_LIST_HEAD(&steam->list); + INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); + +@@ -1096,6 +1176,7 @@ static int steam_probe(struct hid_device *hdev, + hid_hw_open_fail: + hid_hw_start_fail: + cancel_work_sync(&steam->work_connect); ++ cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->rumble_work); + steam_alloc_fail: + hid_err(hdev, "%s: failed with error %d\n", +@@ -1112,6 +1193,7 @@ static void steam_remove(struct hid_device *hdev) + return; + } + ++ cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->work_connect); + hid_destroy_device(steam->client_hdev); + steam->client_hdev = NULL; +@@ -1397,6 +1479,17 @@ static void steam_do_deck_input_event(struct steam_device *steam, + b13 = data[13]; + b14 = data[14]; + ++ if (!(b9 & BIT(6)) && steam->did_mode_switch) { ++ steam->did_mode_switch = false; ++ cancel_delayed_work_sync(&steam->mode_switch); ++ } else if (!steam->client_opened && (b9 & BIT(6)) && !steam->did_mode_switch) { ++ steam->did_mode_switch = true; ++ schedule_delayed_work(&steam->mode_switch, 45 * HZ / 100); ++ } ++ ++ if (!steam->gamepad_mode) ++ return; ++ + lpad_touched = b10 & BIT(3); + rpad_touched = b10 & BIT(4); + +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-avoid-overwriting-smoothing-parameter.patch b/queue-6.6/hid-hid-steam-avoid-overwriting-smoothing-parameter.patch new file mode 100644 index 0000000000..c49d64feff --- /dev/null +++ b/queue-6.6/hid-hid-steam-avoid-overwriting-smoothing-parameter.patch @@ -0,0 +1,55 @@ +From 0f8400facd03cd52f854dec6f79173f69876931d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 19:38:31 -0800 +Subject: HID: hid-steam: Avoid overwriting smoothing parameter + +From: Vicki Pfau + +[ Upstream commit 34281b4d916f167a6f77975380e1df07f06248b7 ] + +The original implementation of this driver incorrectly guessed the function of +this register. It's not only unnecessary to write to this register for lizard +mode but actually counter-productive since it overwrites whatever previous +value was intentionally set, for example by Steam. + +Signed-off-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index b110818fc9458..7aefd52e945a1 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -340,9 +340,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS); + /* enable mouse */ + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE); +- steam_write_registers(steam, +- STEAM_REG_RPAD_MARGIN, 0x01, /* enable margin */ +- 0); + + cancel_delayed_work_sync(&steam->heartbeat); + } else { +@@ -351,7 +348,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + + if (steam->quirks & STEAM_QUIRK_DECK) { + steam_write_registers(steam, +- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */ + STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ + STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ + STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ +@@ -365,7 +361,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + schedule_delayed_work(&steam->heartbeat, 5 * HZ); + } else { + steam_write_registers(steam, +- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */ + STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ + STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ + 0); +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-clean-up-locking.patch b/queue-6.6/hid-hid-steam-clean-up-locking.patch new file mode 100644 index 0000000000..5d3acd592e --- /dev/null +++ b/queue-6.6/hid-hid-steam-clean-up-locking.patch @@ -0,0 +1,334 @@ +From ef363458e9ac38c1019db4749f54cb142646cb16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 19:38:33 -0800 +Subject: HID: hid-steam: Clean up locking + +From: Vicki Pfau + +[ Upstream commit 691ead124a0c35e56633dbb73e43711ff3db23ef ] + +This cleans up the locking logic so that the spinlock is consistently used for +access to a small handful of struct variables, and the mutex is exclusively and +consistently used for ensuring that mutliple threads aren't trying to +send/receive reports at the same time. Previously, only some report +transactions were guarded by this mutex, potentially breaking atomicity. The +mutex has been renamed to reflect this usage. + +Signed-off-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 122 +++++++++++++++++++++++----------------- + 1 file changed, 69 insertions(+), 53 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index efd297e0ea8c2..57cb58941c9fc 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -124,7 +124,7 @@ struct steam_device { + struct list_head list; + spinlock_t lock; + struct hid_device *hdev, *client_hdev; +- struct mutex mutex; ++ struct mutex report_mutex; + bool client_opened; + struct input_dev __rcu *input; + unsigned long quirks; +@@ -267,21 +267,26 @@ static int steam_get_serial(struct steam_device *steam) + * Send: 0xae 0x15 0x01 + * Recv: 0xae 0x15 0x01 serialnumber (10 chars) + */ +- int ret; ++ int ret = 0; + u8 cmd[] = {STEAM_CMD_GET_SERIAL, 0x15, 0x01}; + u8 reply[3 + STEAM_SERIAL_LEN + 1]; + ++ mutex_lock(&steam->report_mutex); + ret = steam_send_report(steam, cmd, sizeof(cmd)); + if (ret < 0) +- return ret; ++ goto out; + ret = steam_recv_report(steam, reply, sizeof(reply)); + if (ret < 0) +- return ret; +- if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01) +- return -EIO; ++ goto out; ++ if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01) { ++ ret = -EIO; ++ goto out; ++ } + reply[3 + STEAM_SERIAL_LEN] = 0; + strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no)); +- return 0; ++out: ++ mutex_unlock(&steam->report_mutex); ++ return ret; + } + + /* +@@ -291,13 +296,18 @@ static int steam_get_serial(struct steam_device *steam) + */ + static inline int steam_request_conn_status(struct steam_device *steam) + { +- return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS); ++ int ret; ++ mutex_lock(&steam->report_mutex); ++ ret = steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS); ++ mutex_unlock(&steam->report_mutex); ++ return ret; + } + + static inline int steam_haptic_rumble(struct steam_device *steam, + u16 intensity, u16 left_speed, u16 right_speed, + u8 left_gain, u8 right_gain) + { ++ int ret; + u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9}; + + report[3] = intensity & 0xFF; +@@ -309,7 +319,10 @@ static inline int steam_haptic_rumble(struct steam_device *steam, + report[9] = left_gain; + report[10] = right_gain; + +- return steam_send_report(steam, report, sizeof(report)); ++ mutex_lock(&steam->report_mutex); ++ ret = steam_send_report(steam, report, sizeof(report)); ++ mutex_unlock(&steam->report_mutex); ++ return ret; + } + + static void steam_haptic_rumble_cb(struct work_struct *work) +@@ -336,11 +349,14 @@ static int steam_play_effect(struct input_dev *dev, void *data, + static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + { + if (enable) { ++ mutex_lock(&steam->report_mutex); + /* enable esc, enter, cursors */ + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS); + /* enable mouse */ + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE); ++ mutex_unlock(&steam->report_mutex); + } else { ++ mutex_lock(&steam->report_mutex); + /* disable esc, enter, cursor */ + steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); + +@@ -352,11 +368,13 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ + STEAM_REG_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */ + 0); ++ mutex_unlock(&steam->report_mutex); + } else { + steam_write_registers(steam, + STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ + STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ + 0); ++ mutex_unlock(&steam->report_mutex); + } + } + } +@@ -364,22 +382,29 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + static int steam_input_open(struct input_dev *dev) + { + struct steam_device *steam = input_get_drvdata(dev); ++ unsigned long flags; ++ bool set_lizard_mode; + +- mutex_lock(&steam->mutex); +- if (!steam->client_opened && lizard_mode) ++ spin_lock_irqsave(&steam->lock, flags); ++ set_lizard_mode = !steam->client_opened && lizard_mode; ++ spin_unlock_irqrestore(&steam->lock, flags); ++ if (set_lizard_mode) + steam_set_lizard_mode(steam, false); +- mutex_unlock(&steam->mutex); ++ + return 0; + } + + static void steam_input_close(struct input_dev *dev) + { + struct steam_device *steam = input_get_drvdata(dev); ++ unsigned long flags; ++ bool set_lizard_mode; + +- mutex_lock(&steam->mutex); +- if (!steam->client_opened && lizard_mode) ++ spin_lock_irqsave(&steam->lock, flags); ++ set_lizard_mode = !steam->client_opened && lizard_mode; ++ spin_unlock_irqrestore(&steam->lock, flags); ++ if (set_lizard_mode) + steam_set_lizard_mode(steam, true); +- mutex_unlock(&steam->mutex); + } + + static enum power_supply_property steam_battery_props[] = { +@@ -624,6 +649,7 @@ static int steam_register(struct steam_device *steam) + { + int ret; + bool client_opened; ++ unsigned long flags; + + /* + * This function can be called several times in a row with the +@@ -636,11 +662,9 @@ static int steam_register(struct steam_device *steam) + * Unlikely, but getting the serial could fail, and it is not so + * important, so make up a serial number and go on. + */ +- mutex_lock(&steam->mutex); + if (steam_get_serial(steam) < 0) + strscpy(steam->serial_no, "XXXXXXXXXX", + sizeof(steam->serial_no)); +- mutex_unlock(&steam->mutex); + + hid_info(steam->hdev, "Steam Controller '%s' connected", + steam->serial_no); +@@ -655,15 +679,13 @@ static int steam_register(struct steam_device *steam) + mutex_unlock(&steam_devices_lock); + } + +- mutex_lock(&steam->mutex); ++ spin_lock_irqsave(&steam->lock, flags); + client_opened = steam->client_opened; +- if (!client_opened) ++ spin_unlock_irqrestore(&steam->lock, flags); ++ if (!client_opened) { + steam_set_lizard_mode(steam, lizard_mode); +- mutex_unlock(&steam->mutex); +- +- if (!client_opened) + ret = steam_input_register(steam); +- else ++ } else + ret = 0; + + return ret; +@@ -746,10 +768,11 @@ static void steam_client_ll_stop(struct hid_device *hdev) + static int steam_client_ll_open(struct hid_device *hdev) + { + struct steam_device *steam = hdev->driver_data; ++ unsigned long flags; + +- mutex_lock(&steam->mutex); ++ spin_lock_irqsave(&steam->lock, flags); + steam->client_opened = true; +- mutex_unlock(&steam->mutex); ++ spin_unlock_irqrestore(&steam->lock, flags); + + steam_input_unregister(steam); + +@@ -764,17 +787,14 @@ static void steam_client_ll_close(struct hid_device *hdev) + bool connected; + + spin_lock_irqsave(&steam->lock, flags); +- connected = steam->connected; ++ steam->client_opened = false; ++ connected = steam->connected && !steam->client_opened; + spin_unlock_irqrestore(&steam->lock, flags); + +- mutex_lock(&steam->mutex); +- steam->client_opened = false; +- if (connected) ++ if (connected) { + steam_set_lizard_mode(steam, lizard_mode); +- mutex_unlock(&steam->mutex); +- +- if (connected) + steam_input_register(steam); ++ } + } + + static int steam_client_ll_raw_request(struct hid_device *hdev, +@@ -860,19 +880,12 @@ static int steam_probe(struct hid_device *hdev, + steam->hdev = hdev; + hid_set_drvdata(hdev, steam); + spin_lock_init(&steam->lock); +- mutex_init(&steam->mutex); ++ mutex_init(&steam->report_mutex); + steam->quirks = id->driver_data; + INIT_WORK(&steam->work_connect, steam_work_connect_cb); + INIT_LIST_HEAD(&steam->list); + INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); + +- steam->client_hdev = steam_create_client_hid(hdev); +- if (IS_ERR(steam->client_hdev)) { +- ret = PTR_ERR(steam->client_hdev); +- goto client_hdev_fail; +- } +- steam->client_hdev->driver_data = steam; +- + /* + * With the real steam controller interface, do not connect hidraw. + * Instead, create the client_hid and connect that. +@@ -881,10 +894,6 @@ static int steam_probe(struct hid_device *hdev, + if (ret) + goto hid_hw_start_fail; + +- ret = hid_add_device(steam->client_hdev); +- if (ret) +- goto client_hdev_add_fail; +- + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, +@@ -910,15 +919,26 @@ static int steam_probe(struct hid_device *hdev, + } + } + ++ steam->client_hdev = steam_create_client_hid(hdev); ++ if (IS_ERR(steam->client_hdev)) { ++ ret = PTR_ERR(steam->client_hdev); ++ goto client_hdev_fail; ++ } ++ steam->client_hdev->driver_data = steam; ++ ++ ret = hid_add_device(steam->client_hdev); ++ if (ret) ++ goto client_hdev_add_fail; ++ + return 0; + +-input_register_fail: +-hid_hw_open_fail: + client_hdev_add_fail: + hid_hw_stop(hdev); +-hid_hw_start_fail: +- hid_destroy_device(steam->client_hdev); + client_hdev_fail: ++ hid_destroy_device(steam->client_hdev); ++input_register_fail: ++hid_hw_open_fail: ++hid_hw_start_fail: + cancel_work_sync(&steam->work_connect); + cancel_work_sync(&steam->rumble_work); + steam_alloc_fail: +@@ -936,12 +956,10 @@ static void steam_remove(struct hid_device *hdev) + return; + } + ++ cancel_work_sync(&steam->work_connect); + hid_destroy_device(steam->client_hdev); +- mutex_lock(&steam->mutex); + steam->client_hdev = NULL; + steam->client_opened = false; +- mutex_unlock(&steam->mutex); +- cancel_work_sync(&steam->work_connect); + if (steam->quirks & STEAM_QUIRK_WIRELESS) { + hid_info(hdev, "Steam wireless receiver disconnected"); + } +@@ -1408,10 +1426,8 @@ static int steam_param_set_lizard_mode(const char *val, + + mutex_lock(&steam_devices_lock); + list_for_each_entry(steam, &steam_devices, list) { +- mutex_lock(&steam->mutex); + if (!steam->client_opened) + steam_set_lizard_mode(steam, lizard_mode); +- mutex_unlock(&steam->mutex); + } + mutex_unlock(&steam_devices_lock); + return 0; +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-disable-watchdog-instead-of-using-a-he.patch b/queue-6.6/hid-hid-steam-disable-watchdog-instead-of-using-a-he.patch new file mode 100644 index 0000000000..162b092aec --- /dev/null +++ b/queue-6.6/hid-hid-steam-disable-watchdog-instead-of-using-a-he.patch @@ -0,0 +1,114 @@ +From 6d2bc1a78f46ebade44c91cbe6652762bb876f68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 19:38:32 -0800 +Subject: HID: hid-steam: Disable watchdog instead of using a heartbeat + +From: Vicki Pfau + +[ Upstream commit 917972636e8271c5691710ce5dcd66c2d3bd04f2 ] + +The Steam Deck has a setting that controls whether or not the watchdog is +enabled, so instead of using a heartbeat to keep the watchdog from triggering, +this commit changes the behavior to simply disable the watchdog instead. + +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 30 ++---------------------------- + 1 file changed, 2 insertions(+), 28 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 7aefd52e945a1..efd297e0ea8c2 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -101,6 +101,7 @@ static LIST_HEAD(steam_devices); + #define STEAM_REG_GYRO_MODE 0x30 + #define STEAM_REG_LPAD_CLICK_PRESSURE 0x34 + #define STEAM_REG_RPAD_CLICK_PRESSURE 0x35 ++#define STEAM_REG_WATCHDOG_ENABLE 0x47 + + /* Raw event identifiers */ + #define STEAM_EV_INPUT_DATA 0x01 +@@ -134,7 +135,6 @@ struct steam_device { + struct power_supply __rcu *battery; + u8 battery_charge; + u16 voltage; +- struct delayed_work heartbeat; + struct work_struct rumble_work; + u16 rumble_left; + u16 rumble_right; +@@ -340,8 +340,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS); + /* enable mouse */ + steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE); +- +- cancel_delayed_work_sync(&steam->heartbeat); + } else { + /* disable esc, enter, cursor */ + steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); +@@ -352,13 +350,8 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ + STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ + STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ ++ STEAM_REG_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */ + 0); +- /* +- * The Steam Deck has a watchdog that automatically enables +- * lizard mode if it doesn't see any traffic for too long +- */ +- if (!work_busy(&steam->heartbeat.work)) +- schedule_delayed_work(&steam->heartbeat, 5 * HZ); + } else { + steam_write_registers(steam, + STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ +@@ -733,22 +726,6 @@ static bool steam_is_valve_interface(struct hid_device *hdev) + return !list_empty(&rep_enum->report_list); + } + +-static void steam_lizard_mode_heartbeat(struct work_struct *work) +-{ +- struct steam_device *steam = container_of(work, struct steam_device, +- heartbeat.work); +- +- mutex_lock(&steam->mutex); +- if (!steam->client_opened && steam->client_hdev) { +- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); +- steam_write_registers(steam, +- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ +- 0); +- schedule_delayed_work(&steam->heartbeat, 5 * HZ); +- } +- mutex_unlock(&steam->mutex); +-} +- + static int steam_client_ll_parse(struct hid_device *hdev) + { + struct steam_device *steam = hdev->driver_data; +@@ -887,7 +864,6 @@ static int steam_probe(struct hid_device *hdev, + steam->quirks = id->driver_data; + INIT_WORK(&steam->work_connect, steam_work_connect_cb); + INIT_LIST_HEAD(&steam->list); +- INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat); + INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); + + steam->client_hdev = steam_create_client_hid(hdev); +@@ -944,7 +920,6 @@ static int steam_probe(struct hid_device *hdev, + hid_destroy_device(steam->client_hdev); + client_hdev_fail: + cancel_work_sync(&steam->work_connect); +- cancel_delayed_work_sync(&steam->heartbeat); + cancel_work_sync(&steam->rumble_work); + steam_alloc_fail: + hid_err(hdev, "%s: failed with error %d\n", +@@ -965,7 +940,6 @@ static void steam_remove(struct hid_device *hdev) + mutex_lock(&steam->mutex); + steam->client_hdev = NULL; + steam->client_opened = false; +- cancel_delayed_work_sync(&steam->heartbeat); + mutex_unlock(&steam->mutex); + cancel_work_sync(&steam->work_connect); + if (steam->quirks & STEAM_QUIRK_WIRELESS) { +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-fix-cleanup-in-probe.patch b/queue-6.6/hid-hid-steam-fix-cleanup-in-probe.patch new file mode 100644 index 0000000000..67a82699a6 --- /dev/null +++ b/queue-6.6/hid-hid-steam-fix-cleanup-in-probe.patch @@ -0,0 +1,99 @@ +From e0d238c36b7994c94fcf698c471e21babf731599 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jan 2024 17:35:06 +0300 +Subject: HID: hid-steam: Fix cleanup in probe() + +From: Dan Carpenter + +[ Upstream commit a9f1da09c69f13ef471db8b22107a28042d230ca ] + +There are a number of issues in this code. First of all if +steam_create_client_hid() fails then it leads to an error pointer +dereference when we call hid_destroy_device(steam->client_hdev). + +Also there are a number of leaks. hid_hw_stop() is not called if +hid_hw_open() fails for example. And it doesn't call steam_unregister() +or hid_hw_close(). + +Fixes: 691ead124a0c ("HID: hid-steam: Clean up locking") +Signed-off-by: Dan Carpenter +Reviewed-by: Vicki Pfau +Link: https://lore.kernel.org/r/1fd87904-dabf-4879-bb89-72d13ebfc91e@moroto.mountain +Signed-off-by: Benjamin Tissoires +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 2f11f77ae2153..59b46163bc526 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -1127,14 +1127,14 @@ static int steam_probe(struct hid_device *hdev, + */ + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW); + if (ret) +- goto hid_hw_start_fail; ++ goto err_cancel_work; + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, + "%s:hid_hw_open\n", + __func__); +- goto hid_hw_open_fail; ++ goto err_hw_stop; + } + + if (steam->quirks & STEAM_QUIRK_WIRELESS) { +@@ -1150,33 +1150,37 @@ static int steam_probe(struct hid_device *hdev, + hid_err(hdev, + "%s:steam_register failed with error %d\n", + __func__, ret); +- goto input_register_fail; ++ goto err_hw_close; + } + } + + steam->client_hdev = steam_create_client_hid(hdev); + if (IS_ERR(steam->client_hdev)) { + ret = PTR_ERR(steam->client_hdev); +- goto client_hdev_fail; ++ goto err_stream_unregister; + } + steam->client_hdev->driver_data = steam; + + ret = hid_add_device(steam->client_hdev); + if (ret) +- goto client_hdev_add_fail; ++ goto err_destroy; + + return 0; + +-client_hdev_add_fail: +- hid_hw_stop(hdev); +-client_hdev_fail: ++err_destroy: + hid_destroy_device(steam->client_hdev); +-input_register_fail: +-hid_hw_open_fail: +-hid_hw_start_fail: ++err_stream_unregister: ++ if (steam->connected) ++ steam_unregister(steam); ++err_hw_close: ++ hid_hw_close(hdev); ++err_hw_stop: ++ hid_hw_stop(hdev); ++err_cancel_work: + cancel_work_sync(&steam->work_connect); + cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->rumble_work); ++ + return ret; + } + +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-make-sure-rumble-work-is-canceled-on-r.patch b/queue-6.6/hid-hid-steam-make-sure-rumble-work-is-canceled-on-r.patch new file mode 100644 index 0000000000..f1fa9bdbef --- /dev/null +++ b/queue-6.6/hid-hid-steam-make-sure-rumble-work-is-canceled-on-r.patch @@ -0,0 +1,38 @@ +From 47e14b4af54f700a9b0a0bf11817d43f1857db0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Dec 2024 18:34:24 -0800 +Subject: HID: hid-steam: Make sure rumble work is canceled on removal + +From: Vicki Pfau + +[ Upstream commit cc4f952427aaa44ecfd92542e10a65cce67bd6f4 ] + +When a force feedback command is sent from userspace, work is scheduled to pass +this data to the controller without blocking userspace itself. However, in +theory, this work might not be properly canceled if the controller is removed +at the exact right time. This patch ensures the work is properly canceled when +the device is removed. + +Signed-off-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 29a0e1f395339..a25d0034dc1ea 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -1304,6 +1304,7 @@ static void steam_remove(struct hid_device *hdev) + + cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->work_connect); ++ cancel_work_sync(&steam->rumble_work); + hid_destroy_device(steam->client_hdev); + steam->client_hdev = NULL; + steam->client_opened = false; +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-move-hidraw-input-un-registering-to-wo.patch b/queue-6.6/hid-hid-steam-move-hidraw-input-un-registering-to-wo.patch new file mode 100644 index 0000000000..590e89ff77 --- /dev/null +++ b/queue-6.6/hid-hid-steam-move-hidraw-input-un-registering-to-wo.patch @@ -0,0 +1,117 @@ +From 9e2f8177b284e249ae0a53a5658c6e41bedb7d9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Feb 2025 19:55:27 -0800 +Subject: HID: hid-steam: Move hidraw input (un)registering to work + +From: Vicki Pfau + +[ Upstream commit 79504249d7e27cad4a3eeb9afc6386e418728ce0 ] + +Due to an interplay between locking in the input and hid transport subsystems, +attempting to register or deregister the relevant input devices during the +hidraw open/close events can lead to a lock ordering issue. Though this +shouldn't cause a deadlock, this commit moves the input device manipulation to +deferred work to sidestep the issue. + +Fixes: 385a4886778f6 ("HID: steam: remove input device when a hid client is running.") +Signed-off-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 38 +++++++++++++++++++++++++++++++------- + 1 file changed, 31 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index a25d0034dc1ea..ee3c27e133443 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -312,6 +312,7 @@ struct steam_device { + u16 rumble_left; + u16 rumble_right; + unsigned int sensor_timestamp_us; ++ struct work_struct unregister_work; + }; + + static int steam_recv_report(struct steam_device *steam, +@@ -1070,6 +1071,31 @@ static void steam_mode_switch_cb(struct work_struct *work) + } + } + ++static void steam_work_unregister_cb(struct work_struct *work) ++{ ++ struct steam_device *steam = container_of(work, struct steam_device, ++ unregister_work); ++ unsigned long flags; ++ bool connected; ++ bool opened; ++ ++ spin_lock_irqsave(&steam->lock, flags); ++ opened = steam->client_opened; ++ connected = steam->connected; ++ spin_unlock_irqrestore(&steam->lock, flags); ++ ++ if (connected) { ++ if (opened) { ++ steam_sensors_unregister(steam); ++ steam_input_unregister(steam); ++ } else { ++ steam_set_lizard_mode(steam, lizard_mode); ++ steam_input_register(steam); ++ steam_sensors_register(steam); ++ } ++ } ++} ++ + static bool steam_is_valve_interface(struct hid_device *hdev) + { + struct hid_report_enum *rep_enum; +@@ -1115,8 +1141,7 @@ static int steam_client_ll_open(struct hid_device *hdev) + steam->client_opened = true; + spin_unlock_irqrestore(&steam->lock, flags); + +- steam_sensors_unregister(steam); +- steam_input_unregister(steam); ++ schedule_work(&steam->unregister_work); + + return 0; + } +@@ -1133,11 +1158,7 @@ static void steam_client_ll_close(struct hid_device *hdev) + connected = steam->connected && !steam->client_opened; + spin_unlock_irqrestore(&steam->lock, flags); + +- if (connected) { +- steam_set_lizard_mode(steam, lizard_mode); +- steam_input_register(steam); +- steam_sensors_register(steam); +- } ++ schedule_work(&steam->unregister_work); + } + + static int steam_client_ll_raw_request(struct hid_device *hdev, +@@ -1229,6 +1250,7 @@ static int steam_probe(struct hid_device *hdev, + INIT_LIST_HEAD(&steam->list); + INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb); + steam->sensor_timestamp_us = 0; ++ INIT_WORK(&steam->unregister_work, steam_work_unregister_cb); + + /* + * With the real steam controller interface, do not connect hidraw. +@@ -1289,6 +1311,7 @@ static int steam_probe(struct hid_device *hdev, + cancel_work_sync(&steam->work_connect); + cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->rumble_work); ++ cancel_work_sync(&steam->unregister_work); + + return ret; + } +@@ -1305,6 +1328,7 @@ static void steam_remove(struct hid_device *hdev) + cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->work_connect); + cancel_work_sync(&steam->rumble_work); ++ cancel_work_sync(&steam->unregister_work); + hid_destroy_device(steam->client_hdev); + steam->client_hdev = NULL; + steam->client_opened = false; +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-remove-pointless-error-message.patch b/queue-6.6/hid-hid-steam-remove-pointless-error-message.patch new file mode 100644 index 0000000000..4ddfcdea56 --- /dev/null +++ b/queue-6.6/hid-hid-steam-remove-pointless-error-message.patch @@ -0,0 +1,55 @@ +From b89d1a0d7931a1018aee93f3306efe59242293ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jan 2024 17:34:14 +0300 +Subject: HID: hid-steam: remove pointless error message + +From: Dan Carpenter + +[ Upstream commit a9668169961106f3598384fe95004106ec191201 ] + +This error message doesn't really add any information. If modprobe +fails then the user will already know what the error code is. In the +case of kmalloc() it's a style violation to print an error message for +that because kmalloc has it's own better error messages built in. + +Signed-off-by: Dan Carpenter +Reviewed-by: Vicki Pfau +Link: https://lore.kernel.org/r/305898fb-6bd4-4749-806c-05ec51bbeb80@moroto.mountain +Signed-off-by: Benjamin Tissoires +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 10 +++------- + 1 file changed, 3 insertions(+), 7 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 2f87026f01de1..2f11f77ae2153 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -1108,10 +1108,9 @@ static int steam_probe(struct hid_device *hdev, + return hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + steam = devm_kzalloc(&hdev->dev, sizeof(*steam), GFP_KERNEL); +- if (!steam) { +- ret = -ENOMEM; +- goto steam_alloc_fail; +- } ++ if (!steam) ++ return -ENOMEM; ++ + steam->hdev = hdev; + hid_set_drvdata(hdev, steam); + spin_lock_init(&steam->lock); +@@ -1178,9 +1177,6 @@ static int steam_probe(struct hid_device *hdev, + cancel_work_sync(&steam->work_connect); + cancel_delayed_work_sync(&steam->mode_switch); + cancel_work_sync(&steam->rumble_work); +-steam_alloc_fail: +- hid_err(hdev, "%s: failed with error %d\n", +- __func__, ret); + return ret; + } + +-- +2.39.5 + diff --git a/queue-6.6/hid-hid-steam-update-list-of-identifiers-from-sdl.patch b/queue-6.6/hid-hid-steam-update-list-of-identifiers-from-sdl.patch new file mode 100644 index 0000000000..a7539b8ef8 --- /dev/null +++ b/queue-6.6/hid-hid-steam-update-list-of-identifiers-from-sdl.patch @@ -0,0 +1,410 @@ +From fe446bc089a6c7147b445f819cba6427d4f8a2fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Dec 2023 19:38:35 -0800 +Subject: HID: hid-steam: Update list of identifiers from SDL + +From: Vicki Pfau + +[ Upstream commit 4f9a5a9769cc77075e606537e15747e8b8e9c7c9 ] + +SDL includes a list of settings (formerly called registers in this driver), +reports (formerly cmds), and various other identifiers that were provided by +Valve. This commit imports a significant chunk of that list as well as +replacing most of the guessed names and a handful of magic constants. It also +replaces bitmask definitions that used hex with the BIT macro. + +Signed-off-by: Vicki Pfau +Signed-off-by: Jiri Kosina +Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work") +Signed-off-by: Sasha Levin +--- + drivers/hid/hid-steam.c | 286 +++++++++++++++++++++++++++++++--------- + 1 file changed, 221 insertions(+), 65 deletions(-) + +diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c +index 57cb58941c9fc..991db5acf5ddb 100644 +--- a/drivers/hid/hid-steam.c ++++ b/drivers/hid/hid-steam.c +@@ -71,51 +71,207 @@ static LIST_HEAD(steam_devices); + + /* + * Commands that can be sent in a feature report. +- * Thanks to Valve for some valuable hints. ++ * Thanks to Valve and SDL for the names. + */ +-#define STEAM_CMD_SET_MAPPINGS 0x80 +-#define STEAM_CMD_CLEAR_MAPPINGS 0x81 +-#define STEAM_CMD_GET_MAPPINGS 0x82 +-#define STEAM_CMD_GET_ATTRIB 0x83 +-#define STEAM_CMD_GET_ATTRIB_LABEL 0x84 +-#define STEAM_CMD_DEFAULT_MAPPINGS 0x85 +-#define STEAM_CMD_FACTORY_RESET 0x86 +-#define STEAM_CMD_WRITE_REGISTER 0x87 +-#define STEAM_CMD_CLEAR_REGISTER 0x88 +-#define STEAM_CMD_READ_REGISTER 0x89 +-#define STEAM_CMD_GET_REGISTER_LABEL 0x8a +-#define STEAM_CMD_GET_REGISTER_MAX 0x8b +-#define STEAM_CMD_GET_REGISTER_DEFAULT 0x8c +-#define STEAM_CMD_SET_MODE 0x8d +-#define STEAM_CMD_DEFAULT_MOUSE 0x8e +-#define STEAM_CMD_FORCEFEEDBAK 0x8f +-#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4 +-#define STEAM_CMD_GET_SERIAL 0xae +-#define STEAM_CMD_HAPTIC_RUMBLE 0xeb +- +-/* Some useful register ids */ +-#define STEAM_REG_LPAD_MODE 0x07 +-#define STEAM_REG_RPAD_MODE 0x08 +-#define STEAM_REG_RPAD_MARGIN 0x18 +-#define STEAM_REG_LED 0x2d +-#define STEAM_REG_GYRO_MODE 0x30 +-#define STEAM_REG_LPAD_CLICK_PRESSURE 0x34 +-#define STEAM_REG_RPAD_CLICK_PRESSURE 0x35 +-#define STEAM_REG_WATCHDOG_ENABLE 0x47 +- +-/* Raw event identifiers */ +-#define STEAM_EV_INPUT_DATA 0x01 +-#define STEAM_EV_CONNECT 0x03 +-#define STEAM_EV_BATTERY 0x04 +-#define STEAM_EV_DECK_INPUT_DATA 0x09 ++enum { ++ ID_SET_DIGITAL_MAPPINGS = 0x80, ++ ID_CLEAR_DIGITAL_MAPPINGS = 0x81, ++ ID_GET_DIGITAL_MAPPINGS = 0x82, ++ ID_GET_ATTRIBUTES_VALUES = 0x83, ++ ID_GET_ATTRIBUTE_LABEL = 0x84, ++ ID_SET_DEFAULT_DIGITAL_MAPPINGS = 0x85, ++ ID_FACTORY_RESET = 0x86, ++ ID_SET_SETTINGS_VALUES = 0x87, ++ ID_CLEAR_SETTINGS_VALUES = 0x88, ++ ID_GET_SETTINGS_VALUES = 0x89, ++ ID_GET_SETTING_LABEL = 0x8A, ++ ID_GET_SETTINGS_MAXS = 0x8B, ++ ID_GET_SETTINGS_DEFAULTS = 0x8C, ++ ID_SET_CONTROLLER_MODE = 0x8D, ++ ID_LOAD_DEFAULT_SETTINGS = 0x8E, ++ ID_TRIGGER_HAPTIC_PULSE = 0x8F, ++ ID_TURN_OFF_CONTROLLER = 0x9F, ++ ++ ID_GET_DEVICE_INFO = 0xA1, ++ ++ ID_CALIBRATE_TRACKPADS = 0xA7, ++ ID_RESERVED_0 = 0xA8, ++ ID_SET_SERIAL_NUMBER = 0xA9, ++ ID_GET_TRACKPAD_CALIBRATION = 0xAA, ++ ID_GET_TRACKPAD_FACTORY_CALIBRATION = 0xAB, ++ ID_GET_TRACKPAD_RAW_DATA = 0xAC, ++ ID_ENABLE_PAIRING = 0xAD, ++ ID_GET_STRING_ATTRIBUTE = 0xAE, ++ ID_RADIO_ERASE_RECORDS = 0xAF, ++ ID_RADIO_WRITE_RECORD = 0xB0, ++ ID_SET_DONGLE_SETTING = 0xB1, ++ ID_DONGLE_DISCONNECT_DEVICE = 0xB2, ++ ID_DONGLE_COMMIT_DEVICE = 0xB3, ++ ID_DONGLE_GET_WIRELESS_STATE = 0xB4, ++ ID_CALIBRATE_GYRO = 0xB5, ++ ID_PLAY_AUDIO = 0xB6, ++ ID_AUDIO_UPDATE_START = 0xB7, ++ ID_AUDIO_UPDATE_DATA = 0xB8, ++ ID_AUDIO_UPDATE_COMPLETE = 0xB9, ++ ID_GET_CHIPID = 0xBA, ++ ++ ID_CALIBRATE_JOYSTICK = 0xBF, ++ ID_CALIBRATE_ANALOG_TRIGGERS = 0xC0, ++ ID_SET_AUDIO_MAPPING = 0xC1, ++ ID_CHECK_GYRO_FW_LOAD = 0xC2, ++ ID_CALIBRATE_ANALOG = 0xC3, ++ ID_DONGLE_GET_CONNECTED_SLOTS = 0xC4, ++ ++ ID_RESET_IMU = 0xCE, ++ ++ ID_TRIGGER_HAPTIC_CMD = 0xEA, ++ ID_TRIGGER_RUMBLE_CMD = 0xEB, ++}; ++ ++/* Settings IDs */ ++enum { ++ /* 0 */ ++ SETTING_MOUSE_SENSITIVITY, ++ SETTING_MOUSE_ACCELERATION, ++ SETTING_TRACKBALL_ROTATION_ANGLE, ++ SETTING_HAPTIC_INTENSITY_UNUSED, ++ SETTING_LEFT_GAMEPAD_STICK_ENABLED, ++ SETTING_RIGHT_GAMEPAD_STICK_ENABLED, ++ SETTING_USB_DEBUG_MODE, ++ SETTING_LEFT_TRACKPAD_MODE, ++ SETTING_RIGHT_TRACKPAD_MODE, ++ SETTING_MOUSE_POINTER_ENABLED, ++ ++ /* 10 */ ++ SETTING_DPAD_DEADZONE, ++ SETTING_MINIMUM_MOMENTUM_VEL, ++ SETTING_MOMENTUM_DECAY_AMMOUNT, ++ SETTING_TRACKPAD_RELATIVE_MODE_TICKS_PER_PIXEL, ++ SETTING_HAPTIC_INCREMENT, ++ SETTING_DPAD_ANGLE_SIN, ++ SETTING_DPAD_ANGLE_COS, ++ SETTING_MOMENTUM_VERTICAL_DIVISOR, ++ SETTING_MOMENTUM_MAXIMUM_VELOCITY, ++ SETTING_TRACKPAD_Z_ON, ++ ++ /* 20 */ ++ SETTING_TRACKPAD_Z_OFF, ++ SETTING_SENSITIVY_SCALE_AMMOUNT, ++ SETTING_LEFT_TRACKPAD_SECONDARY_MODE, ++ SETTING_RIGHT_TRACKPAD_SECONDARY_MODE, ++ SETTING_SMOOTH_ABSOLUTE_MOUSE, ++ SETTING_STEAMBUTTON_POWEROFF_TIME, ++ SETTING_UNUSED_1, ++ SETTING_TRACKPAD_OUTER_RADIUS, ++ SETTING_TRACKPAD_Z_ON_LEFT, ++ SETTING_TRACKPAD_Z_OFF_LEFT, ++ ++ /* 30 */ ++ SETTING_TRACKPAD_OUTER_SPIN_VEL, ++ SETTING_TRACKPAD_OUTER_SPIN_RADIUS, ++ SETTING_TRACKPAD_OUTER_SPIN_HORIZONTAL_ONLY, ++ SETTING_TRACKPAD_RELATIVE_MODE_DEADZONE, ++ SETTING_TRACKPAD_RELATIVE_MODE_MAX_VEL, ++ SETTING_TRACKPAD_RELATIVE_MODE_INVERT_Y, ++ SETTING_TRACKPAD_DOUBLE_TAP_BEEP_ENABLED, ++ SETTING_TRACKPAD_DOUBLE_TAP_BEEP_PERIOD, ++ SETTING_TRACKPAD_DOUBLE_TAP_BEEP_COUNT, ++ SETTING_TRACKPAD_OUTER_RADIUS_RELEASE_ON_TRANSITION, ++ ++ /* 40 */ ++ SETTING_RADIAL_MODE_ANGLE, ++ SETTING_HAPTIC_INTENSITY_MOUSE_MODE, ++ SETTING_LEFT_DPAD_REQUIRES_CLICK, ++ SETTING_RIGHT_DPAD_REQUIRES_CLICK, ++ SETTING_LED_BASELINE_BRIGHTNESS, ++ SETTING_LED_USER_BRIGHTNESS, ++ SETTING_ENABLE_RAW_JOYSTICK, ++ SETTING_ENABLE_FAST_SCAN, ++ SETTING_IMU_MODE, ++ SETTING_WIRELESS_PACKET_VERSION, ++ ++ /* 50 */ ++ SETTING_SLEEP_INACTIVITY_TIMEOUT, ++ SETTING_TRACKPAD_NOISE_THRESHOLD, ++ SETTING_LEFT_TRACKPAD_CLICK_PRESSURE, ++ SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE, ++ SETTING_LEFT_BUMPER_CLICK_PRESSURE, ++ SETTING_RIGHT_BUMPER_CLICK_PRESSURE, ++ SETTING_LEFT_GRIP_CLICK_PRESSURE, ++ SETTING_RIGHT_GRIP_CLICK_PRESSURE, ++ SETTING_LEFT_GRIP2_CLICK_PRESSURE, ++ SETTING_RIGHT_GRIP2_CLICK_PRESSURE, ++ ++ /* 60 */ ++ SETTING_PRESSURE_MODE, ++ SETTING_CONTROLLER_TEST_MODE, ++ SETTING_TRIGGER_MODE, ++ SETTING_TRACKPAD_Z_THRESHOLD, ++ SETTING_FRAME_RATE, ++ SETTING_TRACKPAD_FILT_CTRL, ++ SETTING_TRACKPAD_CLIP, ++ SETTING_DEBUG_OUTPUT_SELECT, ++ SETTING_TRIGGER_THRESHOLD_PERCENT, ++ SETTING_TRACKPAD_FREQUENCY_HOPPING, ++ ++ /* 70 */ ++ SETTING_HAPTICS_ENABLED, ++ SETTING_STEAM_WATCHDOG_ENABLE, ++ SETTING_TIMP_TOUCH_THRESHOLD_ON, ++ SETTING_TIMP_TOUCH_THRESHOLD_OFF, ++ SETTING_FREQ_HOPPING, ++ SETTING_TEST_CONTROL, ++ SETTING_HAPTIC_MASTER_GAIN_DB, ++ SETTING_THUMB_TOUCH_THRESH, ++ SETTING_DEVICE_POWER_STATUS, ++ SETTING_HAPTIC_INTENSITY, ++ ++ /* 80 */ ++ SETTING_STABILIZER_ENABLED, ++ SETTING_TIMP_MODE_MTE, ++}; ++ ++/* Input report identifiers */ ++enum ++{ ++ ID_CONTROLLER_STATE = 1, ++ ID_CONTROLLER_DEBUG = 2, ++ ID_CONTROLLER_WIRELESS = 3, ++ ID_CONTROLLER_STATUS = 4, ++ ID_CONTROLLER_DEBUG2 = 5, ++ ID_CONTROLLER_SECONDARY_STATE = 6, ++ ID_CONTROLLER_BLE_STATE = 7, ++ ID_CONTROLLER_DECK_STATE = 9 ++}; ++ ++/* String attribute idenitifiers */ ++enum { ++ ATTRIB_STR_BOARD_SERIAL, ++ ATTRIB_STR_UNIT_SERIAL, ++}; + + /* Values for GYRO_MODE (bitmask) */ +-#define STEAM_GYRO_MODE_OFF 0x0000 +-#define STEAM_GYRO_MODE_STEERING 0x0001 +-#define STEAM_GYRO_MODE_TILT 0x0002 +-#define STEAM_GYRO_MODE_SEND_ORIENTATION 0x0004 +-#define STEAM_GYRO_MODE_SEND_RAW_ACCEL 0x0008 +-#define STEAM_GYRO_MODE_SEND_RAW_GYRO 0x0010 ++enum { ++ SETTING_GYRO_MODE_OFF = 0, ++ SETTING_GYRO_MODE_STEERING = BIT(0), ++ SETTING_GYRO_MODE_TILT = BIT(1), ++ SETTING_GYRO_MODE_SEND_ORIENTATION = BIT(2), ++ SETTING_GYRO_MODE_SEND_RAW_ACCEL = BIT(3), ++ SETTING_GYRO_MODE_SEND_RAW_GYRO = BIT(4), ++}; ++ ++/* Trackpad modes */ ++enum { ++ TRACKPAD_ABSOLUTE_MOUSE, ++ TRACKPAD_RELATIVE_MOUSE, ++ TRACKPAD_DPAD_FOUR_WAY_DISCRETE, ++ TRACKPAD_DPAD_FOUR_WAY_OVERLAP, ++ TRACKPAD_DPAD_EIGHT_WAY, ++ TRACKPAD_RADIAL_MODE, ++ TRACKPAD_ABSOLUTE_DPAD, ++ TRACKPAD_NONE, ++ TRACKPAD_GESTURE_KEYBOARD, ++}; + + /* Other random constants */ + #define STEAM_SERIAL_LEN 10 +@@ -226,13 +382,13 @@ static inline int steam_send_report_byte(struct steam_device *steam, u8 cmd) + return steam_send_report(steam, &cmd, 1); + } + +-static int steam_write_registers(struct steam_device *steam, ++static int steam_write_settings(struct steam_device *steam, + /* u8 reg, u16 val */...) + { + /* Send: 0x87 len (reg valLo valHi)* */ + u8 reg; + u16 val; +- u8 cmd[64] = {STEAM_CMD_WRITE_REGISTER, 0x00}; ++ u8 cmd[64] = {ID_SET_SETTINGS_VALUES, 0x00}; + int ret; + va_list args; + +@@ -268,7 +424,7 @@ static int steam_get_serial(struct steam_device *steam) + * Recv: 0xae 0x15 0x01 serialnumber (10 chars) + */ + int ret = 0; +- u8 cmd[] = {STEAM_CMD_GET_SERIAL, 0x15, 0x01}; ++ u8 cmd[] = {ID_GET_STRING_ATTRIBUTE, 0x15, ATTRIB_STR_UNIT_SERIAL}; + u8 reply[3 + STEAM_SERIAL_LEN + 1]; + + mutex_lock(&steam->report_mutex); +@@ -278,7 +434,7 @@ static int steam_get_serial(struct steam_device *steam) + ret = steam_recv_report(steam, reply, sizeof(reply)); + if (ret < 0) + goto out; +- if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01) { ++ if (reply[0] != ID_GET_STRING_ATTRIBUTE || reply[1] != 0x15 || reply[2] != ATTRIB_STR_UNIT_SERIAL) { + ret = -EIO; + goto out; + } +@@ -298,7 +454,7 @@ static inline int steam_request_conn_status(struct steam_device *steam) + { + int ret; + mutex_lock(&steam->report_mutex); +- ret = steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS); ++ ret = steam_send_report_byte(steam, ID_DONGLE_GET_WIRELESS_STATE); + mutex_unlock(&steam->report_mutex); + return ret; + } +@@ -308,7 +464,7 @@ static inline int steam_haptic_rumble(struct steam_device *steam, + u8 left_gain, u8 right_gain) + { + int ret; +- u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9}; ++ u8 report[11] = {ID_TRIGGER_RUMBLE_CMD, 9}; + + report[3] = intensity & 0xFF; + report[4] = intensity >> 8; +@@ -351,28 +507,28 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) + if (enable) { + mutex_lock(&steam->report_mutex); + /* enable esc, enter, cursors */ +- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS); +- /* enable mouse */ +- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE); ++ steam_send_report_byte(steam, ID_SET_DEFAULT_DIGITAL_MAPPINGS); ++ /* reset settings */ ++ steam_send_report_byte(steam, ID_LOAD_DEFAULT_SETTINGS); + mutex_unlock(&steam->report_mutex); + } else { + mutex_lock(&steam->report_mutex); + /* disable esc, enter, cursor */ +- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS); ++ steam_send_report_byte(steam, ID_CLEAR_DIGITAL_MAPPINGS); + + if (steam->quirks & STEAM_QUIRK_DECK) { +- steam_write_registers(steam, +- STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ +- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ +- STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ +- STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */ +- STEAM_REG_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */ ++ steam_write_settings(steam, ++ SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ ++ SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ ++ SETTING_LEFT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */ ++ SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */ ++ SETTING_STEAM_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */ + 0); + mutex_unlock(&steam->report_mutex); + } else { +- steam_write_registers(steam, +- STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */ +- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */ ++ steam_write_settings(steam, ++ SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ ++ SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */ + 0); + mutex_unlock(&steam->report_mutex); + } +@@ -1362,7 +1518,7 @@ static int steam_raw_event(struct hid_device *hdev, + return 0; + + switch (data[2]) { +- case STEAM_EV_INPUT_DATA: ++ case ID_CONTROLLER_STATE: + if (steam->client_opened) + return 0; + rcu_read_lock(); +@@ -1371,7 +1527,7 @@ static int steam_raw_event(struct hid_device *hdev, + steam_do_input_event(steam, input, data); + rcu_read_unlock(); + break; +- case STEAM_EV_DECK_INPUT_DATA: ++ case ID_CONTROLLER_DECK_STATE: + if (steam->client_opened) + return 0; + rcu_read_lock(); +@@ -1380,7 +1536,7 @@ static int steam_raw_event(struct hid_device *hdev, + steam_do_deck_input_event(steam, input, data); + rcu_read_unlock(); + break; +- case STEAM_EV_CONNECT: ++ case ID_CONTROLLER_WIRELESS: + /* + * The payload of this event is a single byte: + * 0x01: disconnected. +@@ -1395,7 +1551,7 @@ static int steam_raw_event(struct hid_device *hdev, + break; + } + break; +- case STEAM_EV_BATTERY: ++ case ID_CONTROLLER_STATUS: + if (steam->quirks & STEAM_QUIRK_WIRELESS) { + rcu_read_lock(); + battery = rcu_dereference(steam->battery); +-- +2.39.5 + diff --git a/queue-6.6/ipv4-add-rcu-protection-to-ip4_dst_hoplimit.patch b/queue-6.6/ipv4-add-rcu-protection-to-ip4_dst_hoplimit.patch new file mode 100644 index 0000000000..68b6265e30 --- /dev/null +++ b/queue-6.6/ipv4-add-rcu-protection-to-ip4_dst_hoplimit.patch @@ -0,0 +1,47 @@ +From 10b48585546bad0a85656701c640393bfa26df41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:10 +0000 +Subject: ipv4: add RCU protection to ip4_dst_hoplimit() + +From: Eric Dumazet + +[ Upstream commit 469308552ca4560176cfc100e7ca84add1bebd7c ] + +ip4_dst_hoplimit() must use RCU protection to make +sure the net structure it reads does not disappear. + +Fixes: fa50d974d104 ("ipv4: Namespaceify ip_default_ttl sysctl knob") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250205155120.1676781-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + include/net/route.h | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/include/net/route.h b/include/net/route.h +index 51a45b1887b56..0171e9e1bbea3 100644 +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -357,10 +357,15 @@ static inline int inet_iif(const struct sk_buff *skb) + static inline int ip4_dst_hoplimit(const struct dst_entry *dst) + { + int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); +- struct net *net = dev_net(dst->dev); + +- if (hoplimit == 0) ++ if (hoplimit == 0) { ++ const struct net *net; ++ ++ rcu_read_lock(); ++ net = dev_net_rcu(dst->dev); + hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl); ++ rcu_read_unlock(); ++ } + return hoplimit; + } + +-- +2.39.5 + diff --git a/queue-6.6/ipv4-icmp-convert-to-dev_net_rcu.patch b/queue-6.6/ipv4-icmp-convert-to-dev_net_rcu.patch new file mode 100644 index 0000000000..b41c874491 --- /dev/null +++ b/queue-6.6/ipv4-icmp-convert-to-dev_net_rcu.patch @@ -0,0 +1,150 @@ +From 58a0718e856c47d597cb03e1ddbce04ae65eba2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:16 +0000 +Subject: ipv4: icmp: convert to dev_net_rcu() + +From: Eric Dumazet + +[ Upstream commit 4b8474a0951e605d2a27a2c483da4eb4b8c63760 ] + +__icmp_send() must ensure rcu_read_lock() is held, as spotted +by Jakub. + +Other ICMP uses of dev_net() seem safe, change them to dev_net_rcu() +to get LOCKDEP support. + +Fixes: dde1bc0e6f86 ("[NETNS]: Add namespace for ICMP replying code.") +Closes: https://lore.kernel.org/netdev/20250203153633.46ce0337@kernel.org/ +Reported-by: Jakub Kicinski +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20250205155120.1676781-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/icmp.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c +index a6adf6a2ec4b5..a21d32b3ae6c3 100644 +--- a/net/ipv4/icmp.c ++++ b/net/ipv4/icmp.c +@@ -403,10 +403,10 @@ static void icmp_push_reply(struct sock *sk, + + static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) + { +- struct ipcm_cookie ipc; + struct rtable *rt = skb_rtable(skb); +- struct net *net = dev_net(rt->dst.dev); ++ struct net *net = dev_net_rcu(rt->dst.dev); + bool apply_ratelimit = false; ++ struct ipcm_cookie ipc; + struct flowi4 fl4; + struct sock *sk; + struct inet_sock *inet; +@@ -609,12 +609,14 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, + struct sock *sk; + + if (!rt) +- goto out; ++ return; ++ ++ rcu_read_lock(); + + if (rt->dst.dev) +- net = dev_net(rt->dst.dev); ++ net = dev_net_rcu(rt->dst.dev); + else if (skb_in->dev) +- net = dev_net(skb_in->dev); ++ net = dev_net_rcu(skb_in->dev); + else + goto out; + +@@ -783,7 +785,8 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, + icmp_xmit_unlock(sk); + out_bh_enable: + local_bh_enable(); +-out:; ++out: ++ rcu_read_unlock(); + } + EXPORT_SYMBOL(__icmp_send); + +@@ -832,7 +835,7 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info) + * avoid additional coding at protocol handlers. + */ + if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { +- __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); ++ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); + return; + } + +@@ -866,7 +869,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb) + struct net *net; + u32 info = 0; + +- net = dev_net(skb_dst(skb)->dev); ++ net = dev_net_rcu(skb_dst(skb)->dev); + + /* + * Incomplete header ? +@@ -977,7 +980,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb) + static enum skb_drop_reason icmp_redirect(struct sk_buff *skb) + { + if (skb->len < sizeof(struct iphdr)) { +- __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); ++ __ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS); + return SKB_DROP_REASON_PKT_TOO_SMALL; + } + +@@ -1009,7 +1012,7 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb) + struct icmp_bxm icmp_param; + struct net *net; + +- net = dev_net(skb_dst(skb)->dev); ++ net = dev_net_rcu(skb_dst(skb)->dev); + /* should there be an ICMP stat for ignored echos? */ + if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all)) + return SKB_NOT_DROPPED_YET; +@@ -1038,9 +1041,9 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb) + + bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr) + { ++ struct net *net = dev_net_rcu(skb->dev); + struct icmp_ext_hdr *ext_hdr, _ext_hdr; + struct icmp_ext_echo_iio *iio, _iio; +- struct net *net = dev_net(skb->dev); + struct inet6_dev *in6_dev; + struct in_device *in_dev; + struct net_device *dev; +@@ -1179,7 +1182,7 @@ static enum skb_drop_reason icmp_timestamp(struct sk_buff *skb) + return SKB_NOT_DROPPED_YET; + + out_err: +- __ICMP_INC_STATS(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); ++ __ICMP_INC_STATS(dev_net_rcu(skb_dst(skb)->dev), ICMP_MIB_INERRORS); + return SKB_DROP_REASON_PKT_TOO_SMALL; + } + +@@ -1196,7 +1199,7 @@ int icmp_rcv(struct sk_buff *skb) + { + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; + struct rtable *rt = skb_rtable(skb); +- struct net *net = dev_net(rt->dst.dev); ++ struct net *net = dev_net_rcu(rt->dst.dev); + struct icmphdr *icmph; + + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { +@@ -1369,9 +1372,9 @@ int icmp_err(struct sk_buff *skb, u32 info) + struct iphdr *iph = (struct iphdr *)skb->data; + int offset = iph->ihl<<2; + struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset); ++ struct net *net = dev_net_rcu(skb->dev); + int type = icmp_hdr(skb)->type; + int code = icmp_hdr(skb)->code; +- struct net *net = dev_net(skb->dev); + + /* + * Use ping_err to handle all icmp errors except those +-- +2.39.5 + diff --git a/queue-6.6/ipv4-use-rcu-protection-in-__ip_rt_update_pmtu.patch b/queue-6.6/ipv4-use-rcu-protection-in-__ip_rt_update_pmtu.patch new file mode 100644 index 0000000000..c5500c8ea2 --- /dev/null +++ b/queue-6.6/ipv4-use-rcu-protection-in-__ip_rt_update_pmtu.patch @@ -0,0 +1,77 @@ +From 8c048c1c6f1ad0fd47a090345cb9e675d1317653 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:15 +0000 +Subject: ipv4: use RCU protection in __ip_rt_update_pmtu() + +From: Eric Dumazet + +[ Upstream commit 139512191bd06f1b496117c76372b2ce372c9a41 ] + +__ip_rt_update_pmtu() must use RCU protection to make +sure the net structure it reads does not disappear. + +Fixes: 2fbc6e89b2f1 ("ipv4: Update exception handling for multipath routes via same device") +Fixes: 1de6b15a434c ("Namespaceify min_pmtu sysctl") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20250205155120.1676781-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/route.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 2e524c27a5171..97dc30a03dbf2 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -1020,9 +1020,9 @@ out: kfree_skb_reason(skb, reason); + static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + { + struct dst_entry *dst = &rt->dst; +- struct net *net = dev_net(dst->dev); + struct fib_result res; + bool lock = false; ++ struct net *net; + u32 old_mtu; + + if (ip_mtu_locked(dst)) +@@ -1032,6 +1032,8 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + if (old_mtu < mtu) + return; + ++ rcu_read_lock(); ++ net = dev_net_rcu(dst->dev); + if (mtu < net->ipv4.ip_rt_min_pmtu) { + lock = true; + mtu = min(old_mtu, net->ipv4.ip_rt_min_pmtu); +@@ -1039,9 +1041,8 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + + if (rt->rt_pmtu == mtu && !lock && + time_before(jiffies, dst->expires - net->ipv4.ip_rt_mtu_expires / 2)) +- return; ++ goto out; + +- rcu_read_lock(); + if (fib_lookup(net, fl4, &res, 0) == 0) { + struct fib_nh_common *nhc; + +@@ -1055,14 +1056,14 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock, + jiffies + net->ipv4.ip_rt_mtu_expires); + } +- rcu_read_unlock(); +- return; ++ goto out; + } + #endif /* CONFIG_IP_ROUTE_MULTIPATH */ + nhc = FIB_RES_NHC(res); + update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock, + jiffies + net->ipv4.ip_rt_mtu_expires); + } ++out: + rcu_read_unlock(); + } + +-- +2.39.5 + diff --git a/queue-6.6/ipv4-use-rcu-protection-in-inet_select_addr.patch b/queue-6.6/ipv4-use-rcu-protection-in-inet_select_addr.patch new file mode 100644 index 0000000000..b61619ea73 --- /dev/null +++ b/queue-6.6/ipv4-use-rcu-protection-in-inet_select_addr.patch @@ -0,0 +1,41 @@ +From 20f70039b88fe3b8aa98048e9a3c33eebbfaf4ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:14 +0000 +Subject: ipv4: use RCU protection in inet_select_addr() + +From: Eric Dumazet + +[ Upstream commit 719817cd293e4fa389e1f69c396f3f816ed5aa41 ] + +inet_select_addr() must use RCU protection to make +sure the net structure it reads does not disappear. + +Fixes: c4544c724322 ("[NETNS]: Process inet_select_addr inside a namespace.") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20250205155120.1676781-7-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/devinet.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 4822f68edbf08..c33b1ecc591e4 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -1341,10 +1341,11 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) + __be32 addr = 0; + unsigned char localnet_scope = RT_SCOPE_HOST; + struct in_device *in_dev; +- struct net *net = dev_net(dev); ++ struct net *net; + int master_idx; + + rcu_read_lock(); ++ net = dev_net_rcu(dev); + in_dev = __in_dev_get_rcu(dev); + if (!in_dev) + goto no_in_dev; +-- +2.39.5 + diff --git a/queue-6.6/ipv4-use-rcu-protection-in-ipv4_default_advmss.patch b/queue-6.6/ipv4-use-rcu-protection-in-ipv4_default_advmss.patch new file mode 100644 index 0000000000..502f421a10 --- /dev/null +++ b/queue-6.6/ipv4-use-rcu-protection-in-ipv4_default_advmss.patch @@ -0,0 +1,48 @@ +From 7966558932d043b89d988916b242917a170b33c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:12 +0000 +Subject: ipv4: use RCU protection in ipv4_default_advmss() + +From: Eric Dumazet + +[ Upstream commit 71b8471c93fa0bcab911fcb65da1eb6c4f5f735f ] + +ipv4_default_advmss() must use RCU protection to make +sure the net structure it reads does not disappear. + +Fixes: 2e9589ff809e ("ipv4: Namespaceify min_adv_mss sysctl knob") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250205155120.1676781-5-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/route.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 61fc2166a870e..15cf2949ce951 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -1306,10 +1306,15 @@ static void set_class_tag(struct rtable *rt, u32 tag) + + static unsigned int ipv4_default_advmss(const struct dst_entry *dst) + { +- struct net *net = dev_net(dst->dev); + unsigned int header_size = sizeof(struct tcphdr) + sizeof(struct iphdr); +- unsigned int advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size, +- net->ipv4.ip_rt_min_advmss); ++ unsigned int advmss; ++ struct net *net; ++ ++ rcu_read_lock(); ++ net = dev_net_rcu(dst->dev); ++ advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size, ++ net->ipv4.ip_rt_min_advmss); ++ rcu_read_unlock(); + + return min(advmss, IPV4_MAX_PMTU - header_size); + } +-- +2.39.5 + diff --git a/queue-6.6/ipv4-use-rcu-protection-in-rt_is_expired.patch b/queue-6.6/ipv4-use-rcu-protection-in-rt_is_expired.patch new file mode 100644 index 0000000000..213248f004 --- /dev/null +++ b/queue-6.6/ipv4-use-rcu-protection-in-rt_is_expired.patch @@ -0,0 +1,44 @@ +From 991bba8ee88b4f3b012da9d98d60a1fab39f0352 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:13 +0000 +Subject: ipv4: use RCU protection in rt_is_expired() + +From: Eric Dumazet + +[ Upstream commit dd205fcc33d92d54eee4d7f21bb073af9bd5ce2b ] + +rt_is_expired() must use RCU protection to make +sure the net structure it reads does not disappear. + +Fixes: e84f84f27647 ("netns: place rt_genid into struct net") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250205155120.1676781-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/route.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 15cf2949ce951..c96837e6626c3 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -393,7 +393,13 @@ static inline int ip_rt_proc_init(void) + + static inline bool rt_is_expired(const struct rtable *rth) + { +- return rth->rt_genid != rt_genid_ipv4(dev_net(rth->dst.dev)); ++ bool res; ++ ++ rcu_read_lock(); ++ res = rth->rt_genid != rt_genid_ipv4(dev_net_rcu(rth->dst.dev)); ++ rcu_read_unlock(); ++ ++ return res; + } + + void rt_cache_flush(struct net *net) +-- +2.39.5 + diff --git a/queue-6.6/ipv6-icmp-convert-to-dev_net_rcu.patch b/queue-6.6/ipv6-icmp-convert-to-dev_net_rcu.patch new file mode 100644 index 0000000000..ebf6430ac2 --- /dev/null +++ b/queue-6.6/ipv6-icmp-convert-to-dev_net_rcu.patch @@ -0,0 +1,191 @@ +From 2cd78e698c9ab4384991c6a383352e2fb889eef0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:19 +0000 +Subject: ipv6: icmp: convert to dev_net_rcu() + +From: Eric Dumazet + +[ Upstream commit 34aef2b0ce3aa4eb4ef2e1f5cad3738d527032f5 ] + +icmp6_send() must acquire rcu_read_lock() sooner to ensure +the dev_net() call done from a safe context. + +Other ICMPv6 uses of dev_net() seem safe, change them to +dev_net_rcu() to get LOCKDEP support to catch bugs. + +Fixes: 9a43b709a230 ("[NETNS][IPV6] icmp6 - make icmpv6_socket per namespace") +Signed-off-by: Eric Dumazet +Link: https://patch.msgid.link/20250205155120.1676781-12-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/icmp.c | 42 +++++++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 19 deletions(-) + +diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c +index 35df405ce1f75..fd91fd139d76c 100644 +--- a/net/ipv6/icmp.c ++++ b/net/ipv6/icmp.c +@@ -76,7 +76,7 @@ static int icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + { + /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */ + struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset); +- struct net *net = dev_net(skb->dev); ++ struct net *net = dev_net_rcu(skb->dev); + + if (type == ICMPV6_PKT_TOOBIG) + ip6_update_pmtu(skb, net, info, skb->dev->ifindex, 0, sock_net_uid(net, NULL)); +@@ -473,7 +473,10 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + + if (!skb->dev) + return; +- net = dev_net(skb->dev); ++ ++ rcu_read_lock(); ++ ++ net = dev_net_rcu(skb->dev); + mark = IP6_REPLY_MARK(net, skb->mark); + /* + * Make sure we respect the rules +@@ -496,7 +499,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + !(type == ICMPV6_PARAMPROB && + code == ICMPV6_UNK_OPTION && + (opt_unrec(skb, info)))) +- return; ++ goto out; + + saddr = NULL; + } +@@ -526,7 +529,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { + net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n", + &hdr->saddr, &hdr->daddr); +- return; ++ goto out; + } + + /* +@@ -535,7 +538,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + if (is_ineligible(skb)) { + net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n", + &hdr->saddr, &hdr->daddr); +- return; ++ goto out; + } + + /* Needed by both icmpv6_global_allow and icmpv6_xmit_lock */ +@@ -582,7 +585,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + np = inet6_sk(sk); + + if (!icmpv6_xrlim_allow(sk, type, &fl6, apply_ratelimit)) +- goto out; ++ goto out_unlock; + + tmp_hdr.icmp6_type = type; + tmp_hdr.icmp6_code = code; +@@ -600,7 +603,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + + dst = icmpv6_route_lookup(net, skb, sk, &fl6); + if (IS_ERR(dst)) +- goto out; ++ goto out_unlock; + + ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); + +@@ -616,7 +619,6 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + goto out_dst_release; + } + +- rcu_read_lock(); + idev = __in6_dev_get(skb->dev); + + if (ip6_append_data(sk, icmpv6_getfrag, &msg, +@@ -630,13 +632,15 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, + icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, + len + sizeof(struct icmp6hdr)); + } +- rcu_read_unlock(); ++ + out_dst_release: + dst_release(dst); +-out: ++out_unlock: + icmpv6_xmit_unlock(sk); + out_bh_enable: + local_bh_enable(); ++out: ++ rcu_read_unlock(); + } + EXPORT_SYMBOL(icmp6_send); + +@@ -679,8 +683,8 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type, + skb_pull(skb2, nhs); + skb_reset_network_header(skb2); + +- rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, +- skb, 0); ++ rt = rt6_lookup(dev_net_rcu(skb->dev), &ipv6_hdr(skb2)->saddr, ++ NULL, 0, skb, 0); + + if (rt && rt->dst.dev) + skb2->dev = rt->dst.dev; +@@ -717,7 +721,7 @@ EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach); + + static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb) + { +- struct net *net = dev_net(skb->dev); ++ struct net *net = dev_net_rcu(skb->dev); + struct sock *sk; + struct inet6_dev *idev; + struct ipv6_pinfo *np; +@@ -832,7 +836,7 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, + u8 code, __be32 info) + { + struct inet6_skb_parm *opt = IP6CB(skb); +- struct net *net = dev_net(skb->dev); ++ struct net *net = dev_net_rcu(skb->dev); + const struct inet6_protocol *ipprot; + enum skb_drop_reason reason; + int inner_offset; +@@ -889,7 +893,7 @@ enum skb_drop_reason icmpv6_notify(struct sk_buff *skb, u8 type, + static int icmpv6_rcv(struct sk_buff *skb) + { + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; +- struct net *net = dev_net(skb->dev); ++ struct net *net = dev_net_rcu(skb->dev); + struct net_device *dev = icmp6_dev(skb); + struct inet6_dev *idev = __in6_dev_get(dev); + const struct in6_addr *saddr, *daddr; +@@ -921,7 +925,7 @@ static int icmpv6_rcv(struct sk_buff *skb) + skb_set_network_header(skb, nh); + } + +- __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS); ++ __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INMSGS); + + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; +@@ -939,7 +943,7 @@ static int icmpv6_rcv(struct sk_buff *skb) + + type = hdr->icmp6_type; + +- ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type); ++ ICMP6MSGIN_INC_STATS(dev_net_rcu(dev), idev, type); + + switch (type) { + case ICMPV6_ECHO_REQUEST: +@@ -1034,9 +1038,9 @@ static int icmpv6_rcv(struct sk_buff *skb) + + csum_error: + reason = SKB_DROP_REASON_ICMP_CSUM; +- __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS); ++ __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_CSUMERRORS); + discard_it: +- __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS); ++ __ICMP6_INC_STATS(dev_net_rcu(dev), idev, ICMP6_MIB_INERRORS); + drop_no_count: + kfree_skb_reason(skb, reason); + return 0; +-- +2.39.5 + diff --git a/queue-6.6/ipv6-mcast-add-rcu-protection-to-mld_newpack.patch b/queue-6.6/ipv6-mcast-add-rcu-protection-to-mld_newpack.patch new file mode 100644 index 0000000000..035df6704f --- /dev/null +++ b/queue-6.6/ipv6-mcast-add-rcu-protection-to-mld_newpack.patch @@ -0,0 +1,80 @@ +From c21d9a56bd3435b3017070bb73df4c8cabd630d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Feb 2025 14:10:21 +0000 +Subject: ipv6: mcast: add RCU protection to mld_newpack() + +From: Eric Dumazet + +[ Upstream commit a527750d877fd334de87eef81f1cb5f0f0ca3373 ] + +mld_newpack() can be called without RTNL or RCU being held. + +Note that we no longer can use sock_alloc_send_skb() because +ipv6.igmp_sk uses GFP_KERNEL allocations which can sleep. + +Instead use alloc_skb() and charge the net->ipv6.igmp_sk +socket under RCU protection. + +Fixes: b8ad0cbc58f7 ("[NETNS][IPV6] mcast - handle several network namespace") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20250212141021.1663666-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index a502669b2b28a..9bb246c09fcee 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -1729,21 +1729,19 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu) + struct net_device *dev = idev->dev; + int hlen = LL_RESERVED_SPACE(dev); + int tlen = dev->needed_tailroom; +- struct net *net = dev_net(dev); + const struct in6_addr *saddr; + struct in6_addr addr_buf; + struct mld2_report *pmr; + struct sk_buff *skb; + unsigned int size; + struct sock *sk; +- int err; ++ struct net *net; + +- sk = net->ipv6.igmp_sk; + /* we assume size > sizeof(ra) here + * Also try to not allocate high-order pages for big MTU + */ + size = min_t(int, mtu, PAGE_SIZE / 2) + hlen + tlen; +- skb = sock_alloc_send_skb(sk, size, 1, &err); ++ skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return NULL; + +@@ -1751,6 +1749,12 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu) + skb_reserve(skb, hlen); + skb_tailroom_reserve(skb, mtu, tlen); + ++ rcu_read_lock(); ++ ++ net = dev_net_rcu(dev); ++ sk = net->ipv6.igmp_sk; ++ skb_set_owner_w(skb, sk); ++ + if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) { + /* : + * use unspecified address as the source address +@@ -1762,6 +1766,8 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu) + + ip6_mc_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); + ++ rcu_read_unlock(); ++ + skb_put_data(skb, ra, sizeof(ra)); + + skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data); +-- +2.39.5 + diff --git a/queue-6.6/ipv6-mcast-extend-rcu-protection-in-igmp6_send.patch b/queue-6.6/ipv6-mcast-extend-rcu-protection-in-igmp6_send.patch new file mode 100644 index 0000000000..a47e91d75d --- /dev/null +++ b/queue-6.6/ipv6-mcast-extend-rcu-protection-in-igmp6_send.patch @@ -0,0 +1,105 @@ +From 5cdc9562085f1ae474e09332713509620c55774d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Feb 2025 13:58:40 +0000 +Subject: ipv6: mcast: extend RCU protection in igmp6_send() + +From: Eric Dumazet + +[ Upstream commit 087c1faa594fa07a66933d750c0b2610aa1a2946 ] + +igmp6_send() can be called without RTNL or RCU being held. + +Extend RCU protection so that we can safely fetch the net pointer +and avoid a potential UAF. + +Note that we no longer can use sock_alloc_send_skb() because +ipv6.igmp_sk uses GFP_KERNEL allocations which can sleep. + +Instead use alloc_skb() and charge the net->ipv6.igmp_sk +socket under RCU protection. + +Fixes: b8ad0cbc58f7 ("[NETNS][IPV6] mcast - handle several network namespace") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250207135841.1948589-9-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/mcast.c | 31 +++++++++++++++---------------- + 1 file changed, 15 insertions(+), 16 deletions(-) + +diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c +index 6e2f77a95a657..a502669b2b28a 100644 +--- a/net/ipv6/mcast.c ++++ b/net/ipv6/mcast.c +@@ -2121,21 +2121,21 @@ static void mld_send_cr(struct inet6_dev *idev) + + static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) + { +- struct net *net = dev_net(dev); +- struct sock *sk = net->ipv6.igmp_sk; ++ const struct in6_addr *snd_addr, *saddr; ++ int err, len, payload_len, full_len; ++ struct in6_addr addr_buf; + struct inet6_dev *idev; + struct sk_buff *skb; + struct mld_msg *hdr; +- const struct in6_addr *snd_addr, *saddr; +- struct in6_addr addr_buf; + int hlen = LL_RESERVED_SPACE(dev); + int tlen = dev->needed_tailroom; +- int err, len, payload_len, full_len; + u8 ra[8] = { IPPROTO_ICMPV6, 0, + IPV6_TLV_ROUTERALERT, 2, 0, 0, + IPV6_TLV_PADN, 0 }; +- struct flowi6 fl6; + struct dst_entry *dst; ++ struct flowi6 fl6; ++ struct net *net; ++ struct sock *sk; + + if (type == ICMPV6_MGM_REDUCTION) + snd_addr = &in6addr_linklocal_allrouters; +@@ -2146,19 +2146,21 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) + payload_len = len + sizeof(ra); + full_len = sizeof(struct ipv6hdr) + payload_len; + +- rcu_read_lock(); +- IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_OUTREQUESTS); +- rcu_read_unlock(); ++ skb = alloc_skb(hlen + tlen + full_len, GFP_KERNEL); + +- skb = sock_alloc_send_skb(sk, hlen + tlen + full_len, 1, &err); ++ rcu_read_lock(); + ++ net = dev_net_rcu(dev); ++ idev = __in6_dev_get(dev); ++ IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + if (!skb) { +- rcu_read_lock(); +- IP6_INC_STATS(net, __in6_dev_get(dev), +- IPSTATS_MIB_OUTDISCARDS); ++ IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); + rcu_read_unlock(); + return; + } ++ sk = net->ipv6.igmp_sk; ++ skb_set_owner_w(skb, sk); ++ + skb->priority = TC_PRIO_CONTROL; + skb_reserve(skb, hlen); + +@@ -2183,9 +2185,6 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) + IPPROTO_ICMPV6, + csum_partial(hdr, len, 0)); + +- rcu_read_lock(); +- idev = __in6_dev_get(skb->dev); +- + icmpv6_flow_init(sk, &fl6, type, + &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + skb->dev->ifindex); +-- +2.39.5 + diff --git a/queue-6.6/ipv6-use-rcu-protection-in-ip6_default_advmss.patch b/queue-6.6/ipv6-use-rcu-protection-in-ip6_default_advmss.patch new file mode 100644 index 0000000000..aec3df4e5a --- /dev/null +++ b/queue-6.6/ipv6-use-rcu-protection-in-ip6_default_advmss.patch @@ -0,0 +1,49 @@ +From f5a24e73ae93c7023166dea4c5d9b609932a6e39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:18 +0000 +Subject: ipv6: use RCU protection in ip6_default_advmss() + +From: Eric Dumazet + +[ Upstream commit 3c8ffcd248da34fc41e52a46e51505900115fc2a ] + +ip6_default_advmss() needs rcu protection to make +sure the net structure it reads does not disappear. + +Fixes: 5578689a4e3c ("[NETNS][IPV6] route6 - make route6 per namespace") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250205155120.1676781-11-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/route.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index c5cee40a658b4..5715d54f3d0be 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -3188,13 +3188,18 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst) + { + struct net_device *dev = dst->dev; + unsigned int mtu = dst_mtu(dst); +- struct net *net = dev_net(dev); ++ struct net *net; + + mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); + ++ rcu_read_lock(); ++ ++ net = dev_net_rcu(dev); + if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) + mtu = net->ipv6.sysctl.ip6_rt_min_advmss; + ++ rcu_read_unlock(); ++ + /* + * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and + * corresponding MSS is IPV6_MAXPLEN - tcp_header_size. +-- +2.39.5 + diff --git a/queue-6.6/ndisc-extend-rcu-protection-in-ndisc_send_skb.patch b/queue-6.6/ndisc-extend-rcu-protection-in-ndisc_send_skb.patch new file mode 100644 index 0000000000..a91eb54708 --- /dev/null +++ b/queue-6.6/ndisc-extend-rcu-protection-in-ndisc_send_skb.patch @@ -0,0 +1,72 @@ +From 835aff5cd98c08aabf26924c57283e7f9912cafe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Feb 2025 13:58:39 +0000 +Subject: ndisc: extend RCU protection in ndisc_send_skb() + +From: Eric Dumazet + +[ Upstream commit ed6ae1f325d3c43966ec1b62ac1459e2b8e45640 ] + +ndisc_send_skb() can be called without RTNL or RCU held. + +Acquire rcu_read_lock() earlier, so that we can use dev_net_rcu() +and avoid a potential UAF. + +Fixes: 1762f7e88eb3 ("[NETNS][IPV6] ndisc - make socket control per namespace") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250207135841.1948589-8-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ndisc.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index ea3cb26da5846..8d853971f2f68 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -471,16 +471,20 @@ static void ip6_nd_hdr(struct sk_buff *skb, + void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, + const struct in6_addr *saddr) + { ++ struct icmp6hdr *icmp6h = icmp6_hdr(skb); + struct dst_entry *dst = skb_dst(skb); +- struct net *net = dev_net(skb->dev); +- struct sock *sk = net->ipv6.ndisc_sk; + struct inet6_dev *idev; ++ struct net *net; ++ struct sock *sk; + int err; +- struct icmp6hdr *icmp6h = icmp6_hdr(skb); + u8 type; + + type = icmp6h->icmp6_type; + ++ rcu_read_lock(); ++ ++ net = dev_net_rcu(skb->dev); ++ sk = net->ipv6.ndisc_sk; + if (!dst) { + struct flowi6 fl6; + int oif = skb->dev->ifindex; +@@ -488,6 +492,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, + icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif); + dst = icmp6_dst_alloc(skb->dev, &fl6); + if (IS_ERR(dst)) { ++ rcu_read_unlock(); + kfree_skb(skb); + return; + } +@@ -502,7 +507,6 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr, + + ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); + +- rcu_read_lock(); + idev = __in6_dev_get(dst->dev); + IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS); + +-- +2.39.5 + diff --git a/queue-6.6/ndisc-use-rcu-protection-in-ndisc_alloc_skb.patch b/queue-6.6/ndisc-use-rcu-protection-in-ndisc_alloc_skb.patch new file mode 100644 index 0000000000..a5c5d837ff --- /dev/null +++ b/queue-6.6/ndisc-use-rcu-protection-in-ndisc_alloc_skb.patch @@ -0,0 +1,59 @@ +From 647df0cc795f962a52832fe40c8a2b4ea1f081bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Feb 2025 13:58:34 +0000 +Subject: ndisc: use RCU protection in ndisc_alloc_skb() + +From: Eric Dumazet + +[ Upstream commit 628e6d18930bbd21f2d4562228afe27694f66da9 ] + +ndisc_alloc_skb() can be called without RTNL or RCU being held. + +Add RCU protection to avoid possible UAF. + +Fixes: de09334b9326 ("ndisc: Introduce ndisc_alloc_skb() helper.") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250207135841.1948589-3-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv6/ndisc.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c +index 561972143ca42..ea3cb26da5846 100644 +--- a/net/ipv6/ndisc.c ++++ b/net/ipv6/ndisc.c +@@ -418,15 +418,11 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, + { + int hlen = LL_RESERVED_SPACE(dev); + int tlen = dev->needed_tailroom; +- struct sock *sk = dev_net(dev)->ipv6.ndisc_sk; + struct sk_buff *skb; + + skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC); +- if (!skb) { +- ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n", +- __func__); ++ if (!skb) + return NULL; +- } + + skb->protocol = htons(ETH_P_IPV6); + skb->dev = dev; +@@ -437,7 +433,9 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, + /* Manually assign socket ownership as we avoid calling + * sock_alloc_send_pskb() to bypass wmem buffer limits + */ +- skb_set_owner_w(skb, sk); ++ rcu_read_lock(); ++ skb_set_owner_w(skb, dev_net_rcu(dev)->ipv6.ndisc_sk); ++ rcu_read_unlock(); + + return skb; + } +-- +2.39.5 + diff --git a/queue-6.6/neighbour-delete-redundant-judgment-statements.patch b/queue-6.6/neighbour-delete-redundant-judgment-statements.patch new file mode 100644 index 0000000000..c3800f4e41 --- /dev/null +++ b/queue-6.6/neighbour-delete-redundant-judgment-statements.patch @@ -0,0 +1,40 @@ +From 61f2092651726d360fd87255368c59b26a5b1830 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Aug 2024 12:32:45 +0800 +Subject: neighbour: delete redundant judgment statements + +From: Li Zetao + +[ Upstream commit c25bdd2ac8cf7da70a226f1a66cdce7af15ff86f ] + +The initial value of err is -ENOBUFS, and err is guaranteed to be +less than 0 before all goto errout. Therefore, on the error path +of errout, there is no need to repeatedly judge that err is less than 0, +and delete redundant judgments to make the code more concise. + +Signed-off-by: Li Zetao +Reviewed-by: Petr Machata +Signed-off-by: David S. Miller +Stable-dep-of: becbd5850c03 ("neighbour: use RCU protection in __neigh_notify()") +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index cb0c233e83962..118d932b3baa1 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3526,8 +3526,7 @@ static void __neigh_notify(struct neighbour *n, int type, int flags, + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); + return; + errout: +- if (err < 0) +- rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); ++ rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); + } + + void neigh_app_ns(struct neighbour *n) +-- +2.39.5 + diff --git a/queue-6.6/neighbour-use-rcu-protection-in-__neigh_notify.patch b/queue-6.6/neighbour-use-rcu-protection-in-__neigh_notify.patch new file mode 100644 index 0000000000..e6970406d4 --- /dev/null +++ b/queue-6.6/neighbour-use-rcu-protection-in-__neigh_notify.patch @@ -0,0 +1,58 @@ +From 245b248e640dd4b9c338a9b30646f92876c3ff92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Feb 2025 13:58:35 +0000 +Subject: neighbour: use RCU protection in __neigh_notify() + +From: Eric Dumazet + +[ Upstream commit becbd5850c03ed33b232083dd66c6e38c0c0e569 ] + +__neigh_notify() can be called without RTNL or RCU protection. + +Use RCU protection to avoid potential UAF. + +Fixes: 426b5303eb43 ("[NETNS]: Modify the neighbour table code so it handles multiple network namespaces") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250207135841.1948589-4-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/core/neighbour.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index 118d932b3baa1..e44feb39d459a 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -3508,10 +3508,12 @@ static const struct seq_operations neigh_stat_seq_ops = { + static void __neigh_notify(struct neighbour *n, int type, int flags, + u32 pid) + { +- struct net *net = dev_net(n->dev); + struct sk_buff *skb; + int err = -ENOBUFS; ++ struct net *net; + ++ rcu_read_lock(); ++ net = dev_net_rcu(n->dev); + skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC); + if (skb == NULL) + goto errout; +@@ -3524,9 +3526,11 @@ static void __neigh_notify(struct neighbour *n, int type, int flags, + goto errout; + } + rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); +- return; ++ goto out; + errout: + rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); ++out: ++ rcu_read_unlock(); + } + + void neigh_app_ns(struct neighbour *n) +-- +2.39.5 + diff --git a/queue-6.6/net-add-dev_net_rcu-helper.patch b/queue-6.6/net-add-dev_net_rcu-helper.patch new file mode 100644 index 0000000000..1f03fc63b8 --- /dev/null +++ b/queue-6.6/net-add-dev_net_rcu-helper.patch @@ -0,0 +1,62 @@ +From bdcf9427705b16f16f33183b8fc4a84d5e619506 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Feb 2025 15:51:09 +0000 +Subject: net: add dev_net_rcu() helper + +From: Eric Dumazet + +[ Upstream commit 482ad2a4ace2740ca0ff1cbc8f3c7f862f3ab507 ] + +dev->nd_net can change, readers should either +use rcu_read_lock() or RTNL. + +We currently use a generic helper, dev_net() with +no debugging support. We probably have many hidden bugs. + +Add dev_net_rcu() helper for callers using rcu_read_lock() +protection. + +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250205155120.1676781-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +Stable-dep-of: 71b8471c93fa ("ipv4: use RCU protection in ipv4_default_advmss()") +Signed-off-by: Sasha Levin +--- + include/linux/netdevice.h | 6 ++++++ + include/net/net_namespace.h | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index 8b5121eb8757e..95ee88dfe0b9c 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2593,6 +2593,12 @@ struct net *dev_net(const struct net_device *dev) + return read_pnet(&dev->nd_net); + } + ++static inline ++struct net *dev_net_rcu(const struct net_device *dev) ++{ ++ return read_pnet_rcu(&dev->nd_net); ++} ++ + static inline + void dev_net_set(struct net_device *dev, struct net *net) + { +diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h +index b767bdcd9e122..ce3f84c6eb8eb 100644 +--- a/include/net/net_namespace.h ++++ b/include/net/net_namespace.h +@@ -389,7 +389,7 @@ static inline struct net *read_pnet(const possible_net_t *pnet) + #endif + } + +-static inline struct net *read_pnet_rcu(possible_net_t *pnet) ++static inline struct net *read_pnet_rcu(const possible_net_t *pnet) + { + #ifdef CONFIG_NET_NS + return rcu_dereference(pnet->net); +-- +2.39.5 + diff --git a/queue-6.6/net-ipv4-cache-pmtu-for-all-packet-paths-if-multipat.patch b/queue-6.6/net-ipv4-cache-pmtu-for-all-packet-paths-if-multipat.patch new file mode 100644 index 0000000000..2b2f8e5010 --- /dev/null +++ b/queue-6.6/net-ipv4-cache-pmtu-for-all-packet-paths-if-multipat.patch @@ -0,0 +1,292 @@ +From b8a26376a2ec662e33d84dd6370300ed2ad9aad6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Nov 2024 09:34:24 +0000 +Subject: net: ipv4: Cache pmtu for all packet paths if multipath enabled + +From: Vladimir Vdovin + +[ Upstream commit 7d3f3b4367f315a61fc615e3138f3d320da8c466 ] + +Check number of paths by fib_info_num_path(), +and update_or_create_fnhe() for every path. +Problem is that pmtu is cached only for the oif +that has received icmp message "need to frag", +other oifs will still try to use "default" iface mtu. + +An example topology showing the problem: + + | host1 + +---------+ + | dummy0 | 10.179.20.18/32 mtu9000 + +---------+ + +-----------+----------------+ + +---------+ +---------+ + | ens17f0 | 10.179.2.141/31 | ens17f1 | 10.179.2.13/31 + +---------+ +---------+ + | (all here have mtu 9000) | + +------+ +------+ + | ro1 | 10.179.2.140/31 | ro2 | 10.179.2.12/31 + +------+ +------+ + | | +---------+------------+-------------------+------ + | + +-----+ + | ro3 | 10.10.10.10 mtu1500 + +-----+ + | + ======================================== + some networks + ======================================== + | + +-----+ + | eth0| 10.10.30.30 mtu9000 + +-----+ + | host2 + +host1 have enabled multipath and +sysctl net.ipv4.fib_multipath_hash_policy = 1: + +default proto static src 10.179.20.18 + nexthop via 10.179.2.12 dev ens17f1 weight 1 + nexthop via 10.179.2.140 dev ens17f0 weight 1 + +When host1 tries to do pmtud from 10.179.20.18/32 to host2, +host1 receives at ens17f1 iface an icmp packet from ro3 that ro3 mtu=1500. +And host1 caches it in nexthop exceptions cache. + +Problem is that it is cached only for the iface that has received icmp, +and there is no way that ro3 will send icmp msg to host1 via another path. + +Host1 now have this routes to host2: + +ip r g 10.10.30.30 sport 30000 dport 443 +10.10.30.30 via 10.179.2.12 dev ens17f1 src 10.179.20.18 uid 0 + cache expires 521sec mtu 1500 + +ip r g 10.10.30.30 sport 30033 dport 443 +10.10.30.30 via 10.179.2.140 dev ens17f0 src 10.179.20.18 uid 0 + cache + +So when host1 tries again to reach host2 with mtu>1500, +if packet flow is lucky enough to be hashed with oif=ens17f1 its ok, +if oif=ens17f0 it blackholes and still gets icmp msgs from ro3 to ens17f1, +until lucky day when ro3 will send it through another flow to ens17f0. + +Signed-off-by: Vladimir Vdovin +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20241108093427.317942-1-deliran@verdict.gg +Signed-off-by: Jakub Kicinski +Stable-dep-of: 139512191bd0 ("ipv4: use RCU protection in __ip_rt_update_pmtu()") +Signed-off-by: Sasha Levin +--- + net/ipv4/route.c | 13 ++++ + tools/testing/selftests/net/pmtu.sh | 112 +++++++++++++++++++++++----- + 2 files changed, 108 insertions(+), 17 deletions(-) + +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index c96837e6626c3..2e524c27a5171 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -1046,6 +1046,19 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) + struct fib_nh_common *nhc; + + fib_select_path(net, &res, fl4, NULL); ++#ifdef CONFIG_IP_ROUTE_MULTIPATH ++ if (fib_info_num_path(res.fi) > 1) { ++ int nhsel; ++ ++ for (nhsel = 0; nhsel < fib_info_num_path(res.fi); nhsel++) { ++ nhc = fib_info_nhc(res.fi, nhsel); ++ update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock, ++ jiffies + net->ipv4.ip_rt_mtu_expires); ++ } ++ rcu_read_unlock(); ++ return; ++ } ++#endif /* CONFIG_IP_ROUTE_MULTIPATH */ + nhc = FIB_RES_NHC(res); + update_or_create_fnhe(nhc, fl4->daddr, 0, mtu, lock, + jiffies + net->ipv4.ip_rt_mtu_expires); +diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh +index 1c0dd2f781678..771f237c43534 100755 +--- a/tools/testing/selftests/net/pmtu.sh ++++ b/tools/testing/selftests/net/pmtu.sh +@@ -197,6 +197,12 @@ + # + # - pmtu_ipv6_route_change + # Same as above but with IPv6 ++# ++# - pmtu_ipv4_mp_exceptions ++# Use the same topology as in pmtu_ipv4, but add routeable addresses ++# on host A and B on lo reachable via both routers. Host A and B ++# addresses have multipath routes to each other, b_r1 mtu = 1500. ++# Check that PMTU exceptions are created for both paths. + + source lib.sh + source net_helper.sh +@@ -266,7 +272,8 @@ tests=" + list_flush_ipv4_exception ipv4: list and flush cached exceptions 1 + list_flush_ipv6_exception ipv6: list and flush cached exceptions 1 + pmtu_ipv4_route_change ipv4: PMTU exception w/route replace 1 +- pmtu_ipv6_route_change ipv6: PMTU exception w/route replace 1" ++ pmtu_ipv6_route_change ipv6: PMTU exception w/route replace 1 ++ pmtu_ipv4_mp_exceptions ipv4: PMTU multipath nh exceptions 1" + + # Addressing and routing for tests with routers: four network segments, with + # index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an +@@ -343,6 +350,9 @@ tunnel6_a_addr="fd00:2::a" + tunnel6_b_addr="fd00:2::b" + tunnel6_mask="64" + ++host4_a_addr="192.168.99.99" ++host4_b_addr="192.168.88.88" ++ + dummy6_0_prefix="fc00:1000::" + dummy6_1_prefix="fc00:1001::" + dummy6_mask="64" +@@ -902,6 +912,52 @@ setup_ovs_bridge() { + run_cmd ip route add ${prefix6}:${b_r1}::1 via ${prefix6}:${a_r1}::2 + } + ++setup_multipath_new() { ++ # Set up host A with multipath routes to host B host4_b_addr ++ run_cmd ${ns_a} ip addr add ${host4_a_addr} dev lo ++ run_cmd ${ns_a} ip nexthop add id 401 via ${prefix4}.${a_r1}.2 dev veth_A-R1 ++ run_cmd ${ns_a} ip nexthop add id 402 via ${prefix4}.${a_r2}.2 dev veth_A-R2 ++ run_cmd ${ns_a} ip nexthop add id 403 group 401/402 ++ run_cmd ${ns_a} ip route add ${host4_b_addr} src ${host4_a_addr} nhid 403 ++ ++ # Set up host B with multipath routes to host A host4_a_addr ++ run_cmd ${ns_b} ip addr add ${host4_b_addr} dev lo ++ run_cmd ${ns_b} ip nexthop add id 401 via ${prefix4}.${b_r1}.2 dev veth_B-R1 ++ run_cmd ${ns_b} ip nexthop add id 402 via ${prefix4}.${b_r2}.2 dev veth_B-R2 ++ run_cmd ${ns_b} ip nexthop add id 403 group 401/402 ++ run_cmd ${ns_b} ip route add ${host4_a_addr} src ${host4_b_addr} nhid 403 ++} ++ ++setup_multipath_old() { ++ # Set up host A with multipath routes to host B host4_b_addr ++ run_cmd ${ns_a} ip addr add ${host4_a_addr} dev lo ++ run_cmd ${ns_a} ip route add ${host4_b_addr} \ ++ src ${host4_a_addr} \ ++ nexthop via ${prefix4}.${a_r1}.2 weight 1 \ ++ nexthop via ${prefix4}.${a_r2}.2 weight 1 ++ ++ # Set up host B with multipath routes to host A host4_a_addr ++ run_cmd ${ns_b} ip addr add ${host4_b_addr} dev lo ++ run_cmd ${ns_b} ip route add ${host4_a_addr} \ ++ src ${host4_b_addr} \ ++ nexthop via ${prefix4}.${b_r1}.2 weight 1 \ ++ nexthop via ${prefix4}.${b_r2}.2 weight 1 ++} ++ ++setup_multipath() { ++ if [ "$USE_NH" = "yes" ]; then ++ setup_multipath_new ++ else ++ setup_multipath_old ++ fi ++ ++ # Set up routers with routes to dummies ++ run_cmd ${ns_r1} ip route add ${host4_a_addr} via ${prefix4}.${a_r1}.1 ++ run_cmd ${ns_r2} ip route add ${host4_a_addr} via ${prefix4}.${a_r2}.1 ++ run_cmd ${ns_r1} ip route add ${host4_b_addr} via ${prefix4}.${b_r1}.1 ++ run_cmd ${ns_r2} ip route add ${host4_b_addr} via ${prefix4}.${b_r2}.1 ++} ++ + setup() { + [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return $ksft_skip + +@@ -982,23 +1038,15 @@ link_get_mtu() { + } + + route_get_dst_exception() { +- ns_cmd="${1}" +- dst="${2}" +- dsfield="${3}" ++ ns_cmd="${1}"; shift + +- if [ -z "${dsfield}" ]; then +- dsfield=0 +- fi +- +- ${ns_cmd} ip route get "${dst}" dsfield "${dsfield}" ++ ${ns_cmd} ip route get "$@" + } + + route_get_dst_pmtu_from_exception() { +- ns_cmd="${1}" +- dst="${2}" +- dsfield="${3}" ++ ns_cmd="${1}"; shift + +- mtu_parse "$(route_get_dst_exception "${ns_cmd}" "${dst}" "${dsfield}")" ++ mtu_parse "$(route_get_dst_exception "${ns_cmd}" "$@")" + } + + check_pmtu_value() { +@@ -1141,10 +1189,10 @@ test_pmtu_ipv4_dscp_icmp_exception() { + run_cmd "${ns_a}" ping -q -M want -Q "${dsfield}" -c 1 -w 1 -s "${len}" "${dst2}" + + # Check that exceptions have been created with the correct PMTU +- pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" "${policy_mark}")" ++ pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" dsfield "${policy_mark}")" + check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1 + +- pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" "${policy_mark}")" ++ pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" dsfield "${policy_mark}")" + check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1 + } + +@@ -1191,9 +1239,9 @@ test_pmtu_ipv4_dscp_udp_exception() { + UDP:"${dst2}":50000,tos="${dsfield}" + + # Check that exceptions have been created with the correct PMTU +- pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" "${policy_mark}")" ++ pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst1}" dsfield "${policy_mark}")" + check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1 +- pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" "${policy_mark}")" ++ pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${dst2}" dsfield "${policy_mark}")" + check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1 + } + +@@ -2234,6 +2282,36 @@ test_pmtu_ipv6_route_change() { + test_pmtu_ipvX_route_change 6 + } + ++test_pmtu_ipv4_mp_exceptions() { ++ setup namespaces routing multipath || return $ksft_skip ++ ++ trace "${ns_a}" veth_A-R1 "${ns_r1}" veth_R1-A \ ++ "${ns_r1}" veth_R1-B "${ns_b}" veth_B-R1 \ ++ "${ns_a}" veth_A-R2 "${ns_r2}" veth_R2-A \ ++ "${ns_r2}" veth_R2-B "${ns_b}" veth_B-R2 ++ ++ # Set up initial MTU values ++ mtu "${ns_a}" veth_A-R1 2000 ++ mtu "${ns_r1}" veth_R1-A 2000 ++ mtu "${ns_r1}" veth_R1-B 1500 ++ mtu "${ns_b}" veth_B-R1 1500 ++ ++ mtu "${ns_a}" veth_A-R2 2000 ++ mtu "${ns_r2}" veth_R2-A 2000 ++ mtu "${ns_r2}" veth_R2-B 1500 ++ mtu "${ns_b}" veth_B-R2 1500 ++ ++ # Ping and expect two nexthop exceptions for two routes ++ run_cmd ${ns_a} ping -q -M want -i 0.1 -c 1 -s 1800 "${host4_b_addr}" ++ ++ # Check that exceptions have been created with the correct PMTU ++ pmtu_a_R1="$(route_get_dst_pmtu_from_exception "${ns_a}" "${host4_b_addr}" oif veth_A-R1)" ++ pmtu_a_R2="$(route_get_dst_pmtu_from_exception "${ns_a}" "${host4_b_addr}" oif veth_A-R2)" ++ ++ check_pmtu_value "1500" "${pmtu_a_R1}" "exceeding MTU (veth_A-R1)" || return 1 ++ check_pmtu_value "1500" "${pmtu_a_R2}" "exceeding MTU (veth_A-R2)" || return 1 ++} ++ + usage() { + echo + echo "$0 [OPTIONS] [TEST]..." +-- +2.39.5 + diff --git a/queue-6.6/net-treat-possible_net_t-net-pointer-as-an-rcu-one-a.patch b/queue-6.6/net-treat-possible_net_t-net-pointer-as-an-rcu-one-a.patch new file mode 100644 index 0000000000..16d826e2ce --- /dev/null +++ b/queue-6.6/net-treat-possible_net_t-net-pointer-as-an-rcu-one-a.patch @@ -0,0 +1,65 @@ +From fcd784b7fb946f6750ded7f88f9ce2fd88bc1b30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Oct 2023 14:10:23 +0200 +Subject: net: treat possible_net_t net pointer as an RCU one and add + read_pnet_rcu() + +From: Jiri Pirko + +[ Upstream commit 2034d90ae41ae93e30d492ebcf1f06f97a9cfba6 ] + +Make the net pointer stored in possible_net_t structure annotated as +an RCU pointer. Change the access helpers to treat it as such. +Introduce read_pnet_rcu() helper to allow caller to dereference +the net pointer under RCU read lock. + +Signed-off-by: Jiri Pirko +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +Stable-dep-of: 71b8471c93fa ("ipv4: use RCU protection in ipv4_default_advmss()") +Signed-off-by: Sasha Levin +--- + include/net/net_namespace.h | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h +index 1befad79a6734..b767bdcd9e122 100644 +--- a/include/net/net_namespace.h ++++ b/include/net/net_namespace.h +@@ -369,21 +369,30 @@ static inline void put_net_track(struct net *net, netns_tracker *tracker) + + typedef struct { + #ifdef CONFIG_NET_NS +- struct net *net; ++ struct net __rcu *net; + #endif + } possible_net_t; + + static inline void write_pnet(possible_net_t *pnet, struct net *net) + { + #ifdef CONFIG_NET_NS +- pnet->net = net; ++ rcu_assign_pointer(pnet->net, net); + #endif + } + + static inline struct net *read_pnet(const possible_net_t *pnet) + { + #ifdef CONFIG_NET_NS +- return pnet->net; ++ return rcu_dereference_protected(pnet->net, true); ++#else ++ return &init_net; ++#endif ++} ++ ++static inline struct net *read_pnet_rcu(possible_net_t *pnet) ++{ ++#ifdef CONFIG_NET_NS ++ return rcu_dereference(pnet->net); + #else + return &init_net; + #endif +-- +2.39.5 + diff --git a/queue-6.6/openvswitch-use-rcu-protection-in-ovs_vport_cmd_fill.patch b/queue-6.6/openvswitch-use-rcu-protection-in-ovs_vport_cmd_fill.patch new file mode 100644 index 0000000000..70005822bd --- /dev/null +++ b/queue-6.6/openvswitch-use-rcu-protection-in-ovs_vport_cmd_fill.patch @@ -0,0 +1,66 @@ +From 5b990f1f002ae421e6d4b4d6792189e0200647ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Feb 2025 13:58:37 +0000 +Subject: openvswitch: use RCU protection in ovs_vport_cmd_fill_info() + +From: Eric Dumazet + +[ Upstream commit 90b2f49a502fa71090d9f4fe29a2f51fe5dff76d ] + +ovs_vport_cmd_fill_info() can be called without RTNL or RCU. + +Use RCU protection and dev_net_rcu() to avoid potential UAF. + +Fixes: 9354d4520342 ("openvswitch: reliable interface indentification in port dumps") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250207135841.1948589-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/openvswitch/datapath.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c +index b7232142c13f8..cb52fac7caa3c 100644 +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -2103,6 +2103,7 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + { + struct ovs_header *ovs_header; + struct ovs_vport_stats vport_stats; ++ struct net *net_vport; + int err; + + ovs_header = genlmsg_put(skb, portid, seq, &dp_vport_genl_family, +@@ -2119,12 +2120,15 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + nla_put_u32(skb, OVS_VPORT_ATTR_IFINDEX, vport->dev->ifindex)) + goto nla_put_failure; + +- if (!net_eq(net, dev_net(vport->dev))) { +- int id = peernet2id_alloc(net, dev_net(vport->dev), gfp); ++ rcu_read_lock(); ++ net_vport = dev_net_rcu(vport->dev); ++ if (!net_eq(net, net_vport)) { ++ int id = peernet2id_alloc(net, net_vport, GFP_ATOMIC); + + if (nla_put_s32(skb, OVS_VPORT_ATTR_NETNSID, id)) +- goto nla_put_failure; ++ goto nla_put_failure_unlock; + } ++ rcu_read_unlock(); + + ovs_vport_get_stats(vport, &vport_stats); + if (nla_put_64bit(skb, OVS_VPORT_ATTR_STATS, +@@ -2145,6 +2149,8 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, + genlmsg_end(skb, ovs_header); + return 0; + ++nla_put_failure_unlock: ++ rcu_read_unlock(); + nla_put_failure: + err = -EMSGSIZE; + error: +-- +2.39.5 + diff --git a/queue-6.6/series b/queue-6.6/series index eb401bc3be..b4765bdfde 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -46,3 +46,35 @@ acpi-x86-add-skip-i2c-clients-quirk-for-vexia-edu-at.patch x86-mm-tlb-only-trim-the-mm_cpumask-once-a-second.patch orangefs-fix-a-oob-in-orangefs_debug_write.patch asoc-intel-bytcr_rt5640-add-dmi-quirk-for-vexia-edu-.patch +clocksource-use-pr_info-for-checking-clocksource-syn.patch +clocksource-use-migrate_disable-to-avoid-calling-get.patch +ipv4-add-rcu-protection-to-ip4_dst_hoplimit.patch +net-treat-possible_net_t-net-pointer-as-an-rcu-one-a.patch +net-add-dev_net_rcu-helper.patch +ipv4-use-rcu-protection-in-ipv4_default_advmss.patch +ipv4-use-rcu-protection-in-rt_is_expired.patch +ipv4-use-rcu-protection-in-inet_select_addr.patch +net-ipv4-cache-pmtu-for-all-packet-paths-if-multipat.patch +ipv4-use-rcu-protection-in-__ip_rt_update_pmtu.patch +ipv4-icmp-convert-to-dev_net_rcu.patch +flow_dissector-use-rcu-protection-to-fetch-dev_net.patch +ipv6-use-rcu-protection-in-ip6_default_advmss.patch +ipv6-icmp-convert-to-dev_net_rcu.patch +hid-hid-steam-avoid-overwriting-smoothing-parameter.patch +hid-hid-steam-disable-watchdog-instead-of-using-a-he.patch +hid-hid-steam-clean-up-locking.patch +hid-hid-steam-update-list-of-identifiers-from-sdl.patch +hid-hid-steam-add-gamepad-only-mode-switched-to-by-h.patch +hid-hid-steam-remove-pointless-error-message.patch +hid-hid-steam-fix-cleanup-in-probe.patch +hid-hid-steam-add-deck-imu-support.patch +hid-hid-steam-make-sure-rumble-work-is-canceled-on-r.patch +hid-hid-steam-move-hidraw-input-un-registering-to-wo.patch +ndisc-use-rcu-protection-in-ndisc_alloc_skb.patch +neighbour-delete-redundant-judgment-statements.patch +neighbour-use-rcu-protection-in-__neigh_notify.patch +arp-use-rcu-protection-in-arp_xmit.patch +openvswitch-use-rcu-protection-in-ovs_vport_cmd_fill.patch +ndisc-extend-rcu-protection-in-ndisc_send_skb.patch +ipv6-mcast-extend-rcu-protection-in-igmp6_send.patch +ipv6-mcast-add-rcu-protection-to-mld_newpack.patch