xref: /CoreMQTT-Agent-v1.1.0/test/cbmc/stubs/core_mqtt_stubs.c (revision c76bf4a7fea24d4200a48aa22cf91767b59c7dae)
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