aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipvs/ip_vs_sync.c
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2008-04-29 06:21:23 -0400
committerDavid S. Miller <davem@davemloft.net>2008-04-29 06:21:23 -0400
commit2ad17defd596ca7e8ba782d5fc6950ee0e99513c (patch)
treefa971402d7e832c3dcfa4bb2dd401b76f5249a58 /net/ipv4/ipvs/ip_vs_sync.c
parentd69efb16891ddfa6c0b527f912a7193054d50281 (diff)
ipvs: fix oops in backup for fwmark conn templates
Fixes bug http://bugzilla.kernel.org/show_bug.cgi?id=10556 where conn templates with protocol=IPPROTO_IP can oops backup box. Result from ip_vs_proto_get() should be checked because protocol value can be invalid or unsupported in backup. But for valid message we should not fail for templates which use IPPROTO_IP. Also, add checks to validate message limits and connection state. Show state NONE for templates using IPPROTO_IP. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_sync.c')
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c80
1 files changed, 59 insertions, 21 deletions
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 69c56663cc9a..eff54efe0351 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -288,11 +288,16 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
288 char *p; 288 char *p;
289 int i; 289 int i;
290 290
291 if (buflen < sizeof(struct ip_vs_sync_mesg)) {
292 IP_VS_ERR_RL("sync message header too short\n");
293 return;
294 }
295
291 /* Convert size back to host byte order */ 296 /* Convert size back to host byte order */
292 m->size = ntohs(m->size); 297 m->size = ntohs(m->size);
293 298
294 if (buflen != m->size) { 299 if (buflen != m->size) {
295 IP_VS_ERR("bogus message\n"); 300 IP_VS_ERR_RL("bogus sync message size\n");
296 return; 301 return;
297 } 302 }
298 303
@@ -307,9 +312,48 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
307 for (i=0; i<m->nr_conns; i++) { 312 for (i=0; i<m->nr_conns; i++) {
308 unsigned flags, state; 313 unsigned flags, state;
309 314
310 s = (struct ip_vs_sync_conn *)p; 315 if (p + SIMPLE_CONN_SIZE > buffer+buflen) {
316 IP_VS_ERR_RL("bogus conn in sync message\n");
317 return;
318 }
319 s = (struct ip_vs_sync_conn *) p;
311 flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC; 320 flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC;
321 flags &= ~IP_VS_CONN_F_HASHED;
322 if (flags & IP_VS_CONN_F_SEQ_MASK) {
323 opt = (struct ip_vs_sync_conn_options *)&s[1];
324 p += FULL_CONN_SIZE;
325 if (p > buffer+buflen) {
326 IP_VS_ERR_RL("bogus conn options in sync message\n");
327 return;
328 }
329 } else {
330 opt = NULL;
331 p += SIMPLE_CONN_SIZE;
332 }
333
312 state = ntohs(s->state); 334 state = ntohs(s->state);
335 if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
336 pp = ip_vs_proto_get(s->protocol);
337 if (!pp) {
338 IP_VS_ERR_RL("Unsupported protocol %u in sync msg\n",
339 s->protocol);
340 continue;
341 }
342 if (state >= pp->num_states) {
343 IP_VS_DBG(2, "Invalid %s state %u in sync msg\n",
344 pp->name, state);
345 continue;
346 }
347 } else {
348 /* protocol in templates is not used for state/timeout */
349 pp = NULL;
350 if (state > 0) {
351 IP_VS_DBG(2, "Invalid template state %u in sync msg\n",
352 state);
353 state = 0;
354 }
355 }
356
313 if (!(flags & IP_VS_CONN_F_TEMPLATE)) 357 if (!(flags & IP_VS_CONN_F_TEMPLATE))
314 cp = ip_vs_conn_in_get(s->protocol, 358 cp = ip_vs_conn_in_get(s->protocol,
315 s->caddr, s->cport, 359 s->caddr, s->cport,
@@ -345,14 +389,9 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
345 IP_VS_ERR("ip_vs_conn_new failed\n"); 389 IP_VS_ERR("ip_vs_conn_new failed\n");
346 return; 390 return;
347 } 391 }
348 cp->state = state;
349 } else if (!cp->dest) { 392 } else if (!cp->dest) {
350 dest = ip_vs_try_bind_dest(cp); 393 dest = ip_vs_try_bind_dest(cp);
351 if (!dest) { 394 if (dest)
352 /* it is an unbound entry created by
353 * synchronization */
354 cp->flags = flags | IP_VS_CONN_F_HASHED;
355 } else
356 atomic_dec(&dest->refcnt); 395 atomic_dec(&dest->refcnt);
357 } else if ((cp->dest) && (cp->protocol == IPPROTO_TCP) && 396 } else if ((cp->dest) && (cp->protocol == IPPROTO_TCP) &&
358 (cp->state != state)) { 397 (cp->state != state)) {
@@ -371,23 +410,22 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
371 } 410 }
372 } 411 }
373 412
374 if (flags & IP_VS_CONN_F_SEQ_MASK) { 413 if (opt)
375 opt = (struct ip_vs_sync_conn_options *)&s[1];
376 memcpy(&cp->in_seq, opt, sizeof(*opt)); 414 memcpy(&cp->in_seq, opt, sizeof(*opt));
377 p += FULL_CONN_SIZE;
378 } else
379 p += SIMPLE_CONN_SIZE;
380
381 atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]); 415 atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]);
382 cp->state = state; 416 cp->state = state;
383 pp = ip_vs_proto_get(s->protocol); 417 cp->old_state = cp->state;
384 cp->timeout = pp->timeout_table[cp->state]; 418 /*
419 * We can not recover the right timeout for templates
420 * in all cases, we can not find the right fwmark
421 * virtual service. If needed, we can do it for
422 * non-fwmark persistent services.
423 */
424 if (!(flags & IP_VS_CONN_F_TEMPLATE) && pp->timeout_table)
425 cp->timeout = pp->timeout_table[state];
426 else
427 cp->timeout = (3*60*HZ);
385 ip_vs_conn_put(cp); 428 ip_vs_conn_put(cp);
386
387 if (p > buffer+buflen) {
388 IP_VS_ERR("bogus message\n");
389 return;
390 }
391 } 429 }
392} 430}
393 431