login: restore blocking mode on console fds before spawning the shell
The login name is read via the liner line editor, which puts the console fd into non-blocking (and raw) mode and does not restore it. The shell inherits fd 0; an interactive shell doing blocking line reads on a non-blocking pty slave never receives forwarded input (reads return empty), so the shell can never run a command. Clear O_NONBLOCK on stdin/stdout/stderr in spawn_shell before spawning. Restores the login namespace restriction (skipping it did not affect the symptom).
This commit is contained in:
+12
-9
@@ -176,16 +176,19 @@ pub fn main() {
|
||||
stdout.flush().r#try(&mut stderr);
|
||||
}
|
||||
|
||||
// DIAGNOSTIC: temporarily skip the login namespace
|
||||
// restriction (apply_login_schemes). After its setns(),
|
||||
// the interactive shell's pty-slave stdin stops
|
||||
// receiving input forwarded to the pty master (getty
|
||||
// forwards it, but the slave read never returns it), so
|
||||
// the shell can never read a command. Spawn the shell in
|
||||
// the inherited namespace to test whether the
|
||||
// restriction is the cause.
|
||||
let _ = apply_login_schemes; // keep import used
|
||||
let before_ns_fd =
|
||||
apply_login_schemes(user, &DEFAULT_SCHEMES).unwrap_or_exit(1);
|
||||
|
||||
let _ = syscall::fcntl(
|
||||
before_ns_fd.raw(),
|
||||
syscall::F_SETFD,
|
||||
syscall::O_CLOEXEC,
|
||||
);
|
||||
spawn_shell(user).unwrap_or_exit(1);
|
||||
let _ = syscall::fcntl(before_ns_fd.raw(), syscall::F_SETFD, 0);
|
||||
let _ = libredox::call::close(
|
||||
libredox::call::setns(before_ns_fd.into_raw()).unwrap_or_exit(1),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+16
-2
@@ -18,9 +18,9 @@
|
||||
|
||||
use std::io::Result as IoResult;
|
||||
|
||||
use libredox::call::{fchown, open};
|
||||
use libredox::call::{fchown, fcntl, open};
|
||||
use libredox::error::Result as SysResult;
|
||||
use libredox::flag::{O_CLOEXEC, O_CREAT, O_DIRECTORY};
|
||||
use libredox::flag::{O_CLOEXEC, O_CREAT, O_DIRECTORY, O_NONBLOCK};
|
||||
use redox_users::{All, AllGroups, Error, Result, User, auth};
|
||||
|
||||
const DEFAULT_MODE: u16 = 0o700;
|
||||
@@ -72,6 +72,20 @@ impl AllGroupsExt for AllGroups {
|
||||
/// spawn_shell(user).unwrap();
|
||||
/// ```
|
||||
pub fn spawn_shell<T: Default>(user: &User<T>) -> IoResult<i32> {
|
||||
// The login name is read by a line editor (liner) that puts the console
|
||||
// fd into non-blocking (and raw) mode and does not always restore it. The
|
||||
// shell inherits fd 0, and an interactive shell that does blocking line
|
||||
// reads on a non-blocking pty slave never receives forwarded input (the
|
||||
// read returns empty). Restore blocking mode on stdin/stdout/stderr before
|
||||
// spawning the shell.
|
||||
const F_GETFL: usize = 3;
|
||||
const F_SETFL: usize = 4;
|
||||
for fd in 0..=2 {
|
||||
if let Ok(flags) = fcntl(fd, F_GETFL, 0) {
|
||||
let _ = fcntl(fd, F_SETFL, flags & !(O_NONBLOCK as usize));
|
||||
}
|
||||
}
|
||||
|
||||
let mut command = user.shell_cmd();
|
||||
|
||||
let mut child = command.spawn()?;
|
||||
|
||||
Reference in New Issue
Block a user