fusefs: allow non-owners to set timestamps to UTIME_NOW

utimensat should allow anybody with write access to set atime and mtime to
UTIME_NOW.

PR:		237181
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Alan Somers 2019-05-08 19:42:00 +00:00
parent 4ae3a56cb1
commit d943c93e76
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/fuse2/; revision=347367
2 changed files with 61 additions and 8 deletions

View File

@ -1609,14 +1609,12 @@ fuse_vnop_setattr(struct vop_setattr_args *ap)
}
/* Don't set accmode. Permission to trunc is checked upstack */
}
/*
* TODO: for atime and mtime, only require VWRITE if UTIMENS_NULL is
* set. PR 237181
*/
if (vap->va_atime.tv_sec != VNOVAL)
accmode |= VADMIN;
if (vap->va_mtime.tv_sec != VNOVAL)
accmode |= VADMIN;
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
if (vap->va_vaflags & VA_UTIMES_NULL)
accmode |= VWRITE;
else
accmode |= VADMIN;
}
if (drop_suid) {
if (vap->va_mode != (mode_t)VNOVAL)
vap->va_mode &= ~(S_ISUID | S_ISGID);

View File

@ -141,6 +141,7 @@ class Lookup: public DefaultPermissions {};
class Open: public DefaultPermissions {};
class Setattr: public DefaultPermissions {};
class Unlink: public DefaultPermissions {};
class Utimensat: public DefaultPermissions {};
class Write: public DefaultPermissions {};
/*
@ -544,6 +545,60 @@ TEST_F(Deleteextattr, system)
ASSERT_EQ(EPERM, errno);
}
/* Anybody with write permission can set both timestamps to UTIME_NOW */
TEST_F(Utimensat, utime_now)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
/* Write permissions for everybody */
const mode_t mode = 0666;
uid_t owner = 0;
const timespec times[2] = {
{.tv_sec = 0, .tv_nsec = UTIME_NOW},
{.tv_sec = 0, .tv_nsec = UTIME_NOW},
};
expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1);
expect_lookup(RELPATH, ino, S_IFREG | mode, UINT64_MAX, owner);
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in->header.opcode == FUSE_SETATTR &&
in->header.nodeid == ino &&
in->body.setattr.valid & FATTR_ATIME &&
in->body.setattr.valid & FATTR_MTIME);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([](auto in __unused, auto out) {
SET_OUT_HEADER_LEN(out, attr);
out->body.attr.attr.mode = S_IFREG | mode;
})));
ASSERT_EQ(0, utimensat(AT_FDCWD, FULLPATH, &times[0], 0))
<< strerror(errno);
}
/* Anybody can set both timestamps to UTIME_OMIT */
TEST_F(Utimensat, utime_omit)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
/* Write permissions for no one */
const mode_t mode = 0444;
uid_t owner = 0;
const timespec times[2] = {
{.tv_sec = 0, .tv_nsec = UTIME_OMIT},
{.tv_sec = 0, .tv_nsec = UTIME_OMIT},
};
expect_getattr(1, S_IFDIR | 0755, UINT64_MAX, 1);
expect_lookup(RELPATH, ino, S_IFREG | mode, UINT64_MAX, owner);
ASSERT_EQ(0, utimensat(AT_FDCWD, FULLPATH, &times[0], 0))
<< strerror(errno);
}
/* Deleting user attributes merely requires WRITE privilege */
TEST_F(Deleteextattr, user)
{