Coverage Report

Created: 2023-06-07 06:47

/src/sudo/plugins/sudoers/redblack.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 2004-2005, 2007, 2009-2015
5
 *  Todd C. Miller <Todd.Miller@sudo.ws>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
/*
21
 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
22
 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
23
 */
24
25
/*
26
 * Adapted from the following code written by Emin Martinian:
27
 * http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
28
 *
29
 * Copyright (c) 2001 Emin Martinian
30
 *
31
 * Redistribution and use in source and binary forms, with or without
32
 * modification, are permitted provided that neither the name of Emin
33
 * Martinian nor the names of any contributors are be used to endorse or
34
 * promote products derived from this software without specific prior
35
 * written permission.
36
 *
37
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48
 */
49
50
#include <config.h>
51
52
#include <stdio.h>
53
#include <stdlib.h>
54
55
#include "sudoers.h"
56
#include "redblack.h"
57
58
static void rbrepair(struct rbtree *, struct rbnode *);
59
static void rotate_left(struct rbtree *, struct rbnode *);
60
static void rotate_right(struct rbtree *, struct rbnode *);
61
static void rbdestroy_int(struct rbtree *, struct rbnode *, void (*)(void *));
62
63
/*
64
 * Red-Black tree, see http://en.wikipedia.org/wiki/Red-black_tree
65
 *
66
 * A red-black tree is a binary search tree where each node has a color
67
 * attribute, the value of which is either red or black.  Essentially, it
68
 * is just a convenient way to express a 2-3-4 binary search tree where
69
 * the color indicates whether the node is part of a 3-node or a 4-node.
70
 * In addition to the ordinary requirements imposed on binary search
71
 * trees, we make the following additional requirements of any valid
72
 * red-black tree:
73
 *  1) Every node is either red or black.
74
 *  2) The root is black.
75
 *  3) All leaves are black.
76
 *  4) Both children of each red node are black.
77
 *  5) The paths from each leaf up to the root each contain the same
78
 *     number of black nodes.
79
 */
80
81
/*
82
 * Create a red black tree struct using the specified compare routine.
83
 * Allocates and returns the initialized (empty) tree or NULL if
84
 * memory cannot be allocated.
85
 */
86
struct rbtree *
87
rbcreate(int (*compar)(const void *, const void*))
88
85.6k
{
89
85.6k
    struct rbtree *tree;
90
85.6k
    debug_decl(rbcreate, SUDOERS_DEBUG_RBTREE);
91
92
85.6k
    if ((tree = malloc(sizeof(*tree))) == NULL) {
93
0
  sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
94
0
      "unable to allocate memory");
95
0
  debug_return_ptr(NULL);
96
0
    }
97
98
85.6k
    tree->compar = compar;
99
100
    /*
101
     * We use a self-referencing sentinel node called nil to simplify the
102
     * code by avoiding the need to check for NULL pointers.
103
     */
104
85.6k
    tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil;
105
85.6k
    tree->nil.color = black;
106
85.6k
    tree->nil.data = NULL;
107
108
    /*
109
     * Similarly, the fake root node keeps us from having to worry
110
     * about splitting the root.
111
     */
112
85.6k
    tree->root.left = tree->root.right = tree->root.parent = &tree->nil; // -V778
113
85.6k
    tree->root.color = black;
114
85.6k
    tree->root.data = NULL;
115
116
85.6k
    debug_return_ptr(tree);
117
85.6k
}
118
119
/*
120
 * Perform a left rotation starting at node.
121
 */
122
static void
123
rotate_left(struct rbtree *tree, struct rbnode *node)
124
5.72k
{
125
5.72k
    struct rbnode *child;
126
5.72k
    debug_decl(rotate_left, SUDOERS_DEBUG_RBTREE);
127
128
5.72k
    child = node->right;
129
5.72k
    node->right = child->left;
130
131
5.72k
    if (child->left != rbnil(tree))
132
1.61k
        child->left->parent = node;
133
5.72k
    child->parent = node->parent;
134
135
5.72k
    if (node == node->parent->left)
136
3.88k
  node->parent->left = child;
137
1.84k
    else
138
1.84k
  node->parent->right = child;
139
5.72k
    child->left = node;
140
5.72k
    node->parent = child;
141
142
5.72k
    debug_return;
143
5.72k
}
144
145
/*
146
 * Perform a right rotation starting at node.
147
 */
148
static void
149
rotate_right(struct rbtree *tree, struct rbnode *node)
150
5.44k
{
151
5.44k
    struct rbnode *child;
152
5.44k
    debug_decl(rotate_right, SUDOERS_DEBUG_RBTREE);
153
154
5.44k
    child = node->left;
155
5.44k
    node->left = child->right;
156
157
5.44k
    if (child->right != rbnil(tree))
158
1.44k
        child->right->parent = node;
159
5.44k
    child->parent = node->parent;
160
161
5.44k
    if (node == node->parent->left)
162
1.84k
  node->parent->left = child;
163
3.59k
    else
164
3.59k
  node->parent->right = child;
165
5.44k
    child->right = node;
166
5.44k
    node->parent = child;
167
168
5.44k
    debug_return;
169
5.44k
}
170
171
/*
172
 * Insert data pointer into a redblack tree.
173
 * Returns a 0 on success, 1 if a node matching "data" already exists
174
 * (filling in "existing" if not NULL), or -1 on malloc() failure.
175
 */
176
int
177
rbinsert(struct rbtree *tree, void *data, struct rbnode **existing)
178
365k
{
179
365k
    struct rbnode *node = rbfirst(tree);
180
365k
    struct rbnode *parent = rbroot(tree);
181
365k
    int res;
182
365k
    debug_decl(rbinsert, SUDOERS_DEBUG_RBTREE);
183
184
    /* Find correct insertion point. */
185
690k
    while (node != rbnil(tree)) {
186
564k
  parent = node;
187
564k
  if ((res = tree->compar(data, node->data)) == 0) {
188
240k
      if (existing != NULL)
189
240k
    *existing = node;
190
240k
      debug_return_int(1);
191
240k
  }
192
324k
  node = res < 0 ? node->left : node->right;
193
324k
    }
194
195
125k
    node = malloc(sizeof(*node));
196
125k
    if (node == NULL) {
197
0
  sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
198
0
      "unable to allocate memory");
199
0
  debug_return_int(-1);
200
0
    }
201
125k
    node->data = data;
202
125k
    node->left = node->right = rbnil(tree);
203
125k
    node->parent = parent;
204
125k
    if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0)
205
91.6k
  parent->left = node;
206
33.7k
    else
207
33.7k
  parent->right = node;
208
125k
    node->color = red;
209
210
    /*
211
     * If the parent node is black we are all set, if it is red we have
212
     * the following possible cases to deal with.  We iterate through
213
     * the rest of the tree to make sure none of the required properties
214
     * is violated.
215
     *
216
     *  1) The uncle is red.  We repaint both the parent and uncle black
217
     *     and repaint the grandparent node red.
218
     *
219
     *  2) The uncle is black and the new node is the right child of its
220
     *     parent, and the parent in turn is the left child of its parent.
221
     *     We do a left rotation to switch the roles of the parent and
222
     *     child, relying on further iterations to fixup the old parent.
223
     *
224
     *  3) The uncle is black and the new node is the left child of its
225
     *     parent, and the parent in turn is the left child of its parent.
226
     *     We switch the colors of the parent and grandparent and perform
227
     *     a right rotation around the grandparent.  This makes the former
228
     *     parent the parent of the new node and the former grandparent.
229
     *
230
     * Note that because we use a sentinel for the root node we never
231
     * need to worry about replacing the root.
232
     */
233
140k
    while (node->parent->color == red) {
234
15.1k
  struct rbnode *uncle;
235
15.1k
  if (node->parent == node->parent->parent->left) {
236
7.24k
      uncle = node->parent->parent->right;
237
7.24k
      if (uncle->color == red) {
238
3.74k
    node->parent->color = black;
239
3.74k
    uncle->color = black;
240
3.74k
    node->parent->parent->color = red;
241
3.74k
    node = node->parent->parent;
242
3.74k
      } else /* if (uncle->color == black) */ {
243
3.49k
    if (node == node->parent->right) {
244
1.84k
        node = node->parent;
245
1.84k
        rotate_left(tree, node);
246
1.84k
    }
247
3.49k
    node->parent->color = black;
248
3.49k
    node->parent->parent->color = red;
249
3.49k
    rotate_right(tree, node->parent->parent);
250
3.49k
      }
251
7.88k
  } else { /* if (node->parent == node->parent->parent->right) */
252
7.88k
      uncle = node->parent->parent->left;
253
7.88k
      if (uncle->color == red) {
254
4.00k
    node->parent->color = black;
255
4.00k
    uncle->color = black;
256
4.00k
    node->parent->parent->color = red;
257
4.00k
    node = node->parent->parent;
258
4.00k
      } else /* if (uncle->color == black) */ {
259
3.88k
    if (node == node->parent->left) {
260
1.94k
        node = node->parent;
261
1.94k
        rotate_right(tree, node);
262
1.94k
    }
263
3.88k
    node->parent->color = black;
264
3.88k
    node->parent->parent->color = red;
265
3.88k
    rotate_left(tree, node->parent->parent);
266
3.88k
      }
267
7.88k
  }
268
15.1k
    }
269
125k
    rbfirst(tree)->color = black;  /* first node is always black */
270
125k
    debug_return_int(0);
271
125k
}
272
273
/*
274
 * Look for a node matching key in tree.
275
 * Returns a pointer to the node if found, else NULL.
276
 */
277
struct rbnode *
278
rbfind(struct rbtree *tree, void *key)
279
159k
{
280
159k
    struct rbnode *node = rbfirst(tree);
281
159k
    int res;
282
159k
    debug_decl(rbfind, SUDOERS_DEBUG_RBTREE);
283
284
232k
    while (node != rbnil(tree)) {
285
139k
  if ((res = tree->compar(key, node->data)) == 0)
286
67.2k
      debug_return_ptr(node);
287
72.2k
  node = res < 0 ? node->left : node->right;
288
72.2k
    }
289
92.6k
    debug_return_ptr(NULL);
290
92.6k
}
291
292
/*
293
 * Call func() for each node, passing it the node data and a cookie;
294
 * If func() returns non-zero for a node, the traversal stops and the
295
 * error value is returned.  Returns 0 on successful traversal.
296
 */
297
int
298
rbapply_node(struct rbtree *tree, struct rbnode *node,
299
    int (*func)(void *, void *), void *cookie, enum rbtraversal order)
300
0
{
301
0
    int error;
302
0
    debug_decl(rbapply_node, SUDOERS_DEBUG_RBTREE);
303
304
0
    if (node != rbnil(tree)) {
305
0
  if (order == preorder)
306
0
      if ((error = func(node->data, cookie)) != 0)
307
0
    debug_return_int(error);
308
0
  if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0)
309
0
      debug_return_int(error);
310
0
  if (order == inorder)
311
0
      if ((error = func(node->data, cookie)) != 0)
312
0
    debug_return_int(error);
313
0
  if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0)
314
0
      debug_return_int(error);
315
0
  if (order == postorder)
316
0
      if ((error = func(node->data, cookie)) != 0)
317
0
    debug_return_int(error);
318
0
    }
319
0
    debug_return_int(0);
320
0
}
321
322
/*
323
 * Returns the successor of node, or nil if there is none.
324
 */
325
static struct rbnode *
326
rbsuccessor(struct rbtree *tree, struct rbnode *node)
327
0
{
328
0
    struct rbnode *succ;
329
0
    debug_decl(rbsuccessor, SUDOERS_DEBUG_RBTREE);
330
331
0
    if ((succ = node->right) != rbnil(tree)) {
332
0
  while (succ->left != rbnil(tree))
333
0
      succ = succ->left;
334
0
    } else {
335
  /* No right child, move up until we find it or hit the root */
336
0
  for (succ = node->parent; node == succ->right; succ = succ->parent)
337
0
      node = succ;
338
0
  if (succ == rbroot(tree))
339
0
      succ = rbnil(tree);
340
0
    }
341
0
    debug_return_ptr(succ);
342
0
}
343
344
/*
345
 * Recursive portion of rbdestroy().
346
 */
347
static void
348
rbdestroy_int(struct rbtree *tree, struct rbnode *node, void (*destroy)(void *))
349
336k
{
350
336k
    debug_decl(rbdestroy_int, SUDOERS_DEBUG_RBTREE);
351
336k
    if (node != rbnil(tree)) {
352
125k
  rbdestroy_int(tree, node->left, destroy);
353
125k
  rbdestroy_int(tree, node->right, destroy);
354
125k
  if (destroy != NULL)
355
125k
      destroy(node->data);
356
125k
  free(node);
357
125k
    }
358
336k
    debug_return;
359
336k
}
360
361
/*
362
 * Destroy the specified tree, calling the destructor "destroy"
363
 * for each node and then freeing the tree itself.
364
 */
365
void
366
rbdestroy(struct rbtree *tree, void (*destroy)(void *))
367
85.6k
{
368
85.6k
    debug_decl(rbdestroy, SUDOERS_DEBUG_RBTREE);
369
85.6k
    rbdestroy_int(tree, rbfirst(tree), destroy);
370
85.6k
    free(tree);
371
85.6k
    debug_return;
372
85.6k
}
373
374
/*
375
 * Delete node 'z' from the tree and return its data pointer.
376
 */
377
void *rbdelete(struct rbtree *tree, struct rbnode *z)
378
1
{
379
1
    struct rbnode *x, *y;
380
1
    void *data = z->data;
381
1
    debug_decl(rbdelete, SUDOERS_DEBUG_RBTREE);
382
383
1
    if (z->left == rbnil(tree) || z->right == rbnil(tree))
384
1
  y = z;
385
0
    else
386
0
  y = rbsuccessor(tree, z);
387
1
    x = (y->left == rbnil(tree)) ? y->right : y->left;
388
389
1
    if ((x->parent = y->parent) == rbroot(tree)) {
390
1
  rbfirst(tree) = x;
391
1
    } else {
392
0
  if (y == y->parent->left)
393
0
      y->parent->left = x;
394
0
  else
395
0
      y->parent->right = x;
396
0
    }
397
1
    if (y->color == black)
398
1
  rbrepair(tree, x);
399
1
    if (y != z) {
400
0
  y->left = z->left;
401
0
  y->right = z->right;
402
0
  y->parent = z->parent;
403
0
  y->color = z->color;
404
0
  z->left->parent = z->right->parent = y;
405
0
  if (z == z->parent->left)
406
0
      z->parent->left = y; 
407
0
  else
408
0
      z->parent->right = y;
409
0
    }
410
1
    free(z); 
411
    
412
1
    debug_return_ptr(data);
413
1
}
414
415
/*
416
 * Repair the tree after a node has been deleted by rotating and repainting
417
 * colors to restore the 4 properties inherent in red-black trees.
418
 */
419
static void
420
rbrepair(struct rbtree *tree, struct rbnode *node)
421
1
{
422
1
    struct rbnode *sibling;
423
1
    debug_decl(rbrepair, SUDOERS_DEBUG_RBTREE);
424
425
1
    while (node->color == black && node != rbfirst(tree)) {
426
0
  if (node == node->parent->left) {
427
0
      sibling = node->parent->right;
428
0
      if (sibling->color == red) {
429
0
    sibling->color = black;
430
0
    node->parent->color = red;
431
0
    rotate_left(tree, node->parent);
432
0
    sibling = node->parent->right;
433
0
      }
434
0
      if (sibling->right->color == black && sibling->left->color == black) {
435
0
    sibling->color = red;
436
0
    node = node->parent;
437
0
      } else {
438
0
    if (sibling->right->color == black) {
439
0
          sibling->left->color = black;
440
0
          sibling->color = red;
441
0
          rotate_right(tree, sibling);
442
0
          sibling = node->parent->right;
443
0
    }
444
0
    sibling->color = node->parent->color;
445
0
    node->parent->color = black;
446
0
    sibling->right->color = black;
447
0
    rotate_left(tree, node->parent);
448
0
    node = rbfirst(tree); /* exit loop */
449
0
      }
450
0
  } else { /* if (node == node->parent->right) */
451
0
      sibling = node->parent->left;
452
0
      if (sibling->color == red) {
453
0
    sibling->color = black;
454
0
    node->parent->color = red;
455
0
    rotate_right(tree, node->parent);
456
0
    sibling = node->parent->left;
457
0
      }
458
0
      if (sibling->right->color == black && sibling->left->color == black) {
459
0
    sibling->color = red;
460
0
    node = node->parent;
461
0
      } else {
462
0
    if (sibling->left->color == black) {
463
0
        sibling->right->color = black;
464
0
        sibling->color = red;
465
0
        rotate_left(tree, sibling);
466
0
        sibling = node->parent->left;
467
0
    }
468
0
    sibling->color = node->parent->color;
469
0
    node->parent->color = black;
470
0
    sibling->left->color = black;
471
0
    rotate_right(tree, node->parent);
472
0
    node = rbfirst(tree); /* exit loop */
473
0
      }
474
0
  }
475
0
    }
476
1
    node->color = black;
477
478
1
    debug_return;
479
1
}