Coverage Report

Created: 2026-01-09 06:37

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
377k
{
43
377k
#ifdef NO_LEAKS
44
377k
    struct sudoers_gc_entry *gc;
45
377k
    debug_decl(sudoers_gc_add, SUDOERS_DEBUG_UTIL);
46
47
377k
    if (v == NULL)
48
0
  debug_return_bool(false);
49
50
377k
    gc = calloc(1, sizeof(*gc));
51
377k
    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
377k
    switch (type) {
56
363k
    case GC_PTR:
57
363k
  gc->u.ptr = v;
58
363k
  break;
59
13.3k
    case GC_VECTOR:
60
13.3k
  gc->u.vec = v;
61
13.3k
  break;
62
0
    default:
63
0
  free(gc);
64
0
  sudo_warnx("unexpected garbage type %d", type);
65
0
  debug_return_bool(false);
66
377k
    }
67
377k
    gc->type = type;
68
377k
    SLIST_INSERT_HEAD(&sudoers_gc_list, gc, entries);
69
377k
    debug_return_bool(true);
70
#else
71
    return true;
72
#endif /* NO_LEAKS */
73
377k
}
74
75
bool
76
sudoers_gc_remove(enum sudoers_gc_types type, void *v)
77
139k
{
78
139k
#ifdef NO_LEAKS
79
139k
    struct sudoers_gc_entry *gc, *prev = NULL;
80
139k
    debug_decl(sudoers_gc_remove, SUDOERS_DEBUG_UTIL);
81
82
139k
    if (v == NULL)
83
78.0k
  debug_return_bool(false);
84
85
673k
    SLIST_FOREACH(gc, &sudoers_gc_list, entries) {
86
673k
  switch (gc->type) {
87
644k
  case GC_PTR:
88
644k
      if (gc->u.ptr == v)
89
55.3k
        goto found;
90
589k
      break;
91
589k
  case GC_VECTOR:
92
29.1k
      if (gc->u.vec == v)
93
5.67k
        goto found;
94
23.4k
      break;
95
23.4k
  default:
96
0
      sudo_warnx("unexpected garbage type %d in %p", gc->type, gc);
97
673k
  }
98
612k
  prev = gc;
99
612k
    }
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
61.0k
found:
108
61.0k
    if (prev == NULL)
109
11.0k
  SLIST_REMOVE_HEAD(&sudoers_gc_list, entries);
110
50.0k
    else
111
50.0k
  SLIST_REMOVE_AFTER(prev, entries);
112
61.0k
    free(gc);
113
114
61.0k
    debug_return_bool(true);
115
#else
116
    return true;
117
#endif /* NO_LEAKS */
118
61.0k
}
119
120
void
121
sudoers_gc_run(void)
122
25.3k
{
123
25.3k
#ifdef NO_LEAKS
124
25.3k
    struct sudoers_gc_entry *gc;
125
25.3k
    char **cur;
126
25.3k
    debug_decl(sudoers_gc_run, SUDOERS_DEBUG_UTIL);
127
128
    /* Collect garbage. */
129
341k
    while ((gc = SLIST_FIRST(&sudoers_gc_list)) != NULL) {
130
315k
  SLIST_REMOVE_HEAD(&sudoers_gc_list, entries);
131
315k
  switch (gc->type) {
132
308k
  case GC_PTR:
133
308k
      free(gc->u.ptr);
134
308k
      free(gc);
135
308k
      break;
136
7.65k
  case GC_VECTOR:
137
270k
      for (cur = gc->u.vec; *cur != NULL; cur++)
138
263k
    free(*cur);
139
7.65k
      free(gc->u.vec);
140
7.65k
      free(gc);
141
7.65k
      break;
142
0
  default:
143
0
      sudo_warnx("unexpected garbage type %d", gc->type);
144
315k
  }
145
315k
    }
146
147
25.3k
    debug_return;
148
25.3k
#endif /* NO_LEAKS */
149
25.3k
}