1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2015 Garrett D'Amore <garrett@damore.org>
  14  */
  15 
  16 /*
  17  * This program tests that fexecve works properly.
  18  */
  19 
  20 #include <stdio.h>
  21 #include <stdlib.h>
  22 #include <string.h>
  23 #include <fcntl.h>
  24 #include <err.h>
  25 #include <errno.h>
  26 #include <unistd.h>
  27 #include <note.h>
  28 #include <sys/utsname.h>
  29 #include <sys/wait.h>
  30 #include "test_common.h"
  31 
  32 int extra_debug = 0;
  33 
  34 struct utsname un;
  35 
  36 void
  37 forkit(char *msg, const char *expect, void (*postfn)(void))
  38 {
  39         int fd;
  40         FILE *f;
  41         pid_t pid;
  42         char *ptr = NULL;
  43         size_t cap = 0;
  44         int wstat;
  45         int rv;
  46         test_t t;
  47         char fname[32];
  48 
  49         (void) strcpy(fname, "/tmp/testXXXXXX");
  50         t = test_start(msg);
  51 
  52         fd = mkstemp(fname);
  53         if (fd < 0) {
  54                 test_failed(t, "mkstemp failed: %s", strerror(errno));
  55                 return;
  56         }
  57 
  58         /* don't leave it in the filesystem */
  59         (void) unlink(fname);
  60 
  61         pid = vfork();
  62         switch (pid) {
  63         case -1:
  64                 test_failed(t, "vfork failed: %s", strerror(errno));
  65                 return;
  66         case 0:
  67                 if (dup2(fd, 1) < 0) {
  68                         test_failed(t, "dup2 failed: %s", strerror(errno));
  69                         exit(9);
  70                 }
  71                 postfn();
  72                 exit(0);
  73         default:
  74                 break;
  75         }
  76 
  77         /* parent */
  78         f = fdopen(fd, "r");
  79         if (f == NULL) {
  80                 (void) close(fd);
  81                 test_failed(t, "fdopen failed: %s", strerror(errno));
  82                 (void) wait(NULL);
  83                 return;
  84         }
  85         if (waitpid(pid, &wstat, NULL) < 0) {
  86                 test_failed(t, "wait failed: %s", strerror(errno));
  87                 (void) fclose(f);
  88                 return;
  89         }
  90         if (!WIFEXITED(wstat) || WEXITSTATUS(wstat) != 0) {
  91                 test_failed(t, "child failed: %#x", wstat);
  92                 (void) fclose(f);
  93                 return;
  94         }
  95         (void) lseek(fd, 0, SEEK_SET);
  96         if ((rv = getline(&ptr, &cap, f)) < 1) {
  97                 test_failed(t, "child gave no data: %d", rv);
  98                 (void) fclose(f);
  99                 return;
 100         }
 101         (void) fclose(f);
 102 
 103         if (strncmp(ptr, expect, strlen(expect)) != 0) {
 104                 test_failed(t, "%s != %s", ptr, expect);
 105                 return;
 106         }
 107 
 108         (void) free(ptr);
 109         test_passed(t);
 110 }
 111 
 112 void
 113 case_badf(void)
 114 {
 115         int fd = -1;
 116         int rv;
 117         char *args[] = { "uname", NULL };
 118         char *env[] = { NULL };
 119 
 120         rv = fexecve(fd, args, env);
 121         if (rv != -1) {
 122                 (void) printf("rv is not -1\n");
 123                 (void) exit(0);
 124         }
 125         if (errno != EBADF) {
 126                 (void) printf("err %d(%s) != EBADF\n", errno, strerror(errno));
 127                 (void) exit(0);
 128         }
 129         (void) printf("GOOD\n");
 130         (void) exit(0);
 131 }
 132 
 133 void
 134 case_notexec(void)
 135 {
 136         int fd;
 137         int rv;
 138         char *args[] = { "uname", NULL };
 139         char *env[] = { NULL };
 140 
 141         fd = open("/usr/bin/uname", O_RDONLY);
 142 
 143         rv = fexecve(fd, args, env);
 144         if (rv != -1) {
 145                 (void) printf("rv is not -1\n");
 146                 (void) exit(0);
 147         }
 148         (void) printf("FAILURE\n");
 149         (void) exit(0);
 150 }
 151 
 152 void
 153 case_uname(void)
 154 {
 155         int fd;
 156         char *args[] = { "uname", NULL };
 157         char *env[] = { NULL };
 158 
 159         fd = open("/usr/bin/uname", O_EXEC);
 160         if (fd < 0) {
 161                 (void) printf("failed to open /usr/bin/uname: %s",
 162                     strerror(errno));
 163                 (void) exit(0);
 164         }
 165 
 166         (void) fexecve(fd, args, env);
 167         (void) printf("EXEC FAILED: %s\n", strerror(errno));
 168         (void) exit(0);
 169 }
 170 
 171 void
 172 case_uname_r(void)
 173 {
 174         int fd;
 175         char *args[] = { "uname", "-r", NULL };
 176         char *env[] = { NULL };
 177 
 178         fd = open("/usr/bin/uname", O_EXEC);
 179         if (fd < 0) {
 180                 (void) printf("failed to open /usr/bin/uname: %s",
 181                     strerror(errno));
 182                 (void) exit(0);
 183         }
 184 
 185         (void) fexecve(fd, args, env);
 186         (void) printf("EXEC FAILED: %s\n", strerror(errno));
 187         (void) exit(0);
 188 }
 189 
 190 void
 191 test_fexecve_badf(void)
 192 {
 193         forkit("fexecve (bad FD)", "GOOD\n", case_badf);
 194 }
 195 
 196 void
 197 test_fexecve_notexec(void)
 198 {
 199         forkit("fexecve (not O_EXEC)", un.sysname, case_notexec);
 200 }
 201 
 202 void
 203 test_fexecve_uname(void)
 204 {
 205         forkit("fexecve (uname)", un.sysname, case_uname);
 206 }
 207 
 208 void
 209 test_fexecve_uname_r(void)
 210 {
 211         forkit("fexecve (uname)", un.release, case_uname_r);
 212 }
 213 
 214 int
 215 main(int argc, char **argv)
 216 {
 217         int optc;
 218 
 219         (void) uname(&un);
 220 
 221         while ((optc = getopt(argc, argv, "dfD")) != EOF) {
 222                 switch (optc) {
 223                 case 'd':
 224                         test_set_debug();
 225                         break;
 226                 case 'f':
 227                         test_set_force();
 228                         break;
 229                 case 'D':
 230                         test_set_debug();
 231                         extra_debug++;
 232                         break;
 233                 default:
 234                         (void) fprintf(stderr, "Usage: %s [-dfD]\n", argv[0]);
 235                         exit(1);
 236                 }
 237         }
 238 
 239         test_fexecve_badf();
 240         test_fexecve_notexec();
 241         test_fexecve_uname();
 242         test_fexecve_uname_r();
 243 
 244         exit(0);
 245 }