Coverage Report

Created: 2024-09-08 06:23

/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, const unsigned char *data, int size)
26
383
{
27
383
  FILE *fp;
28
383
  int ret = 0;
29
383
  struct strbuf fname = STRBUF_INIT;
30
31
383
  strbuf_addf(&fname, "%s/%s", dir, name);
32
33
383
  fp = fopen(fname.buf, "wb");
34
383
  if (fp)
35
383
  {
36
383
    fwrite(data, 1, size, fp);
37
383
  }
38
0
  else
39
0
  {
40
0
    ret = -1;
41
0
  }
42
43
383
  fclose(fp);
44
383
  strbuf_release(&fname);
45
46
383
  return ret;
47
383
}
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, const unsigned char *data, int size)
58
0
{
59
0
  int i;
60
0
  int data_size = size / files_count;
61
62
0
  for (i = 0; i < files_count; i++)
63
0
  {
64
0
    randomize_git_file(dir, name_set[i], data + (i * data_size), data_size);
65
0
  }
66
0
}
67
68
/*
69
 * Instead of randomizing the content of existing files. This helper
70
 * function helps generate a temp file with random file name before
71
 * passing to the above functions to get randomized content for later
72
 * fuzzing of git command.
73
 */
74
void generate_random_file(const unsigned char *data, int size)
75
0
{
76
0
  unsigned char *hash = xmallocz_gently(size);
77
0
  const unsigned char *data_chunk = data + size;
78
0
  struct strbuf fname = STRBUF_INIT;
79
80
0
  if (!hash || !data_chunk)
81
0
  {
82
0
    return;
83
0
  }
84
85
0
  memcpy(hash, data, size);
86
87
0
  strbuf_addf(&fname, "TEMP-%s-TEMP", hash_to_hex(hash));
88
0
  randomize_git_file(".", fname.buf, data_chunk, size);
89
90
0
  free(hash);
91
0
  strbuf_release(&fname);
92
0
}
93
94
/*
95
 * This function provides a shorthand for generate commit in master
96
 * branch.
97
 */
98
int generate_commit(const unsigned char *data, int size)
99
0
{
100
0
  return generate_commit_in_branch(data, size, "master");
101
0
}
102
103
/*
104
 * This function helps to generate random commit and build up a
105
 * worktree with randomization to provide a target for the fuzzing
106
 * of git command under specific branch.
107
 */
108
int generate_commit_in_branch(const unsigned char *data, int size, char *branch_name)
109
0
{
110
0
  char *argv[4];
111
112
0
  generate_random_file(data, size);
113
114
0
  argv[0] = "add";
115
0
  argv[1] = "TEMP-*-TEMP";
116
0
  argv[2] = NULL;
117
0
  if (cmd_add(2, (const char **)argv, (const char *)""))
118
0
  {
119
0
    return -1;
120
0
  }
121
122
0
  argv[0] = "commit";
123
0
  argv[1] = "-m\"New Commit\"";
124
0
  argv[2] = NULL;
125
0
  if (cmd_commit(2, (const char **)argv, (const char *)""))
126
0
  {
127
0
    return -2;
128
0
  }
129
0
    return 0;
130
0
}
131
132
/*
133
 * In some cases, there maybe some fuzzing logic that will mess
134
 * up with the git repository and its configuration and settings.
135
 * This function integrates into the fuzzing processing and
136
 * reset the git repository into the default
137
 * base settings before each round of fuzzing.
138
 * Return 0 for success.
139
 */
140
int reset_git_folder(void)
141
0
{
142
0
  char *argv[6];
143
0
  argv[0] = "init";
144
0
  argv[1] = "--quiet";
145
0
  argv[2] = NULL;
146
0
  if (cmd_init_db(2, (const char **)argv, (const char *)""))
147
0
  {
148
0
    return -1;
149
0
  }
150
151
  /*
152
  printf("R2\n");
153
  argv[0] = "config";
154
  argv[1] = "--global";
155
  argv[2] = "user.name";
156
  argv[3] = "\"FUZZ\"";
157
  argv[4] = NULL;
158
  if (cmd_config(4, (const char **)argv, (const char *)""))
159
  {
160
    return -2;
161
  }
162
163
  printf("R3\n");
164
  argv[0] = "config";
165
  argv[1] = "--global";
166
  argv[2] = "user.email";
167
  argv[3] = "\"FUZZ@LOCALHOST\"";
168
  argv[4] = NULL;
169
  if (cmd_config(4, (const char **)argv, (const char *)""))
170
  {
171
    return -3;
172
  }
173
174
  printf("R4\n");
175
  argv[0] = "config";
176
  argv[1] = "--global";
177
  argv[2] = "safe.directory";
178
  argv[3] = "\"*\"";
179
  argv[4] = NULL;
180
  if (cmd_config(4, (const char **)argv, (const char *)""))
181
  {
182
    return -4;
183
  }
184
  */
185
0
  argv[0] = "add";
186
0
  argv[1] = "TEMP_1";
187
0
  argv[2] = "TEMP_2";
188
0
  argv[3] = NULL;
189
0
  if (cmd_add(3, (const char **)argv, (const char *)""))
190
0
  {
191
0
    return -5;
192
0
  }
193
194
0
  argv[0] = "commit";
195
0
  argv[1] = "-m\"First Commit\"";
196
0
  argv[2] = NULL;
197
0
  if (cmd_commit(2, (const char **)argv, (const char *)""))
198
0
  {
199
0
    return -6;
200
0
  }
201
202
0
  return 0;
203
0
}
204
205
/*
206
 * This helper function returns the maximum number of commit can
207
 * be generated by the provided random data without reusing the
208
 * data to increase randomization of the fuzzing target and allow
209
 * more path of fuzzing to be covered.
210
 */
211
int get_max_commit_count(int data_size, int git_files_count, int reserve_size)
212
0
{
213
0
  int count = (data_size - reserve_size  - git_files_count * HASH_SIZE) / (HASH_HEX_SIZE);
214
215
0
  if (count > 20)
216
0
  {
217
0
    count = 20;
218
0
  }
219
220
0
  return count;
221
0
}
222
223
static char template_directory_env[350];
224
225
void create_templ_dir(void)
226
1
{
227
  /*
228
  * Create an empty and accessible template directory.
229
  */
230
1
  char template_directory[250];
231
1
  snprintf(template_directory, 250, "/tmp/templatedir-%d", getpid());
232
1
  struct stat stats;
233
1
  if (stat(template_directory, &stats) != 0 || S_ISDIR(stats.st_mode) == 0)
234
1
  {
235
1
    mkdir(template_directory, 0777);
236
1
  }
237
1
  snprintf(template_directory_env, 350,
238
1
      "GIT_TEMPLATE_DIR=%s", template_directory);
239
1
  putenv(template_directory_env);
240
1
}
241
242
void put_envs(void)
243
1
{
244
1
  putenv("GIT_CONFIG_NOSYSTEM=true");
245
1
  putenv("GIT_AUTHOR_EMAIL=FUZZ@LOCALHOST");
246
1
  putenv("GIT_AUTHOR_NAME=FUZZ");
247
1
  putenv("GIT_COMMITTER_NAME=FUZZ");
248
1
  putenv("GIT_COMMITTER_EMAIL=FUZZ@LOCALHOST");
249
1
}