LCOV - code coverage report
Current view: top level - fs - utimes.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 68 76 89.5 %
Date: 2023-07-31 20:08:17 Functions: 6 6 100.0 %

          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     3728454 :         if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
      15             :                 return true;
      16             : 
      17     3723332 :         return nsec >= 0 && nsec <= 999999999;
      18             : }
      19             : 
      20     2556365 : int vfs_utimes(const struct path *path, struct timespec64 *times)
      21             : {
      22     2556365 :         int error;
      23     2556365 :         struct iattr newattrs;
      24     2556365 :         struct inode *inode = path->dentry->d_inode;
      25     2556365 :         struct inode *delegated_inode = NULL;
      26             : 
      27     2556365 :         if (times) {
      28     3728440 :                 if (!nsec_valid(times[0].tv_nsec) ||
      29     1864227 :                     !nsec_valid(times[1].tv_nsec))
      30             :                         return -EINVAL;
      31     1864227 :                 if (times[0].tv_nsec == UTIME_NOW &&
      32             :                     times[1].tv_nsec == UTIME_NOW)
      33           0 :                         times = NULL;
      34             :         }
      35             : 
      36     2556365 :         error = mnt_want_write(path->mnt);
      37     2556373 :         if (error)
      38           2 :                 goto out;
      39             : 
      40     2556371 :         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
      41     2556371 :         if (times) {
      42     1864235 :                 if (times[0].tv_nsec == UTIME_OMIT)
      43        5096 :                         newattrs.ia_valid &= ~ATTR_ATIME;
      44     1859139 :                 else if (times[0].tv_nsec != UTIME_NOW) {
      45     1859127 :                         newattrs.ia_atime = times[0];
      46     1859127 :                         newattrs.ia_valid |= ATTR_ATIME_SET;
      47             :                 }
      48             : 
      49     1864235 :                 if (times[1].tv_nsec == UTIME_OMIT)
      50          14 :                         newattrs.ia_valid &= ~ATTR_MTIME;
      51     1864221 :                 else if (times[1].tv_nsec != UTIME_NOW) {
      52     1864205 :                         newattrs.ia_mtime = times[1];
      53     1864205 :                         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     1864235 :                 newattrs.ia_valid |= ATTR_TIMES_SET;
      61             :         } else {
      62      692136 :                 newattrs.ia_valid |= ATTR_TOUCH;
      63             :         }
      64             : retry_deleg:
      65     2556371 :         inode_lock(inode);
      66     2556371 :         error = notify_change(mnt_idmap(path->mnt), path->dentry, &newattrs,
      67             :                               &delegated_inode);
      68     2556366 :         inode_unlock(inode);
      69     2556368 :         if (delegated_inode) {
      70           0 :                 error = break_deleg_wait(&delegated_inode);
      71           0 :                 if (!error)
      72           0 :                         goto retry_deleg;
      73             :         }
      74             : 
      75     2556368 :         mnt_drop_write(path->mnt);
      76             : out:
      77             :         return error;
      78             : }
      79             : 
      80      305542 : static int do_utimes_path(int dfd, const char __user *filename,
      81             :                 struct timespec64 *times, int flags)
      82             : {
      83      305542 :         struct path path;
      84      305542 :         int lookup_flags = 0, error;
      85             : 
      86      305542 :         if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
      87             :                 return -EINVAL;
      88             : 
      89      305542 :         if (!(flags & AT_SYMLINK_NOFOLLOW))
      90      302665 :                 lookup_flags |= LOOKUP_FOLLOW;
      91      305542 :         if (flags & AT_EMPTY_PATH)
      92           0 :                 lookup_flags |= LOOKUP_EMPTY;
      93             : 
      94      305542 : retry:
      95      305542 :         error = user_path_at(dfd, filename, lookup_flags, &path);
      96      305542 :         if (error)
      97        2686 :                 return error;
      98             : 
      99      302856 :         error = vfs_utimes(&path, times);
     100      302856 :         path_put(&path);
     101      605712 :         if (retry_estale(error, lookup_flags)) {
     102           0 :                 lookup_flags |= LOOKUP_REVAL;
     103           0 :                 goto retry;
     104             :         }
     105             : 
     106             :         return error;
     107             : }
     108             : 
     109     2253509 : static int do_utimes_fd(int fd, struct timespec64 *times, int flags)
     110             : {
     111     2253509 :         struct fd f;
     112     2253509 :         int error;
     113             : 
     114     2253509 :         if (flags)
     115             :                 return -EINVAL;
     116             : 
     117     2253509 :         f = fdget(fd);
     118     2253512 :         if (!f.file)
     119             :                 return -EBADF;
     120     2253512 :         error = vfs_utimes(&f.file->f_path, times);
     121     2253490 :         fdput(f);
     122     2253490 :         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     2559049 : long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
     141             :                int flags)
     142             : {
     143     2559049 :         if (filename == NULL && dfd != AT_FDCWD)
     144     2253507 :                 return do_utimes_fd(dfd, times, flags);
     145      305542 :         return do_utimes_path(dfd, filename, times, flags);
     146             : }
     147             : 
     148     5118022 : SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
     149             :                 struct __kernel_timespec __user *, utimes, int, flags)
     150             : {
     151     2559048 :         struct timespec64 tstimes[2];
     152             : 
     153     2559048 :         if (utimes) {
     154     3728456 :                 if ((get_timespec64(&tstimes[0], &utimes[0]) ||
     155     1864229 :                         get_timespec64(&tstimes[1], &utimes[1])))
     156           0 :                         return -EFAULT;
     157             : 
     158             :                 /* Nothing to do, we must not even check the path.  */
     159     1864232 :                 if (tstimes[0].tv_nsec == UTIME_OMIT &&
     160        5096 :                     tstimes[1].tv_nsec == UTIME_OMIT)
     161             :                         return 0;
     162             :         }
     163             : 
     164     3253880 :         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             : static long do_futimesat(int dfd, const char __user *filename,
     175             :                          struct __kernel_old_timeval __user *utimes)
     176             : {
     177             :         struct __kernel_old_timeval times[2];
     178             :         struct timespec64 tstimes[2];
     179             : 
     180             :         if (utimes) {
     181             :                 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             :                 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
     190             :                     times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
     191             :                         return -EINVAL;
     192             : 
     193             :                 tstimes[0].tv_sec = times[0].tv_sec;
     194             :                 tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
     195             :                 tstimes[1].tv_sec = times[1].tv_sec;
     196             :                 tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
     197             :         }
     198             : 
     199             :         return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
     200             : }
     201             : 
     202             : 
     203             : SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename,
     204             :                 struct __kernel_old_timeval __user *, utimes)
     205             : {
     206             :         return do_futimesat(dfd, filename, utimes);
     207             : }
     208             : 
     209             : SYSCALL_DEFINE2(utimes, char __user *, filename,
     210             :                 struct __kernel_old_timeval __user *, utimes)
     211             : {
     212             :         return do_futimesat(AT_FDCWD, filename, utimes);
     213             : }
     214             : 
     215             : SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
     216             : {
     217             :         struct timespec64 tv[2];
     218             : 
     219             :         if (times) {
     220             :                 if (get_user(tv[0].tv_sec, &times->actime) ||
     221             :                     get_user(tv[1].tv_sec, &times->modtime))
     222             :                         return -EFAULT;
     223             :                 tv[0].tv_nsec = 0;
     224             :                 tv[1].tv_nsec = 0;
     225             :         }
     226             :         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             : SYSCALL_DEFINE2(utime32, const char __user *, filename,
     237             :                 struct old_utimbuf32 __user *, t)
     238             : {
     239             :         struct timespec64 tv[2];
     240             : 
     241             :         if (t) {
     242             :                 if (get_user(tv[0].tv_sec, &t->actime) ||
     243             :                     get_user(tv[1].tv_sec, &t->modtime))
     244             :                         return -EFAULT;
     245             :                 tv[0].tv_nsec = 0;
     246             :                 tv[1].tv_nsec = 0;
     247             :         }
     248             :         return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
     249             : }
     250             : #endif
     251             : 
     252             : SYSCALL_DEFINE4(utimensat_time32, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags)
     253             : {
     254             :         struct timespec64 tv[2];
     255             : 
     256             :         if  (t) {
     257             :                 if (get_old_timespec32(&tv[0], &t[0]) ||
     258             :                     get_old_timespec32(&tv[1], &t[1]))
     259             :                         return -EFAULT;
     260             : 
     261             :                 if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
     262             :                         return 0;
     263             :         }
     264             :         return do_utimes(dfd, filename, t ? tv : NULL, flags);
     265             : }
     266             : 
     267             : #ifdef __ARCH_WANT_SYS_UTIME32
     268             : static long do_compat_futimesat(unsigned int dfd, const char __user *filename,
     269             :                                 struct old_timeval32 __user *t)
     270             : {
     271             :         struct timespec64 tv[2];
     272             : 
     273             :         if (t) {
     274             :                 if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
     275             :                     get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
     276             :                     get_user(tv[1].tv_sec, &t[1].tv_sec) ||
     277             :                     get_user(tv[1].tv_nsec, &t[1].tv_usec))
     278             :                         return -EFAULT;
     279             :                 if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
     280             :                     tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
     281             :                         return -EINVAL;
     282             :                 tv[0].tv_nsec *= 1000;
     283             :                 tv[1].tv_nsec *= 1000;
     284             :         }
     285             :         return do_utimes(dfd, filename, t ? tv : NULL, 0);
     286             : }
     287             : 
     288             : SYSCALL_DEFINE3(futimesat_time32, unsigned int, dfd,
     289             :                        const char __user *, filename,
     290             :                        struct old_timeval32 __user *, t)
     291             : {
     292             :         return do_compat_futimesat(dfd, filename, t);
     293             : }
     294             : 
     295             : SYSCALL_DEFINE2(utimes_time32, const char __user *, filename, struct old_timeval32 __user *, t)
     296             : {
     297             :         return do_compat_futimesat(AT_FDCWD, filename, t);
     298             : }
     299             : #endif
     300             : #endif

Generated by: LCOV version 1.14