xref: /freebsd/tests/sys/capsicum/smoketest.c (revision 670b568ec1c36464c6d55e400382c290b0391ccf)
1*670b568eSEd Maste /* Small standalone test program to check the existence of Capsicum syscalls */
2*670b568eSEd Maste #include <sys/types.h>
3*670b568eSEd Maste #include <sys/stat.h>
4*670b568eSEd Maste #include <sys/wait.h>
5*670b568eSEd Maste #include <fcntl.h>
6*670b568eSEd Maste #include <unistd.h>
7*670b568eSEd Maste #include <sys/syscall.h>
8*670b568eSEd Maste #include <stdio.h>
9*670b568eSEd Maste #include <string.h>
10*670b568eSEd Maste #include <errno.h>
11*670b568eSEd Maste #include <stdlib.h>
12*670b568eSEd Maste #include <signal.h>
13*670b568eSEd Maste 
14*670b568eSEd Maste #include "capsicum.h"
15*670b568eSEd Maste 
16*670b568eSEd Maste #ifdef __linux__
17*670b568eSEd Maste // glibc on Linux caches getpid() return value.
getpid_(void)18*670b568eSEd Maste int getpid_(void) { return syscall(__NR_getpid); }
19*670b568eSEd Maste #else
20*670b568eSEd Maste #define getpid_ getpid
21*670b568eSEd Maste #endif
22*670b568eSEd Maste 
23*670b568eSEd Maste static int seen_sigchld = 0;
handle_signal(int x)24*670b568eSEd Maste static void handle_signal(int x) {
25*670b568eSEd Maste   fprintf(stderr, "[%d] received SIGCHLD\n", getpid_());
26*670b568eSEd Maste   seen_sigchld = 1;
27*670b568eSEd Maste }
28*670b568eSEd Maste 
main(int argc,char * argv[])29*670b568eSEd Maste int main(int argc, char *argv[]) {
30*670b568eSEd Maste   signal(SIGCHLD, handle_signal);
31*670b568eSEd Maste   int lifetime = 4; /* seconds */
32*670b568eSEd Maste   if (1 < argc) {
33*670b568eSEd Maste     lifetime = atoi(argv[1]);
34*670b568eSEd Maste   }
35*670b568eSEd Maste 
36*670b568eSEd Maste   /* cap_rights_limit() available? */
37*670b568eSEd Maste   cap_rights_t r_rws;
38*670b568eSEd Maste   cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
39*670b568eSEd Maste   int cap_fd = dup(STDOUT_FILENO);
40*670b568eSEd Maste   int rc = cap_rights_limit(cap_fd, &r_rws);
41*670b568eSEd Maste   fprintf(stderr, "[%d] cap_fd=%d\n", getpid_(), cap_fd);
42*670b568eSEd Maste   if (rc < 0) fprintf(stderr, "*** cap_rights_limit() failed: errno=%d %s\n", errno, strerror(errno));
43*670b568eSEd Maste 
44*670b568eSEd Maste   /* cap_rights_get() available? */
45*670b568eSEd Maste   cap_rights_t rights;
46*670b568eSEd Maste   cap_rights_init(&rights, 0);
47*670b568eSEd Maste   rc = cap_rights_get(cap_fd, &rights);
48*670b568eSEd Maste   char buffer[256];
49*670b568eSEd Maste   cap_rights_describe(&rights, buffer);
50*670b568eSEd Maste   fprintf(stderr, "[%d] cap_rights_get(cap_fd=%d) rc=%d rights=%s\n", getpid_(), cap_fd, rc, buffer);
51*670b568eSEd Maste   if (rc < 0) fprintf(stderr, "*** cap_rights_get() failed: errno=%d %s\n", errno, strerror(errno));
52*670b568eSEd Maste 
53*670b568eSEd Maste   /* fstat() policed? */
54*670b568eSEd Maste   struct stat buf;
55*670b568eSEd Maste   rc = fstat(cap_fd, &buf);
56*670b568eSEd Maste   fprintf(stderr, "[%d] fstat(cap_fd=%d) rc=%d errno=%d\n", getpid_(), cap_fd, rc, errno);
57*670b568eSEd Maste   if (rc != -1) fprintf(stderr, "*** fstat() unexpectedly succeeded\n");
58*670b568eSEd Maste 
59*670b568eSEd Maste   /* pdfork() available? */
60*670b568eSEd Maste   int pd = -1;
61*670b568eSEd Maste   rc = pdfork(&pd, 0);
62*670b568eSEd Maste   if (rc < 0) fprintf(stderr, "*** pdfork() failed: errno=%d %s\n", errno, strerror(errno));
63*670b568eSEd Maste 
64*670b568eSEd Maste   if (rc == 0) { /* child */
65*670b568eSEd Maste     int count = 0;
66*670b568eSEd Maste     while (count < 20) {
67*670b568eSEd Maste       fprintf(stderr, "  [%d] child alive, parent is ppid=%d\n", getpid_(), getppid());
68*670b568eSEd Maste       sleep(1);
69*670b568eSEd Maste     }
70*670b568eSEd Maste     fprintf(stderr, "  [%d] child exit(0)\n", getpid_());
71*670b568eSEd Maste     exit(0);
72*670b568eSEd Maste   }
73*670b568eSEd Maste   fprintf(stderr, "[%d] pdfork() rc=%d pd=%d\n", getpid_(), rc, pd);
74*670b568eSEd Maste 
75*670b568eSEd Maste   /* pdgetpid() available? */
76*670b568eSEd Maste   pid_t actual_pid = rc;
77*670b568eSEd Maste   pid_t got_pid = -1;
78*670b568eSEd Maste   rc = pdgetpid(pd, &got_pid);
79*670b568eSEd Maste   if (rc < 0) fprintf(stderr, "*** pdgetpid(pd=%d) failed: errno=%d %s\n", pd, errno, strerror(errno));
80*670b568eSEd Maste   fprintf(stderr, "[%d] pdgetpid(pd=%d)=%d, pdfork returned %d\n", getpid_(), pd, got_pid, actual_pid);
81*670b568eSEd Maste 
82*670b568eSEd Maste   sleep(lifetime);
83*670b568eSEd Maste 
84*670b568eSEd Maste   /* pdkill() available? */
85*670b568eSEd Maste   rc = pdkill(pd, SIGKILL);
86*670b568eSEd Maste   fprintf(stderr, "[%d] pdkill(pd=%d, SIGKILL) -> rc=%d\n", getpid_(), pd, rc);
87*670b568eSEd Maste   if (rc < 0) fprintf(stderr, "*** pdkill() failed: errno=%d %s\n", errno, strerror(errno));
88*670b568eSEd Maste   usleep(50000);  /* Allow time for death and signals */
89*670b568eSEd Maste 
90*670b568eSEd Maste   /* Death of a pdforked child should be invisible */
91*670b568eSEd Maste   if (seen_sigchld) fprintf(stderr, "*** SIGCHLD emitted\n");
92*670b568eSEd Maste   int status;
93*670b568eSEd Maste   rc = wait4(-1, &status, WNOHANG, NULL);
94*670b568eSEd Maste   if (rc > 0) fprintf(stderr, "*** wait4(-1, ...) unexpectedly found child %d\n", rc);
95*670b568eSEd Maste 
96*670b568eSEd Maste   fprintf(stderr, "[%d] forking off a child process to check cap_enter()\n", getpid_());
97*670b568eSEd Maste   pid_t child = fork();
98*670b568eSEd Maste   if (child == 0) { /* child */
99*670b568eSEd Maste     /* cap_getmode() / cap_enter() available? */
100*670b568eSEd Maste     unsigned int cap_mode = -1;
101*670b568eSEd Maste     rc = cap_getmode(&cap_mode);
102*670b568eSEd Maste     fprintf(stderr, "  [%d] cap_getmode() -> rc=%d, cap_mode=%d\n", getpid_(), rc, cap_mode);
103*670b568eSEd Maste     if (rc < 0) fprintf(stderr, "*** cap_getmode() failed: errno=%d %s\n", errno, strerror(errno));
104*670b568eSEd Maste 
105*670b568eSEd Maste     rc = cap_enter();
106*670b568eSEd Maste     fprintf(stderr, "  [%d] cap_enter() -> rc=%d\n", getpid_(), rc);
107*670b568eSEd Maste     if (rc < 0) fprintf(stderr, "*** cap_enter() failed: errno=%d %s\n", errno, strerror(errno));
108*670b568eSEd Maste 
109*670b568eSEd Maste     rc = cap_getmode(&cap_mode);
110*670b568eSEd Maste     fprintf(stderr, "  [%d] cap_getmode() -> rc=%d, cap_mode=%d\n", getpid_(), rc, cap_mode);
111*670b568eSEd Maste     if (rc < 0) fprintf(stderr, "*** cap_getmode() failed: errno=%d %s\n", errno, strerror(errno));
112*670b568eSEd Maste 
113*670b568eSEd Maste     /* open disallowed? */
114*670b568eSEd Maste     rc = open("/etc/passwd", O_RDONLY);
115*670b568eSEd Maste     fprintf(stderr, "  [%d] open('/etc/passwd') -> rc=%d, errno=%d\n", getpid_(), rc, errno);
116*670b568eSEd Maste     if (rc != -1) fprintf(stderr, "*** open() unexpectedly succeeded\n");
117*670b568eSEd Maste #ifdef ECAPMODE
118*670b568eSEd Maste     if (errno != ECAPMODE) fprintf(stderr, "*** open() failed with errno %d not ECAPMODE\n", errno);
119*670b568eSEd Maste #endif
120*670b568eSEd Maste     exit(0);
121*670b568eSEd Maste   }
122*670b568eSEd Maste   rc = wait4(child, &status, 0, NULL);
123*670b568eSEd Maste   fprintf(stderr, "[%d] child %d exited with status %x\n", getpid_(), child, status);
124*670b568eSEd Maste 
125*670b568eSEd Maste   /* fexecve() available? */
126*670b568eSEd Maste   char* argv_pass[] = {(char*)"/bin/ls", "-l", "smoketest", NULL};
127*670b568eSEd Maste   char* null_envp[] = {NULL};
128*670b568eSEd Maste   int ls_bin = open("/bin/ls", O_RDONLY);
129*670b568eSEd Maste   fprintf(stderr, "[%d] about to fexecve('/bin/ls', '-l', 'smoketest')\n", getpid_());
130*670b568eSEd Maste   rc = fexecve(ls_bin, argv_pass, null_envp);
131*670b568eSEd Maste   /* should never reach here */
132*670b568eSEd Maste   fprintf(stderr, "*** fexecve(fd=%d) failed: rc=%d errno=%d %s\n", ls_bin, rc, errno, strerror(errno));
133*670b568eSEd Maste 
134*670b568eSEd Maste   return 0;
135*670b568eSEd Maste }
136