Exemplo n.º 1
0
/**
 * Replace current @tracee's syscall with an older and compatible one
 * whenever it's required, i.e. when the syscall is supported by the
 * kernel as specified by @config->virtual_release but it isn't
 * supported by the actual kernel.
 */
static int handle_sysenter_end(Tracee *tracee, Config *config)
{
	/* Note: syscalls like "openat" can be replaced by "open" since PRoot
	 * has canonicalized "fd + path" into "path".  */
	switch (get_sysnum(tracee, ORIGINAL)) {
	case PR_accept4: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,28),
			.new_sysarg_num   = PR_accept,
			.shifts		  = NONE
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_dup3: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_dup2,
			.shifts		  = NONE
		};

		/* "If oldfd equals newfd, then dup3() fails with the
		 * error EINVAL" -- man dup3 */
		if (peek_reg(tracee, CURRENT, SYSARG_1) == peek_reg(tracee, CURRENT, SYSARG_2))
			return -EINVAL;

		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_epoll_create1: {
		bool modified;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_epoll_create,
			.shifts		  = NONE
		};

		/* "the size argument is ignored, but must be greater
		 * than zero" -- man epoll_create */
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_1, 1);
		return 0;
	}

	case PR_epoll_pwait: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,19),
			.new_sysarg_num   = PR_epoll_wait,
			.shifts		  = NONE
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_eventfd2: {
		bool modified;
		word_t flags;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_eventfd,
			.shifts		  = NONE
		};

		modified = modify_syscall(tracee, config, &modif);
		if (modified) {
			/* EFD_SEMAPHORE can't be emulated with eventfd.  */
			flags = peek_reg(tracee, CURRENT, SYSARG_2);
			if ((flags & EFD_SEMAPHORE) != 0)
				return -EINVAL;
		}
		return 0;
	}

	case PR_faccessat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_access,
			.shifts	= { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_fchmodat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_chmod,
			.shifts	= { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_fchownat: {
		word_t flags;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.shifts	= { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 3,
					.offset  = -1 }
			}
		};

		flags = peek_reg(tracee, CURRENT, SYSARG_5);
		modif.new_sysarg_num = ((flags & AT_SYMLINK_NOFOLLOW) != 0
					? PR_lchown
					: PR_chown);

		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_fcntl: {
		word_t command;

		if (!needs_kompat(config, KERNEL_VERSION(2,6,24)))
			return 0;

		command = peek_reg(tracee, ORIGINAL, SYSARG_2);
		if (command == F_DUPFD_CLOEXEC)
			poke_reg(tracee, SYSARG_2, F_DUPFD);

		return 0;
	}

	case PR_newfstatat:
	case PR_fstatat64: {
		word_t flags;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};

		flags = peek_reg(tracee, CURRENT, SYSARG_4);
		if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0)
			return -EINVAL; /* Exposed by LTP.  */

#if defined(ARCH_X86_64)
		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_lstat : PR_lstat64);
		else
			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_stat : PR_stat64);
#else
		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
			modif.new_sysarg_num = PR_lstat64;
		else
			modif.new_sysarg_num = PR_stat64;
#endif

		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_futex: {
		word_t operation;
		static bool warned = false;

		if (!needs_kompat(config, KERNEL_VERSION(2,6,22)) || config->actual_release == 0)
			return 0;

		operation = peek_reg(tracee, CURRENT, SYSARG_2);
		if ((operation & FUTEX_PRIVATE_FLAG) == 0)
			return 0;

		if (!warned) {
			warned = true;
			note(tracee, WARNING, USER,
				"kompat: this kernel doesn't support private futexes "
				"and PRoot can't emulate them.  Expect some troubles...");
		}

		poke_reg(tracee, SYSARG_2, operation & ~FUTEX_PRIVATE_FLAG);
		return 0;
	}

	case PR_futimesat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_utimes,
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_inotify_init1: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_inotify_init,
			.shifts		  = NONE
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_linkat: {
		word_t flags;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_link,
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 1,
					.offset  = -1 },
				    [1] = {
					.sysarg  = SYSARG_4,
					.nb_args = 1,
					.offset  = -2 }
			}
		};

		flags = peek_reg(tracee, CURRENT, SYSARG_5);
		if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
			return -EINVAL; /* Exposed by LTP.  */

		modify_syscall(tracee, config, &modif);
		return 0;
	}

	case PR_mkdirat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_mkdir,
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modify_syscall(tracee, config, &modif);
		return 0;
	}
Exemplo n.º 2
0
Arquivo: kompat.c Projeto: AQBoy/PRoot
/**
 * Replace current @tracee's syscall with an older and compatible one
 * whenever it's required, i.e. when the syscall is supported by the
 * kernel as specified by @config->release but it isn't supported by
 * the actual kernel.
 */
static void handle_sysenter_end(Tracee *tracee, Config *config)
{
	bool modified;

	/* Note: syscalls like "openat" can be replaced by "open" since PRoot
	 * has canonicalized "fd + path" into "path".  */
	switch (get_sysnum(tracee, ORIGINAL)) {
	case PR_accept4: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,28),
			.new_sysarg_num   = PR_accept,
			.shifts		  = {{0}}
		};
		modify_syscall(tracee, config, &modif);
		return;
	}

	case PR_dup3: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_dup2,
			.shifts		  = {{0}}
		};
		modify_syscall(tracee, config, &modif);
		return;
	}

	case PR_epoll_create1: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_epoll_create,
			.shifts		  = {{0}}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_1, 0); /* Force "size" to 0.  */
		return;
	}

	case PR_epoll_pwait: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,19),
			.new_sysarg_num   = PR_epoll_wait,
			.shifts		  = {{0}}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_5, 0); /* Force "sigmask" to 0.  */
		return;
	}

	case PR_eventfd2: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_eventfd,
			.shifts		  = {{0}}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_2, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_faccessat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_access,
			.shifts	= { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_4, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_fchmodat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_chmod,
			.shifts	= { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_4, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_fchownat: {
		word_t flags;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.shifts	= { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 3,
					.offset  = -1 }
			}
		};

		flags = peek_reg(tracee, CURRENT, SYSARG_5);
		modif.new_sysarg_num = ((flags & AT_SYMLINK_NOFOLLOW) != 0
					? PR_lchown
					: PR_chown);

		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_5, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_newfstatat:
	case PR_fstatat64: {
		word_t flags;
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};

		flags = peek_reg(tracee, CURRENT, SYSARG_4);
#if defined(ARCH_X86_64)
		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_lstat : PR_lstat64);
		else
			modif.new_sysarg_num = (get_abi(tracee) != ABI_2 ? PR_stat : PR_stat64);
#else
		if ((flags & AT_SYMLINK_NOFOLLOW) != 0)
			modif.new_sysarg_num = PR_lstat64;
		else
			modif.new_sysarg_num = PR_stat64;
#endif
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_4, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_futimesat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_utimes,
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modify_syscall(tracee, config, &modif);
		return;
	}

	case PR_inotify_init1: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,27),
			.new_sysarg_num   = PR_inotify_init,
			.shifts		  = {{0}}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_1, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_linkat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_link,
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 1,
					.offset  = -1 },
				    [1] = {
					    .sysarg  = SYSARG_4,
					    .nb_args = 1,
					    .offset  = -2 }
			}
		};
		modified = modify_syscall(tracee, config, &modif);
		if (modified)
			poke_reg(tracee, SYSARG_5, 0); /* Force "flags" to 0.  */
		return;
	}

	case PR_mkdirat: {
		Modif modif = {
			.expected_release = KERNEL_VERSION(2,6,16),
			.new_sysarg_num   = PR_mkdir,
			.shifts = { [0] = {
					.sysarg  = SYSARG_2,
					.nb_args = 2,
					.offset  = -1 }
			}
		};
		modify_syscall(tracee, config, &modif);
		return;
	}