diff options
Diffstat (limited to 'fs/utimes.c')
| -rw-r--r-- | fs/utimes.c | 59 | 
1 files changed, 28 insertions, 31 deletions
diff --git a/fs/utimes.c b/fs/utimes.c index af059d5cb48..b6b664e7145 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -40,14 +40,9 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)  #endif -static bool nsec_special(long nsec) -{ -	return nsec == UTIME_OMIT || nsec == UTIME_NOW; -} -  static bool nsec_valid(long nsec)  { -	if (nsec_special(nsec)) +	if (nsec == UTIME_OMIT || nsec == UTIME_NOW)  		return true;  	return nsec >= 0 && nsec <= 999999999; @@ -102,7 +97,11 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags  	if (error)  		goto dput_and_out; -	/* Don't worry, the checks are done in inode_change_ok() */ +	if (times && times[0].tv_nsec == UTIME_NOW && +		     times[1].tv_nsec == UTIME_NOW) +		times = NULL; + +	/* In most cases, the checks are done in inode_change_ok() */  	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;  	if (times) {  		error = -EPERM; @@ -124,28 +123,34 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags  			newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;  			newattrs.ia_valid |= ATTR_MTIME_SET;  		} -	} -	/* -	 * If times is NULL or both times are either UTIME_OMIT or -	 * UTIME_NOW, then need to check permissions, because -	 * inode_change_ok() won't do it. -	 */ -	if (!times || (nsec_special(times[0].tv_nsec) && -		       nsec_special(times[1].tv_nsec))) { +		/* +		 * For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT +		 * cases, we need to make an extra check that is not done by +		 * inode_change_ok(). +		 */ +		if (((times[0].tv_nsec == UTIME_NOW && +			    times[1].tv_nsec == UTIME_OMIT) +		     || +		     (times[0].tv_nsec == UTIME_OMIT && +			    times[1].tv_nsec == UTIME_NOW)) +		    && !is_owner_or_cap(inode)) +			goto mnt_drop_write_and_out; +	} else { + +		/* +		 * If times is NULL (or both times are UTIME_NOW), +		 * then we need to check permissions, because +		 * inode_change_ok() won't do it. +		 */  		error = -EACCES;                  if (IS_IMMUTABLE(inode))  			goto mnt_drop_write_and_out;  		if (!is_owner_or_cap(inode)) { -			if (f) { -				if (!(f->f_mode & FMODE_WRITE)) -					goto mnt_drop_write_and_out; -			} else { -				error = vfs_permission(&nd, MAY_WRITE); -				if (error) -					goto mnt_drop_write_and_out; -			} +			error = permission(inode, MAY_WRITE, NULL); +			if (error) +				goto mnt_drop_write_and_out;  		}  	}  	mutex_lock(&inode->i_mutex); @@ -169,14 +174,6 @@ asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __  	if (utimes) {  		if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))  			return -EFAULT; -		if ((tstimes[0].tv_nsec == UTIME_OMIT || -		     tstimes[0].tv_nsec == UTIME_NOW) && -		    tstimes[0].tv_sec != 0) -			return -EINVAL; -		if ((tstimes[1].tv_nsec == UTIME_OMIT || -		     tstimes[1].tv_nsec == UTIME_NOW) && -		    tstimes[1].tv_sec != 0) -			return -EINVAL;  		/* Nothing to do, we must not even check the path.  */  		if (tstimes[0].tv_nsec == UTIME_OMIT &&  |