1 #include <linux/file.h> 2 #include <linux/mount.h> 3 #include <linux/namei.h> 4 #include <linux/utime.h> 5 #include <linux/syscalls.h> 6 #include <linux/uaccess.h> 7 #include <linux/compat.h> 8 #include <asm/unistd.h> 9 10 #ifdef __ARCH_WANT_SYS_UTIME 11 12 /* 13 * sys_utime() can be implemented in user-level using sys_utimes(). 14 * Is this for backwards compatibility? If so, why not move it 15 * into the appropriate arch directory (for those architectures that 16 * need it). 17 */ 18 19 /* If times==NULL, set access and modification to current time, 20 * must be owner or have write permission. 21 * Else, update from *times, must be owner or super user. 22 */ 23 SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) 24 { 25 struct timespec64 tv[2]; 26 27 if (times) { 28 if (get_user(tv[0].tv_sec, ×->actime) || 29 get_user(tv[1].tv_sec, ×->modtime)) 30 return -EFAULT; 31 tv[0].tv_nsec = 0; 32 tv[1].tv_nsec = 0; 33 } 34 return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); 35 } 36 37 #endif 38 39 static bool nsec_valid(long nsec) 40 { 41 if (nsec == UTIME_OMIT || nsec == UTIME_NOW) 42 return true; 43 44 return nsec >= 0 && nsec <= 999999999; 45 } 46 47 static int utimes_common(const struct path *path, struct timespec64 *times) 48 { 49 int error; 50 struct iattr newattrs; 51 struct inode *inode = path->dentry->d_inode; 52 struct inode *delegated_inode = NULL; 53 54 error = mnt_want_write(path->mnt); 55 if (error) 56 goto out; 57 58 if (times && times[0].tv_nsec == UTIME_NOW && 59 times[1].tv_nsec == UTIME_NOW) 60 times = NULL; 61 62 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 63 if (times) { 64 if (times[0].tv_nsec == UTIME_OMIT) 65 newattrs.ia_valid &= ~ATTR_ATIME; 66 else if (times[0].tv_nsec != UTIME_NOW) { 67 newattrs.ia_atime.tv_sec = times[0].tv_sec; 68 newattrs.ia_atime.tv_nsec = times[0].tv_nsec; 69 newattrs.ia_valid |= ATTR_ATIME_SET; 70 } 71 72 if (times[1].tv_nsec == UTIME_OMIT) 73 newattrs.ia_valid &= ~ATTR_MTIME; 74 else if (times[1].tv_nsec != UTIME_NOW) { 75 newattrs.ia_mtime.tv_sec = times[1].tv_sec; 76 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; 77 newattrs.ia_valid |= ATTR_MTIME_SET; 78 } 79 /* 80 * Tell setattr_prepare(), that this is an explicit time 81 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET 82 * were used. 83 */ 84 newattrs.ia_valid |= ATTR_TIMES_SET; 85 } else { 86 newattrs.ia_valid |= ATTR_TOUCH; 87 } 88 retry_deleg: 89 inode_lock(inode); 90 error = notify_change(path->dentry, &newattrs, &delegated_inode); 91 inode_unlock(inode); 92 if (delegated_inode) { 93 error = break_deleg_wait(&delegated_inode); 94 if (!error) 95 goto retry_deleg; 96 } 97 98 mnt_drop_write(path->mnt); 99 out: 100 return error; 101 } 102 103 /* 104 * do_utimes - change times on filename or file descriptor 105 * @dfd: open file descriptor, -1 or AT_FDCWD 106 * @filename: path name or NULL 107 * @times: new times or NULL 108 * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) 109 * 110 * If filename is NULL and dfd refers to an open file, then operate on 111 * the file. Otherwise look up filename, possibly using dfd as a 112 * starting point. 113 * 114 * If times==NULL, set access and modification to current time, 115 * must be owner or have write permission. 116 * Else, update from *times, must be owner or super user. 117 */ 118 long do_utimes(int dfd, const char __user *filename, struct timespec64 *times, 119 int flags) 120 { 121 int error = -EINVAL; 122 123 if (times && (!nsec_valid(times[0].tv_nsec) || 124 !nsec_valid(times[1].tv_nsec))) { 125 goto out; 126 } 127 128 if (flags & ~AT_SYMLINK_NOFOLLOW) 129 goto out; 130 131 if (filename == NULL && dfd != AT_FDCWD) { 132 struct fd f; 133 134 if (flags & AT_SYMLINK_NOFOLLOW) 135 goto out; 136 137 f = fdget(dfd); 138 error = -EBADF; 139 if (!f.file) 140 goto out; 141 142 error = utimes_common(&f.file->f_path, times); 143 fdput(f); 144 } else { 145 struct path path; 146 int lookup_flags = 0; 147 148 if (!(flags & AT_SYMLINK_NOFOLLOW)) 149 lookup_flags |= LOOKUP_FOLLOW; 150 retry: 151 error = user_path_at(dfd, filename, lookup_flags, &path); 152 if (error) 153 goto out; 154 155 error = utimes_common(&path, times); 156 path_put(&path); 157 if (retry_estale(error, lookup_flags)) { 158 lookup_flags |= LOOKUP_REVAL; 159 goto retry; 160 } 161 } 162 163 out: 164 return error; 165 } 166 167 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, 168 struct timespec __user *, utimes, int, flags) 169 { 170 struct timespec64 tstimes[2]; 171 172 if (utimes) { 173 if ((get_timespec64(&tstimes[0], &utimes[0]) || 174 get_timespec64(&tstimes[1], &utimes[1]))) 175 return -EFAULT; 176 177 /* Nothing to do, we must not even check the path. */ 178 if (tstimes[0].tv_nsec == UTIME_OMIT && 179 tstimes[1].tv_nsec == UTIME_OMIT) 180 return 0; 181 } 182 183 return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); 184 } 185 186 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, 187 struct timeval __user *, utimes) 188 { 189 struct timeval times[2]; 190 struct timespec64 tstimes[2]; 191 192 if (utimes) { 193 if (copy_from_user(×, utimes, sizeof(times))) 194 return -EFAULT; 195 196 /* This test is needed to catch all invalid values. If we 197 would test only in do_utimes we would miss those invalid 198 values truncated by the multiplication with 1000. Note 199 that we also catch UTIME_{NOW,OMIT} here which are only 200 valid for utimensat. */ 201 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || 202 times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) 203 return -EINVAL; 204 205 tstimes[0].tv_sec = times[0].tv_sec; 206 tstimes[0].tv_nsec = 1000 * times[0].tv_usec; 207 tstimes[1].tv_sec = times[1].tv_sec; 208 tstimes[1].tv_nsec = 1000 * times[1].tv_usec; 209 } 210 211 return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); 212 } 213 214 SYSCALL_DEFINE2(utimes, char __user *, filename, 215 struct timeval __user *, utimes) 216 { 217 return sys_futimesat(AT_FDCWD, filename, utimes); 218 } 219 220 #ifdef CONFIG_COMPAT 221 /* 222 * Not all architectures have sys_utime, so implement this in terms 223 * of sys_utimes. 224 */ 225 COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, 226 struct compat_utimbuf __user *, t) 227 { 228 struct timespec64 tv[2]; 229 230 if (t) { 231 if (get_user(tv[0].tv_sec, &t->actime) || 232 get_user(tv[1].tv_sec, &t->modtime)) 233 return -EFAULT; 234 tv[0].tv_nsec = 0; 235 tv[1].tv_nsec = 0; 236 } 237 return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); 238 } 239 240 COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags) 241 { 242 struct timespec64 tv[2]; 243 244 if (t) { 245 if (compat_get_timespec64(&tv[0], &t[0]) || 246 compat_get_timespec64(&tv[1], &t[1])) 247 return -EFAULT; 248 249 if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) 250 return 0; 251 } 252 return do_utimes(dfd, filename, t ? tv : NULL, flags); 253 } 254 255 COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, struct compat_timeval __user *, t) 256 { 257 struct timespec64 tv[2]; 258 259 if (t) { 260 if (get_user(tv[0].tv_sec, &t[0].tv_sec) || 261 get_user(tv[0].tv_nsec, &t[0].tv_usec) || 262 get_user(tv[1].tv_sec, &t[1].tv_sec) || 263 get_user(tv[1].tv_nsec, &t[1].tv_usec)) 264 return -EFAULT; 265 if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 || 266 tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0) 267 return -EINVAL; 268 tv[0].tv_nsec *= 1000; 269 tv[1].tv_nsec *= 1000; 270 } 271 return do_utimes(dfd, filename, t ? tv : NULL, 0); 272 } 273 274 COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t) 275 { 276 return compat_sys_futimesat(AT_FDCWD, filename, t); 277 } 278 #endif 279