diff options
| author | Karsten Keil <kkeil@suse.de> | 2007-02-28 23:13:50 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-01 17:53:39 -0500 |
| commit | 17f0cd2f350b90b28301e27fe0e39f34bfe7e730 (patch) | |
| tree | 6baba85d4f3b83398dc5a412b328bfcef1633548 | |
| parent | 34bbd704051c9d053d69e90569a3a2365f4c7b50 (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/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/isdn/capi/capidrv.c | 28 | ||||
| -rw-r--r-- | drivers/isdn/capi/capiutil.c | 254 | ||||
| -rw-r--r-- | drivers/isdn/capi/kcapi.c | 77 | ||||
| -rw-r--r-- | include/linux/isdn/capiutil.h | 21 |
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 | # |
| 4 | config ISDN_DRV_AVMB1_VERBOSE_REASON | 4 | config 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 | ||
| 13 | config 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 | |||
| 12 | config ISDN_CAPI_MIDDLEWARE | 24 | config 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; | |||
| 1371 | static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) | 1379 | static 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 | ||
| 653 | static char *pnames[] = | 656 | static char *pnames[] = |
| @@ -703,44 +706,77 @@ static char *pnames[] = | |||
| 703 | }; | 706 | }; |
| 704 | 707 | ||
| 705 | 708 | ||
| 706 | static char buf[8192]; | ||
| 707 | static char *p = NULL; | ||
| 708 | 709 | ||
| 709 | #include <stdarg.h> | 710 | #include <stdarg.h> |
| 710 | 711 | ||
| 711 | /*-------------------------------------------------------*/ | 712 | /*-------------------------------------------------------*/ |
| 712 | static void bufprint(char *fmt,...) | 713 | static _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 | ||
| 721 | static void printstructlen(u8 * m, unsigned len) | 752 | static _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< | |||
