LCOV - code coverage report
Current view: top level - fs - utimes.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-achx @ Mon Jul 31 20:08:12 PDT 2023 Lines: 68 135 50.4 %
Date: 2023-07-31 20:08:12 Functions: 6 26 23.1 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/file.h>
       3             : #include <linux/mount.h>
       4             : #include <linux/namei.h>
       5             : #include <linux/utime.h>
       6             : #include <linux/syscalls.h>
       7             : #include <linux/uaccess.h>
       8             : #include <linux/compat.h>
       9             : #include <asm/unistd.h>
      10             : #include <linux/filelock.h>
      11             : 
      12             : static bool nsec_valid(long nsec)
      13             : {
      14    23900322 :         if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
      15             :                 return true;
      16             : 
      17    23867041 :         return nsec >= 0 && nsec <= 999999999;
      18             : }
      19             : 
      20    15414447 : int vfs_utimes(const struct path *path, struct timespec64 *times)
      21             : {
      22    15414447 :         int error;
      23    15414447 :         struct iattr newattrs;
      24    15414447 :         struct inode *inode = path->dentry->d_inode;
      25    15414447 :         struct inode *delegated_inode = NULL;
      26             : 
      27    15414447 :         if (times) {
      28    23900237 :                 if (!nsec_valid(times[0].tv_nsec) ||
      29    11950161 :                     !nsec_valid(times[1].tv_nsec))
      30             :                         return -EINVAL;
      31    11950161 :                 if (times[0].tv_nsec == UTIME_NOW &&
      32             :                     times[1].tv_nsec == UTIME_NOW)
      33           0 :                         times = NULL;
      34             :         }
      35             : 
      36    15414447 :         error = mnt_want_write(path->mnt);
      37    15445738 :         if (error)
      38          13 :                 goto out;
      39             : 
      40    15445725 :         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
      41    15445725 :         if (times) {
      42    11981432 :                 if (times[0].tv_nsec == UTIME_OMIT)
      43       33124 :                         newattrs.ia_valid &= ~ATTR_ATIME;
      44    11948308 :                 else if (times[0].tv_nsec != UTIME_NOW) {
      45    11948236 :                         newattrs.ia_atime = times[0];
      46    11948236 :                         newattrs.ia_valid |= ATTR_ATIME_SET;
      47             :                 }
      48             : 
      49    11981432 :                 if (times[1].tv_nsec == UTIME_OMIT)
      50          85 :                         newattrs.ia_valid &= ~ATTR_MTIME;
      51    11981347 :                 else if (times[1].tv_nsec != UTIME_NOW) {
      52    11979004 :                         newattrs.ia_mtime = times[1];
      53    11979004 :                         newattrs.ia_valid |= ATTR_MTIME_SET;
      54             :                 }
      55             :                 /*
      56             :                  * Tell setattr_prepare(), that this is an explicit time
      57             :                  * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
      58             :                  * were used.
      59             :                  */
      60    11981432 :                 newattrs.ia_valid |= ATTR_TIMES_SET;
      61             :         } else {
      62     3464293 :                 newattrs.ia_valid |= ATTR_TOUCH;
      63             :         }
      64             : retry_deleg:
      65    15445725 :         inode_lock(inode);
      66    15407971 :         error = notify_change(mnt_idmap(path->mnt), path->dentry, &newattrs,
      67             :                               &delegated_inode);
      68    15366315 :         inode_unlock(inode);
      69    15320325 :         if (delegated_inode) {
      70           0 :                 error = break_deleg_wait(&delegated_inode);
      71           0 :                 if (!error)
      72           0 :                         goto retry_deleg;
      73             :         }
      74             : 
      75    15320325 :         mnt_drop_write(path->mnt);
      76             : out:
      77             :         return error;
      78             : }
      79             : 
      80     1264120 : static int do_utimes_path(int dfd, const char __user *filename,
      81             :                 struct timespec64 *times, int flags)
      82             : {
      83     1264120 :         struct path path;
      84     1264120 :         int lookup_flags = 0, error;
      85             : 
      86     1264120 :         if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
      87             :                 return -EINVAL;
      88             : 
      89     1264120 :         if (!(flags & AT_SYMLINK_NOFOLLOW))
      90     1232616 :                 lookup_flags |= LOOKUP_FOLLOW;
      91     1264120 :         if (flags & AT_EMPTY_PATH)
      92           0 :                 lookup_flags |= LOOKUP_EMPTY;
      93             : 
      94     1264120 : retry:
      95     1264100 :         error = user_path_at(dfd, filename, lookup_flags, &path);
      96     1264865 :         if (error)
      97       15122 :                 return error;
      98             : 
      99     1249743 :         error = vfs_utimes(&path, times);
     100     1249533 :         path_put(&path);
     101     2499242 :         if (retry_estale(error, lookup_flags)) {
     102           0 :                 lookup_flags |= LOOKUP_REVAL;
     103           0 :                 goto retry;
     104             :         }
     105             : 
     106             :         return error;
     107             : }
     108             : 
     109    14109227 : static int do_utimes_fd(int fd, struct timespec64 *times, int flags)
     110             : {
     111    14109227 :         struct fd f;
     112    14109227 :         int error;
     113             : 
     114    14109227 :         if (flags)
     115             :                 return -EINVAL;
     116             : 
     117    14109227 :         f = fdget(fd);
     118    14158793 :         if (!f.file)
     119             :                 return -EBADF;
     120    14158793 :         error = vfs_utimes(&f.file->f_path, times);
     121    14165570 :         fdput(f);
     122    14165570 :         return error;
     123             : }
     124             : 
     125             : /*
     126             :  * do_utimes - change times on filename or file descriptor
     127             :  * @dfd: open file descriptor, -1 or AT_FDCWD
     128             :  * @filename: path name or NULL
     129             :  * @times: new times or NULL
     130             :  * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
     131             :  *
     132             :  * If filename is NULL and dfd refers to an open file, then operate on
     133             :  * the file.  Otherwise look up filename, possibly using dfd as a
     134             :  * starting point.
     135             :  *
     136             :  * If times==NULL, set access and modification to current time,
     137             :  * must be owner or have write permission.
     138             :  * Else, update from *times, must be owner or super user.
     139             :  */
     140    15420751 : long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
     141             :                int flags)
     142             : {
     143    15420751 :         if (filename == NULL && dfd != AT_FDCWD)
     144    14156398 :                 return do_utimes_fd(dfd, times, flags);
     145     1264353 :         return do_utimes_path(dfd, filename, times, flags);
     146             : }
     147             : 
     148    30844577 : SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
     149             :                 struct __kernel_timespec __user *, utimes, int, flags)
     150             : {
     151    15418645 :         struct timespec64 tstimes[2];
     152             : 
     153    15418645 :         if (utimes) {
     154    23806658 :                 if ((get_timespec64(&tstimes[0], &utimes[0]) ||
     155    11871479 :                         get_timespec64(&tstimes[1], &utimes[1])))
     156           0 :                         return -EFAULT;
     157             : 
     158             :                 /* Nothing to do, we must not even check the path.  */
     159    11866988 :                 if (tstimes[0].tv_nsec == UTIME_OMIT &&
     160       33124 :                     tstimes[1].tv_nsec == UTIME_OMIT)
     161             :                         return 0;
     162             :         }
     163             : 
     164    18824859 :         return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
     165             : }
     166             : 
     167             : #ifdef __ARCH_WANT_SYS_UTIME
     168             : /*
     169             :  * futimesat(), utimes() and utime() are older versions of utimensat()
     170             :  * that are provided for compatibility with traditional C libraries.
     171             :  * On modern architectures, we always use libc wrappers around
     172             :  * utimensat() instead.
     173             :  */
     174           0 : static long do_futimesat(int dfd, const char __user *filename,
     175             :                          struct __kernel_old_timeval __user *utimes)
     176             : {
     177           0 :         struct __kernel_old_timeval times[2];
     178           0 :         struct timespec64 tstimes[2];
     179             : 
     180           0 :         if (utimes) {
     181           0 :                 if (copy_from_user(&times, utimes, sizeof(times)))
     182             :                         return -EFAULT;
     183             : 
     184             :                 /* This test is needed to catch all invalid values.  If we
     185             :                    would test only in do_utimes we would miss those invalid
     186             :                    values truncated by the multiplication with 1000.  Note
     187             :                    that we also catch UTIME_{NOW,OMIT} here which are only
     188             :                    valid for utimensat.  */
     189           0 :                 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
     190           0 :                     times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
     191             :                         return -EINVAL;
     192             : 
     193           0 :                 tstimes[0].tv_sec = times[0].tv_sec;
     194           0 :                 tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
     195           0 :                 tstimes[1].tv_sec = times[1].tv_sec;
     196           0 :                 tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
     197             :         }
     198             : 
     199           0 :         return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
     200             : }
     201             : 
     202             : 
     203           0 : SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename,
     204             :                 struct __kernel_old_timeval __user *, utimes)
     205             : {
     206           0 :         return do_futimesat(dfd, filename, utimes);
     207             : }
     208             : 
     209           0 : SYSCALL_DEFINE2(utimes, char __user *, filename,
     210             :                 struct __kernel_old_timeval __user *, utimes)
     211             : {
     212           0 :         return do_futimesat(AT_FDCWD, filename, utimes);
     213             : }
     214             : 
     215           0 : SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
     216             : {
     217           0 :         struct timespec64 tv[2];
     218             : 
     219           0 :         if (times) {
     220           0 :                 if (get_user(tv[0].tv_sec, &times->actime) ||
     221           0 :                     get_user(tv[1].tv_sec, &times->modtime))
     222           0 :                         return -EFAULT;
     223           0 :                 tv[0].tv_nsec = 0;
     224           0 :                 tv[1].tv_nsec = 0;
     225             :         }
     226           0 :         return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
     227             : }
     228             : #endif
     229             : 
     230             : #ifdef CONFIG_COMPAT_32BIT_TIME
     231             : /*
     232             :  * Not all architectures have sys_utime, so implement this in terms
     233             :  * of sys_utimes.
     234             :  */
     235             : #ifdef __ARCH_WANT_SYS_UTIME32
     236           0 : SYSCALL_DEFINE2(utime32, const char __user *, filename,
     237             :                 struct old_utimbuf32 __user *, t)
     238             : {
     239           0 :         struct timespec64 tv[2];
     240             : 
     241           0 :         if (t) {
     242           0 :                 if (get_user(tv[0].tv_sec, &t->actime) ||
     243           0 :                     get_user(tv[1].tv_sec, &t->modtime))
     244           0 :                         return -EFAULT;
     245           0 :                 tv[0].tv_nsec = 0;
     246           0 :                 tv[1].tv_nsec = 0;
     247             :         }
     248           0 :         return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
     249             : }
     250             : #endif
     251             : 
     252           0 : SYSCALL_DEFINE4(utimensat_time32, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags)
     253             : {
     254           0 :         struct timespec64 tv[2];
     255             : 
     256           0 :         if  (t) {
     257           0 :                 if (get_old_timespec32(&tv[0], &t[0]) ||
     258           0 :                     get_old_timespec32(&tv[1], &t[1]))
     259           0 :                         return -EFAULT;
     260             : 
     261           0 :                 if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
     262             :                         return 0;
     263             :         }
     264           0 :         return do_utimes(dfd, filename, t ? tv : NULL, flags);
     265             : }
     266             : 
     267             : #ifdef __ARCH_WANT_SYS_UTIME32
     268           0 : static long do_compat_futimesat(unsigned int dfd, const char __user *filename,
     269             :                                 struct old_timeval32 __user *t)
     270             : {
     271           0 :         struct timespec64 tv[2];
     272             : 
     273           0 :         if (t) {
     274           0 :                 if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
     275           0 :                     get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
     276           0 :                     get_user(tv[1].tv_sec, &t[1].tv_sec) ||
     277           0 :                     get_user(tv[1].tv_nsec, &t[1].tv_usec))
     278           0 :                         return -EFAULT;
     279           0 :                 if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
     280           0 :                     tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
     281             :                         return -EINVAL;
     282           0 :                 tv[0].tv_nsec *= 1000;
     283           0 :                 tv[1].tv_nsec *= 1000;
     284             :         }
     285           0 :         return do_utimes(dfd, filename, t ? tv : NULL, 0);
     286             : }
     287             : 
     288           0 : SYSCALL_DEFINE3(futimesat_time32, unsigned int, dfd,
     289             :                        const char __user *, filename,
     290             :                        struct old_timeval32 __user *, t)
     291             : {
     292           0 :         return do_compat_futimesat(dfd, filename, t);
     293             : }
     294             : 
     295           0 : SYSCALL_DEFINE2(utimes_time32, const char __user *, filename, struct old_timeval32 __user *, t)
     296             : {
     297           0 :         return do_compat_futimesat(AT_FDCWD, filename, t);
     298             : }
     299             : #endif
     300             : #endif

Generated by: LCOV version 1.14