Commit fd64898d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '9p-for-6.1-rc7' of https://github.com/martinetd/linux

Pull 9p fixes from Dominique Martinet:

 - 9p now uses a variable size for its recv buffer, but every place
   hadn't been updated properly to use it and some buffer overflows have
   been found and needed fixing.

   There's still one place where msize is incorrectly used in a safety
   check (p9_check_errors), but all paths leading to it should already
   be avoiding overflows and that patch took a bit more time to get
   right for zero-copy requests so I'll send it for 6.2

 - yet another race condition in p9_conn_cancel introduced by a fix for
   a syzbot report in the same place. Maybe at some point we'll get it
   right without burning it all down...

* tag '9p-for-6.1-rc7' of https://github.com/martinetd/linux:
  9p/xen: check logical size for buffer size
  9p/fd: Use P9_HDRSZ for header size
  9p/fd: Fix write overflow in p9_read_work
  9p/fd: fix issue of list_del corruption in p9_fd_cancel()
parents 9f0933ac 391c18cf
...@@ -120,7 +120,7 @@ struct p9_conn { ...@@ -120,7 +120,7 @@ struct p9_conn {
struct list_head unsent_req_list; struct list_head unsent_req_list;
struct p9_req_t *rreq; struct p9_req_t *rreq;
struct p9_req_t *wreq; struct p9_req_t *wreq;
char tmp_buf[7]; char tmp_buf[P9_HDRSZ];
struct p9_fcall rc; struct p9_fcall rc;
int wpos; int wpos;
int wsize; int wsize;
...@@ -202,9 +202,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err) ...@@ -202,9 +202,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err)
list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
list_move(&req->req_list, &cancel_list); list_move(&req->req_list, &cancel_list);
req->status = REQ_STATUS_ERROR;
} }
list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
list_move(&req->req_list, &cancel_list); list_move(&req->req_list, &cancel_list);
req->status = REQ_STATUS_ERROR;
} }
spin_unlock(&m->req_lock); spin_unlock(&m->req_lock);
...@@ -291,7 +293,7 @@ static void p9_read_work(struct work_struct *work) ...@@ -291,7 +293,7 @@ static void p9_read_work(struct work_struct *work)
if (!m->rc.sdata) { if (!m->rc.sdata) {
m->rc.sdata = m->tmp_buf; m->rc.sdata = m->tmp_buf;
m->rc.offset = 0; m->rc.offset = 0;
m->rc.capacity = 7; /* start by reading header */ m->rc.capacity = P9_HDRSZ; /* start by reading header */
} }
clear_bit(Rpending, &m->wsched); clear_bit(Rpending, &m->wsched);
...@@ -314,7 +316,7 @@ static void p9_read_work(struct work_struct *work) ...@@ -314,7 +316,7 @@ static void p9_read_work(struct work_struct *work)
p9_debug(P9_DEBUG_TRANS, "got new header\n"); p9_debug(P9_DEBUG_TRANS, "got new header\n");
/* Header size */ /* Header size */
m->rc.size = 7; m->rc.size = P9_HDRSZ;
err = p9_parse_header(&m->rc, &m->rc.size, NULL, NULL, 0); err = p9_parse_header(&m->rc, &m->rc.size, NULL, NULL, 0);
if (err) { if (err) {
p9_debug(P9_DEBUG_ERROR, p9_debug(P9_DEBUG_ERROR,
...@@ -322,14 +324,6 @@ static void p9_read_work(struct work_struct *work) ...@@ -322,14 +324,6 @@ static void p9_read_work(struct work_struct *work)
goto error; goto error;
} }
if (m->rc.size >= m->client->msize) {
p9_debug(P9_DEBUG_ERROR,
"requested packet size too big: %d\n",
m->rc.size);
err = -EIO;
goto error;
}
p9_debug(P9_DEBUG_TRANS, p9_debug(P9_DEBUG_TRANS,
"mux %p pkt: size: %d bytes tag: %d\n", "mux %p pkt: size: %d bytes tag: %d\n",
m, m->rc.size, m->rc.tag); m, m->rc.size, m->rc.tag);
...@@ -342,6 +336,14 @@ static void p9_read_work(struct work_struct *work) ...@@ -342,6 +336,14 @@ static void p9_read_work(struct work_struct *work)
goto error; goto error;
} }
if (m->rc.size > m->rreq->rc.capacity) {
p9_debug(P9_DEBUG_ERROR,
"requested packet size too big: %d for tag %d with capacity %zd\n",
m->rc.size, m->rc.tag, m->rreq->rc.capacity);
err = -EIO;
goto error;
}
if (!m->rreq->rc.sdata) { if (!m->rreq->rc.sdata) {
p9_debug(P9_DEBUG_ERROR, p9_debug(P9_DEBUG_ERROR,
"No recv fcall for tag %d (req %p), disconnecting!\n", "No recv fcall for tag %d (req %p), disconnecting!\n",
......
...@@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work) ...@@ -208,6 +208,14 @@ static void p9_xen_response(struct work_struct *work)
continue; continue;
} }
if (h.size > req->rc.capacity) {
dev_warn(&priv->dev->dev,
"requested packet size too big: %d for tag %d with capacity %zd\n",
h.size, h.tag, req->rc.capacity);
req->status = REQ_STATUS_ERROR;
goto recv_error;
}
memcpy(&req->rc, &h, sizeof(h)); memcpy(&req->rc, &h, sizeof(h));
req->rc.offset = 0; req->rc.offset = 0;
...@@ -217,6 +225,7 @@ static void p9_xen_response(struct work_struct *work) ...@@ -217,6 +225,7 @@ static void p9_xen_response(struct work_struct *work)
masked_prod, &masked_cons, masked_prod, &masked_cons,
XEN_9PFS_RING_SIZE(ring)); XEN_9PFS_RING_SIZE(ring));
recv_error:
virt_mb(); virt_mb();
cons += h.size; cons += h.size;
ring->intf->in_cons = cons; ring->intf->in_cons = cons;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment