Use nix mode for open_cloexec

This commit is contained in:
PolyMeilex 2024-01-20 23:57:34 +01:00 committed by Johannes Altmanninger
parent 23301e4895
commit 6915aeb44c
11 changed files with 57 additions and 19 deletions

View file

@ -336,7 +336,19 @@ fn test_autoload() {
} }
fn touch_file(path: &wstr) { fn touch_file(path: &wstr) {
let fd = wopen_cloexec(path, O_RDWR | O_CREAT, 0o666).unwrap(); use nix::sys::stat::Mode;
let fd = wopen_cloexec(
path,
O_RDWR | O_CREAT,
Mode::S_IRUSR
| Mode::S_IWUSR
| Mode::S_IRGRP
| Mode::S_IWGRP
| Mode::S_IROTH
| Mode::S_IWOTH,
)
.unwrap();
write_loop(&fd, "Hello".as_bytes()).unwrap(); write_loop(&fd, "Hello".as_bytes()).unwrap();
unsafe { libc::close(fd) }; unsafe { libc::close(fd) };
} }

View file

@ -9,6 +9,7 @@ use crate::{
}; };
use errno::{self, Errno}; use errno::{self, Errno};
use libc::{fchdir, EACCES, ELOOP, ENOENT, ENOTDIR, EPERM, O_RDONLY}; use libc::{fchdir, EACCES, ELOOP, ENOENT, ENOTDIR, EPERM, O_RDONLY};
use nix::sys::stat::Mode;
use std::{os::fd::AsRawFd, sync::Arc}; use std::{os::fd::AsRawFd, sync::Arc};
// The cd builtin. Changes the current directory to the one specified or to $HOME if none is // The cd builtin. Changes the current directory to the one specified or to $HOME if none is
@ -86,7 +87,7 @@ pub fn cd(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Optio
errno::set_errno(Errno(0)); errno::set_errno(Errno(0));
let res = wopen_cloexec(&norm_dir, O_RDONLY, 0) let res = wopen_cloexec(&norm_dir, O_RDONLY, Mode::empty())
.map(AutoCloseFd::new) .map(AutoCloseFd::new)
.map_err(|err| err as i32); .map_err(|err| err as i32);

View file

@ -8,6 +8,7 @@ use crate::{
reader::reader_read, reader::reader_read,
}; };
use libc::{c_int, O_RDONLY, S_IFMT, S_IFREG}; use libc::{c_int, O_RDONLY, S_IFMT, S_IFREG};
use nix::sys::stat::Mode;
use super::prelude::*; use super::prelude::*;
@ -50,7 +51,7 @@ pub fn source(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O
func_filename = FilenameRef::new(L!("-").to_owned()); func_filename = FilenameRef::new(L!("-").to_owned());
fd = streams.stdin_fd; fd = streams.stdin_fd;
} else { } else {
let Ok(raw_fd) = wopen_cloexec(args[optind], O_RDONLY, 0) else { let Ok(raw_fd) = wopen_cloexec(args[optind], O_RDONLY, Mode::empty()) else {
let esc = escape(args[optind]); let esc = escape(args[optind]);
streams.err.append(wgettext_fmt!( streams.err.append(wgettext_fmt!(
"%ls: Error encountered while sourcing file '%ls':\n", "%ls: Error encountered while sourcing file '%ls':\n",

View file

@ -20,6 +20,7 @@ use crate::wutil::{
}; };
use errno::{errno, Errno}; use errno::{errno, Errno};
use libc::{EINTR, LOCK_EX, O_CREAT, O_RDONLY, O_RDWR}; use libc::{EINTR, LOCK_EX, O_CREAT, O_RDONLY, O_RDWR};
use nix::sys::stat::Mode;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::collections::HashSet; use std::collections::HashSet;
use std::ffi::CString; use std::ffi::CString;
@ -388,7 +389,7 @@ impl EnvUniversal {
return true; return true;
} }
let Ok(raw_fd) = open_cloexec(&self.narrow_vars_path, O_RDONLY, 0) else { let Ok(raw_fd) = open_cloexec(&self.narrow_vars_path, O_RDONLY, Mode::empty()) else {
return false; return false;
}; };
@ -441,7 +442,11 @@ impl EnvUniversal {
let mut res_fd = None; let mut res_fd = None;
while res_fd.is_none() { while res_fd.is_none() {
let raw = match wopen_cloexec(&self.vars_path, flags, 0o644) { let raw = match wopen_cloexec(
&self.vars_path,
flags,
Mode::S_IRUSR | Mode::S_IWUSR | Mode::S_IRGRP | Mode::S_IROTH,
) {
Ok(raw) => raw, Ok(raw) => raw,
Err(err) => { Err(err) => {
if err == nix::Error::EINTR { if err == nix::Error::EINTR {

View file

@ -53,6 +53,7 @@ use libc::{
c_char, EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, O_NOCTTY, c_char, EACCES, ENOENT, ENOEXEC, ENOTDIR, EPIPE, EXIT_FAILURE, EXIT_SUCCESS, O_NOCTTY,
O_RDONLY, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO, O_RDONLY, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO,
}; };
use nix::sys::stat;
use std::ffi::CStr; use std::ffi::CStr;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::os::fd::{FromRawFd, RawFd}; use std::os::fd::{FromRawFd, RawFd};
@ -366,7 +367,7 @@ pub fn is_thompson_shell_script(path: &CStr) -> bool {
} }
let e = errno(); let e = errno();
let mut res = false; let mut res = false;
let fd = open_cloexec(path, O_RDONLY | O_NOCTTY, 0); let fd = open_cloexec(path, O_RDONLY | O_NOCTTY, stat::Mode::empty());
if let Ok(fd) = fd { if let Ok(fd) = fd {
let mut file = unsafe { std::fs::File::from_raw_fd(fd) }; let mut file = unsafe { std::fs::File::from_raw_fd(fd) };
let mut buf = [b'\0'; 256]; let mut buf = [b'\0'; 256];

View file

@ -222,14 +222,17 @@ pub fn set_cloexec(fd: RawFd, should_set: bool /* = true */) -> c_int {
/// Wide character version of open() that also sets the close-on-exec flag (atomically when /// Wide character version of open() that also sets the close-on-exec flag (atomically when
/// possible). /// possible).
pub fn wopen_cloexec(pathname: &wstr, flags: i32, mode: libc::c_int) -> nix::Result<RawFd> { pub fn wopen_cloexec(
pathname: &wstr,
flags: i32,
mode: nix::sys::stat::Mode,
) -> nix::Result<RawFd> {
open_cloexec(wcs2zstring(pathname).as_c_str(), flags, mode) open_cloexec(wcs2zstring(pathname).as_c_str(), flags, mode)
} }
/// Narrow versions of wopen_cloexec. /// Narrow versions of wopen_cloexec.
pub fn open_cloexec(path: &CStr, flags: i32, mode: libc::c_int) -> nix::Result<RawFd> { pub fn open_cloexec(path: &CStr, flags: i32, mode: nix::sys::stat::Mode) -> nix::Result<RawFd> {
let flags = unsafe { OFlag::from_bits_unchecked(flags) }; let flags = unsafe { OFlag::from_bits_unchecked(flags) };
let mode = unsafe { nix::sys::stat::Mode::from_bits_unchecked(mode as u32) };
// Port note: the C++ version of this function had a fallback for platforms where // Port note: the C++ version of this function had a fallback for platforms where
// O_CLOEXEC is not supported, using fcntl. In 2023, this is no longer needed. // O_CLOEXEC is not supported, using fcntl. In 2023, this is no longer needed.
let saved_errno = errno(); let saved_errno = errno();

View file

@ -36,6 +36,7 @@ use libc::{
O_RDONLY, O_WRONLY, SEEK_SET, O_RDONLY, O_WRONLY, SEEK_SET,
}; };
use lru::LruCache; use lru::LruCache;
use nix::sys::stat::Mode;
use rand::Rng; use rand::Rng;
use crate::{ use crate::{
@ -130,7 +131,7 @@ const HISTORY_SAVE_MAX: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1024
const HISTORY_OUTPUT_BUFFER_SIZE: usize = 64 * 1024; const HISTORY_OUTPUT_BUFFER_SIZE: usize = 64 * 1024;
/// The file access mode we use for creating history files /// The file access mode we use for creating history files
const HISTORY_FILE_MODE: i32 = 0o600; const HISTORY_FILE_MODE: Mode = Mode::S_IRUSR.union(Mode::S_IWUSR);
/// How many times we retry to save /// How many times we retry to save
/// Saving may fail if the file is modified in between our opening /// Saving may fail if the file is modified in between our opening
@ -480,7 +481,7 @@ impl HistoryImpl {
let _profiler = TimeProfiler::new("load_old"); let _profiler = TimeProfiler::new("load_old");
if let Some(filename) = history_filename(&self.name, L!("")) { if let Some(filename) = history_filename(&self.name, L!("")) {
let Ok(raw_fd) = wopen_cloexec(&filename, O_RDONLY, 0) else { let Ok(raw_fd) = wopen_cloexec(&filename, O_RDONLY, Mode::empty()) else {
return; return;
}; };
@ -697,7 +698,7 @@ impl HistoryImpl {
// If the open fails, then proceed; this may be because there is no current history // If the open fails, then proceed; this may be because there is no current history
let mut new_file_id = INVALID_FILE_ID; let mut new_file_id = INVALID_FILE_ID;
let target_fd_after = wopen_cloexec(&target_name, O_RDONLY, 0) let target_fd_after = wopen_cloexec(&target_name, O_RDONLY, Mode::empty())
.map(|raw_fd| unsafe { OwnedFd::from_raw_fd(raw_fd) }); .map(|raw_fd| unsafe { OwnedFd::from_raw_fd(raw_fd) });
if let Ok(target_fd_after) = target_fd_after.as_ref() { if let Ok(target_fd_after) = target_fd_after.as_ref() {
@ -814,7 +815,7 @@ impl HistoryImpl {
// Limit our max tries so we don't do this forever. // Limit our max tries so we don't do this forever.
let mut history_fd = None; let mut history_fd = None;
for _i in 0..MAX_SAVE_TRIES { for _i in 0..MAX_SAVE_TRIES {
let Ok(fd) = wopen_cloexec(&history_path, O_WRONLY | O_APPEND, 0) else { let Ok(fd) = wopen_cloexec(&history_path, O_WRONLY | O_APPEND, Mode::empty()) else {
// can't open, we're hosed // can't open, we're hosed
break; break;
}; };
@ -1105,7 +1106,7 @@ impl HistoryImpl {
old_file.push_utfstr(&self.name); old_file.push_utfstr(&self.name);
old_file.push_str("_history"); old_file.push_str("_history");
let Ok(src_fd) = wopen_cloexec(&old_file, O_RDONLY, 0) else { let Ok(src_fd) = wopen_cloexec(&old_file, O_RDONLY, Mode::empty()) else {
return; return;
}; };

View file

@ -18,6 +18,7 @@ use crate::wchar::prelude::*;
use crate::wutil::{perror, perror_io, wdirname, wstat, wwrite_to_fd}; use crate::wutil::{perror, perror_io, wdirname, wstat, wwrite_to_fd};
use errno::Errno; use errno::Errno;
use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDOUT_FILENO}; use libc::{EAGAIN, EINTR, ENOENT, ENOTDIR, EPIPE, EWOULDBLOCK, O_EXCL, STDOUT_FILENO};
use nix::sys::stat::Mode;
use std::cell::{RefCell, UnsafeCell}; use std::cell::{RefCell, UnsafeCell};
use std::os::fd::RawFd; use std::os::fd::RawFd;
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
@ -1006,7 +1007,12 @@ const FILE_ERROR: &wstr = L!("An error occurred while redirecting file '%ls'");
const NOCLOB_ERROR: &wstr = L!("The file '%ls' already exists"); const NOCLOB_ERROR: &wstr = L!("The file '%ls' already exists");
/// Base open mode to pass to calls to open. /// Base open mode to pass to calls to open.
const OPEN_MASK: libc::c_int = 0o666; const OPEN_MASK: Mode = Mode::S_IRUSR
.union(Mode::S_IWUSR)
.union(Mode::S_IRGRP)
.union(Mode::S_IWGRP)
.union(Mode::S_IROTH)
.union(Mode::S_IWOTH);
/// Provide the fd monitor used for background fillthread operations. /// Provide the fd monitor used for background fillthread operations.
fn fd_monitor() -> &'static mut FdMonitor { fn fd_monitor() -> &'static mut FdMonitor {

View file

@ -34,6 +34,7 @@ use crate::wchar::{wstr, WString, L};
use crate::wutil::{perror, wgettext, wgettext_fmt}; use crate::wutil::{perror, wgettext, wgettext_fmt};
use libc::c_int; use libc::c_int;
use libc::O_RDONLY; use libc::O_RDONLY;
use nix::sys::stat::Mode;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use printf_compat::sprintf; use printf_compat::sprintf;
use std::cell::{Ref, RefCell, RefMut}; use std::cell::{Ref, RefCell, RefMut};
@ -358,7 +359,11 @@ impl Parser {
global_event_blocks: AtomicU64::new(0), global_event_blocks: AtomicU64::new(0),
}); });
match open_cloexec(CStr::from_bytes_with_nul(b".\0").unwrap(), O_RDONLY, 0) { match open_cloexec(
CStr::from_bytes_with_nul(b".\0").unwrap(),
O_RDONLY,
Mode::empty(),
) {
Ok(raw_fd) => { Ok(raw_fd) => {
result.libdata_mut().cwd_fd = Some(Arc::new(AutoCloseFd::new(raw_fd))); result.libdata_mut().cwd_fd = Some(Arc::new(AutoCloseFd::new(raw_fd)));
} }

View file

@ -17,6 +17,7 @@ use libc::{
IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, STDIN_FILENO, STDOUT_FILENO, IXOFF, IXON, ONLCR, OPOST, O_NONBLOCK, O_RDONLY, SIGINT, SIGTTIN, STDIN_FILENO, STDOUT_FILENO,
S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE, S_IFDIR, TCSANOW, VMIN, VQUIT, VSUSP, VTIME, _POSIX_VDISABLE,
}; };
use nix::sys::stat::Mode;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::io::BufReader; use std::io::BufReader;
@ -4659,7 +4660,7 @@ impl ReaderData {
var.map_or_else(|| L!("~/.bash_history").to_owned(), |var| var.as_string()); var.map_or_else(|| L!("~/.bash_history").to_owned(), |var| var.as_string());
expand_tilde(&mut path, self.vars()); expand_tilde(&mut path, self.vars());
let Ok(raw_fd) = wopen_cloexec(&path, O_RDONLY, 0) else { let Ok(raw_fd) = wopen_cloexec(&path, O_RDONLY, Mode::empty()) else {
return; return;
}; };

View file

@ -8,6 +8,7 @@ use crate::tests::string_escape::ESCAPE_TEST_CHAR;
use crate::wchar::prelude::*; use crate::wchar::prelude::*;
use crate::wcstringutil::{string_prefixes_string, string_prefixes_string_case_insensitive}; use crate::wcstringutil::{string_prefixes_string, string_prefixes_string_case_insensitive};
use libc::O_RDONLY; use libc::O_RDONLY;
use nix::sys::stat::Mode;
use rand::random; use rand::random;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ffi::CString; use std::ffi::CString;
@ -594,8 +595,9 @@ fn test_history_formats() {
"echo foo".into(), "echo foo".into(),
]; ];
let test_history_imported_from_bash = History::with_name(L!("bash_import")); let test_history_imported_from_bash = History::with_name(L!("bash_import"));
let file = let file = AutoCloseFd::new(
AutoCloseFd::new(wopen_cloexec(L!("tests/history_sample_bash"), O_RDONLY, 0).unwrap()); wopen_cloexec(L!("tests/history_sample_bash"), O_RDONLY, Mode::empty()).unwrap(),
);
test_history_imported_from_bash.populate_from_bash(BufReader::new(file)); test_history_imported_from_bash.populate_from_bash(BufReader::new(file));
assert_eq!(test_history_imported_from_bash.get_history(), expected); assert_eq!(test_history_imported_from_bash.get_history(), expected);
test_history_imported_from_bash.clear(); test_history_imported_from_bash.clear();