Coverage Report

Created: 2023-11-27 06:56

/src/git/oss-fuzz/fuzz-cmd-base.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2022 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 "builtin.h"
13
#include "hex.h"
14
#include "strbuf.h"
15
#include "fuzz-cmd-base.h"
16
17
18
/*
19
 * This function is used to randomize the content of a file with the
20
 * random data. The random data normally come from the fuzzing engine
21
 * LibFuzzer in order to create randomization of the git file worktree
22
 * and possibly messing up of certain git config file to fuzz different
23
 * git command execution logic. Return -1 if it fails to create the file.
24
 */
25
int randomize_git_file(char *dir, char *name, char *data, int size)
26
8.48k
{
27
8.48k
  FILE *fp;
28
8.48k
  int ret = 0;
29
8.48k
  struct strbuf fname = STRBUF_INIT;
30
31
8.48k
  strbuf_addf(&fname, "%s/%s", dir, name);
32
33
8.48k
  fp = fopen(fname.buf, "wb");
34
8.48k
  if (fp)
35
8.48k
  {
36
8.48k
    fwrite(data, 1, size, fp);
37
8.48k
  }
38
0
  else
39
0
  {
40
0
    ret = -1;
41
0
  }
42
43
8.48k
  fclose(fp);
44
8.48k
  strbuf_release(&fname);
45
46
8.48k
  return ret;
47
8.48k
}
48
49
/*
50
 * This function is a variant of the above function which takes
51
 * a set of target files to be processed. These target file are
52
 * passing to the above function one by one for content rewrite.
53
 * The data is equally divided for each of the files, and the
54
 * remaining bytes (if not divisible) will be ignored.
55
 */
56
void randomize_git_files(char *dir, char *name_set[],
57
  int files_count, char *data, int size)
58
0
{
59
0
  int i;
60
0
  int data_size = size / files_count;
61
0
  char *data_chunk = xmallocz_gently(data_size);
62
63
0
  if (!data_chunk)
64
0
  {
65
0
    return;
66
0
  }
67
68
0
  for (i = 0; i < files_count; i++)
69
0
  {
70
0
    memcpy(data_chunk, data + (i * data_size), data_size);
71
0
    randomize_git_file(dir, name_set[i], data_chunk, data_size);
72
0
  }
73
0
  free(data_chunk);
74
0
}
75
76
/*
77
 * Instead of randomizing the content of existing files. This helper
78
 * function helps generate a temp file with random file name before
79
 * passing to the above functions to get randomized content for later
80
 * fuzzing of git command.
81
 */
82
void generate_random_file(char *data, int size)
83
6.21k
{
84
6.21k
  unsigned char *hash = xmallocz_gently(size);
85
6.21k
  char *data_chunk = xmallocz_gently(size);
86
6.21k
  struct strbuf fname = STRBUF_INIT;
87
88
6.21k
  if (!hash || !data_chunk)
89
0
  {
90
0
    return;
91
0
  }
92
93
6.21k
  memcpy(hash, data, size);
94
6.21k
  memcpy(data_chunk, data + size, size);
95
96
6.21k
  strbuf_addf(&fname, "TEMP-%s-TEMP", hash_to_hex(hash));
97
6.21k
  randomize_git_file(".", fname.buf, data_chunk, size);
98
99
6.21k
  free(hash);
100
6.21k
  free(data_chunk);
101
6.21k
  strbuf_release(&fname);
102
6.21k
}
103
104
/*
105
 * This function provides a shorthand for generate commit in master
106
 * branch.
107
 */
108
int generate_commit(char *data, int size)
109
6.21k
{
110
6.21k
  return generate_commit_in_branch(data, size, "master");
111
6.21k
}
112
113
/*
114
 * This function helps to generate random commit and build up a
115
 * worktree with randomization to provide a target for the fuzzing
116
 * of git command under specific branch.
117
 */
118
int generate_commit_in_branch(char *data, int size, char *branch_name)
119
6.21k
{
120
6.21k
  char *argv[4];
121
6.21k
  char *data_chunk = xmallocz_gently(HASH_HEX_SIZE);
122
123
6.21k
  if (!data_chunk)
124
0
  {
125
0
    return -1;
126
0
  }
127
128
6.21k
  memcpy(data_chunk, data, size * 2);
129
6.21k
  generate_random_file(data_chunk, size);
130
131
6.21k
  free(data_chunk);
132
133
6.21k
  argv[0] = "add";
134
6.21k
  argv[1] = "TEMP-*-TEMP";
135
6.21k
  argv[2] = NULL;
136
6.21k
  if (cmd_add(2, (const char **)argv, (const char *)""))
137
0
  {
138
0
    return -1;
139
0
  }
140
141
6.21k
  argv[0] = "commit";
142
6.21k
  argv[1] = "-m\"New Commit\"";
143
6.21k
  argv[2] = NULL;
144
6.21k
  if (cmd_commit(2, (const char **)argv, (const char *)""))
145
89
  {
146
89
    return -2;
147
148
89
  }
149
6.13k
    return 0;
150
6.21k
}
151
152
/*
153
 * In some cases, there maybe some fuzzing logic that will mess
154
 * up with the git repository and its configuration and settings.
155
 * This function integrates into the fuzzing processing and
156
 * reset the git repository into the default
157
 * base settings before each round of fuzzing.
158
 * Return 0 for success.
159
 */
160
int reset_git_folder(void)
161
1.22k
{
162
1.22k
  char *argv[6];
163
1.22k
  argv[0] = "init";
164
1.22k
  argv[1] = NULL;
165
1.22k
  if (cmd_init_db(1, (const char **)argv, (const char *)""))
166
0
  {
167
0
    return -1;
168
0
  }
169
170
  /*
171
  printf("R2\n");
172
  argv[0] = "config";
173
  argv[1] = "--global";
174
  argv[2] = "user.name";
175
  argv[3] = "\"FUZZ\"";
176
  argv[4] = NULL;
177
  if (cmd_config(4, (const char **)argv, (const char *)""))
178
  {
179
    return -2;
180
  }
181
182
  printf("R3\n");
183
  argv[0] = "config";
184
  argv[1] = "--global";
185
  argv[2] = "user.email";
186
  argv[3] = "\"FUZZ@LOCALHOST\"";
187
  argv[4] = NULL;
188
  if (cmd_config(4, (const char **)argv, (const char *)""))
189
  {
190
    return -3;
191
  }
192
193
  printf("R4\n");
194
  argv[0] = "config";
195
  argv[1] = "--global";
196
  argv[2] = "safe.directory";
197
  argv[3] = "\"*\"";
198
  argv[4] = NULL;
199
  if (cmd_config(4, (const char **)argv, (const char *)""))
200
  {
201
    return -4;
202
  }
203
  */
204
1.22k
  argv[0] = "add";
205
1.22k
  argv[1] = "TEMP_1";
206
1.22k
  argv[2] = "TEMP_2";
207
1.22k
  argv[3] = NULL;
208
1.22k
  if (cmd_add(3, (const char **)argv, (const char *)""))
209
0
  {
210
0
    return -5;
211
0
  }
212
213
1.22k
  argv[0] = "commit";
214
1.22k
  argv[1] = "-m\"First Commit\"";
215
1.22k
  argv[2] = NULL;
216
1.22k
  if (cmd_commit(2, (const char **)argv, (const char *)""))
217
0
  {
218
0
    return -6;
219
0
  }
220
221
1.22k
  return 0;
222
1.22k
}
223
224
/*
225
 * This helper function returns the maximum number of commit can
226
 * be generated by the provided random data without reusing the
227
 * data to increase randomization of the fuzzing target and allow
228
 * more path of fuzzing to be covered.
229
 */
230
int get_max_commit_count(int data_size, int git_files_count, int reserve_size)
231
1.22k
{
232
1.22k
  int count = (data_size - reserve_size  - git_files_count * HASH_SIZE) / (HASH_HEX_SIZE);
233
234
1.22k
  if (count > 20)
235
30
  {
236
30
    count = 20;
237
30
  }
238
239
1.22k
  return count;
240
1.22k
}