static void do_setxid(void *p) { struct ctx *c = p; if (c->err) return; if (c->rlim && c->id >= 0 && c->id != getuid()) { struct rlimit inf = { RLIM_INFINITY, RLIM_INFINITY }, old; getrlimit(RLIMIT_NPROC, &old); if ((c->err = -__setrlimit(RLIMIT_NPROC, &inf)) && libc.threads_minus_1) return; c->err = -__syscall(c->nr, c->id, c->eid, c->sid); __setrlimit(RLIMIT_NPROC, &old); return; } c->err = -__syscall(c->nr, c->id, c->eid, c->sid); }
/* Function depends on CMD: 1 = Return the limit on the size of a file, in units of 512 bytes. 2 = Set the limit on the size of a file to NEWLIMIT. Only the super-user can increase the limit. 3 = illegal due to shared libraries; normally is (Return the maximum possible address of the data segment.) 4 = Return the maximum number of files that the calling process can open. Returns -1 on errors. */ long int __ulimit (int cmd, ...) { struct rlimit limit; va_list va; long int result = -1; va_start (va, cmd); switch (cmd) { case UL_GETFSIZE: /* Get limit on file size. */ if (__getrlimit (RLIMIT_FSIZE, &limit) == 0) /* Convert from bytes to 512 byte units. */ result = (limit.rlim_cur == RLIM_INFINITY ? LONG_MAX : limit.rlim_cur / 512); break; case UL_SETFSIZE: /* Set limit on file size. */ { long int newlimit = va_arg (va, long int); long int newlen; if ((rlim_t) newlimit > RLIM_INFINITY / 512) { limit.rlim_cur = RLIM_INFINITY; limit.rlim_max = RLIM_INFINITY; newlen = LONG_MAX; } else { limit.rlim_cur = newlimit * 512; limit.rlim_max = newlimit * 512; newlen = newlimit; } result = __setrlimit (RLIMIT_FSIZE, &limit); if (result != -1) result = newlen; } break; case __UL_GETOPENMAX: result = __sysconf (_SC_OPEN_MAX); break; default: __set_errno (EINVAL); } va_end (va); return result; }
static void do_setxid(void *p) { struct ctx *c = p; if (c->err) return; if (c->rlim && c->id >= 0 && c->id != getuid()) { struct rlimit inf = { RLIM_INFINITY, RLIM_INFINITY }, old; getrlimit(RLIMIT_NPROC, &old); if ((c->err = -__setrlimit(RLIMIT_NPROC, &inf)) && libc.threads_minus_1) return; #ifndef __EMSCRIPTEN__ c->err = -__syscall(c->nr, c->id, c->eid, c->sid); #else c->err = EPERM; // we don't allow dynamic syscalls, and don't need to support these anyhow #endif __setrlimit(RLIMIT_NPROC, &old); return; } #ifndef __EMSCRIPTEN__ c->err = -__syscall(c->nr, c->id, c->eid, c->sid); #else c->err = EPERM; // we don't allow dynamic syscalls, and don't need to support these anyhow #endif }
/* Set the soft and hard limits for RESOURCE to *RLIMITS. Only the super-user can increase hard limits. Return 0 if successful, -1 if not (and sets errno). */ int setrlimit64 (enum __rlimit_resource resource, const struct rlimit64 *rlimits) { struct rlimit rlimits32; if (rlimits->rlim_cur >= RLIM_INFINITY) rlimits32.rlim_cur = RLIM_INFINITY; else rlimits32.rlim_cur = rlimits->rlim_cur; if (rlimits->rlim_max >= RLIM_INFINITY) rlimits32.rlim_max = RLIM_INFINITY; else rlimits32.rlim_max = rlimits->rlim_max; return __setrlimit (resource, &rlimits32); }
/* Set the soft limit for RESOURCE to be VALUE. Returns 0 for success, -1 for failure. */ int vlimit (enum __vlimit_resource resource, int value) { if (resource >= LIM_CPU && resource <= LIM_MAXRSS) { /* The rlimit codes happen to each be one less than the corresponding vlimit codes. */ enum __rlimit_resource rlimit_res = (enum __rlimit_resource) ((int) resource - 1); struct rlimit lims; if (__getrlimit (rlimit_res, &lims) < 0) return -1; lims.rlim_cur = value; return __setrlimit (rlimit_res, &lims); } __set_errno (EINVAL); return -1; }
int grantpt (int fd) { #if defined __OpenBSD__ /* On OpenBSD, master and slave of a pseudo-terminal are allocated together, through an ioctl on /dev/ptm. There is no need for grantpt(). */ return 0; #else /* This function is most often called from a process without 'root' credentials. Use the helper program. */ int retval = -1; pid_t pid = __fork (); if (pid == -1) goto cleanup; else if (pid == 0) { /* This is executed in the child process. */ # if HAVE_SETRLIMIT && defined RLIMIT_CORE /* Disable core dumps. */ struct rlimit rl = { 0, 0 }; __setrlimit (RLIMIT_CORE, &rl); # endif /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */ if (fd != PTY_FILENO) if (__dup2 (fd, PTY_FILENO) < 0) _exit (FAIL_EBADF); # ifdef CLOSE_ALL_FDS CLOSE_ALL_FDS (); # endif execle (_PATH_PT_CHOWN, strrchr (_PATH_PT_CHOWN, '/') + 1, NULL, NULL); _exit (FAIL_EXEC); } else { int w; if (__waitpid (pid, &w, 0) == -1) goto cleanup; if (!WIFEXITED (w)) __set_errno (ENOEXEC); else switch (WEXITSTATUS (w)) { case 0: retval = 0; break; case FAIL_EBADF: __set_errno (EBADF); break; case FAIL_EINVAL: __set_errno (EINVAL); break; case FAIL_EACCES: __set_errno (EACCES); break; case FAIL_EXEC: __set_errno (ENOEXEC); break; case FAIL_ENOMEM: __set_errno (ENOMEM); break; default: assert(! "getpt: internal error: invalid exit code from pt_chown"); } } cleanup: return retval; #endif }
/* Change the ownership and access permission of the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ int grantpt (int fd) { int retval = -1; #ifdef PATH_MAX char _buf[PATH_MAX]; #else char _buf[512]; #endif char *buf = _buf; struct stat64 st; if (__glibc_unlikely (pts_name (fd, &buf, sizeof (_buf), &st))) { int save_errno = errno; /* Check, if the file descriptor is valid. pts_name returns the wrong errno number, so we cannot use that. */ if (__libc_fcntl (fd, F_GETFD) == -1 && errno == EBADF) return -1; /* If the filedescriptor is no TTY, grantpt has to set errno to EINVAL. */ if (save_errno == ENOTTY) __set_errno (EINVAL); else __set_errno (save_errno); return -1; } /* Make sure that we own the device. */ uid_t uid = __getuid (); if (st.st_uid != uid) { if (__chown (buf, uid, st.st_gid) < 0) goto helper; } static int tty_gid = -1; if (__glibc_unlikely (tty_gid == -1)) { char *grtmpbuf; struct group grbuf; size_t grbuflen = __sysconf (_SC_GETGR_R_SIZE_MAX); struct group *p; /* Get the group ID of the special `tty' group. */ if (grbuflen == (size_t) -1L) /* `sysconf' does not support _SC_GETGR_R_SIZE_MAX. Try a moderate value. */ grbuflen = 1024; grtmpbuf = (char *) __alloca (grbuflen); __getgrnam_r (TTY_GROUP, &grbuf, grtmpbuf, grbuflen, &p); if (p != NULL) tty_gid = p->gr_gid; } gid_t gid = tty_gid == -1 ? __getgid () : tty_gid; /* Make sure the group of the device is that special group. */ if (st.st_gid != gid) { if (__chown (buf, uid, gid) < 0) goto helper; } /* Make sure the permission mode is set to readable and writable by the owner, and writable by the group. */ if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP)) { if (__chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0) goto helper; } retval = 0; goto cleanup; /* We have to use the helper program if it is available. */ helper:; #ifdef HAVE_PT_CHOWN pid_t pid = __fork (); if (pid == -1) goto cleanup; else if (pid == 0) { /* Disable core dumps. */ struct rlimit rl = { 0, 0 }; __setrlimit (RLIMIT_CORE, &rl); /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */ if (fd != PTY_FILENO) if (__dup2 (fd, PTY_FILENO) < 0) _exit (FAIL_EBADF); # ifdef CLOSE_ALL_FDS CLOSE_ALL_FDS (); # endif execle (_PATH_PT_CHOWN, basename (_PATH_PT_CHOWN), NULL, NULL); _exit (FAIL_EXEC); } else { int w; if (__waitpid (pid, &w, 0) == -1) goto cleanup; if (!WIFEXITED (w)) __set_errno (ENOEXEC); else switch (WEXITSTATUS (w)) { case 0: retval = 0; break; case FAIL_EBADF: __set_errno (EBADF); break; case FAIL_EINVAL: __set_errno (EINVAL); break; case FAIL_EACCES: __set_errno (EACCES); break; case FAIL_EXEC: __set_errno (ENOEXEC); break; case FAIL_ENOMEM: __set_errno (ENOMEM); break; default: assert(! "getpt: internal error: invalid exit code from pt_chown"); } } #endif cleanup: if (buf != _buf) free (buf); return retval; }
static void do_setrlimit(void *p) { struct ctx *c = p; if (c->err) return; c->err = -__setrlimit(c->res, c->rlim); }