static mksh_uari_t rndsetup(void) { register uint32_t h; struct { ALLOC_ITEM alloc_INT; void *dataptr, *stkptr, *mallocptr; #if defined(__GLIBC__) && (__GLIBC__ >= 2) sigjmp_buf jbuf; #endif struct timeval tv; } *bufptr; char *cp; cp = alloc(sizeof(*bufptr) - sizeof(ALLOC_ITEM), APERM); /* clear the allocated space, for valgrind and to avoid UB */ memset(cp, 0, sizeof(*bufptr) - sizeof(ALLOC_ITEM)); /* undo what alloc() did to the malloc result address */ bufptr = (void *)(cp - sizeof(ALLOC_ITEM)); /* PIE or something similar provides us with deltas here */ bufptr->dataptr = &rndsetupstate; /* ASLR in at least Windows, Linux, some BSDs */ bufptr->stkptr = &bufptr; /* randomised malloc in BSD (and possibly others) */ bufptr->mallocptr = bufptr; #if defined(__GLIBC__) && (__GLIBC__ >= 2) /* glibc pointer guard */ sigsetjmp(bufptr->jbuf, 1); #endif /* introduce variation (and yes, second arg MBZ for portability) */ mksh_TIME(bufptr->tv); #ifdef MKSH_ALLOC_CATCH_UNDERRUNS mprotect(((char *)bufptr) + 4096, 4096, PROT_READ | PROT_WRITE); #endif h = chvt_rndsetup(bufptr, sizeof(*bufptr)); afree(cp, APERM); return ((mksh_uari_t)h); }
static void chvt(const Getopt *go) { const char *dv = go->optarg; char *cp = NULL; int fd; switch (*dv) { case '-': dv = "/dev/null"; break; case '!': ++dv; /* FALLTHROUGH */ default: { struct stat sb; if (stat(dv, &sb)) { cp = shf_smprintf("/dev/ttyC%s", dv); dv = cp; if (stat(dv, &sb)) { memmove(cp + 1, cp, /* /dev/tty */ 8); dv = cp + 1; if (stat(dv, &sb)) { errorf("%s: %s: %s", "chvt", "can't find tty", go->optarg); } } } if (!(sb.st_mode & S_IFCHR)) errorf("%s: %s: %s", "chvt", "not a char device", dv); #ifndef MKSH_DISABLE_REVOKE_WARNING #if HAVE_REVOKE if (revoke(dv)) #endif warningf(false, "%s: %s %s", "chvt", "new shell is potentially insecure, can't revoke", dv); #endif } } if ((fd = binopen2(dv, O_RDWR)) < 0) { sleep(1); if ((fd = binopen2(dv, O_RDWR)) < 0) { errorf("%s: %s %s", "chvt", "can't open", dv); } } if (go->optarg[0] != '!') { switch (fork()) { case -1: errorf("%s: %s %s", "chvt", "fork", "failed"); case 0: break; default: exit(0); } } if (setsid() == -1) errorf("%s: %s %s", "chvt", "setsid", "failed"); if (go->optarg[0] != '-') { if (ioctl(fd, TIOCSCTTY, NULL) == -1) errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed"); if (tcflush(fd, TCIOFLUSH)) errorf("%s: %s %s", "chvt", "TCIOFLUSH", "failed"); } ksh_dup2(fd, 0, false); ksh_dup2(fd, 1, false); ksh_dup2(fd, 2, false); if (fd > 2) close(fd); rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt))); chvt_reinit(); }