Kernel: Add syscalls for set{,e,re}{uid,gid}
This commit is contained in:
		
							parent
							
								
									99f8133b91
								
							
						
					
					
						commit
						ef4ebaa969
					
				|  | @ -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