Coverage Report

Created: 2025-07-12 06:12

/src/libmodbus/fuzz/FuzzServer.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2021 Google LLC
2
Licensed under the Apache License, Version 2.0 (the "License");
3
you may not use this file except in compliance with the License.
4
You may obtain a copy of the License at
5
      http://www.apache.org/licenses/LICENSE-2.0
6
Unless required by applicable law or agreed to in writing, software
7
distributed under the License is distributed on an "AS IS" BASIS,
8
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
See the License for the specific language governing permissions and
10
limitations under the License.
11
*/
12
#include <stdio.h>
13
#include <errno.h>
14
#include <stdlib.h>
15
#include <stdint.h>
16
#include <unistd.h>
17
#include <string.h>
18
#include <stddef.h>
19
#include <pthread.h>
20
#include <arpa/inet.h>
21
#include <sys/socket.h>
22
#include <netinet/in.h>
23
#include <netinet/tcp.h>
24
25
#include <modbus.h>
26
#include "unit-test.h"
27
28
1
#define PORT 8080
29
40
#define kMinInputLength 9
30
17
#define kMaxInputLength MODBUS_RTU_MAX_ADU_LENGTH
31
32
struct Fuzzer{
33
    uint16_t    port;    
34
    char*       file;
35
36
    FILE*       inFile;
37
    uint64_t    size;
38
    uint8_t*    buffer;
39
40
    pthread_t   thread;
41
    int         socket;
42
};
43
typedef struct Fuzzer Fuzzer;
44
45
int server(Fuzzer *fuzzer);
46
47
1
void *client(void *args){ 
48
49
1
    Fuzzer *fuzzer = (Fuzzer*)args;
50
1
    int sockfd;
51
1
    struct sockaddr_in serv_addr;
52
53
1
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
54
1
    serv_addr.sin_family = AF_INET;
55
1
    serv_addr.sin_port = htons(fuzzer->port);
56
1
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
57
58
1
    while(1){/* Try until connect*/
59
1
        if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
60
0
            continue;
61
1
        }else{
62
1
            break;
63
1
        }
64
1
    }
65
66
1
    send(sockfd,fuzzer->buffer,fuzzer->size,0);
67
68
1
    close(sockfd);
69
1
    pthread_exit(NULL);
70
1
}
71
72
20
extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
73
74
20
    if (size < kMinInputLength || size > kMaxInputLength){
75
19
        return 0;
76
19
    }
77
78
1
    Fuzzer *fuzzer = (Fuzzer*)malloc(sizeof(Fuzzer));
79
1
    fuzzer->port = PORT;
80
81
1
    fuzzer->size = size;
82
1
    fuzzer->buffer = data;
83
84
1
    pthread_create(&fuzzer->thread, NULL,client,fuzzer);
85
1
    server(fuzzer);
86
1
    pthread_join(fuzzer->thread, NULL); /* Avoid UAF*/
87
88
1
    free(fuzzer);
89
1
    return 0;
90
20
}
91
92
int server(Fuzzer *fuzzer)
93
1
{
94
1
    int s = -1;
95
1
    modbus_t *ctx;
96
1
    modbus_mapping_t *mb_mapping;
97
1
    int rc;
98
1
    int i;
99
1
    uint8_t *query;
100
101
1
    ctx = modbus_new_tcp("127.0.0.1", fuzzer->port);
102
1
    query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);
103
104
1
    mb_mapping = modbus_mapping_new_start_address(
105
1
        UT_BITS_ADDRESS, UT_BITS_NB,
106
1
        UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,
107
1
        UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX,
108
1
        UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB);
109
1
    if (mb_mapping == NULL) {
110
0
        fprintf(stderr, "Failed to allocate the mapping: %s\n",
111
0
                modbus_strerror(errno));
112
0
        modbus_free(ctx);
113
0
        return -1;
114
0
    }
115
116
    /* Initialize input values that's can be only done server side. */
117
1
    modbus_set_bits_from_bytes(mb_mapping->tab_input_bits, 0, UT_INPUT_BITS_NB,
118
1
                               UT_INPUT_BITS_TAB);
119
120
    /* Initialize values of INPUT REGISTERS */
121
2
    for (i=0; i < UT_INPUT_REGISTERS_NB; i++) {
122
1
        mb_mapping->tab_input_registers[i] = UT_INPUT_REGISTERS_TAB[i];
123
1
    }
124
125
1
    s = modbus_tcp_listen(ctx, 1);
126
1
    modbus_tcp_accept(ctx, &s);
127
128
1
    rc = modbus_receive(ctx, query);
129
130
1
    if (s != -1) {
131
1
        close(s);
132
1
    }
133
134
1
    modbus_mapping_free(mb_mapping);
135
1
    free(query);
136
    /* For RTU */
137
1
    modbus_close(ctx);
138
1
    modbus_free(ctx);
139
140
1
    return rc;
141
1
}