Compare commits

...

7 Commits

Author SHA1 Message Date
Ramon Roche 0b6e4687de fix(mavlink): remove all stale mavlink_tests references
The mavlink_tests module was deleted in 1009268d31 but several
references were left behind, breaking builds on all targets.

Removed:
- CMakeLists.txt: add_subdirectory(mavlink_tests)
- mavlink_ftp.cpp: #include of deleted mavlink_ftp_test.h
- mavlink_ftp.h: MavlinkFtpTest forward decl and friend class
- posix-configs/SITL/init/test/test_mavlink: dead init script
- sitl_tests.cmake: sitl-mavlink CTest target
- install-voxl.sh: px4-mavlink_tests symlink

Ref: https://github.com/PX4/PX4-Autopilot/issues/26738
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
Ramon Roche 69a6b9eee6 fix(zenoh): validate payload size before stack allocation
Reject Zenoh payloads that exceed the expected uORB topic size plus
CDR header (4 bytes), or that are too small to contain a valid CDR
header. This prevents a stack overflow from crafted network input
where z_bytes_len(payload) controls a VLA allocation.

Fixes GHSA-69g4-hcqf-j45p

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
Ramon Roche b5b48536a3 fix(mavlink): correct session validation in FTP write and burst operations
Use logical OR (||) instead of AND (&&) in _workWrite() and _workBurst()
session validation, matching the correct logic already used in _workRead()
and _workTerminate(). The AND operator allowed operations to proceed with
an invalid session ID as long as a valid file descriptor existed.

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
Ramon Roche 3bd06cc02f refactor(mavlink): remove dead FTP unit test code
Remove the old MAVLINK_FTP_UNIT_TEST infrastructure that has been dead
code for years (not enabled in any board config). This includes:

- src/modules/mavlink/mavlink_tests/ directory (test suite, CMakeLists)
- All #ifdef MAVLINK_FTP_UNIT_TEST blocks in mavlink_ftp.cpp
- set_unittest_worker() callback mechanism in mavlink_ftp.h
- Conditional uAvionix include in mavlink_bridge_header.h

The test suite will be ported to GTest as a follow-up.

Ref: https://github.com/PX4/PX4-Autopilot/issues/26738
Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
Ramon Roche 48335ac3f1 fix(mavlink): reject path traversal sequences in FTP operations
Add _validatePath() that rejects paths containing ".." components,
preventing directory traversal outside the FTP root directory.
Applied to all FTP operation handlers (list, open, remove, truncate,
rename, mkdir, rmdir, CRC32).

Fixes GHSA-fh32-qxj9-x32f, GHSA-pm28-2j4f-8jxv

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
Ramon Roche 9605d8dce8 fix(tattu_can): validate CAN frame bounds before buffer copy
Add bounds checking in the CAN frame assembly loop to prevent a buffer
overflow when copying payloads into the Tattu12SBatteryMessage struct.
A crafted CAN frame with a corrupt payload_size could write past the
48-byte struct boundary. Also guard against payload_size of 0 which
would cause an unsigned integer underflow on the size_t subtraction.

Fixes GHSA-wxwm-xmx9-hr32

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
Ramon Roche 3d63672c03 fix(telemetry/bst): validate reply length and dev_name_len before use
Reject replies with length >= sizeof(BSTPacket) to prevent OOB read
in CRC calculation. Clamp dev_name_len to buffer size to prevent OOB
write during null termination.

Signed-off-by: Ramon Roche <mrpollo@gmail.com>
2026-03-13 12:30:05 -07:00
14 changed files with 78 additions and 1389 deletions
@@ -65,7 +65,6 @@ adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-logger"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-manual_control"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-mavlink"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-mavlink_bridge"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-mavlink_tests"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-mb12xx"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-mc_att_control"
adb shell "cd /usr/bin; /bin/ln -f -s px4 px4-mc_pos_control"
-14
View File
@@ -72,20 +72,6 @@ endforeach()
# Mavlink test requires mavlink running
add_test(NAME sitl-mavlink
COMMAND $<TARGET_FILE:px4>
-s ${PX4_SOURCE_DIR}/posix-configs/SITL/init/test/test_mavlink
-t ${PX4_SOURCE_DIR}/test_data
${PX4_SOURCE_DIR}/ROMFS/px4fmu_test
WORKING_DIRECTORY ${SITL_WORKING_DIR}
)
set_tests_properties(sitl-mavlink PROPERTIES FAIL_REGULAR_EXPRESSION "FAIL")
set_tests_properties(sitl-mavlink PROPERTIES PASS_REGULAR_EXPRESSION "ALL TESTS PASSED")
sanitizer_fail_test_on_error(sitl-mavlink)
# IMU filtering
add_test(NAME sitl-imu_filtering
COMMAND $<TARGET_FILE:px4>
-23
View File
@@ -1,23 +0,0 @@
#!/bin/sh
# PX4 commands need the 'px4-' prefix in bash.
# (px4-alias.sh is expected to be in the PATH)
. px4-alias.sh
param load
param set CBRK_SUPPLY_CHK 894281
dataman start
battery_simulator start
simulator_mavlink start
tone_alarm start
pwm_out_sim start
ver all
mavlink start -x -u 14556 -r 2000000
mavlink boot_complete
mavlink_tests
shutdown
+9 -2
View File
@@ -96,9 +96,16 @@ void TattuCan::Run()
while (receive(&received_frame) > 0) {
if (received_frame.payload_size == 0) {
break;
}
size_t payload_size = received_frame.payload_size - 1;
// TODO: add check to prevent buffer overflow from a corrupt 'payload_size' value
// TODO: AND look for TAIL_BYTE_START_OF_TRANSFER to indicate end of transfer. Untested...
if (offset + payload_size > sizeof(tattu_message)) {
break;
}
memcpy(((char *)&tattu_message) + offset, received_frame.payload, payload_size);
offset += payload_size;
}
+10
View File
@@ -197,6 +197,12 @@ int BST::probe()
}
uint8_t *reply_raw = reinterpret_cast<uint8_t *>(&dev_info_reply);
if (dev_info_reply.length >= sizeof(dev_info_reply)) {
PX4_ERR("invalid reply length: %u", dev_info_reply.length);
return -EIO;
}
uint8_t crc_calc = crc8(reinterpret_cast<uint8_t *>(&dev_info_reply.type), dev_info_reply.length - 1);
uint8_t crc_recv = reply_raw[dev_info_reply.length];
@@ -205,6 +211,10 @@ int BST::probe()
return -EIO;
}
if (dev_info_reply.payload.dev_name_len >= sizeof(dev_info_reply.payload.dev_name)) {
dev_info_reply.payload.dev_name_len = sizeof(dev_info_reply.payload.dev_name) - 1;
}
dev_info_reply.payload.dev_name[dev_info_reply.payload.dev_name_len] = '\0';
PX4_DEBUG("device info: hardware ID: 0x%08X, firmware ID: 0x%04X, device name: %s",
(int)swap_uint32(dev_info_reply.payload.hw_id), (int)swap_uint16(dev_info_reply.payload.fw_id),
-4
View File
@@ -143,10 +143,6 @@ px4_add_module(
UNITY_BUILD
)
if(PX4_TESTING)
add_subdirectory(mavlink_tests)
endif()
px4_add_unit_gtest(SRC MavlinkStatustextHandlerTest.cpp
INCLUDES
${MAVLINK_LIBRARY_DIR}
@@ -93,9 +93,7 @@ extern mavlink_status_t *mavlink_get_channel_status(uint8_t chan);
extern mavlink_message_t *mavlink_get_channel_buffer(uint8_t chan);
#include <mavlink.h>
#if !MAVLINK_FTP_UNIT_TEST
#include <uAvionix.h>
#endif
__END_DECLS
+49 -54
View File
@@ -43,8 +43,6 @@
#include <cstring>
#include "mavlink_ftp.h"
#include "mavlink_tests/mavlink_ftp_test.h"
#include "mavlink_main.h"
using namespace time_literals;
@@ -75,49 +73,22 @@ MavlinkFTP::get_size()
}
}
#ifdef MAVLINK_FTP_UNIT_TEST
void
MavlinkFTP::set_unittest_worker(ReceiveMessageFunc_t rcvMsgFunc, void *worker_data)
{
_utRcvMsgFunc = rcvMsgFunc;
_worker_data = worker_data;
}
#endif
uint8_t
MavlinkFTP::_getServerSystemId()
{
#ifdef MAVLINK_FTP_UNIT_TEST
// We use fake ids when unit testing
return MavlinkFtpTest::serverSystemId;
#else
// Not unit testing, use the real thing
return _mavlink.get_system_id();
#endif
}
uint8_t
MavlinkFTP::_getServerComponentId()
{
#ifdef MAVLINK_FTP_UNIT_TEST
// We use fake ids when unit testing
return MavlinkFtpTest::serverComponentId;
#else
// Not unit testing, use the real thing
return _mavlink.get_component_id();
#endif
}
uint8_t
MavlinkFTP::_getServerChannel()
{
#ifdef MAVLINK_FTP_UNIT_TEST
// We use fake ids when unit testing
return MavlinkFtpTest::serverChannel;
#else
// Not unit testing, use the real thing
return _mavlink.get_channel();
#endif
}
void
@@ -173,11 +144,7 @@ MavlinkFTP::_process_request(
if (payload->seq_number + 1 == last_payload->seq_number) {
// this is the same request as the one we replied to last. It means the (n)ack got lost, and the GCS
// resent the request
#ifdef MAVLINK_FTP_UNIT_TEST
_utRcvMsgFunc(last_reply, _worker_data);
#else
mavlink_msg_file_transfer_protocol_send_struct(_mavlink.get_channel(), last_reply);
#endif
return;
}
}
@@ -332,12 +299,7 @@ MavlinkFTP::_reply(mavlink_file_transfer_protocol_t *ftp_req)
PX4_DEBUG("FTP: %s seq_number: %" PRIu16, payload->opcode == kRspAck ? "Ack" : "Nak", payload->seq_number);
#ifdef MAVLINK_FTP_UNIT_TEST
// Unit test hook is set, call that instead
_utRcvMsgFunc(ftp_req, _worker_data);
#else
mavlink_msg_file_transfer_protocol_send_struct(_mavlink.get_channel(), ftp_req);
#endif
}
void MavlinkFTP::_constructPath(char *dst, int dst_len, const char *path) const
@@ -362,6 +324,10 @@ MavlinkFTP::_workList(PayloadHeader *payload)
{
_constructPath(_work_buffer1, _work_buffer1_len, _data_as_cstring(payload));
if (!_validatePath(_work_buffer1)) {
return kErrFailFileProtected;
}
ErrorCode errorCode = kErrNone;
unsigned offset = 0;
@@ -510,6 +476,10 @@ MavlinkFTP::_workOpen(PayloadHeader *payload, int oflag)
_constructPath(_work_buffer1, _work_buffer1_len, _data_as_cstring(payload));
if (!_validatePath(_work_buffer1)) {
return kErrFailFileProtected;
}
PX4_DEBUG("FTP: open '%s'", _work_buffer1);
uint32_t fileSize = 0;
@@ -594,7 +564,7 @@ MavlinkFTP::_workRead(PayloadHeader *payload)
MavlinkFTP::ErrorCode
MavlinkFTP::_workBurst(PayloadHeader *payload, uint8_t target_system_id, uint8_t target_component_id)
{
if (payload->session != 0 && _session_info.fd < 0) {
if (payload->session != 0 || _session_info.fd < 0) {
PX4_DEBUG("_workBurst: no session or no fd");
return kErrInvalidSession;
}
@@ -615,7 +585,7 @@ MavlinkFTP::_workBurst(PayloadHeader *payload, uint8_t target_system_id, uint8_t
MavlinkFTP::ErrorCode
MavlinkFTP::_workWrite(PayloadHeader *payload)
{
if (payload->session != 0 && _session_info.fd < 0) {
if (payload->session != 0 || _session_info.fd < 0) {
PX4_DEBUG("_workWrite: no session or no fd");
return kErrInvalidSession;
}
@@ -652,7 +622,7 @@ MavlinkFTP::_workRemoveFile(PayloadHeader *payload)
{
_constructPath(_work_buffer1, _work_buffer1_len, _data_as_cstring(payload));
if (!_validatePathIsWritable(_work_buffer1)) {
if (!_validatePath(_work_buffer1) || !_validatePathIsWritable(_work_buffer1)) {
return kErrFailFileProtected;
}
@@ -676,7 +646,7 @@ MavlinkFTP::_workTruncateFile(PayloadHeader *payload)
_constructPath(_work_buffer1, _work_buffer1_len, _data_as_cstring(payload));
payload->size = 0;
if (!_validatePathIsWritable(_work_buffer1)) {
if (!_validatePath(_work_buffer1) || !_validatePathIsWritable(_work_buffer1)) {
return kErrFailFileProtected;
}
@@ -837,7 +807,7 @@ MavlinkFTP::_workRename(PayloadHeader *payload)
_constructPath(_work_buffer1, _work_buffer1_len, ptr);
_constructPath(_work_buffer2, _work_buffer2_len, ptr + oldpath_sz + 1);
if (!_validatePathIsWritable(_work_buffer2)) {
if (!_validatePath(_work_buffer1) || !_validatePath(_work_buffer2) || !_validatePathIsWritable(_work_buffer2)) {
return kErrFailFileProtected;
}
@@ -860,7 +830,7 @@ MavlinkFTP::_workRemoveDirectory(PayloadHeader *payload)
{
_constructPath(_work_buffer1, _work_buffer1_len, _data_as_cstring(payload));
if (!_validatePathIsWritable(_work_buffer1)) {
if (!_validatePath(_work_buffer1) || !_validatePathIsWritable(_work_buffer1)) {
return kErrFailFileProtected;
}
@@ -883,7 +853,7 @@ MavlinkFTP::_workCreateDirectory(PayloadHeader *payload)
{
_constructPath(_work_buffer1, _work_buffer1_len, _data_as_cstring(payload));
if (!_validatePathIsWritable(_work_buffer1)) {
if (!_validatePath(_work_buffer1) || !_validatePathIsWritable(_work_buffer1)) {
return kErrFailFileProtected;
}
@@ -908,6 +878,10 @@ MavlinkFTP::_workCalcFileCRC32(PayloadHeader *payload)
ssize_t bytes_read;
_constructPath(_work_buffer2, _work_buffer2_len, _data_as_cstring(payload));
if (!_validatePath(_work_buffer2)) {
return kErrFailFileProtected;
}
int fd = ::open(_work_buffer2, O_RDONLY);
if (fd < 0) {
@@ -1043,7 +1017,6 @@ void MavlinkFTP::send()
return;
}
#ifndef MAVLINK_FTP_UNIT_TEST
// Skip send if not enough room
unsigned max_bytes_to_send = _mavlink.get_free_tx_buf();
PX4_DEBUG("MavlinkFTP::send max_bytes_to_send(%u) get_free_tx_buf(%u)", max_bytes_to_send, _mavlink.get_free_tx_buf());
@@ -1052,8 +1025,6 @@ void MavlinkFTP::send()
return;
}
#endif
// Send stream packets until buffer is full
bool more_data;
@@ -1117,8 +1088,6 @@ void MavlinkFTP::send()
_session_info.stream_download = false;
} else {
#ifndef MAVLINK_FTP_UNIT_TEST
if (max_bytes_to_send < (get_size() * 2)) {
more_data = false;
@@ -1130,14 +1099,10 @@ void MavlinkFTP::send()
}
} else {
#endif
more_data = true;
payload->burst_complete = false;
#ifndef MAVLINK_FTP_UNIT_TEST
max_bytes_to_send -= get_size();
}
#endif
}
ftp_msg.target_system = _session_info.stream_target_system_id;
@@ -1147,6 +1112,36 @@ void MavlinkFTP::send()
} while (more_data);
}
/**
* Reject paths containing ".." components to prevent directory traversal
* outside of _root_dir. Walks the path checking each component between
* '/' separators. A component of exactly ".." (followed by '/' or end
* of string) is rejected.
*
* Examples:
* "/fs/microsd/logs" -> allowed
* "/fs/microsd/../etc" -> rejected
* "../../tmp/pwned" -> rejected
* "/fs/microsd/logs/.." -> rejected
* "/fs/microsd/..hidden" -> allowed (not a ".." component)
*/
bool MavlinkFTP::_validatePath(const char *path)
{
const char *p = path;
while (*p != '\0') {
if ((p == path || *(p - 1) == '/') && p[0] == '.' && p[1] == '.'
&& (p[2] == '/' || p[2] == '\0')) {
PX4_ERR("FTP: rejecting path traversal in %s", path);
return false;
}
p++;
}
return true;
}
bool MavlinkFTP::_validatePathIsWritable(const char *path)
{
#ifdef __PX4_NUTTX
+2 -19
View File
@@ -45,7 +45,6 @@
#include "mavlink_bridge_header.h"
class MavlinkFtpTest;
class Mavlink;
/// MAVLink remote file server. Support FTP like commands using MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL message.
@@ -64,13 +63,6 @@ public:
/// Handle possible FTP message
void handle_message(const mavlink_message_t *msg);
typedef void (*ReceiveMessageFunc_t)(const mavlink_file_transfer_protocol_t *ftp_req, void *worker_data);
/// @brief Sets up the server to run in unit test mode.
/// @param rcvmsgFunc Function which will be called to handle outgoing mavlink messages.
/// @param worker_data Data to pass to worker
void set_unittest_worker(ReceiveMessageFunc_t rcvMsgFunc, void *worker_data);
/// @brief This is the payload which is in mavlink_file_transfer_protocol_t.payload.
/// This needs to be packed, because it's typecasted from mavlink_file_transfer_protocol_t.payload, which starts
/// at a 3 byte offset, causing an unaligned access to seq_number and offset
@@ -156,6 +148,7 @@ private:
*/
void _constructPath(char *dst, int dst_len, const char *path) const;
bool _validatePath(const char *path);
bool _validatePathIsWritable(const char *path);
/**
@@ -183,9 +176,6 @@ private:
};
struct SessionInfo _session_info {}; ///< Session info, fd=-1 for no active session
ReceiveMessageFunc_t _utRcvMsgFunc{}; ///< Unit test override for mavlink message sending
void *_worker_data{nullptr}; ///< Additional parameter to _utRcvMsgFunc;
Mavlink &_mavlink;
/* do not allow copying this class */
@@ -200,20 +190,13 @@ private:
hrt_abstime _last_work_buffer_access{0}; ///< timestamp when the buffers were last accessed
// prepend a root directory to each file/dir access to avoid enumerating the full FS tree (e.g. on Linux).
// Note that requests can still fall outside of the root dir by using ../..
#ifdef MAVLINK_FTP_UNIT_TEST
static constexpr const char _root_dir[] = "";
#else
// Path traversal via ".." is rejected by _validatePath().
static constexpr const char _root_dir[] = PX4_ROOTFSDIR;
#endif
static constexpr const int _root_dir_len = sizeof(_root_dir) - 1;
bool _last_reply_valid = false;
uint8_t _last_reply[MAVLINK_MSG_ID_FILE_TRANSFER_PROTOCOL_LEN - MAVLINK_MSG_FILE_TRANSFER_PROTOCOL_FIELD_PAYLOAD_LEN
+ sizeof(PayloadHeader) + sizeof(uint32_t)];
// Mavlink test needs to be able to call send
friend class MavlinkFtpTest;
int _our_errno {0};
};
@@ -1,56 +0,0 @@
############################################################################
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE modules__mavlink__mavlink_tests
MAIN mavlink_tests
STACK_MAIN 8192
INCLUDES
${MAVLINK_LIBRARY_DIR}
${MAVLINK_LIBRARY_DIR}/${CONFIG_MAVLINK_DIALECT}
COMPILE_FLAGS
-DMAVLINK_FTP_UNIT_TEST
#-DMAVLINK_FTP_DEBUG
-DMavlinkStream=MavlinkStreamTest
-DMavlinkFTP=MavlinkFTPTest
-Wno-cast-align # TODO: fix and enable
-Wno-address-of-packed-member # TODO: fix in c_library_v2
-Wno-double-promotion # The fix has been proposed as PR upstream (2020-03-08)
SRCS
mavlink_tests.cpp
mavlink_ftp_test.cpp
../mavlink_stream.cpp
../mavlink_ftp.cpp
DEPENDS
mavlink_c_generate
)
File diff suppressed because it is too large Load Diff
@@ -1,139 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2014 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/// @file mavlink_ftp_test.h
/// @author Don Gagne <don@thegagnes.com>
#pragma once
#include <unit_test.h>
#include "../mavlink_bridge_header.h"
#include "../mavlink_ftp.h"
#include "../mavlink_main.h"
class MavlinkFtpTest : public UnitTest
{
public:
MavlinkFtpTest();
virtual ~MavlinkFtpTest() = default;
virtual bool run_tests(void);
static void receive_message_handler_generic(const mavlink_file_transfer_protocol_t *ftp_req, void *worker_data);
/// Worker data for stream handler
struct BurstInfo {
MavlinkFtpTest *ftp_test_class;
int burst_state;
bool single_packet_file;
uint32_t file_size;
uint8_t *file_bytes;
};
static void receive_message_handler_burst(const mavlink_file_transfer_protocol_t *ftp_req, void *worker_data);
static const uint8_t serverSystemId = 50; ///< System ID for server
static const uint8_t serverComponentId = 1; ///< Component ID for server
static const uint8_t serverChannel = 0; ///< Channel to send to
static const uint8_t clientSystemId = 1; ///< System ID for client
static const uint8_t clientComponentId = 0; ///< Component ID for client
// We don't want any of these
MavlinkFtpTest(const MavlinkFtpTest &);
MavlinkFtpTest &operator=(const MavlinkFtpTest &);
private:
virtual void _init(void);
virtual void _cleanup(void);
bool _create_test_files(void);
bool _remove_test_files(void);
bool _ack_test(void);
bool _bad_opcode_test(void);
bool _bad_datasize_test(void);
bool _list_test(void);
bool _list_eof_test(void);
bool _open_badfile_test(void);
bool _open_terminate_test(void);
bool _terminate_badsession_test(void);
bool _read_test(void);
bool _read_badsession_test(void);
bool _burst_test(void);
bool _removedirectory_test(void);
bool _createdirectory_test(void);
bool _removefile_test(void);
void _receive_message_handler_generic(const mavlink_file_transfer_protocol_t *ftp_req);
bool _setup_ftp_msg(const MavlinkFTP::PayloadHeader *payload_header,
const uint8_t *data, const uint8_t data_len,
mavlink_message_t *msg);
bool _decode_message(const mavlink_file_transfer_protocol_t *ftp_msg, const MavlinkFTP::PayloadHeader **payload);
bool _send_receive_msg(MavlinkFTP::PayloadHeader *payload_header,
const uint8_t *data,
const size_t data_len,
const MavlinkFTP::PayloadHeader **payload_reply);
void _cleanup_microsd(void);
/// A single download test case
struct DownloadTestCase {
const char *file;
const uint16_t length;
bool singlePacketRead;
bool exactlyFillPacket;
};
/// The set of test cases for download testing
static const DownloadTestCase _rgDownloadTestCases[];
/// States for stream download handler
enum {
burst_state_first_ack,
burst_state_last_ack,
burst_state_nak_eof,
burst_state_complete
};
bool _receive_message_handler_burst(const mavlink_file_transfer_protocol_t *ftp_req, BurstInfo *burst_info);
MavlinkFTP *_ftp_server;
Mavlink _mavlink;
uint16_t _expected_seq_number;
mavlink_file_transfer_protocol_t _reply_msg;
static const char _unittest_microsd_dir[];
static const char _unittest_microsd_file[];
};
bool mavlink_ftp_test(void);
@@ -1,47 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2014 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file mavlink_tests.cpp
*/
#include <systemlib/err.h>
#include "mavlink_ftp_test.h"
extern "C" __EXPORT int mavlink_tests_main(int argc, char *argv[]);
int mavlink_tests_main(int argc, char *argv[])
{
return mavlink_ftp_test() ? 0 : -1;
}
@@ -79,6 +79,14 @@ public:
const z_loaned_bytes_t *payload = z_sample_payload(sample);
size_t len = z_bytes_len(payload);
// Validate payload size to prevent stack overflow from untrusted input.
// CDR payload = 4-byte header + serialized data, which should not exceed o_size + 4.
const size_t max_payload_size = _uorb_meta->o_size + 4;
if (len > max_payload_size || len < 4) {
return;
}
#if defined(Z_FEATURE_UNSTABLE_API)
// Check if payload is contiguous so we can decode directly on that pointer
z_view_slice_t view;