/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 | } |