Subject: [Suggestion] drivers/isdn/divert: break looping, or memory leak by calling kmalloc again

From: Chen Gang <[email-masked]>
Date: Mon, 01 Apr 2013 10:11:09 +0800

Hello Maintainers:

in drivers/isdn/divert/isdn_divert.c:

  in 'for' looping (line 395..515)
    the 'cs' may call kmalloc again (line 453).

  it seems need break looping, when get valid 'cs' value (line 509)

  please help check, thanks.

gchen.

382 /*************************************************/
383 /* called from common module on an incoming call */
384 /*************************************************/
385 static int isdn_divert_icall(isdn_ctrl *ic)
386 {
387         int retval = 0;
388         unsigned long flags;
389         struct call_struc *cs = NULL;
390         struct deflect_struc *dv;
391         char *p, *p1;
392         u_char accept;
393 
394         /* first check the internal deflection table */
395         for (dv = table_head; dv; dv = dv->next) {
396                 /* scan table */
397                 if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
398                     ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
399                         continue; /* call option check */
400                 if (!(dv->rule.drvid & (1L << ic->driver)))
401                         continue; /* driver not matching */
402                 if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
403                         continue; /* si1 not matching */
404                 if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
405                         continue; /* si2 not matching */
406 
407                 p = dv->rule.my_msn;
408                 p1 = ic->parm.setup.eazmsn;
409                 accept = 0;
410                 while (*p) {
411                         /* complete compare */
412                         if (*p == '-') {
413                                 accept = 1; /* call accepted */
414                                 break;
415                         }
416                         if (*p++ != *p1++)
417                                 break; /* not accepted */
418                         if ((!*p) && (!*p1))
419                                 accept = 1;
420                 } /* complete compare */
421                 if (!accept) continue; /* not accepted */
422 
423                 if ((strcmp(dv->rule.caller, "0")) ||
424                     (ic->parm.setup.phone[0])) {
425                         p = dv->rule.caller;
426                         p1 = ic->parm.setup.phone;
427                         accept = 0;
428                         while (*p) {
429                                 /* complete compare */
430                                 if (*p == '-') {
431                                         accept = 1; /* call accepted */
432                                         break;
433                                 }
434                                 if (*p++ != *p1++)
435                                         break; /* not accepted */
436                                 if ((!*p) && (!*p1))
437                                         accept = 1;
438                         } /* complete compare */
439                         if (!accept) continue; /* not accepted */
440                 }
441 
442                 switch (dv->rule.action) {
443                 case DEFLECT_IGNORE:
444                         return (0);
445 
446                 case DEFLECT_ALERT:
447                 case DEFLECT_PROCEED:
448                 case DEFLECT_REPORT:
449                 case DEFLECT_REJECT:
450                         if (dv->rule.action == DEFLECT_PROCEED)
451                                 if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
452                                         return (0); /* no external deflection needed */
453                         if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
454                                 return (0); /* no memory */
455                         init_timer(&cs->timer);
456                         cs->info[0] = '\0';
457                         cs->timer.function = deflect_timer_expire;
458                         cs->timer.data = (ulong) cs; /* pointer to own structure */
459 
460                         cs->ics = *ic; /* copy incoming data */
461                         if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0");
462                         if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0");
463                         cs->ics.parm.setup.screen = dv->rule.screen;
464                         if (dv->rule.waittime)
465                                 cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
466                         else if (dv->rule.action == DEFLECT_PROCEED)
467                                 cs->timer.expires = jiffies + (HZ * extern_wait_max);
468                         else
469                                 cs->timer.expires = 0;
470                         cs->akt_state = dv->rule.action;
471                         spin_lock_irqsave(&divert_lock, flags);
472                         cs->divert_id = next_id++; /* new sequence number */
473                         spin_unlock_irqrestore(&divert_lock, flags);
474                         cs->prev = NULL;
475                         if (cs->akt_state == DEFLECT_ALERT) {
476                                 strcpy(cs->deflect_dest, dv->rule.to_nr);
477                                 if (!cs->timer.expires) {
478                                         strcpy(ic->parm.setup.eazmsn,
479                                                "Testtext direct");
480                                         ic->parm.setup.screen = dv->rule.screen;
481                                         strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone));
482                                         cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
483                                         cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
484                                         retval = 5;
485                                 } else
486                                         retval = 1; /* alerting */
487                         } else {
488                                 cs->deflect_dest[0] = '\0';
489                                 retval = 4; /* only proceed */
490                         }
491                         sprintf(cs->info, "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
492                                 cs->akt_state,
493                                 cs->divert_id,
494                                 divert_if.drv_to_name(cs->ics.driver),
495                                 (ic->command == ISDN_STAT_ICALLW) ? "1" : "0",
496                                 cs->ics.parm.setup.phone,
497                                 cs->ics.parm.setup.eazmsn,
498                                 cs->ics.parm.setup.si1,
499                                 cs->ics.parm.setup.si2,
500                                 cs->ics.parm.setup.screen,
501                                 dv->rule.waittime,
502                                 cs->deflect_dest);
503                         if ((dv->rule.action == DEFLECT_REPORT) ||
504                             (dv->rule.action == DEFLECT_REJECT)) {
505                                 put_info_buffer(cs->info);
506                                 kfree(cs); /* remove */
507                                 return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */
508                         }
509                         break;
510 
511                 default:
512                         return (0); /* ignore call */
513                 } /* switch action */
514                 break;
515         } /* scan_table */
516 
517         if (cs) {
518                 cs->prev = NULL;
519                 spin_lock_irqsave(&divert_lock, flags);
520                 cs->next = divert_head;
521                 divert_head = cs;
522                 if (cs->timer.expires) add_timer(&cs->timer);
523                 spin_unlock_irqrestore(&divert_lock, flags);
524 
525                 put_info_buffer(cs->info);
526                 return (retval);
527         } else
528                 return (0);
529 } /* isdn_divert_icall */