@@ -193,14 +193,14 @@ struct cloudsync_payload_context {
193193#endif
194194
195195typedef struct PACKED {
196- uint32_t signature ; // 'CLSY'
197- uint8_t version ; // protocol version
198- uint8_t libversion [3 ]; // major.minor.patch
196+ uint32_t signature ; // 'CLSY'
197+ uint8_t version ; // protocol version
198+ uint8_t libversion [3 ]; // major.minor.patch
199199 uint32_t expanded_size ;
200200 uint16_t ncols ;
201201 uint32_t nrows ;
202202 uint64_t schema_hash ;
203- uint8_t unused [6 ]; // padding to ensure the struct is exactly 32 bytes
203+ uint8_t checksum [6 ]; // 48 bits checksum ( to ensure struct is 32 bytes)
204204} cloudsync_payload_header ;
205205
206206#ifdef _MSC_VER
@@ -1949,6 +1949,31 @@ int local_update_move_meta (cloudsync_table_context *table, const char *pk, size
19491949
19501950// MARK: - Payload Encode / Decode -
19511951
1952+ static void cloudsync_payload_checksum_store (cloudsync_payload_header * header , uint64_t checksum ) {
1953+ uint64_t h = checksum & 0xFFFFFFFFFFFFULL ; // keep 48 bits
1954+ header -> checksum [0 ] = (uint8_t )(h >> 40 );
1955+ header -> checksum [1 ] = (uint8_t )(h >> 32 );
1956+ header -> checksum [2 ] = (uint8_t )(h >> 24 );
1957+ header -> checksum [3 ] = (uint8_t )(h >> 16 );
1958+ header -> checksum [4 ] = (uint8_t )(h >> 8 );
1959+ header -> checksum [5 ] = (uint8_t )(h >> 0 );
1960+ }
1961+
1962+ static uint64_t cloudsync_payload_checksum_load (cloudsync_payload_header * header ) {
1963+ return ((uint64_t )header -> checksum [0 ] << 40 ) |
1964+ ((uint64_t )header -> checksum [1 ] << 32 ) |
1965+ ((uint64_t )header -> checksum [2 ] << 24 ) |
1966+ ((uint64_t )header -> checksum [3 ] << 16 ) |
1967+ ((uint64_t )header -> checksum [4 ] << 8 ) |
1968+ ((uint64_t )header -> checksum [5 ] << 0 );
1969+ }
1970+
1971+ static bool cloudsync_payload_checksum_verify (cloudsync_payload_header * header , uint64_t checksum ) {
1972+ uint64_t checksum1 = cloudsync_payload_checksum_load (header );
1973+ uint64_t checksum2 = checksum & 0xFFFFFFFFFFFFULL ;
1974+ return (checksum1 == checksum2 );
1975+ }
1976+
19521977static bool cloudsync_payload_encode_check (cloudsync_payload_context * payload , size_t needed ) {
19531978 if (payload -> nrows == 0 ) needed += sizeof (cloudsync_payload_header );
19541979
@@ -2008,7 +2033,9 @@ int cloudsync_payload_encode_step (cloudsync_payload_context *payload, cloudsync
20082033 }
20092034
20102035 char * buffer = payload -> buffer + payload -> bused ;
2011- pk_encode ((dbvalue_t * * )argv , argc , buffer , false, NULL , data -> skip_decode_idx );
2036+ size_t bsize = payload -> balloc - payload -> bused ;
2037+ char * p = pk_encode ((dbvalue_t * * )argv , argc , buffer , false, & bsize , data -> skip_decode_idx );
2038+ if (!p ) cloudsync_set_error (data , "An error occurred while encoding payload" , DBRES_ERROR );
20122039
20132040 // update buffer
20142041 payload -> bused += breq ;
@@ -2077,6 +2104,10 @@ int cloudsync_payload_encode_final (cloudsync_payload_context *payload, cloudsyn
20772104 zused = real_buffer_size ;
20782105 }
20792106
2107+ // compute checksum of the buffer
2108+ uint64_t checksum = pk_checksum (zbuffer + header_size , zused );
2109+ cloudsync_payload_checksum_store (& header , checksum );
2110+
20802111 // copy header and data to SQLite BLOB
20812112 memcpy (zbuffer , & header , sizeof (cloudsync_payload_header ));
20822113 int blob_size = zused + sizeof (cloudsync_payload_header );
@@ -2179,6 +2210,12 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
21792210 const char * buffer = payload + sizeof (cloudsync_payload_header );
21802211 blen -= sizeof (cloudsync_payload_header );
21812212
2213+ // sanity check checksum
2214+ uint64_t checksum = pk_checksum (buffer , blen );
2215+ if (cloudsync_payload_checksum_verify (& header , checksum ) == false) {
2216+ return cloudsync_set_error (data , "Error on cloudsync_payload_apply: invalid checksum" , DBRES_MISUSE );
2217+ }
2218+
21822219 // check if payload is compressed
21832220 char * clone = NULL ;
21842221 if (header .expanded_size != 0 ) {
@@ -2216,7 +2253,12 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
22162253
22172254 for (uint32_t i = 0 ; i < nrows ; ++ i ) {
22182255 size_t seek = 0 ;
2219- pk_decode ((char * )buffer , blen , ncols , & seek , data -> skip_decode_idx , cloudsync_payload_decode_callback , & decoded_context );
2256+ int res = pk_decode ((char * )buffer , blen , ncols , & seek , data -> skip_decode_idx , cloudsync_payload_decode_callback , & decoded_context );
2257+ if (res == -1 ) {
2258+ if (in_savepoint ) database_rollback_savepoint (data , "cloudsync_payload_apply" );
2259+ rc = DBRES_ERROR ;
2260+ goto cleanup ;
2261+ }
22202262 // n is the pk_decode return value, I don't think I should assert here because in any case the next databasevm_step would fail
22212263 // assert(n == ncols);
22222264
@@ -2301,6 +2343,7 @@ int cloudsync_payload_apply (cloudsync_context *data, const char *payload, int b
23012343 }
23022344 }
23032345
2346+ cleanup :
23042347 // cleanup vm
23052348 if (vm ) databasevm_finalize (vm );
23062349
0 commit comments