1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <sched.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/capability.h>
11 #include <sys/ioctl.h>
12 #include <sys/stat.h>
13 #include <sys/syscall.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 #include <linux/nsfs.h>
18 #include "../kselftest_harness.h"
19 #include "../filesystems/utils.h"
20 #include "wrappers.h"
21
22 /*
23 * Test credential changes and their impact on namespace active references.
24 */
25
26 /*
27 * Test setuid() in a user namespace properly swaps active references.
28 * Create a user namespace with multiple UIDs mapped, then setuid() between them.
29 * Verify that the user namespace remains active throughout.
30 */
TEST(setuid_preserves_active_refs)31 TEST(setuid_preserves_active_refs)
32 {
33 pid_t pid;
34 int status;
35 __u64 userns_id;
36 struct ns_id_req req = {
37 .size = sizeof(req),
38 .spare = 0,
39 .ns_id = 0,
40 .ns_type = CLONE_NEWUSER,
41 .spare2 = 0,
42 .user_ns_id = 0,
43 };
44 __u64 ns_ids[256];
45 ssize_t ret;
46 int i;
47 bool found = false;
48 int pipefd[2];
49
50 ASSERT_EQ(pipe(pipefd), 0);
51
52 pid = fork();
53 ASSERT_GE(pid, 0);
54
55 if (pid == 0) {
56 /* Child process */
57 int fd, userns_fd;
58 __u64 child_userns_id;
59 uid_t orig_uid = getuid();
60 int setuid_count;
61
62 close(pipefd[0]);
63
64 /* Create new user namespace with multiple UIDs mapped (0-9) */
65 userns_fd = get_userns_fd(0, orig_uid, 10);
66 if (userns_fd < 0) {
67 close(pipefd[1]);
68 exit(1);
69 }
70
71 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
72 close(userns_fd);
73 close(pipefd[1]);
74 exit(1);
75 }
76 close(userns_fd);
77
78 /* Get user namespace ID */
79 fd = open("/proc/self/ns/user", O_RDONLY);
80 if (fd < 0) {
81 close(pipefd[1]);
82 exit(1);
83 }
84
85 if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
86 close(fd);
87 close(pipefd[1]);
88 exit(1);
89 }
90 close(fd);
91
92 /* Send namespace ID to parent */
93 write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
94
95 /*
96 * Perform multiple setuid() calls.
97 * Each setuid() triggers commit_creds() which should properly
98 * swap active references via switch_cred_namespaces().
99 */
100 for (setuid_count = 0; setuid_count < 50; setuid_count++) {
101 uid_t target_uid = (setuid_count % 10);
102 if (setuid(target_uid) < 0) {
103 if (errno != EPERM) {
104 close(pipefd[1]);
105 exit(1);
106 }
107 }
108 }
109
110 close(pipefd[1]);
111 exit(0);
112 }
113
114 /* Parent process */
115 close(pipefd[1]);
116
117 if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
118 close(pipefd[0]);
119 kill(pid, SIGKILL);
120 waitpid(pid, NULL, 0);
121 SKIP(return, "Failed to get namespace ID from child");
122 }
123 close(pipefd[0]);
124
125 TH_LOG("Child user namespace ID: %llu", (unsigned long long)userns_id);
126
127 /* Verify namespace is active while child is running */
128 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
129 if (ret < 0) {
130 kill(pid, SIGKILL);
131 waitpid(pid, NULL, 0);
132 if (errno == ENOSYS)
133 SKIP(return, "listns() not supported");
134 ASSERT_GE(ret, 0);
135 }
136
137 for (i = 0; i < ret; i++) {
138 if (ns_ids[i] == userns_id) {
139 found = true;
140 break;
141 }
142 }
143 ASSERT_TRUE(found);
144
145 waitpid(pid, &status, 0);
146 ASSERT_TRUE(WIFEXITED(status));
147 ASSERT_EQ(WEXITSTATUS(status), 0);
148
149 /* Verify namespace becomes inactive after child exits */
150 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
151 ASSERT_GE(ret, 0);
152
153 found = false;
154 for (i = 0; i < ret; i++) {
155 if (ns_ids[i] == userns_id) {
156 found = true;
157 break;
158 }
159 }
160
161 ASSERT_FALSE(found);
162 TH_LOG("setuid() correctly preserved active references (no leak)");
163 }
164
165 /*
166 * Test setgid() in a user namespace properly handles active references.
167 */
TEST(setgid_preserves_active_refs)168 TEST(setgid_preserves_active_refs)
169 {
170 pid_t pid;
171 int status;
172 __u64 userns_id;
173 struct ns_id_req req = {
174 .size = sizeof(req),
175 .spare = 0,
176 .ns_id = 0,
177 .ns_type = CLONE_NEWUSER,
178 .spare2 = 0,
179 .user_ns_id = 0,
180 };
181 __u64 ns_ids[256];
182 ssize_t ret;
183 int i;
184 bool found = false;
185 int pipefd[2];
186
187 ASSERT_EQ(pipe(pipefd), 0);
188
189 pid = fork();
190 ASSERT_GE(pid, 0);
191
192 if (pid == 0) {
193 /* Child process */
194 int fd, userns_fd;
195 __u64 child_userns_id;
196 uid_t orig_uid = getuid();
197 int setgid_count;
198
199 close(pipefd[0]);
200
201 /* Create new user namespace with multiple GIDs mapped */
202 userns_fd = get_userns_fd(0, orig_uid, 10);
203 if (userns_fd < 0) {
204 close(pipefd[1]);
205 exit(1);
206 }
207
208 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
209 close(userns_fd);
210 close(pipefd[1]);
211 exit(1);
212 }
213 close(userns_fd);
214
215 /* Get user namespace ID */
216 fd = open("/proc/self/ns/user", O_RDONLY);
217 if (fd < 0) {
218 close(pipefd[1]);
219 exit(1);
220 }
221
222 if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
223 close(fd);
224 close(pipefd[1]);
225 exit(1);
226 }
227 close(fd);
228
229 write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
230
231 /* Perform multiple setgid() calls */
232 for (setgid_count = 0; setgid_count < 50; setgid_count++) {
233 gid_t target_gid = (setgid_count % 10);
234 if (setgid(target_gid) < 0) {
235 if (errno != EPERM) {
236 close(pipefd[1]);
237 exit(1);
238 }
239 }
240 }
241
242 close(pipefd[1]);
243 exit(0);
244 }
245
246 /* Parent process */
247 close(pipefd[1]);
248
249 if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
250 close(pipefd[0]);
251 kill(pid, SIGKILL);
252 waitpid(pid, NULL, 0);
253 SKIP(return, "Failed to get namespace ID from child");
254 }
255 close(pipefd[0]);
256
257 waitpid(pid, &status, 0);
258 ASSERT_TRUE(WIFEXITED(status));
259 ASSERT_EQ(WEXITSTATUS(status), 0);
260
261 /* Verify namespace becomes inactive */
262 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
263 if (ret < 0) {
264 if (errno == ENOSYS)
265 SKIP(return, "listns() not supported");
266 ASSERT_GE(ret, 0);
267 }
268
269 for (i = 0; i < ret; i++) {
270 if (ns_ids[i] == userns_id) {
271 found = true;
272 break;
273 }
274 }
275
276 ASSERT_FALSE(found);
277 TH_LOG("setgid() correctly preserved active references (no leak)");
278 }
279
280 /*
281 * Test setresuid() which changes real, effective, and saved UIDs.
282 * This should properly swap active references via commit_creds().
283 */
TEST(setresuid_preserves_active_refs)284 TEST(setresuid_preserves_active_refs)
285 {
286 pid_t pid;
287 int status;
288 __u64 userns_id;
289 struct ns_id_req req = {
290 .size = sizeof(req),
291 .spare = 0,
292 .ns_id = 0,
293 .ns_type = CLONE_NEWUSER,
294 .spare2 = 0,
295 .user_ns_id = 0,
296 };
297 __u64 ns_ids[256];
298 ssize_t ret;
299 int i;
300 bool found = false;
301 int pipefd[2];
302
303 ASSERT_EQ(pipe(pipefd), 0);
304
305 pid = fork();
306 ASSERT_GE(pid, 0);
307
308 if (pid == 0) {
309 /* Child process */
310 int fd, userns_fd;
311 __u64 child_userns_id;
312 uid_t orig_uid = getuid();
313 int setres_count;
314
315 close(pipefd[0]);
316
317 /* Create new user namespace */
318 userns_fd = get_userns_fd(0, orig_uid, 10);
319 if (userns_fd < 0) {
320 close(pipefd[1]);
321 exit(1);
322 }
323
324 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
325 close(userns_fd);
326 close(pipefd[1]);
327 exit(1);
328 }
329 close(userns_fd);
330
331 /* Get user namespace ID */
332 fd = open("/proc/self/ns/user", O_RDONLY);
333 if (fd < 0) {
334 close(pipefd[1]);
335 exit(1);
336 }
337
338 if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
339 close(fd);
340 close(pipefd[1]);
341 exit(1);
342 }
343 close(fd);
344
345 write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
346
347 /* Perform multiple setresuid() calls */
348 for (setres_count = 0; setres_count < 30; setres_count++) {
349 uid_t uid1 = (setres_count % 5);
350 uid_t uid2 = ((setres_count + 1) % 5);
351 uid_t uid3 = ((setres_count + 2) % 5);
352
353 if (setresuid(uid1, uid2, uid3) < 0) {
354 if (errno != EPERM) {
355 close(pipefd[1]);
356 exit(1);
357 }
358 }
359 }
360
361 close(pipefd[1]);
362 exit(0);
363 }
364
365 /* Parent process */
366 close(pipefd[1]);
367
368 if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
369 close(pipefd[0]);
370 kill(pid, SIGKILL);
371 waitpid(pid, NULL, 0);
372 SKIP(return, "Failed to get namespace ID from child");
373 }
374 close(pipefd[0]);
375
376 waitpid(pid, &status, 0);
377 ASSERT_TRUE(WIFEXITED(status));
378 ASSERT_EQ(WEXITSTATUS(status), 0);
379
380 /* Verify namespace becomes inactive */
381 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
382 if (ret < 0) {
383 if (errno == ENOSYS)
384 SKIP(return, "listns() not supported");
385 ASSERT_GE(ret, 0);
386 }
387
388 for (i = 0; i < ret; i++) {
389 if (ns_ids[i] == userns_id) {
390 found = true;
391 break;
392 }
393 }
394
395 ASSERT_FALSE(found);
396 TH_LOG("setresuid() correctly preserved active references (no leak)");
397 }
398
399 /*
400 * Test credential changes across multiple user namespaces.
401 * Create nested user namespaces and verify active reference tracking.
402 */
TEST(cred_change_nested_userns)403 TEST(cred_change_nested_userns)
404 {
405 pid_t pid;
406 int status;
407 __u64 parent_userns_id, child_userns_id;
408 struct ns_id_req req = {
409 .size = sizeof(req),
410 .spare = 0,
411 .ns_id = 0,
412 .ns_type = CLONE_NEWUSER,
413 .spare2 = 0,
414 .user_ns_id = 0,
415 };
416 __u64 ns_ids[256];
417 ssize_t ret;
418 int i;
419 bool found_parent = false, found_child = false;
420 int pipefd[2];
421
422 ASSERT_EQ(pipe(pipefd), 0);
423
424 pid = fork();
425 ASSERT_GE(pid, 0);
426
427 if (pid == 0) {
428 /* Child process */
429 int fd, userns_fd;
430 __u64 parent_id, child_id;
431 uid_t orig_uid = getuid();
432
433 close(pipefd[0]);
434
435 /* Create first user namespace */
436 userns_fd = get_userns_fd(0, orig_uid, 1);
437 if (userns_fd < 0) {
438 close(pipefd[1]);
439 exit(1);
440 }
441
442 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
443 close(userns_fd);
444 close(pipefd[1]);
445 exit(1);
446 }
447 close(userns_fd);
448
449 /* Get first namespace ID */
450 fd = open("/proc/self/ns/user", O_RDONLY);
451 if (fd < 0) {
452 close(pipefd[1]);
453 exit(1);
454 }
455
456 if (ioctl(fd, NS_GET_ID, &parent_id) < 0) {
457 close(fd);
458 close(pipefd[1]);
459 exit(1);
460 }
461 close(fd);
462
463 /* Create nested user namespace */
464 userns_fd = get_userns_fd(0, 0, 1);
465 if (userns_fd < 0) {
466 close(pipefd[1]);
467 exit(1);
468 }
469
470 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
471 close(userns_fd);
472 close(pipefd[1]);
473 exit(1);
474 }
475 close(userns_fd);
476
477 /* Get nested namespace ID */
478 fd = open("/proc/self/ns/user", O_RDONLY);
479 if (fd < 0) {
480 close(pipefd[1]);
481 exit(1);
482 }
483
484 if (ioctl(fd, NS_GET_ID, &child_id) < 0) {
485 close(fd);
486 close(pipefd[1]);
487 exit(1);
488 }
489 close(fd);
490
491 /* Send both IDs to parent */
492 write(pipefd[1], &parent_id, sizeof(parent_id));
493 write(pipefd[1], &child_id, sizeof(child_id));
494
495 /* Perform some credential changes in nested namespace */
496 setuid(0);
497 setgid(0);
498
499 close(pipefd[1]);
500 exit(0);
501 }
502
503 /* Parent process */
504 close(pipefd[1]);
505
506 /* Read both namespace IDs */
507 if (read(pipefd[0], &parent_userns_id, sizeof(parent_userns_id)) != sizeof(parent_userns_id)) {
508 close(pipefd[0]);
509 kill(pid, SIGKILL);
510 waitpid(pid, NULL, 0);
511 SKIP(return, "Failed to get parent namespace ID");
512 }
513
514 if (read(pipefd[0], &child_userns_id, sizeof(child_userns_id)) != sizeof(child_userns_id)) {
515 close(pipefd[0]);
516 kill(pid, SIGKILL);
517 waitpid(pid, NULL, 0);
518 SKIP(return, "Failed to get child namespace ID");
519 }
520 close(pipefd[0]);
521
522 TH_LOG("Parent userns: %llu, Child userns: %llu",
523 (unsigned long long)parent_userns_id,
524 (unsigned long long)child_userns_id);
525
526 /* Verify both namespaces are active */
527 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
528 if (ret < 0) {
529 kill(pid, SIGKILL);
530 waitpid(pid, NULL, 0);
531 if (errno == ENOSYS)
532 SKIP(return, "listns() not supported");
533 ASSERT_GE(ret, 0);
534 }
535
536 for (i = 0; i < ret; i++) {
537 if (ns_ids[i] == parent_userns_id)
538 found_parent = true;
539 if (ns_ids[i] == child_userns_id)
540 found_child = true;
541 }
542
543 ASSERT_TRUE(found_parent);
544 ASSERT_TRUE(found_child);
545
546 /* Wait for child */
547 waitpid(pid, &status, 0);
548 ASSERT_TRUE(WIFEXITED(status));
549 ASSERT_EQ(WEXITSTATUS(status), 0);
550
551 /* Verify both namespaces become inactive */
552 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
553 ASSERT_GE(ret, 0);
554
555 found_parent = false;
556 found_child = false;
557 for (i = 0; i < ret; i++) {
558 if (ns_ids[i] == parent_userns_id)
559 found_parent = true;
560 if (ns_ids[i] == child_userns_id)
561 found_child = true;
562 }
563
564 ASSERT_FALSE(found_parent);
565 ASSERT_FALSE(found_child);
566 TH_LOG("Nested user namespace credential changes preserved active refs (no leak)");
567 }
568
569 /*
570 * Test rapid credential changes don't cause refcount imbalances.
571 * This stress-tests the switch_cred_namespaces() logic.
572 */
TEST(rapid_cred_changes_no_leak)573 TEST(rapid_cred_changes_no_leak)
574 {
575 pid_t pid;
576 int status;
577 __u64 userns_id;
578 struct ns_id_req req = {
579 .size = sizeof(req),
580 .spare = 0,
581 .ns_id = 0,
582 .ns_type = CLONE_NEWUSER,
583 .spare2 = 0,
584 .user_ns_id = 0,
585 };
586 __u64 ns_ids[256];
587 ssize_t ret;
588 int i;
589 bool found = false;
590 int pipefd[2];
591
592 ASSERT_EQ(pipe(pipefd), 0);
593
594 pid = fork();
595 ASSERT_GE(pid, 0);
596
597 if (pid == 0) {
598 /* Child process */
599 int fd, userns_fd;
600 __u64 child_userns_id;
601 uid_t orig_uid = getuid();
602 int change_count;
603
604 close(pipefd[0]);
605
606 /* Create new user namespace with wider range of UIDs/GIDs */
607 userns_fd = get_userns_fd(0, orig_uid, 100);
608 if (userns_fd < 0) {
609 close(pipefd[1]);
610 exit(1);
611 }
612
613 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
614 close(userns_fd);
615 close(pipefd[1]);
616 exit(1);
617 }
618 close(userns_fd);
619
620 /* Get user namespace ID */
621 fd = open("/proc/self/ns/user", O_RDONLY);
622 if (fd < 0) {
623 close(pipefd[1]);
624 exit(1);
625 }
626
627 if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
628 close(fd);
629 close(pipefd[1]);
630 exit(1);
631 }
632 close(fd);
633
634 write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
635
636 /*
637 * Perform many rapid credential changes.
638 * Mix setuid, setgid, setreuid, setregid, setresuid, setresgid.
639 */
640 for (change_count = 0; change_count < 200; change_count++) {
641 switch (change_count % 6) {
642 case 0:
643 setuid(change_count % 50);
644 break;
645 case 1:
646 setgid(change_count % 50);
647 break;
648 case 2:
649 setreuid(change_count % 50, (change_count + 1) % 50);
650 break;
651 case 3:
652 setregid(change_count % 50, (change_count + 1) % 50);
653 break;
654 case 4:
655 setresuid(change_count % 50, (change_count + 1) % 50, (change_count + 2) % 50);
656 break;
657 case 5:
658 setresgid(change_count % 50, (change_count + 1) % 50, (change_count + 2) % 50);
659 break;
660 }
661 }
662
663 close(pipefd[1]);
664 exit(0);
665 }
666
667 /* Parent process */
668 close(pipefd[1]);
669
670 if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
671 close(pipefd[0]);
672 kill(pid, SIGKILL);
673 waitpid(pid, NULL, 0);
674 SKIP(return, "Failed to get namespace ID from child");
675 }
676 close(pipefd[0]);
677
678 TH_LOG("Testing with user namespace ID: %llu", (unsigned long long)userns_id);
679
680 waitpid(pid, &status, 0);
681 ASSERT_TRUE(WIFEXITED(status));
682 ASSERT_EQ(WEXITSTATUS(status), 0);
683
684 /* Verify namespace becomes inactive (no leaked active refs) */
685 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
686 if (ret < 0) {
687 if (errno == ENOSYS)
688 SKIP(return, "listns() not supported");
689 ASSERT_GE(ret, 0);
690 }
691
692 for (i = 0; i < ret; i++) {
693 if (ns_ids[i] == userns_id) {
694 found = true;
695 break;
696 }
697 }
698
699 ASSERT_FALSE(found);
700 TH_LOG("200 rapid credential changes completed with no active ref leak");
701 }
702
703 /*
704 * Test setfsuid/setfsgid which change filesystem UID/GID.
705 * These also trigger credential changes but may have different code paths.
706 */
TEST(setfsuid_preserves_active_refs)707 TEST(setfsuid_preserves_active_refs)
708 {
709 pid_t pid;
710 int status;
711 __u64 userns_id;
712 struct ns_id_req req = {
713 .size = sizeof(req),
714 .spare = 0,
715 .ns_id = 0,
716 .ns_type = CLONE_NEWUSER,
717 .spare2 = 0,
718 .user_ns_id = 0,
719 };
720 __u64 ns_ids[256];
721 ssize_t ret;
722 int i;
723 bool found = false;
724 int pipefd[2];
725
726 ASSERT_EQ(pipe(pipefd), 0);
727
728 pid = fork();
729 ASSERT_GE(pid, 0);
730
731 if (pid == 0) {
732 /* Child process */
733 int fd, userns_fd;
734 __u64 child_userns_id;
735 uid_t orig_uid = getuid();
736 int change_count;
737
738 close(pipefd[0]);
739
740 /* Create new user namespace */
741 userns_fd = get_userns_fd(0, orig_uid, 10);
742 if (userns_fd < 0) {
743 close(pipefd[1]);
744 exit(1);
745 }
746
747 if (setns(userns_fd, CLONE_NEWUSER) < 0) {
748 close(userns_fd);
749 close(pipefd[1]);
750 exit(1);
751 }
752 close(userns_fd);
753
754 /* Get user namespace ID */
755 fd = open("/proc/self/ns/user", O_RDONLY);
756 if (fd < 0) {
757 close(pipefd[1]);
758 exit(1);
759 }
760
761 if (ioctl(fd, NS_GET_ID, &child_userns_id) < 0) {
762 close(fd);
763 close(pipefd[1]);
764 exit(1);
765 }
766 close(fd);
767
768 write(pipefd[1], &child_userns_id, sizeof(child_userns_id));
769
770 /* Perform multiple setfsuid/setfsgid calls */
771 for (change_count = 0; change_count < 50; change_count++) {
772 setfsuid(change_count % 10);
773 setfsgid(change_count % 10);
774 }
775
776 close(pipefd[1]);
777 exit(0);
778 }
779
780 /* Parent process */
781 close(pipefd[1]);
782
783 if (read(pipefd[0], &userns_id, sizeof(userns_id)) != sizeof(userns_id)) {
784 close(pipefd[0]);
785 kill(pid, SIGKILL);
786 waitpid(pid, NULL, 0);
787 SKIP(return, "Failed to get namespace ID from child");
788 }
789 close(pipefd[0]);
790
791 waitpid(pid, &status, 0);
792 ASSERT_TRUE(WIFEXITED(status));
793 ASSERT_EQ(WEXITSTATUS(status), 0);
794
795 /* Verify namespace becomes inactive */
796 ret = sys_listns(&req, ns_ids, ARRAY_SIZE(ns_ids), 0);
797 if (ret < 0) {
798 if (errno == ENOSYS)
799 SKIP(return, "listns() not supported");
800 ASSERT_GE(ret, 0);
801 }
802
803 for (i = 0; i < ret; i++) {
804 if (ns_ids[i] == userns_id) {
805 found = true;
806 break;
807 }
808 }
809
810 ASSERT_FALSE(found);
811 TH_LOG("setfsuid/setfsgid correctly preserved active references (no leak)");
812 }
813
814 TEST_HARNESS_MAIN
815