fs: Fix {GET,SET}FLAGS ioctls on arm

crosvm runs as a 32-bit binary on arm devices but arcvm has a 64-bit
kernel with a 64-bit userspace.  Since the {GET,SET}FLAGS ioctls use a
c_long as part of the encoding, the encoded value changes based on
whether a long is 4 bytes or 8 bytes. This causes a mismatch where the
server expects the 4 byte encoding while the VM sends the 8 byte
encoding.

Check for both encodings when handling ioctls.  The actual flag value
itself is actually just a c_int and not a c_long as you might expect
from the encoding. Since that has the same width on both 32 and 64 bit
systems we don't have to change the actual value that's returned.

BUG=b:163729385
TEST=lsattr and chattr still work inside the VM. Also use a test program
     to check that the 64-bit versions also work inside the VM.

Change-Id: I77e98ea83372306597f7b3eb2bd675035be98d5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2352281
Auto-Submit: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: Chirantan Ekbote <chirantan@chromium.org>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
This commit is contained in:
Chirantan Ekbote 2020-08-13 21:38:56 +09:00 committed by Commit Bot
parent 32f423723a
commit be48c252db

View file

@ -73,6 +73,12 @@ ioctl_iow_nr!(FS_IOC_FSSETXATTR, 'X' as u32, 32, fsxattr);
ioctl_ior_nr!(FS_IOC_GETFLAGS, 'f' as u32, 1, c_long);
ioctl_iow_nr!(FS_IOC_SETFLAGS, 'f' as u32, 2, c_long);
ioctl_ior_nr!(FS_IOC32_GETFLAGS, 'f' as u32, 1, u32);
ioctl_iow_nr!(FS_IOC32_SETFLAGS, 'f' as u32, 2, u32);
ioctl_ior_nr!(FS_IOC64_GETFLAGS, 'f' as u32, 1, u64);
ioctl_iow_nr!(FS_IOC64_SETFLAGS, 'f' as u32, 2, u64);
type Inode = u64;
type Handle = u64;
@ -2256,8 +2262,10 @@ impl FileSystem for PassthroughFs {
const SET_ENCRYPTION_POLICY: u32 = FS_IOC_SET_ENCRYPTION_POLICY() as u32;
const GET_FSXATTR: u32 = FS_IOC_FSGETXATTR() as u32;
const SET_FSXATTR: u32 = FS_IOC_FSSETXATTR() as u32;
const GET_FLAGS: u32 = FS_IOC_GETFLAGS() as u32;
const SET_FLAGS: u32 = FS_IOC_SETFLAGS() as u32;
const GET_FLAGS32: u32 = FS_IOC32_GETFLAGS() as u32;
const SET_FLAGS32: u32 = FS_IOC32_SETFLAGS() as u32;
const GET_FLAGS64: u32 = FS_IOC64_GETFLAGS() as u32;
const SET_FLAGS64: u32 = FS_IOC64_SETFLAGS() as u32;
// Normally, we wouldn't need to retry the FS_IOC_GET_ENCRYPTION_POLICY and
// FS_IOC_SET_ENCRYPTION_POLICY ioctls. Unfortunately, the I/O directions for both of them
@ -2301,14 +2309,14 @@ impl FileSystem for PassthroughFs {
self.set_fsxattr(handle, r)
}
}
GET_FLAGS => {
GET_FLAGS32 | GET_FLAGS64 => {
if out_size < size_of::<c_int>() as u32 {
Err(io::Error::from_raw_os_error(libc::ENOMEM))
} else {
self.get_flags(handle)
}
}
SET_FLAGS => {
SET_FLAGS32 | SET_FLAGS64 => {
if in_size < size_of::<c_int>() as u32 {
Err(io::Error::from_raw_os_error(libc::ENOMEM))
} else {