Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] v9fs: fix handling of malformed 9P messages

This patch attempts to do a better job of cleaning up after detecting errors
on the transport. This should also improve error reporting on broken
connections to servers.

Signed-off-by: Latchesar Ionkov <lucho@ionkov.net>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Eric Van Hensbergen and committed by
Linus Torvalds
cb2e87a6 b501611a

+46 -21
+1
fs/9p/error.h
··· 47 47 {"Operation not permitted", EPERM}, 48 48 {"wstat prohibited", EPERM}, 49 49 {"No such file or directory", ENOENT}, 50 + {"directory entry not found", ENOENT}, 50 51 {"file not found", ENOENT}, 51 52 {"Interrupted system call", EINTR}, 52 53 {"Input/output error", EIO},
+34 -19
fs/9p/mux.c
··· 162 162 dprintk(DEBUG_MUX, "waiting for response: %d\n", req->tcall->tag); 163 163 ret = wait_event_interruptible(v9ses->read_wait, 164 164 ((v9ses->transport->status != Connected) || 165 - (req->rcall != 0) || dprintcond(v9ses, req))); 165 + (req->rcall != 0) || (req->err < 0) || 166 + dprintcond(v9ses, req))); 166 167 167 168 dprintk(DEBUG_MUX, "got it: rcall %p\n", req->rcall); 169 + 170 + spin_lock(&v9ses->muxlock); 171 + list_del(&req->next); 172 + spin_unlock(&v9ses->muxlock); 173 + 174 + if (req->err < 0) 175 + return req->err; 176 + 168 177 if (v9ses->transport->status == Disconnected) 169 178 return -ECONNRESET; 170 - 171 - if (ret == 0) { 172 - spin_lock(&v9ses->muxlock); 173 - list_del(&req->next); 174 - spin_unlock(&v9ses->muxlock); 175 - } 176 179 177 180 return ret; 178 181 } ··· 248 245 if (!v9ses) 249 246 return -EINVAL; 250 247 248 + if (!v9ses->transport || v9ses->transport->status != Connected) 249 + return -EIO; 250 + 251 251 if (rcall) 252 252 *rcall = NULL; 253 253 ··· 263 257 tcall->tag = tid; 264 258 265 259 req.tcall = tcall; 260 + req.err = 0; 266 261 req.rcall = NULL; 267 262 268 263 ret = v9fs_send(v9ses, &req); ··· 378 371 } 379 372 380 373 err = read_message(v9ses, rcall, v9ses->maxdata + V9FS_IOHDRSZ); 381 - if (err < 0) { 382 - kfree(rcall); 383 - break; 384 - } 385 374 spin_lock(&v9ses->muxlock); 386 - list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { 387 - if (rreq->tcall->tag == rcall->tag) { 388 - req = rreq; 389 - req->rcall = rcall; 390 - break; 375 + if (err < 0) { 376 + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { 377 + rreq->err = err; 378 + } 379 + if(err != -ERESTARTSYS) 380 + eprintk(KERN_ERR, 381 + "Transport error while reading message %d\n", err); 382 + } else { 383 + list_for_each_entry_safe(rreq, rptr, &v9ses->mux_fcalls, next) { 384 + if (rreq->tcall->tag == rcall->tag) { 385 + req = rreq; 386 + req->rcall = rcall; 387 + break; 388 + } 391 389 } 392 390 } 393 391 ··· 411 399 spin_unlock(&v9ses->muxlock); 412 400 413 401 if (!req) { 414 - dprintk(DEBUG_ERROR, 415 - "unexpected response: id %d tag %d\n", 416 - rcall->id, rcall->tag); 402 + if (err >= 0) 403 + dprintk(DEBUG_ERROR, 404 + "unexpected response: id %d tag %d\n", 405 + rcall->id, rcall->tag); 417 406 418 407 kfree(rcall); 419 408 } ··· 422 409 wake_up_all(&v9ses->read_wait); 423 410 set_current_state(TASK_INTERRUPTIBLE); 424 411 } 412 + 413 + v9ses->transport->close(v9ses->transport); 425 414 426 415 /* Inform all pending processes about the failure */ 427 416 wake_up_all(&v9ses->read_wait);
+1
fs/9p/mux.h
··· 28 28 struct v9fs_rpcreq { 29 29 struct v9fs_fcall *tcall; 30 30 struct v9fs_fcall *rcall; 31 + int err; /* error code if response failed */ 31 32 32 33 /* XXX - could we put scatter/gather buffers here? */ 33 34
+10 -2
fs/9p/trans_sock.c
··· 254 254 255 255 static void v9fs_sock_close(struct v9fs_transport *trans) 256 256 { 257 - struct v9fs_trans_sock *ts = trans ? trans->priv : NULL; 257 + struct v9fs_trans_sock *ts; 258 + 259 + if (!trans) 260 + return; 261 + 262 + ts = trans->priv; 258 263 259 264 if ((ts) && (ts->s)) { 260 265 dprintk(DEBUG_TRANS, "closing the socket %p\n", ts->s); ··· 269 264 dprintk(DEBUG_TRANS, "socket closed\n"); 270 265 } 271 266 272 - kfree(ts); 267 + if (ts) 268 + kfree(ts); 269 + 270 + trans->priv = NULL; 273 271 } 274 272 275 273 struct v9fs_transport v9fs_trans_tcp = {