vm_tools: p9: Use MAPPED_FLAGS for P9_{CREATE,EXCL,TRUNC,APPEND}
The rust standard library fails with InvalidInput for any call to open
where create[_new] is set, but write is not set.
https://rust-lang.github.io/rfcs/1252-open-options.html#combination-of-access-modes-and-creation-modes
This fails for some clients such as Microsoft Edge. It creates an empty
file first as O_RDONLY before reopening as O_RDWR to download a file.
Rather than call `.create`, `.create_new`, `.truncate`, or `.append`, in
lopen and lcreate, we have added P9_CREATE, P9_EXCL, P9_TRUNC, and
P9_APPEND to MAPPED_FLAGS, and we unconditionally set O_CREAT|O_EXCL for
lcreate.
BUG=b:161856673
TEST=unit tests
Change-Id: I010d91fa4b14ebb911f26df3af347a2be40e885d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2324089
Tested-by: Joel Hockey <joelhockey@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Auto-Submit: Joel Hockey <joelhockey@chromium.org>
diff --git a/vm_tools/p9/src/server/mod.rs b/vm_tools/p9/src/server/mod.rs
index 0d3038b..640b080 100644
--- a/vm_tools/p9/src/server/mod.rs
+++ b/vm_tools/p9/src/server/mod.rs
@@ -39,8 +39,12 @@
const P9_SYNC: u32 = 0o04000000;
// Mapping from 9P flags to libc flags.
-const MAPPED_FLAGS: [(u32, i32); 10] = [
+const MAPPED_FLAGS: [(u32, i32); 14] = [
+ (P9_CREATE, libc::O_CREAT),
+ (P9_EXCL, libc::O_EXCL),
(P9_NOCTTY, libc::O_NOCTTY),
+ (P9_TRUNC, libc::O_TRUNC),
+ (P9_APPEND, libc::O_APPEND),
(P9_NONBLOCK, libc::O_NONBLOCK),
(P9_DSYNC, libc::O_DSYNC),
(P9_FASYNC, 0), // Unsupported
@@ -528,13 +532,10 @@
}
}
+ // MAPPED_FLAGS will handle append, create[_new], and truncate.
let file = fs::OpenOptions::new()
.read((lopen.flags & P9_NOACCESS) == 0 || (lopen.flags & P9_RDWR) != 0)
.write((lopen.flags & P9_WRONLY) != 0 || (lopen.flags & P9_RDWR) != 0)
- .append((lopen.flags & P9_APPEND) != 0)
- .truncate((lopen.flags & P9_TRUNC) != 0)
- .create((lopen.flags & P9_CREATE) != 0)
- .create_new((lopen.flags & P9_CREATE) != 0 && (lopen.flags & P9_EXCL) != 0)
.custom_flags(custom_flags)
.open(&fid.path)?;
@@ -567,14 +568,11 @@
}
}
- // The file must not already exist, which is why we unconditionally set
- // `create_new(true)`. This is also why we don't set `truncate`. If
- // the file does not exist then it doesn't need to be truncated.
+ // Set O_CREAT|O_EXCL, MAPPED_FLAGS will handle append and truncate.
+ custom_flags |= libc::O_CREAT | libc::O_EXCL;
let file = fs::OpenOptions::new()
.read((lcreate.flags & P9_NOACCESS) == 0 || (lcreate.flags & P9_RDWR) != 0)
.write((lcreate.flags & P9_WRONLY) != 0 || (lcreate.flags & P9_RDWR) != 0)
- .append((lcreate.flags & P9_APPEND) != 0)
- .create_new(true)
.custom_flags(custom_flags)
.mode(lcreate.mode & 0o755)
.open(&path)?;
diff --git a/vm_tools/p9/src/server/tests.rs b/vm_tools/p9/src/server/tests.rs
index 15d569e..56bec39 100644
--- a/vm_tools/p9/src/server/tests.rs
+++ b/vm_tools/p9/src/server/tests.rs
@@ -919,7 +919,7 @@
}
// Check that we can write to the file.
- if $flags & P9_RDWR != 0 || $flags & P9_WRONLY != 0 || $flags & P9_APPEND != 0 {
+ if $flags & P9_RDWR != 0 || $flags & P9_WRONLY != 0 {
write(&mut server, &test_dir, name, fid, $flags);
}
@@ -950,11 +950,7 @@
open_test!(read_write_file_open, P9_RDWR);
open_test!(write_only_file_open, P9_WRONLY);
-open_test!(
- create_read_only_file_open,
- P9_CREATE | _P9_RDONLY,
- io::ErrorKind::InvalidInput
-);
+open_test!(create_read_only_file_open, P9_CREATE | _P9_RDONLY);
open_test!(create_read_write_file_open, P9_CREATE | P9_RDWR);
open_test!(create_write_only_file_open, P9_CREATE | P9_WRONLY);
@@ -962,11 +958,7 @@
open_test!(append_read_write_file_open, P9_APPEND | P9_RDWR);
open_test!(append_write_only_file_open, P9_APPEND | P9_WRONLY);
-open_test!(
- trunc_read_only_file_open,
- P9_TRUNC | _P9_RDONLY,
- io::ErrorKind::InvalidInput
-);
+open_test!(trunc_read_only_file_open, P9_TRUNC | _P9_RDONLY);
open_test!(trunc_read_write_file_open, P9_TRUNC | P9_RDWR);
open_test!(trunc_write_only_file_open, P9_TRUNC | P9_WRONLY);
@@ -985,8 +977,7 @@
open_test!(
create_trunc_read_only_file_open,
- P9_CREATE | P9_TRUNC | _P9_RDONLY,
- io::ErrorKind::InvalidInput
+ P9_CREATE | P9_TRUNC | _P9_RDONLY
);
open_test!(
create_trunc_read_write_file_open,
@@ -999,40 +990,34 @@
open_test!(
append_trunc_read_only_file_open,
- P9_APPEND | P9_TRUNC | _P9_RDONLY,
- io::ErrorKind::InvalidInput
+ P9_APPEND | P9_TRUNC | _P9_RDONLY
);
open_test!(
append_trunc_read_write_file_open,
- P9_APPEND | P9_TRUNC | P9_RDWR,
- io::ErrorKind::InvalidInput
+ P9_APPEND | P9_TRUNC | P9_RDWR
);
open_test!(
append_trunc_wronly_file_open,
- P9_APPEND | P9_TRUNC | P9_WRONLY,
- io::ErrorKind::InvalidInput
+ P9_APPEND | P9_TRUNC | P9_WRONLY
);
open_test!(
create_append_trunc_read_only_file_open,
- P9_CREATE | P9_APPEND | P9_TRUNC | _P9_RDONLY,
- io::ErrorKind::InvalidInput
+ P9_CREATE | P9_APPEND | P9_TRUNC | _P9_RDONLY
);
open_test!(
create_append_trunc_read_write_file_open,
- P9_CREATE | P9_APPEND | P9_TRUNC | P9_RDWR,
- io::ErrorKind::InvalidInput
+ P9_CREATE | P9_APPEND | P9_TRUNC | P9_RDWR
);
open_test!(
create_append_trunc_wronly_file_open,
- P9_CREATE | P9_APPEND | P9_TRUNC | P9_WRONLY,
- io::ErrorKind::InvalidInput
+ P9_CREATE | P9_APPEND | P9_TRUNC | P9_WRONLY
);
open_test!(
create_excl_read_only_file_open,
P9_CREATE | P9_EXCL | _P9_RDONLY,
- io::ErrorKind::InvalidInput
+ io::ErrorKind::AlreadyExists
);
open_test!(
create_excl_read_write_file_open,
@@ -1063,7 +1048,7 @@
check_attr(&mut server, fid, &md);
// Check that we can write to the file.
- if $flags & P9_RDWR != 0 || $flags & P9_WRONLY != 0 || $flags & P9_APPEND != 0 {
+ if $flags & P9_RDWR != 0 || $flags & P9_WRONLY != 0 {
write(&mut server, &test_dir, name, fid, $flags);
}
@@ -1089,12 +1074,7 @@
};
}
-create_test!(
- read_only_file_create,
- _P9_RDONLY,
- 0o600u32,
- io::ErrorKind::InvalidInput
-);
+create_test!(read_only_file_create, _P9_RDONLY, 0o600u32);
create_test!(read_write_file_create, P9_RDWR, 0o600u32);
create_test!(write_only_file_create, P9_WRONLY, 0o600u32);