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:
parent
0456375cd3
commit
c7552fcf1a
@ -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);
|
||||
|
@ -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, ×[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, ×[0], 0))
|
||||
<< strerror(errno);
|
||||
}
|
||||
|
||||
/* Deleting user attributes merely requires WRITE privilege */
|
||||
TEST_F(Deleteextattr, user)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user