aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarsten Keil <kkeil@suse.de>2007-02-28 23:13:50 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-01 17:53:39 -0500
commit17f0cd2f350b90b28301e27fe0e39f34bfe7e730 (patch)
tree6baba85d4f3b83398dc5a412b328bfcef1633548
parent34bbd704051c9d053d69e90569a3a2365f4c7b50 (diff)
[PATCH] Fix buffer overflow and races in capi debug functions
The CAPI trace debug functions were using a fixed size buffer, which can be overflowed if wrong formatted CAPI messages were sent to the kernel capi layer. The code was also not protected against multiple callers. This fix bug 8028. Additionally the patch make the CAPI trace functions optional. Signed-off-by: Karsten Keil <kkeil@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/isdn/capi/Kconfig16
-rw-r--r--drivers/isdn/capi/capidrv.c28
-rw-r--r--drivers/isdn/capi/capiutil.c254
-rw-r--r--drivers/isdn/capi/kcapi.c77
-rw-r--r--include/linux/isdn/capiutil.h21
5 files changed, 318 insertions, 78 deletions
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index 8b6c9a431ffa..c921d6c522f5 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -2,13 +2,25 @@
2# Config.in for the CAPI subsystem 2# Config.in for the CAPI subsystem
3# 3#
4config ISDN_DRV_AVMB1_VERBOSE_REASON 4config ISDN_DRV_AVMB1_VERBOSE_REASON
5 bool "Verbose reason code reporting (kernel size +=7K)" 5 bool "Verbose reason code reporting"
6 depends on ISDN_CAPI 6 depends on ISDN_CAPI
7 default y
7 help 8 help
8 If you say Y here, the AVM B1 driver will give verbose reasons for 9 If you say Y here, the CAPI drivers will give verbose reasons for
9 disconnecting. This will increase the size of the kernel by 7 KB. If 10 disconnecting. This will increase the size of the kernel by 7 KB. If
10 unsure, say Y. 11 unsure, say Y.
11 12
13config CAPI_TRACE
14 bool "CAPI trace support"
15 depends on ISDN_CAPI
16 default y
17 help
18 If you say Y here, the kernelcapi driver can make verbose traces
19 of CAPI messages. This feature can be enabled/disabled via IOCTL for
20 every controler (default disabled).
21 This will increase the size of the kernelcapi module by 20 KB.
22 If unsure, say Y.
23
12config ISDN_CAPI_MIDDLEWARE 24config ISDN_CAPI_MIDDLEWARE
13 bool "CAPI2.0 Middleware support (EXPERIMENTAL)" 25 bool "CAPI2.0 Middleware support (EXPERIMENTAL)"
14 depends on ISDN_CAPI && EXPERIMENTAL 26 depends on ISDN_CAPI && EXPERIMENTAL
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 2a49cea0a223..23b6f7bc16b7 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -990,6 +990,7 @@ static void handle_plci(_cmsg * cmsg)
990 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); 990 capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
991 capidrv_plci *plcip; 991 capidrv_plci *plcip;
992 isdn_ctrl cmd; 992 isdn_ctrl cmd;
993 _cdebbuf *cdb;
993 994
994 if (!card) { 995 if (!card) {
995 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", 996 printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
@@ -1122,8 +1123,15 @@ static void handle_plci(_cmsg * cmsg)
1122 break; 1123 break;
1123 } 1124 }
1124 } 1125 }
1125 printk(KERN_ERR "capidrv-%d: %s\n", 1126 cdb = capi_cmsg2str(cmsg);
1126 card->contrnr, capi_cmsg2str(cmsg)); 1127 if (cdb) {
1128 printk(KERN_WARNING "capidrv-%d: %s\n",
1129 card->contrnr, cdb->buf);
1130 cdebbuf_free(cdb);
1131 } else
1132 printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
1133 card->contrnr, cmsg->InfoNumber);
1134
1127 break; 1135 break;
1128 1136
1129 case CAPI_CONNECT_ACTIVE_CONF: /* plci */ 1137 case CAPI_CONNECT_ACTIVE_CONF: /* plci */
@@ -1371,10 +1379,18 @@ static _cmsg s_cmsg;
1371static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) 1379static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
1372{ 1380{
1373 capi_message2cmsg(&s_cmsg, skb->data); 1381 capi_message2cmsg(&s_cmsg, skb->data);
1374 if (debugmode > 3) 1382 if (debugmode > 3) {
1375 printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n", 1383 _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
1376 ap->applid, capi_cmsg2str(&s_cmsg)); 1384
1377 1385 if (cdb) {
1386 printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__,
1387 ap->applid, cdb->buf);
1388 cdebbuf_free(cdb);
1389 } else
1390 printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
1391 __FUNCTION__, ap->applid,
1392 capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
1393 }
1378 if (s_cmsg.Command == CAPI_DATA_B3 1394 if (s_cmsg.Command == CAPI_DATA_B3
1379 && s_cmsg.Subcommand == CAPI_IND) { 1395 && s_cmsg.Subcommand == CAPI_IND) {
1380 handle_data(&s_cmsg, skb); 1396 handle_data(&s_cmsg, skb);
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index c1b21552fc03..ad1e2702c2d1 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -648,6 +648,9 @@ char *capi_cmd2str(u8 cmd, u8 subcmd)
648 648
649 649
650/*-------------------------------------------------------*/ 650/*-------------------------------------------------------*/
651
652#ifdef CONFIG_CAPI_TRACE
653
651/*-------------------------------------------------------*/ 654/*-------------------------------------------------------*/
652 655
653static char *pnames[] = 656static char *pnames[] =
@@ -703,44 +706,77 @@ static char *pnames[] =
703}; 706};
704 707
705 708
706static char buf[8192];
707static char *p = NULL;
708 709
709#include <stdarg.h> 710#include <stdarg.h>
710 711
711/*-------------------------------------------------------*/ 712/*-------------------------------------------------------*/
712static void bufprint(char *fmt,...) 713static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt,...)
713{ 714{
714 va_list f; 715 va_list f;
716 size_t n,r;
717
718 if (!cdb)
719 return NULL;
715 va_start(f, fmt); 720 va_start(f, fmt);
716 vsprintf(p, fmt, f); 721 r = cdb->size - cdb->pos;
722 n = vsnprintf(cdb->p, r, fmt, f);
717 va_end(f); 723 va_end(f);
718 p += strlen(p); 724 if (n >= r) {
725 /* truncated, need bigger buffer */
726 size_t ns = 2 * cdb->size;
727 u_char *nb;
728
729 while ((ns - cdb->pos) <= n)
730 ns *= 2;
731 nb = kmalloc(ns, GFP_ATOMIC);
732 if (!nb) {
733 cdebbuf_free(cdb);
734 return NULL;
735 }
736 memcpy(nb, cdb->buf, cdb->pos);
737 kfree(cdb->buf);
738 nb[cdb->pos] = 0;
739 cdb->buf = nb;
740 cdb->p = cdb->buf + cdb->pos;
741 cdb->size = ns;
742 va_start(f, fmt);
743 r = cdb->size - cdb->pos;
744 n = vsnprintf(cdb->p, r, fmt, f);
745 va_end(f);
746 }
747 cdb->p += n;
748 cdb->pos += n;
749 return cdb;
719} 750}
720 751
721static void printstructlen(u8 * m, unsigned len) 752static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 * m, unsigned len)
722{ 753{
723 unsigned hex = 0; 754 unsigned hex = 0;
755
756 if (!cdb)
757 return NULL;
724 for (; len; len--, m++) 758 for (; len; len--, m++)
725 if (isalnum(*m) || *m == ' ') { 759 if (isalnum(*m) || *m == ' ') {
726 if (hex) 760 if (hex)
727 bufprint(">"); 761 cdb = bufprint(cdb, ">");
728 bufprint("%c", *m); 762 cdb = bufprint(cdb, "%c", *m);
729 hex = 0; 763 hex = 0;
730 } else { 764 } else {
731 if (!hex) 765 if (!hex)
732 bufprint("<%02x", *m); 766 cdb = bufprint(cdb, "<%02x", *m);
733<