* [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop
@ 2026-10-31 22:10 Jérémy Jean
2026-10-31 22:10 ` [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update Jérémy Jean
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Jérémy Jean @ 2026-10-31 22:10 UTC (permalink / raw)
To: Subash Abhinov Kasiviswanathan, Sean Tranchetti
Cc: netdev, linux-kernel, Jérémy Jean, stable
A struct rmnet_port stores a pointer to the most recently created
RMNET VND in port->rmnet_dev, but userspace can delete that VND while
the port still has another attached VND. When RMNET later sends a
buffered TX skb, a failure in __skb_linearize() makes rmnet_send_skb()
update the drop counter through that stale pointer, which causes a UAF.
Account TX drops on the lower device instead of port->rmnet_dev.
Fixes: 64b5d1f8f2d1 ("net: qualcomm: rmnet: add tx packets aggregation")
Cc: stable@vger.kernel.org
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index e6f48dc9fe64..4df75f4215fa 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -543,10 +543,7 @@ static void rmnet_send_skb(struct rmnet_port *port, struct sk_buff *skb)
{
if (skb_needs_linearize(skb, port->dev->features)) {
if (unlikely(__skb_linearize(skb))) {
- struct rmnet_priv *priv;
-
- priv = netdev_priv(port->rmnet_dev);
- this_cpu_inc(priv->pcpu_stats->stats.tx_drops);
+ dev_core_stats_tx_dropped_inc(port->dev);
dev_kfree_skb_any(skb);
return;
}
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update
2026-10-31 22:10 [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop Jérémy Jean
@ 2026-10-31 22:10 ` Jérémy Jean
2026-10-31 22:13 ` netdev-bot+sinfo
2026-10-31 22:13 ` [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop netdev-bot+sinfo
2026-11-01 22:11 ` netdev-bot+sashiko
2 siblings, 1 reply; 6+ messages in thread
From: Jérémy Jean @ 2026-10-31 22:10 UTC (permalink / raw)
To: Subash Abhinov Kasiviswanathan, Sean Tranchetti
Cc: netdev, linux-kernel, Jérémy Jean, stable
If userspace reduces the TX aggregation byte limit while a buffered skb
is pending, subtracting the skb length from the new limit underflows.
The later comparison with unsigned skb->len then lets the buffered skb
grow past the limit.
Check lengths before subtracting. Flush a buffered skb if it is already
at or above the new byte limit.
Fixes: 64b5d1f8f2d1 ("net: qualcomm: rmnet: add tx packets aggregation")
Cc: stable@vger.kernel.org
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index e6f48dc9fe64..205ac81f2c82 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -594,7 +594,7 @@ unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port
struct timespec64 diff, last;
unsigned int len = skb->len;
struct sk_buff *agg_skb;
- int size;
+ unsigned int size;
spin_lock_bh(&port->agg_lock);
memcpy(&last, &port->agg_last, sizeof(struct timespec64));
@@ -606,13 +606,14 @@ unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port
*/
new_packet:
diff = timespec64_sub(port->agg_last, last);
- size = port->egress_agg_params.bytes - skb->len;
+ size = port->egress_agg_params.bytes;
- if (size < 0) {
+ if (skb->len > size) {
/* dropped */
spin_unlock_bh(&port->agg_lock);
return 0;
}
+ size -= skb->len;
if (diff.tv_sec > 0 || diff.tv_nsec > RMNET_AGG_BYPASS_TIME_NSEC ||
size == 0)
@@ -630,9 +631,8 @@ unsigned int rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port
goto schedule;
}
diff = timespec64_sub(port->agg_last, port->agg_time);
- size = port->egress_agg_params.bytes - port->skbagg_head->len;
-
- if (skb->len > size) {
+ if (port->skbagg_head->len >= port->egress_agg_params.bytes ||
+ skb->len > port->egress_agg_params.bytes - port->skbagg_head->len) {
agg_skb = port->skbagg_head;
reset_aggr_params(port);
spin_unlock_bh(&port->agg_lock);
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update
2026-10-31 22:10 ` [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update Jérémy Jean
@ 2026-10-31 22:13 ` netdev-bot+sinfo
0 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sinfo @ 2026-10-31 22:13 UTC (permalink / raw)
To: Jérémy Jean
Cc: Subash Abhinov Kasiviswanathan, Sean Tranchetti, netdev,
linux-kernel, stable
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
- What hardware the change was tested on. For driver fixes please
mention the device (and if relevant firmware version) used for
testing, or say that the change was not tested on real hardware.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop
2026-10-31 22:10 [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop Jérémy Jean
2026-10-31 22:10 ` [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update Jérémy Jean
@ 2026-10-31 22:13 ` netdev-bot+sinfo
2026-11-01 22:11 ` netdev-bot+sashiko
2 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sinfo @ 2026-10-31 22:13 UTC (permalink / raw)
To: Jérémy Jean
Cc: Subash Abhinov Kasiviswanathan, Sean Tranchetti, netdev,
linux-kernel, stable
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
- Whether the issue was actually triggered, or is only theoretical
(e.g. found by code inspection). If it was triggered please include
the symptoms, like the stack trace or error messages.
- What hardware the change was tested on. For driver fixes please
mention the device (and if relevant firmware version) used for
testing, or say that the change was not tested on real hardware.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop
2026-10-31 22:10 [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop Jérémy Jean
2026-10-31 22:10 ` [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update Jérémy Jean
2026-10-31 22:13 ` [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop netdev-bot+sinfo
@ 2026-11-01 22:11 ` netdev-bot+sashiko
2026-11-01 22:59 ` Jérémy Jean
2 siblings, 1 reply; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-01 22:11 UTC (permalink / raw)
To: Jeremy.Jean
Cc: subash.a.kasiviswanathan, sean.tranchetti, netdev, linux-kernel,
stable, kuba
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 (1) · Medium: 0 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The fix is incomplete: the stale port->rmnet_dev UAF described
in the commit message can still be reached.
Pre-existing issues:
- [High] Teardown race: rmnet_port can be freed while its hrtimer is
still armed.
--
net: qualcomm: rmnet: avoid stale VND access on TX drop
This commit changes rmnet_send_skb() so that a TX drop after a failed
__skb_linearize() is counted on the lower device with
dev_core_stats_tx_dropped_inc(). Before, the drop was counted through
port->rmnet_dev, which can still point at a VND that has been deleted.
> diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> index 39d6d084e73f0..bd68d60b50d35 100644
> --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
> @@ -543,10 +543,7 @@ static void rmnet_send_skb(struct rmnet_port *port, struct sk_buff *skb)
> {
> if (skb_needs_linearize(skb, port->dev->features)) {
> if (unlikely(__skb_linearize(skb))) {
> - struct rmnet_priv *priv;
> -
> - priv = netdev_priv(port->rmnet_dev);
> - this_cpu_inc(priv->pcpu_stats->stats.tx_drops);
[Severity: High]
This removes one reader of the stale port->rmnet_dev. Can the stale
pointer still be reached another way?
rmnet_newlink() is the only function that writes port->rmnet_dev.
rmnet_dellink() does not clear or reassign it when the VND it points to
is deleted. rmnet_unregister_bridge() still uses it on the real-device
branch:
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c:rmnet_unregister_bridge() {
...
rmnet_dev = port->rmnet_dev;
if (!port->nr_rmnet_devs) {
...
} else {
/* real device */
bridge_dev = port->bridge_ep;
...
}
netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
...
}
This sequence seems to reach it without any race:
1. Create VNDs A and B on real device R, so port->rmnet_dev = B.
2. Delete B. nr_rmnet_devs drops to 1 and B is unregistered and freed
(needs_free_netdev), but port->rmnet_dev still points at B.
3. Run "ip link set S master A". rmnet_add_bridge() only rejects
nr_rmnet_devs > 1, so the call succeeds. It puts R's port into
bridge mode but does not update R's port->rmnet_dev.
4. Unregister R:
rmnet_config_notify_cb(NETDEV_UNREGISTER)
rmnet_force_unassociate_device(R)
rmnet_unregister_bridge(port)
netdev_upper_dev_unlink(S, B) <- B already freed
__netdev_upper_dev_unlink()
__netdev_upper_dev_unlink() passes B to the PRECHANGEUPPER and
CHANGEUPPER notifiers. It then calls __netdev_update_lower_level(B),
which writes to B, and __netdev_walk_all_upper_dev(B), which walks B's
adjacency lists.
The real S->A adjacency is also never removed. Does that leak the
reference on A, so that unregistering A later hangs in
netdev_wait_allrefs()?
Should port->rmnet_dev be kept valid in rmnet_dellink() instead? The
other option is to stop using it in rmnet_unregister_bridge() as well,
for example by using the slave port's rmnet_dev or
netdev_master_upper_dev_get(bridge_ep).
> + dev_core_stats_tx_dropped_inc(port->dev);
[Severity: High]
This is a pre-existing issue and was not introduced by this patch. Can
rmnet_send_skb() run on an rmnet_port that has already been freed? If
so, both port->dev->features and the new
dev_core_stats_tx_dropped_inc(port->dev) read freed memory.
When the last VND is deleted, rmnet_dellink() tears down the port before
it unregisters the VND:
netdev_upper_dev_unlink(real_dev, dev);
rmnet_unregister_real_device(real_dev);
unregister_netdevice_queue(dev, head);
rmnet_unregister_real_device() then does:
rmnet_map_tx_aggregate_exit(port);
netdev_rx_handler_unregister(real_dev);
kfree(port);
Nothing marks the port as shutting down. With TX aggregation enabled
(egress_agg_params.count > 1, set through ethtool coalesce), a transmit
on another CPU at the same time could go like this:
CPU1
rmnet_vnd_start_xmit()
rmnet_egress_handler()
port = rmnet_get_port_rcu(skb->dev); <- before rx_handler is NULL
rmnet_map_egress_handler()
rmnet_map_tx_aggregate()
spin_lock_bh(&port->agg_lock); <- waits for CPU2
CPU2
rmnet_unregister_real_device()
rmnet_map_tx_aggregate_exit()
hrtimer_cancel(&port->hrtimer);
cancel_work_sync(&port->agg_wq);
spin_lock_bh(&port->agg_lock);
... frees skbagg_head ...
spin_unlock_bh(&port->agg_lock);
CPU1 then takes agg_lock, sets port->skbagg_head with skb_copy_expand()
and re-arms the timer:
hrtimer_start(&port->hrtimer,
ns_to_ktime(port->egress_agg_params.time_nsec),
HRTIMER_MODE_REL);
CPU2 continues:
netdev_rx_handler_unregister() <- synchronize_net() waits for CPU1
kfree(port); <- hrtimer still queued
When the timer fires, rmnet_map_flush_tx_packet_queue() calls
schedule_work(&port->agg_wq) on the freed port. The work then reaches
rmnet_send_skb() through rmnet_map_flush_tx_packet_work(). The
aggregated skb also seems to leak.
synchronize_net() waits for the reader to finish, but nothing cancels
the timer that the reader armed. Would a shutdown flag checked under
agg_lock work here, or a second cancel after
netdev_rx_handler_unregister()?
This looks like it comes from the TX aggregation code added by the
commit in the Fixes: tag.
> dev_kfree_skb_any(skb);
> return;
> }
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261031221052.1642262-1-Jeremy.Jean%40oss.cyber.gouv.fr
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop
2026-11-01 22:11 ` netdev-bot+sashiko
@ 2026-11-01 22:59 ` Jérémy Jean
0 siblings, 0 replies; 6+ messages in thread
From: Jérémy Jean @ 2026-11-01 22:59 UTC (permalink / raw)
To: netdev-bot+sashiko
Cc: subash.a.kasiviswanathan, sean.tranchetti, netdev, linux-kernel,
stable, kuba
On 2026-11-01 23:11, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider.
>
> Critical: 0 · High: 1 (1) · Medium: 0 · Low: 0
>
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let
> patchwork
> know by including "pw-bot: cr" as a separate line at the end of your
> reply
> (one such reply per series is enough).
>
> - [High] The fix is incomplete: the stale port->rmnet_dev UAF described
> in the commit message can still be reached.
>
> Pre-existing issues:
> - [High] Teardown race: rmnet_port can be freed while its hrtimer is
> still armed.
>
> --
>
> net: qualcomm: rmnet: avoid stale VND access on TX drop
>
> This commit changes rmnet_send_skb() so that a TX drop after a failed
> __skb_linearize() is counted on the lower device with
> dev_core_stats_tx_dropped_inc(). Before, the drop was counted through
> port->rmnet_dev, which can still point at a VND that has been deleted.
>
>> diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
>> b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
>> index 39d6d084e73f0..bd68d60b50d35 100644
>> --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
>> +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
>> @@ -543,10 +543,7 @@ static void rmnet_send_skb(struct rmnet_port
>> *port, struct sk_buff *skb)
>> {
>> if (skb_needs_linearize(skb, port->dev->features)) {
>> if (unlikely(__skb_linearize(skb))) {
>> - struct rmnet_priv *priv;
>> -
>> - priv = netdev_priv(port->rmnet_dev);
>> - this_cpu_inc(priv->pcpu_stats->stats.tx_drops);
>
> [Severity: High]
> This removes one reader of the stale port->rmnet_dev. Can the stale
> pointer still be reached another way?
>
> rmnet_newlink() is the only function that writes port->rmnet_dev.
> rmnet_dellink() does not clear or reassign it when the VND it points to
> is deleted. rmnet_unregister_bridge() still uses it on the real-device
> branch:
>
> drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c:rmnet_unregister_bridge()
> {
> ...
> rmnet_dev = port->rmnet_dev;
> if (!port->nr_rmnet_devs) {
> ...
> } else {
> /* real device */
> bridge_dev = port->bridge_ep;
> ...
> }
>
> netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
> ...
> }
>
> This sequence seems to reach it without any race:
>
> 1. Create VNDs A and B on real device R, so port->rmnet_dev = B.
>
> 2. Delete B. nr_rmnet_devs drops to 1 and B is unregistered and freed
> (needs_free_netdev), but port->rmnet_dev still points at B.
>
> 3. Run "ip link set S master A". rmnet_add_bridge() only rejects
> nr_rmnet_devs > 1, so the call succeeds. It puts R's port into
> bridge mode but does not update R's port->rmnet_dev.
>
> 4. Unregister R:
>
> rmnet_config_notify_cb(NETDEV_UNREGISTER)
> rmnet_force_unassociate_device(R)
> rmnet_unregister_bridge(port)
> netdev_upper_dev_unlink(S, B) <- B already freed
> __netdev_upper_dev_unlink()
>
> __netdev_upper_dev_unlink() passes B to the PRECHANGEUPPER and
> CHANGEUPPER notifiers. It then calls __netdev_update_lower_level(B),
> which writes to B, and __netdev_walk_all_upper_dev(B), which walks B's
> adjacency lists.
>
> The real S->A adjacency is also never removed. Does that leak the
> reference on A, so that unregistering A later hangs in
> netdev_wait_allrefs()?
>
> Should port->rmnet_dev be kept valid in rmnet_dellink() instead? The
> other option is to stop using it in rmnet_unregister_bridge() as well,
> for example by using the slave port's rmnet_dev or
> netdev_master_upper_dev_get(bridge_ep).
>
>> + dev_core_stats_tx_dropped_inc(port->dev);
>
> [Severity: High]
> This is a pre-existing issue and was not introduced by this patch. Can
> rmnet_send_skb() run on an rmnet_port that has already been freed? If
> so, both port->dev->features and the new
> dev_core_stats_tx_dropped_inc(port->dev) read freed memory.
>
> When the last VND is deleted, rmnet_dellink() tears down the port
> before
> it unregisters the VND:
>
> netdev_upper_dev_unlink(real_dev, dev);
> rmnet_unregister_real_device(real_dev);
> unregister_netdevice_queue(dev, head);
>
> rmnet_unregister_real_device() then does:
>
> rmnet_map_tx_aggregate_exit(port);
>
> netdev_rx_handler_unregister(real_dev);
>
> kfree(port);
>
> Nothing marks the port as shutting down. With TX aggregation enabled
> (egress_agg_params.count > 1, set through ethtool coalesce), a transmit
> on another CPU at the same time could go like this:
>
> CPU1
> rmnet_vnd_start_xmit()
> rmnet_egress_handler()
> port = rmnet_get_port_rcu(skb->dev); <- before rx_handler is NULL
> rmnet_map_egress_handler()
> rmnet_map_tx_aggregate()
> spin_lock_bh(&port->agg_lock); <- waits for CPU2
>
> CPU2
> rmnet_unregister_real_device()
> rmnet_map_tx_aggregate_exit()
> hrtimer_cancel(&port->hrtimer);
> cancel_work_sync(&port->agg_wq);
> spin_lock_bh(&port->agg_lock);
> ... frees skbagg_head ...
> spin_unlock_bh(&port->agg_lock);
>
> CPU1 then takes agg_lock, sets port->skbagg_head with skb_copy_expand()
> and re-arms the timer:
>
> hrtimer_start(&port->hrtimer,
> ns_to_ktime(port->egress_agg_params.time_nsec),
> HRTIMER_MODE_REL);
>
> CPU2 continues:
>
> netdev_rx_handler_unregister() <- synchronize_net() waits for CPU1
> kfree(port); <- hrtimer still queued
>
> When the timer fires, rmnet_map_flush_tx_packet_queue() calls
> schedule_work(&port->agg_wq) on the freed port. The work then reaches
> rmnet_send_skb() through rmnet_map_flush_tx_packet_work(). The
> aggregated skb also seems to leak.
>
> synchronize_net() waits for the reader to finish, but nothing cancels
> the timer that the reader armed. Would a shutdown flag checked under
> agg_lock work here, or a second cancel after
> netdev_rx_handler_unregister()?
>
> This looks like it comes from the TX aggregation code added by the
> commit in the Fixes: tag.
>
>> dev_kfree_skb_any(skb);
>> return;
>> }
Both comments from Sashiko seem valid, thanks.
I will make a v2 for the first one, and create a dedicated patch for
the second one.
Jérémy
pw-bot: cr
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-01 22:59 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-31 22:10 [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop Jérémy Jean
2026-10-31 22:10 ` [PATCH net] net: qualcomm: rmnet: bound TX aggregates on byte-limit update Jérémy Jean
2026-10-31 22:13 ` netdev-bot+sinfo
2026-10-31 22:13 ` [PATCH net] net: qualcomm: rmnet: avoid stale VND access on TX drop netdev-bot+sinfo
2026-11-01 22:11 ` netdev-bot+sashiko
2026-11-01 22:59 ` Jérémy Jean
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®