1 #include <linux/compiler.h> 2 #include <linux/file.h> 3 #include <linux/fs.h> 4 #include <linux/linkage.h> 5 #include <linux/mount.h> 6 #include <linux/namei.h> 7 #include <linux/sched.h> 8 #include <linux/stat.h> 9 #include <linux/utime.h> 10 #include <linux/syscalls.h> 11 #include <asm/uaccess.h> 12 #include <asm/unistd.h> 13 14 #ifdef __ARCH_WANT_SYS_UTIME 15 16 /* 17 * sys_utime() can be implemented in user-level using sys_utimes(). 18 * Is this for backwards compatibility? If so, why not move it 19 * into the appropriate arch directory (for those architectures that 20 * need it). 21 */ 22 23 /* If times==NULL, set access and modification to current time, 24 * must be owner or have write permission. 25 * Else, update from *times, must be owner or super user. 26 */ 27 asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times) 28 { 29 struct timespec tv[2]; 30 31 if (times) { 32 if (get_user(tv[0].tv_sec, ×->actime) || 33 get_user(tv[1].tv_sec, ×->modtime)) 34 return -EFAULT; 35 tv[0].tv_nsec = 0; 36 tv[1].tv_nsec = 0; 37 } 38 return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); 39 } 40 41 #endif 42 43 static bool nsec_valid(long nsec) 44 { 45 if (nsec == UTIME_OMIT || nsec == UTIME_NOW) 46 return true; 47 48 return nsec >= 0 && nsec <= 999999999; 49 } 50 51 /* If times==NULL, set access and modification to current time, 52 * must be owner or have write permission. 53 * Else, update from *times, must be owner or super user. 54 */ 55 long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) 56 { 57 int error; 58 struct nameidata nd; 59 struct dentry *dentry; 60 struct inode *inode; 61 struct iattr newattrs; 62 struct file *f = NULL; 63 struct vfsmount *mnt; 64 65 error = -EINVAL; 66 if (times && (!nsec_valid(times[0].tv_nsec) || 67 !nsec_valid(times[1].tv_nsec))) { 68 goto out; 69 } 70 71 if (flags & ~AT_SYMLINK_NOFOLLOW) 72 goto out; 73 74 if (filename == NULL && dfd != AT_FDCWD) { 75 error = -EINVAL; 76 if (flags & AT_SYMLINK_NOFOLLOW) 77 goto out; 78 79 error = -EBADF; 80 f = fget(dfd); 81 if (!f) 82 goto out; 83 dentry = f->f_path.dentry; 84 mnt = f->f_path.mnt; 85 } else { 86 error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd); 87 if (error) 88 goto out; 89 90 dentry = nd.path.dentry; 91 mnt = nd.path.mnt; 92 } 93 94 inode = dentry->d_inode; 95 96 error = mnt_want_write(mnt); 97 if (error) 98 goto dput_and_out; 99 100 if (times && times[0].tv_nsec == UTIME_NOW && 101 times[1].tv_nsec == UTIME_NOW) 102 times = NULL; 103 104 /* In most cases, the checks are done in inode_change_ok() */ 105 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 106 if (times) { 107 error = -EPERM; 108 if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 109 goto mnt_drop_write_and_out; 110 111 if (times[0].tv_nsec == UTIME_OMIT) 112 newattrs.ia_valid &= ~ATTR_ATIME; 113 else if (times[0].tv_nsec != UTIME_NOW) { 114 newattrs.ia_atime.tv_sec = times[0].tv_sec; 115 newattrs.ia_atime.tv_nsec = times[0].tv_nsec; 116 newattrs.ia_valid |= ATTR_ATIME_SET; 117 } 118 119 if (times[1].tv_nsec == UTIME_OMIT) 120 newattrs.ia_valid &= ~ATTR_MTIME; 121 else if (times[1].tv_nsec != UTIME_NOW) { 122 newattrs.ia_mtime.tv_sec = times[1].tv_sec; 123 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; 124 newattrs.ia_valid |= ATTR_MTIME_SET; 125 } 126 127 /* 128 * For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT 129 * cases, we need to make an extra check that is not done by 130 * inode_change_ok(). 131 */ 132 if (((times[0].tv_nsec == UTIME_NOW && 133 times[1].tv_nsec == UTIME_OMIT) 134 || 135 (times[0].tv_nsec == UTIME_OMIT && 136 times[1].tv_nsec == UTIME_NOW)) 137 && !is_owner_or_cap(inode)) 138 goto mnt_drop_write_and_out; 139 } else { 140 141 /* 142 * If times is NULL (or both times are UTIME_NOW), 143 * then we need to check permissions, because 144 * inode_change_ok() won't do it. 145 */ 146 error = -EACCES; 147 if (IS_IMMUTABLE(inode)) 148 goto mnt_drop_write_and_out; 149 150 if (!is_owner_or_cap(inode)) { 151 error = permission(inode, MAY_WRITE, NULL); 152 if (error) 153 goto mnt_drop_write_and_out; 154 } 155 } 156 mutex_lock(&inode->i_mutex); 157 error = notify_change(dentry, &newattrs); 158 mutex_unlock(&inode->i_mutex); 159 mnt_drop_write_and_out: 160 mnt_drop_write(mnt); 161 dput_and_out: 162 if (f) 163 fput(f); 164 else 165 path_put(&nd.path); 166 out: 167 return error; 168 } 169 170 asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __user *utimes, int flags) 171 { 172 struct timespec tstimes[2]; 173 174 if (utimes) { 175 if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) 176 return -EFAULT; 177 178 /* Nothing to do, we must not even check the path. */ 179 if (tstimes[0].tv_nsec == UTIME_OMIT && 180 tstimes[1].tv_nsec == UTIME_OMIT) 181 return 0; 182 } 183 184 return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); 185 } 186 187 asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) 188 { 189 struct timeval times[2]; 190 struct timespec 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 asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) 215 { 216 return sys_futimesat(AT_FDCWD, filename, utimes); 217 } 218