1 /*
2 * coreMQTT Agent v1.1.0
3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 /**
24 * @file core_mqtt_stubs.h
25 * @brief Stub functions to interact with queues.
26 */
27
28 #include "core_mqtt.h"
29 #include "core_mqtt_state.h"
30 #include <string.h>
31
32
isValidIncomingMqttPacket(uint8_t packetType)33 static bool isValidIncomingMqttPacket( uint8_t packetType )
34 {
35 bool isValid = false;
36
37 switch( packetType )
38 {
39 case MQTT_PACKET_TYPE_PUBACK:
40 case MQTT_PACKET_TYPE_PUBCOMP:
41 case MQTT_PACKET_TYPE_SUBACK:
42 case MQTT_PACKET_TYPE_UNSUBACK:
43 case MQTT_PACKET_TYPE_CONNACK:
44 case MQTT_PACKET_TYPE_PUBLISH:
45 case MQTT_PACKET_TYPE_PUBREC:
46 case MQTT_PACKET_TYPE_PUBREL:
47 case MQTT_PACKET_TYPE_PINGRESP:
48 isValid = true;
49 break;
50
51 default:
52 break;
53 }
54
55 return isValid;
56 }
57
MQTT_Init(MQTTContext_t * pContext,const TransportInterface_t * pTransportInterface,MQTTGetCurrentTimeFunc_t getTimeFunction,MQTTEventCallback_t userCallback,const MQTTFixedBuffer_t * pNetworkBuffer)58 MQTTStatus_t MQTT_Init( MQTTContext_t * pContext,
59 const TransportInterface_t * pTransportInterface,
60 MQTTGetCurrentTimeFunc_t getTimeFunction,
61 MQTTEventCallback_t userCallback,
62 const MQTTFixedBuffer_t * pNetworkBuffer )
63 {
64 MQTTStatus_t status;
65
66 __CPROVER_assert( pContext != NULL,
67 "MQTT Context is not NULL." );
68
69 ( void ) memset( pContext, 0x00, sizeof( MQTTContext_t ) );
70
71 pContext->connectStatus = MQTTNotConnected;
72 pContext->transportInterface = *pTransportInterface;
73 pContext->getTime = getTimeFunction;
74 pContext->appCallback = userCallback;
75 pContext->networkBuffer = *pNetworkBuffer;
76
77 /* Zero is not a valid packet ID per MQTT spec. Start from 1. */
78 pContext->nextPacketId = 1;
79
80 return status;
81 }
82
MQTT_ProcessLoop(MQTTContext_t * pContext,uint32_t timeoutMs)83 MQTTStatus_t MQTT_ProcessLoop( MQTTContext_t * pContext,
84 uint32_t timeoutMs )
85 {
86 MQTTStatus_t status;
87 MQTTPacketInfo_t * pPacketInfo;
88 MQTTDeserializedInfo_t * pDeserializedInfo;
89 size_t remainingLength;
90 MQTTPublishInfo_t * pPublishInfo;
91 uint16_t topicNameLength;
92 size_t payloadLength;
93 static bool terminate = false;
94
95 /* These constants are used to limit the range of variable length fields in
96 * an MQTT packet. This will improve the proof run time. */
97 static const uint8_t maxRemainingLength = 64U;
98 static const uint8_t subAckMinRemainingLength = 2U;
99 static const uint8_t maxTopicNameLength = 32U;
100 static const uint8_t maxPayloadLength = 64U;
101
102 __CPROVER_assert( pContext != NULL,
103 "MQTT Context is not NULL." );
104
105 /* Only one packet per MQTT_ProcessLoop is received for the proof and it will be enough
106 * to prove the memory safety. The second invocation of MQTT_ProcessLoop returns without
107 * invoking the appCallback. */
108 if( terminate == false )
109 {
110 pPacketInfo = malloc( sizeof( MQTTPacketInfo_t ) );
111 __CPROVER_assume( pPacketInfo != NULL );
112 __CPROVER_assume( isValidIncomingMqttPacket( pPacketInfo->type ) );
113 __CPROVER_assume( remainingLength < maxRemainingLength );
114
115 /* SUBACK codes will be after 2 bytes. */
116 if( pPacketInfo->type == MQTT_PACKET_TYPE_SUBACK )
117 {
118 __CPROVER_assume( remainingLength > subAckMinRemainingLength );
119 }
120
121 pPacketInfo->pRemainingData = malloc( remainingLength );
122 __CPROVER_assume( pPacketInfo->pRemainingData != NULL );
123 pPacketInfo->remainingLength = remainingLength;
124
125 pDeserializedInfo = malloc( sizeof( MQTTDeserializedInfo_t ) );
126 __CPROVER_assume( pDeserializedInfo != NULL );
127
128 if( pPacketInfo->type == MQTT_PACKET_TYPE_PUBLISH )
129 {
130 pPublishInfo = malloc( sizeof( MQTTPublishInfo_t ) );
131 __CPROVER_assume( pPublishInfo != NULL );
132
133 __CPROVER_assume( topicNameLength < maxTopicNameLength );
134 pPublishInfo->pTopicName = malloc( topicNameLength );
135 __CPROVER_assume( pPublishInfo->pTopicName != NULL );
136 pPublishInfo->topicNameLength = topicNameLength;
137
138 __CPROVER_assume( payloadLength < maxPayloadLength );
139 pPublishInfo->pPayload = malloc( payloadLength );
140 pPublishInfo->payloadLength = ( pPublishInfo->pPayload != NULL ) ? payloadLength : 0;
141
142 pDeserializedInfo->pPublishInfo = pPublishInfo;
143 }
144
145 __CPROVER_assume( pDeserializedInfo->packetIdentifier > MQTT_PACKET_ID_INVALID );
146
147 /* Invoke event callback. */
148 pContext->appCallback( pContext,
149 pPacketInfo,
150 pDeserializedInfo );
151
152 terminate = true;
153 }
154
155 __CPROVER_assume( ( status >= MQTTSuccess && status <= MQTTKeepAliveTimeout ) );
156
157 return status;
158 }
159
MQTT_Publish(MQTTContext_t * pContext,const MQTTPublishInfo_t * pPublishInfo,uint16_t packetId)160 MQTTStatus_t MQTT_Publish( MQTTContext_t * pContext,
161 const MQTTPublishInfo_t * pPublishInfo,
162 uint16_t packetId )
163 {
164 MQTTStatus_t status;
165
166 __CPROVER_assert( pContext != NULL,
167 "MQTT Context is not NULL." );
168 __CPROVER_assert( pPublishInfo != NULL,
169 "Publish Info is not NULL." );
170 __CPROVER_assume( ( status >= MQTTSuccess && status <= MQTTKeepAliveTimeout ) );
171
172 return status;
173 }
174
MQTT_PublishToResend(const MQTTContext_t * pMqttContext,MQTTStateCursor_t * pCursor)175 uint16_t MQTT_PublishToResend( const MQTTContext_t * pMqttContext,
176 MQTTStateCursor_t * pCursor )
177 {
178 uint16_t packetId;
179 static bool terminate = false;
180
181 __CPROVER_assert( pMqttContext != NULL,
182 "MQTT Context is not NULL." );
183 __CPROVER_assert( pCursor != NULL,
184 "MQTT State Cursor is not NULL." );
185
186 if( terminate == true )
187 {
188 packetId = MQTT_PACKET_ID_INVALID;
189 }
190 else
191 {
192 #ifdef MAX_PACKET_ID
193
194 /* Limit the packet Ids so that the range of packet ids so that the
195 * probability of finding a matching packet in the pending acks is high. */
196 __CPROVER_assume( packetId < MAX_PACKET_ID );
197 #endif
198 }
199
200 terminate = true;
201
202 return packetId;
203 }
204