Subject: gpsd: SEGV when receiving short aivdm message type 26
Package: gpsd
Version: 2.95-7
Severity: important
Tags: patch

The gps daemon, when connected to public ais source, is crashing every week or
so.

I traced back the segment violation to a unsigned size being assigned a
negative value, leading to a call to memcpy with an insane value.

You can reproduce this with a simple:
echo '!AIVDM,1,1,,A,J=IJuwOmoTt,2*3F' | gpsdecode

SIGSEGV
(gdb) bt
#0  0xb75e2d5c in memcpy () from /lib/i686/cmov/libc.so.6
#1  0xb66a972b in aivdm_decode (buf=0x868e76c "!AIVDM,1,1,,A,J=IJuwOmoTt,2*3F", 
buflen=31, ais_contexts=0x86e70f8, 
    ais=0x86e4c38) at driver_aivdm.c:810
...
(gdb) up
(gdb) display ais->type
5: ais->type = 26
(gdb) display ais->repeat
6: ais->repeat = 0
(gdb) display ais->mmsi
7: ais->mmsi = 899071485
(gdb) display ais->type
8: ais->type = 26
(gdb) display ais_context->bitlen
9: ais_context->bitlen = 64
(gdb) display ais->type26.addressed
10: ais->type26.addressed = true
(gdb) display ais->type26.structured
11: ais->type26.structured = true
(gdb) display ais->type26.dest_mmsi
12: ais->type26.dest_mmsi = 1031246784
(gdb) display ais->type26.app_id
13: ais->type26.app_id = 0
(gdb) display ais->type26.bitcount
14: ais->type26.bitcount = 4294967284
(gdb) display (ais->type26.bitcount + 7) / 8
15: (ais->type26.bitcount + 7) / 8 = 536870911


(gdb)display 60 + 16*ais->type26.structured
17: 60 + 16 * ais->type26.structured = 76

Message type 25 is checking bitlen is not too small before assigning
bitcount, after testing addressed and structured.

Attached is a 2 lines patch that adds such a test for type 26 messages.

After patching
  echo '!AIVDM,1,1,,A,J=IJuwOmoTt,2*3F' | gpsdecode -D 2
yields
  gpsdecode: AIVDM payload is 64 bits, 8 chars: 68d65af7f7f5de4f
  gpsdecode: AIVDM message type 26, MMSI 899071485:
  gpsdecode: AIVDM message type 26 too short for mode.
instead of
  Segment violation

-- System Information:
Debian Release: squeeze/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: i386 (i686)

Kernel: Linux 2.6.32-5-686 (SMP w/2 CPU cores)
Locale: LANG=en_GB.utf8, LC_CTYPE=en_GB.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Subject: Fixes SEGV on reception of short aivdm type 26 message
Author: Nirgal Vourgère <[email protected]>
Description: gpsd is crashing when receiving some messages such as
 !AIVDM,1,1,,A,J=IJuwOmoTt,2*3F
 because unsigned value ais->type26.bitcount is sometimes assigned
 a negative value.

TODO (see http://dep.debian.net/deps/dep3/):
Bug-Debian: http://bugs.debian.org/500000
Last-Update: 2010-11-14
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>

Index: gpsd-2.95/driver_aivdm.c
===================================================================
--- gpsd-2.95.orig/driver_aivdm.c
+++ gpsd-2.95/driver_aivdm.c
@@ -802,6 +802,10 @@
 	    }
 	    ais->type26.addressed	= (bool)UBITS(38, 1);
 	    ais->type26.structured	= (bool)UBITS(39, 1);
+	    if (ais_context->bitlen < 40 + 16*ais->type26.structured + 30*ais->type26.addressed + 20) {
+		gpsd_report(LOG_WARN, "AIVDM message type 26 too short for mode.\n");
+		return false;
+	    }
 	    if (ais->type26.addressed)
 		ais->type26.dest_mmsi   = UBITS(40, 30);
 	    if (ais->type26.structured)

Reply via email to