Coverage Report

Created: 2026-02-26 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/tests/fuzz/ssh_sftp_attr_fuzzer.c
Line
Count
Source
1
/*
2
 * Copyright 2026 libssh authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <assert.h>
18
#include <stdint.h>
19
#include <stdio.h>
20
#include <stdlib.h>
21
#include <string.h>
22
23
#define LIBSSH_STATIC 1
24
#include "libssh/libssh.h"
25
#include "libssh/sftp.h"
26
#include "libssh/sftp_priv.h"
27
28
#include "nallocinc.c"
29
30
/* SFTP protocol version constants */
31
2.15k
#define SFTP_PROTOCOL_VERSION_3 3
32
2.15k
#define SFTP_PROTOCOL_VERSION_4 4
33
34
/* Flags for sftp_parse_attr expectname parameter */
35
2.15k
#define SFTP_EXPECT_NAME 1
36
2.15k
#define SFTP_NO_NAME 0
37
38
/*
39
 * Helper to create a minimal sftp_session for fuzzing.
40
 * We don't use sftp_new() as it requires a real SSH connection.
41
 */
42
static sftp_session create_minimal_sftp_session(ssh_session session)
43
812
{
44
812
    sftp_session sftp;
45
    
46
812
    sftp = calloc(1, sizeof(struct sftp_session_struct));
47
812
    if (sftp == NULL) {
48
0
        return NULL;
49
0
    }
50
812
    sftp->session = session;
51
    
52
812
    return sftp;
53
812
}
54
55
static void _fuzz_finalize(void)
56
4
{
57
4
    ssh_finalize();
58
4
}
59
60
int LLVMFuzzerInitialize(int *argc, char ***argv)
61
36
{
62
36
    (void)argc;
63
64
36
    nalloc_init(*argv[0]);
65
66
36
    ssh_init();
67
68
36
    atexit(_fuzz_finalize);
69
70
36
    return 0;
71
36
}
72
73
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
74
1.07k
{
75
1.07k
    ssh_session session = NULL;
76
1.07k
    sftp_session sftp = NULL;
77
1.07k
    ssh_buffer buffer = NULL;
78
1.07k
    sftp_attributes attr = NULL;
79
1.07k
    int versions[] = {
80
1.07k
        SFTP_PROTOCOL_VERSION_3, SFTP_PROTOCOL_VERSION_3,
81
1.07k
        SFTP_PROTOCOL_VERSION_4, SFTP_PROTOCOL_VERSION_4
82
1.07k
    };
83
1.07k
    int expectnames[] = {SFTP_NO_NAME, SFTP_EXPECT_NAME, SFTP_NO_NAME, SFTP_EXPECT_NAME};
84
1.07k
    size_t i;
85
86
    /* Minimum bytes for a valid SFTP message */
87
1.07k
    if (size == 0) {
88
0
        return 0;
89
0
    }
90
91
1.07k
    assert(nalloc_start(data, size) > 0);
92
93
    /* Allocate shared resources once for all test iterations */
94
1.07k
    session = ssh_new();
95
1.07k
    if (session == NULL) {
96
263
        goto cleanup;
97
263
    }
98
99
812
    sftp = create_minimal_sftp_session(session);
100
812
    if (sftp == NULL) {
101
0
        goto cleanup;
102
0
    }
103
104
812
    buffer = ssh_buffer_new();
105
812
    if (buffer == NULL) {
106
0
        goto cleanup;
107
0
    }
108
109
    /* Main fuzzing target: sftp_parse_attr */
110
    /* Parses untrusted SFTP messages from client */
111
    /* Test all combinations (v3/v4, with/without name) */
112
4.06k
    for (i = 0; i < (sizeof(versions) / sizeof(versions[0])); i++) {
113
3.24k
        sftp->version = versions[i];
114
115
        /* Reset and repopulate buffer for each iteration */
116
3.24k
        ssh_buffer_reinit(buffer);
117
3.24k
        if (ssh_buffer_add_data(buffer, data, size) == SSH_OK) {
118
3.24k
            attr = sftp_parse_attr(sftp, buffer, expectnames[i]);
119
3.24k
            sftp_attributes_free(attr);
120
3.24k
            attr = NULL;
121
3.24k
        }
122
3.24k
    }
123
124
1.07k
cleanup:
125
1.07k
    ssh_buffer_free(buffer);
126
1.07k
    free(sftp);
127
1.07k
    ssh_free(session);
128
1.07k
    nalloc_end();
129
130
1.07k
    return 0;
131
812
}