Coverage Report

Created: 2025-10-28 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sudo/plugins/sudoers/gc.c
Line
Count
Source
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 2016 Todd C. Miller <Todd.Miller@sudo.ws>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <config.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include <sudoers.h>
25
26
struct sudoers_gc_entry {
27
    SLIST_ENTRY(sudoers_gc_entry) entries;
28
    enum sudoers_gc_types type;
29
    union {
30
  char **vec;
31
  void *ptr;
32
    } u;
33
};
34
SLIST_HEAD(sudoers_gc_list, sudoers_gc_entry);
35
#ifdef NO_LEAKS
36
static struct sudoers_gc_list sudoers_gc_list =
37
    SLIST_HEAD_INITIALIZER(sudoers_gc_list);
38
#endif
39
40
bool
41
sudoers_gc_add(enum sudoers_gc_types type, void *v)
42
365k
{
43
365k
#ifdef NO_LEAKS
44
365k
    struct sudoers_gc_entry *gc;
45
365k
    debug_decl(sudoers_gc_add, SUDOERS_DEBUG_UTIL);
46
47
365k
    if (v == NULL)
48
0
  debug_return_bool(false);
49
50
365k
    gc = calloc(1, sizeof(*gc));
51
365k
    if (gc == NULL) {
52
0
  sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
53
0
  debug_return_bool(false);
54
0
    }
55
365k
    switch (type) {
56
352k
    case GC_PTR:
57
352k
  gc->u.ptr = v;
58
352k
  break;
59
13.0k
    case GC_VECTOR:
60
13.0k
  gc->u.vec = v;
61
13.0k
  break;
62
0
    default:
63
0
  free(gc);
64
0
  sudo_warnx("unexpected garbage type %d", type);
65
0
  debug_return_bool(false);
66
365k
    }
67
365k
    gc->type = type;
68
365k
    SLIST_INSERT_HEAD(&sudoers_gc_list, gc, entries);
69
365k
    debug_return_bool(true);
70
#else
71
    return true;
72
#endif /* NO_LEAKS */
73
365k
}
74
75
bool
76
sudoers_gc_remove(enum sudoers_gc_types type, void *v)
77
136k
{
78
136k
#ifdef NO_LEAKS
79
136k
    struct sudoers_gc_entry *gc, *prev = NULL;
80
136k
    debug_decl(sudoers_gc_remove, SUDOERS_DEBUG_UTIL);
81
82
136k
    if (v == NULL)
83
76.5k
  debug_return_bool(false);
84
85
655k
    SLIST_FOREACH(gc, &sudoers_gc_list, entries) {
86
655k
  switch (gc->type) {
87
626k
  case GC_PTR:
88
626k
      if (gc->u.ptr == v)
89
54.3k
        goto found;
90
572k
      break;
91
572k
  case GC_VECTOR:
92
28.4k
      if (gc->u.vec == v)
93
5.55k
        goto found;
94
22.9k
      break;
95
22.9k
  default:
96
0
      sudo_warnx("unexpected garbage type %d in %p", gc->type, gc);
97
655k
  }
98
595k
  prev = gc;
99
595k
    }
100
    /* If this happens, there is a bug in the g/c code. */
101
0
    sudo_warnx("%s: unable to find %p, type %d", __func__, v, type);
102
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
103
0
    abort();
104
#else
105
    debug_return_bool(false);
106
#endif
107
59.8k
found:
108
59.8k
    if (prev == NULL)
109
11.3k
  SLIST_REMOVE_HEAD(&sudoers_gc_list, entries);
110
48.5k
    else
111
48.5k
  SLIST_REMOVE_AFTER(prev, entries);
112
59.8k
    free(gc);
113
114
59.8k
    debug_return_bool(true);
115
#else
116
    return true;
117
#endif /* NO_LEAKS */
118
59.8k
}
119
120
void
121
sudoers_gc_run(void)
122
25.1k
{
123
25.1k
#ifdef NO_LEAKS
124
25.1k
    struct sudoers_gc_entry *gc;
125
25.1k
    char **cur;
126
25.1k
    debug_decl(sudoers_gc_run, SUDOERS_DEBUG_UTIL);
127
128
    /* Collect garbage. */
129
330k
    while ((gc = SLIST_FIRST(&sudoers_gc_list)) != NULL) {
130
305k
  SLIST_REMOVE_HEAD(&sudoers_gc_list, entries);
131
305k
  switch (gc->type) {
132
298k
  case GC_PTR:
133
298k
      free(gc->u.ptr);
134
298k
      free(gc);
135
298k
      break;
136
7.49k
  case GC_VECTOR:
137
265k
      for (cur = gc->u.vec; *cur != NULL; cur++)
138
258k
    free(*cur);
139
7.49k
      free(gc->u.vec);
140
7.49k
      free(gc);
141
7.49k
      break;
142
0
  default:
143
0
      sudo_warnx("unexpected garbage type %d", gc->type);
144
305k
  }
145
305k
    }
146
147
25.1k
    debug_return;
148
25.1k
#endif /* NO_LEAKS */
149
25.1k
}