/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 | } |