Bug Summary

File:libexec/got-read-gitconfig/got-read-gitconfig.c
Warning:line 240, column 8
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd6.9 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name got-read-gitconfig.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/11.1.0 -I /home/ben/Projects/got/libexec/got-read-gitconfig/../../include -I /home/ben/Projects/got/libexec/got-read-gitconfig/../../lib -D GOT_LIBEXECDIR=/home/ben/bin -D GOT_VERSION=0.53-current -internal-isystem /usr/local/lib/clang/11.1.0/include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/ben/Projects/got/libexec/got-read-gitconfig/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/got/scan/2021-05-28-230913-68537-1 -x c /home/ben/Projects/got/libexec/got-read-gitconfig/got-read-gitconfig.c
1/*
2 * Copyright (c) 2019 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/types.h>
18#include <sys/queue.h>
19#include <sys/uio.h>
20#include <sys/time.h>
21
22#include <stdint.h>
23#include <imsg.h>
24#include <limits.h>
25#include <signal.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sha1.h>
30#include <unistd.h>
31#include <zlib.h>
32
33#include "got_error.h"
34#include "got_object.h"
35#include "got_repository.h"
36
37#include "got_lib_delta.h"
38#include "got_lib_object.h"
39#include "got_lib_privsep.h"
40#include "got_lib_gitconfig.h"
41
42static volatile sig_atomic_t sigint_received;
43
44static void
45catch_sigint(int signo)
46{
47 sigint_received = 1;
48}
49
50static const struct got_error *
51send_gitconfig_int(struct imsgbuf *ibuf, int value)
52{
53 if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_INT_VAL, 0, 0, -1,
54 &value, sizeof(value)) == -1)
55 return got_error_from_errno("imsg_compose GITCONFIG_INT_VAL");
56
57 return got_privsep_flush_imsg(ibuf);
58}
59
60static const struct got_error *
61gitconfig_num_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig,
62 char *section, char *tag, int def)
63{
64 int value;
65
66 if (gitconfig == NULL((void *)0))
67 return got_error(GOT_ERR_PRIVSEP_MSG39);
68
69 value = got_gitconfig_get_num(gitconfig, section, tag, def);
70 return send_gitconfig_int(ibuf, value);
71}
72
73static const struct got_error *
74send_gitconfig_str(struct imsgbuf *ibuf, const char *value)
75{
76 size_t len = value ? strlen(value) : 0;
77
78 if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_STR_VAL, 0, 0, -1,
79 value, len) == -1)
80 return got_error_from_errno("imsg_compose GITCONFIG_STR_VAL");
81
82 return got_privsep_flush_imsg(ibuf);
83}
84
85static const struct got_error *
86gitconfig_str_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig,
87 char *section, char *tag)
88{
89 char *value;
90
91 if (gitconfig == NULL((void *)0))
92 return got_error(GOT_ERR_PRIVSEP_MSG39);
93
94 value = got_gitconfig_get_str(gitconfig, section, tag);
95 return send_gitconfig_str(ibuf, value);
96}
97
98static const struct got_error *
99send_gitconfig_remotes(struct imsgbuf *ibuf, struct got_remote_repo *remotes,
100 int nremotes)
101{
102 const struct got_error *err = NULL((void *)0);
103 struct got_imsg_remotes iremotes;
104 int i;
105
106 iremotes.nremotes = nremotes;
107 if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_REMOTES, 0, 0, -1,
108 &iremotes, sizeof(iremotes)) == -1)
109 return got_error_from_errno("imsg_compose GITCONFIG_REMOTES");
110
111 err = got_privsep_flush_imsg(ibuf);
112 imsg_clear(ibuf);
113 if (err)
114 return err;
115
116 for (i = 0; i < nremotes; i++) {
117 struct got_imsg_remote iremote;
118 size_t len = sizeof(iremote);
119 struct ibuf *wbuf;
120
121 iremote.mirror_references = remotes[i].mirror_references;
122 iremote.name_len = strlen(remotes[i].name);
123 len += iremote.name_len;
124 iremote.url_len = strlen(remotes[i].url);
125 len += iremote.url_len;
126
127 wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_REMOTE, 0, 0, len);
128 if (wbuf == NULL((void *)0))
129 return got_error_from_errno(
130 "imsg_create GITCONFIG_REMOTE");
131
132 if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) {
133 err = got_error_from_errno(
134 "imsg_add GITCONFIG_REMOTE");
135 ibuf_free(wbuf);
136 return err;
137 }
138
139 if (imsg_add(wbuf, remotes[i].name, iremote.name_len) == -1) {
140 err = got_error_from_errno(
141 "imsg_add GITCONFIG_REMOTE");
142 ibuf_free(wbuf);
143 return err;
144 }
145 if (imsg_add(wbuf, remotes[i].url, iremote.url_len) == -1) {
146 err = got_error_from_errno(
147 "imsg_add GITCONFIG_REMOTE");
148 ibuf_free(wbuf);
149 return err;
150 }
151
152 wbuf->fd = -1;
153 imsg_close(ibuf, wbuf);
154 err = got_privsep_flush_imsg(ibuf);
155 if (err)
156 return err;
157 }
158
159 return NULL((void *)0);
160}
161
162static int
163get_boolean_val(char *val)
164{
165 return (strcasecmp(val, "true") == 0 ||
166 strcasecmp(val, "on") == 0 ||
167 strcasecmp(val, "yes") == 0 ||
168 strcmp(val, "1") == 0);
169}
170
171static const struct got_error *
172gitconfig_remotes_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig)
173{
174 const struct got_error *err = NULL((void *)0);
175 struct got_gitconfig_list *sections;
176 struct got_gitconfig_list_node *node;
177 struct got_remote_repo *remotes = NULL((void *)0);
178 int nremotes = 0, i;
179
180 if (gitconfig == NULL((void *)0))
30
Assuming 'gitconfig' is not equal to NULL
31
Taking false branch
181 return got_error(GOT_ERR_PRIVSEP_MSG39);
182
183 err = got_gitconfig_get_section_list(&sections, gitconfig);
184 if (err)
32
Assuming 'err' is null
33
Taking false branch
185 return err;
186
187 TAILQ_FOREACH(node, &sections->fields, link)for((node) = ((&sections->fields)->tqh_first); (node
) != ((void *)0); (node) = ((node)->link.tqe_next))
{
34
Assuming 'node' is not equal to null
35
Loop condition is true. Entering loop body
37
Assuming 'node' is equal to null
38
Loop condition is false. Execution continues on line 193
188 if (strncasecmp("remote \"", node->field, 8) != 0)
36
Taking false branch
189 continue;
190 nremotes++;
191 }
192
193 if (nremotes
38.1
'nremotes' is not equal to 0
== 0) {
39
Taking false branch
194 err = send_gitconfig_remotes(ibuf, NULL((void *)0), 0);
195 goto done;
196 }
197
198 remotes = recallocarray(NULL((void *)0), 0, nremotes, sizeof(*remotes));
40
Value assigned to 'remotes'
199 if (remotes == NULL((void *)0)) {
41
Assuming 'remotes' is equal to NULL
42
Taking true branch
200 err = got_error_from_errno("recallocarray");
201 goto done;
43
Control jumps to line 239
202 }
203
204 i = 0;
205 TAILQ_FOREACH(node, &sections->fields, link)for((node) = ((&sections->fields)->tqh_first); (node
) != ((void *)0); (node) = ((node)->link.tqe_next))
{
206 char *name, *end, *mirror;
207
208 if (strncasecmp("remote \"", node->field, 8) != 0)
209 continue;
210
211 name = strdup(node->field + 8);
212 if (name == NULL((void *)0)) {
213 err = got_error_from_errno("strdup");
214 goto done;
215 }
216 end = strrchr(name, '"');
217 if (end)
218 *end = '\0';
219 remotes[i].name = name;
220
221 remotes[i].url = got_gitconfig_get_str(gitconfig,
222 node->field, "url");
223 if (remotes[i].url == NULL((void *)0)) {
224 err = got_error(GOT_ERR_GITCONFIG_SYNTAX114);
225 goto done;
226 }
227
228 remotes[i].mirror_references = 0;
229 mirror = got_gitconfig_get_str(gitconfig, node->field,
230 "mirror");
231 if (mirror != NULL((void *)0) && get_boolean_val(mirror))
232 remotes[i].mirror_references = 1;
233
234 i++;
235 }
236
237 err = send_gitconfig_remotes(ibuf, remotes, nremotes);
238done:
239 for (i = 0; i < nremotes; i++)
44
Loop condition is true. Entering loop body
240 free(remotes[i].name);
45
Dereference of null pointer
241 free(remotes);
242 got_gitconfig_free_list(sections);
243 return err;
244}
245
246static const struct got_error *
247gitconfig_owner_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig)
248{
249 char *value;
250
251 if (gitconfig == NULL((void *)0))
252 return got_error(GOT_ERR_PRIVSEP_MSG39);
253
254 value = got_gitconfig_get_str(gitconfig, "gotweb", "owner");
255 if (value)
256 return send_gitconfig_str(ibuf, value);
257 value = got_gitconfig_get_str(gitconfig, "gitweb", "owner");
258 return send_gitconfig_str(ibuf, value);
259}
260
261static const struct got_error *
262gitconfig_extensions_request(struct imsgbuf *ibuf,
263 struct got_gitconfig *gitconfig)
264{
265 const struct got_error *err = NULL((void *)0);
266 struct got_gitconfig_list *tags;
267 struct got_gitconfig_list_node *node;
268 int nextensions = 0;
269 char *val;
270
271 if (gitconfig == NULL((void *)0))
272 return got_error(GOT_ERR_PRIVSEP_MSG39);
273
274 tags = got_gitconfig_get_tag_list(gitconfig, "extensions");
275 if (tags == NULL((void *)0))
276 return send_gitconfig_int(ibuf, 0);
277
278 TAILQ_FOREACH(node, &tags->fields, link)for((node) = ((&tags->fields)->tqh_first); (node) !=
((void *)0); (node) = ((node)->link.tqe_next))
{
279 val = got_gitconfig_get_str(gitconfig, "extensions",
280 node->field);
281 if (get_boolean_val(val))
282 nextensions++;
283 }
284
285 err = send_gitconfig_int(ibuf, nextensions);
286 if (err)
287 goto done;
288
289 TAILQ_FOREACH(node, &tags->fields, link)for((node) = ((&tags->fields)->tqh_first); (node) !=
((void *)0); (node) = ((node)->link.tqe_next))
{
290 val = got_gitconfig_get_str(gitconfig, "extensions",
291 node->field);
292 if (get_boolean_val(val)) {
293 err = send_gitconfig_str(ibuf, node->field);
294 if (err)
295 goto done;
296 }
297 }
298done:
299 got_gitconfig_free_list(tags);
300 return err;
301}
302
303int
304main(int argc, char *argv[])
305{
306 const struct got_error *err = NULL((void *)0);
307 struct imsgbuf ibuf;
308 size_t datalen;
309 struct got_gitconfig *gitconfig = NULL((void *)0);
310#if 0
311 static int attached;
312
313 while (!attached)
314 sleep(1);
315#endif
316 signal(SIGINT2, catch_sigint);
317
318 imsg_init(&ibuf, GOT_IMSG_FD_CHILD(2 + 1));
319
320#ifndef PROFILE
321 /* revoke access to most system calls */
322 if (pledge("stdio recvfd", NULL((void *)0)) == -1) {
1
Assuming the condition is false
2
Taking false branch
323 err = got_error_from_errno("pledge");
324 got_privsep_send_error(&ibuf, err);
325 return 1;
326 }
327#endif
328
329 for (;;) {
3
Loop condition is true. Entering loop body
21
Loop condition is true. Entering loop body
330 struct imsg imsg;
331
332 memset(&imsg, 0, sizeof(imsg));
333 imsg.fd = -1;
334
335 if (sigint_received) {
4
Assuming 'sigint_received' is 0
5
Taking false branch
22
Assuming 'sigint_received' is 0
23
Taking false branch
336 err = got_error(GOT_ERR_CANCELLED49);
337 break;
338 }
339
340 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
341 if (err) {
6
Assuming 'err' is null
7
Taking false branch
24
Assuming 'err' is null
25
Taking false branch
342 if (err->code == GOT_ERR_PRIVSEP_PIPE37)
343 err = NULL((void *)0);
344 break;
345 }
346
347 if (imsg.hdr.type == GOT_IMSG_STOP)
8
Assuming field 'type' is not equal to GOT_IMSG_STOP
9
Taking false branch
26
Assuming field 'type' is not equal to GOT_IMSG_STOP
27
Taking false branch
348 break;
349
350 switch (imsg.hdr.type) {
10
Control jumps to 'case GOT_IMSG_GITCONFIG_PARSE_REQUEST:' at line 351
28
Control jumps to 'case GOT_IMSG_GITCONFIG_REMOTES_REQUEST:' at line 381
351 case GOT_IMSG_GITCONFIG_PARSE_REQUEST:
352 datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr);
353 if (datalen != 0) {
11
Assuming 'datalen' is equal to 0
12
Taking false branch
354 err = got_error(GOT_ERR_PRIVSEP_LEN36);
355 break;
356 }
357 if (imsg.fd == -1){
13
Assuming the condition is false
14
Taking false branch
358 err = got_error(GOT_ERR_PRIVSEP_NO_FD38);
359 break;
360 }
361
362 if (gitconfig
14.1
'gitconfig' is null
)
15
Taking false branch
363 got_gitconfig_close(gitconfig);
364 err = got_gitconfig_open(&gitconfig, imsg.fd);
365 break;
16
Execution continues on line 392
366 case GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST:
367 err = gitconfig_num_request(&ibuf, gitconfig, "core",
368 "repositoryformatversion", 0);
369 break;
370 case GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST:
371 err = gitconfig_extensions_request(&ibuf, gitconfig);
372 break;
373 case GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST:
374 err = gitconfig_str_request(&ibuf, gitconfig, "user",
375 "name");
376 break;
377 case GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST:
378 err = gitconfig_str_request(&ibuf, gitconfig, "user",
379 "email");
380 break;
381 case GOT_IMSG_GITCONFIG_REMOTES_REQUEST:
382 err = gitconfig_remotes_request(&ibuf, gitconfig);
29
Calling 'gitconfig_remotes_request'
383 break;
384 case GOT_IMSG_GITCONFIG_OWNER_REQUEST:
385 err = gitconfig_owner_request(&ibuf, gitconfig);
386 break;
387 default:
388 err = got_error(GOT_ERR_PRIVSEP_MSG39);
389 break;
390 }
391
392 if (imsg.fd != -1) {
17
Taking true branch
393 if (close(imsg.fd) == -1 && err == NULL((void *)0))
18
Assuming the condition is false
394 err = got_error_from_errno("close");
395 }
396
397 imsg_free(&imsg);
398 if (err)
19
Assuming 'err' is null
20
Taking false branch
399 break;
400 }
401
402 imsg_clear(&ibuf);
403 if (err) {
404 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE37) {
405 fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), err->msg);
406 got_privsep_send_error(&ibuf, err);
407 }
408 }
409 if (close(GOT_IMSG_FD_CHILD(2 + 1)) == -1 && err == NULL((void *)0))
410 err = got_error_from_errno("close");
411 return err ? 1 : 0;
412}