File: tests_libcrun_linux.c

package info (click to toggle)
crun 1.26-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,356 kB
  • sloc: ansic: 70,844; python: 14,125; sh: 5,122; makefile: 928
file content (447 lines) | stat: -rw-r--r-- 10,146 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
/*
 * crun - OCI runtime written in C
 *
 * Copyright (C) 2017, 2018, 2019 Giuseppe Scrivano <giuseppe@scrivano.org>
 * crun is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * crun is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with crun.  If not, see <http://www.gnu.org/licenses/>.
 */

#define _GNU_SOURCE
#include <config.h>
#include <stdio.h>
#include <libcrun/error.h>
#include <libcrun/utils.h>
#include <libcrun/linux.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sched.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <limits.h>
#include <ocispec/runtime_spec_schema_config_schema.h>

/* Ensure namespace constants are defined */
#ifndef CLONE_NEWNS
#  define CLONE_NEWNS 0x00020000
#endif
#ifndef CLONE_NEWNET
#  define CLONE_NEWNET 0x40000000
#endif
#ifndef CLONE_NEWIPC
#  define CLONE_NEWIPC 0x08000000
#endif
#ifndef CLONE_NEWPID
#  define CLONE_NEWPID 0x20000000
#endif
#ifndef CLONE_NEWUTS
#  define CLONE_NEWUTS 0x04000000
#endif
#ifndef CLONE_NEWUSER
#  define CLONE_NEWUSER 0x10000000
#endif
#ifndef CLONE_NEWCGROUP
#  define CLONE_NEWCGROUP 0x02000000
#endif
#ifndef CLONE_NEWTIME
#  define CLONE_NEWTIME 0x00000080
#endif

typedef int (*test) ();

/* Test libcrun_find_namespace function */
static int
test_find_namespace ()
{
  int ret;

  /* Test valid namespace names */
  ret = libcrun_find_namespace ("mount");
  if (ret != CLONE_NEWNS)
    return -1;

  ret = libcrun_find_namespace ("network");
  if (ret != CLONE_NEWNET)
    return -1;

  ret = libcrun_find_namespace ("ipc");
  if (ret != CLONE_NEWIPC)
    return -1;

  ret = libcrun_find_namespace ("pid");
  if (ret != CLONE_NEWPID)
    return -1;

  ret = libcrun_find_namespace ("uts");
  if (ret != CLONE_NEWUTS)
    return -1;

  ret = libcrun_find_namespace ("user");
  if (ret != CLONE_NEWUSER)
    return -1;

#ifdef CLONE_NEWCGROUP
  ret = libcrun_find_namespace ("cgroup");
  if (ret != CLONE_NEWCGROUP)
    return -1;
#endif

#ifdef CLONE_NEWTIME
  ret = libcrun_find_namespace ("time");
  if (ret != CLONE_NEWTIME)
    return -1;
#endif

  /* Test invalid namespace name */
  ret = libcrun_find_namespace ("invalid");
  if (ret != -1)
    return -1;

  ret = libcrun_find_namespace ("");
  if (ret != -1)
    return -1;

  /* Note: Do NOT test NULL - libcrun_find_namespace likely doesn't handle NULL */

  return 0;
}

/* Test path_is_slash_dev function (from utils.h but used heavily in linux.c) */
static int
test_path_is_slash_dev_linux ()
{
  /* Test exact /dev */
  if (! path_is_slash_dev ("/dev"))
    return -1;
  if (! path_is_slash_dev ("/dev/"))
    return -1;
  if (! path_is_slash_dev ("dev"))
    return -1;
  if (! path_is_slash_dev ("dev/"))
    return -1;

  /* Test with extra slashes */
  if (! path_is_slash_dev ("/dev//"))
    return -1;
  if (! path_is_slash_dev ("///dev///"))
    return -1;

  /* Test subdirectories of /dev - should fail */
  if (path_is_slash_dev ("/dev/null"))
    return -1;
  if (path_is_slash_dev ("/dev/pts"))
    return -1;
  if (path_is_slash_dev ("/dev/pts/0"))
    return -1;

  /* Test other paths */
  if (path_is_slash_dev ("/"))
    return -1;
  if (path_is_slash_dev ("/home"))
    return -1;
  if (path_is_slash_dev (""))
    return -1;

  return 0;
}

/* Test libcrun_reopen_dev_null function */
static int
test_reopen_dev_null ()
{
  libcrun_error_t err = NULL;
  int ret;
  int saved_stdin, saved_stdout, saved_stderr;

  /* Save current stdin/stdout/stderr */
  saved_stdin = dup (0);
  saved_stdout = dup (1);
  saved_stderr = dup (2);

  if (saved_stdin < 0 || saved_stdout < 0 || saved_stderr < 0)
    {
      /* Cleanup on failure */
      if (saved_stdin >= 0)
        close (saved_stdin);
      if (saved_stdout >= 0)
        close (saved_stdout);
      if (saved_stderr >= 0)
        close (saved_stderr);
      return 77; /* SKIP - can't save descriptors */
    }

  /* Call the function */
  ret = libcrun_reopen_dev_null (&err);

  /* Restore original descriptors */
  dup2 (saved_stdin, 0);
  dup2 (saved_stdout, 1);
  dup2 (saved_stderr, 2);
  close (saved_stdin);
  close (saved_stdout);
  close (saved_stderr);

  if (ret < 0)
    {
      crun_error_release (&err);
      return -1;
    }

  return 0;
}

/* Test libcrun_set_rlimits function */
static int
test_set_rlimits ()
{
  libcrun_error_t err = NULL;
  int ret;
  struct rlimit current_nofile;

  /* Get current NOFILE limit to restore later */
  if (getrlimit (RLIMIT_NOFILE, &current_nofile) < 0)
    return 77; /* SKIP */

  /* Test with NULL rlimits - should succeed */
  ret = libcrun_set_rlimits (NULL, 0, &err);
  if (ret < 0)
    {
      crun_error_release (&err);
      return -1;
    }

  /* Restore original limit */
  setrlimit (RLIMIT_NOFILE, &current_nofile);

  return 0;
}

/* Test libcrun_find_namespace with edge cases */
static int
test_find_namespace_edge_cases ()
{
  int ret;

  /* Test with partial names - should fail */
  ret = libcrun_find_namespace ("moun");
  if (ret != -1)
    return -1;

  ret = libcrun_find_namespace ("networ");
  if (ret != -1)
    return -1;

  /* Test with wrong case - should fail */
  ret = libcrun_find_namespace ("MOUNT");
  if (ret != -1)
    return -1;

  ret = libcrun_find_namespace ("Network");
  if (ret != -1)
    return -1;

  /* Test with extra characters */
  ret = libcrun_find_namespace ("mount ");
  if (ret != -1)
    return -1;

  ret = libcrun_find_namespace (" mount");
  if (ret != -1)
    return -1;

  return 0;
}

/* Test path boundary conditions */
static int
test_path_boundary ()
{
  /* Test paths that start with dev but aren't /dev */
  if (path_is_slash_dev ("devious"))
    return -1;

  if (path_is_slash_dev ("developer"))
    return -1;

  /* Various forms of /dev */
  if (! path_is_slash_dev ("/dev"))
    return -1;

  return 0;
}

/* Test libcrun_safe_chdir function */
static int
test_safe_chdir ()
{
  libcrun_error_t err = NULL;
  char saved_cwd[PATH_MAX];
  int ret;

  /* Save current directory */
  if (getcwd (saved_cwd, sizeof (saved_cwd)) == NULL)
    return 77; /* SKIP */

  /* Test with valid directory */
  ret = libcrun_safe_chdir ("/tmp", &err);
  if (ret < 0)
    {
      crun_error_release (&err);
      /* Restore cwd */
      if (chdir (saved_cwd) < 0)
        {
          /* ignore */
        }
      return -1;
    }

  /* Test with another valid directory */
  ret = libcrun_safe_chdir ("/", &err);
  if (ret < 0)
    {
      crun_error_release (&err);
      if (chdir (saved_cwd) < 0)
        {
          /* ignore */
        }
      return -1;
    }

  /* Test with non-existent directory - should fail */
  ret = libcrun_safe_chdir ("/nonexistent_directory_12345", &err);
  if (ret >= 0)
    {
      /* Should have failed */
      if (chdir (saved_cwd) < 0)
        {
          /* ignore */
        }
      return -1;
    }
  crun_error_release (&err);

  /* Restore original directory */
  if (chdir (saved_cwd) < 0)
    return -1;

  return 0;
}

/* Test syscall_clone inline function indirectly by checking it compiles and constants are correct */
static int
test_clone_constants ()
{
  /* Just verify the constants are defined correctly - we can't actually call clone without side effects */
  if (CLONE_NEWNS == 0)
    return -1;
  if (CLONE_NEWNET == 0)
    return -1;
  if (CLONE_NEWIPC == 0)
    return -1;
  if (CLONE_NEWPID == 0)
    return -1;
  if (CLONE_NEWUTS == 0)
    return -1;
  if (CLONE_NEWUSER == 0)
    return -1;

  /* Verify namespace values are different */
  if (CLONE_NEWNS == CLONE_NEWNET)
    return -1;
  if (CLONE_NEWNS == CLONE_NEWIPC)
    return -1;
  if (CLONE_NEWNET == CLONE_NEWPID)
    return -1;

  return 0;
}

/* Test that namespace lookup is consistent */
static int
test_namespace_consistency ()
{
  /* Verify that libcrun_find_namespace returns the expected clone flags */
  int mount_val = libcrun_find_namespace ("mount");
  int net_val = libcrun_find_namespace ("network");
  int pid_val = libcrun_find_namespace ("pid");
  int user_val = libcrun_find_namespace ("user");

  /* All should be non-zero (valid namespaces) */
  if (mount_val == 0 || net_val == 0 || pid_val == 0 || user_val == 0)
    return -1;

  /* All should be different */
  if (mount_val == net_val || mount_val == pid_val || mount_val == user_val)
    return -1;
  if (net_val == pid_val || net_val == user_val)
    return -1;
  if (pid_val == user_val)
    return -1;

  return 0;
}

/* Test rlimits with zero length */
static int
test_rlimits_zero_length ()
{
  libcrun_error_t err = NULL;
  runtime_spec_schema_config_schema_process_rlimits_element *rlimits[1] = { NULL };
  int ret;

  /* Test with empty array */
  ret = libcrun_set_rlimits (rlimits, 0, &err);
  if (ret < 0)
    {
      crun_error_release (&err);
      return -1;
    }

  return 0;
}

static void
run_and_print_test_result (const char *name, int id, test t)
{
  int ret = t ();
  if (ret == 0)
    printf ("ok %d - %s\n", id, name);
  else if (ret == 77)
    printf ("ok %d - %s #SKIP\n", id, name);
  else
    printf ("not ok %d - %s\n", id, name);
}

#define RUN_TEST(T)                            \
  do                                           \
    {                                          \
      run_and_print_test_result (#T, id++, T); \
  } while (0)

int
main ()
{
  int id = 1;
  printf ("1..10\n");
  RUN_TEST (test_find_namespace);
  RUN_TEST (test_path_is_slash_dev_linux);
  RUN_TEST (test_reopen_dev_null);
  RUN_TEST (test_set_rlimits);
  RUN_TEST (test_find_namespace_edge_cases);
  RUN_TEST (test_path_boundary);
  RUN_TEST (test_safe_chdir);
  RUN_TEST (test_clone_constants);
  RUN_TEST (test_namespace_consistency);
  RUN_TEST (test_rlimits_zero_length);
  return 0;
}