devices: fs: Fix linkat impl

Using AT_EMPTY_PATH with linkat requires the caller to have
CAP_DAC_READ_SEARCH in the init user namespace.  Since the fs device
isn't going to have this when run in a sandbox, switch to using
/proc/self/fd with AT_SYMLINK_FOLLOW instead, which is documented in the
manpage as an alternative to AT_EMPTY_PATH.

BUG=b:159861594
TEST=`touch foo; ln foo bar` succeeds

Change-Id: I944d80d955742d653e36d245024adc48cf77d77e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2265933
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
Auto-Submit: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Chirantan Ekbote 2020-06-25 13:57:46 +09:00 committed by Commit Bot
parent b865569893
commit d8447077f0

View file

@ -1640,17 +1640,17 @@ impl FileSystem for PassthroughFs {
.map(Arc::clone)
.ok_or_else(ebadf)?;
// Safe because this is a constant value and a valid C string.
let empty = unsafe { CStr::from_bytes_with_nul_unchecked(EMPTY_CSTR) };
let path = CString::new(format!("self/fd/{}", data.file.as_raw_fd()))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
// Safe because this doesn't modify any memory and we check the return value.
let res = unsafe {
libc::linkat(
data.file.as_raw_fd(),
empty.as_ptr(),
self.proc.as_raw_fd(),
path.as_ptr(),
new_inode.file.as_raw_fd(),
newname.as_ptr(),
libc::AT_EMPTY_PATH,
libc::AT_SYMLINK_FOLLOW,
)
};
if res == 0 {