Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/file.h>
0003 #include <linux/mount.h>
0004 #include <linux/namei.h>
0005 #include <linux/utime.h>
0006 #include <linux/syscalls.h>
0007 #include <linux/uaccess.h>
0008 #include <linux/compat.h>
0009 #include <asm/unistd.h>
0010 
0011 static bool nsec_valid(long nsec)
0012 {
0013     if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
0014         return true;
0015 
0016     return nsec >= 0 && nsec <= 999999999;
0017 }
0018 
0019 int vfs_utimes(const struct path *path, struct timespec64 *times)
0020 {
0021     int error;
0022     struct iattr newattrs;
0023     struct inode *inode = path->dentry->d_inode;
0024     struct inode *delegated_inode = NULL;
0025 
0026     if (times) {
0027         if (!nsec_valid(times[0].tv_nsec) ||
0028             !nsec_valid(times[1].tv_nsec))
0029             return -EINVAL;
0030         if (times[0].tv_nsec == UTIME_NOW &&
0031             times[1].tv_nsec == UTIME_NOW)
0032             times = NULL;
0033     }
0034 
0035     error = mnt_want_write(path->mnt);
0036     if (error)
0037         goto out;
0038 
0039     newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
0040     if (times) {
0041         if (times[0].tv_nsec == UTIME_OMIT)
0042             newattrs.ia_valid &= ~ATTR_ATIME;
0043         else if (times[0].tv_nsec != UTIME_NOW) {
0044             newattrs.ia_atime = times[0];
0045             newattrs.ia_valid |= ATTR_ATIME_SET;
0046         }
0047 
0048         if (times[1].tv_nsec == UTIME_OMIT)
0049             newattrs.ia_valid &= ~ATTR_MTIME;
0050         else if (times[1].tv_nsec != UTIME_NOW) {
0051             newattrs.ia_mtime = times[1];
0052             newattrs.ia_valid |= ATTR_MTIME_SET;
0053         }
0054         /*
0055          * Tell setattr_prepare(), that this is an explicit time
0056          * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
0057          * were used.
0058          */
0059         newattrs.ia_valid |= ATTR_TIMES_SET;
0060     } else {
0061         newattrs.ia_valid |= ATTR_TOUCH;
0062     }
0063 retry_deleg:
0064     inode_lock(inode);
0065     error = notify_change(mnt_user_ns(path->mnt), path->dentry, &newattrs,
0066                   &delegated_inode);
0067     inode_unlock(inode);
0068     if (delegated_inode) {
0069         error = break_deleg_wait(&delegated_inode);
0070         if (!error)
0071             goto retry_deleg;
0072     }
0073 
0074     mnt_drop_write(path->mnt);
0075 out:
0076     return error;
0077 }
0078 
0079 static int do_utimes_path(int dfd, const char __user *filename,
0080         struct timespec64 *times, int flags)
0081 {
0082     struct path path;
0083     int lookup_flags = 0, error;
0084 
0085     if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
0086         return -EINVAL;
0087 
0088     if (!(flags & AT_SYMLINK_NOFOLLOW))
0089         lookup_flags |= LOOKUP_FOLLOW;
0090     if (flags & AT_EMPTY_PATH)
0091         lookup_flags |= LOOKUP_EMPTY;
0092 
0093 retry:
0094     error = user_path_at(dfd, filename, lookup_flags, &path);
0095     if (error)
0096         return error;
0097 
0098     error = vfs_utimes(&path, times);
0099     path_put(&path);
0100     if (retry_estale(error, lookup_flags)) {
0101         lookup_flags |= LOOKUP_REVAL;
0102         goto retry;
0103     }
0104 
0105     return error;
0106 }
0107 
0108 static int do_utimes_fd(int fd, struct timespec64 *times, int flags)
0109 {
0110     struct fd f;
0111     int error;
0112 
0113     if (flags)
0114         return -EINVAL;
0115 
0116     f = fdget(fd);
0117     if (!f.file)
0118         return -EBADF;
0119     error = vfs_utimes(&f.file->f_path, times);
0120     fdput(f);
0121     return error;
0122 }
0123 
0124 /*
0125  * do_utimes - change times on filename or file descriptor
0126  * @dfd: open file descriptor, -1 or AT_FDCWD
0127  * @filename: path name or NULL
0128  * @times: new times or NULL
0129  * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment)
0130  *
0131  * If filename is NULL and dfd refers to an open file, then operate on
0132  * the file.  Otherwise look up filename, possibly using dfd as a
0133  * starting point.
0134  *
0135  * If times==NULL, set access and modification to current time,
0136  * must be owner or have write permission.
0137  * Else, update from *times, must be owner or super user.
0138  */
0139 long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
0140            int flags)
0141 {
0142     if (filename == NULL && dfd != AT_FDCWD)
0143         return do_utimes_fd(dfd, times, flags);
0144     return do_utimes_path(dfd, filename, times, flags);
0145 }
0146 
0147 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
0148         struct __kernel_timespec __user *, utimes, int, flags)
0149 {
0150     struct timespec64 tstimes[2];
0151 
0152     if (utimes) {
0153         if ((get_timespec64(&tstimes[0], &utimes[0]) ||
0154             get_timespec64(&tstimes[1], &utimes[1])))
0155             return -EFAULT;
0156 
0157         /* Nothing to do, we must not even check the path.  */
0158         if (tstimes[0].tv_nsec == UTIME_OMIT &&
0159             tstimes[1].tv_nsec == UTIME_OMIT)
0160             return 0;
0161     }
0162 
0163     return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
0164 }
0165 
0166 #ifdef __ARCH_WANT_SYS_UTIME
0167 /*
0168  * futimesat(), utimes() and utime() are older versions of utimensat()
0169  * that are provided for compatibility with traditional C libraries.
0170  * On modern architectures, we always use libc wrappers around
0171  * utimensat() instead.
0172  */
0173 static long do_futimesat(int dfd, const char __user *filename,
0174              struct __kernel_old_timeval __user *utimes)
0175 {
0176     struct __kernel_old_timeval times[2];
0177     struct timespec64 tstimes[2];
0178 
0179     if (utimes) {
0180         if (copy_from_user(&times, utimes, sizeof(times)))
0181             return -EFAULT;
0182 
0183         /* This test is needed to catch all invalid values.  If we
0184            would test only in do_utimes we would miss those invalid
0185            values truncated by the multiplication with 1000.  Note
0186            that we also catch UTIME_{NOW,OMIT} here which are only
0187            valid for utimensat.  */
0188         if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
0189             times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
0190             return -EINVAL;
0191 
0192         tstimes[0].tv_sec = times[0].tv_sec;
0193         tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
0194         tstimes[1].tv_sec = times[1].tv_sec;
0195         tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
0196     }
0197 
0198     return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
0199 }
0200 
0201 
0202 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename,
0203         struct __kernel_old_timeval __user *, utimes)
0204 {
0205     return do_futimesat(dfd, filename, utimes);
0206 }
0207 
0208 SYSCALL_DEFINE2(utimes, char __user *, filename,
0209         struct __kernel_old_timeval __user *, utimes)
0210 {
0211     return do_futimesat(AT_FDCWD, filename, utimes);
0212 }
0213 
0214 SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
0215 {
0216     struct timespec64 tv[2];
0217 
0218     if (times) {
0219         if (get_user(tv[0].tv_sec, &times->actime) ||
0220             get_user(tv[1].tv_sec, &times->modtime))
0221             return -EFAULT;
0222         tv[0].tv_nsec = 0;
0223         tv[1].tv_nsec = 0;
0224     }
0225     return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
0226 }
0227 #endif
0228 
0229 #ifdef CONFIG_COMPAT_32BIT_TIME
0230 /*
0231  * Not all architectures have sys_utime, so implement this in terms
0232  * of sys_utimes.
0233  */
0234 #ifdef __ARCH_WANT_SYS_UTIME32
0235 SYSCALL_DEFINE2(utime32, const char __user *, filename,
0236         struct old_utimbuf32 __user *, t)
0237 {
0238     struct timespec64 tv[2];
0239 
0240     if (t) {
0241         if (get_user(tv[0].tv_sec, &t->actime) ||
0242             get_user(tv[1].tv_sec, &t->modtime))
0243             return -EFAULT;
0244         tv[0].tv_nsec = 0;
0245         tv[1].tv_nsec = 0;
0246     }
0247     return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
0248 }
0249 #endif
0250 
0251 SYSCALL_DEFINE4(utimensat_time32, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags)
0252 {
0253     struct timespec64 tv[2];
0254 
0255     if  (t) {
0256         if (get_old_timespec32(&tv[0], &t[0]) ||
0257             get_old_timespec32(&tv[1], &t[1]))
0258             return -EFAULT;
0259 
0260         if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
0261             return 0;
0262     }
0263     return do_utimes(dfd, filename, t ? tv : NULL, flags);
0264 }
0265 
0266 #ifdef __ARCH_WANT_SYS_UTIME32
0267 static long do_compat_futimesat(unsigned int dfd, const char __user *filename,
0268                 struct old_timeval32 __user *t)
0269 {
0270     struct timespec64 tv[2];
0271 
0272     if (t) {
0273         if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
0274             get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
0275             get_user(tv[1].tv_sec, &t[1].tv_sec) ||
0276             get_user(tv[1].tv_nsec, &t[1].tv_usec))
0277             return -EFAULT;
0278         if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
0279             tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
0280             return -EINVAL;
0281         tv[0].tv_nsec *= 1000;
0282         tv[1].tv_nsec *= 1000;
0283     }
0284     return do_utimes(dfd, filename, t ? tv : NULL, 0);
0285 }
0286 
0287 SYSCALL_DEFINE3(futimesat_time32, unsigned int, dfd,
0288                const char __user *, filename,
0289                struct old_timeval32 __user *, t)
0290 {
0291     return do_compat_futimesat(dfd, filename, t);
0292 }
0293 
0294 SYSCALL_DEFINE2(utimes_time32, const char __user *, filename, struct old_timeval32 __user *, t)
0295 {
0296     return do_compat_futimesat(AT_FDCWD, filename, t);
0297 }
0298 #endif
0299 #endif