]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.6
authorSasha Levin <sashal@kernel.org>
Tue, 18 Feb 2025 12:30:05 +0000 (07:30 -0500)
committerSasha Levin <sashal@kernel.org>
Tue, 18 Feb 2025 12:30:48 +0000 (07:30 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
33 files changed:
queue-6.6/arp-use-rcu-protection-in-arp_xmit.patch [new file with mode: 0644]
queue-6.6/clocksource-use-migrate_disable-to-avoid-calling-get.patch [new file with mode: 0644]
queue-6.6/clocksource-use-pr_info-for-checking-clocksource-syn.patch [new file with mode: 0644]
queue-6.6/flow_dissector-use-rcu-protection-to-fetch-dev_net.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-add-deck-imu-support.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-add-gamepad-only-mode-switched-to-by-h.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-avoid-overwriting-smoothing-parameter.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-clean-up-locking.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-disable-watchdog-instead-of-using-a-he.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-fix-cleanup-in-probe.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-make-sure-rumble-work-is-canceled-on-r.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-move-hidraw-input-un-registering-to-wo.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-remove-pointless-error-message.patch [new file with mode: 0644]
queue-6.6/hid-hid-steam-update-list-of-identifiers-from-sdl.patch [new file with mode: 0644]
queue-6.6/ipv4-add-rcu-protection-to-ip4_dst_hoplimit.patch [new file with mode: 0644]
queue-6.6/ipv4-icmp-convert-to-dev_net_rcu.patch [new file with mode: 0644]
queue-6.6/ipv4-use-rcu-protection-in-__ip_rt_update_pmtu.patch [new file with mode: 0644]
queue-6.6/ipv4-use-rcu-protection-in-inet_select_addr.patch [new file with mode: 0644]
queue-6.6/ipv4-use-rcu-protection-in-ipv4_default_advmss.patch [new file with mode: 0644]
queue-6.6/ipv4-use-rcu-protection-in-rt_is_expired.patch [new file with mode: 0644]
queue-6.6/ipv6-icmp-convert-to-dev_net_rcu.patch [new file with mode: 0644]
queue-6.6/ipv6-mcast-add-rcu-protection-to-mld_newpack.patch [new file with mode: 0644]
queue-6.6/ipv6-mcast-extend-rcu-protection-in-igmp6_send.patch [new file with mode: 0644]
queue-6.6/ipv6-use-rcu-protection-in-ip6_default_advmss.patch [new file with mode: 0644]
queue-6.6/ndisc-extend-rcu-protection-in-ndisc_send_skb.patch [new file with mode: 0644]
queue-6.6/ndisc-use-rcu-protection-in-ndisc_alloc_skb.patch [new file with mode: 0644]
queue-6.6/neighbour-delete-redundant-judgment-statements.patch [new file with mode: 0644]
queue-6.6/neighbour-use-rcu-protection-in-__neigh_notify.patch [new file with mode: 0644]
queue-6.6/net-add-dev_net_rcu-helper.patch [new file with mode: 0644]
queue-6.6/net-ipv4-cache-pmtu-for-all-packet-paths-if-multipat.patch [new file with mode: 0644]
queue-6.6/net-treat-possible_net_t-net-pointer-as-an-rcu-one-a.patch [new file with mode: 0644]
queue-6.6/openvswitch-use-rcu-protection-in-ovs_vport_cmd_fill.patch [new file with mode: 0644]
queue-6.6/series

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 (file)
index 0000000..70d78b9
--- /dev/null
@@ -0,0 +1,45 @@
+From a4373a52c02c78578e1f41a621e5297f376afd73 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:58:36 +0000
+Subject: arp: use RCU protection in arp_xmit()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250207135841.1948589-5-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..2122767
--- /dev/null
@@ -0,0 +1,82 @@
+From f4b49af215b2381b38525bc1225c90c5e29806f2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <longman@redhat.com>
+
+[ 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 <bigeasy@linutronix.de>
+Signed-off-by: Waiman Long <longman@redhat.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
+Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/all/20250131173323.891943-2-longman@redhat.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..b944f8a
--- /dev/null
@@ -0,0 +1,45 @@
+From b28dd542264fa90d8c0988eeac61f7ceba087a80 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2025 20:54:41 -0500
+Subject: clocksource: Use pr_info() for "Checking clocksource synchronization"
+ message
+
+From: Waiman Long <longman@redhat.com>
+
+[ 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 <longman@redhat.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
+Acked-by: John Stultz <jstultz@google.com>
+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 <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..486d5dc
--- /dev/null
@@ -0,0 +1,81 @@
+From 8335e45f7d639dec74d53ee96a1ab33d7cf6f737 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:17 +0000
+Subject: flow_dissector: use RCU protection to fetch dev_net()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250205155120.1676781-10-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..96d5424
--- /dev/null
@@ -0,0 +1,286 @@
+From 985feefa48ba4b5652d705192fca2f19e97672ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 20 Apr 2024 12:34:18 +0000
+Subject: HID: hid-steam: Add Deck IMU support
+
+From: Max Maisel <mmm-1@posteo.net>
+
+[ 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 <mmm-1@posteo.net>
+Reviewed-by: Vicki Pfau <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..fe03bfd
--- /dev/null
@@ -0,0 +1,222 @@
+From 327baaefb2fef1b920ba1500e5b53d2a664b6d4b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <vi@endrift.com>
+
+[ 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 <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..c49d64f
--- /dev/null
@@ -0,0 +1,55 @@
+From 0f8400facd03cd52f854dec6f79173f69876931d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 19:38:31 -0800
+Subject: HID: hid-steam: Avoid overwriting smoothing parameter
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ 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 <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..5d3acd5
--- /dev/null
@@ -0,0 +1,334 @@
+From ef363458e9ac38c1019db4749f54cb142646cb16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 19:38:33 -0800
+Subject: HID: hid-steam: Clean up locking
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ 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 <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..162b092
--- /dev/null
@@ -0,0 +1,114 @@
+From 6d2bc1a78f46ebade44c91cbe6652762bb876f68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 19:38:32 -0800
+Subject: HID: hid-steam: Disable watchdog instead of using a heartbeat
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ 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 <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..67a8269
--- /dev/null
@@ -0,0 +1,99 @@
+From e0d238c36b7994c94fcf698c471e21babf731599 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jan 2024 17:35:06 +0300
+Subject: HID: hid-steam: Fix cleanup in probe()
+
+From: Dan Carpenter <dan.carpenter@linaro.org>
+
+[ 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 <dan.carpenter@linaro.org>
+Reviewed-by: Vicki Pfau <vi@endrift.com>
+Link: https://lore.kernel.org/r/1fd87904-dabf-4879-bb89-72d13ebfc91e@moroto.mountain
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..f1fa9bd
--- /dev/null
@@ -0,0 +1,38 @@
+From 47e14b4af54f700a9b0a0bf11817d43f1857db0e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Dec 2024 18:34:24 -0800
+Subject: HID: hid-steam: Make sure rumble work is canceled on removal
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ 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 <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..590e89f
--- /dev/null
@@ -0,0 +1,117 @@
+From 9e2f8177b284e249ae0a53a5658c6e41bedb7d9e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Feb 2025 19:55:27 -0800
+Subject: HID: hid-steam: Move hidraw input (un)registering to work
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ 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 <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..4ddfcde
--- /dev/null
@@ -0,0 +1,55 @@
+From b89d1a0d7931a1018aee93f3306efe59242293ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 12 Jan 2024 17:34:14 +0300
+Subject: HID: hid-steam: remove pointless error message
+
+From: Dan Carpenter <dan.carpenter@linaro.org>
+
+[ 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 <dan.carpenter@linaro.org>
+Reviewed-by: Vicki Pfau <vi@endrift.com>
+Link: https://lore.kernel.org/r/305898fb-6bd4-4749-806c-05ec51bbeb80@moroto.mountain
+Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..a7539b8
--- /dev/null
@@ -0,0 +1,410 @@
+From fe446bc089a6c7147b445f819cba6427d4f8a2fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 19 Dec 2023 19:38:35 -0800
+Subject: HID: hid-steam: Update list of identifiers from SDL
+
+From: Vicki Pfau <vi@endrift.com>
+
+[ 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 <vi@endrift.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Stable-dep-of: 79504249d7e2 ("HID: hid-steam: Move hidraw input (un)registering to work")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..68b6265
--- /dev/null
@@ -0,0 +1,47 @@
+From 10b48585546bad0a85656701c640393bfa26df41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:10 +0000
+Subject: ipv4: add RCU protection to ip4_dst_hoplimit()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250205155120.1676781-3-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..b41c874
--- /dev/null
@@ -0,0 +1,150 @@
+From 58a0718e856c47d597cb03e1ddbce04ae65eba2b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:16 +0000
+Subject: ipv4: icmp: convert to dev_net_rcu()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <kuba@kernel.org>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20250205155120.1676781-9-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..c5500c8
--- /dev/null
@@ -0,0 +1,77 @@
+From 8c048c1c6f1ad0fd47a090345cb9e675d1317653 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:15 +0000
+Subject: ipv4: use RCU protection in __ip_rt_update_pmtu()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Link: https://patch.msgid.link/20250205155120.1676781-8-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..b61619e
--- /dev/null
@@ -0,0 +1,41 @@
+From 20f70039b88fe3b8aa98048e9a3c33eebbfaf4ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:14 +0000
+Subject: ipv4: use RCU protection in inet_select_addr()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Link: https://patch.msgid.link/20250205155120.1676781-7-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..502f421
--- /dev/null
@@ -0,0 +1,48 @@
+From 7966558932d043b89d988916b242917a170b33c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:12 +0000
+Subject: ipv4: use RCU protection in ipv4_default_advmss()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250205155120.1676781-5-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..213248f
--- /dev/null
@@ -0,0 +1,44 @@
+From 991bba8ee88b4f3b012da9d98d60a1fab39f0352 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:13 +0000
+Subject: ipv4: use RCU protection in rt_is_expired()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250205155120.1676781-6-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..ebf6430
--- /dev/null
@@ -0,0 +1,191 @@
+From 2cd78e698c9ab4384991c6a383352e2fb889eef0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:19 +0000
+Subject: ipv6: icmp: convert to dev_net_rcu()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Link: https://patch.msgid.link/20250205155120.1676781-12-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..035df67
--- /dev/null
@@ -0,0 +1,80 @@
+From c21d9a56bd3435b3017070bb73df4c8cabd630d0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 14:10:21 +0000
+Subject: ipv6: mcast: add RCU protection to mld_newpack()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Link: https://patch.msgid.link/20250212141021.1663666-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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)) {
+               /* <draft-ietf-magma-mld-source-05.txt>:
+                * 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 (file)
index 0000000..a47e91d
--- /dev/null
@@ -0,0 +1,105 @@
+From 5cdc9562085f1ae474e09332713509620c55774d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:58:40 +0000
+Subject: ipv6: mcast: extend RCU protection in igmp6_send()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250207135841.1948589-9-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..aec3df4
--- /dev/null
@@ -0,0 +1,49 @@
+From f5a24e73ae93c7023166dea4c5d9b609932a6e39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:18 +0000
+Subject: ipv6: use RCU protection in ip6_default_advmss()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250205155120.1676781-11-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..a91eb54
--- /dev/null
@@ -0,0 +1,72 @@
+From 835aff5cd98c08aabf26924c57283e7f9912cafe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:58:39 +0000
+Subject: ndisc: extend RCU protection in ndisc_send_skb()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250207135841.1948589-8-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..a5c5d83
--- /dev/null
@@ -0,0 +1,59 @@
+From 647df0cc795f962a52832fe40c8a2b4ea1f081bc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:58:34 +0000
+Subject: ndisc: use RCU protection in ndisc_alloc_skb()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250207135841.1948589-3-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..c3800f4
--- /dev/null
@@ -0,0 +1,40 @@
+From 61f2092651726d360fd87255368c59b26a5b1830 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Aug 2024 12:32:45 +0800
+Subject: neighbour: delete redundant judgment statements
+
+From: Li Zetao <lizetao1@huawei.com>
+
+[ 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 <lizetao1@huawei.com>
+Reviewed-by: Petr Machata <petrm@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: becbd5850c03 ("neighbour: use RCU protection in __neigh_notify()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..e697040
--- /dev/null
@@ -0,0 +1,58 @@
+From 245b248e640dd4b9c338a9b30646f92876c3ff92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:58:35 +0000
+Subject: neighbour: use RCU protection in __neigh_notify()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: David Ahern <dsahern@kernel.org>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250207135841.1948589-4-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..1f03fc6
--- /dev/null
@@ -0,0 +1,62 @@
+From bdcf9427705b16f16f33183b8fc4a84d5e619506 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Feb 2025 15:51:09 +0000
+Subject: net: add dev_net_rcu() helper
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250205155120.1676781-2-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 71b8471c93fa ("ipv4: use RCU protection in ipv4_default_advmss()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..2b2f8e5
--- /dev/null
@@ -0,0 +1,292 @@
+From b8a26376a2ec662e33d84dd6370300ed2ad9aad6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 8 Nov 2024 09:34:24 +0000
+Subject: net: ipv4: Cache pmtu for all packet paths if multipath enabled
+
+From: Vladimir Vdovin <deliran@verdict.gg>
+
+[ 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 <deliran@verdict.gg>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Link: https://patch.msgid.link/20241108093427.317942-1-deliran@verdict.gg
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 139512191bd0 ("ipv4: use RCU protection in __ip_rt_update_pmtu()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..16d826e
--- /dev/null
@@ -0,0 +1,65 @@
+From fcd784b7fb946f6750ded7f88f9ce2fd88bc1b30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <jiri@nvidia.com>
+
+[ 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 <jiri@nvidia.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 71b8471c93fa ("ipv4: use RCU protection in ipv4_default_advmss()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 (file)
index 0000000..7000582
--- /dev/null
@@ -0,0 +1,66 @@
+From 5b990f1f002ae421e6d4b4d6792189e0200647ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 13:58:37 +0000
+Subject: openvswitch: use RCU protection in ovs_vport_cmd_fill_info()
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ 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 <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250207135841.1948589-6-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
index eb401bc3be904a7209183b15bbea389fe6d38f69..b4765bdfdea2dd82c8a6d6de3fb5d85d1ed6460a 100644 (file)
@@ -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