From dan@obluda.cz  Sun Jul  8 11:58:09 2012
Return-Path: <dan@obluda.cz>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id E26C9106564A;
	Sun,  8 Jul 2012 11:58:08 +0000 (UTC)
	(envelope-from dan@obluda.cz)
Received: from kgw.obluda.cz (kgw.obluda.cz [193.179.199.50])
	by mx1.freebsd.org (Postfix) with ESMTP id 48E828FC18;
	Sun,  8 Jul 2012 11:58:08 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
	by localhost (8.14.5/8.14.5) with ESMTP id q68BseAD002032;
	Sun, 8 Jul 2012 13:54:40 +0200 (CEST)
	(envelope-from dan@obluda.cz)
Received: (from root@localhost)
	by localhost (8.14.5/8.14.5/Submit) id q68BseNo002031;
	Sun, 8 Jul 2012 13:54:40 +0200 (CEST)
	(envelope-from dan@obluda.cz)
Message-Id: <201207081154.q68BseNo002031@nb.obluda.cz>
Date: Sun, 8 Jul 2012 13:54:40 +0200 (CEST)
From: Dan Lukes <dan@obluda.cz>
Reply-To: Dan Lukes <dan@obluda.cz>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Hans-Joerg_Hoexer@genua.de, freebsd-acpi@freebsd.org
Subject: [ patch ] improper handling of ACPI TCPA table, acpidump abend imminent
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         169707
>Category:       bin
>Synopsis:       [ patch ] improper handling of ACPI TCPA table, acpidump abend imminent
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    takawata
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jul 08 12:00:24 UTC 2012
>Closed-Date:    Mon Jul 09 09:43:28 UTC 2012
>Last-Modified:  Thu Jul 12 07:40:28 UTC 2012
>Originator:     Dan Lukes
>Release:        FreeBSD 9.0 i386
>Organization:
Obludarium
>Environment:
System: FreeBSD 9.0
src/usr.sbin/acpi/acpidump/acpi.c,v 1.42.2.1.2.1

but apply for all revisions past 1.38 (e.g. all RELENG_9 and HEAD)

>Description:
	TCG ACPI (TPCA) support added as SVN rev 211196

1. event->event_type and event->event_size are big-endian (see TPCA PC Specific Specification, paragraph 7.2.2.2). Current code use them directly. It cause misinterpretation of values and may cause abend.

2. 'if (vaddr + event->event_size >= vend )' test is insufficient because:

2a) event->event_size is declared signed and may be negative (especialy when big-endian value used without proper conversion)
2b) vaddr+event->event_size may overflow / wrap around even in the case the event_size is positive

in both cases, memory outside of <vaddr,vend> range may be referenced. Abend is imminent.

>How-To-Repeat:
Dump non-empty TCPA table. It will print events incorrectly, may abend.

>Fix:

1. use ntohl() to convert event->event_size and event->event_type before use
2. test vaddr + eventdatasize for wraparound/underflow case also 

--- usr.sbin/acpi/acpidump/acpi.c.old	2012-07-08 13:14:21.000000000 +0200
+++ usr.sbin/acpi/acpidump/acpi.c	2012-07-08 13:06:46.000000000 +0200
@@ -40,6 +40,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <netinet/in.h>
 
 #include "acpidump.h"
 
@@ -538,10 +539,15 @@
 {
 	struct TCPApc_event *pc_event;
 	char *eventname = NULL;
+	unsigned int eventid, eventdatasize;
+
+	// EventID and EventDataSize are big endian (TPCA PC Specific Specification [7.2.2.2])
+	eventid = ntohl(event->event_type);
+	eventdatasize = ntohl(event->event_size);
 
 	pc_event = (struct TCPApc_event *)(event + 1);
 
-	switch(event->event_type) {
+	switch(eventid) {
 	case PREBOOT:
 	case POST_CODE:
 	case UNUSED:
@@ -559,12 +565,12 @@
 	case NONHOST_CONFIG:
 	case NONHOST_INFO:
 		asprintf(&eventname, "%s",
-		    tcpa_event_type_strings[event->event_type]);
+		    tcpa_event_type_strings[eventid]);
 		break;
 
 	case ACTION:
-		eventname = calloc(event->event_size + 1, sizeof(char));
-		memcpy(eventname, pc_event, event->event_size);
+		eventname = calloc(eventdatasize + 1, sizeof(char));
+		memcpy(eventname, pc_event, eventdatasize);
 		break;
 
 	case EVENT_TAG:
@@ -593,7 +599,7 @@
 		break;
 
 	default:
-		asprintf(&eventname, "<unknown 0x%02x>", event->event_type);
+		asprintf(&eventname, "<unknown 0x%02x>", eventid);
 		break;
 	}
 
@@ -659,20 +665,27 @@
 	vend = vaddr + len;
 
 	while (vaddr != NULL) {
+		unsigned int eventid, eventdatasize;
+		
 		if (vaddr + sizeof(struct TCPAevent) >= vend)
 			break;
 		event = (struct TCPAevent *)(void *)vaddr;
-		if (vaddr + event->event_size >= vend)
+		// EventID and EventDataSize are big endian (TPCA PC Specific Specification [7.2.2.2])
+		eventid = ntohl(event->event_type);
+		eventdatasize = ntohl(event->event_size);
+		if (vaddr + eventdatasize >= vend )
+			break;
+		if (vaddr + eventdatasize < vaddr )
 			break;
-		if (event->event_type == 0 && event->event_size == 0)
+		if (eventid == 0 && eventdatasize == 0)
 			break;
 #if 0
 		{
 		unsigned int i, j, k;
 
-		printf("\n\tsize %d\n\t\t%p ", event->event_size, vaddr);
+		printf("\n\tsize %u\n\t\t%p ", eventdatasize, vaddr);
 		for (j = 0, i = 0; i <
-		    sizeof(struct TCPAevent) + event->event_size; i++) {
+		    sizeof(struct TCPAevent) + eventdatasize; i++) {
 			printf("%02x ", vaddr[i]);
 			if ((i+1) % 8 == 0) {
 				for (k = 0; k < 8; k++)
@@ -686,7 +699,7 @@
 #endif
 		acpi_print_tcpa(event);
 
-		vaddr += sizeof(struct TCPAevent) + event->event_size;
+		vaddr += sizeof(struct TCPAevent) + eventdatasize;
 	}
 
 	printf(END_COMMENT);
--- patch ends here ---

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->takawata  
Responsible-Changed-By: takawata 
Responsible-Changed-When: Sun Jul 8 14:56:11 UTC 2012 
Responsible-Changed-Why:  
I'll handle this. 


http://www.freebsd.org/cgi/query-pr.cgi?pr=169707 

From: Takanori Watanabe <takawata@init-main.com>
To: bug-followup@freebsd.org, dan@obluda.cz
Cc:  
Subject: Re:bin/169707: [ patch ] improper handling of ACPI TCPA table, acpidump abend imminent
Date: Mon, 09 Jul 2012 02:57:37 +0900

 With your patch, my TCPA (may wrong)log disappers .
 
 Would you send me right output of TCPA trace table on your machine?
 
 == This is mine, without your patch.
         0 0x3789f03d35e84f23d0a465d00302362eaec0f68f [S-CRTM Version]
         0 0x5e3cb095eec7b0d5931b1f600a4ceccca87e2e69 [POST Code]
         0 0x1ea88d2d2610eaeaaeab5ba7728db32000d3496d [POST Code]
         0 0xdd261ca7511a7daf9e16cb572318e8e5fbd22963 [POST Code]
         0 0xdf22cabc0e09aabf938bcb8ff76853dbcaae670d [POST Code]
         0 0x3fc77571c74de982a8baed64f02de47a514dbfb6 [POST Code]
 	.....
 ==

From: Dan Lukes <dan@obluda.cz>
To: Takanori Watanabe <takawata@init-main.com>
Cc: bug-followup@freebsd.org
Subject: Re: bin/169707: [ patch ] improper handling of ACPI TCPA table, acpidump
 abend imminent
Date: Sun, 08 Jul 2012 21:40:50 +0200

 This is a multi-part message in MIME format.
 --------------060705030708050001040006
 Content-Type: text/plain; charset=us-ascii; format=flowed
 Content-Transfer-Encoding: 7bit
 
 On 07/08/12 19:57, Takanori Watanabe:
 > With your patch, my TCPA (may wrong)log disappers .
 >
 > Would you send me right output of TCPA trace table on your machine?
 >
 > == This is mine, without your patch.
 >          0 0x3789f03d35e84f23d0a465d00302362eaec0f68f [S-CRTM Version]
 >          0 0x5e3cb095eec7b0d5931b1f600a4ceccca87e2e69 [POST Code]
 >          0 0x1ea88d2d2610eaeaaeab5ba7728db32000d3496d [POST Code]
 >          0 0xdd261ca7511a7daf9e16cb572318e8e5fbd22963 [POST Code]
 >          0 0xdf22cabc0e09aabf938bcb8ff76853dbcaae670d [POST Code]
 >          0 0x3fc77571c74de982a8baed64f02de47a514dbfb6 [POST Code]
 > 	.....
 > ==
 
 Damn - problem is found. I attached old version of patch. It's 
 completely bad, resulting code can't work correctly. I'm so sorry for this.
 
 The correct patch is attached now.
 
 The only records affected by big-endian issue is [Event tag] type, e.g. 
 "Platform Specific Event Log".  Your's output will not change unless you 
 have the one.
 
 Unfortunately, my TCPA log doesn't contain such type of record also.
 
 I'm affected by "abend" issue only as my TCPA log contain record 
 claiming negative size.
 
 Thank you very much for your cooperation and sorry, again, for buggy patch.
 
 Dan
 
 --------------060705030708050001040006
 Content-Type: text/plain; charset=us-ascii;
  name="patch-acpidump-TCPA"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="patch-acpidump-TCPA"
 
 --- usr.sbin/acpi/acpidump/acpi.c.orig	2011-11-11 05:20:22.000000000 +0100
 +++ usr.sbin/acpi/acpidump/acpi.c	2012-07-08 21:01:10.000000000 +0200
 @@ -40,6 +40,7 @@
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
 +#include <netinet/in.h>
  
  #include "acpidump.h"
  
 @@ -538,8 +539,12 @@
  {
  	struct TCPApc_event *pc_event;
  	char *eventname = NULL;
 +	unsigned int eventid, eventdatasize;
  
  	pc_event = (struct TCPApc_event *)(event + 1);
 +	// EventID and EventDataSize are big endian (TPCA PC Specific Specification [7.2.2.2])
 +	eventid = ntohl(pc_event->event_id);
 +	eventdatasize = ntohl(pc_event->event_size);
  
  	switch(event->event_type) {
  	case PREBOOT:
 @@ -568,7 +573,7 @@
  		break;
  
  	case EVENT_TAG:
 -		switch (pc_event->event_id) {
 +		switch (eventid) {
  		case SMBIOS:
  		case BIS_CERT:
  		case CMOS:
 @@ -582,12 +587,12 @@
  		case S_CRTM_CONTENTS:
  		case POST_CONTENTS:
  			asprintf(&eventname, "%s",
 -			    TCPA_pcclient_strings[pc_event->event_id]);
 +			    TCPA_pcclient_strings[eventid]);
  			break;
  
  		default:
  			asprintf(&eventname, "<unknown tag 0x%02x>",
 -			    pc_event->event_id);
 +			    eventid);
  			break;
  		}
  		break;
 @@ -664,6 +669,8 @@
  		event = (struct TCPAevent *)(void *)vaddr;
  		if (vaddr + event->event_size >= vend)
  			break;
 +		if (vaddr + event->event_size <= vaddr)
 +			break;
  		if (event->event_type == 0 && event->event_size == 0)
  			break;
  #if 0
 
 --------------060705030708050001040006--

From: Takanori Watanabe <takawata@init-main.com>
To: bug-followup@freebsd.org, dan@obluda.cz
Cc:  
Subject: Re: bin/169707: [ patch ] improper handling of ACPI TCPA table, acpidump
Date: Mon, 09 Jul 2012 12:36:13 +0900

 With your newer patch, I only see single first entry.
 And commenting out additional range check will produce such entries like this.
 ==
  1 0x23cb40d9b316f8a18adc8e1eddf5f0fe854a443f [<unknown tag 0x6000000>]
 ==
 Probably current code is correct in my machine and
 newer Specification may have endian parameter somewhere.
 I'll looking at this.
 
 cf: 
 http://trustedjava.sourceforge.net/jtss/javadoc_tsp/iaik/tc/tss/api/structs/common/TcByteOrder.html

From: Takanori Watanabe <takawata@init-main.com>
To: bug-followup@freebsd.org, dan@obluda.cz
Cc:  
Subject: Re: bin/169707: [ patch ] improper handling of ACPI TCPA table, acpidump
Date: Mon, 09 Jul 2012 15:38:25 +0900

 According to "TCG PC Client Specific Implementation Specification for Conventional BIOS",TCG_PCClientImplementation_1-12_1_00.pdf 
 
 11.1 Byte-ordering (Endianness)
  Start of informative comment:
 TPM data and structures, are Big Endian. However, the processor
 in the PC Client represents data in Little Endian format, so all
 constants and data created and used by the PC Clients structures
 shall be in Little Endian format.
 The justification for this is that when software deals with the
 Host Platform itself (e.g., the PC Client data,structures, etc.),
 it uses Little Endian always. Software already deals with this 
 bifurcation when communicating over a network.
 When getting packets from the network (e.g., FTP, HTTP, etc.) it deals
 with Big Endian; when it deals with data and structures
 from the Host Platform itself, it does so using Little
 Endian. Changing within the context or purview would be inconsistent.
 End of informative comment.
 1. All constants and data SHALL be represented as Little Endian unless otherwise explicitly stated.
 2. All strings SHALL be represented as an array of ASCII bytes with the left-most character placed in the
      lowest memory location.
 
 TCPA spec is old so we have to check revision member on TCPA header.

From: Takanori Watanabe <takawata@init-main.com>
To: bug-followup@freebsd.org, dan@obluda.cz
Cc:  
Subject: Re: bin/169707: [ patch ] improper handling of ACPI TCPA table, acpidump
Date: Mon, 09 Jul 2012 16:13:05 +0900

 We have possible fix as follows. I recommend latter one.
 
 1. Dump TCPA log as TCG PC spec. I cannot ensure the event interpretation
 is correct.
 
 Index: acpi.c
 ===================================================================
 --- acpi.c	(revision 238253)
 +++ acpi.c	(working copy)
 @@ -40,6 +40,7 @@
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
 +#include <netinet/in.h>
  
  #include "acpidump.h"
  
 @@ -534,13 +535,26 @@
  }
  
  static char *
 -acpi_tcpa_evname(struct TCPAevent *event)
 +acpi_tcpa_evname(struct TCPAevent *event, int rev)
  {
  	struct TCPApc_event *pc_event;
  	char *eventname = NULL;
 +	unsigned int eventid, eventdatasize;
  
  	pc_event = (struct TCPApc_event *)(event + 1);
 -
 +	
 +	eventid = pc_event->event_id;
 +	eventdatasize = pc_event->event_size;
 +	
 +	if(rev == 1){
 +		/*  EventID and EventDataSize are big endian
 +		 *  in TPCA PC Specific Specification [7.2.2.2],
 +		 *  the obsolete spec.
 +		 */
 +		eventid = htonl(eventid);
 +		eventdatasize = htonl(eventdatasize);
 +	}
 +	
  	switch(event->event_type) {
  	case PREBOOT:
  	case POST_CODE:
 @@ -568,7 +582,7 @@
  		break;
  
  	case EVENT_TAG:
 -		switch (pc_event->event_id) {
 +		switch (eventid) {
  		case SMBIOS:
  		case BIS_CERT:
  		case CMOS:
 @@ -582,12 +596,12 @@
  		case S_CRTM_CONTENTS:
  		case POST_CONTENTS:
  			asprintf(&eventname, "%s",
 -			    TCPA_pcclient_strings[pc_event->event_id]);
 +			    TCPA_pcclient_strings[eventid]);
  			break;
  
  		default:
  			asprintf(&eventname, "<unknown tag 0x%02x>",
 -			    pc_event->event_id);
 +			    eventid);
  			break;
  		}
  		break;
 @@ -601,12 +615,12 @@
  }
  
  static void
 -acpi_print_tcpa(struct TCPAevent *event)
 +acpi_print_tcpa(struct TCPAevent *event, int rev)
  {
  	int i;
  	char *eventname;
  
 -	eventname = acpi_tcpa_evname(event);
 +	eventname = acpi_tcpa_evname(event, rev);
  
  	printf("\t%d", event->pcr_index);
  	printf(" 0x");
 @@ -664,6 +678,8 @@
  		event = (struct TCPAevent *)(void *)vaddr;
  		if (vaddr + event->event_size >= vend)
  			break;
 +		if (vaddr + event->event_size < vaddr)
 +			break;
  		if (event->event_type == 0 && event->event_size == 0)
  			break;
  #if 0
 @@ -684,7 +700,7 @@
  		}
  		printf("\n"); }
  #endif
 -		acpi_print_tcpa(event);
 +		acpi_print_tcpa(event, sdp->Revision);
  
  		vaddr += sizeof(struct TCPAevent) + event->event_size;
  	}
 
 ===
 2. Simply stop parsing TCPA event log entry because we don't 
 actually support old obsolete spec.
 
 Index: acpi.c
 ===================================================================
 --- acpi.c	(revision 238276)
 +++ acpi.c	(working copy)
 @@ -654,6 +654,11 @@
  		printf(END_COMMENT);
  		return;
  	}
 +	if(sdp->Revision == 1){
 +		printf("\tOLD TCPA spec log found. dumping not supported.\n");
 +		printf(END_COMMENT);
 +		return;
 +	}
  
  	vaddr = (unsigned char *)acpi_map_physical(paddr, len);
  	vend = vaddr + len;
 @@ -664,6 +669,8 @@
  		event = (struct TCPAevent *)(void *)vaddr;
  		if (vaddr + event->event_size >= vend)
  			break;
 +		if (vaddr + event->event_size < vaddr)
 +			break;
  		if (event->event_type == 0 && event->event_size == 0)
  			break;
  #if 0
 
 

From: Dan Lukes <dan@obluda.cz>
To: Takanori Watanabe <takawata@init-main.com>
Cc: bug-followup@freebsd.org
Subject: Re: bin/169707: [ patch ] improper handling of ACPI TCPA table, acpidump
Date: Mon, 09 Jul 2012 09:51:11 +0200

 On 07/09/12 09:13, Takanori Watanabe:
 > We have possible fix as follows. I recommend latter one.
 >
 > 1. Dump TCPA log as TCG PC spec. I cannot ensure the event interpretation
 > is correct.
 
 I prefer this. It's not worse than current code and MAY work better, 
 although we can't test it with our hardware. But it's up to you.
 
   ----------------
 
 I have short notice about the range test (note it's another test that we 
 are modifying by current patch):
 
 > if (vaddr + sizeof(struct TCPAevent) >= vend)
 >            break;
 
 In edge case, vaddr + sizeof(struct TCPAevent) may overflow also.
 
 > (vaddr + sizeof(struct TCPAevent) >= vend || vaddr + sizeof(struct TCPAevent) < vaddr )
 
 looks more safe approach for me. It's not exceptional the ACPI 
 structures are terribly broken on some hardware.
 
 Thank you for your cooperation.
 
 Dan

Date: Mon, 9 Jul 2012 08:45:19 -0400
From: John Baldwin <jhb@freebsd.org>
To: freebsd-acpi@freebsd.org, Dan Lukes <dan@obluda.cz>
Subject: Re: [ patch ] improper handling of ACPI TCPA table, acpidump abend imminent

 > 1. use ntohl() to convert event->event_size and event->event_type before use
 > 2. test vaddr + eventdatasize for wraparound/underflow case also 
 
 It might be best to use betoh() macros from <sys/endian.h> instead of nthol().
 
 -- 
 John Baldwin
 
From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/169707: commit references a PR
Date: Mon,  9 Jul 2012 09:39:07 +0000 (UTC)

 Author: takawata
 Date: Mon Jul  9 09:38:53 2012
 New Revision: 238288
 URL: http://svn.freebsd.org/changeset/base/238288
 
 Log:
   Add range and table revision checking to avoid abend.
   
   PR:bin/169707
   Submitted by:Dan Lukes <dan@obluda.cz>
   MFC after:3 days.
 
 Modified:
   head/usr.sbin/acpi/acpidump/acpi.c
 
 Modified: head/usr.sbin/acpi/acpidump/acpi.c
 ==============================================================================
 --- head/usr.sbin/acpi/acpidump/acpi.c	Mon Jul  9 09:24:46 2012	(r238287)
 +++ head/usr.sbin/acpi/acpidump/acpi.c	Mon Jul  9 09:38:53 2012	(r238288)
 @@ -654,16 +654,24 @@ acpi_handle_tcpa(ACPI_TABLE_HEADER *sdp)
  		printf(END_COMMENT);
  		return;
  	}
 +	if(sdp->Revision == 1){
 +		printf("\tOLD TCPA spec log found. Dumping not supported.\n");
 +		printf(END_COMMENT);
 +		return;
 +	}
  
  	vaddr = (unsigned char *)acpi_map_physical(paddr, len);
  	vend = vaddr + len;
  
  	while (vaddr != NULL) {
 -		if (vaddr + sizeof(struct TCPAevent) >= vend)
 +		if ((vaddr + sizeof(struct TCPAevent) >= vend)||
 +		    (vaddr + sizeof(struct TCPAevent) < vaddr))
  			break;
  		event = (struct TCPAevent *)(void *)vaddr;
  		if (vaddr + event->event_size >= vend)
  			break;
 +		if (vaddr + event->event_size < vaddr)
 +			break;
  		if (event->event_type == 0 && event->event_size == 0)
  			break;
  #if 0
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed  
State-Changed-By: takawata 
State-Changed-When: Mon Jul 9 09:42:21 UTC 2012 
State-Changed-Why:  
Fix committed. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=169707 
>Unformatted:
