Re: [PATCH] utimensat() non-conformances and fixes -- version 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Regarding your suggestions above, are you meaning something like the
> patch below?

Yes.

> The patch is a little less pretty than I'd like because of the need to
> return EACCES or EPERM depending on whether (times == NULL).  In
> particular, these lines in utimes.c:
> 
> +	if (!times && error == -EPERM)
> +		error = -EACCES;
> 
> seem a little fragile (but maybe I worry too much).

It's not only fragile, it's ugly as sin.  I'd rather do it this way:

- initialize error to zero
- if no write access then set error, and the ATTR_TIMES_UPDATE(*) flag
- set error2 from result of notify_change()
- if error is zero then return error2, otherwise return error

(*) I've been mulling over the name and perhaps ATTR_OWNER_CHECK would
be better, or something that implies that it's not really about
updating the times, but about checking the owner.

Also could you do the patch against the

  git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git vfs-cleanups

tree, which does big structural cleanups to do_utimes?

Thanks,
Miklos

> ========================
> 
> diff -ru linux-2.6.26-rc2/fs/attr.c linux-2.6.26-rc2-utimensat-fix/fs/attr.c
> --- linux-2.6.26-rc2/fs/attr.c	2008-01-24 23:58:37.000000000 +0100
> +++ linux-2.6.26-rc2-utimensat-fix/fs/attr.c	2008-05-16 21:56:51.000000000 +0200
> @@ -51,7 +51,8 @@
>  	}
> 
>  	/* Check for setting the inode time. */
> -	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
> +	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET |
> +			ATTR_TIMES_UPDATE)) {
>  		if (!is_owner_or_cap(inode))
>  			goto error;
>  	}
> diff -ru linux-2.6.26-rc2/fs/utimes.c linux-2.6.26-rc2-utimensat-fix/fs/utimes.c
> --- linux-2.6.26-rc2/fs/utimes.c	2008-05-15 10:33:20.000000000 +0200
> +++ linux-2.6.26-rc2-utimensat-fix/fs/utimes.c	2008-05-16 22:14:31.000000000 +0200
> @@ -40,14 +40,9 @@
> 
>  #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,11 +97,15 @@
>  	if (error)
>  		goto dput_and_out;
> 
> +	if (times && times[0].tv_nsec == UTIME_NOW &&
> +		     times[1].tv_nsec == UTIME_NOW)
> +		times = NULL;
> +
>  	/* Don't worry, the checks are done in inode_change_ok() */
>  	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
>  	if (times) {
>  		error = -EPERM;
> -                if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
> +		if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
>  			goto mnt_drop_write_and_out;
> 
>  		if (times[0].tv_nsec == UTIME_OMIT)
> @@ -131,25 +130,39 @@
>  	 * 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))) {
> +	if (!times) {
>  		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;
> -			}
> +		if (f) {
> +			if (!(f->f_mode & FMODE_WRITE))
> +				newattrs.ia_valid |= ATTR_TIMES_UPDATE;
> +		} else {
> +			error = vfs_permission(&nd, MAY_WRITE);
> +			if (error == -EACCES)
> +				newattrs.ia_valid |= ATTR_TIMES_UPDATE;
> +			else if (error)
> +				goto mnt_drop_write_and_out;
>  		}
> +	} else if (times && ((times[0].tv_nsec == UTIME_NOW &&
> +			      times[1].tv_nsec == UTIME_OMIT)
> +			     ||
> +			     (times[0].tv_nsec == UTIME_OMIT &&
> +			      times[1].tv_nsec == UTIME_NOW))) {
> +		error = -EPERM;
> +
> +		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
> +			goto mnt_drop_write_and_out;
> +
> +		newattrs.ia_valid |= ATTR_TIMES_UPDATE;
>  	}
> +
>  	mutex_lock(&inode->i_mutex);
>  	error = notify_change(dentry, &newattrs);
> +	if (!times && error == -EPERM)
> +		error = -EACCES;
> +		
>  	mutex_unlock(&inode->i_mutex);
>  mnt_drop_write_and_out:
>  	mnt_drop_write(mnt);
> diff -ru linux-2.6.26-rc2/include/linux/fs.h linux-2.6.26-rc2-utimensat-fix/include/linux/fs.h
> --- linux-2.6.26-rc2/include/linux/fs.h	2008-05-15 10:33:25.000000000 +0200
> +++ linux-2.6.26-rc2-utimensat-fix/include/linux/fs.h	2008-05-16 21:39:24.000000000 +0200
> @@ -317,22 +317,23 @@
>   * Attribute flags.  These should be or-ed together to figure out what
>   * has been changed!
>   */
> -#define ATTR_MODE	1
> -#define ATTR_UID	2
> -#define ATTR_GID	4
> -#define ATTR_SIZE	8
> -#define ATTR_ATIME	16
> -#define ATTR_MTIME	32
> -#define ATTR_CTIME	64
> -#define ATTR_ATIME_SET	128
> -#define ATTR_MTIME_SET	256
> -#define ATTR_FORCE	512	/* Not a change, but a change it */
> -#define ATTR_ATTR_FLAG	1024
> -#define ATTR_KILL_SUID	2048
> -#define ATTR_KILL_SGID	4096
> -#define ATTR_FILE	8192
> -#define ATTR_KILL_PRIV	16384
> -#define ATTR_OPEN	32768	/* Truncating from open(O_TRUNC) */
> +#define ATTR_MODE		1
> +#define ATTR_UID		2
> +#define ATTR_GID		4
> +#define ATTR_SIZE		8
> +#define ATTR_ATIME		16
> +#define ATTR_MTIME		32
> +#define ATTR_CTIME		64
> +#define ATTR_ATIME_SET		128
> +#define ATTR_MTIME_SET		256
> +#define ATTR_FORCE		512	/* Not a change, but a change it */
> +#define ATTR_ATTR_FLAG		1024
> +#define ATTR_KILL_SUID		2048
> +#define ATTR_KILL_SGID		4096
> +#define ATTR_FILE		8192
> +#define ATTR_KILL_PRIV		16384
> +#define ATTR_OPEN		32768	/* Truncating from open(O_TRUNC) */
> +#define ATTR_TIMES_UPDATE	65536
> 
>  /*
>   * This is the Inode Attributes structure, used for notify_change().  It
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux