Coverage Report

Created: 2024-09-08 06:24

/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
10.8k
{
27
10.8k
  FILE *fp;
28
10.8k
  int ret = 0;
29
10.8k
  struct strbuf fname = STRBUF_INIT;
30
31
10.8k
  strbuf_addf(&fname, "%s/%s", dir, name);
32
33
10.8k
  fp = fopen(fname.buf, "wb");
34
10.8k
  if (fp)
35
10.8k
  {
36
10.8k
    fwrite(data, 1, size, fp);
37
10.8k
  }
38
0
  else
39
0
  {
40
0
    ret = -1;
41
0
  }
42
43
10.8k
  fclose(fp);
44
10.8k
  strbuf_release(&fname);
45
46
10.8k
  return ret;
47
10.8k
}
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
7.69k
{
76
7.69k
  unsigned char *hash = xmallocz_gently(size);
77
7.69k
  const unsigned char *data_chunk = data + size;
78
7.69k
  struct strbuf fname = STRBUF_INIT;
79
80
7.69k
  if (!hash || !data_chunk)
81
0
  {
82
0
    return;
83
0
  }
84
85
7.69k
  memcpy(hash, data, size);
86
87
7.69k
  strbuf_addf(&fname, "TEMP-%s-TEMP", hash_to_hex(hash));
88
7.69k
  randomize_git_file(".", fname.buf, data_chunk, size);
89
90
7.69k
  free(hash);
91
7.69k
  strbuf_release(&fname);
92
7.69k
}
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
7.69k
{
100
7.69k
  return generate_commit_in_branch(data, size, "master");
101
7.69k
}
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
7.69k
{
110
7.69k
  char *argv[4];
111
112
7.69k
  generate_random_file(data, size);
113
114
7.69k
  argv[0] = "add";
115
7.69k
  argv[1] = "TEMP-*-TEMP";
116
7.69k
  argv[2] = NULL;
117
7.69k
  if (cmd_add(2, (const char **)argv, (const char *)""))
118
0
  {
119
0
    return -1;
120
0
  }
121
122
7.69k
  argv[0] = "commit";
123
7.69k
  argv[1] = "-m\"New Commit\"";
124
7.69k
  argv[2] = NULL;
125
7.69k
  if (cmd_commit(2, (const char **)argv, (const char *)""))
126
82
  {
127
82
    return -2;
128
82
  }
129
7.61k
    return 0;
130
7.69k
}
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
1.46k
{
142
1.46k
  char *argv[6];
143
1.46k
  argv[0] = "init";
144
1.46k
  argv[1] = "--quiet";
145
1.46k
  argv[2] = NULL;
146
1.46k
  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
1.46k
  argv[0] = "add";
186
1.46k
  argv[1] = "TEMP_1";
187
1.46k
  argv[2] = "TEMP_2";
188
1.46k
  argv[3] = NULL;
189
1.46k
  if (cmd_add(3, (const char **)argv, (const char *)""))
190
0
  {
191
0
    return -5;
192
0
  }
193
194
1.46k
  argv[0] = "commit";
195
1.46k
  argv[1] = "-m\"First Commit\"";
196
1.46k
  argv[2] = NULL;
197
1.46k
  if (cmd_commit(2, (const char **)argv, (const char *)""))
198
0
  {
199
0
    return -6;
200
0
  }
201
202
1.46k
  return 0;
203
1.46k
}
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
1.46k
{
213
1.46k
  int count = (data_size - reserve_size  - git_files_count * HASH_SIZE) / (HASH_HEX_SIZE);
214
215
1.46k
  if (count > 20)
216
43
  {
217
43
    count = 20;
218
43
  }
219
220
1.46k
  return count;
221
1.46k
}
222
223
static char template_directory_env[350];
224
225
void create_templ_dir(void)
226
2
{
227
  /*
228
  * Create an empty and accessible template directory.
229
  */
230
2
  char template_directory[250];
231
2
  snprintf(template_directory, 250, "/tmp/templatedir-%d", getpid());
232
2
  struct stat stats;
233
2
  if (stat(template_directory, &stats) != 0 || S_ISDIR(stats.st_mode) == 0)
234
2
  {
235
2
    mkdir(template_directory, 0777);
236
2
  }
237
2
  snprintf(template_directory_env, 350,
238
2
      "GIT_TEMPLATE_DIR=%s", template_directory);
239
2
  putenv(template_directory_env);
240
2
}
241
242
void put_envs(void)
243
2
{
244
2
  putenv("GIT_CONFIG_NOSYSTEM=true");
245
2
  putenv("GIT_AUTHOR_EMAIL=FUZZ@LOCALHOST");
246
2
  putenv("GIT_AUTHOR_NAME=FUZZ");
247
2
  putenv("GIT_COMMITTER_NAME=FUZZ");
248
2
  putenv("GIT_COMMITTER_EMAIL=FUZZ@LOCALHOST");
249
2
}