aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2013-07-31 21:59:29 +0200
committerIvan Kluchnikov <kluchnikovi@gmail.com>2013-09-04 21:29:00 +0400
commit9d938388f678e8c753e128199185f17a35a45247 (patch)
treeece4f4830cef79cd95595db9f4c089926abafbd3
parentbc1e52cfbf89dc9c669281181f99dc5098ea8364 (diff)
emu: Add a crash re-producer for the SGSN (and the concept of tests)
Introduce the concept of tests that will be ran one after the other. This new test will send static message that will lead to the opening of a PDP context. At this point one should use ping with a large packet size and suspend/stop the emulator. Once the NS connection is considered dead the SGSN will crash with a double free. Reproduce: 0.) Add IMSI 901700000003094 to the ACL 1.) Stop/Suspend the emulation process so the NS Alive times out 2.) Use ping IP -s 2048 This will create a double free... #4 0xb7bb2646 in talloc_abort_double_free () at talloc.c:175 #5 0xb7bbd41a in talloc_chunk_from_ptr (ptr=0x8091208) at talloc.c:190 #6 _talloc_free (ptr=0x8091208) at talloc.c:517 #7 talloc_free (ptr=ptr@entry=0x8091208) at talloc.c:990 #8 0xb7bb319b in msgb_free (m=m@entry=0x8091208) at msgb.c:72 #9 0x0804db54 in sndcp_send_ud_frag (fs=0xbfffcc6c) at gprs_sndcp.c:423 #10 sndcp_unitdata_req (msg=msg@entry=0x808eed8, lle=0x808fbc8, nsapi=5 '\005', mmcontext=mmcontext@entry=0x80903e8) at gprs_sndcp.c:471
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/emu/gprs_tests.h65
-rw-r--r--tests/emu/openbsc_clone.c18
-rw-r--r--tests/emu/openbsc_clone.h32
-rw-r--r--tests/emu/pcu_emu.cpp42
-rw-r--r--tests/emu/test_pdp_activation.cpp171
-rw-r--r--tests/emu/test_replay_gprs_attach.cpp15
7 files changed, 332 insertions, 14 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0131e47..88be652 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -10,7 +10,8 @@ rlcmac_RLCMACTest_LDADD = \
$(COMMON_LA)
emu_pcu_emu_SOURCES = emu/pcu_emu.cpp emu/test_replay_gprs_attach.cpp \
- emu/openbsc_clone.c emu/openbsc_clone.h
+ emu/openbsc_clone.c emu/openbsc_clone.h emu/gprs_tests.h \
+ emu/test_pdp_activation.cpp
emu_pcu_emu_LDADD = \
$(top_builddir)/src/libgprs.la \
$(LIBOSMOGB_LIBS) \
diff --git a/tests/emu/gprs_tests.h b/tests/emu/gprs_tests.h
new file mode 100644
index 0000000..1f2c3fb
--- /dev/null
+++ b/tests/emu/gprs_tests.h
@@ -0,0 +1,65 @@
+/* (C) 2013 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef tests_h
+#define tests_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <osmocom/core/msgb.h>
+#include <string.h>
+
+struct gprs_bssgp_pcu;
+struct tlv_parsed;
+struct msgb;
+
+struct gprs_test {
+ gprs_test(const char *name, const char *description,
+ void (*start)(struct gprs_bssgp_pcu *),
+ void (*data) (struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *parsed))
+ : name(name)
+ , description(description)
+ , start(start)
+ , data(data)
+ {}
+
+ const char *name;
+ const char *description;
+ void (*start)(struct gprs_bssgp_pcu *);
+ void (*data) (struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *);
+};
+
+void gprs_test_success(struct gprs_bssgp_pcu *);
+
+static inline struct msgb *create_msg(const uint8_t *data, size_t len)
+{
+ struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg");
+ msg->l3h = msgb_put(msg, len);
+ memcpy(msg->l3h, data, len);
+ return msg;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/emu/openbsc_clone.c b/tests/emu/openbsc_clone.c
index 707819b..575f4e1 100644
--- a/tests/emu/openbsc_clone.c
+++ b/tests/emu/openbsc_clone.c
@@ -21,6 +21,7 @@
#include <gprs_debug.h>
#include <osmocom/core/utils.h>
+#include <osmocom/gsm/tlv.h>
#include <errno.h>
@@ -214,3 +215,20 @@ int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
return 0;
}
+
+const struct tlv_definition gsm48_gmm_att_tlvdef = {
+ .def = {
+ [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 },
+ [GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 },
+ [GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 },
+ [GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 },
+ [GSM48_IE_GMM_AUTH_RAND] = { TLV_TYPE_FIXED, 16 },
+ [GSM48_IE_GMM_AUTH_SRES] = { TLV_TYPE_FIXED, 4 },
+ [GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 },
+ [GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 },
+ [GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 },
+ [GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 },
+ [GSM48_IE_GMM_PS_LCS_CAPA] = { TLV_TYPE_TLV, 0 },
+ [GSM48_IE_GMM_GMM_MBMS_CTX_ST] = { TLV_TYPE_TLV, 0 },
+ },
+};
diff --git a/tests/emu/openbsc_clone.h b/tests/emu/openbsc_clone.h
index d62ff22..b3cc033 100644
--- a/tests/emu/openbsc_clone.h
+++ b/tests/emu/openbsc_clone.h
@@ -23,6 +23,8 @@
extern "C" {
#endif
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
#include <stdint.h>
enum gprs_llc_cmd {
@@ -57,6 +59,36 @@ struct gprs_llc_hdr_parsed {
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, const uint8_t *llc_hdr, int len);
+/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */
+#define GSM48_MT_GMM_ATTACH_ACK 0x02
+
+/* Chapter 9.4.2 / Table 9.4.2 */
+struct gsm48_attach_ack {
+ uint8_t att_result:4, /* 10.5.5.7 */
+ force_stby:4; /* 10.5.5.1 */
+ uint8_t ra_upd_timer; /* 10.5.7.3 */
+ uint8_t radio_prio; /* 10.5.7.2 */
+ struct gsm48_ra_id ra_id; /* 10.5.5.15 */
+ uint8_t data[0];
+} __attribute__((packed));
+
+enum gsm48_gprs_ie_mm {
+ GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */
+ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */
+ GSM48_IE_GMM_ALLOC_PTMSI = 0x18, /* 10.5.1.4 */
+ GSM48_IE_GMM_PTMSI_SIG = 0x19, /* 10.5.5.8 */
+ GSM48_IE_GMM_AUTH_RAND = 0x21, /* 10.5.3.1 */
+ GSM48_IE_GMM_AUTH_SRES = 0x22, /* 10.5.3.2 */
+ GSM48_IE_GMM_IMEISV = 0x23, /* 10.5.1.4 */
+ GSM48_IE_GMM_DRX_PARAM = 0x27, /* 10.5.5.6 */
+ GSM48_IE_GMM_MS_NET_CAPA = 0x31, /* 10.5.5.12 */
+ GSM48_IE_GMM_PDP_CTX_STATUS = 0x32, /* 10.5.7.1 */
+ GSM48_IE_GMM_PS_LCS_CAPA = 0x33, /* 10.5.5.22 */
+ GSM48_IE_GMM_GMM_MBMS_CTX_ST = 0x35, /* 10.5.7.6 */
+};
+
+extern const struct tlv_definition gsm48_gmm_att_tlvdef;
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/emu/pcu_emu.cpp b/tests/emu/pcu_emu.cpp
index f4d38cd..b68b856 100644
--- a/tests/emu/pcu_emu.cpp
+++ b/tests/emu/pcu_emu.cpp
@@ -24,6 +24,9 @@ extern "C" {
#include <pcu_vty.h>
}
+#include "gprs_tests.h"
+
+
#include <gprs_bssgp_pcu.h>
#include <gprs_rlcmac.h>
@@ -31,6 +34,8 @@ extern "C" {
#include <sys/types.h>
#include <sys/socket.h>
+static int current_test;
+
/* Extern data to please the underlying code */
void *tall_pcu_ctx;
struct gprs_rlcmac_bts *gprs_rlcmac_bts;
@@ -39,6 +44,24 @@ int16_t spoof_mnc = 0, spoof_mcc = 0;
extern void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu);
extern void test_replay_gprs_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *);
+extern void test_pdp_activation_start(struct gprs_bssgp_pcu *pcu);
+extern void test_pdp_activation_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed*);
+
+struct gprs_test all_tests[] = {
+ gprs_test("gprs_attach_with_tmsi",
+ "A simple test that verifies that N(U) is "
+ "increasing across various messages. This makes "
+ "sure that no new LLE/LLME is created on the fly.",
+ test_replay_gprs_attach,
+ test_replay_gprs_data),
+ gprs_test("gprs_full_attach_pdp_activation",
+ "A simple test to do a GPRS attach and open a PDP "
+ "context. Then goes to sleep and waits for you to ping "
+ "the connection and hopefully re-produce a crash.",
+ test_pdp_activation_start,
+ test_pdp_activation_data),
+};
+
struct gprs_rlcmac_bts *create_bts()
{
struct gprs_rlcmac_bts *bts;
@@ -68,12 +91,12 @@ struct gprs_rlcmac_bts *create_bts()
static void bvci_unblocked(struct gprs_bssgp_pcu *pcu)
{
printf("BVCI unblocked. We can begin with test cases.\n");
- test_replay_gprs_attach(pcu);
+ all_tests[current_test].start(pcu);
}
static void bssgp_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp)
{
- test_replay_gprs_data(pcu, msg, tp);
+ all_tests[current_test].data(pcu, msg, tp);
}
void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts,
@@ -112,6 +135,21 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
}
+
+/*
+ * Test handling..
+ */
+void gprs_test_success(struct gprs_bssgp_pcu *pcu)
+{
+ current_test += 1;
+ if (current_test >= ARRAY_SIZE(all_tests)) {
+ printf("All tests executed.\n");
+ exit(EXIT_SUCCESS);
+ }
+
+ all_tests[current_test].start(pcu);
+}
+
/*
* stubs that should not be reached
*/
diff --git a/tests/emu/test_pdp_activation.cpp b/tests/emu/test_pdp_activation.cpp
new file mode 100644
index 0000000..673874f
--- /dev/null
+++ b/tests/emu/test_pdp_activation.cpp
@@ -0,0 +1,171 @@
+/* (C) 2013 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+extern "C" {
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/backtrace.h>
+#include <osmocom/gsm/gsm_utils.h>
+}
+
+#include "openbsc_clone.h"
+#include "gprs_tests.h"
+
+#include <gprs_bssgp_pcu.h>
+
+#include <stdint.h>
+#include <string.h>
+
+static const uint8_t attach[] = {
+ 0x0e, 0x00, 0x26,
+ 0x01, 0xc0, 0x01, 0x08, 0x01, 0x02, 0xe5, 0x80,
+ 0x71, 0x0d, 0x01, 0x05, 0xf4, 0x02, 0x30, 0xef,
+ 0x0e, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x00, 0x0b,
+ 0x34, 0xc7, 0x03, 0x2a, 0xa0, 0x42, 0x7c, 0xad,
+ 0xe1, 0x18, 0x0b, 0xf8, 0xef, 0xfc
+};
+
+static const uint8_t id_resp_imei[] = {
+ 0x0e, 0x00, 0x11,
+ 0x01, 0xc0, 0x05, 0x08, 0x16, 0x08, 0x3a, 0x49,
+ 0x50, 0x13, 0x28, 0x15, 0x80, 0x01, 0x21, 0x6c,
+ 0x22
+};
+
+static const uint8_t id_resp_imsi[] = {
+ 0x0e, 0x00, 0x11,
+ 0x01, 0xc0, 0x09, 0x08, 0x16, 0x08, 0x99, 0x10,
+ 0x07, 0x00, 0x00, 0x00, 0x03, 0x49, 0xc7, 0x5b,
+ 0xb6
+};
+
+static const uint8_t attach_complete[] = {
+ 0x0e, 0x00, 0x08,
+ 0x01, 0xc0, 0x0d, 0x08, 0x03, 0x55, 0x1c, 0xea
+};
+
+static const uint8_t pdp_context[] = {
+ 0x0e, 0x00, 0x5a,
+ 0x01, 0xc0, 0x11, 0x0a, 0x41, 0x05, 0x03, 0x0c,
+ 0x00, 0x00, 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x21, 0x28,
+ 0x12, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
+ 0x65, 0x74, 0x05, 0x65, 0x70, 0x6c, 0x75, 0x73,
+ 0x02, 0x64, 0x65, 0x27, 0x2a, 0x80, 0xc0, 0x23,
+ 0x13, 0x01, 0x00, 0x00, 0x13, 0x05, 0x65, 0x70,
+ 0x6c, 0x75, 0x73, 0x08, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x80, 0x21, 0x10, 0x01,
+ 0x00, 0x00, 0x10, 0x81, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x83, 0x06, 0x00, 0x00, 0x00, 0x00, 0xcf,
+ 0x90, 0xcc
+};
+
+static const uint8_t qos_profile[] = { 0x0, 0x0, 0x04 };
+static uint32_t tlli = 0xadf11821;
+
+enum state {
+ Test_Start,
+ Test_IdRespIMEI,
+ Test_IdRespIMSI,
+ Test_AttachCompl,
+ Test_PDPAct,
+ Test_Done,
+};
+
+static enum state current_state = Test_Start;
+
+static void extract_tmsi_and_generate_tlli(struct msgb *msg, struct tlv_parsed *tp)
+{
+ uint32_t tmsi;
+ struct bssgp_ud_hdr *budh;
+ struct gprs_llc_hdr_parsed hp;
+ struct tlv_parsed ack_tp;
+ int rc;
+
+ gprs_llc_hdr_parse(&hp, TLVP_VAL(tp, BSSGP_IE_LLC_PDU),
+ TLVP_LEN(tp, BSSGP_IE_LLC_PDU));
+ msgb_gmmh(msg) = (unsigned char *) hp.data;
+
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+
+ OSMO_ASSERT(gh->msg_type == GSM48_MT_GMM_ATTACH_ACK);
+ struct gsm48_attach_ack *ack = (struct gsm48_attach_ack *) gh->data;
+ rc = tlv_parse(&ack_tp, &gsm48_gmm_att_tlvdef, ack->data,
+ (msg->data + msg->len) - ack->data, 0, 0);
+
+
+ OSMO_ASSERT(TLVP_PRESENT(&ack_tp, GSM48_IE_GMM_ALLOC_PTMSI));
+ memcpy(&tmsi, TLVP_VAL(&ack_tp, GSM48_IE_GMM_ALLOC_PTMSI) + 1, 4);
+ tmsi = ntohl(tmsi);
+ tlli = gprs_tmsi2tlli(tmsi, TLLI_LOCAL);
+ printf("New TLLI(0x%08x) based on tmsi(0x%x)\n", tlli, tmsi);
+}
+
+void test_pdp_activation_start(struct gprs_bssgp_pcu *pcu)
+{
+ struct msgb *msg = create_msg(attach, ARRAY_SIZE(attach));
+ bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, msg);
+ current_state = Test_IdRespIMEI;
+}
+
+
+void test_pdp_activation_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp)
+{
+ const uint8_t *data;
+ size_t len;
+
+ switch (current_state) {
+ case Test_IdRespIMEI:
+ data = id_resp_imei;
+ len = ARRAY_SIZE(id_resp_imei);
+ current_state = Test_IdRespIMSI;
+ break;
+ case Test_IdRespIMSI:
+ data = id_resp_imsi;
+ len = ARRAY_SIZE(id_resp_imsi);
+ current_state = Test_AttachCompl;
+ break;
+ case Test_AttachCompl:
+ data = attach_complete;
+ len = ARRAY_SIZE(attach_complete);
+ extract_tmsi_and_generate_tlli(msg, tp);
+ current_state = Test_PDPAct;
+ break;
+ case Test_PDPAct:
+ printf("PDP context is active or not...\n");
+ return;
+ break;
+ case Test_Done:
+ case Test_Start: /* fall through */
+ return;
+ break;
+ default:
+ printf("Unknown state. %d\n", current_state);
+ return;
+ break;
+ };
+
+ struct msgb *out = create_msg(data, len);
+ bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, out);
+
+ /* send it after the PDP... */
+ if (current_state == Test_PDPAct) {
+ out = create_msg(pdp_context, ARRAY_SIZE(pdp_context));
+ bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, out);
+ }
+}
diff --git a/tests/emu/test_replay_gprs_attach.cpp b/tests/emu/test_replay_gprs_attach.cpp
index fb1e77f..9bcab57 100644
--- a/tests/emu/test_replay_gprs_attach.cpp
+++ b/tests/emu/test_replay_gprs_attach.cpp
@@ -24,6 +24,7 @@ extern "C" {
}
#include "openbsc_clone.h"
+#include "gprs_tests.h"
#include <gprs_bssgp_pcu.h>
@@ -45,14 +46,6 @@ static const uint8_t gprs_attach_llc[] = {
static int next_wanted_nu;
-struct msgb *create_msg(const uint8_t *data, size_t len)
-{
- struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg");
- msg->l3h = msgb_put(msg, len);
- memcpy(msg->l3h, data, len);
- return msg;
-}
-
void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu)
{
uint32_t tlli = 0xadf11820;
@@ -88,8 +81,8 @@ void test_replay_gprs_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct
OSMO_ASSERT(ph.seq_tx == next_wanted_nu++);
/* this test just wants to see messages... no further data is sent */
- if (next_wanted_nu == 4) {
- printf("Test done.\n");
- exit(EXIT_SUCCESS);
+ if (next_wanted_nu == 6) {
+ printf("GPRS attach with increasing N(U) done.\n");
+ gprs_test_success(pcu);
}
}