[PATCH] phonet: pep: fix out-of-bounds reads in pep_ctrlreq_error() and pep_sock_accept()

From: Hui Peng

Date: Sat Sep 19 2026 - 17:32:00 EST


Fix three packet-parsing and locking bugs in Phonet Pipe End Point
(`net/phonet/pep.c`):

1. In `pep_ctrlreq_error()`, `oph = pnp_hdr(oskb)` is dereferenced at
`oph->pep_type` (`oph->data[0]`, offset 4 from `pnp_hdr(oskb)`)
before verifying that `oph->data[0]` lies within the linear `oskb`
data area. When called from `pep_do_rcv()`
(`PN_PIPE_INVALID_HANDLE`), `oskb->data` still points to `oph` and
only `pskb_may_pull(skb, sizeof(*hdr))` (4 bytes) was checked,
causing `oph->pep_type` to read 1 byte past `oskb->tail` and echo it
back to the peer in `PNS_PEP_CTRL_RESP`. Ensure `pskb_may_pull()`
covers `(oph->data + 1) - oskb->data` bytes (and `sizeof(*hdr) + 1`
in `pipe_do_rcv()`).
2. In `pep_sock_accept()`, `n_sb = hdr->data[3]` is read from the
`PNS_PIPE_CONNECT_REQ` header, but `__skb_pull(skb, sizeof(*hdr) +
4)` is omitted before the `pep_get_sb()` loop, causing `pep_get_sb()`
to parse the 8-byte `pnpipehdr` and connect-request header as
sub-blocks, and `PN_PIPE_SB_ALIGNED_DATA` reads `data[0]` without
checking `len >= 1`.
3. In `pep_setsockopt()` (`PNPIPE_ENCAP`), `release_sock(sk)` is dropped
around `gprs_attach(sk)`, and `pn->ifindex` is assigned afterwards
without re-acquiring `lock_sock(sk)` or checking `SOCK_DEAD` /
concurrent attachment.

Fixes: 9641458d3ec4 ("Phonet: Pipe End Point for Phonet Pipes protocol")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@xxxxxxxxx>

---
net/phonet/pep.c | 35 +++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index bd1cdd00edfa..5511770bb21c 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -192,15 +192,21 @@ static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code,
static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code,
gfp_t priority)
{
- const struct pnpipehdr *oph = pnp_hdr(oskb);
+ const struct pnpipehdr *oph;
struct sk_buff *skb;
struct pnpipehdr *ph;
struct sockaddr_pn dst;
- u8 data[4] = {
- oph->pep_type, /* PEP type */
- code, /* error code, at an unusual offset */
- PAD, PAD,
- };
+ u8 data[4];
+
+ oph = pnp_hdr(oskb);
+ if (!pskb_may_pull(oskb, (unsigned int)((oph->data + 1) - oskb->data)))
+ return -EINVAL;
+
+ oph = pnp_hdr(oskb);
+ data[0] = oph->pep_type; /* PEP type */
+ data[1] = code; /* error code, at an unusual offset */
+ data[2] = PAD;
+ data[3] = PAD;

skb = pep_alloc_skb(sk, data, 4, priority);
if (!skb)
@@ -377,6 +383,8 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
break;

case PNS_PEP_CTRL_REQ:
+ if (!pskb_may_pull(skb, sizeof(*hdr) + 1))
+ break;
if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
sk_drops_inc(sk);
break;
@@ -823,6 +831,7 @@ static struct sock *pep_sock_accept(struct sock *sk,

/* Parse sub-blocks (options) */
n_sb = hdr->data[3];
+ __skb_pull(skb, sizeof(*hdr) + 4);
while (n_sb > 0) {
u8 type, buf[1], len = sizeof(buf);
const u8 *data = pep_get_sb(skb, &type, &len, buf);
@@ -836,6 +845,8 @@ static struct sock *pep_sock_accept(struct sock *sk,
peer_type = (peer_type & 0xff00) | data[0];
break;
case PN_PIPE_SB_ALIGNED_DATA:
+ if (len < 1)
+ goto drop;
aligned = data[0] != 0;
break;
}
@@ -1048,8 +1059,16 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
release_sock(sk);
err = gprs_attach(sk);
if (err > 0) {
- pn->ifindex = err;
- err = 0;
+ lock_sock(sk);
+ if (sock_flag(sk, SOCK_DEAD) || pn->ifindex) {
+ release_sock(sk);
+ gprs_detach(sk);
+ err = -EINVAL;
+ } else {
+ pn->ifindex = err;
+ err = 0;
+ release_sock(sk);
+ }
}
} else {
pn->ifindex = 0;