Skip to content

Commit

Permalink
add setfsuid and setfsgid implementation for filesystem checks
Browse files Browse the repository at this point in the history
  • Loading branch information
gliderkite committed Feb 29, 2020
1 parent 922d5ee commit 207d892
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
(#[1185](https://github.com/nix-rust/nix/pull/1185))
- `FsType` inner value made public.
(#[1187](https://github.com/nix-rust/nix/pull/1187))
- Added `unistd::setfsuid` and `unistd::setfsgid` to set the user or group
identity for filesystem checks per-thread.
(#[1163](https://github.com/nix-rust/nix/pull/1163))
### Changed
### Fixed
### Removed
Expand Down
22 changes: 22 additions & 0 deletions src/unistd.rs
Expand Up @@ -1398,6 +1398,28 @@ pub fn setgid(gid: Gid) -> Result<()> {
Errno::result(res).map(drop)
}

/// Set the user identity used for filesystem checks per-thread.
/// On both success and failure, this call returns the previous filesystem user
/// ID of the caller.
///
/// See also [setfsuid(2)](http://man7.org/linux/man-pages/man2/setfsuid.2.html)
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn setfsuid(uid: Uid) -> Uid {
let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
Uid::from_raw(prev_fsuid as uid_t)
}

/// Set the group identity used for filesystem checks per-thread.
/// On both success and failure, this call returns the previous filesystem group
/// ID of the caller.
///
/// See also [setfsgid(2)](http://man7.org/linux/man-pages/man2/setfsgid.2.html)
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn setfsgid(gid: Gid) -> Gid {
let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
Gid::from_raw(prev_fsgid as gid_t)
}

/// Get the list of supplementary group IDs of the calling process.
///
/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
Expand Down
38 changes: 38 additions & 0 deletions test/test_unistd.rs
Expand Up @@ -866,3 +866,41 @@ fn test_access_file_exists() {
let _file = File::create(path.clone()).unwrap();
assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok());
}

/// Tests setting the filesystem UID with `setfsuid`.
#[cfg(any(target_os = "linux", target_os = "android"))]
#[test]
fn test_setfsuid() {
use std::os::unix::fs::PermissionsExt;
use std::{fs, thread};
require_capability!(CAP_SETUID);

// get the UID of the "nobody" user
let nobody = User::from_name("nobody").unwrap().unwrap();

// create a temporary file with permissions '-rw-r-----'
let file = tempfile::NamedTempFile::new().unwrap();
let temp_path = file.into_temp_path();
let temp_path_2 = (&temp_path).to_path_buf();
let mut permissions = fs::metadata(&temp_path).unwrap().permissions();
permissions.set_mode(640);

// spawn a new thread where to test setfsuid
thread::spawn(move || {
// set filesystem UID
let fuid = setfsuid(nobody.uid);
// trying to open the temporary file should fail with EACCES
let res = fs::File::open(&temp_path);
assert!(res.is_err());
assert_eq!(res.err().unwrap().kind(), io::ErrorKind::PermissionDenied);

// assert fuid actually changes
let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32));
assert_ne!(prev_fuid, fuid);
})
.join()
.unwrap();

// open the temporary file with the current thread filesystem UID
fs::File::open(temp_path_2).unwrap();
}

0 comments on commit 207d892

Please sign in to comment.