mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-28 21:54:40 +03:00
Kernel: Allow fchmod() and fchown() on pre-bind() local sockets
In order to ensure a specific owner and mode when the local socket filesystem endpoint is instantiated, we need to be able to call fchmod() and fchown() on a socket fd between socket() and bind(). This is because until we call bind(), there is no filesystem inode for the socket yet.
This commit is contained in:
parent
4abbedb6e4
commit
d84299c7be
Notes:
sideshowbarker
2024-07-19 10:23:44 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/d84299c7be8
@ -57,6 +57,8 @@ public:
|
||||
virtual String absolute_path(const FileDescription&) const = 0;
|
||||
|
||||
virtual KResult truncate(off_t) { return KResult(-EINVAL); }
|
||||
virtual KResult chown(uid_t, gid_t) { return KResult(-EBADF); }
|
||||
virtual KResult chmod(mode_t) { return KResult(-EBADF); }
|
||||
|
||||
virtual const char* class_name() const = 0;
|
||||
|
||||
|
@ -64,13 +64,6 @@ KResult FileDescription::fstat(stat& buffer)
|
||||
return metadata().stat(buffer);
|
||||
}
|
||||
|
||||
KResult FileDescription::fchmod(mode_t mode)
|
||||
{
|
||||
if (!m_inode)
|
||||
return KResult(-EBADF);
|
||||
return VFS::the().chmod(*m_inode, mode);
|
||||
}
|
||||
|
||||
off_t FileDescription::seek(off_t offset, int whence)
|
||||
{
|
||||
if (!m_file->is_seekable())
|
||||
@ -282,9 +275,12 @@ void FileDescription::set_file_flags(u32 flags)
|
||||
m_file_flags = flags;
|
||||
}
|
||||
|
||||
KResult FileDescription::chmod(mode_t mode)
|
||||
{
|
||||
return m_file->chmod(mode);
|
||||
}
|
||||
|
||||
KResult FileDescription::chown(uid_t uid, gid_t gid)
|
||||
{
|
||||
if (!m_inode)
|
||||
return KResult(-EINVAL);
|
||||
return VFS::the().chown(*m_inode, uid, gid);
|
||||
return m_file->chown(uid, gid);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
ssize_t write(const u8* data, ssize_t);
|
||||
KResult fstat(stat&);
|
||||
|
||||
KResult fchmod(mode_t);
|
||||
KResult chmod(mode_t);
|
||||
|
||||
bool can_read() const;
|
||||
bool can_write() const;
|
||||
|
@ -52,3 +52,13 @@ KResult InodeFile::truncate(off_t size)
|
||||
{
|
||||
return m_inode->truncate(size);
|
||||
}
|
||||
|
||||
KResult InodeFile::chown(uid_t uid, gid_t gid)
|
||||
{
|
||||
return VFS::the().chown(*m_inode, uid, gid);
|
||||
}
|
||||
|
||||
KResult InodeFile::chmod(mode_t mode)
|
||||
{
|
||||
return VFS::the().chmod(*m_inode, mode);
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ public:
|
||||
virtual String absolute_path(const FileDescription&) const override;
|
||||
|
||||
virtual KResult truncate(off_t) override;
|
||||
virtual KResult chown(uid_t, gid_t) override;
|
||||
virtual KResult chmod(mode_t) override;
|
||||
|
||||
virtual const char* class_name() const override { return "InodeFile"; }
|
||||
|
||||
|
@ -34,6 +34,10 @@ LocalSocket::LocalSocket(int type)
|
||||
LOCKER(all_sockets().lock());
|
||||
all_sockets().resource().append(this);
|
||||
|
||||
m_prebind_uid = current->process().uid();
|
||||
m_prebind_gid = current->process().gid();
|
||||
m_prebind_mode = 0666;
|
||||
|
||||
#ifdef DEBUG_LOCAL_SOCKET
|
||||
kprintf("%s(%u) LocalSocket{%p} created with type=%u\n", current->process().name().characters(), current->pid(), this, type);
|
||||
#endif
|
||||
@ -76,7 +80,9 @@ KResult LocalSocket::bind(const sockaddr* address, socklen_t address_size)
|
||||
kprintf("%s(%u) LocalSocket{%p} bind(%s)\n", current->process().name().characters(), current->pid(), this, safe_address);
|
||||
#endif
|
||||
|
||||
auto result = VFS::the().open(safe_address, O_CREAT | O_EXCL, S_IFSOCK | 0666, current->process().current_directory());
|
||||
mode_t mode = S_IFSOCK | (m_prebind_mode & ~current->process().umask());
|
||||
UidAndGid owner { m_prebind_uid, m_prebind_gid };
|
||||
auto result = VFS::the().open( safe_address, O_CREAT | O_EXCL, mode, current->process().current_directory(), owner);
|
||||
if (result.is_error()) {
|
||||
if (result.error() == -EEXIST)
|
||||
return KResult(-EADDRINUSE);
|
||||
@ -334,3 +340,25 @@ KResult LocalSocket::getsockopt(FileDescription& description, int level, int opt
|
||||
return Socket::getsockopt(description, level, option, value, value_size);
|
||||
}
|
||||
}
|
||||
|
||||
KResult LocalSocket::chmod(mode_t mode)
|
||||
{
|
||||
if (m_file)
|
||||
return m_file->chmod(mode);
|
||||
|
||||
m_prebind_mode = mode & 04777;
|
||||
return KSuccess;
|
||||
}
|
||||
|
||||
KResult LocalSocket::chown(uid_t uid, gid_t gid)
|
||||
{
|
||||
if (m_file)
|
||||
return m_file->chown(uid, gid);
|
||||
|
||||
if (!current->process().is_superuser() && (current->process().euid() != uid || !current->process().in_group(gid)))
|
||||
return KResult(-EPERM);
|
||||
|
||||
m_prebind_uid = uid;
|
||||
m_prebind_gid = gid;
|
||||
return KSuccess;
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ public:
|
||||
virtual ssize_t sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||
virtual ssize_t recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
|
||||
virtual KResult getsockopt(FileDescription&, int level, int option, void*, socklen_t*) override;
|
||||
virtual KResult chown(uid_t, gid_t) override;
|
||||
virtual KResult chmod(mode_t) override;
|
||||
|
||||
private:
|
||||
explicit LocalSocket(int type);
|
||||
@ -43,6 +45,10 @@ private:
|
||||
// An open socket file on the filesystem.
|
||||
RefPtr<FileDescription> m_file;
|
||||
|
||||
uid_t m_prebind_uid { 0 };
|
||||
uid_t m_prebind_gid { 0 };
|
||||
mode_t m_prebind_mode { 0 };
|
||||
|
||||
// A single LocalSocket is shared between two file descriptions
|
||||
// on the connect side and the accept side; so we need to store
|
||||
// an additional role for the connect side and differentiate
|
||||
|
@ -2524,7 +2524,7 @@ int Process::sys$fchmod(int fd, mode_t mode)
|
||||
auto* description = file_description(fd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
return description->fchmod(mode);
|
||||
return description->chmod(mode);
|
||||
}
|
||||
|
||||
int Process::sys$fchown(int fd, uid_t uid, gid_t gid)
|
||||
|
Loading…
Reference in New Issue
Block a user