Skip to content

Commit 7cb2f01

Browse files
h56983577bergwolf
authored andcommitted
UID/GID remapping support
Once ID mapping is configured, the VFS layer remaps the external IDs in context to internal IDs and remaps the internal IDs in entries back to external IDs. Signed-off-by: HanZiyao <[email protected]>
1 parent e42310a commit 7cb2f01

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

src/api/filesystem/sync_io.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,11 @@ pub trait FileSystem {
896896
fn notify_reply(&self) -> io::Result<()> {
897897
Err(io::Error::from_raw_os_error(libc::ENOSYS))
898898
}
899+
900+
/// Remap the external IDs in context to internal IDs.
901+
fn id_remap(&self, ctx: &mut Context) -> io::Result<()> {
902+
Ok(())
903+
}
899904
}
900905

901906
impl<FS: FileSystem> FileSystem for Arc<FS> {
@@ -1341,4 +1346,9 @@ impl<FS: FileSystem> FileSystem for Arc<FS> {
13411346
fn notify_reply(&self) -> io::Result<()> {
13421347
self.deref().notify_reply()
13431348
}
1349+
1350+
#[inline]
1351+
fn id_remap(&self, ctx: &mut Context) -> io::Result<()> {
1352+
self.deref().id_remap(ctx)
1353+
}
13441354
}

src/api/server/sync_io.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ impl<F: FileSystem + Sync> Server<F> {
7272
) -> Result<usize> {
7373
let in_header: InHeader = r.read_obj().map_err(Error::DecodeMessage)?;
7474
let mut ctx = SrvContext::<F, S>::new(in_header, r, w);
75+
self.fs
76+
.id_remap(&mut ctx.context)
77+
.map_err(|e| Error::FailedToRemapID((ctx.context.uid, ctx.context.gid)))?;
7578
if ctx.in_header.len > (MAX_BUFFER_SIZE + BUFFER_HEADER_SIZE) {
7679
if in_header.opcode == Opcode::Forget as u32
7780
|| in_header.opcode == Opcode::BatchForget as u32

src/api/vfs/mod.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ pub struct VfsOptions {
242242
pub in_opts: FsOptions,
243243
/// File system options returned to client
244244
pub out_opts: FsOptions,
245+
/// Declaration of ID mapping, in the format (internal ID, external ID, range).
246+
/// For example, (0, 1, 65536) represents mapping the external UID/GID range of `1~65536`
247+
/// to the range of `0~65535` within the filesystem.
248+
pub id_mapping: (u32, u32, u32),
245249
}
246250

247251
impl VfsOptions {
@@ -277,6 +281,7 @@ impl Default for VfsOptions {
277281
| FsOptions::ZERO_MESSAGE_OPENDIR
278282
| FsOptions::HANDLE_KILLPRIV_V2
279283
| FsOptions::PERFILE_DAX,
284+
id_mapping: (0, 0, 0),
280285
}
281286
}
282287
}
@@ -293,6 +298,7 @@ pub struct Vfs {
293298
initialized: AtomicBool,
294299
lock: Mutex<()>,
295300
remove_pseudo_root: bool,
301+
id_mapping: Option<(u32, u32, u32)>,
296302
}
297303

298304
impl Default for Vfs {
@@ -313,6 +319,10 @@ impl Vfs {
313319
lock: Mutex::new(()),
314320
initialized: AtomicBool::new(false),
315321
remove_pseudo_root: false,
322+
id_mapping: match opts.id_mapping.2 {
323+
0 => None,
324+
_ => Some(opts.id_mapping),
325+
},
316326
}
317327
}
318328

@@ -501,10 +511,54 @@ impl Vfs {
501511
self.convert_inode(fs_idx, inode).map(|ino| {
502512
entry.inode = ino;
503513
entry.attr.st_ino = ino;
514+
// If id_mapping is enabled, map the internal ID to the external ID.
515+
if let Some((internal_id, external_id, range)) = self.id_mapping {
516+
if entry.attr.st_uid >= internal_id && entry.attr.st_uid < internal_id + range {
517+
entry.attr.st_uid += external_id - internal_id;
518+
}
519+
if entry.attr.st_gid >= internal_id && entry.attr.st_gid < internal_id + range {
520+
entry.attr.st_gid += external_id - internal_id;
521+
}
522+
}
504523
*entry
505524
})
506525
}
507526

527+
/// If id_mapping is enabled, remap the uid/gid in attributes.
528+
///
529+
/// If `map_internal_to_external` is true, the IDs inside VFS will be mapped
530+
/// to external IDs.
531+
/// If `map_internal_to_external` is false, the external IDs will be mapped
532+
/// to VFS internal IDs.
533+
fn remap_attr_id(&self, map_internal_to_external: bool, attr: &mut stat64) {
534+
if let Some((internal_id, external_id, range)) = self.id_mapping {
535+
if map_internal_to_external
536+
&& attr.st_uid >= internal_id
537+
&& attr.st_uid < internal_id + range
538+
{
539+
attr.st_uid += external_id - internal_id;
540+
}
541+
if map_internal_to_external
542+
&& attr.st_gid >= internal_id
543+
&& attr.st_gid < internal_id + range
544+
{
545+
attr.st_gid += external_id - internal_id;
546+
}
547+
if !map_internal_to_external
548+
&& attr.st_uid >= external_id
549+
&& attr.st_uid < external_id + range
550+
{
551+
attr.st_uid += internal_id - external_id;
552+
}
553+
if !map_internal_to_external
554+
&& attr.st_gid >= external_id
555+
&& attr.st_gid < external_id + range
556+
{
557+
attr.st_gid += internal_id - external_id;
558+
}
559+
}
560+
}
561+
508562
fn allocate_fs_idx(&self) -> Result<VfsIndex> {
509563
let superblocks = self.superblocks.load().deref().deref().clone();
510564
let start = self.next_super.load(Ordering::SeqCst);

src/api/vfs/sync_io.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright 2020 Ant Financial. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use std::sync::Arc;
5+
46
use super::*;
57
use crate::abi::fuse_abi::{stat64, statvfs64};
68
#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
@@ -116,6 +118,7 @@ impl FileSystem for Vfs {
116118
fs.getattr(ctx, idata.ino(), handle)
117119
.map(|(mut attr, duration)| {
118120
attr.st_ino = idata.into();
121+
self.remap_attr_id(true, &mut attr);
119122
(attr, duration)
120123
})
121124
}
@@ -133,9 +136,12 @@ impl FileSystem for Vfs {
133136
match self.get_real_rootfs(inode)? {
134137
(Left(fs), idata) => fs.setattr(ctx, idata.ino(), attr, handle, valid),
135138
(Right(fs), idata) => {
139+
let mut attr = attr;
140+
self.remap_attr_id(false, &mut attr);
136141
fs.setattr(ctx, idata.ino(), attr, handle, valid)
137142
.map(|(mut attr, duration)| {
138143
attr.st_ino = idata.into();
144+
self.remap_attr_id(true, &mut attr);
139145
(attr, duration)
140146
})
141147
}
@@ -610,6 +616,7 @@ impl FileSystem for Vfs {
610616
dir_entry.ino = self.convert_inode(idata.fs_idx(), entry.inode)?;
611617
entry.inode = dir_entry.ino;
612618
entry.attr.st_ino = entry.inode;
619+
self.remap_attr_id(true, &mut entry.attr);
613620
add_entry(dir_entry, entry)
614621
},
615622
),
@@ -637,6 +644,21 @@ impl FileSystem for Vfs {
637644
}
638645
}
639646

647+
#[inline]
648+
fn id_remap(&self, ctx: &mut Context) -> Result<()> {
649+
// If id_mapping is enabled, map the external ID to the internal ID.
650+
if let Some((internal_id, external_id, range)) = self.id_mapping {
651+
if ctx.uid >= external_id && ctx.uid < external_id + range {
652+
ctx.uid += internal_id - external_id;
653+
}
654+
if ctx.gid >= external_id && ctx.gid < external_id + range {
655+
ctx.gid += internal_id - external_id;
656+
}
657+
}
658+
659+
Ok(())
660+
}
661+
640662
#[cfg(any(feature = "vhost-user-fs", feature = "virtiofs"))]
641663
fn setupmapping(
642664
&self,

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub enum Error {
8080
FailedToWrite(io::Error),
8181
/// Failed to split a writer.
8282
FailedToSplitWriter(transport::Error),
83+
/// Failed to remap uid/gid.
84+
FailedToRemapID((u32, u32)),
8385
}
8486

8587
impl error::Error for Error {}
@@ -101,6 +103,10 @@ impl fmt::Display for Error {
101103
InvalidMessage(err) => write!(f, "cannot process fuse message: {err}"),
102104
FailedToWrite(err) => write!(f, "cannot write to buffer: {err}"),
103105
FailedToSplitWriter(err) => write!(f, "cannot split a writer: {err}"),
106+
FailedToRemapID((uid, gid)) => write!(
107+
f,
108+
"failed to remap the context of user (uid={uid}, gid={gid})."
109+
),
104110
}
105111
}
106112
}

0 commit comments

Comments
 (0)