1. 09 Nov, 2013 1 commit
  2. 20 Dec, 2012 1 commit
  3. 27 Sep, 2012 1 commit
  4. 30 May, 2012 1 commit
  5. 24 Mar, 2011 1 commit
  6. 13 Aug, 2010 1 commit
  7. 14 Jan, 2009 2 commits
  8. 27 Jul, 2008 5 commits
  9. 23 Jun, 2008 4 commits
    • Michael Kerrisk's avatar
      [patch for 2.6.26 4/4] vfs: utimensat(): fix write access check for futimens() · c70f8441
      Michael Kerrisk authored
      The POSIX.1 draft spec for futimens()/utimensat() says:
      
              Only a process with the effective user ID equal to the
              user ID of the file, *or with write access to the file*,
              or with appropriate privileges may use futimens() or
              utimensat() with a null pointer as the times argument
              or with both tv_nsec fields set to the special value
              UTIME_NOW.
      
      The important piece here is "with write access to the file", and
      this matters for futimens(), which deals with an argument that
      is a file descriptor referring to the file whose timestamps are
      being updated,  The standard is saying that the "writability"
      check is based on the file permissions, not the access mode with
      which the file is opened.  (This behavior is consistent with the
      semantics of FreeBSD's futimes().)  However, Linux is currently
      doing the latter -- futimens(fd, times) is a library
      function implemented as
      
             utimensat(fd, NULL, times, 0)
      
      and within the utimensat() implementation we have the code:
      
                      f = fget(dfd);  // dfd is 'fd'
                      ...
                      if (f) {
                              if (!(f->f_mode & FMODE_WRITE))
                                      goto mnt_drop_write_and_out;
      
      The check should instead be based on the file permissions.
      
      Thanks to Miklos for pointing out how to do this check.
      Miklos also pointed out a simplification that could be
      made to my first version of this patch, since the checks
      for the pathname and file descriptor cases can now be
      conflated.
      Acked-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
      Cc: Al Viro <viro@zeniv.linux.org.uk>
      Cc: Ulrich Drepper <drepper@redhat.com>
      Signed-off-by: default avatarMichael Kerrisk <mtk.manpages@gmail.com>
      Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
      c70f8441
    • Michael Kerrisk's avatar
      [patch for 2.6.26 3/4] vfs: utimensat(): fix error checking for {UTIME_NOW,UTIME_OMIT} case · 4cca9226
      Michael Kerrisk authored
      The POSIX.1 draft spec for utimensat() says:
      
          Only a process with the effective user ID equal to the
          user ID of the file or with appropriate privileges may use
          futimens() or utimensat() with a non-null times argument
          that does not have both tv_nsec fields set to UTIME_NOW
          and does not have both tv_nsec fields set to UTIME_OMIT.
      
      If this condition is violated, then the error EPERM should result.
      However, the current implementation does not generate EPERM if
      one tv_nsec field is UTIME_NOW while the other is UTIME_OMIT.
      It should give this error for that case.
      
      This patch:
      
      a) Repairs that problem.
      b) Removes the now unneeded nsec_special() helper function.
      c) Adds some comments to explain the checks that are being
         performed.
      
      Thanks to Miklos, who provided comments on the previous iteration
      of this patch.  As a result, this version is a little simpler and
      and its logic is better structured.
      
      Miklos suggested an alternative idea, migrating the
      is_owner_or_cap() checks into fs/attr.c:inode_change_ok() via
      the use of an ATTR_OWNER_CHECK flag.  Maybe we could do that
      later, but for now I've gone with this version, which is
      IMO simpler, and can be more easily read as being correct.
      Acked-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
      Cc: Al Viro <viro@zeniv.linux.org.uk>
      Cc: Ulrich Drepper <drepper@redhat.com>
      Signed-off-by: default avatarMichael Kerrisk <mtk.manpages@gmail.com>
      Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
      4cca9226
    • Michael Kerrisk's avatar
      [patch for 2.6.26 1/4] vfs: utimensat(): ignore tv_sec if tv_nsec == UTIME_OMIT or UTIME_NOW · 94c70b9b
      Michael Kerrisk authored
      The POSIX.1 draft spec for utimensat() says that if a times[n].tv_nsec
      field is UTIME_OMIT or UTIME_NOW, then the value in the corresponding
      tv_sec field is ignored.  See the last sentence of this para, from
      the spec:
      
          If the tv_nsec field of a timespec structure has
          the special value UTIME_NOW, the file's relevant
          timestamp shall be set to the greatest value
          supported by the file system that is not greater than
          the current time. If the tv_nsec field has the
          special value UTIME_OMIT, the file's relevant
          timestamp shall not be changed. In either case,
          the tv_sec field shall be ignored.
      
      However the current Linux implementation requires the tv_sec value to be
      zero (or the EINVAL error results). This requirement should be removed.
      Acked-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
      Cc: Al Viro <viro@zeniv.linux.org.uk>
      Cc: Ulrich Drepper <drepper@redhat.com>
      Signed-off-by: default avatarMichael Kerrisk <mtk.manpages@gmail.com>
      Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
      94c70b9b
    • Michael Kerrisk's avatar
      [patch for 2.6.26 2/4] vfs: utimensat(): be consistent with utime() for... · 12fd0d30
      Michael Kerrisk authored
      [patch for 2.6.26 2/4] vfs: utimensat(): be consistent with utime() for immutable and append-only files
      
      This patch fixes utimensat() to make its behavior consistent
      with that of utime()/utimes() when dealing with files marked
      immutable and append-only.
      
      The current utimensat() implementation also returns EPERM if
      'times' is non-NULL and the tv_nsec fields are both UTIME_NOW.
      For consistency, the
      
      (times != NULL && times[0].tv_nsec == UTIME_NOW &&
                        times[1].tv_nsec == UTIME_NOW)
      
      case should be treated like the traditional utimes() case where
      'times' is NULL.  That is, the call should succeed for a file
      marked append-only and should give the error EACCES if the file
      is marked as immutable.
      
      The simple way to do this is to set 'times' to NULL
      if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW).
      
      This is also the natural approach, since POSIX.1 semantics consider the
      times == {{x, UTIME_NOW}, {y, UTIME_NOW}}
      to be exactly equivalent to the case for
      times == NULL.
      
      (Thanks to Miklos for pointing this out.)
      
      Patch 3 in this series relies on the simplification provided
      by this patch.
      Acked-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
      Cc: Al Viro <viro@zeniv.linux.org.uk>
      Cc: Ulrich Drepper <drepper@redhat.com>
      Signed-off-by: default avatarMichael Kerrisk <mtk.manpages@gmail.com>
      Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
      12fd0d30
  10. 01 May, 2008 1 commit
    • Miklos Szeredi's avatar
      vfs: fix permission checking in sys_utimensat · 02c6be61
      Miklos Szeredi authored
      If utimensat() is called with both times set to UTIME_NOW or one of them to
      UTIME_NOW and the other to UTIME_OMIT, then it will update the file time
      without any permission checking.
      
      I don't think this can be used for anything other than a local DoS, but could
      be quite bewildering at that (e.g.  "Why was that large source tree rebuilt
      when I didn't modify anything???")
      
      This affects all kernels from 2.6.22, when the utimensat() syscall was
      introduced.
      
      Fix by doing the same permission checking as for the "times == NULL" case.
      
      Thanks to Michael Kerrisk, whose utimensat-non-conformances-and-fixes.patch in
      -mm also fixes this (and breaks other stuff), only he didn't realize the
      security implications of this bug.
      Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
      Cc: Ulrich Drepper <drepper@redhat.com>
      Cc: Michael Kerrisk <mtk-manpages@gmx.net>
      Cc: <stable@kernel.org>
      Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      02c6be61
  11. 19 Apr, 2008 1 commit
  12. 15 Feb, 2008 2 commits
  13. 06 Feb, 2008 1 commit
  14. 17 Oct, 2007 1 commit
  15. 17 Jul, 2007 1 commit
    • Satyam Sharma's avatar
      Introduce is_owner_or_cap() to wrap CAP_FOWNER use with fsuid check · 3bd858ab
      Satyam Sharma authored
      Introduce is_owner_or_cap() macro in fs.h, and convert over relevant
      users to it. This is done because we want to avoid bugs in the future
      where we check for only effective fsuid of the current task against a
      file's owning uid, without simultaneously checking for CAP_FOWNER as
      well, thus violating its semantics.
      [ XFS uses special macros and structures, and in general looked ...
      untouchable, so we leave it alone -- but it has been looked over. ]
      
      The (current->fsuid != inode->i_uid) check in generic_permission() and
      exec_permission_lite() is left alone, because those operations are
      covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH. Similarly operations
      falling under the purview of CAP_CHOWN and CAP_LEASE are also left alone.
      Signed-off-by: default avatarSatyam Sharma <ssatyam@cse.iitk.ac.in>
      Cc: Al Viro <viro@ftp.linux.org.uk>
      Acked-by: default avatarSerge E. Hallyn <serge@hallyn.com>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      3bd858ab
  16. 16 Jul, 2007 1 commit
  17. 08 Jul, 2007 1 commit
  18. 08 May, 2007 1 commit
    • Ulrich Drepper's avatar
      utimensat implementation · 1c710c89
      Ulrich Drepper authored
      Implement utimensat(2) which is an extension to futimesat(2) in that it
      
      a) supports nano-second resolution for the timestamps
      b) allows to selectively ignore the atime/mtime value
      c) allows to selectively use the current time for either atime or mtime
      d) supports changing the atime/mtime of a symlink itself along the lines
         of the BSD lutimes(3) functions
      
      For this change the internally used do_utimes() functions was changed to
      accept a timespec time value and an additional flags parameter.
      
      Additionally the sys_utime function was changed to match compat_sys_utime
      which already use do_utimes instead of duplicating the work.
      
      Also, the completely missing futimensat() functionality is added.  We have
      such a function in glibc but we have to resort to using /proc/self/fd/* which
      not everybody likes (chroot etc).
      
      Test application (the syscall number will need per-arch editing):
      
      #include <errno.h>
      #include <fcntl.h>
      #include <time.h>
      #include <sys/time.h>
      #include <stddef.h>
      #include <syscall.h>
      
      #define __NR_utimensat 280
      
      #define UTIME_NOW       ((1l << 30) - 1l)
      #define UTIME_OMIT      ((1l << 30) - 2l)
      
      int
      main(void)
      {
        int status = 0;
      
        int fd = open("ttt", O_RDWR|O_CREAT|O_EXCL, 0666);
        if (fd == -1)
          error (1, errno, "failed to create test file \"ttt\"");
      
        struct stat64 st1;
        if (fstat64 (fd, &st1) != 0)
          error (1, errno, "fstat failed");
      
        struct timespec t[2];
        t[0].tv_sec = 0;
        t[0].tv_nsec = 0;
        t[1].tv_sec = 0;
        t[1].tv_nsec = 0;
        if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
          error (1, errno, "utimensat failed");
      
        struct stat64 st2;
        if (fstat64 (fd, &st2) != 0)
          error (1, errno, "fstat failed");
      
        if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
          {
            puts ("atim not reset to zero");
            status = 1;
          }
        if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
          {
            puts ("mtim not reset to zero");
            status = 1;
          }
        if (status != 0)
          goto out;
      
        t[0] = st1.st_atim;
        t[1].tv_sec = 0;
        t[1].tv_nsec = UTIME_OMIT;
        if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
          error (1, errno, "utimensat failed");
      
        if (fstat64 (fd, &st2) != 0)
          error (1, errno, "fstat failed");
      
        if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
            || st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
          {
            puts ("atim not set");
            status = 1;
          }
        if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
          {
            puts ("mtim changed from zero");
            status = 1;
          }
        if (status != 0)
          goto out;
      
        t[0].tv_sec = 0;
        t[0].tv_nsec = UTIME_OMIT;
        t[1] = st1.st_mtim;
        if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
          error (1, errno, "utimensat failed");
      
        if (fstat64 (fd, &st2) != 0)
          error (1, errno, "fstat failed");
      
        if (st2.st_atim.tv_sec != st1.st_atim.tv_sec
            || st2.st_atim.tv_nsec != st1.st_atim.tv_nsec)
          {
            puts ("mtim changed from original time");
            status = 1;
          }
        if (st2.st_mtim.tv_sec != st1.st_mtim.tv_sec
            || st2.st_mtim.tv_nsec != st1.st_mtim.tv_nsec)
          {
            puts ("mtim not set");
            status = 1;
          }
        if (status != 0)
          goto out;
      
        sleep (2);
      
        t[0].tv_sec = 0;
        t[0].tv_nsec = UTIME_NOW;
        t[1].tv_sec = 0;
        t[1].tv_nsec = UTIME_NOW;
        if (syscall(__NR_utimensat, AT_FDCWD, "ttt", t, 0) != 0)
          error (1, errno, "utimensat failed");
      
        if (fstat64 (fd, &st2) != 0)
          error (1, errno, "fstat failed");
      
        struct timeval tv;
        gettimeofday(&tv,NULL);
      
        if (st2.st_atim.tv_sec <= st1.st_atim.tv_sec
            || st2.st_atim.tv_sec > tv.tv_sec)
          {
            puts ("atim not set to NOW");
            status = 1;
          }
        if (st2.st_mtim.tv_sec <= st1.st_mtim.tv_sec
            || st2.st_mtim.tv_sec > tv.tv_sec)
          {
            puts ("mtim not set to NOW");
            status = 1;
          }
      
        if (symlink ("ttt", "tttsym") != 0)
          error (1, errno, "cannot create symlink");
      
        t[0].tv_sec = 0;
        t[0].tv_nsec = 0;
        t[1].tv_sec = 0;
        t[1].tv_nsec = 0;
        if (syscall(__NR_utimensat, AT_FDCWD, "tttsym", t, AT_SYMLINK_NOFOLLOW) != 0)
          error (1, errno, "utimensat failed");
      
        if (lstat64 ("tttsym", &st2) != 0)
          error (1, errno, "lstat failed");
      
        if (st2.st_atim.tv_sec != 0 || st2.st_atim.tv_nsec != 0)
          {
            puts ("symlink atim not reset to zero");
            status = 1;
          }
        if (st2.st_mtim.tv_sec != 0 || st2.st_mtim.tv_nsec != 0)
          {
            puts ("symlink mtim not reset to zero");
            status = 1;
          }
        if (status != 0)
          goto out;
      
        t[0].tv_sec = 1;
        t[0].tv_nsec = 0;
        t[1].tv_sec = 1;
        t[1].tv_nsec = 0;
        if (syscall(__NR_utimensat, fd, NULL, t, 0) != 0)
          error (1, errno, "utimensat failed");
      
        if (fstat64 (fd, &st2) != 0)
          error (1, errno, "fstat failed");
      
        if (st2.st_atim.tv_sec != 1 || st2.st_atim.tv_nsec != 0)
          {
            puts ("atim not reset to one");
            status = 1;
          }
        if (st2.st_mtim.tv_sec != 1 || st2.st_mtim.tv_nsec != 0)
          {
            puts ("mtim not reset to one");
            status = 1;
          }
      
        if (status == 0)
           puts ("all OK");
      
       out:
        close (fd);
        unlink ("ttt");
        unlink ("tttsym");
      
        return status;
      }
      
      [akpm@linux-foundation.org: add missing i386 syscall table entry]
      Signed-off-by: default avatarUlrich Drepper <drepper@redhat.com>
      Cc: Alexey Dobriyan <adobriyan@openvz.org>
      Cc: Michael Kerrisk <mtk-manpages@gmx.net>
      Cc: <linux-arch@vger.kernel.org>
      Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      1c710c89
  19. 04 Dec, 2006 1 commit
  20. 01 Oct, 2006 1 commit