diff options
author | Jeff Layton <jlayton@redhat.com> | 2011-01-29 07:02:28 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-01-30 23:38:15 -0500 |
commit | 92a4e0f0169498867ecb19c2244510dd4beba149 (patch) | |
tree | 031011d451bf3d19813fbbceabceacfb9ce76db8 /fs/cifs/misc.c | |
parent | d804d41d163c0975d2890c82d7135ada7a2f23a4 (diff) |
cifs: force a reconnect if there are too many MIDs in flight
Currently, we allow the pending_mid_q to grow without bound with
SIGKILL'ed processes. This could eventually be a DoS'able problem. An
unprivileged user could a process that does a long-running call and then
SIGKILL it.
If he can also intercept the NT_CANCEL calls or the replies from the
server, then the pending_mid_q could grow very large, possibly even to
2^16 entries which might leave GetNextMid in an infinite loop. Fix this
by imposing a hard limit of 32k calls per server. If we cross that
limit, set the tcpStatus to CifsNeedReconnect to force cifsd to
eventually reconnect the socket and clean out the pending_mid_q.
While we're at it, clean up the function a bit and eliminate an
unnecessary NULL pointer check.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/misc.c')
-rw-r--r-- | fs/cifs/misc.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 72e99ece78cf..24f0a9d97ad8 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -236,10 +236,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
236 | { | 236 | { |
237 | __u16 mid = 0; | 237 | __u16 mid = 0; |
238 | __u16 last_mid; | 238 | __u16 last_mid; |
239 | int collision; | 239 | bool collision; |
240 | |||
241 | if (server == NULL) | ||
242 | return mid; | ||
243 | 240 | ||
244 | spin_lock(&GlobalMid_Lock); | 241 | spin_lock(&GlobalMid_Lock); |
245 | last_mid = server->CurrentMid; /* we do not want to loop forever */ | 242 | last_mid = server->CurrentMid; /* we do not want to loop forever */ |
@@ -252,24 +249,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
252 | (and it would also have to have been a request that | 249 | (and it would also have to have been a request that |
253 | did not time out) */ | 250 | did not time out) */ |
254 | while (server->CurrentMid != last_mid) { | 251 | while (server->CurrentMid != last_mid) { |
255 | struct list_head *tmp; | ||
256 | struct mid_q_entry *mid_entry; | 252 | struct mid_q_entry *mid_entry; |
253 | unsigned int num_mids; | ||
257 | 254 | ||
258 | collision = 0; | 255 | collision = false; |
259 | if (server->CurrentMid == 0) | 256 | if (server->CurrentMid == 0) |
260 | server->CurrentMid++; | 257 | server->CurrentMid++; |
261 | 258 | ||
262 | list_for_each(tmp, &server->pending_mid_q) { | 259 | num_mids = 0; |
263 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 260 | list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { |
264 | 261 | ++num_mids; | |
265 | if ((mid_entry->mid == server->CurrentMid) && | 262 | if (mid_entry->mid == server->CurrentMid && |
266 | (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | 263 | mid_entry->midState == MID_REQUEST_SUBMITTED) { |
267 | /* This mid is in use, try a different one */ | 264 | /* This mid is in use, try a different one */ |
268 | collision = 1; | 265 | collision = true; |
269 | break; | 266 | break; |
270 | } | 267 | } |
271 | } | 268 | } |
272 | if (collision == 0) { | 269 | |
270 | /* | ||
271 | * if we have more than 32k mids in the list, then something | ||
272 | * is very wrong. Possibly a local user is trying to DoS the | ||
273 | * box by issuing long-running calls and SIGKILL'ing them. If | ||
274 | * we get to 2^16 mids then we're in big trouble as this | ||
275 | * function could loop forever. | ||
276 | * | ||
277 | * Go ahead and assign out the mid in this situation, but force | ||
278 | * an eventual reconnect to clean out the pending_mid_q. | ||
279 | */ | ||
280 | if (num_mids > 32768) | ||
281 | server->tcpStatus = CifsNeedReconnect; | ||
282 | |||
283 | if (!collision) { | ||
273 | mid = server->CurrentMid; | 284 | mid = server->CurrentMid; |
274 | break; | 285 | break; |
275 | } | 286 | } |