Blame view

fs/utimes.c 5.62 KB
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
1
  #include <linux/compiler.h>
1c710c896   Ulrich Drepper   utimensat impleme...
2
  #include <linux/file.h>
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
3
4
  #include <linux/fs.h>
  #include <linux/linkage.h>
74f9fdfa1   Dave Hansen   [PATCH] r/o bind ...
5
  #include <linux/mount.h>
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
6
  #include <linux/namei.h>
914e26379   Al Viro   [PATCH] severing ...
7
  #include <linux/sched.h>
1c710c896   Ulrich Drepper   utimensat impleme...
8
  #include <linux/stat.h>
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
9
  #include <linux/utime.h>
12c2ab5e8   Adrian Bunk   fs/utimes.c shoul...
10
  #include <linux/syscalls.h>
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  #include <asm/uaccess.h>
  #include <asm/unistd.h>
  
  #ifdef __ARCH_WANT_SYS_UTIME
  
  /*
   * sys_utime() can be implemented in user-level using sys_utimes().
   * Is this for backwards compatibility?  If so, why not move it
   * into the appropriate arch directory (for those architectures that
   * need it).
   */
  
  /* 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.
   */
003d7ab47   Heiko Carstens   [CVE-2009-0029] S...
27
  SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
28
  {
1c710c896   Ulrich Drepper   utimensat impleme...
29
  	struct timespec tv[2];
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
30

82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
31
  	if (times) {
1c710c896   Ulrich Drepper   utimensat impleme...
32
33
34
35
36
  		if (get_user(tv[0].tv_sec, &times->actime) ||
  		    get_user(tv[1].tv_sec, &times->modtime))
  			return -EFAULT;
  		tv[0].tv_nsec = 0;
  		tv[1].tv_nsec = 0;
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
37
  	}
1c710c896   Ulrich Drepper   utimensat impleme...
38
  	return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
39
40
41
  }
  
  #endif
043f46f61   Miklos Szeredi   VFS: check nanose...
42
43
  static bool nsec_valid(long nsec)
  {
4cca92264   Michael Kerrisk   [patch for 2.6.26...
44
  	if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
043f46f61   Miklos Szeredi   VFS: check nanose...
45
46
47
48
  		return true;
  
  	return nsec >= 0 && nsec <= 999999999;
  }
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
49
  static int utimes_common(struct path *path, struct timespec *times)
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
50
51
  {
  	int error;
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
52
  	struct iattr newattrs;
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
53
  	struct inode *inode = path->dentry->d_inode;
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
54

e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
55
  	error = mnt_want_write(path->mnt);
74f9fdfa1   Dave Hansen   [PATCH] r/o bind ...
56
  	if (error)
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
57
  		goto out;
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
58

12fd0d308   Michael Kerrisk   [patch for 2.6.26...
59
60
61
  	if (times && times[0].tv_nsec == UTIME_NOW &&
  		     times[1].tv_nsec == UTIME_NOW)
  		times = NULL;
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
62
63
  	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
  	if (times) {
1c710c896   Ulrich Drepper   utimensat impleme...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  		if (times[0].tv_nsec == UTIME_OMIT)
  			newattrs.ia_valid &= ~ATTR_ATIME;
  		else if (times[0].tv_nsec != UTIME_NOW) {
  			newattrs.ia_atime.tv_sec = times[0].tv_sec;
  			newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
  			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) {
  			newattrs.ia_mtime.tv_sec = times[1].tv_sec;
  			newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
  			newattrs.ia_valid |= ATTR_MTIME_SET;
  		}
4cca92264   Michael Kerrisk   [patch for 2.6.26...
79
  		/*
9767d7495   Miklos Szeredi   [patch 1/4] vfs: ...
80
81
82
  		 * Tell inode_change_ok(), that this is an explicit time
  		 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
  		 * were used.
4cca92264   Michael Kerrisk   [patch for 2.6.26...
83
  		 */
9767d7495   Miklos Szeredi   [patch 1/4] vfs: ...
84
  		newattrs.ia_valid |= ATTR_TIMES_SET;
4cca92264   Michael Kerrisk   [patch for 2.6.26...
85
  	} else {
4cca92264   Michael Kerrisk   [patch for 2.6.26...
86
87
88
89
90
  		/*
  		 * If times is NULL (or both times are UTIME_NOW),
  		 * then we need to check permissions, because
  		 * inode_change_ok() won't do it.
  		 */
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
91
92
  		error = -EACCES;
                  if (IS_IMMUTABLE(inode))
74f9fdfa1   Dave Hansen   [PATCH] r/o bind ...
93
  			goto mnt_drop_write_and_out;
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
94

3bd858ab1   Satyam Sharma   Introduce is_owne...
95
  		if (!is_owner_or_cap(inode)) {
f419a2e3b   Al Viro   [PATCH] kill name...
96
  			error = inode_permission(inode, MAY_WRITE);
c70f84417   Michael Kerrisk   [patch for 2.6.26...
97
98
  			if (error)
  				goto mnt_drop_write_and_out;
1e5de2837   Linus Torvalds   Fix permission ch...
99
  		}
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
100
101
  	}
  	mutex_lock(&inode->i_mutex);
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
102
  	error = notify_change(path->dentry, &newattrs);
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
103
  	mutex_unlock(&inode->i_mutex);
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
104

74f9fdfa1   Dave Hansen   [PATCH] r/o bind ...
105
  mnt_drop_write_and_out:
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  	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.
   */
  long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
  {
  	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) {
  		struct file *file;
  
  		if (flags & AT_SYMLINK_NOFOLLOW)
  			goto out;
  
  		file = fget(dfd);
  		error = -EBADF;
  		if (!file)
  			goto out;
  
  		error = utimes_common(&file->f_path, times);
  		fput(file);
  	} else {
2d8f30380   Al Viro   [PATCH] sanitize ...
152
  		struct path path;
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
153
154
155
156
  		int lookup_flags = 0;
  
  		if (!(flags & AT_SYMLINK_NOFOLLOW))
  			lookup_flags |= LOOKUP_FOLLOW;
2d8f30380   Al Viro   [PATCH] sanitize ...
157
  		error = user_path_at(dfd, filename, lookup_flags, &path);
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
158
159
  		if (error)
  			goto out;
2d8f30380   Al Viro   [PATCH] sanitize ...
160
161
  		error = utimes_common(&path, times);
  		path_put(&path);
e9b76fedc   Miklos Szeredi   [patch 2/4] vfs: ...
162
  	}
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
163
164
165
  out:
  	return error;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
166
167
  SYSCALL_DEFINE4(utimensat, int, dfd, char __user *, filename,
  		struct timespec __user *, utimes, int, flags)
1c710c896   Ulrich Drepper   utimensat impleme...
168
169
170
171
172
173
  {
  	struct timespec tstimes[2];
  
  	if (utimes) {
  		if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
  			return -EFAULT;
1c710c896   Ulrich Drepper   utimensat impleme...
174
175
176
177
178
179
180
181
182
  
  		/* 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);
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
183
184
  SYSCALL_DEFINE3(futimesat, int, dfd, char __user *, filename,
  		struct timeval __user *, utimes)
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
185
186
  {
  	struct timeval times[2];
1c710c896   Ulrich Drepper   utimensat impleme...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	struct timespec tstimes[2];
  
  	if (utimes) {
  		if (copy_from_user(&times, 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   Alexey Dobriyan   [PATCH] Create fs...
207

1c710c896   Ulrich Drepper   utimensat impleme...
208
  	return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
209
  }
003d7ab47   Heiko Carstens   [CVE-2009-0029] S...
210
211
  SYSCALL_DEFINE2(utimes, char __user *, filename,
  		struct timeval __user *, utimes)
82b0547cf   Alexey Dobriyan   [PATCH] Create fs...
212
213
214
  {
  	return sys_futimesat(AT_FDCWD, filename, utimes);
  }