Fix the chown syscall with negative id
This commit is contained in:
parent
6eaad69941
commit
db3a31d42e
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user