Skip to content

Commit 7f3d5b7

Browse files
jiangliubergwolf
authored andcommitted
ptfs: import mount-fd.rs from project virtiofsd
Import mount-fd.rs from project virtiofsd with commit id: daa4e3216a6d9df502da89c69567c4e56b79dbcc Signed-off-by: Jiang Liu <[email protected]>
1 parent 310784e commit 7f3d5b7

File tree

6 files changed

+1706
-0
lines changed

6 files changed

+1706
-0
lines changed

src/passthrough/credentials.rs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
3+
use crate::oslib;
4+
use crate::passthrough::util::einval;
5+
use std::io;
6+
7+
pub struct UnixCredentials {
8+
uid: libc::uid_t,
9+
gid: libc::gid_t,
10+
sup_gid: Option<u32>,
11+
keep_capability: bool,
12+
}
13+
14+
impl UnixCredentials {
15+
pub fn new(uid: libc::uid_t, gid: libc::gid_t) -> Self {
16+
UnixCredentials {
17+
uid,
18+
gid,
19+
sup_gid: None,
20+
keep_capability: false,
21+
}
22+
}
23+
24+
/// Set a supplementary group. Set `supported_extension` to `false` to signal that a
25+
/// supplementary group maybe required, but the guest was not able to tell us which,
26+
/// so we have to rely on keeping the DAC_OVERRIDE capability.
27+
pub fn supplementary_gid(self, supported_extension: bool, sup_gid: Option<u32>) -> Self {
28+
UnixCredentials {
29+
uid: self.uid,
30+
gid: self.gid,
31+
sup_gid,
32+
keep_capability: !supported_extension,
33+
}
34+
}
35+
36+
/// Changes the effective uid/gid of the current thread to `val`. Changes
37+
/// the thread's credentials back to root when the returned struct is dropped.
38+
pub fn set(self) -> io::Result<Option<UnixCredentialsGuard>> {
39+
let change_uid = self.uid != 0;
40+
let change_gid = self.gid != 0;
41+
42+
// We have to change the gid before we change the uid because if we
43+
// change the uid first then we lose the capability to change the gid.
44+
// However changing back can happen in any order.
45+
if let Some(sup_gid) = self.sup_gid {
46+
oslib::setsupgroup(sup_gid)?;
47+
}
48+
49+
if change_gid {
50+
oslib::seteffgid(self.gid)?;
51+
}
52+
53+
if change_uid {
54+
oslib::seteffuid(self.uid)?;
55+
}
56+
57+
if change_uid && self.keep_capability {
58+
// Before kernel 6.3, we don't have access to process supplementary groups.
59+
// To work around this we can set the `DAC_OVERRIDE` in the effective set.
60+
// We are allowed to set the capability because we only change the effective
61+
// user ID, so we still have the 'DAC_OVERRIDE' in the permitted set.
62+
// After switching back to root the permitted set is copied to the effective set,
63+
// so no additional steps are required.
64+
if let Err(e) = crate::util::add_cap_to_eff("DAC_OVERRIDE") {
65+
warn!("failed to add 'DAC_OVERRIDE' to the effective set of capabilities: {e}");
66+
}
67+
}
68+
69+
if !change_uid && !change_gid {
70+
return Ok(None);
71+
}
72+
73+
Ok(Some(UnixCredentialsGuard {
74+
reset_uid: change_uid,
75+
reset_gid: change_gid,
76+
drop_sup_gid: self.sup_gid.is_some(),
77+
}))
78+
}
79+
}
80+
81+
pub struct UnixCredentialsGuard {
82+
reset_uid: bool,
83+
reset_gid: bool,
84+
drop_sup_gid: bool,
85+
}
86+
87+
impl Drop for UnixCredentialsGuard {
88+
fn drop(&mut self) {
89+
if self.reset_uid {
90+
oslib::seteffuid(0).unwrap_or_else(|e| {
91+
error!("failed to change uid back to root: {e}");
92+
});
93+
}
94+
95+
if self.reset_gid {
96+
oslib::seteffgid(0).unwrap_or_else(|e| {
97+
error!("failed to change gid back to root: {e}");
98+
});
99+
}
100+
101+
if self.drop_sup_gid {
102+
oslib::dropsupgroups().unwrap_or_else(|e| {
103+
error!("failed to drop supplementary groups: {e}");
104+
});
105+
}
106+
}
107+
}
108+
109+
pub struct ScopedCaps {
110+
cap: capng::Capability,
111+
}
112+
113+
impl ScopedCaps {
114+
fn new(cap_name: &str) -> io::Result<Option<Self>> {
115+
use capng::{Action, CUpdate, Set, Type};
116+
117+
let cap = capng::name_to_capability(cap_name).map_err(|_| {
118+
let err = io::Error::last_os_error();
119+
error!(
120+
"couldn't get the capability id for name {}: {:?}",
121+
cap_name, err
122+
);
123+
err
124+
})?;
125+
126+
if capng::have_capability(Type::EFFECTIVE, cap) {
127+
let req = vec![CUpdate {
128+
action: Action::DROP,
129+
cap_type: Type::EFFECTIVE,
130+
capability: cap,
131+
}];
132+
capng::update(req).map_err(|e| {
133+
error!("couldn't drop {} capability: {:?}", cap, e);
134+
einval()
135+
})?;
136+
capng::apply(Set::CAPS).map_err(|e| {
137+
error!(
138+
"couldn't apply capabilities after dropping {}: {:?}",
139+
cap, e
140+
);
141+
einval()
142+
})?;
143+
Ok(Some(Self { cap }))
144+
} else {
145+
Ok(None)
146+
}
147+
}
148+
}
149+
150+
impl Drop for ScopedCaps {
151+
fn drop(&mut self) {
152+
use capng::{Action, CUpdate, Set, Type};
153+
154+
let req = vec![CUpdate {
155+
action: Action::ADD,
156+
cap_type: Type::EFFECTIVE,
157+
capability: self.cap,
158+
}];
159+
160+
if let Err(e) = capng::update(req) {
161+
panic!("couldn't restore {} capability: {:?}", self.cap, e);
162+
}
163+
if let Err(e) = capng::apply(Set::CAPS) {
164+
panic!(
165+
"couldn't apply capabilities after restoring {}: {:?}",
166+
self.cap, e
167+
);
168+
}
169+
}
170+
}
171+
172+
pub fn drop_effective_cap(cap_name: &str) -> io::Result<Option<ScopedCaps>> {
173+
ScopedCaps::new(cap_name)
174+
}

src/passthrough/file_status.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
3+
#[cfg(target_env = "gnu")]
4+
pub use libc::statx as statx_st;
5+
6+
#[cfg(target_env = "gnu")]
7+
pub use libc::{STATX_BASIC_STATS, STATX_MNT_ID};
8+
9+
// musl provides the 'struct statx', but without stx_mnt_id.
10+
// However, the libc crate does not provide libc::statx
11+
// if musl is used. So we add just the required struct and
12+
// constants to make it works.
13+
14+
#[cfg(not(target_env = "gnu"))]
15+
#[repr(C)]
16+
pub struct statx_st_timestamp {
17+
pub tv_sec: i64,
18+
pub tv_nsec: u32,
19+
pub __statx_timestamp_pad1: [i32; 1],
20+
}
21+
22+
#[cfg(not(target_env = "gnu"))]
23+
#[repr(C)]
24+
pub struct statx_st {
25+
pub stx_mask: u32,
26+
pub stx_blksize: u32,
27+
pub stx_attributes: u64,
28+
pub stx_nlink: u32,
29+
pub stx_uid: u32,
30+
pub stx_gid: u32,
31+
pub stx_mode: u16,
32+
__statx_pad1: [u16; 1],
33+
pub stx_ino: u64,
34+
pub stx_size: u64,
35+
pub stx_blocks: u64,
36+
pub stx_attributes_mask: u64,
37+
pub stx_atime: statx_st_timestamp,
38+
pub stx_btime: statx_st_timestamp,
39+
pub stx_ctime: statx_st_timestamp,
40+
pub stx_mtime: statx_st_timestamp,
41+
pub stx_rdev_major: u32,
42+
pub stx_rdev_minor: u32,
43+
pub stx_dev_major: u32,
44+
pub stx_dev_minor: u32,
45+
pub stx_mnt_id: u64,
46+
__statx_pad2: u64,
47+
__statx_pad3: [u64; 12],
48+
}
49+
50+
#[cfg(not(target_env = "gnu"))]
51+
pub const STATX_BASIC_STATS: libc::c_uint = 0x07ff;
52+
53+
#[cfg(not(target_env = "gnu"))]
54+
pub const STATX_MNT_ID: libc::c_uint = 0x1000;

0 commit comments

Comments
 (0)