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 mqtt_agent_cbmc_state.c
25  * @brief Implements the functions defined in mqtt_agent_cbmc_state.h.
26  */
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include "core_mqtt_agent.h"
30 #include "mqtt_agent_cbmc_state.h"
31 #include "network_interface_stubs.h"
32 #include "get_time_stub.h"
33 #include "incoming_publish_callback_stub.h"
34 #include "agent_message_stubs.h"
35 #include "agent_command_pool_stubs.h"
36 
commandCompleteCallbackStub(void * pCmdCallbackContext,MQTTAgentReturnInfo_t * pReturnInfo)37 static void commandCompleteCallbackStub( void * pCmdCallbackContext,
38                                          MQTTAgentReturnInfo_t * pReturnInfo )
39 {
40     __CPROVER_assert( pReturnInfo != NULL,
41                       "Command complete return info is not NULL." );
42 }
43 
allocateMqttFixedBuffer(MQTTFixedBuffer_t * pFixedBuffer)44 MQTTFixedBuffer_t * allocateMqttFixedBuffer( MQTTFixedBuffer_t * pFixedBuffer )
45 {
46     if( pFixedBuffer == NULL )
47     {
48         pFixedBuffer = malloc( sizeof( MQTTFixedBuffer_t ) );
49     }
50 
51     if( pFixedBuffer != NULL )
52     {
53         __CPROVER_assume( pFixedBuffer->size < CBMC_MAX_OBJECT_SIZE );
54         pFixedBuffer->pBuffer = malloc( pFixedBuffer->size );
55     }
56 
57     return pFixedBuffer;
58 }
59 
isValidMqttFixedBuffer(const MQTTFixedBuffer_t * pFixedBuffer)60 bool isValidMqttFixedBuffer( const MQTTFixedBuffer_t * pFixedBuffer )
61 {
62     bool isValid = false;
63 
64     if( pFixedBuffer != NULL )
65     {
66         isValid = pFixedBuffer->size < CBMC_MAX_OBJECT_SIZE;
67     }
68 
69     return isValid;
70 }
71 
allocateMqttAgentContext(MQTTAgentContext_t * pContext)72 MQTTAgentContext_t * allocateMqttAgentContext( MQTTAgentContext_t * pContext )
73 {
74     TransportInterface_t * pTransportInterface;
75     MQTTFixedBuffer_t * pNetworkBuffer;
76     MQTTAgentMessageInterface_t * pMessageInterface;
77     MQTTStatus_t status = MQTTSuccess;
78     void * pIncomingCallbackContext;
79 
80     if( pContext == NULL )
81     {
82         pContext = malloc( sizeof( MQTTAgentContext_t ) );
83     }
84 
85     pTransportInterface = malloc( sizeof( TransportInterface_t ) );
86 
87     if( pTransportInterface != NULL )
88     {
89         /* The possibility that recv and send callbacks are NULL is tested in the
90          * MQTT_Init proof. MQTT_Init is required to be called before any other
91          * function in core_mqtt.h. */
92         pTransportInterface->recv = NetworkInterfaceReceiveStub;
93         pTransportInterface->send = NetworkInterfaceSendStub;
94     }
95 
96     pNetworkBuffer = allocateMqttFixedBuffer( NULL );
97     __CPROVER_assume( isValidMqttFixedBuffer( pNetworkBuffer ) );
98 
99     pMessageInterface = malloc( sizeof( MQTTAgentMessageInterface_t ) );
100 
101     if( pMessageInterface != NULL )
102     {
103         pMessageInterface->send = AgentMessageSendStub;
104         pMessageInterface->recv = AgentMessageRecvStub;
105         pMessageInterface->getCommand = AgentGetCommandStub;
106         pMessageInterface->releaseCommand = Agent_ReleaseCommand;
107     }
108 
109     /* It is part of the API contract to call MQTT_Init() with the MQTTContext_t
110      * before any other function in core_mqtt.h. */
111     if( pContext != NULL )
112     {
113         status = MQTTAgent_Init( pContext,
114                                  pMessageInterface,
115                                  pNetworkBuffer,
116                                  pTransportInterface,
117                                  GetCurrentTimeStub,
118                                  IncomingPublishCallbackStub,
119                                  pIncomingCallbackContext );
120     }
121 
122     /* If the MQTTAgentContext_t initialization failed, then set the context to NULL
123      * so that function under harness will return immediately upon a NULL
124      * parameter check. */
125     if( status != MQTTSuccess )
126     {
127         pContext = NULL;
128     }
129 
130     return pContext;
131 }
132 
isValidMqttAgentContext(const MQTTAgentContext_t * pContext)133 bool isValidMqttAgentContext( const MQTTAgentContext_t * pContext )
134 {
135     bool isValid = false;
136 
137     if( pContext != NULL )
138     {
139         isValid = isValidMqttFixedBuffer( &( pContext->mqttContext.networkBuffer ) );
140     }
141 
142     return isValid;
143 }
144 
isAgentSendCommandFunctionStatus(MQTTStatus_t mqttStatus)145 bool isAgentSendCommandFunctionStatus( MQTTStatus_t mqttStatus )
146 {
147     return( ( mqttStatus == MQTTSuccess ) ||
148             ( mqttStatus == MQTTBadParameter ) ||
149             ( mqttStatus == MQTTNoMemory ) ||
150             ( mqttStatus == MQTTSendFailed ) );
151 }
152 
allocateConnectArgs(MQTTAgentConnectArgs_t * pConnectArgs)153 MQTTAgentConnectArgs_t * allocateConnectArgs( MQTTAgentConnectArgs_t * pConnectArgs )
154 {
155     if( pConnectArgs == NULL )
156     {
157         pConnectArgs = malloc( sizeof( MQTTAgentConnectArgs_t ) );
158         __CPROVER_assume( pConnectArgs != NULL );
159     }
160 
161     pConnectArgs->pConnectInfo = malloc( sizeof( MQTTConnectInfo_t ) );
162     __CPROVER_assume( pConnectArgs->pConnectInfo != NULL );
163     pConnectArgs->pWillInfo = malloc( sizeof( MQTTPublishInfo_t ) );
164 
165     return pConnectArgs;
166 }
167 
addPendingAcks(MQTTAgentContext_t * pContext)168 void addPendingAcks( MQTTAgentContext_t * pContext )
169 {
170     uint8_t i;
171     uint16_t packetId;
172     MQTTAgentCommand_t * pCommand;
173     MQTTPublishInfo_t * pPublishInfo;
174 
175     __CPROVER_assert( pContext != NULL, "MQTT Agent Context is not NULL" );
176 
177     for( i = 0; i < MQTT_AGENT_MAX_OUTSTANDING_ACKS; i++ )
178     {
179         #ifdef MAX_PACKET_ID
180 
181             /* Limit the packet Ids so that the range of packet ids retrieved through
182              * MQTT_PublishToResend can be limited as well. */
183             __CPROVER_assume( packetId < MAX_PACKET_ID );
184         #endif
185         pContext->pPendingAcks[ i ].packetId = packetId;
186 
187         /* Add a publish command. */
188         pCommand = malloc( sizeof( MQTTAgentCommand_t ) );
189         __CPROVER_assume( pCommand != NULL );
190 
191         pCommand->commandType = MQTT_PACKET_TYPE_PUBLISH;
192 
193         /* Add Publish Info. */
194         pPublishInfo = malloc( sizeof( MQTTPublishInfo_t ) );
195         __CPROVER_assume( pPublishInfo != NULL );
196         pCommand->pArgs = pPublishInfo;
197 
198         pCommand->pCommandCompleteCallback = commandCompleteCallbackStub;
199 
200         pContext->pPendingAcks[ i ].pOriginalCommand = pCommand;
201     }
202 }
203 
allocateSubscribeArgs(MQTTAgentSubscribeArgs_t * pSubscribeArgs)204 MQTTAgentSubscribeArgs_t * allocateSubscribeArgs( MQTTAgentSubscribeArgs_t * pSubscribeArgs )
205 {
206     if( pSubscribeArgs == NULL )
207     {
208         pSubscribeArgs = malloc( sizeof( MQTTAgentSubscribeArgs_t ) );
209         __CPROVER_assume( pSubscribeArgs != NULL );
210     }
211 
212     pSubscribeArgs->pSubscribeInfo = malloc( sizeof( MQTTSubscribeInfo_t ) );
213     __CPROVER_assume( pSubscribeArgs->pSubscribeInfo != NULL );
214 
215     return pSubscribeArgs;
216 }
217