Blame view
fs/utimes.c
7.32 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
1c710c896 utimensat impleme... |
2 |
#include <linux/file.h> |
74f9fdfa1 [PATCH] r/o bind ... |
3 |
#include <linux/mount.h> |
82b0547cf [PATCH] Create fs... |
4 5 |
#include <linux/namei.h> #include <linux/utime.h> |
12c2ab5e8 fs/utimes.c shoul... |
6 |
#include <linux/syscalls.h> |
7c0f6ba68 Replace <asm/uacc... |
7 |
#include <linux/uaccess.h> |
1a060ba3c utimes: move comp... |
8 |
#include <linux/compat.h> |
82b0547cf [PATCH] Create fs... |
9 |
#include <asm/unistd.h> |
043f46f61 VFS: check nanose... |
10 11 |
static bool nsec_valid(long nsec) { |
4cca92264 [patch for 2.6.26... |
12 |
if (nsec == UTIME_OMIT || nsec == UTIME_NOW) |
043f46f61 VFS: check nanose... |
13 14 15 16 |
return true; return nsec >= 0 && nsec <= 999999999; } |
aaed2dd8a utimes: Make utim... |
17 |
static int utimes_common(const struct path *path, struct timespec64 *times) |
82b0547cf [PATCH] Create fs... |
18 19 |
{ int error; |
82b0547cf [PATCH] Create fs... |
20 |
struct iattr newattrs; |
e9b76fedc [patch 2/4] vfs: ... |
21 |
struct inode *inode = path->dentry->d_inode; |
27ac0ffea locks: break dele... |
22 |
struct inode *delegated_inode = NULL; |
82b0547cf [PATCH] Create fs... |
23 |
|
e9b76fedc [patch 2/4] vfs: ... |
24 |
error = mnt_want_write(path->mnt); |
74f9fdfa1 [PATCH] r/o bind ... |
25 |
if (error) |
e9b76fedc [patch 2/4] vfs: ... |
26 |
goto out; |
82b0547cf [PATCH] Create fs... |
27 |
|
12fd0d308 [patch for 2.6.26... |
28 29 30 |
if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) times = NULL; |
82b0547cf [PATCH] Create fs... |
31 32 |
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { |
1c710c896 utimensat impleme... |
33 34 35 |
if (times[0].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_ATIME; else if (times[0].tv_nsec != UTIME_NOW) { |
eb31e2f63 utimes: Clamp the... |
36 |
newattrs.ia_atime = times[0]; |
1c710c896 utimensat impleme... |
37 38 39 40 41 42 |
newattrs.ia_valid |= ATTR_ATIME_SET; } if (times[1].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_MTIME; else if (times[1].tv_nsec != UTIME_NOW) { |
eb31e2f63 utimes: Clamp the... |
43 |
newattrs.ia_mtime = times[1]; |
1c710c896 utimensat impleme... |
44 45 |
newattrs.ia_valid |= ATTR_MTIME_SET; } |
4cca92264 [patch for 2.6.26... |
46 |
/* |
31051c85b fs: Give dentry t... |
47 |
* Tell setattr_prepare(), that this is an explicit time |
9767d7495 [patch 1/4] vfs: ... |
48 49 |
* update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET * were used. |
4cca92264 [patch for 2.6.26... |
50 |
*/ |
9767d7495 [patch 1/4] vfs: ... |
51 |
newattrs.ia_valid |= ATTR_TIMES_SET; |
4cca92264 [patch for 2.6.26... |
52 |
} else { |
f2b20f6ee vfs: move permiss... |
53 |
newattrs.ia_valid |= ATTR_TOUCH; |
82b0547cf [PATCH] Create fs... |
54 |
} |
27ac0ffea locks: break dele... |
55 |
retry_deleg: |
5955102c9 wrappers for ->i_... |
56 |
inode_lock(inode); |
27ac0ffea locks: break dele... |
57 |
error = notify_change(path->dentry, &newattrs, &delegated_inode); |
5955102c9 wrappers for ->i_... |
58 |
inode_unlock(inode); |
27ac0ffea locks: break dele... |
59 60 61 62 63 |
if (delegated_inode) { error = break_deleg_wait(&delegated_inode); if (!error) goto retry_deleg; } |
e9b76fedc [patch 2/4] vfs: ... |
64 |
|
e9b76fedc [patch 2/4] vfs: ... |
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
mnt_drop_write(path->mnt); out: return error; } /* * do_utimes - change times on filename or file descriptor * @dfd: open file descriptor, -1 or AT_FDCWD * @filename: path name or NULL * @times: new times or NULL * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) * * If filename is NULL and dfd refers to an open file, then operate on * the file. Otherwise look up filename, possibly using dfd as a * starting point. * * If times==NULL, set access and modification to current time, * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ |
aaed2dd8a utimes: Make utim... |
85 |
long do_utimes(int dfd, const char __user *filename, struct timespec64 *times, |
c78873252 Mark arguments to... |
86 |
int flags) |
e9b76fedc [patch 2/4] vfs: ... |
87 88 89 90 91 92 93 94 95 96 97 98 |
{ int error = -EINVAL; if (times && (!nsec_valid(times[0].tv_nsec) || !nsec_valid(times[1].tv_nsec))) { goto out; } if (flags & ~AT_SYMLINK_NOFOLLOW) goto out; if (filename == NULL && dfd != AT_FDCWD) { |
2903ff019 switch simple cas... |
99 |
struct fd f; |
e9b76fedc [patch 2/4] vfs: ... |
100 101 102 |
if (flags & AT_SYMLINK_NOFOLLOW) goto out; |
2903ff019 switch simple cas... |
103 |
f = fdget(dfd); |
e9b76fedc [patch 2/4] vfs: ... |
104 |
error = -EBADF; |
2903ff019 switch simple cas... |
105 |
if (!f.file) |
e9b76fedc [patch 2/4] vfs: ... |
106 |
goto out; |
2903ff019 switch simple cas... |
107 108 |
error = utimes_common(&f.file->f_path, times); fdput(f); |
e9b76fedc [patch 2/4] vfs: ... |
109 |
} else { |
2d8f30380 [PATCH] sanitize ... |
110 |
struct path path; |
e9b76fedc [patch 2/4] vfs: ... |
111 112 113 114 |
int lookup_flags = 0; if (!(flags & AT_SYMLINK_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; |
a69201d6f vfs: allow utimen... |
115 |
retry: |
2d8f30380 [PATCH] sanitize ... |
116 |
error = user_path_at(dfd, filename, lookup_flags, &path); |
e9b76fedc [patch 2/4] vfs: ... |
117 118 |
if (error) goto out; |
2d8f30380 [PATCH] sanitize ... |
119 120 |
error = utimes_common(&path, times); path_put(&path); |
a69201d6f vfs: allow utimen... |
121 122 123 124 |
if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; goto retry; } |
e9b76fedc [patch 2/4] vfs: ... |
125 |
} |
82b0547cf [PATCH] Create fs... |
126 127 128 |
out: return error; } |
c78873252 Mark arguments to... |
129 |
SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, |
a4f7a3004 y2038: Change sys... |
130 |
struct __kernel_timespec __user *, utimes, int, flags) |
1c710c896 utimensat impleme... |
131 |
{ |
aaed2dd8a utimes: Make utim... |
132 |
struct timespec64 tstimes[2]; |
1c710c896 utimensat impleme... |
133 134 |
if (utimes) { |
aaed2dd8a utimes: Make utim... |
135 136 |
if ((get_timespec64(&tstimes[0], &utimes[0]) || get_timespec64(&tstimes[1], &utimes[1]))) |
1c710c896 utimensat impleme... |
137 |
return -EFAULT; |
1c710c896 utimensat impleme... |
138 139 140 141 142 143 144 145 146 |
/* Nothing to do, we must not even check the path. */ if (tstimes[0].tv_nsec == UTIME_OMIT && tstimes[1].tv_nsec == UTIME_OMIT) return 0; } return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); } |
185cfaf76 y2038: Compile ut... |
147 148 149 150 151 152 153 |
#ifdef __ARCH_WANT_SYS_UTIME /* * futimesat(), utimes() and utime() are older versions of utimensat() * that are provided for compatibility with traditional C libraries. * On modern architectures, we always use libc wrappers around * utimensat() instead. */ |
f13903587 fs: add do_futime... |
154 |
static long do_futimesat(int dfd, const char __user *filename, |
75d319c06 y2038: syscalls: ... |
155 |
struct __kernel_old_timeval __user *utimes) |
82b0547cf [PATCH] Create fs... |
156 |
{ |
75d319c06 y2038: syscalls: ... |
157 |
struct __kernel_old_timeval times[2]; |
aaed2dd8a utimes: Make utim... |
158 |
struct timespec64 tstimes[2]; |
1c710c896 utimensat impleme... |
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
if (utimes) { if (copy_from_user(×, utimes, sizeof(times))) return -EFAULT; /* This test is needed to catch all invalid values. If we would test only in do_utimes we would miss those invalid values truncated by the multiplication with 1000. Note that we also catch UTIME_{NOW,OMIT} here which are only valid for utimensat. */ if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) return -EINVAL; tstimes[0].tv_sec = times[0].tv_sec; tstimes[0].tv_nsec = 1000 * times[0].tv_usec; tstimes[1].tv_sec = times[1].tv_sec; tstimes[1].tv_nsec = 1000 * times[1].tv_usec; } |
82b0547cf [PATCH] Create fs... |
178 |
|
1c710c896 utimensat impleme... |
179 |
return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); |
82b0547cf [PATCH] Create fs... |
180 |
} |
f13903587 fs: add do_futime... |
181 182 |
SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, |
75d319c06 y2038: syscalls: ... |
183 |
struct __kernel_old_timeval __user *, utimes) |
f13903587 fs: add do_futime... |
184 185 186 |
{ return do_futimesat(dfd, filename, utimes); } |
003d7ab47 [CVE-2009-0029] S... |
187 |
SYSCALL_DEFINE2(utimes, char __user *, filename, |
75d319c06 y2038: syscalls: ... |
188 |
struct __kernel_old_timeval __user *, utimes) |
82b0547cf [PATCH] Create fs... |
189 |
{ |
f13903587 fs: add do_futime... |
190 |
return do_futimesat(AT_FDCWD, filename, utimes); |
82b0547cf [PATCH] Create fs... |
191 |
} |
1a060ba3c utimes: move comp... |
192 |
|
185cfaf76 y2038: Compile ut... |
193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) { struct timespec64 tv[2]; if (times) { if (get_user(tv[0].tv_sec, ×->actime) || get_user(tv[1].tv_sec, ×->modtime)) return -EFAULT; tv[0].tv_nsec = 0; tv[1].tv_nsec = 0; } return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); } #endif |
4faea239e y2038: utimes: Re... |
207 |
#ifdef CONFIG_COMPAT_32BIT_TIME |
1a060ba3c utimes: move comp... |
208 209 210 211 |
/* * Not all architectures have sys_utime, so implement this in terms * of sys_utimes. */ |
4faea239e y2038: utimes: Re... |
212 |
#ifdef __ARCH_WANT_SYS_UTIME32 |
8dabe7245 y2038: syscalls: ... |
213 214 |
SYSCALL_DEFINE2(utime32, const char __user *, filename, struct old_utimbuf32 __user *, t) |
1a060ba3c utimes: move comp... |
215 |
{ |
aaed2dd8a utimes: Make utim... |
216 |
struct timespec64 tv[2]; |
1a060ba3c utimes: move comp... |
217 218 219 220 221 222 223 224 225 226 |
if (t) { if (get_user(tv[0].tv_sec, &t->actime) || get_user(tv[1].tv_sec, &t->modtime)) return -EFAULT; tv[0].tv_nsec = 0; tv[1].tv_nsec = 0; } return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); } |
4faea239e y2038: utimes: Re... |
227 |
#endif |
1a060ba3c utimes: move comp... |
228 |
|
8dabe7245 y2038: syscalls: ... |
229 |
SYSCALL_DEFINE4(utimensat_time32, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags) |
1a060ba3c utimes: move comp... |
230 |
{ |
aaed2dd8a utimes: Make utim... |
231 |
struct timespec64 tv[2]; |
1a060ba3c utimes: move comp... |
232 233 |
if (t) { |
9afc5eee6 y2038: globally r... |
234 235 |
if (get_old_timespec32(&tv[0], &t[0]) || get_old_timespec32(&tv[1], &t[1])) |
1a060ba3c utimes: move comp... |
236 237 238 239 240 241 242 |
return -EFAULT; if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) return 0; } return do_utimes(dfd, filename, t ? tv : NULL, flags); } |
4faea239e y2038: utimes: Re... |
243 |
#ifdef __ARCH_WANT_SYS_UTIME32 |
ab641afa7 fs: add do_compat... |
244 |
static long do_compat_futimesat(unsigned int dfd, const char __user *filename, |
9afc5eee6 y2038: globally r... |
245 |
struct old_timeval32 __user *t) |
1a060ba3c utimes: move comp... |
246 |
{ |
aaed2dd8a utimes: Make utim... |
247 |
struct timespec64 tv[2]; |
1a060ba3c utimes: move comp... |
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
if (t) { if (get_user(tv[0].tv_sec, &t[0].tv_sec) || get_user(tv[0].tv_nsec, &t[0].tv_usec) || get_user(tv[1].tv_sec, &t[1].tv_sec) || get_user(tv[1].tv_nsec, &t[1].tv_usec)) return -EFAULT; if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 || tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0) return -EINVAL; tv[0].tv_nsec *= 1000; tv[1].tv_nsec *= 1000; } return do_utimes(dfd, filename, t ? tv : NULL, 0); } |
8dabe7245 y2038: syscalls: ... |
263 |
SYSCALL_DEFINE3(futimesat_time32, unsigned int, dfd, |
ab641afa7 fs: add do_compat... |
264 |
const char __user *, filename, |
9afc5eee6 y2038: globally r... |
265 |
struct old_timeval32 __user *, t) |
ab641afa7 fs: add do_compat... |
266 267 268 |
{ return do_compat_futimesat(dfd, filename, t); } |
8dabe7245 y2038: syscalls: ... |
269 |
SYSCALL_DEFINE2(utimes_time32, const char __user *, filename, struct old_timeval32 __user *, t) |
1a060ba3c utimes: move comp... |
270 |
{ |
ab641afa7 fs: add do_compat... |
271 |
return do_compat_futimesat(AT_FDCWD, filename, t); |
1a060ba3c utimes: move comp... |
272 273 |
} #endif |
4faea239e y2038: utimes: Re... |
274 |
#endif |