diff --git a/Kernel/Ext2FileSystem.cpp b/Kernel/Ext2FileSystem.cpp index f4a7f452be..0719283a77 100644 --- a/Kernel/Ext2FileSystem.cpp +++ b/Kernel/Ext2FileSystem.cpp @@ -9,6 +9,7 @@ #include #include #include +#include //#define EXT2_DEBUG @@ -1183,13 +1184,13 @@ RetainPtr Ext2FS::create_inode(InodeIdentifier parent_id, const String& n ext2_inode e2inode; memset(&e2inode, 0, sizeof(ext2_inode)); e2inode.i_mode = mode; - e2inode.i_uid = 0; + e2inode.i_uid = current->euid(); + e2inode.i_gid = current->egid(); e2inode.i_size = size; e2inode.i_atime = timestamp; e2inode.i_ctime = timestamp; e2inode.i_mtime = timestamp; e2inode.i_dtime = 0; - e2inode.i_gid = 0; e2inode.i_links_count = initial_links_count; success = write_block_list_for_inode(inode_id, e2inode, blocks); diff --git a/Kernel/InodeMetadata.h b/Kernel/InodeMetadata.h index 8a5ffeb87b..4a964b44cf 100644 --- a/Kernel/InodeMetadata.h +++ b/Kernel/InodeMetadata.h @@ -4,6 +4,8 @@ #include "UnixTypes.h" #include +class Process; + inline bool is_directory(mode_t mode) { return (mode & 0170000) == 0040000; } inline bool is_character_device(mode_t mode) { return (mode & 0170000) == 0020000; } inline bool is_block_device(mode_t mode) { return (mode & 0170000) == 0060000; } @@ -18,6 +20,28 @@ inline bool is_setgid(mode_t mode) { return mode & 02000; } struct InodeMetadata { bool is_valid() const { return inode.is_valid(); } + bool may_read(Process&) const; + bool may_write(Process&) const; + bool may_execute(Process&) const; + + bool may_read(uid_t u, const HashTable& g) const + { + if (uid == u) + return mode & 0400; + if (g.contains(gid)) + return mode & 0040; + return mode & 0004; + } + + bool may_write(uid_t u, const HashTable& g) const + { + if (uid == u) + return mode & 0200; + if (g.contains(gid)) + return mode & 0020; + return mode & 0002; + } + bool may_execute(uid_t u, const HashTable& g) const { if (uid == u) diff --git a/Kernel/Process.h b/Kernel/Process.h index f77996105c..316933832c 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -115,6 +115,7 @@ public: State state() const { return m_state; } uid_t uid() const { return m_uid; } gid_t gid() const { return m_gid; } + const HashTable& gids() const { return m_gids; } uid_t euid() const { return m_euid; } gid_t egid() const { return m_egid; } pid_t ppid() const { return m_ppid; } @@ -537,3 +538,18 @@ inline void Process::for_each_living(Callback callback) process = next_process; } } + +inline bool InodeMetadata::may_read(Process& process) const +{ + return may_read(process.euid(), process.gids()); +} + +inline bool InodeMetadata::may_write(Process& process) const +{ + return may_write(process.euid(), process.gids()); +} + +inline bool InodeMetadata::may_execute(Process& process) const +{ + return may_execute(process.euid(), process.gids()); +} diff --git a/Kernel/VirtualFileSystem.cpp b/Kernel/VirtualFileSystem.cpp index 64876669f5..02530cbb1f 100644 --- a/Kernel/VirtualFileSystem.cpp +++ b/Kernel/VirtualFileSystem.cpp @@ -8,6 +8,7 @@ #include #include "CharacterDevice.h" #include +#include //#define VFS_DEBUG @@ -145,6 +146,20 @@ RetainPtr VFS::open(const String& path, int& error, int options, if (!inode) return nullptr; auto metadata = inode->metadata(); + // NOTE: Read permission is a bit weird, since O_RDONLY == 0, + // so we check if (NOT write_only OR read_and_write) + if (!(options & O_WRONLY) || (options & O_RDWR)) { + if (!metadata.may_read(*current)) { + error = -EACCES; + return nullptr; + } + } + if ((options & O_WRONLY) || (options & O_RDWR)) { + if (!metadata.may_write(*current)) { + error = -EACCES; + return nullptr; + } + } if (!(options & O_DONT_OPEN_DEVICE) && metadata.is_device()) { auto it = m_devices.find(encoded_device(metadata.major_device, metadata.minor_device)); if (it == m_devices.end()) { @@ -181,6 +196,11 @@ RetainPtr VFS::create(const String& path, int& error, int option if (error != -ENOENT) { return nullptr; } + if (!parent_inode->metadata().may_write(*current)) { + error = -EACCES; + return nullptr; + } + FileSystemPath p(path); dbgprintf("VFS::create_file: '%s' in %u:%u\n", p.basename().characters(), parent_inode->fsid(), parent_inode->index()); auto new_file = parent_inode->fs().create_inode(parent_inode->identifier(), p.basename(), mode, 0, error); @@ -208,6 +228,11 @@ bool VFS::mkdir(const String& path, mode_t mode, Inode& base, int& error) if (error != -ENOENT) { return false; } + if (!parent_inode->metadata().may_write(*current)) { + error = -EACCES; + return false; + } + FileSystemPath p(path); dbgprintf("VFS::mkdir: '%s' in %u:%u\n", p.basename().characters(), parent_inode->fsid(), parent_inode->index()); auto new_dir = parent_inode->fs().create_directory(parent_inode->identifier(), p.basename(), mode, error); @@ -225,7 +250,15 @@ bool VFS::chmod(const String& path, mode_t mode, Inode& base, int& error) if (!inode) return false; - // FIXME: Permission checks. + if (inode->fs().is_readonly()) { + error = -EROFS; + return false; + } + + if (current->euid() != inode->metadata().uid) { + error = -EPERM; + return false; + } // Only change the permission bits. mode = (inode->mode() & ~04777) | (mode & 04777); @@ -299,6 +332,11 @@ bool VFS::unlink(const String& path, Inode& base, int& error) return false; } + if (!parent_inode->metadata().may_write(*current)) { + error = -EACCES; + return false; + } + if (!parent_inode->remove_child(FileSystemPath(path).basename(), error)) return false; @@ -328,6 +366,11 @@ bool VFS::rmdir(const String& path, Inode& base, int& error) return false; } + if (!parent_inode->metadata().may_write(*current)) { + error = -EACCES; + return false; + } + if (inode->directory_entry_count() != 2) { error = -ENOTEMPTY; return false; @@ -455,6 +498,10 @@ InodeIdentifier VFS::resolve_path(const String& path, InodeIdentifier base, int& error = -ENOTDIR; return { }; } + if (!metadata.may_execute(*current)) { + error = -EACCES; + return { }; + } auto parent = crumb_id; crumb_id = crumb_inode->lookup(part); if (!crumb_id.is_valid()) { diff --git a/Kernel/sync.sh b/Kernel/sync.sh index 54e1e1ead0..6127135904 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -16,7 +16,7 @@ mkdir -vp mnt/tmp chmod 1777 mnt/tmp mkdir -vp mnt/dev mkdir -vp mnt/dev/pts -mknod mnt/dev/bxvga b 82 413 +mknod -m 666 mnt/dev/bxvga b 82 413 mknod mnt/dev/tty0 c 4 0 mknod mnt/dev/tty1 c 4 1 mknod mnt/dev/tty2 c 4 2 @@ -27,7 +27,7 @@ mknod mnt/dev/zero c 1 5 mknod mnt/dev/full c 1 7 mknod mnt/dev/keyboard c 85 1 mknod mnt/dev/psaux c 10 1 -mknod mnt/dev/ptmx c 5 2 +mknod -m 666 mnt/dev/ptmx c 5 2 ln -s /proc/self/fd/0 mnt/dev/stdin ln -s /proc/self/fd/1 mnt/dev/stdout ln -s /proc/self/fd/2 mnt/dev/stderr diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 6587cd78ae..c1de3e52fa 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -38,7 +38,7 @@ GEventLoop::GEventLoop() sockaddr_un address; address.sun_family = AF_LOCAL; - strcpy(address.sun_path, "/wsportal"); + strcpy(address.sun_path, "/tmp/wsportal"); int retries = 1000; int rc = 0; diff --git a/WindowServer/WSMessageLoop.cpp b/WindowServer/WSMessageLoop.cpp index 15ea696fc6..f189e73354 100644 --- a/WindowServer/WSMessageLoop.cpp +++ b/WindowServer/WSMessageLoop.cpp @@ -39,13 +39,13 @@ int WSMessageLoop::exec() m_keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK | O_CLOEXEC); m_mouse_fd = open("/dev/psaux", O_RDONLY | O_NONBLOCK | O_CLOEXEC); - unlink("/wsportal"); + unlink("/tmp/wsportal"); m_server_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); ASSERT(m_server_fd >= 0); sockaddr_un address; address.sun_family = AF_LOCAL; - strcpy(address.sun_path, "/wsportal"); + strcpy(address.sun_path, "/tmp/wsportal"); int rc = bind(m_server_fd, (const sockaddr*)&address, sizeof(address)); ASSERT(rc == 0); rc = listen(m_server_fd, 5);