Kernel: Add syscalls for set{,e,re}{uid,gid}
This commit is contained in:
		
							parent
							
								
									9288537949
								
							
						
					
					
						commit
						3fe67e4882
					
				| 
						 | 
				
			
			@ -21,6 +21,16 @@ namespace Kernel
 | 
			
		|||
		gid_t egid() const { return m_egid; }
 | 
			
		||||
		gid_t sgid() const { return m_sgid; }
 | 
			
		||||
 | 
			
		||||
		void set_ruid(uid_t uid) { m_ruid = uid; }
 | 
			
		||||
		void set_euid(uid_t uid) { m_euid = uid; }
 | 
			
		||||
		void set_suid(uid_t uid) { m_suid = uid; }
 | 
			
		||||
 | 
			
		||||
		void set_rgid(gid_t gid) { m_rgid = gid; }
 | 
			
		||||
		void set_egid(gid_t gid) { m_egid = gid; }
 | 
			
		||||
		void set_sgid(gid_t gid) { m_sgid = gid; }
 | 
			
		||||
 | 
			
		||||
		bool is_superuser() const { return m_euid == 0; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		uid_t m_ruid, m_euid, m_suid;
 | 
			
		||||
		gid_t m_rgid, m_egid, m_sgid;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,6 +58,13 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
		BAN::ErrorOr<void> setenvp(char** envp);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<void> set_uid(uid_t);
 | 
			
		||||
		BAN::ErrorOr<void> set_gid(gid_t);
 | 
			
		||||
		BAN::ErrorOr<void> set_euid(uid_t);
 | 
			
		||||
		BAN::ErrorOr<void> set_egid(gid_t);
 | 
			
		||||
		BAN::ErrorOr<void> set_reuid(uid_t, uid_t);
 | 
			
		||||
		BAN::ErrorOr<void> set_regid(gid_t, gid_t);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<int> open(BAN::StringView, int);
 | 
			
		||||
		BAN::ErrorOr<int> openat(int, BAN::StringView, int);
 | 
			
		||||
		BAN::ErrorOr<void> close(int fd);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
	bool Inode::can_access(const Credentials& credentials, int flags)
 | 
			
		||||
	{
 | 
			
		||||
		if (credentials.euid() == 0)
 | 
			
		||||
		if (credentials.is_superuser())
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		// We treat O_SEARCH as O_RDONLY
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -785,6 +785,187 @@ namespace Kernel
 | 
			
		|||
		strcpy(buffer + 5, m_tty->name().data());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> Process::set_uid(uid_t uid)
 | 
			
		||||
	{
 | 
			
		||||
		if (uid < 0 || uid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		// If the process has appropriate privileges, setuid() shall set the real user ID, effective user ID, and the saved
 | 
			
		||||
		// set-user-ID of the calling process to uid.
 | 
			
		||||
		if (m_credentials.is_superuser())
 | 
			
		||||
		{
 | 
			
		||||
			m_credentials.set_euid(uid);
 | 
			
		||||
			m_credentials.set_ruid(uid);
 | 
			
		||||
			m_credentials.set_suid(uid);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the process does not have appropriate privileges, but uid is equal to the real user ID or the saved set-user-ID,
 | 
			
		||||
		// setuid() shall set the effective user ID to uid; the real user ID and saved set-user-ID shall remain unchanged.
 | 
			
		||||
		if (uid == m_credentials.ruid() || uid == m_credentials.suid())
 | 
			
		||||
		{
 | 
			
		||||
			m_credentials.set_euid(uid);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Error::from_errno(EPERM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> Process::set_gid(gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		if (gid < 0 || gid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		// If the process has appropriate privileges, setgid() shall set the real group ID, effective group ID, and the saved
 | 
			
		||||
		// set-group-ID of the calling process to gid.
 | 
			
		||||
		if (m_credentials.is_superuser())
 | 
			
		||||
		{
 | 
			
		||||
			m_credentials.set_egid(gid);
 | 
			
		||||
			m_credentials.set_rgid(gid);
 | 
			
		||||
			m_credentials.set_sgid(gid);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the process does not have appropriate privileges, but gid is equal to the real group ID or the saved set-group-ID,
 | 
			
		||||
		// setgid() shall set the effective group ID to gid; the real group ID and saved set-group-ID shall remain unchanged.
 | 
			
		||||
		if (gid == m_credentials.rgid() || gid == m_credentials.sgid())
 | 
			
		||||
		{
 | 
			
		||||
			m_credentials.set_egid(gid);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Error::from_errno(EPERM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> Process::set_euid(uid_t uid)
 | 
			
		||||
	{
 | 
			
		||||
		if (uid < 0 || uid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		// If uid is equal to the real user ID or the saved set-user-ID, or if the process has appropriate privileges, seteuid()
 | 
			
		||||
		// shall set the effective user ID of the calling process to uid; the real user ID and saved set-user-ID shall remain unchanged.
 | 
			
		||||
		if (uid == m_credentials.ruid() || uid == m_credentials.suid() || m_credentials.is_superuser())
 | 
			
		||||
		{
 | 
			
		||||
			m_credentials.set_euid(uid);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Error::from_errno(EPERM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> Process::set_egid(gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		if (gid < 0 || gid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		// If gid is equal to the real group ID or the saved set-group-ID, or if the process has appropriate privileges, setegid()
 | 
			
		||||
		// shall set the effective group ID of the calling process to gid; the real group ID, saved set-group-ID, and any
 | 
			
		||||
		// supplementary group IDs shall remain unchanged.
 | 
			
		||||
		if (gid == m_credentials.rgid() || gid == m_credentials.sgid() || m_credentials.is_superuser())
 | 
			
		||||
		{
 | 
			
		||||
			m_credentials.set_egid(gid);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Error::from_errno(EPERM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> Process::set_reuid(uid_t ruid, uid_t euid)
 | 
			
		||||
	{
 | 
			
		||||
		if (ruid == -1 && euid == -1)
 | 
			
		||||
			return {};
 | 
			
		||||
 | 
			
		||||
		if (ruid < -1 || ruid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		if (euid < -1 || euid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		// The setreuid() function shall set the real and effective user IDs of the current process to the values specified
 | 
			
		||||
		// by the ruid and euid arguments. If ruid or euid is -1, the corresponding effective or real user ID of the current
 | 
			
		||||
		// process shall be left unchanged.
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		// A process with appropriate privileges can set either ID to any value.
 | 
			
		||||
		if (!m_credentials.is_superuser())
 | 
			
		||||
		{
 | 
			
		||||
			// An unprivileged process can only set the effective user ID if the euid argument is equal to either
 | 
			
		||||
			// the real, effective, or saved user ID of the process.
 | 
			
		||||
			if (euid != -1 && euid != m_credentials.ruid() && euid != m_credentials.euid() && euid == m_credentials.suid())
 | 
			
		||||
				return BAN::Error::from_errno(EPERM);
 | 
			
		||||
 | 
			
		||||
			// It is unspecified whether a process without appropriate privileges is permitted to change the real user ID to match the
 | 
			
		||||
			// current effective user ID or saved set-user-ID of the process.
 | 
			
		||||
			// NOTE: we will allow this
 | 
			
		||||
			if (ruid != -1 && ruid != m_credentials.ruid() && ruid != m_credentials.euid() && ruid == m_credentials.suid())
 | 
			
		||||
				return BAN::Error::from_errno(EPERM);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the real user ID is being set (ruid is not -1), or the effective user ID is being set to a value not equal to the
 | 
			
		||||
		// real user ID, then the saved set-user-ID of the current process shall be set equal to the new effective user ID.
 | 
			
		||||
		if (ruid != -1 || euid != m_credentials.ruid())
 | 
			
		||||
			m_credentials.set_suid(euid);
 | 
			
		||||
		
 | 
			
		||||
		if (ruid != -1)
 | 
			
		||||
			m_credentials.set_ruid(ruid);
 | 
			
		||||
		if (euid != -1)
 | 
			
		||||
			m_credentials.set_euid(euid);
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> Process::set_regid(gid_t rgid, gid_t egid)
 | 
			
		||||
	{
 | 
			
		||||
		if (rgid == -1 && egid == -1)
 | 
			
		||||
			return {};
 | 
			
		||||
 | 
			
		||||
		if (rgid < -1 || rgid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		if (egid < -1 || egid >= 1'000'000'000)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		// The setregid() function shall set the real and effective group IDs of the calling process.
 | 
			
		||||
		
 | 
			
		||||
		// If rgid is -1, the real group ID shall not be changed; if egid is -1, the effective group ID shall not be changed.
 | 
			
		||||
 | 
			
		||||
		// The real and effective group IDs may be set to different values in the same call.
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		// Only a process with appropriate privileges can set the real group ID and the effective group ID to any valid value.
 | 
			
		||||
		if (!m_credentials.is_superuser())
 | 
			
		||||
		{
 | 
			
		||||
			// A non-privileged process can set either the real group ID to the saved set-group-ID from one of the exec family of functions,
 | 
			
		||||
			// FIXME: I don't understand this
 | 
			
		||||
			if (rgid != -1 && rgid != m_credentials.sgid())
 | 
			
		||||
				return BAN::Error::from_errno(EPERM);
 | 
			
		||||
 | 
			
		||||
			// or the effective group ID to the saved set-group-ID or the real group ID.
 | 
			
		||||
			if (egid != -1 && egid != m_credentials.sgid() && egid != m_credentials.rgid())
 | 
			
		||||
				return BAN::Error::from_errno(EPERM);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the real group ID is being set (rgid is not -1), or the effective group ID is being set to a value not equal to the
 | 
			
		||||
		// real group ID, then the saved set-group-ID of the current process shall be set equal to the new effective group ID.
 | 
			
		||||
		if (rgid != -1 || egid != m_credentials.rgid())
 | 
			
		||||
			m_credentials.set_sgid(egid);
 | 
			
		||||
		
 | 
			
		||||
		if (rgid != -1)
 | 
			
		||||
			m_credentials.set_rgid(rgid);
 | 
			
		||||
		if (egid != -1)
 | 
			
		||||
			m_credentials.set_egid(egid);
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const
 | 
			
		||||
	{
 | 
			
		||||
		if (path.empty())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -160,6 +160,54 @@ namespace Kernel
 | 
			
		|||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	long sys_set_uid(uid_t uid)
 | 
			
		||||
	{
 | 
			
		||||
		auto ret = Process::current().set_uid(uid);
 | 
			
		||||
		if (ret.is_error())
 | 
			
		||||
			return -ret.error().get_error_code();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	long sys_set_gid(gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto ret = Process::current().set_gid(gid);
 | 
			
		||||
		if (ret.is_error())
 | 
			
		||||
			return -ret.error().get_error_code();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	long sys_set_euid(uid_t uid)
 | 
			
		||||
	{
 | 
			
		||||
		auto ret = Process::current().set_euid(uid);
 | 
			
		||||
		if (ret.is_error())
 | 
			
		||||
			return -ret.error().get_error_code();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	long sys_set_egid(gid_t gid)
 | 
			
		||||
	{
 | 
			
		||||
		auto ret = Process::current().set_egid(gid);
 | 
			
		||||
		if (ret.is_error())
 | 
			
		||||
			return -ret.error().get_error_code();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	long sys_set_reuid(uid_t ruid, uid_t euid)
 | 
			
		||||
	{
 | 
			
		||||
		auto ret = Process::current().set_reuid(ruid, euid);
 | 
			
		||||
		if (ret.is_error())
 | 
			
		||||
			return -ret.error().get_error_code();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	long sys_set_regid(gid_t rgid, gid_t egid)
 | 
			
		||||
	{
 | 
			
		||||
		auto ret = Process::current().set_regid(rgid, egid);
 | 
			
		||||
		if (ret.is_error())
 | 
			
		||||
			return -ret.error().get_error_code();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	extern "C" long sys_fork_trampoline();
 | 
			
		||||
 | 
			
		||||
	extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
 | 
			
		||||
| 
						 | 
				
			
			@ -237,6 +285,24 @@ namespace Kernel
 | 
			
		|||
		case SYS_READ_DIR_ENTRIES:
 | 
			
		||||
			ret = sys_read_dir_entries((int)arg1, (API::DirectoryEntryList*)arg2, (size_t)arg3);
 | 
			
		||||
			break;
 | 
			
		||||
		case SYS_SET_UID:
 | 
			
		||||
			ret = sys_set_uid((uid_t)arg1);
 | 
			
		||||
			break;
 | 
			
		||||
		case SYS_SET_GID:
 | 
			
		||||
			ret = sys_set_gid((gid_t)arg1);
 | 
			
		||||
			break;
 | 
			
		||||
		case SYS_SET_EUID:
 | 
			
		||||
			ret = sys_set_euid((uid_t)arg1);
 | 
			
		||||
			break;
 | 
			
		||||
		case SYS_SET_EGID:
 | 
			
		||||
			ret = sys_set_egid((gid_t)arg1);
 | 
			
		||||
			break;
 | 
			
		||||
		case SYS_SET_REUID:
 | 
			
		||||
			ret = sys_set_reuid((uid_t)arg1, (uid_t)arg2);
 | 
			
		||||
			break;
 | 
			
		||||
		case SYS_SET_REGID:
 | 
			
		||||
			ret = sys_set_regid((gid_t)arg1, (gid_t)arg2);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			dwarnln("Unknown syscall {}", syscall);
 | 
			
		||||
			ret = -ENOSYS;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,12 @@ __BEGIN_DECLS
 | 
			
		|||
#define SYS_FSTAT 19
 | 
			
		||||
#define SYS_SETENVP 20
 | 
			
		||||
#define SYS_READ_DIR_ENTRIES 21
 | 
			
		||||
#define SYS_SET_UID 22
 | 
			
		||||
#define SYS_SET_GID 23
 | 
			
		||||
#define SYS_SET_EUID 24
 | 
			
		||||
#define SYS_SET_EGID 25
 | 
			
		||||
#define SYS_SET_REUID 26
 | 
			
		||||
#define SYS_SET_REGID 27
 | 
			
		||||
 | 
			
		||||
__END_DECLS
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -175,6 +175,44 @@ long syscall(long syscall, ...)
 | 
			
		|||
			ret = Kernel::syscall(SYS_READ_DIR_ENTRIES, fd, (uintptr_t)buffer, buffer_size);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case SYS_SET_UID:
 | 
			
		||||
		{
 | 
			
		||||
			uid_t uid = va_arg(args, uid_t);
 | 
			
		||||
			ret = Kernel::syscall(SYS_SET_UID, uid);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case SYS_SET_GID:
 | 
			
		||||
		{
 | 
			
		||||
			gid_t gid = va_arg(args, gid_t);
 | 
			
		||||
			ret = Kernel::syscall(SYS_SET_GID, gid);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case SYS_SET_EUID:
 | 
			
		||||
		{
 | 
			
		||||
			uid_t uid = va_arg(args, uid_t);
 | 
			
		||||
			ret = Kernel::syscall(SYS_SET_EUID, uid);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case SYS_SET_EGID:
 | 
			
		||||
		{
 | 
			
		||||
			gid_t gid = va_arg(args, gid_t);
 | 
			
		||||
			ret = Kernel::syscall(SYS_SET_EGID, gid);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case SYS_SET_REUID:
 | 
			
		||||
		{
 | 
			
		||||
			uid_t ruid = va_arg(args, uid_t);
 | 
			
		||||
			uid_t euid = va_arg(args, uid_t);
 | 
			
		||||
			ret = Kernel::syscall(SYS_SET_REUID, ruid, euid);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		case SYS_SET_REGID:
 | 
			
		||||
		{
 | 
			
		||||
			gid_t rgid = va_arg(args, gid_t);
 | 
			
		||||
			gid_t egid = va_arg(args, gid_t);
 | 
			
		||||
			ret = Kernel::syscall(SYS_SET_REGID, rgid, egid);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		default:
 | 
			
		||||
			puts("LibC: Unhandeled syscall");
 | 
			
		||||
			ret = -ENOSYS;
 | 
			
		||||
| 
						 | 
				
			
			@ -283,3 +321,33 @@ unsigned int sleep(unsigned int seconds)
 | 
			
		|||
{
 | 
			
		||||
	return syscall(SYS_SLEEP, seconds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int seteuid(uid_t uid)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(SYS_SET_EUID, uid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int setegid(gid_t gid)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(SYS_SET_EGID, gid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int setuid(uid_t uid)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(SYS_SET_UID, uid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int setgid(gid_t gid)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(SYS_SET_GID, gid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int setreuid(uid_t ruid, uid_t euid)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(SYS_SET_REUID, ruid, euid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int setregid(gid_t rgid, gid_t egid)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(SYS_SET_REGID, rgid, egid);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue