diff options
| author | Ali Ahmet Memis <ali@iusegentoo.com> | 2026-08-21 01:45:27 +0000 |
|---|---|---|
| committer | Stafford Horne <shorne@gmail.com> | 2026-08-29 07:32:26 +0100 |
| commit | 78004e9a87f240df03e2f73120d291763c32e0a7 (patch) | |
| tree | 137c22dd795222931b9d2bf2501d37cd766741aa /net/sctp/offload.c | |
| download | linux-stable-78004e9a87f240df03e2f73120d291763c32e0a7.tar.gz linux-stable-78004e9a87f240df03e2f73120d291763c32e0a7.zip | |
openrisc: fix arbitrary kernel memory access via or1k_atomic syscallgrafted
sys_or1k_atomic() (syscall 244 in the "or1k" ABI) takes two user
pointers, v1 and v2, and swaps the words they point to in hand-written
assembly.
l.lwz r29,0(r4)
l.lwz r27,0(r5)
l.sw 0(r4),r27
l.sw 0(r5),r29
The pointers are not checked with access_ok(). The four memory
accesses also have no exception table entries.
A caller passes a kernel address as either pointer, and the syscall
reads from and writes to it directly.
This gives an unprivileged process a kernel read/write primitive. It
overwrites kernel data such as the sys_call_table, gaining code
execution in kernel context.
Check both pointers before entering the critical section. Add fixups
for the four memory accesses so faults on valid but unmapped user
addresses return -EFAULT.
[shorne@gmail.com: fix comment style]
Fixes: 9d02a4283e9c ("OpenRISC: Boot code")
Cc: stable@vger.kernel.org
Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Stafford Horne <shorne@gmail.com>
Diffstat (limited to 'net/sctp/offload.c')
| -rw-r--r-- | net/sctp/offload.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/net/sctp/offload.c b/net/sctp/offload.c new file mode 100644 index 000000000..e6f863c03 --- /dev/null +++ b/net/sctp/offload.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * sctp_offload - GRO/GSO Offloading for SCTP + * + * Copyright (C) 2015, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/kprobes.h> +#include <linux/socket.h> +#include <linux/sctp.h> +#include <linux/proc_fs.h> +#include <linux/vmalloc.h> +#include <linux/module.h> +#include <linux/kfifo.h> +#include <linux/time.h> +#include <net/net_namespace.h> + +#include <linux/skbuff.h> +#include <net/sctp/sctp.h> +#include <net/sctp/checksum.h> +#include <net/protocol.h> +#include <net/gso.h> + +static __le32 sctp_gso_make_checksum(struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + skb->csum_not_inet = 0; + /* csum and csum_start in GSO CB may be needed to do the UDP + * checksum when it's a UDP tunneling packet. + */ + SKB_GSO_CB(skb)->csum = (__force __wsum)~0; + SKB_GSO_CB(skb)->csum_start = skb_headroom(skb) + skb->len; + return sctp_compute_cksum(skb, skb_transport_offset(skb)); +} + +static struct sk_buff *sctp_gso_segment(struct sk_buff *skb, + netdev_features_t features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct sctphdr *sh; + + if (!skb_is_gso_sctp(skb)) + goto out; + + sh = sctp_hdr(skb); + if (!pskb_may_pull(skb, sizeof(*sh))) + goto out; + + __skb_pull(skb, sizeof(*sh)); + + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + struct skb_shared_info *pinfo = skb_shinfo(skb); + struct sk_buff *frag_iter; + + pinfo->gso_segs = 0; + if (skb->len != skb->data_len) { + /* Means we have chunks in here too */ + pinfo->gso_segs++; + } + + skb_walk_frags(skb, frag_iter) + pinfo->gso_segs++; + + segs = NULL; + goto out; + } + + segs = skb_segment(skb, (features | NETIF_F_HW_CSUM) & ~NETIF_F_SG); + if (IS_ERR(segs)) + goto out; + + /* All that is left is update SCTP CRC if necessary */ + if (!(features & NETIF_F_SCTP_CRC)) { + for (skb = segs; skb; skb = skb->next) { + if (skb->ip_summed == CHECKSUM_PARTIAL) { + sh = sctp_hdr(skb); + sh->checksum = sctp_gso_make_checksum(skb); + } + } + } + +out: + return segs; +} + +static const struct net_offload sctp_offload = { + .callbacks = { + .gso_segment = sctp_gso_segment, + }, +}; + +static const struct net_offload sctp6_offload = { + .callbacks = { + .gso_segment = sctp_gso_segment, + }, +}; + +int __init sctp_offload_init(void) +{ + int ret; + + ret = inet_add_offload(&sctp_offload, IPPROTO_SCTP); + if (ret) + goto out; + + ret = inet6_add_offload(&sctp6_offload, IPPROTO_SCTP); + if (ret) + goto ipv4; + + return ret; + +ipv4: + inet_del_offload(&sctp_offload, IPPROTO_SCTP); +out: + return ret; +} |
