Fix the chown syscall with negative id

This commit is contained in:
LI Qing 2024-03-12 13:28:55 +08:00 committed by volcano
parent 6eaad69941
commit db3a31d42e
4 changed files with 105 additions and 14 deletions

@ -7,12 +7,19 @@ bitflags! {
} }
} }
pub fn do_fchownat(fs_path: &FsPath, uid: u32, gid: u32, flags: ChownFlags) -> Result<()> { pub fn do_fchownat(fs_path: &FsPath, uid: i32, gid: i32, flags: ChownFlags) -> Result<()> {
debug!( debug!(
"fchownat: fs_path: {:?}, uid: {}, gid: {}, flags: {:?}", "fchownat: fs_path: {:?}, uid: {}, gid: {}, flags: {:?}",
fs_path, uid, gid, flags fs_path, uid, gid, flags
); );
let uid = to_opt(uid)?;
let gid = to_opt(gid)?;
// Return early if owner and group are -1
if uid.is_none() && gid.is_none() {
return Ok(());
}
let inode = { let inode = {
let path = fs_path.to_abs_path()?; let path = fs_path.to_abs_path()?;
let current = current!(); let current = current!();
@ -24,19 +31,47 @@ pub fn do_fchownat(fs_path: &FsPath, uid: u32, gid: u32, flags: ChownFlags) -> R
} }
}; };
let mut info = inode.metadata()?; let mut info = inode.metadata()?;
info.uid = uid as usize; if let Some(uid) = uid {
info.gid = gid as usize; info.uid = uid as usize;
}
if let Some(gid) = gid {
info.gid = gid as usize;
}
inode.set_metadata(&info)?; inode.set_metadata(&info)?;
Ok(()) Ok(())
} }
pub fn do_fchown(fd: FileDesc, uid: u32, gid: u32) -> Result<()> { pub fn do_fchown(fd: FileDesc, uid: i32, gid: i32) -> Result<()> {
debug!("fchown: fd: {}, uid: {}, gid: {}", fd, uid, gid); debug!("fchown: fd: {}, uid: {}, gid: {}", fd, uid, gid);
let uid = to_opt(uid)?;
let gid = to_opt(gid)?;
// Return early if owner and group are -1
if uid.is_none() && gid.is_none() {
return Ok(());
}
let file_ref = current!().file(fd)?; let file_ref = current!().file(fd)?;
let mut info = file_ref.metadata()?; let mut info = file_ref.metadata()?;
info.uid = uid as usize; if let Some(uid) = uid {
info.gid = gid as usize; info.uid = uid as usize;
}
if let Some(gid) = gid {
info.gid = gid as usize;
}
file_ref.set_metadata(&info)?; file_ref.set_metadata(&info)?;
Ok(()) Ok(())
} }
fn to_opt(id: i32) -> Result<Option<u32>> {
let id = if id >= 0 {
Some(id as u32)
} else if id == -1 {
// If the ID is specified as -1, then that ID is not changed
None
} else {
return_errno!(EINVAL, "invalid id");
};
Ok(id)
}

@ -606,16 +606,16 @@ pub fn do_fchmodat(dirfd: i32, path: *const i8, mode: u16) -> Result<isize> {
Ok(0) Ok(0)
} }
pub fn do_chown(path: *const i8, uid: u32, gid: u32) -> Result<isize> { pub fn do_chown(path: *const i8, uid: i32, gid: i32) -> Result<isize> {
self::do_fchownat(AT_FDCWD, path, uid, gid, 0) self::do_fchownat(AT_FDCWD, path, uid, gid, 0)
} }
pub fn do_fchown(fd: FileDesc, uid: u32, gid: u32) -> Result<isize> { pub fn do_fchown(fd: FileDesc, uid: i32, gid: i32) -> Result<isize> {
file_ops::do_fchown(fd, uid, gid)?; file_ops::do_fchown(fd, uid, gid)?;
Ok(0) Ok(0)
} }
pub fn do_fchownat(dirfd: i32, path: *const i8, uid: u32, gid: u32, flags: i32) -> Result<isize> { pub fn do_fchownat(dirfd: i32, path: *const i8, uid: i32, gid: i32, flags: i32) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)? let path = from_user::clone_cstring_safely(path)?
.to_string_lossy() .to_string_lossy()
.into_owned(); .into_owned();
@ -631,7 +631,7 @@ pub fn do_fchownat(dirfd: i32, path: *const i8, uid: u32, gid: u32, flags: i32)
Ok(0) Ok(0)
} }
pub fn do_lchown(path: *const i8, uid: u32, gid: u32) -> Result<isize> { pub fn do_lchown(path: *const i8, uid: i32, gid: i32) -> Result<isize> {
self::do_fchownat( self::do_fchownat(
AT_FDCWD, AT_FDCWD,
path, path,

@ -189,9 +189,9 @@ macro_rules! process_syscall_table_with_callback {
(Readlink = 89) => do_readlink(path: *const i8, buf: *mut u8, size: usize), (Readlink = 89) => do_readlink(path: *const i8, buf: *mut u8, size: usize),
(Chmod = 90) => do_chmod(path: *const i8, mode: u16), (Chmod = 90) => do_chmod(path: *const i8, mode: u16),
(Fchmod = 91) => do_fchmod(fd: FileDesc, mode: u16), (Fchmod = 91) => do_fchmod(fd: FileDesc, mode: u16),
(Chown = 92) => do_chown(path: *const i8, uid: u32, gid: u32), (Chown = 92) => do_chown(path: *const i8, uid: i32, gid: i32),
(Fchown = 93) => do_fchown(fd: FileDesc, uid: u32, gid: u32), (Fchown = 93) => do_fchown(fd: FileDesc, uid: i32, gid: i32),
(Lchown = 94) => do_lchown(path: *const i8, uid: u32, gid: u32), (Lchown = 94) => do_lchown(path: *const i8, uid: i32, gid: i32),
(Umask = 95) => do_umask(mask: u16), (Umask = 95) => do_umask(mask: u16),
(Gettimeofday = 96) => do_gettimeofday(tv_u: *mut timeval_t), (Gettimeofday = 96) => do_gettimeofday(tv_u: *mut timeval_t),
(Getrlimit = 97) => do_gettrlimit(resource: u32, rlim: *mut rlimit_t), (Getrlimit = 97) => do_gettrlimit(resource: u32, rlim: *mut rlimit_t),
@ -357,7 +357,7 @@ macro_rules! process_syscall_table_with_callback {
(Openat = 257) => do_openat(dirfd: i32, path: *const i8, flags: u32, mode: u16), (Openat = 257) => do_openat(dirfd: i32, path: *const i8, flags: u32, mode: u16),
(Mkdirat = 258) => do_mkdirat(dirfd: i32, path: *const i8, mode: u16), (Mkdirat = 258) => do_mkdirat(dirfd: i32, path: *const i8, mode: u16),
(Mknodat = 259) => handle_unsupported(), (Mknodat = 259) => handle_unsupported(),
(Fchownat = 260) => do_fchownat(dirfd: i32, path: *const i8, uid: u32, gid: u32, flags: i32), (Fchownat = 260) => do_fchownat(dirfd: i32, path: *const i8, uid: i32, gid: i32, flags: i32),
(Futimesat = 261) => do_futimesat(dirfd: i32, path: *const i8, times: *const timeval_t), (Futimesat = 261) => do_futimesat(dirfd: i32, path: *const i8, times: *const timeval_t),
(Fstatat = 262) => do_fstatat(dirfd: i32, path: *const i8, stat_buf: *mut Stat, flags: u32), (Fstatat = 262) => do_fstatat(dirfd: i32, path: *const i8, stat_buf: *mut Stat, flags: u32),
(Unlinkat = 263) => do_unlinkat(dirfd: i32, path: *const i8, flags: i32), (Unlinkat = 263) => do_unlinkat(dirfd: i32, path: *const i8, flags: i32),

@ -55,6 +55,57 @@ static int __test_chown(const char *file_path) {
return 0; return 0;
} }
static int __test_chown_with_negative_id(const char *file_path) {
struct stat old_stat_buf;
struct stat new_stat_buf;
uid_t uid = -100;
gid_t gid = -100;
int ret;
ret = chown(file_path, uid, gid);
if (!(ret < 0 && errno == EINVAL)) {
THROW_ERROR("chown should return EINVAL");
}
ret = stat(file_path, &old_stat_buf);
if (ret < 0) {
THROW_ERROR("failed to stat file");
}
uid = 100;
gid = -1;
ret = chown(file_path, uid, gid);
if (ret < 0) {
THROW_ERROR("failed to chown file");
}
ret = stat(file_path, &new_stat_buf);
if (ret < 0) {
THROW_ERROR("failed to stat file");
}
if (new_stat_buf.st_uid != uid || new_stat_buf.st_gid != old_stat_buf.st_gid) {
THROW_ERROR("check chown result failed");
}
old_stat_buf.st_uid = new_stat_buf.st_uid;
uid = -1;
gid = 100;
ret = chown(file_path, uid, gid);
if (ret < 0) {
THROW_ERROR("failed to chown file");
}
ret = stat(file_path, &new_stat_buf);
if (ret < 0) {
THROW_ERROR("failed to stat file");
}
if (new_stat_buf.st_uid != old_stat_buf.st_uid || new_stat_buf.st_gid != gid) {
THROW_ERROR("check chown result failed");
}
return 0;
}
static int __test_lchown(const char *file_path) { static int __test_lchown(const char *file_path) {
struct stat stat_buf; struct stat stat_buf;
uid_t uid = 100; uid_t uid = 100;
@ -188,6 +239,10 @@ static int test_chown() {
return test_chown_framework(__test_chown); return test_chown_framework(__test_chown);
} }
static int test_chown_with_negative_id() {
return test_chown_framework(__test_chown_with_negative_id);
}
static int test_lchown() { static int test_lchown() {
return test_chown_framework(__test_lchown); return test_chown_framework(__test_lchown);
} }
@ -210,6 +265,7 @@ static int test_fchownat_with_empty_path() {
static test_case_t test_cases[] = { static test_case_t test_cases[] = {
TEST_CASE(test_chown), TEST_CASE(test_chown),
TEST_CASE(test_chown_with_negative_id),
TEST_CASE(test_lchown), TEST_CASE(test_lchown),
TEST_CASE(test_fchown), TEST_CASE(test_fchown),
TEST_CASE(test_fchownat), TEST_CASE(test_fchownat),