Package: mod-proxy-msrpc Version: 0.5-1 Severity: serious Tags: sid + patch Justification: FTBFS User: debian-m...@lists.debian.org Usertags: mips-patch
Hello, Package mod-proxy-msrpc_0.5-1 FTBFS on mips and on other big-endian architectures. mips build log: https://buildd.debian.org/status/fetch.php?pkg=mod-proxy-msrpc&arch=mips&ver=0.5-1&stamp=1399057058 There is a solution for this problem upstream. I have created a patch using upstream fixes for big-endian. A patch is attached. With this patch applied, package builds successfully on mips. Regards, Jurica
--- mod-proxy-msrpc-0.5.orig/src/msrpc_pdu_parser.c +++ mod-proxy-msrpc-0.5/src/msrpc_pdu_parser.c @@ -72,6 +72,8 @@ static const char const *msrpc_rts_pdu_c NULL, }; +#define MSRPC_PDU_IS_LITTLE_ENDIAN (pdu->data_representation == MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN) + apr_status_t msrpc_pdu_get_length(const char *buf, apr_size_t *length) { msrpc_pdu_t *pdu = (msrpc_pdu_t *)buf; @@ -81,7 +83,10 @@ apr_status_t msrpc_pdu_get_length(const return APR_INCOMPLETE; } - *length = pdu->frag_length; + #ifdef DEBUG_MSRPC_PDU_PARSER + printf("data representation: 0x%08x\n", (uint32_t)pdu->data_representation); + #endif + *length = MSRPC_PDU_IS_LITTLE_ENDIAN ? pdu->frag_length : swap_bytes_uint16_t(pdu->frag_length); return APR_SUCCESS; } @@ -110,11 +115,13 @@ apr_status_t msrpc_pdu_validate(const ch if (error) *error = "PDU type"; return APR_FROM_OS_ERROR(EBADMSG); } - if (pdu->data_representation != 16) { + if ((pdu->data_representation != MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN) && + (pdu->data_representation != MSRPC_PDU_DATA_REPRESENTATION_BIG_ENDIAN)) { if (error) *error = "data representation"; return APR_FROM_OS_ERROR(EBADMSG); } - if (pdu->frag_length % 4 != 0) { + uint16_t frag_length = MSRPC_PDU_IS_LITTLE_ENDIAN ? pdu->frag_length : swap_bytes_uint16_t(pdu->frag_length); + if (frag_length % 4 != 0) { if (error) *error = "unaligned length"; return APR_FROM_OS_ERROR(EBADMSG); } @@ -130,18 +137,24 @@ apr_status_t msrpc_pdu_get_rts_pdu_count if (pdu->type != MSRPC_PDU_RTS) { return APR_FROM_OS_ERROR(EINVAL); } - *count = pdu->rts_pdu_count; + *count = MSRPC_PDU_IS_LITTLE_ENDIAN ? pdu->rts_pdu_count : swap_bytes_uint16_t(pdu->rts_pdu_count); return APR_SUCCESS; } -apr_size_t msrpc_rts_pdu_len(const msrpc_rts_pdu_t *pdu) +unsigned int msrpc_rts_pdu_len(const msrpc_rts_pdu_t *pdu, uint32_t data_representation) { apr_size_t size = 0; uint32_t conformance_count; uint32_t addrtype; + uint32_t command; assert(pdu != NULL); - switch (pdu->command) { + command = (data_representation == MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN) ? pdu->command : swap_bytes_uint32_t(pdu->command); + #ifdef DEBUG_MSRPC_PDU_PARSER + printf("msrpc_rts_pdu_len: data representation: 0x%08x, command: 0x%08x\n", data_representation, command); + #endif + + switch (command) { case RTS_CMD_RECEIVE_WINDOW_SIZE: case RTS_CMD_CONNECTION_TIMEOUT: case RTS_CMD_CHANNEL_LIFETIME: @@ -167,14 +180,22 @@ apr_size_t msrpc_rts_pdu_len(const msrpc break; case RTS_CMD_PADDING: // see http://msdn.microsoft.com/en-us/library/cc244015.aspx - conformance_count = pdu->u32[0]; + if (data_representation == MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN) { + conformance_count = pdu->u32[0]; + } else { + conformance_count = swap_bytes_uint32_t(pdu->u32[0]); + } size = sizeof(pdu->command) + sizeof(conformance_count) + conformance_count; break; case RTS_CMD_CLIENT_ADDRESS: // see http://msdn.microsoft.com/en-us/library/cc244004.aspx // and http://msdn.microsoft.com/en-us/library/cc243993.aspx - addrtype = pdu->u32[0]; + if (data_representation == MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN) { + addrtype = pdu->u32[0]; + } else { + addrtype = swap_bytes_uint32_t(pdu->u32[0]); + } size = sizeof(pdu->command) + sizeof(addrtype); switch (addrtype) { case RTS_IPV4: @@ -194,32 +215,33 @@ apr_size_t msrpc_rts_pdu_len(const msrpc return size; } -apr_status_t msrpc_pdu_get_rts_pdu(const char *buf, unsigned int offset, msrpc_rts_pdu_t **rts_pdu, apr_size_t *len) +apr_status_t msrpc_pdu_get_rts_pdu(const char *buf, unsigned int offset, msrpc_rts_pdu_t **rts_pdu, unsigned int *len) { assert(buf != NULL); assert(rts_pdu != NULL); msrpc_pdu_t *pdu = (msrpc_pdu_t *)buf; + uint16_t frag_length = MSRPC_PDU_IS_LITTLE_ENDIAN ? pdu->frag_length : swap_bytes_uint16_t(pdu->frag_length); if (pdu->type != MSRPC_PDU_RTS) { #ifdef DEBUG_MSRPC_PDU_PARSER printf("No RTS PDU\n"); #endif return APR_FROM_OS_ERROR(EINVAL); } - if (offsetof(msrpc_pdu_t, rts_pdu_buf) + offset >= pdu->frag_length) { + if (offsetof(msrpc_pdu_t, rts_pdu_buf) + offset >= frag_length) { #ifdef DEBUG_MSRPC_PDU_PARSER printf("Frag length shorter than offset\n"); #endif return APR_FROM_OS_ERROR(EINVAL); } - apr_size_t pdusize = msrpc_rts_pdu_len((msrpc_rts_pdu_t *)(pdu->rts_pdu_buf + offset)); + unsigned int pdusize = msrpc_rts_pdu_len((msrpc_rts_pdu_t *)(pdu->rts_pdu_buf + offset), pdu->data_representation); if (pdusize == 0) { #ifdef DEBUG_MSRPC_PDU_PARSER printf("failed to parse RTS PDU\n"); #endif return APR_FROM_OS_ERROR(EBADMSG); } - if (offsetof(msrpc_pdu_t, rts_pdu_buf) + offset + pdusize > pdu->frag_length) { + if (offsetof(msrpc_pdu_t, rts_pdu_buf) + offset + pdusize > frag_length) { #ifdef DEBUG_MSRPC_PDU_PARSER printf("RTS PDU length doesn't fit into frag length at the given offset\n"); #endif @@ -240,21 +262,27 @@ const char *msrpc_pdu_get_name(const cha return NULL; } -const char *msrpc_rts_pdu_get_command_name(msrpc_rts_pdu_t *pdu) +const char *msrpc_rts_pdu_get_command_name(msrpc_rts_pdu_t *pdu, uint32_t data_representation) { + uint32_t command; + assert(pdu); - if (pdu->command <= RTS_CMD_PING_TRAFFIC_SENT_NOTIFY) { - return msrpc_rts_pdu_command_name[pdu->command]; + command = (data_representation == MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN) ? pdu->command : swap_bytes_uint32_t(pdu->command); + if (command <= RTS_CMD_PING_TRAFFIC_SENT_NOTIFY) { + return msrpc_rts_pdu_command_name[command]; } return NULL; } apr_status_t msrpc_rts_get_virtual_channel_cookie(const char *buf, uuid_t **cookie, const char **error) { + msrpc_pdu_t *pdu = (msrpc_pdu_t *)buf; + uint16_t rts_pdu_count; + apr_status_t rv; + assert(buf); assert(cookie); - msrpc_pdu_t *pdu = (msrpc_pdu_t *)buf; if (pdu->type != MSRPC_PDU_RTS) { if (error) *error = "not a RTS pdu"; return APR_FROM_OS_ERROR(EINVAL); @@ -265,22 +293,30 @@ apr_status_t msrpc_rts_get_virtual_chann return APR_FROM_OS_ERROR(EBADMSG); } - if ((pdu->rts_pdu_count != 4) && - (pdu->rts_pdu_count != 6)) { + rv = msrpc_pdu_get_rts_pdu_count(buf, &rts_pdu_count); + if (rv != APR_SUCCESS) { + if (error) *error = "unexpected error from msrpc_pdu_get_rts_pdu_count()"; + return rv; + } + + if ((rts_pdu_count != 4) && + (rts_pdu_count != 6)) { if (error) *error = "unexpected RTS command count"; return APR_FROM_OS_ERROR(EBADMSG); } unsigned int offset = 0; msrpc_rts_pdu_t *rtspdu = NULL; - apr_size_t rtspdulen = 0; - apr_size_t rv = msrpc_pdu_get_rts_pdu(buf, offset, &rtspdu, &rtspdulen); + unsigned int rtspdulen = 0; + rv = msrpc_pdu_get_rts_pdu(buf, offset, &rtspdu, &rtspdulen); if (rv != APR_SUCCESS) { if (error) *error = "failed to get first RTS command"; return rv; } - if ((rtspdu->command != RTS_CMD_VERSION) && - (rtspdu->u32[0] != 1)) { + uint32_t command = MSRPC_PDU_IS_LITTLE_ENDIAN ? rtspdu->command : swap_bytes_uint32_t(rtspdu->command); + uint32_t rts_version = MSRPC_PDU_IS_LITTLE_ENDIAN ? rtspdu->u32[0] : swap_bytes_uint32_t(rtspdu->u32[0]); + if ((command != RTS_CMD_VERSION) && + (rts_version != 1)) { if (error) *error = "unexpected first RTS command or RTS version"; return APR_FROM_OS_ERROR(EBADMSG); } @@ -291,7 +327,8 @@ apr_status_t msrpc_rts_get_virtual_chann if (error) *error = "failed to get second RTS command"; return rv; } - if (rtspdu->command != RTS_CMD_COOKIE) { + command = MSRPC_PDU_IS_LITTLE_ENDIAN ? rtspdu->command : swap_bytes_uint32_t(rtspdu->command); + if (command != RTS_CMD_COOKIE) { if (error) *error = "unexpected second RTS command"; return APR_FROM_OS_ERROR(EBADMSG); } --- mod-proxy-msrpc-0.5.orig/src/msrpc_pdu_parser.h +++ mod-proxy-msrpc-0.5/src/msrpc_pdu_parser.h @@ -30,10 +30,10 @@ typedef struct msrpc_rts_pdu msrpc_rts_p apr_status_t msrpc_pdu_get_length(const char *buf, apr_size_t *length); apr_status_t msrpc_pdu_validate(const char *buf, const char **error); apr_status_t msrpc_pdu_get_rts_pdu_count(const char *buf, uint16_t *count); -apr_size_t msrpc_rts_pdu_len(const msrpc_rts_pdu_t *pdu); -apr_status_t msrpc_pdu_get_rts_pdu(const char *buf, unsigned int offset, msrpc_rts_pdu_t **rts_pdu, apr_size_t *len); +unsigned int msrpc_rts_pdu_len(const msrpc_rts_pdu_t *pdu, uint32_t data_representation); +apr_status_t msrpc_pdu_get_rts_pdu(const char *buf, unsigned int offset, msrpc_rts_pdu_t **rts_pdu, unsigned int *len); const char *msrpc_pdu_get_name(const char *buf); -const char *msrpc_rts_pdu_get_command_name(msrpc_rts_pdu_t *pdu); +const char *msrpc_rts_pdu_get_command_name(msrpc_rts_pdu_t *pdu, uint32_t data_representation); apr_status_t msrpc_rts_get_virtual_channel_cookie(const char *buf, uuid_t **cookie, const char **error); --- mod-proxy-msrpc-0.5.orig/src/msrpc_pdu_private.h +++ mod-proxy-msrpc-0.5/src/msrpc_pdu_private.h @@ -22,6 +22,12 @@ #include <netinet/in.h> #include <uuid/uuid.h> +#define MSRPC_PDU_DATA_REPRESENTATION_BIG_ENDIAN 0x10000000 +#define MSRPC_PDU_DATA_REPRESENTATION_LITTLE_ENDIAN 0x00000010 +#define swap_bytes_uint16_t(x) ((((x) & 0x00FF) << 8) | (((x) & 0xFF00) >> 8)) +#define swap_bytes_uint32_t(x) ((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | \ + (((x) & 0x00FF0000) >> 8) | (((x) & 0xFF000000) >> 24)) + /* interpretation of such PDUs, see Microsoft's documentation: * http://msdn.microsoft.com/en-us/library/cc244017.aspx (RTS PDU header) * http://msdn.microsoft.com/en-us/library/cc244018.aspx (RTS PDU body) --- mod-proxy-msrpc-0.5.orig/test/check_msrpc_pdu_parser.c +++ mod-proxy-msrpc-0.5/test/check_msrpc_pdu_parser.c @@ -67,9 +67,11 @@ const static test_msrpc_pdu_validate_t t { "\x06\x00\x14\x03\x10\x00\x00\x00\x0c\x00\x00\x00", "PDU version", APR_FROM_OS_ERROR(EBADMSG) }, { "\x05\x01\x14\x03\x10\x00\x00\x00\x0c\x00\x00\x00", "PDU minor version", APR_FROM_OS_ERROR(EBADMSG) }, { "\x05\x00\x15\x03\x10\x00\x00\x00\x0c\x00\x00\x00", "PDU type", APR_FROM_OS_ERROR(EBADMSG) }, - { "\x05\x00\x14\x03\x00\x00\x00\x10\x0c\x00\x00\x00", "data representation", APR_FROM_OS_ERROR(EBADMSG) }, + { "\x05\x00\x14\x03\x01\x11\x11\x11\x0c\x00\x00\x00", "data representation", APR_FROM_OS_ERROR(EBADMSG) }, { "\x05\x00\x14\x03\x10\x00\x00\x00\x0d\x00\x00\x00\x00", "unaligned length", APR_FROM_OS_ERROR(EBADMSG) }, { "\x05\x00\x14\x03\x10\x00\x00\x00\x0c\x00\x00\x00", NULL, APR_SUCCESS }, + // Caution: next is a synthetic test case, big endian data representation has not been seen in the wild: + { "\x05\x00\x14\x03\x00\x00\x00\x10\x00\x0c\x00\x00", NULL, APR_SUCCESS }, { TESTDATA_INITIAL_PDU_IN, NULL, APR_SUCCESS }, { TESTDATA_INITIAL_PDU_OUT, NULL, APR_SUCCESS }, }; @@ -89,32 +91,33 @@ const static test_msrpc_pdu_get_rts_pdu_ const static size_t testset_msrpc_pdu_get_rts_pdu_count_size = sizeof(testset_msrpc_pdu_get_rts_pdu_count) / sizeof(test_msrpc_pdu_get_rts_pdu_count_t); typedef struct { + const char data_representation[4]; const char *data; - apr_size_t expected_size; + unsigned int expected_size; } test_msrpc_rts_pdu_len_t; const static test_msrpc_rts_pdu_len_t testset_msrpc_rts_pdu_len[] = { - { "\x00\x00\x00\x00", 8 }, - { "\x01\x00\x00\x00", 28 }, - { "\x02\x00\x00\x00", 8 }, - { "\x03\x00\x00\x00", 20 }, - { "\x04\x00\x00\x00", 8 }, - { "\x05\x00\x00\x00", 8 }, - { "\x06\x00\x00\x00", 8 }, - { "\x07\x00\x00\x00", 4 }, - { "\x08\x00\x00\x00\x00\x00\x00\x00", 8 }, - { "\x08\x00\x00\x00\x01\x00\x00\x00", 9 }, + { "\x10\x00\x00\x00", "\x00\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x01\x00\x00\x00", 28 }, + { "\x10\x00\x00\x00", "\x02\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x03\x00\x00\x00", 20 }, + { "\x10\x00\x00\x00", "\x04\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x05\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x06\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x07\x00\x00\x00", 4 }, + { "\x10\x00\x00\x00", "\x08\x00\x00\x00\x00\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x08\x00\x00\x00\x01\x00\x00\x00", 9 }, // checking whether all the bits from padding count are evaluated correctly: - { "\x08\x00\x00\x00\x01\x02\x03\x04", 8 + 0x04030201 }, - { "\x09\x00\x00\x00", 4 }, - { "\x0a\x00\x00\x00", 4 }, - { "\x0b\x00\x00\x00\x00\x00\x00\x00", 8 + 4 + 12 }, // IPv4 address - { "\x0b\x00\x00\x00\x01\x00\x00\x00", 8 + 16 + 12 }, // IPv6 address - { "\x0b\x00\x00\x00\x03\x00\x00\x00", 0 }, // neither IPv4 nor IPv6 address - { "\x0c\x00\x00\x00", 20 }, - { "\x0d\x00\x00\x00", 8 }, - { "\x0e\x00\x00\x00", 8 }, - { "\x0f\x00\x00\x00", 0 }, + { "\x10\x00\x00\x00", "\x08\x00\x00\x00\x01\x02\x03\x04", 8 + 0x04030201 }, + { "\x10\x00\x00\x00", "\x09\x00\x00\x00", 4 }, + { "\x10\x00\x00\x00", "\x0a\x00\x00\x00", 4 }, + { "\x10\x00\x00\x00", "\x0b\x00\x00\x00\x00\x00\x00\x00", 8 + 4 + 12 }, // IPv4 address + { "\x10\x00\x00\x00", "\x0b\x00\x00\x00\x01\x00\x00\x00", 8 + 16 + 12 }, // IPv6 address + { "\x10\x00\x00\x00", "\x0b\x00\x00\x00\x03\x00\x00\x00", 0 }, // neither IPv4 nor IPv6 address + { "\x10\x00\x00\x00", "\x0c\x00\x00\x00", 20 }, + { "\x10\x00\x00\x00", "\x0d\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x0e\x00\x00\x00", 8 }, + { "\x10\x00\x00\x00", "\x0f\x00\x00\x00", 0 }, }; const static size_t testset_msrpc_rts_pdu_len_size = sizeof(testset_msrpc_rts_pdu_len) / sizeof(test_msrpc_rts_pdu_len_t); @@ -124,7 +127,7 @@ typedef struct { int output_buffer_length; apr_status_t expected_rv; const char *expected_data; - apr_size_t expected_length; + unsigned int expected_length; } test_msrpc_pdu_get_rts_pdu_t; const static test_msrpc_pdu_get_rts_pdu_t testset_msrpc_pdu_get_rts_pdu[] = { @@ -167,7 +170,7 @@ const static size_t testset_msrpc_pdu_ge typedef struct { const char *data; - apr_size_t rts_command_count; + unsigned int rts_command_count; const char *name[7]; } test_msrpc_rts_pdu_get_command_name_t; @@ -243,10 +246,11 @@ END_TEST START_TEST (test_msrpc_rts_pdu_len) { + uint32_t data_representation = *((uint32_t *)(testset_msrpc_rts_pdu_len[_i].data_representation)); const msrpc_rts_pdu_t *pdu = (const msrpc_rts_pdu_t *)testset_msrpc_rts_pdu_len[_i].data; apr_size_t expected_size = testset_msrpc_rts_pdu_len[_i].expected_size; - apr_size_t size = msrpc_rts_pdu_len(pdu); + apr_size_t size = msrpc_rts_pdu_len(pdu, data_representation); fail_unless(size == expected_size, " for iteration %u\n" "EXPECTED size: %lu, BUT GOT size: %lu", _i, expected_size, size); } @@ -256,7 +260,7 @@ START_TEST (test_msrpc_pdu_get_rts_pdu) { const test_msrpc_pdu_get_rts_pdu_t *testset = &testset_msrpc_pdu_get_rts_pdu[_i]; msrpc_rts_pdu_t *rtspdu = NULL; - apr_size_t rtspdulen = 0; + unsigned int rtspdulen = 0; apr_status_t rv = msrpc_pdu_get_rts_pdu(testset->data, testset->offset, &rtspdu, &rtspdulen); fail_unless(testset->expected_rv == rv, " for iteration %u\n" @@ -305,9 +309,10 @@ END_TEST START_TEST (test_msrpc_rts_pdu_get_command_name) { const char *pdu = testset_msrpc_rts_pdu_get_command_name[_i].data; - apr_size_t expected_command_count = testset_msrpc_rts_pdu_get_command_name[_i].rts_command_count; + uint32_t data_representation = ((msrpc_pdu_t *)pdu)->data_representation; + unsigned int expected_command_count = testset_msrpc_rts_pdu_get_command_name[_i].rts_command_count; msrpc_rts_pdu_t *rtspdu = NULL; - apr_size_t i, rtspdulen; + unsigned int i, rtspdulen; unsigned int offset = 0; apr_status_t rv; @@ -315,7 +320,7 @@ START_TEST (test_msrpc_rts_pdu_get_comma rv = msrpc_pdu_get_rts_pdu(pdu, offset, &rtspdu, &rtspdulen); fail_unless(rv == APR_SUCCESS, " for iteration %u\n" "EXPECTED rv 0, BUT GOT rv %u", _i, rv); - const char *name = msrpc_rts_pdu_get_command_name(rtspdu); + const char *name = msrpc_rts_pdu_get_command_name(rtspdu, data_representation); const char *expected_name = testset_msrpc_rts_pdu_get_command_name[_i].name[i]; if (name) { if (!expected_name) {