openSAFETY: Fixing rare crash as well as dissector errors. Bug 9314 (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9314)

From Roland Knall

svn path=/trunk/; revision=52752
This commit is contained in:
Michael Mann 2013-10-22 02:08:42 +00:00
parent b6df06199c
commit 7a360326ab
1 changed files with 83 additions and 67 deletions

View File

@ -41,6 +41,7 @@
#include "config.h"
#include <glib.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/etypes.h>
@ -454,6 +455,7 @@ static expert_field ei_crc_frame_2_unknown_scm_udid = EI_INIT;
static expert_field ei_message_unknown_type = EI_INIT;
static expert_field ei_message_reassembly_size_differs_from_header = EI_INIT;
static expert_field ei_message_spdo_address_invalid = EI_INIT;
static expert_field ei_message_id_field_mismatch = EI_INIT;
static expert_field ei_scmudid_autodetected = EI_INIT;
static expert_field ei_scmudid_invalid_preference = EI_INIT;
static expert_field ei_scmudid_unknown = EI_INIT;
@ -758,6 +760,7 @@ static guint8 findSafetyFrame ( tvbuff_t * message_tvb, guint u_Offset, gboolean
if ( b_ID != 0x0 )
{
b_Length = tvb_get_guint8(message_tvb, ctr + 1 );
/* 0xFF is often used, but always false, otherwise start detection, if the highest
* bit is set */
if ( ( b_ID != 0xFF ) && ( b_ID & 0x80 ) )
@ -767,72 +770,72 @@ static guint8 findSafetyFrame ( tvbuff_t * message_tvb, guint u_Offset, gboolean
* calculate it here again, to have a sane value */
rem_length = tvb_reported_length_remaining(message_tvb, ctr);
/* The calculated length must fit, but for the CRC16 check, also the calculated length
* plus the CRC16 end position must fit in the remaining length */
if ( ( b_Length <= (guint) 8 && ( b_Length <= rem_length ) ) ||
( b_Length > (guint) 8 && ( ( b_Length + (guint) 5 ) <= rem_length ) ) )
/* Plausability check on length */
if ( (guint)( b_Length * 2 ) < ( rem_length + OSS_MINIMUM_LENGTH ) )
{
/* Ensure, that the correct length for CRC calculation
* still exists in byte stream, so that we can calculate the crc */
if ( tvb_bytes_exist(message_tvb, ctr - 1, b_Length + 5) )
/* The calculated length must fit, but for the CRC16 check, also the calculated length
* plus the CRC16 end position must fit in the remaining length */
if ( ( b_Length <= (guint) 8 && ( b_Length <= rem_length ) ) ||
( b_Length > (guint) 8 && ( ( b_Length + (guint) 5 ) <= rem_length ) ) )
{
/* An openSAFETY command has to have a high-byte range between 0x0A and 0x0E
* b_ID & 0x80 took care of everything underneath, we check for 0x09 and 0x0F,
* as they remain the only values left, which are not valid */
if ( ( ( b_ID >> 4 ) != 0x09 ) && ( ( b_ID >> 4 ) != 0x0F ) )
/* Ensure, that the correct length for CRC calculation
* still exists in byte stream, so that we can calculate the crc */
if ( tvb_bytes_exist(message_tvb, ctr - 1, b_Length + 5) )
{
/* Find CRC position and calculate checksum */
crc = tvb_get_guint8(message_tvb, ctr + 3 + b_Length );
bytes = (guint8 *)tvb_memdup(wmem_packet_scope(), message_tvb, ctr - 1, b_Length + 5 );
if ( b_Length > 8 ) {
crc = tvb_get_letohs ( message_tvb, ctr + 3 + b_Length );
crcOffset = 1;
calcCrc = crc16_0x755B( bytes, b_Length + 4, 0 );
if ( ( crc ^ calcCrc ) != 0 )
calcCrc = crc16_0x5935( bytes, b_Length + 4, 0 );
} else {
calcCrc = crc8_0x2F ( bytes, b_Length + 4, 0 );
}
if ( ( crc ^ calcCrc ) == 0 )
/* An openSAFETY command has to have a high-byte range between 0x0A and 0x0E
* b_ID & 0x80 took care of everything underneath, we check for 0x09 and 0x0F,
* as they remain the only values left, which are not valid */
if ( ( ( b_ID >> 4 ) != 0x09 ) && ( ( b_ID >> 4 ) != 0x0F ) )
{
/* Check if this is a Slim SSDO message */
if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
{
/* Slim SSDO messages must have a length != 0, as the first byte
* in the payload contains the SOD access command */
if ( b_Length > 0 )
{
*u_frameOffset = ( ctr - 1 );
*u_frameLength = b_Length + 2 * crcOffset + 11;
/* Find CRC position and calculate checksum */
crc = tvb_get_guint8(message_tvb, ctr + 3 + b_Length );
/* It is highly unlikely, that both frame 1 and frame 2 generate
* a crc == 0 or equal crc's. Therefore we check, if both crc's are
* equal. If so, it is a falsely detected frame. */
f2crc = tvb_get_guint8 ( message_tvb, ctr + 3 + 5 + b_Length );
if ( b_Length > 8 )
f2crc = tvb_get_letohs ( message_tvb, ctr + 3 + 5 + b_Length );
if ( crc != f2crc )
bytes = (guint8 *)tvb_memdup(wmem_packet_scope(), message_tvb, ctr - 1, b_Length + 5 );
if ( b_Length > 8 ) {
crc = tvb_get_letohs ( message_tvb, ctr + 3 + b_Length );
crcOffset = 1;
calcCrc = crc16_0x755B( bytes, b_Length + 4, 0 );
if ( ( crc ^ calcCrc ) != 0 )
calcCrc = crc16_0x5935( bytes, b_Length + 4, 0 );
} else {
calcCrc = crc8_0x2F ( bytes, b_Length + 4, 0 );
}
if ( ( crc ^ calcCrc ) == 0 )
{
/* Check if this is a Slim SSDO message */
if ( ( b_ID >> 3 ) == ( OPENSAFETY_SLIM_SSDO_MESSAGE_TYPE >> 3 ) )
{
/* Slim SSDO messages must have a length != 0, as the first byte
* in the payload contains the SOD access command */
if ( b_Length > 0 )
{
found = 1;
break;
*u_frameOffset = ( ctr - 1 );
*u_frameLength = b_Length + 2 * crcOffset + 11;
/* It is highly unlikely, that both frame 1 and frame 2 generate
* a crc == 0 or equal crc's. Therefore we check, if both crc's are
* equal. If so, it is a falsely detected frame. */
f2crc = tvb_get_guint8 ( message_tvb, ctr + 3 + 5 + b_Length );
if ( b_Length > 8 )
f2crc = tvb_get_letohs ( message_tvb, ctr + 3 + 5 + b_Length );
if ( crc != f2crc )
{
found = 1;
break;
}
}
}
}
else
{
*u_frameLength = 2 * b_Length + 2 * crcOffset + 11;
*u_frameOffset = ( ctr - 1 );
/* EPL SoC messages can be falsely detected as openSAFETY frames,
* so we check if both checksums have no lower byte of 0x00. This
* check remains, although SoC and SoA messages get sorted out in
* the dissector */
if ( tvb_get_guint8(message_tvb, *u_frameOffset + *u_frameLength - 2 ) != 0x00 ||
tvb_get_guint8(message_tvb, *u_frameOffset + *u_frameLength - 1 ) != 0x00 )
else
{
*u_frameLength = 2 * b_Length + 2 * crcOffset + 11;
*u_frameOffset = ( ctr - 1 );
/* At this point frames had been checked for SoC and SoA types of
* EPL. This is no longer necessary and leads to false-negatives.
* SoC and SoA frames get filtered out at the EPL entry point. */
found = 1;
break;
}
@ -902,11 +905,6 @@ dissect_opensafety_spdo_message(tvbuff_t *message_tvb, packet_info *pinfo, proto
b_ID = tvb_get_guint8(message_tvb, frameStart1 + 1) & 0xF8;
conn_Valid = ( (tvb_get_guint8(message_tvb, frameStart1 + 1) & 0x04) == 0x04);
ct = tvb_get_guint8(message_tvb, frameStart1 + 3);
if ( validSCMUDID )
ct = (guint16)((tvb_get_guint8(message_tvb, frameStart2 + 2) ^ scm_udid[2]) << 8) +
(tvb_get_guint8(message_tvb, frameStart1 + 3));
/* Network address is xor'ed into the start of the second frame, but only legible, if the scm given is valid */
taddr = ( ( OSS_FRAME_ADDR_T(message_tvb, frameStart1) ) ^ ( OSS_FRAME_ADDR_T2(message_tvb, frameStart2, scm_udid[0], scm_udid[1]) ) );
if ( ! validSCMUDID )
@ -941,6 +939,14 @@ dissect_opensafety_spdo_message(tvbuff_t *message_tvb, packet_info *pinfo, proto
taddr = OSS_FRAME_ADDR_T2(message_tvb, frameStart2 + 3, scm_udid[3], scm_udid[4]);
tr = ( tvb_get_guint8(message_tvb, frameStart2 + 4) ^ scm_udid[4] ) & 0xFC;
/* determine the ct value. if complete it can be used for analysis of the package */
ct = tvb_get_guint8(message_tvb, frameStart1 + 3);
if ( validSCMUDID )
{
ct = (guint16)((tvb_get_guint8(message_tvb, frameStart2 + 2) ^ scm_udid[2]) << 8) +
(tvb_get_guint8(message_tvb, frameStart1 + 3));
}
if ( b_ID == OPENSAFETY_MSG_SPDO_DATA_WITH_TIME_REQUEST )
{
item = proto_tree_add_uint_format_value(spdo_tree, hf_oss_spdo_time_value_sn, message_tvb, 0, 0, ct,
@ -1669,6 +1675,9 @@ dissect_opensafety_checksum(tvbuff_t *message_tvb, packet_info *pinfo, proto_tre
else
frame2_crc = tvb_get_guint8(message_tvb, start);
/* 0xFFFF is an invalid CRC16 value, therefore valid for initialization */
calc2_crc = 0xFFFF;
if ( global_calculate_crc2 )
{
bytes = (guint8*)tvb_memdup(wmem_packet_scope(), message_tvb, frameStart2, frame2Length + length);
@ -1724,10 +1733,10 @@ dissect_opensafety_checksum(tvbuff_t *message_tvb, packet_info *pinfo, proto_tre
expert_add_info(pinfo, item, &ei_crc_frame_2_unknown_scm_udid );
}
/* For a correct calculation of the second crc we need to know the scm udid as well
* as the sdn. We might have the scm udid, but never the sdn, therefore a calculation
* must allways fail. */
return (gboolean) (frame1_crc == calc1_crc);
/* For a correct calculation of the second crc we need to know the scm udid.
* If the dissection of the second frame has been triggered, we integrate the
* crc for frame2 into the result */
return (gboolean) (frame1_crc == calc1_crc) && ( global_calculate_crc2 == TRUE ? (frame2_crc == calc2_crc) : TRUE);
}
static gboolean
@ -1782,7 +1791,11 @@ dissect_opensafety_message(guint16 frameStart1, guint16 frameStart2, guint8 type
if ( strlen ( (local_scm_udid != NULL ? local_scm_udid : global_scm_udid) ) > 0 && scmUDID->len == 6 )
{
if ( local_scm_udid != NULL )
{
item = proto_tree_add_string(opensafety_tree, hf_oss_scm_udid_auto, message_tvb, 0, 0, local_scm_udid);
if ( ! validSCMUDID )
expert_add_info(pinfo, item, &ei_message_id_field_mismatch );
}
else
item = proto_tree_add_string(opensafety_tree, hf_oss_scm_udid, message_tvb, 0, 0, global_scm_udid);
PROTO_ITEM_SET_GENERATED(item);
@ -1828,7 +1841,7 @@ dissect_opensafety_message(guint16 frameStart1, guint16 frameStart2, guint8 type
/* with SNMT's we can check if the ID's for the frames match. Rare randomized packages do have
* an issue, where an frame 1 can be valid. The id's for both frames must differ, as well as
* the addresses, but addresses won't be checked yet, as there are issues with SDN xored on it */
* the addresses, but addresses won't be checked yet, as there are issues with SDN xored on it. */
if ( crcValid && type == OPENSAFETY_SNMT_MESSAGE_TYPE )
{
if ( OSS_FRAME_ID_T(message_tvb, frameStart1) != OSS_FRAME_ID_T(message_tvb, frameStart2) )
@ -2564,6 +2577,9 @@ proto_register_opensafety(void)
{ &ei_message_spdo_address_invalid,
{ "opensafety.msg.error.spdo_address_invalid", PI_MALFORMED, PI_ERROR,
"SPDO address is invalid", EXPFILL } },
{ &ei_message_id_field_mismatch,
{ "opensafety.msg.error.id.mismatch", PI_PROTOCOL, PI_ERROR,
"ID for frame 2 is not the same as for frame 1", EXPFILL } },
{ &ei_scmudid_autodetected,
{ "opensafety.scm_udid.note.autodetected", PI_PROTOCOL, PI_NOTE,