Skip to content

Commit c20327c

Browse files
committed
mknod: make umask manipulation panic-safe with UmaskGuard
1 parent de567c4 commit c20327c

File tree

1 file changed

+37
-39
lines changed

1 file changed

+37
-39
lines changed

src/uu/mknod/src/mknod.rs

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -64,57 +64,55 @@ pub struct Config<'a> {
6464
fn mknod(file_name: &str, config: Config) -> i32 {
6565
let c_str = CString::new(file_name).expect("Failed to convert to CString");
6666

67-
unsafe {
68-
// set umask to 0 and store previous umask
69-
let have_prev_umask = if config.use_umask {
67+
let errno = {
68+
// Use UmaskGuard to ensure umask is restored even on panic
69+
let _guard = if config.use_umask {
7070
None
7171
} else {
72-
Some(libc::umask(0))
72+
Some(uucore::mode::UmaskGuard::set(0))
7373
};
7474

75-
let errno = libc::mknod(c_str.as_ptr(), config.mode, config.dev);
75+
// SAFETY: mknod is a standard POSIX syscall. The c_str pointer is valid
76+
// for the duration of the call.
77+
unsafe { libc::mknod(c_str.as_ptr(), config.mode, config.dev) }
78+
}; // Guard dropped here, restoring umask
7679

77-
// set umask back to original value
78-
if let Some(prev_umask) = have_prev_umask {
79-
libc::umask(prev_umask);
80-
}
81-
82-
if errno == -1 {
83-
let c_str = CString::new(uucore::execution_phrase().as_bytes())
84-
.expect("Failed to convert to CString");
85-
// shows the error from the mknod syscall
80+
if errno == -1 {
81+
let c_str = CString::new(uucore::execution_phrase().as_bytes())
82+
.expect("Failed to convert to CString");
83+
// shows the error from the mknod syscall
84+
// SAFETY: perror is a standard C function that doesn't store the pointer
85+
unsafe {
8686
libc::perror(c_str.as_ptr());
8787
}
88+
}
8889

89-
// Apply SELinux context if requested
90-
#[cfg(feature = "selinux")]
91-
if config.set_security_context {
92-
if let Err(e) = uucore::selinux::set_selinux_security_context(
93-
std::path::Path::new(file_name),
94-
config.context,
95-
) {
96-
// if it fails, delete the file
97-
let _ = std::fs::remove_dir(file_name);
98-
eprintln!("{}: {}", uucore::util_name(), e);
99-
return 1;
100-
}
90+
// Apply SELinux context if requested
91+
#[cfg(feature = "selinux")]
92+
if config.set_security_context {
93+
if let Err(e) = uucore::selinux::set_selinux_security_context(
94+
std::path::Path::new(file_name),
95+
config.context,
96+
) {
97+
// if it fails, delete the file
98+
let _ = std::fs::remove_dir(file_name);
99+
eprintln!("{}: {}", uucore::util_name(), e);
100+
return 1;
101101
}
102+
}
102103

103-
// Apply SMACK context if requested
104-
#[cfg(feature = "smack")]
105-
if config.set_security_context {
106-
if let Err(e) =
107-
uucore::smack::set_smack_label_and_cleanup(file_name, config.context, |p| {
108-
std::fs::remove_file(p)
109-
})
110-
{
111-
eprintln!("{}: {}", uucore::util_name(), e);
112-
return 1;
113-
}
104+
// Apply SMACK context if requested
105+
#[cfg(feature = "smack")]
106+
if config.set_security_context {
107+
if let Err(e) = uucore::smack::set_smack_label_and_cleanup(file_name, config.context, |p| {
108+
std::fs::remove_file(p)
109+
}) {
110+
eprintln!("{}: {}", uucore::util_name(), e);
111+
return 1;
114112
}
115-
116-
errno
117113
}
114+
115+
errno
118116
}
119117

120118
#[uucore::main]

0 commit comments

Comments
 (0)