1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker * Authors: Dan Walsh <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker * Authors: Thomas Liu <[email protected]>
4*2d543d20SAndroid Build Coastguard Worker */
5*2d543d20SAndroid Build Coastguard Worker
6*2d543d20SAndroid Build Coastguard Worker #define _GNU_SOURCE
7*2d543d20SAndroid Build Coastguard Worker #include <signal.h>
8*2d543d20SAndroid Build Coastguard Worker #include <sys/fsuid.h>
9*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
10*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
11*2d543d20SAndroid Build Coastguard Worker #include <sys/wait.h>
12*2d543d20SAndroid Build Coastguard Worker #include <syslog.h>
13*2d543d20SAndroid Build Coastguard Worker #include <sys/mount.h>
14*2d543d20SAndroid Build Coastguard Worker #include <glob.h>
15*2d543d20SAndroid Build Coastguard Worker #include <pwd.h>
16*2d543d20SAndroid Build Coastguard Worker #include <sched.h>
17*2d543d20SAndroid Build Coastguard Worker #include <string.h>
18*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
19*2d543d20SAndroid Build Coastguard Worker #include <regex.h>
20*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
21*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
22*2d543d20SAndroid Build Coastguard Worker #include <cap-ng.h>
23*2d543d20SAndroid Build Coastguard Worker #include <getopt.h> /* for getopt_long() form of getopt() */
24*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
25*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
26*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
27*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
28*2d543d20SAndroid Build Coastguard Worker
29*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
30*2d543d20SAndroid Build Coastguard Worker #include <selinux/context.h> /* for context-mangling functions */
31*2d543d20SAndroid Build Coastguard Worker #include <dirent.h>
32*2d543d20SAndroid Build Coastguard Worker
33*2d543d20SAndroid Build Coastguard Worker #ifdef USE_NLS
34*2d543d20SAndroid Build Coastguard Worker #include <locale.h> /* for setlocale() */
35*2d543d20SAndroid Build Coastguard Worker #include <libintl.h> /* for gettext() */
36*2d543d20SAndroid Build Coastguard Worker #define _(msgid) gettext (msgid)
37*2d543d20SAndroid Build Coastguard Worker #else
38*2d543d20SAndroid Build Coastguard Worker #define _(msgid) (msgid)
39*2d543d20SAndroid Build Coastguard Worker #endif
40*2d543d20SAndroid Build Coastguard Worker
41*2d543d20SAndroid Build Coastguard Worker #ifndef MS_REC
42*2d543d20SAndroid Build Coastguard Worker #define MS_REC 1<<14
43*2d543d20SAndroid Build Coastguard Worker #endif
44*2d543d20SAndroid Build Coastguard Worker
45*2d543d20SAndroid Build Coastguard Worker #ifndef MS_SLAVE
46*2d543d20SAndroid Build Coastguard Worker #define MS_SLAVE 1<<19
47*2d543d20SAndroid Build Coastguard Worker #endif
48*2d543d20SAndroid Build Coastguard Worker
49*2d543d20SAndroid Build Coastguard Worker #ifndef PACKAGE
50*2d543d20SAndroid Build Coastguard Worker #define PACKAGE "policycoreutils" /* the name of this package lang translation */
51*2d543d20SAndroid Build Coastguard Worker #endif
52*2d543d20SAndroid Build Coastguard Worker
53*2d543d20SAndroid Build Coastguard Worker #define BUF_SIZE 1024
54*2d543d20SAndroid Build Coastguard Worker #define DEFAULT_PATH "/usr/bin:/bin"
55*2d543d20SAndroid Build Coastguard Worker #define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] \
56*2d543d20SAndroid Build Coastguard Worker [ -r runuserdir ] [ -P pipewiresocket ] [ -W waylandsocket ] [ -Z CONTEXT ] -- executable [args] ")
57*2d543d20SAndroid Build Coastguard Worker
58*2d543d20SAndroid Build Coastguard Worker static int verbose = 0;
59*2d543d20SAndroid Build Coastguard Worker static int child = 0;
60*2d543d20SAndroid Build Coastguard Worker
61*2d543d20SAndroid Build Coastguard Worker static capng_select_t cap_set = CAPNG_SELECT_CAPS;
62*2d543d20SAndroid Build Coastguard Worker
63*2d543d20SAndroid Build Coastguard Worker /**
64*2d543d20SAndroid Build Coastguard Worker * This function will drop all capabilities.
65*2d543d20SAndroid Build Coastguard Worker */
drop_caps(void)66*2d543d20SAndroid Build Coastguard Worker static int drop_caps(void)
67*2d543d20SAndroid Build Coastguard Worker {
68*2d543d20SAndroid Build Coastguard Worker if (capng_have_capabilities(cap_set) == CAPNG_NONE)
69*2d543d20SAndroid Build Coastguard Worker return 0;
70*2d543d20SAndroid Build Coastguard Worker capng_clear(cap_set);
71*2d543d20SAndroid Build Coastguard Worker if (capng_lock() == -1 || capng_apply(cap_set) == -1) {
72*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to drop all capabilities\n"));
73*2d543d20SAndroid Build Coastguard Worker return -1;
74*2d543d20SAndroid Build Coastguard Worker }
75*2d543d20SAndroid Build Coastguard Worker return 0;
76*2d543d20SAndroid Build Coastguard Worker }
77*2d543d20SAndroid Build Coastguard Worker
78*2d543d20SAndroid Build Coastguard Worker /**
79*2d543d20SAndroid Build Coastguard Worker * This function will drop all privileges.
80*2d543d20SAndroid Build Coastguard Worker */
drop_privs(uid_t uid)81*2d543d20SAndroid Build Coastguard Worker static int drop_privs(uid_t uid)
82*2d543d20SAndroid Build Coastguard Worker {
83*2d543d20SAndroid Build Coastguard Worker if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) {
84*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to drop privileges\n"));
85*2d543d20SAndroid Build Coastguard Worker return -1;
86*2d543d20SAndroid Build Coastguard Worker }
87*2d543d20SAndroid Build Coastguard Worker return 0;
88*2d543d20SAndroid Build Coastguard Worker }
89*2d543d20SAndroid Build Coastguard Worker
90*2d543d20SAndroid Build Coastguard Worker /**
91*2d543d20SAndroid Build Coastguard Worker * If the user sends a siginto to seunshare, kill the child's session
92*2d543d20SAndroid Build Coastguard Worker */
handler(int sig)93*2d543d20SAndroid Build Coastguard Worker static void handler(int sig) {
94*2d543d20SAndroid Build Coastguard Worker if (child > 0) kill(-child,sig);
95*2d543d20SAndroid Build Coastguard Worker }
96*2d543d20SAndroid Build Coastguard Worker
97*2d543d20SAndroid Build Coastguard Worker /**
98*2d543d20SAndroid Build Coastguard Worker * Take care of any signal setup.
99*2d543d20SAndroid Build Coastguard Worker */
set_signal_handles(void)100*2d543d20SAndroid Build Coastguard Worker static int set_signal_handles(void)
101*2d543d20SAndroid Build Coastguard Worker {
102*2d543d20SAndroid Build Coastguard Worker sigset_t empty;
103*2d543d20SAndroid Build Coastguard Worker
104*2d543d20SAndroid Build Coastguard Worker /* Empty the signal mask in case someone is blocking a signal */
105*2d543d20SAndroid Build Coastguard Worker if (sigemptyset(&empty)) {
106*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, "Unable to obtain empty signal set\n");
107*2d543d20SAndroid Build Coastguard Worker return -1;
108*2d543d20SAndroid Build Coastguard Worker }
109*2d543d20SAndroid Build Coastguard Worker
110*2d543d20SAndroid Build Coastguard Worker (void)sigprocmask(SIG_SETMASK, &empty, NULL);
111*2d543d20SAndroid Build Coastguard Worker
112*2d543d20SAndroid Build Coastguard Worker /* Terminate on SIGHUP */
113*2d543d20SAndroid Build Coastguard Worker if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
114*2d543d20SAndroid Build Coastguard Worker perror("Unable to set SIGHUP handler");
115*2d543d20SAndroid Build Coastguard Worker return -1;
116*2d543d20SAndroid Build Coastguard Worker }
117*2d543d20SAndroid Build Coastguard Worker
118*2d543d20SAndroid Build Coastguard Worker if (signal(SIGINT, handler) == SIG_ERR) {
119*2d543d20SAndroid Build Coastguard Worker perror("Unable to set SIGINT handler");
120*2d543d20SAndroid Build Coastguard Worker return -1;
121*2d543d20SAndroid Build Coastguard Worker }
122*2d543d20SAndroid Build Coastguard Worker
123*2d543d20SAndroid Build Coastguard Worker return 0;
124*2d543d20SAndroid Build Coastguard Worker }
125*2d543d20SAndroid Build Coastguard Worker
126*2d543d20SAndroid Build Coastguard Worker #define status_to_retval(status,retval) do { \
127*2d543d20SAndroid Build Coastguard Worker if ((status) == -1) \
128*2d543d20SAndroid Build Coastguard Worker retval = -1; \
129*2d543d20SAndroid Build Coastguard Worker else if (WIFEXITED((status))) \
130*2d543d20SAndroid Build Coastguard Worker retval = WEXITSTATUS((status)); \
131*2d543d20SAndroid Build Coastguard Worker else if (WIFSIGNALED((status))) \
132*2d543d20SAndroid Build Coastguard Worker retval = 128 + WTERMSIG((status)); \
133*2d543d20SAndroid Build Coastguard Worker else \
134*2d543d20SAndroid Build Coastguard Worker retval = -1; \
135*2d543d20SAndroid Build Coastguard Worker } while(0)
136*2d543d20SAndroid Build Coastguard Worker
137*2d543d20SAndroid Build Coastguard Worker /**
138*2d543d20SAndroid Build Coastguard Worker * Spawn external command using system() with dropped privileges.
139*2d543d20SAndroid Build Coastguard Worker * TODO: avoid system() and use exec*() instead
140*2d543d20SAndroid Build Coastguard Worker */
spawn_command(const char * cmd,uid_t uid)141*2d543d20SAndroid Build Coastguard Worker static int spawn_command(const char *cmd, uid_t uid){
142*2d543d20SAndroid Build Coastguard Worker int childpid;
143*2d543d20SAndroid Build Coastguard Worker int status = -1;
144*2d543d20SAndroid Build Coastguard Worker
145*2d543d20SAndroid Build Coastguard Worker if (verbose > 1)
146*2d543d20SAndroid Build Coastguard Worker printf("spawn_command: %s\n", cmd);
147*2d543d20SAndroid Build Coastguard Worker
148*2d543d20SAndroid Build Coastguard Worker childpid = fork();
149*2d543d20SAndroid Build Coastguard Worker if (childpid == -1) {
150*2d543d20SAndroid Build Coastguard Worker perror(_("Unable to fork"));
151*2d543d20SAndroid Build Coastguard Worker return status;
152*2d543d20SAndroid Build Coastguard Worker }
153*2d543d20SAndroid Build Coastguard Worker
154*2d543d20SAndroid Build Coastguard Worker if (childpid == 0) {
155*2d543d20SAndroid Build Coastguard Worker if (drop_privs(uid) != 0) exit(-1);
156*2d543d20SAndroid Build Coastguard Worker
157*2d543d20SAndroid Build Coastguard Worker status = system(cmd);
158*2d543d20SAndroid Build Coastguard Worker status_to_retval(status, status);
159*2d543d20SAndroid Build Coastguard Worker exit(status);
160*2d543d20SAndroid Build Coastguard Worker }
161*2d543d20SAndroid Build Coastguard Worker
162*2d543d20SAndroid Build Coastguard Worker waitpid(childpid, &status, 0);
163*2d543d20SAndroid Build Coastguard Worker status_to_retval(status, status);
164*2d543d20SAndroid Build Coastguard Worker return status;
165*2d543d20SAndroid Build Coastguard Worker }
166*2d543d20SAndroid Build Coastguard Worker
167*2d543d20SAndroid Build Coastguard Worker /**
168*2d543d20SAndroid Build Coastguard Worker * Check file/directory ownership, struct stat * must be passed to the
169*2d543d20SAndroid Build Coastguard Worker * functions.
170*2d543d20SAndroid Build Coastguard Worker */
check_owner_uid(uid_t uid,const char * file,struct stat * st)171*2d543d20SAndroid Build Coastguard Worker static int check_owner_uid(uid_t uid, const char *file, struct stat *st) {
172*2d543d20SAndroid Build Coastguard Worker if (S_ISLNK(st->st_mode)) {
173*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
174*2d543d20SAndroid Build Coastguard Worker return -1;
175*2d543d20SAndroid Build Coastguard Worker }
176*2d543d20SAndroid Build Coastguard Worker if (st->st_uid != uid) {
177*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid);
178*2d543d20SAndroid Build Coastguard Worker return -1;
179*2d543d20SAndroid Build Coastguard Worker }
180*2d543d20SAndroid Build Coastguard Worker return 0;
181*2d543d20SAndroid Build Coastguard Worker }
182*2d543d20SAndroid Build Coastguard Worker
check_owner_gid(gid_t gid,const char * file,struct stat * st)183*2d543d20SAndroid Build Coastguard Worker static int check_owner_gid(gid_t gid, const char *file, struct stat *st) {
184*2d543d20SAndroid Build Coastguard Worker if (S_ISLNK(st->st_mode)) {
185*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
186*2d543d20SAndroid Build Coastguard Worker return -1;
187*2d543d20SAndroid Build Coastguard Worker }
188*2d543d20SAndroid Build Coastguard Worker if (st->st_gid != gid) {
189*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid);
190*2d543d20SAndroid Build Coastguard Worker return -1;
191*2d543d20SAndroid Build Coastguard Worker }
192*2d543d20SAndroid Build Coastguard Worker return 0;
193*2d543d20SAndroid Build Coastguard Worker }
194*2d543d20SAndroid Build Coastguard Worker
195*2d543d20SAndroid Build Coastguard Worker #define equal_stats(one,two) \
196*2d543d20SAndroid Build Coastguard Worker ((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \
197*2d543d20SAndroid Build Coastguard Worker (one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \
198*2d543d20SAndroid Build Coastguard Worker (one)->st_mode == (two)->st_mode)
199*2d543d20SAndroid Build Coastguard Worker
200*2d543d20SAndroid Build Coastguard Worker /**
201*2d543d20SAndroid Build Coastguard Worker * Sanity check specified directory. Store stat info for future comparison, or
202*2d543d20SAndroid Build Coastguard Worker * compare with previously saved info to detect replaced directories.
203*2d543d20SAndroid Build Coastguard Worker * Note: This function does not perform owner checks.
204*2d543d20SAndroid Build Coastguard Worker */
verify_directory(const char * dir,struct stat * st_in,struct stat * st_out)205*2d543d20SAndroid Build Coastguard Worker static int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) {
206*2d543d20SAndroid Build Coastguard Worker struct stat sb;
207*2d543d20SAndroid Build Coastguard Worker
208*2d543d20SAndroid Build Coastguard Worker if (st_out == NULL) st_out = &sb;
209*2d543d20SAndroid Build Coastguard Worker
210*2d543d20SAndroid Build Coastguard Worker if (lstat(dir, st_out) == -1) {
211*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno));
212*2d543d20SAndroid Build Coastguard Worker return -1;
213*2d543d20SAndroid Build Coastguard Worker }
214*2d543d20SAndroid Build Coastguard Worker if (! S_ISDIR(st_out->st_mode)) {
215*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno));
216*2d543d20SAndroid Build Coastguard Worker return -1;
217*2d543d20SAndroid Build Coastguard Worker }
218*2d543d20SAndroid Build Coastguard Worker if (st_in && !equal_stats(st_in, st_out)) {
219*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir);
220*2d543d20SAndroid Build Coastguard Worker return -1;
221*2d543d20SAndroid Build Coastguard Worker }
222*2d543d20SAndroid Build Coastguard Worker
223*2d543d20SAndroid Build Coastguard Worker return 0;
224*2d543d20SAndroid Build Coastguard Worker }
225*2d543d20SAndroid Build Coastguard Worker
226*2d543d20SAndroid Build Coastguard Worker /**
227*2d543d20SAndroid Build Coastguard Worker * This function checks to see if the shell is known in /etc/shells.
228*2d543d20SAndroid Build Coastguard Worker * If so, it returns 0. On error or illegal shell, it returns -1.
229*2d543d20SAndroid Build Coastguard Worker */
verify_shell(const char * shell_name)230*2d543d20SAndroid Build Coastguard Worker static int verify_shell(const char *shell_name)
231*2d543d20SAndroid Build Coastguard Worker {
232*2d543d20SAndroid Build Coastguard Worker int rc = -1;
233*2d543d20SAndroid Build Coastguard Worker const char *buf;
234*2d543d20SAndroid Build Coastguard Worker
235*2d543d20SAndroid Build Coastguard Worker if (!(shell_name && shell_name[0]))
236*2d543d20SAndroid Build Coastguard Worker return rc;
237*2d543d20SAndroid Build Coastguard Worker
238*2d543d20SAndroid Build Coastguard Worker while ((buf = getusershell()) != NULL) {
239*2d543d20SAndroid Build Coastguard Worker /* ignore comments */
240*2d543d20SAndroid Build Coastguard Worker if (*buf == '#')
241*2d543d20SAndroid Build Coastguard Worker continue;
242*2d543d20SAndroid Build Coastguard Worker
243*2d543d20SAndroid Build Coastguard Worker /* check the shell skipping newline char */
244*2d543d20SAndroid Build Coastguard Worker if (!strcmp(shell_name, buf)) {
245*2d543d20SAndroid Build Coastguard Worker rc = 0;
246*2d543d20SAndroid Build Coastguard Worker break;
247*2d543d20SAndroid Build Coastguard Worker }
248*2d543d20SAndroid Build Coastguard Worker }
249*2d543d20SAndroid Build Coastguard Worker endusershell();
250*2d543d20SAndroid Build Coastguard Worker return rc;
251*2d543d20SAndroid Build Coastguard Worker }
252*2d543d20SAndroid Build Coastguard Worker
253*2d543d20SAndroid Build Coastguard Worker /**
254*2d543d20SAndroid Build Coastguard Worker * Mount directory and check that we mounted the right directory.
255*2d543d20SAndroid Build Coastguard Worker */
seunshare_mount(const char * src,const char * dst,struct stat * src_st)256*2d543d20SAndroid Build Coastguard Worker static int seunshare_mount(const char *src, const char *dst, struct stat *src_st)
257*2d543d20SAndroid Build Coastguard Worker {
258*2d543d20SAndroid Build Coastguard Worker int flags = 0;
259*2d543d20SAndroid Build Coastguard Worker int is_tmp = 0;
260*2d543d20SAndroid Build Coastguard Worker
261*2d543d20SAndroid Build Coastguard Worker if (verbose)
262*2d543d20SAndroid Build Coastguard Worker printf(_("Mounting %s on %s\n"), src, dst);
263*2d543d20SAndroid Build Coastguard Worker
264*2d543d20SAndroid Build Coastguard Worker if (strcmp("/tmp", dst) == 0) {
265*2d543d20SAndroid Build Coastguard Worker flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC;
266*2d543d20SAndroid Build Coastguard Worker is_tmp = 1;
267*2d543d20SAndroid Build Coastguard Worker }
268*2d543d20SAndroid Build Coastguard Worker
269*2d543d20SAndroid Build Coastguard Worker if (strncmp("/run/user", dst, 9) == 0) {
270*2d543d20SAndroid Build Coastguard Worker flags = flags | MS_REC;
271*2d543d20SAndroid Build Coastguard Worker }
272*2d543d20SAndroid Build Coastguard Worker
273*2d543d20SAndroid Build Coastguard Worker /* mount directory */
274*2d543d20SAndroid Build Coastguard Worker if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
275*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
276*2d543d20SAndroid Build Coastguard Worker return -1;
277*2d543d20SAndroid Build Coastguard Worker }
278*2d543d20SAndroid Build Coastguard Worker
279*2d543d20SAndroid Build Coastguard Worker /* verify whether we mounted what we expected to mount */
280*2d543d20SAndroid Build Coastguard Worker if (verify_directory(dst, src_st, NULL) < 0) return -1;
281*2d543d20SAndroid Build Coastguard Worker
282*2d543d20SAndroid Build Coastguard Worker /* bind mount /tmp on /var/tmp too */
283*2d543d20SAndroid Build Coastguard Worker if (is_tmp) {
284*2d543d20SAndroid Build Coastguard Worker if (verbose)
285*2d543d20SAndroid Build Coastguard Worker printf(_("Mounting /tmp on /var/tmp\n"));
286*2d543d20SAndroid Build Coastguard Worker
287*2d543d20SAndroid Build Coastguard Worker if (mount("/tmp", "/var/tmp", NULL, MS_BIND | flags, NULL) < 0) {
288*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
289*2d543d20SAndroid Build Coastguard Worker return -1;
290*2d543d20SAndroid Build Coastguard Worker }
291*2d543d20SAndroid Build Coastguard Worker }
292*2d543d20SAndroid Build Coastguard Worker
293*2d543d20SAndroid Build Coastguard Worker return 0;
294*2d543d20SAndroid Build Coastguard Worker
295*2d543d20SAndroid Build Coastguard Worker }
296*2d543d20SAndroid Build Coastguard Worker
297*2d543d20SAndroid Build Coastguard Worker /**
298*2d543d20SAndroid Build Coastguard Worker * Mount directory and check that we mounted the right directory.
299*2d543d20SAndroid Build Coastguard Worker */
seunshare_mount_file(const char * src,const char * dst)300*2d543d20SAndroid Build Coastguard Worker static int seunshare_mount_file(const char *src, const char *dst)
301*2d543d20SAndroid Build Coastguard Worker {
302*2d543d20SAndroid Build Coastguard Worker int flags = 0;
303*2d543d20SAndroid Build Coastguard Worker
304*2d543d20SAndroid Build Coastguard Worker if (verbose)
305*2d543d20SAndroid Build Coastguard Worker printf(_("Mounting %s on %s\n"), src, dst);
306*2d543d20SAndroid Build Coastguard Worker
307*2d543d20SAndroid Build Coastguard Worker if (access(dst, F_OK) == -1) {
308*2d543d20SAndroid Build Coastguard Worker FILE *fptr;
309*2d543d20SAndroid Build Coastguard Worker fptr = fopen(dst, "w");
310*2d543d20SAndroid Build Coastguard Worker fclose(fptr);
311*2d543d20SAndroid Build Coastguard Worker }
312*2d543d20SAndroid Build Coastguard Worker /* mount file */
313*2d543d20SAndroid Build Coastguard Worker if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
314*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
315*2d543d20SAndroid Build Coastguard Worker return -1;
316*2d543d20SAndroid Build Coastguard Worker }
317*2d543d20SAndroid Build Coastguard Worker
318*2d543d20SAndroid Build Coastguard Worker return 0;
319*2d543d20SAndroid Build Coastguard Worker
320*2d543d20SAndroid Build Coastguard Worker }
321*2d543d20SAndroid Build Coastguard Worker
322*2d543d20SAndroid Build Coastguard Worker /*
323*2d543d20SAndroid Build Coastguard Worker If path is empty or ends with "/." or "/.. return -1 else return 0;
324*2d543d20SAndroid Build Coastguard Worker */
bad_path(const char * path)325*2d543d20SAndroid Build Coastguard Worker static int bad_path(const char *path) {
326*2d543d20SAndroid Build Coastguard Worker const char *ptr;
327*2d543d20SAndroid Build Coastguard Worker ptr = path;
328*2d543d20SAndroid Build Coastguard Worker while (*ptr) ptr++;
329*2d543d20SAndroid Build Coastguard Worker if (ptr == path) return -1; // ptr null
330*2d543d20SAndroid Build Coastguard Worker ptr--;
331*2d543d20SAndroid Build Coastguard Worker if (ptr != path && *ptr == '.') {
332*2d543d20SAndroid Build Coastguard Worker ptr--;
333*2d543d20SAndroid Build Coastguard Worker if (*ptr == '/') return -1; // path ends in /.
334*2d543d20SAndroid Build Coastguard Worker if (*ptr == '.') {
335*2d543d20SAndroid Build Coastguard Worker if (ptr != path) {
336*2d543d20SAndroid Build Coastguard Worker ptr--;
337*2d543d20SAndroid Build Coastguard Worker if (*ptr == '/') return -1; // path ends in /..
338*2d543d20SAndroid Build Coastguard Worker }
339*2d543d20SAndroid Build Coastguard Worker }
340*2d543d20SAndroid Build Coastguard Worker }
341*2d543d20SAndroid Build Coastguard Worker return 0;
342*2d543d20SAndroid Build Coastguard Worker }
343*2d543d20SAndroid Build Coastguard Worker
rsynccmd(const char * src,const char * dst,char ** cmdbuf)344*2d543d20SAndroid Build Coastguard Worker static int rsynccmd(const char * src, const char *dst, char **cmdbuf)
345*2d543d20SAndroid Build Coastguard Worker {
346*2d543d20SAndroid Build Coastguard Worker char *buf = NULL;
347*2d543d20SAndroid Build Coastguard Worker char *newbuf = NULL;
348*2d543d20SAndroid Build Coastguard Worker glob_t fglob;
349*2d543d20SAndroid Build Coastguard Worker fglob.gl_offs = 0;
350*2d543d20SAndroid Build Coastguard Worker int flags = GLOB_PERIOD;
351*2d543d20SAndroid Build Coastguard Worker unsigned int i = 0;
352*2d543d20SAndroid Build Coastguard Worker int rc = -1;
353*2d543d20SAndroid Build Coastguard Worker
354*2d543d20SAndroid Build Coastguard Worker /* match glob for all files in src dir */
355*2d543d20SAndroid Build Coastguard Worker if (asprintf(&buf, "%s/*", src) == -1) {
356*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, "Out of memory\n");
357*2d543d20SAndroid Build Coastguard Worker return -1;
358*2d543d20SAndroid Build Coastguard Worker }
359*2d543d20SAndroid Build Coastguard Worker
360*2d543d20SAndroid Build Coastguard Worker if (glob(buf, flags, NULL, &fglob) != 0) {
361*2d543d20SAndroid Build Coastguard Worker free(buf); buf = NULL;
362*2d543d20SAndroid Build Coastguard Worker return -1;
363*2d543d20SAndroid Build Coastguard Worker }
364*2d543d20SAndroid Build Coastguard Worker
365*2d543d20SAndroid Build Coastguard Worker free(buf); buf = NULL;
366*2d543d20SAndroid Build Coastguard Worker
367*2d543d20SAndroid Build Coastguard Worker for ( i=0; i < fglob.gl_pathc; i++) {
368*2d543d20SAndroid Build Coastguard Worker const char *path = fglob.gl_pathv[i];
369*2d543d20SAndroid Build Coastguard Worker
370*2d543d20SAndroid Build Coastguard Worker if (bad_path(path)) continue;
371*2d543d20SAndroid Build Coastguard Worker
372*2d543d20SAndroid Build Coastguard Worker if (!buf) {
373*2d543d20SAndroid Build Coastguard Worker if (asprintf(&newbuf, "\'%s\'", path) == -1) {
374*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, "Out of memory\n");
375*2d543d20SAndroid Build Coastguard Worker goto err;
376*2d543d20SAndroid Build Coastguard Worker }
377*2d543d20SAndroid Build Coastguard Worker } else {
378*2d543d20SAndroid Build Coastguard Worker if (asprintf(&newbuf, "%s \'%s\'", buf, path) == -1) {
379*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, "Out of memory\n");
380*2d543d20SAndroid Build Coastguard Worker goto err;
381*2d543d20SAndroid Build Coastguard Worker }
382*2d543d20SAndroid Build Coastguard Worker }
383*2d543d20SAndroid Build Coastguard Worker
384*2d543d20SAndroid Build Coastguard Worker free(buf); buf = newbuf;
385*2d543d20SAndroid Build Coastguard Worker newbuf = NULL;
386*2d543d20SAndroid Build Coastguard Worker }
387*2d543d20SAndroid Build Coastguard Worker
388*2d543d20SAndroid Build Coastguard Worker if (buf) {
389*2d543d20SAndroid Build Coastguard Worker if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) {
390*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, "Out of memory\n");
391*2d543d20SAndroid Build Coastguard Worker goto err;
392*2d543d20SAndroid Build Coastguard Worker }
393*2d543d20SAndroid Build Coastguard Worker *cmdbuf=newbuf;
394*2d543d20SAndroid Build Coastguard Worker }
395*2d543d20SAndroid Build Coastguard Worker else {
396*2d543d20SAndroid Build Coastguard Worker *cmdbuf=NULL;
397*2d543d20SAndroid Build Coastguard Worker }
398*2d543d20SAndroid Build Coastguard Worker rc = 0;
399*2d543d20SAndroid Build Coastguard Worker
400*2d543d20SAndroid Build Coastguard Worker err:
401*2d543d20SAndroid Build Coastguard Worker free(buf); buf = NULL;
402*2d543d20SAndroid Build Coastguard Worker globfree(&fglob);
403*2d543d20SAndroid Build Coastguard Worker return rc;
404*2d543d20SAndroid Build Coastguard Worker }
405*2d543d20SAndroid Build Coastguard Worker
406*2d543d20SAndroid Build Coastguard Worker /**
407*2d543d20SAndroid Build Coastguard Worker * Clean up runtime temporary directory. Returns 0 if no problem was detected,
408*2d543d20SAndroid Build Coastguard Worker * >0 if some error was detected, but errors here are treated as non-fatal and
409*2d543d20SAndroid Build Coastguard Worker * left to tmpwatch to finish incomplete cleanup.
410*2d543d20SAndroid Build Coastguard Worker */
cleanup_tmpdir(const char * tmpdir,const char * src,struct passwd * pwd,int copy_content)411*2d543d20SAndroid Build Coastguard Worker static int cleanup_tmpdir(const char *tmpdir, const char *src,
412*2d543d20SAndroid Build Coastguard Worker struct passwd *pwd, int copy_content)
413*2d543d20SAndroid Build Coastguard Worker {
414*2d543d20SAndroid Build Coastguard Worker char *cmdbuf = NULL;
415*2d543d20SAndroid Build Coastguard Worker int rc = 0;
416*2d543d20SAndroid Build Coastguard Worker
417*2d543d20SAndroid Build Coastguard Worker /* rsync files back */
418*2d543d20SAndroid Build Coastguard Worker if (copy_content) {
419*2d543d20SAndroid Build Coastguard Worker if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) {
420*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Out of memory\n"));
421*2d543d20SAndroid Build Coastguard Worker cmdbuf = NULL;
422*2d543d20SAndroid Build Coastguard Worker rc++;
423*2d543d20SAndroid Build Coastguard Worker }
424*2d543d20SAndroid Build Coastguard Worker if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
425*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n"));
426*2d543d20SAndroid Build Coastguard Worker rc++;
427*2d543d20SAndroid Build Coastguard Worker }
428*2d543d20SAndroid Build Coastguard Worker free(cmdbuf); cmdbuf = NULL;
429*2d543d20SAndroid Build Coastguard Worker }
430*2d543d20SAndroid Build Coastguard Worker
431*2d543d20SAndroid Build Coastguard Worker /* remove files from the runtime temporary directory */
432*2d543d20SAndroid Build Coastguard Worker if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) {
433*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Out of memory\n"));
434*2d543d20SAndroid Build Coastguard Worker cmdbuf = NULL;
435*2d543d20SAndroid Build Coastguard Worker rc++;
436*2d543d20SAndroid Build Coastguard Worker }
437*2d543d20SAndroid Build Coastguard Worker /* this may fail if there's root-owned file left in the runtime tmpdir */
438*2d543d20SAndroid Build Coastguard Worker if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++;
439*2d543d20SAndroid Build Coastguard Worker free(cmdbuf); cmdbuf = NULL;
440*2d543d20SAndroid Build Coastguard Worker
441*2d543d20SAndroid Build Coastguard Worker /* remove runtime temporary directory */
442*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(0) != 0) {
443*2d543d20SAndroid Build Coastguard Worker /* setfsuid does not return error, but this check makes code checkers happy */
444*2d543d20SAndroid Build Coastguard Worker rc++;
445*2d543d20SAndroid Build Coastguard Worker }
446*2d543d20SAndroid Build Coastguard Worker
447*2d543d20SAndroid Build Coastguard Worker if (pwd->pw_uid != 0 && rmdir(tmpdir) == -1)
448*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno));
449*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(pwd->pw_uid) != 0) {
450*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("unable to switch back to user after clearing tmp dir\n"));
451*2d543d20SAndroid Build Coastguard Worker rc++;
452*2d543d20SAndroid Build Coastguard Worker }
453*2d543d20SAndroid Build Coastguard Worker
454*2d543d20SAndroid Build Coastguard Worker return rc;
455*2d543d20SAndroid Build Coastguard Worker }
456*2d543d20SAndroid Build Coastguard Worker
457*2d543d20SAndroid Build Coastguard Worker /**
458*2d543d20SAndroid Build Coastguard Worker * seunshare will create a tmpdir in /tmp, with root ownership. The parent
459*2d543d20SAndroid Build Coastguard Worker * process waits for it child to exit to attempt to remove the directory. If
460*2d543d20SAndroid Build Coastguard Worker * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch
461*2d543d20SAndroid Build Coastguard Worker * to clean it up.
462*2d543d20SAndroid Build Coastguard Worker */
create_tmpdir(const char * src,struct stat * src_st,struct stat * out_st,struct passwd * pwd,const char * execcon)463*2d543d20SAndroid Build Coastguard Worker static char *create_tmpdir(const char *src, struct stat *src_st,
464*2d543d20SAndroid Build Coastguard Worker struct stat *out_st, struct passwd *pwd, const char *execcon)
465*2d543d20SAndroid Build Coastguard Worker {
466*2d543d20SAndroid Build Coastguard Worker char *tmpdir = NULL;
467*2d543d20SAndroid Build Coastguard Worker char *cmdbuf = NULL;
468*2d543d20SAndroid Build Coastguard Worker int fd_t = -1, fd_s = -1;
469*2d543d20SAndroid Build Coastguard Worker struct stat tmp_st;
470*2d543d20SAndroid Build Coastguard Worker char *con = NULL;
471*2d543d20SAndroid Build Coastguard Worker
472*2d543d20SAndroid Build Coastguard Worker /* get selinux context */
473*2d543d20SAndroid Build Coastguard Worker if (execcon) {
474*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(pwd->pw_uid) != 0)
475*2d543d20SAndroid Build Coastguard Worker goto err;
476*2d543d20SAndroid Build Coastguard Worker
477*2d543d20SAndroid Build Coastguard Worker if ((fd_s = open(src, O_RDONLY)) < 0) {
478*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno));
479*2d543d20SAndroid Build Coastguard Worker goto err;
480*2d543d20SAndroid Build Coastguard Worker }
481*2d543d20SAndroid Build Coastguard Worker if (fstat(fd_s, &tmp_st) == -1) {
482*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno));
483*2d543d20SAndroid Build Coastguard Worker goto err;
484*2d543d20SAndroid Build Coastguard Worker }
485*2d543d20SAndroid Build Coastguard Worker if (!equal_stats(src_st, &tmp_st)) {
486*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src);
487*2d543d20SAndroid Build Coastguard Worker goto err;
488*2d543d20SAndroid Build Coastguard Worker }
489*2d543d20SAndroid Build Coastguard Worker if (fgetfilecon(fd_s, &con) == -1) {
490*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno));
491*2d543d20SAndroid Build Coastguard Worker goto err;
492*2d543d20SAndroid Build Coastguard Worker }
493*2d543d20SAndroid Build Coastguard Worker
494*2d543d20SAndroid Build Coastguard Worker /* ok to not reach this if there is an error */
495*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(0) != pwd->pw_uid)
496*2d543d20SAndroid Build Coastguard Worker goto err;
497*2d543d20SAndroid Build Coastguard Worker }
498*2d543d20SAndroid Build Coastguard Worker
499*2d543d20SAndroid Build Coastguard Worker if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) {
500*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Out of memory\n"));
501*2d543d20SAndroid Build Coastguard Worker tmpdir = NULL;
502*2d543d20SAndroid Build Coastguard Worker goto err;
503*2d543d20SAndroid Build Coastguard Worker }
504*2d543d20SAndroid Build Coastguard Worker if (mkdtemp(tmpdir) == NULL) {
505*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno));
506*2d543d20SAndroid Build Coastguard Worker goto err;
507*2d543d20SAndroid Build Coastguard Worker }
508*2d543d20SAndroid Build Coastguard Worker
509*2d543d20SAndroid Build Coastguard Worker /* temporary directory must be owned by root:user */
510*2d543d20SAndroid Build Coastguard Worker if (verify_directory(tmpdir, NULL, out_st) < 0) {
511*2d543d20SAndroid Build Coastguard Worker goto err;
512*2d543d20SAndroid Build Coastguard Worker }
513*2d543d20SAndroid Build Coastguard Worker
514*2d543d20SAndroid Build Coastguard Worker if (check_owner_uid(0, tmpdir, out_st) < 0)
515*2d543d20SAndroid Build Coastguard Worker goto err;
516*2d543d20SAndroid Build Coastguard Worker
517*2d543d20SAndroid Build Coastguard Worker if (check_owner_gid(getgid(), tmpdir, out_st) < 0)
518*2d543d20SAndroid Build Coastguard Worker goto err;
519*2d543d20SAndroid Build Coastguard Worker
520*2d543d20SAndroid Build Coastguard Worker /* change permissions of the temporary directory */
521*2d543d20SAndroid Build Coastguard Worker if ((fd_t = open(tmpdir, O_RDONLY)) < 0) {
522*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno));
523*2d543d20SAndroid Build Coastguard Worker goto err;
524*2d543d20SAndroid Build Coastguard Worker }
525*2d543d20SAndroid Build Coastguard Worker if (fstat(fd_t, &tmp_st) == -1) {
526*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
527*2d543d20SAndroid Build Coastguard Worker goto err;
528*2d543d20SAndroid Build Coastguard Worker }
529*2d543d20SAndroid Build Coastguard Worker if (!equal_stats(out_st, &tmp_st)) {
530*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir);
531*2d543d20SAndroid Build Coastguard Worker goto err;
532*2d543d20SAndroid Build Coastguard Worker }
533*2d543d20SAndroid Build Coastguard Worker if (fchmod(fd_t, 01770) == -1) {
534*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno));
535*2d543d20SAndroid Build Coastguard Worker goto err;
536*2d543d20SAndroid Build Coastguard Worker }
537*2d543d20SAndroid Build Coastguard Worker /* re-stat again to pick change mode */
538*2d543d20SAndroid Build Coastguard Worker if (fstat(fd_t, out_st) == -1) {
539*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
540*2d543d20SAndroid Build Coastguard Worker goto err;
541*2d543d20SAndroid Build Coastguard Worker }
542*2d543d20SAndroid Build Coastguard Worker
543*2d543d20SAndroid Build Coastguard Worker /* copy selinux context */
544*2d543d20SAndroid Build Coastguard Worker if (execcon) {
545*2d543d20SAndroid Build Coastguard Worker if (fsetfilecon(fd_t, con) == -1) {
546*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno));
547*2d543d20SAndroid Build Coastguard Worker goto err;
548*2d543d20SAndroid Build Coastguard Worker }
549*2d543d20SAndroid Build Coastguard Worker }
550*2d543d20SAndroid Build Coastguard Worker
551*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(pwd->pw_uid) != 0)
552*2d543d20SAndroid Build Coastguard Worker goto err;
553*2d543d20SAndroid Build Coastguard Worker
554*2d543d20SAndroid Build Coastguard Worker if (rsynccmd(src, tmpdir, &cmdbuf) < 0) {
555*2d543d20SAndroid Build Coastguard Worker goto err;
556*2d543d20SAndroid Build Coastguard Worker }
557*2d543d20SAndroid Build Coastguard Worker
558*2d543d20SAndroid Build Coastguard Worker /* ok to not reach this if there is an error */
559*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(0) != pwd->pw_uid)
560*2d543d20SAndroid Build Coastguard Worker goto err;
561*2d543d20SAndroid Build Coastguard Worker
562*2d543d20SAndroid Build Coastguard Worker if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
563*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to populate runtime temporary directory\n"));
564*2d543d20SAndroid Build Coastguard Worker cleanup_tmpdir(tmpdir, src, pwd, 0);
565*2d543d20SAndroid Build Coastguard Worker goto err;
566*2d543d20SAndroid Build Coastguard Worker }
567*2d543d20SAndroid Build Coastguard Worker
568*2d543d20SAndroid Build Coastguard Worker goto good;
569*2d543d20SAndroid Build Coastguard Worker err:
570*2d543d20SAndroid Build Coastguard Worker free(tmpdir); tmpdir = NULL;
571*2d543d20SAndroid Build Coastguard Worker good:
572*2d543d20SAndroid Build Coastguard Worker free(cmdbuf); cmdbuf = NULL;
573*2d543d20SAndroid Build Coastguard Worker freecon(con); con = NULL;
574*2d543d20SAndroid Build Coastguard Worker if (fd_t >= 0) close(fd_t);
575*2d543d20SAndroid Build Coastguard Worker if (fd_s >= 0) close(fd_s);
576*2d543d20SAndroid Build Coastguard Worker return tmpdir;
577*2d543d20SAndroid Build Coastguard Worker }
578*2d543d20SAndroid Build Coastguard Worker
579*2d543d20SAndroid Build Coastguard Worker #define PROC_BASE "/proc"
580*2d543d20SAndroid Build Coastguard Worker
581*2d543d20SAndroid Build Coastguard Worker static int
killall(const char * execcon)582*2d543d20SAndroid Build Coastguard Worker killall (const char *execcon)
583*2d543d20SAndroid Build Coastguard Worker {
584*2d543d20SAndroid Build Coastguard Worker DIR *dir;
585*2d543d20SAndroid Build Coastguard Worker char *scon;
586*2d543d20SAndroid Build Coastguard Worker struct dirent *de;
587*2d543d20SAndroid Build Coastguard Worker pid_t *pid_table, pid, self;
588*2d543d20SAndroid Build Coastguard Worker int i;
589*2d543d20SAndroid Build Coastguard Worker int pids, max_pids;
590*2d543d20SAndroid Build Coastguard Worker int running = 0;
591*2d543d20SAndroid Build Coastguard Worker self = getpid();
592*2d543d20SAndroid Build Coastguard Worker if (!(dir = opendir(PROC_BASE))) {
593*2d543d20SAndroid Build Coastguard Worker return -1;
594*2d543d20SAndroid Build Coastguard Worker }
595*2d543d20SAndroid Build Coastguard Worker max_pids = 256;
596*2d543d20SAndroid Build Coastguard Worker pid_table = malloc(max_pids * sizeof (pid_t));
597*2d543d20SAndroid Build Coastguard Worker if (!pid_table) {
598*2d543d20SAndroid Build Coastguard Worker (void)closedir(dir);
599*2d543d20SAndroid Build Coastguard Worker return -1;
600*2d543d20SAndroid Build Coastguard Worker }
601*2d543d20SAndroid Build Coastguard Worker pids = 0;
602*2d543d20SAndroid Build Coastguard Worker context_t con;
603*2d543d20SAndroid Build Coastguard Worker con = context_new(execcon);
604*2d543d20SAndroid Build Coastguard Worker const char *mcs = context_range_get(con);
605*2d543d20SAndroid Build Coastguard Worker printf("mcs=%s\n", mcs);
606*2d543d20SAndroid Build Coastguard Worker while ((de = readdir (dir)) != NULL) {
607*2d543d20SAndroid Build Coastguard Worker if (!(pid = (pid_t)atoi(de->d_name)) || pid == self)
608*2d543d20SAndroid Build Coastguard Worker continue;
609*2d543d20SAndroid Build Coastguard Worker
610*2d543d20SAndroid Build Coastguard Worker if (pids == max_pids) {
611*2d543d20SAndroid Build Coastguard Worker pid_t *new_pid_table = realloc(pid_table, 2*pids*sizeof(pid_t));
612*2d543d20SAndroid Build Coastguard Worker if (!new_pid_table) {
613*2d543d20SAndroid Build Coastguard Worker free(pid_table);
614*2d543d20SAndroid Build Coastguard Worker (void)closedir(dir);
615*2d543d20SAndroid Build Coastguard Worker return -1;
616*2d543d20SAndroid Build Coastguard Worker }
617*2d543d20SAndroid Build Coastguard Worker pid_table = new_pid_table;
618*2d543d20SAndroid Build Coastguard Worker max_pids *= 2;
619*2d543d20SAndroid Build Coastguard Worker }
620*2d543d20SAndroid Build Coastguard Worker pid_table[pids++] = pid;
621*2d543d20SAndroid Build Coastguard Worker }
622*2d543d20SAndroid Build Coastguard Worker
623*2d543d20SAndroid Build Coastguard Worker (void)closedir(dir);
624*2d543d20SAndroid Build Coastguard Worker
625*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < pids; i++) {
626*2d543d20SAndroid Build Coastguard Worker pid_t id = pid_table[i];
627*2d543d20SAndroid Build Coastguard Worker
628*2d543d20SAndroid Build Coastguard Worker if (getpidcon(id, &scon) == 0) {
629*2d543d20SAndroid Build Coastguard Worker
630*2d543d20SAndroid Build Coastguard Worker context_t pidcon = context_new(scon);
631*2d543d20SAndroid Build Coastguard Worker /* Attempt to kill remaining processes */
632*2d543d20SAndroid Build Coastguard Worker if (strcmp(context_range_get(pidcon), mcs) == 0)
633*2d543d20SAndroid Build Coastguard Worker kill(id, SIGKILL);
634*2d543d20SAndroid Build Coastguard Worker
635*2d543d20SAndroid Build Coastguard Worker context_free(pidcon);
636*2d543d20SAndroid Build Coastguard Worker freecon(scon);
637*2d543d20SAndroid Build Coastguard Worker }
638*2d543d20SAndroid Build Coastguard Worker running++;
639*2d543d20SAndroid Build Coastguard Worker }
640*2d543d20SAndroid Build Coastguard Worker
641*2d543d20SAndroid Build Coastguard Worker context_free(con);
642*2d543d20SAndroid Build Coastguard Worker free(pid_table);
643*2d543d20SAndroid Build Coastguard Worker return running;
644*2d543d20SAndroid Build Coastguard Worker }
645*2d543d20SAndroid Build Coastguard Worker
main(int argc,char ** argv)646*2d543d20SAndroid Build Coastguard Worker int main(int argc, char **argv) {
647*2d543d20SAndroid Build Coastguard Worker int status = -1;
648*2d543d20SAndroid Build Coastguard Worker const char *execcon = NULL;
649*2d543d20SAndroid Build Coastguard Worker const char *pipewire_socket = NULL;
650*2d543d20SAndroid Build Coastguard Worker const char *wayland_display = NULL;
651*2d543d20SAndroid Build Coastguard Worker
652*2d543d20SAndroid Build Coastguard Worker int clflag; /* holds codes for command line flags */
653*2d543d20SAndroid Build Coastguard Worker int kill_all = 0;
654*2d543d20SAndroid Build Coastguard Worker
655*2d543d20SAndroid Build Coastguard Worker char *homedir_s = NULL; /* homedir spec'd by user in argv[] */
656*2d543d20SAndroid Build Coastguard Worker char *tmpdir_s = NULL; /* tmpdir spec'd by user in argv[] */
657*2d543d20SAndroid Build Coastguard Worker char *tmpdir_r = NULL; /* tmpdir created by seunshare */
658*2d543d20SAndroid Build Coastguard Worker char *runuserdir_s = NULL; /* /var/run/user/UID spec'd by user in argv[] */
659*2d543d20SAndroid Build Coastguard Worker char *runuserdir_r = NULL; /* /var/run/user/UID created by seunshare */
660*2d543d20SAndroid Build Coastguard Worker
661*2d543d20SAndroid Build Coastguard Worker struct stat st_curhomedir;
662*2d543d20SAndroid Build Coastguard Worker struct stat st_homedir;
663*2d543d20SAndroid Build Coastguard Worker struct stat st_tmpdir_s;
664*2d543d20SAndroid Build Coastguard Worker struct stat st_tmpdir_r;
665*2d543d20SAndroid Build Coastguard Worker struct stat st_runuserdir_s;
666*2d543d20SAndroid Build Coastguard Worker struct stat st_runuserdir_r;
667*2d543d20SAndroid Build Coastguard Worker
668*2d543d20SAndroid Build Coastguard Worker const struct option long_options[] = {
669*2d543d20SAndroid Build Coastguard Worker {"homedir", 1, 0, 'h'},
670*2d543d20SAndroid Build Coastguard Worker {"tmpdir", 1, 0, 't'},
671*2d543d20SAndroid Build Coastguard Worker {"runuserdir", 1, 0, 'r'},
672*2d543d20SAndroid Build Coastguard Worker {"kill", 1, 0, 'k'},
673*2d543d20SAndroid Build Coastguard Worker {"verbose", 1, 0, 'v'},
674*2d543d20SAndroid Build Coastguard Worker {"context", 1, 0, 'Z'},
675*2d543d20SAndroid Build Coastguard Worker {"capabilities", 1, 0, 'C'},
676*2d543d20SAndroid Build Coastguard Worker {"wayland", 1, 0, 'W'},
677*2d543d20SAndroid Build Coastguard Worker {"pipewire", 1, 0, 'P'},
678*2d543d20SAndroid Build Coastguard Worker {NULL, 0, 0, 0}
679*2d543d20SAndroid Build Coastguard Worker };
680*2d543d20SAndroid Build Coastguard Worker
681*2d543d20SAndroid Build Coastguard Worker uid_t uid = getuid();
682*2d543d20SAndroid Build Coastguard Worker /*
683*2d543d20SAndroid Build Coastguard Worker if (!uid) {
684*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Must not be root"));
685*2d543d20SAndroid Build Coastguard Worker return -1;
686*2d543d20SAndroid Build Coastguard Worker }
687*2d543d20SAndroid Build Coastguard Worker */
688*2d543d20SAndroid Build Coastguard Worker
689*2d543d20SAndroid Build Coastguard Worker #ifdef USE_NLS
690*2d543d20SAndroid Build Coastguard Worker setlocale(LC_ALL, "");
691*2d543d20SAndroid Build Coastguard Worker bindtextdomain(PACKAGE, LOCALEDIR);
692*2d543d20SAndroid Build Coastguard Worker textdomain(PACKAGE);
693*2d543d20SAndroid Build Coastguard Worker #endif
694*2d543d20SAndroid Build Coastguard Worker
695*2d543d20SAndroid Build Coastguard Worker struct passwd *pwd=getpwuid(uid);
696*2d543d20SAndroid Build Coastguard Worker if (!pwd) {
697*2d543d20SAndroid Build Coastguard Worker perror(_("getpwduid failed"));
698*2d543d20SAndroid Build Coastguard Worker return -1;
699*2d543d20SAndroid Build Coastguard Worker }
700*2d543d20SAndroid Build Coastguard Worker
701*2d543d20SAndroid Build Coastguard Worker if (verify_shell(pwd->pw_shell) < 0) {
702*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: User shell is not valid\n"));
703*2d543d20SAndroid Build Coastguard Worker return -1;
704*2d543d20SAndroid Build Coastguard Worker }
705*2d543d20SAndroid Build Coastguard Worker
706*2d543d20SAndroid Build Coastguard Worker while (1) {
707*2d543d20SAndroid Build Coastguard Worker clflag = getopt_long(argc, argv, "Ccvh:r:t:W:Z:", long_options, NULL);
708*2d543d20SAndroid Build Coastguard Worker if (clflag == -1)
709*2d543d20SAndroid Build Coastguard Worker break;
710*2d543d20SAndroid Build Coastguard Worker
711*2d543d20SAndroid Build Coastguard Worker switch (clflag) {
712*2d543d20SAndroid Build Coastguard Worker case 't':
713*2d543d20SAndroid Build Coastguard Worker tmpdir_s = optarg;
714*2d543d20SAndroid Build Coastguard Worker break;
715*2d543d20SAndroid Build Coastguard Worker case 'k':
716*2d543d20SAndroid Build Coastguard Worker kill_all = 1;
717*2d543d20SAndroid Build Coastguard Worker break;
718*2d543d20SAndroid Build Coastguard Worker case 'h':
719*2d543d20SAndroid Build Coastguard Worker homedir_s = optarg;
720*2d543d20SAndroid Build Coastguard Worker break;
721*2d543d20SAndroid Build Coastguard Worker case 'r':
722*2d543d20SAndroid Build Coastguard Worker runuserdir_s = optarg;
723*2d543d20SAndroid Build Coastguard Worker break;
724*2d543d20SAndroid Build Coastguard Worker case 'v':
725*2d543d20SAndroid Build Coastguard Worker verbose++;
726*2d543d20SAndroid Build Coastguard Worker break;
727*2d543d20SAndroid Build Coastguard Worker case 'C':
728*2d543d20SAndroid Build Coastguard Worker cap_set = CAPNG_SELECT_CAPS;
729*2d543d20SAndroid Build Coastguard Worker break;
730*2d543d20SAndroid Build Coastguard Worker case 'P':
731*2d543d20SAndroid Build Coastguard Worker pipewire_socket = optarg;
732*2d543d20SAndroid Build Coastguard Worker break;
733*2d543d20SAndroid Build Coastguard Worker case 'W':
734*2d543d20SAndroid Build Coastguard Worker wayland_display = optarg;
735*2d543d20SAndroid Build Coastguard Worker break;
736*2d543d20SAndroid Build Coastguard Worker case 'Z':
737*2d543d20SAndroid Build Coastguard Worker execcon = optarg;
738*2d543d20SAndroid Build Coastguard Worker break;
739*2d543d20SAndroid Build Coastguard Worker default:
740*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, "%s\n", USAGE_STRING);
741*2d543d20SAndroid Build Coastguard Worker return -1;
742*2d543d20SAndroid Build Coastguard Worker }
743*2d543d20SAndroid Build Coastguard Worker }
744*2d543d20SAndroid Build Coastguard Worker
745*2d543d20SAndroid Build Coastguard Worker if (! homedir_s && ! tmpdir_s) {
746*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING);
747*2d543d20SAndroid Build Coastguard Worker return -1;
748*2d543d20SAndroid Build Coastguard Worker }
749*2d543d20SAndroid Build Coastguard Worker
750*2d543d20SAndroid Build Coastguard Worker if (argc - optind < 1) {
751*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
752*2d543d20SAndroid Build Coastguard Worker return -1;
753*2d543d20SAndroid Build Coastguard Worker }
754*2d543d20SAndroid Build Coastguard Worker
755*2d543d20SAndroid Build Coastguard Worker if (execcon && is_selinux_enabled() != 1) {
756*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n"));
757*2d543d20SAndroid Build Coastguard Worker return -1;
758*2d543d20SAndroid Build Coastguard Worker }
759*2d543d20SAndroid Build Coastguard Worker
760*2d543d20SAndroid Build Coastguard Worker if (set_signal_handles())
761*2d543d20SAndroid Build Coastguard Worker return -1;
762*2d543d20SAndroid Build Coastguard Worker
763*2d543d20SAndroid Build Coastguard Worker /* set fsuid to ruid */
764*2d543d20SAndroid Build Coastguard Worker /* Changing fsuid is usually required when user-specified directory is
765*2d543d20SAndroid Build Coastguard Worker * on an NFS mount. It's also desired to avoid leaking info about
766*2d543d20SAndroid Build Coastguard Worker * existence of the files not accessible to the user. */
767*2d543d20SAndroid Build Coastguard Worker if (((uid_t)setfsuid(uid) != 0) && (errno != 0)) {
768*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Error: unable to setfsuid %m\n"));
769*2d543d20SAndroid Build Coastguard Worker
770*2d543d20SAndroid Build Coastguard Worker return -1;
771*2d543d20SAndroid Build Coastguard Worker }
772*2d543d20SAndroid Build Coastguard Worker
773*2d543d20SAndroid Build Coastguard Worker /* verify homedir and tmpdir */
774*2d543d20SAndroid Build Coastguard Worker if (homedir_s && (
775*2d543d20SAndroid Build Coastguard Worker verify_directory(homedir_s, NULL, &st_homedir) < 0 ||
776*2d543d20SAndroid Build Coastguard Worker check_owner_uid(uid, homedir_s, &st_homedir))) return -1;
777*2d543d20SAndroid Build Coastguard Worker if (tmpdir_s && (
778*2d543d20SAndroid Build Coastguard Worker verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
779*2d543d20SAndroid Build Coastguard Worker check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
780*2d543d20SAndroid Build Coastguard Worker if (runuserdir_s && (
781*2d543d20SAndroid Build Coastguard Worker verify_directory(runuserdir_s, NULL, &st_runuserdir_s) < 0 ||
782*2d543d20SAndroid Build Coastguard Worker check_owner_uid(uid, runuserdir_s, &st_runuserdir_s))) return -1;
783*2d543d20SAndroid Build Coastguard Worker
784*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(0) != uid) return -1;
785*2d543d20SAndroid Build Coastguard Worker
786*2d543d20SAndroid Build Coastguard Worker /* create runtime tmpdir */
787*2d543d20SAndroid Build Coastguard Worker if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s,
788*2d543d20SAndroid Build Coastguard Worker &st_tmpdir_r, pwd, execcon)) == NULL) {
789*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to create runtime temporary directory\n"));
790*2d543d20SAndroid Build Coastguard Worker return -1;
791*2d543d20SAndroid Build Coastguard Worker }
792*2d543d20SAndroid Build Coastguard Worker /* create runtime runuserdir */
793*2d543d20SAndroid Build Coastguard Worker if (runuserdir_s && (runuserdir_r = create_tmpdir(runuserdir_s, &st_runuserdir_s,
794*2d543d20SAndroid Build Coastguard Worker &st_runuserdir_r, pwd, execcon)) == NULL) {
795*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to create runtime $XDG_RUNTIME_DIR directory\n"));
796*2d543d20SAndroid Build Coastguard Worker return -1;
797*2d543d20SAndroid Build Coastguard Worker }
798*2d543d20SAndroid Build Coastguard Worker
799*2d543d20SAndroid Build Coastguard Worker /* spawn child process */
800*2d543d20SAndroid Build Coastguard Worker child = fork();
801*2d543d20SAndroid Build Coastguard Worker if (child == -1) {
802*2d543d20SAndroid Build Coastguard Worker perror(_("Unable to fork"));
803*2d543d20SAndroid Build Coastguard Worker goto err;
804*2d543d20SAndroid Build Coastguard Worker }
805*2d543d20SAndroid Build Coastguard Worker
806*2d543d20SAndroid Build Coastguard Worker if (child == 0) {
807*2d543d20SAndroid Build Coastguard Worker char *display = NULL;
808*2d543d20SAndroid Build Coastguard Worker char *LANG = NULL;
809*2d543d20SAndroid Build Coastguard Worker char *RUNTIME_DIR = NULL;
810*2d543d20SAndroid Build Coastguard Worker char *XDG_SESSION_TYPE = NULL;
811*2d543d20SAndroid Build Coastguard Worker int rc = -1;
812*2d543d20SAndroid Build Coastguard Worker char *resolved_path = NULL;
813*2d543d20SAndroid Build Coastguard Worker char *wayland_path_s = NULL; /* /tmp/.../wayland-0 */
814*2d543d20SAndroid Build Coastguard Worker char *wayland_path = NULL; /* /run/user/UID/wayland-0 */
815*2d543d20SAndroid Build Coastguard Worker char *pipewire_path_s = NULL; /* /tmp/.../pipewire-0 */
816*2d543d20SAndroid Build Coastguard Worker char *pipewire_path = NULL; /* /run/user/UID/pipewire-0 */
817*2d543d20SAndroid Build Coastguard Worker
818*2d543d20SAndroid Build Coastguard Worker
819*2d543d20SAndroid Build Coastguard Worker if (unshare(CLONE_NEWNS) < 0) {
820*2d543d20SAndroid Build Coastguard Worker perror(_("Failed to unshare"));
821*2d543d20SAndroid Build Coastguard Worker goto childerr;
822*2d543d20SAndroid Build Coastguard Worker }
823*2d543d20SAndroid Build Coastguard Worker
824*2d543d20SAndroid Build Coastguard Worker /* Remount / as SLAVE so that nothing mounted in the namespace
825*2d543d20SAndroid Build Coastguard Worker shows up in the parent */
826*2d543d20SAndroid Build Coastguard Worker if (mount("none", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) {
827*2d543d20SAndroid Build Coastguard Worker perror(_("Failed to make / a SLAVE mountpoint\n"));
828*2d543d20SAndroid Build Coastguard Worker goto childerr;
829*2d543d20SAndroid Build Coastguard Worker }
830*2d543d20SAndroid Build Coastguard Worker
831*2d543d20SAndroid Build Coastguard Worker /* assume fsuid==ruid after this point */
832*2d543d20SAndroid Build Coastguard Worker if ((uid_t)setfsuid(uid) != 0) goto childerr;
833*2d543d20SAndroid Build Coastguard Worker
834*2d543d20SAndroid Build Coastguard Worker resolved_path = realpath(pwd->pw_dir,NULL);
835*2d543d20SAndroid Build Coastguard Worker if (! resolved_path) goto childerr;
836*2d543d20SAndroid Build Coastguard Worker
837*2d543d20SAndroid Build Coastguard Worker if (verify_directory(resolved_path, NULL, &st_curhomedir) < 0)
838*2d543d20SAndroid Build Coastguard Worker goto childerr;
839*2d543d20SAndroid Build Coastguard Worker if (check_owner_uid(uid, resolved_path, &st_curhomedir) < 0)
840*2d543d20SAndroid Build Coastguard Worker goto childerr;
841*2d543d20SAndroid Build Coastguard Worker
842*2d543d20SAndroid Build Coastguard Worker if ((RUNTIME_DIR = getenv("XDG_RUNTIME_DIR")) != NULL) {
843*2d543d20SAndroid Build Coastguard Worker if ((RUNTIME_DIR = strdup(RUNTIME_DIR)) == NULL) {
844*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
845*2d543d20SAndroid Build Coastguard Worker goto childerr;
846*2d543d20SAndroid Build Coastguard Worker }
847*2d543d20SAndroid Build Coastguard Worker } else {
848*2d543d20SAndroid Build Coastguard Worker if (asprintf(&RUNTIME_DIR, "/run/user/%d", uid) == -1) {
849*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory\n"));
850*2d543d20SAndroid Build Coastguard Worker goto childerr;
851*2d543d20SAndroid Build Coastguard Worker }
852*2d543d20SAndroid Build Coastguard Worker }
853*2d543d20SAndroid Build Coastguard Worker
854*2d543d20SAndroid Build Coastguard Worker if ((XDG_SESSION_TYPE = getenv("XDG_SESSION_TYPE")) != NULL) {
855*2d543d20SAndroid Build Coastguard Worker if ((XDG_SESSION_TYPE = strdup(XDG_SESSION_TYPE)) == NULL) {
856*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
857*2d543d20SAndroid Build Coastguard Worker goto childerr;
858*2d543d20SAndroid Build Coastguard Worker }
859*2d543d20SAndroid Build Coastguard Worker }
860*2d543d20SAndroid Build Coastguard Worker
861*2d543d20SAndroid Build Coastguard Worker if (runuserdir_s && (wayland_display || pipewire_socket)) {
862*2d543d20SAndroid Build Coastguard Worker if (wayland_display) {
863*2d543d20SAndroid Build Coastguard Worker if (asprintf(&wayland_path_s, "%s/%s", runuserdir_s, wayland_display) == -1) {
864*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
865*2d543d20SAndroid Build Coastguard Worker goto childerr;
866*2d543d20SAndroid Build Coastguard Worker }
867*2d543d20SAndroid Build Coastguard Worker
868*2d543d20SAndroid Build Coastguard Worker if (asprintf(&wayland_path, "%s/%s", RUNTIME_DIR, wayland_display) == -1) {
869*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
870*2d543d20SAndroid Build Coastguard Worker goto childerr;
871*2d543d20SAndroid Build Coastguard Worker }
872*2d543d20SAndroid Build Coastguard Worker
873*2d543d20SAndroid Build Coastguard Worker if (seunshare_mount_file(wayland_path, wayland_path_s) == -1)
874*2d543d20SAndroid Build Coastguard Worker goto childerr;
875*2d543d20SAndroid Build Coastguard Worker }
876*2d543d20SAndroid Build Coastguard Worker
877*2d543d20SAndroid Build Coastguard Worker if (pipewire_socket) {
878*2d543d20SAndroid Build Coastguard Worker if (asprintf(&pipewire_path_s, "%s/%s", runuserdir_s, pipewire_socket) == -1) {
879*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
880*2d543d20SAndroid Build Coastguard Worker goto childerr;
881*2d543d20SAndroid Build Coastguard Worker }
882*2d543d20SAndroid Build Coastguard Worker if (asprintf(&pipewire_path, "%s/pipewire-0", RUNTIME_DIR) == -1) {
883*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
884*2d543d20SAndroid Build Coastguard Worker goto childerr;
885*2d543d20SAndroid Build Coastguard Worker }
886*2d543d20SAndroid Build Coastguard Worker seunshare_mount_file(pipewire_path, pipewire_path_s);
887*2d543d20SAndroid Build Coastguard Worker }
888*2d543d20SAndroid Build Coastguard Worker }
889*2d543d20SAndroid Build Coastguard Worker
890*2d543d20SAndroid Build Coastguard Worker /* mount homedir, runuserdir and tmpdir, in this order */
891*2d543d20SAndroid Build Coastguard Worker if (runuserdir_s && seunshare_mount(runuserdir_s, RUNTIME_DIR,
892*2d543d20SAndroid Build Coastguard Worker &st_runuserdir_s) != 0) goto childerr;
893*2d543d20SAndroid Build Coastguard Worker if (homedir_s && seunshare_mount(homedir_s, resolved_path,
894*2d543d20SAndroid Build Coastguard Worker &st_homedir) != 0) goto childerr;
895*2d543d20SAndroid Build Coastguard Worker if (tmpdir_s && seunshare_mount(tmpdir_r, "/tmp",
896*2d543d20SAndroid Build Coastguard Worker &st_tmpdir_r) != 0) goto childerr;
897*2d543d20SAndroid Build Coastguard Worker
898*2d543d20SAndroid Build Coastguard Worker if (drop_privs(uid) != 0) goto childerr;
899*2d543d20SAndroid Build Coastguard Worker
900*2d543d20SAndroid Build Coastguard Worker /* construct a new environment */
901*2d543d20SAndroid Build Coastguard Worker
902*2d543d20SAndroid Build Coastguard Worker if (XDG_SESSION_TYPE && strcmp(XDG_SESSION_TYPE, "wayland") == 0) {
903*2d543d20SAndroid Build Coastguard Worker if (wayland_display == NULL && (wayland_display = getenv("WAYLAND_DISPLAY")) != NULL) {
904*2d543d20SAndroid Build Coastguard Worker if ((wayland_display = strdup(wayland_display)) == NULL) {
905*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
906*2d543d20SAndroid Build Coastguard Worker goto childerr;
907*2d543d20SAndroid Build Coastguard Worker }
908*2d543d20SAndroid Build Coastguard Worker }
909*2d543d20SAndroid Build Coastguard Worker }
910*2d543d20SAndroid Build Coastguard Worker else {
911*2d543d20SAndroid Build Coastguard Worker if ((display = getenv("DISPLAY")) != NULL) {
912*2d543d20SAndroid Build Coastguard Worker if ((display = strdup(display)) == NULL) {
913*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
914*2d543d20SAndroid Build Coastguard Worker goto childerr;
915*2d543d20SAndroid Build Coastguard Worker }
916*2d543d20SAndroid Build Coastguard Worker }
917*2d543d20SAndroid Build Coastguard Worker }
918*2d543d20SAndroid Build Coastguard Worker
919*2d543d20SAndroid Build Coastguard Worker /* construct a new environment */
920*2d543d20SAndroid Build Coastguard Worker if ((LANG = getenv("LANG")) != NULL) {
921*2d543d20SAndroid Build Coastguard Worker if ((LANG = strdup(LANG)) == NULL) {
922*2d543d20SAndroid Build Coastguard Worker perror(_("Out of memory"));
923*2d543d20SAndroid Build Coastguard Worker goto childerr;
924*2d543d20SAndroid Build Coastguard Worker }
925*2d543d20SAndroid Build Coastguard Worker }
926*2d543d20SAndroid Build Coastguard Worker
927*2d543d20SAndroid Build Coastguard Worker if ((rc = clearenv()) != 0) {
928*2d543d20SAndroid Build Coastguard Worker perror(_("Failed to clear environment"));
929*2d543d20SAndroid Build Coastguard Worker goto childerr;
930*2d543d20SAndroid Build Coastguard Worker }
931*2d543d20SAndroid Build Coastguard Worker if (display) {
932*2d543d20SAndroid Build Coastguard Worker rc |= setenv("DISPLAY", display, 1);
933*2d543d20SAndroid Build Coastguard Worker }
934*2d543d20SAndroid Build Coastguard Worker if (wayland_display) {
935*2d543d20SAndroid Build Coastguard Worker rc |= setenv("WAYLAND_DISPLAY", wayland_display, 1);
936*2d543d20SAndroid Build Coastguard Worker }
937*2d543d20SAndroid Build Coastguard Worker
938*2d543d20SAndroid Build Coastguard Worker if (XDG_SESSION_TYPE)
939*2d543d20SAndroid Build Coastguard Worker rc |= setenv("XDG_SESSION_TYPE", XDG_SESSION_TYPE, 1);
940*2d543d20SAndroid Build Coastguard Worker
941*2d543d20SAndroid Build Coastguard Worker if (LANG)
942*2d543d20SAndroid Build Coastguard Worker rc |= setenv("LANG", LANG, 1);
943*2d543d20SAndroid Build Coastguard Worker if (RUNTIME_DIR)
944*2d543d20SAndroid Build Coastguard Worker rc |= setenv("XDG_RUNTIME_DIR", RUNTIME_DIR, 1);
945*2d543d20SAndroid Build Coastguard Worker rc |= setenv("HOME", pwd->pw_dir, 1);
946*2d543d20SAndroid Build Coastguard Worker rc |= setenv("SHELL", pwd->pw_shell, 1);
947*2d543d20SAndroid Build Coastguard Worker rc |= setenv("USER", pwd->pw_name, 1);
948*2d543d20SAndroid Build Coastguard Worker rc |= setenv("LOGNAME", pwd->pw_name, 1);
949*2d543d20SAndroid Build Coastguard Worker rc |= setenv("PATH", DEFAULT_PATH, 1);
950*2d543d20SAndroid Build Coastguard Worker if (rc != 0) {
951*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to construct environment\n"));
952*2d543d20SAndroid Build Coastguard Worker goto childerr;
953*2d543d20SAndroid Build Coastguard Worker }
954*2d543d20SAndroid Build Coastguard Worker
955*2d543d20SAndroid Build Coastguard Worker if (chdir(pwd->pw_dir)) {
956*2d543d20SAndroid Build Coastguard Worker perror(_("Failed to change dir to homedir"));
957*2d543d20SAndroid Build Coastguard Worker goto childerr;
958*2d543d20SAndroid Build Coastguard Worker }
959*2d543d20SAndroid Build Coastguard Worker setsid();
960*2d543d20SAndroid Build Coastguard Worker
961*2d543d20SAndroid Build Coastguard Worker /* selinux context */
962*2d543d20SAndroid Build Coastguard Worker if (execcon) {
963*2d543d20SAndroid Build Coastguard Worker /* try dyntransition, since no_new_privs can interfere
964*2d543d20SAndroid Build Coastguard Worker * with setexeccon */
965*2d543d20SAndroid Build Coastguard Worker if (setcon(execcon) != 0) {
966*2d543d20SAndroid Build Coastguard Worker /* failed; fall back to setexeccon */
967*2d543d20SAndroid Build Coastguard Worker if (setexeccon(execcon) != 0) {
968*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Could not set exec context to %s. %s\n"), execcon, strerror(errno));
969*2d543d20SAndroid Build Coastguard Worker goto childerr;
970*2d543d20SAndroid Build Coastguard Worker }
971*2d543d20SAndroid Build Coastguard Worker }
972*2d543d20SAndroid Build Coastguard Worker }
973*2d543d20SAndroid Build Coastguard Worker
974*2d543d20SAndroid Build Coastguard Worker execv(argv[optind], argv + optind);
975*2d543d20SAndroid Build Coastguard Worker fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
976*2d543d20SAndroid Build Coastguard Worker childerr:
977*2d543d20SAndroid Build Coastguard Worker free(resolved_path);
978*2d543d20SAndroid Build Coastguard Worker free(wayland_path);
979*2d543d20SAndroid Build Coastguard Worker free(wayland_path_s);
980*2d543d20SAndroid Build Coastguard Worker free(pipewire_path);
981*2d543d20SAndroid Build Coastguard Worker free(pipewire_path_s);
982*2d543d20SAndroid Build Coastguard Worker free(display);
983*2d543d20SAndroid Build Coastguard Worker free(LANG);
984*2d543d20SAndroid Build Coastguard Worker free(RUNTIME_DIR);
985*2d543d20SAndroid Build Coastguard Worker free(XDG_SESSION_TYPE);
986*2d543d20SAndroid Build Coastguard Worker exit(-1);
987*2d543d20SAndroid Build Coastguard Worker }
988*2d543d20SAndroid Build Coastguard Worker
989*2d543d20SAndroid Build Coastguard Worker drop_caps();
990*2d543d20SAndroid Build Coastguard Worker
991*2d543d20SAndroid Build Coastguard Worker /* parent waits for child exit to do the cleanup */
992*2d543d20SAndroid Build Coastguard Worker waitpid(child, &status, 0);
993*2d543d20SAndroid Build Coastguard Worker status_to_retval(status, status);
994*2d543d20SAndroid Build Coastguard Worker
995*2d543d20SAndroid Build Coastguard Worker /* Make sure all child processes exit */
996*2d543d20SAndroid Build Coastguard Worker kill(-child,SIGTERM);
997*2d543d20SAndroid Build Coastguard Worker
998*2d543d20SAndroid Build Coastguard Worker if (execcon && kill_all)
999*2d543d20SAndroid Build Coastguard Worker killall(execcon);
1000*2d543d20SAndroid Build Coastguard Worker
1001*2d543d20SAndroid Build Coastguard Worker if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
1002*2d543d20SAndroid Build Coastguard Worker
1003*2d543d20SAndroid Build Coastguard Worker err:
1004*2d543d20SAndroid Build Coastguard Worker free(tmpdir_r);
1005*2d543d20SAndroid Build Coastguard Worker return status;
1006*2d543d20SAndroid Build Coastguard Worker }
1007