[starnix] Implement O_TRUNC for open
Test: open_test
Bug: 79308
Change-Id: Idb38de3b5c0e80fffc6657b10120aabffe4e77a1
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/559447
Commit-Queue: Adam Barth <abarth@google.com>
Fuchsia-Auto-Submit: Adam Barth <abarth@google.com>
Reviewed-by: Theodore Dubois <tbodt@google.com>
diff --git a/src/proc/bin/starnix/fs/syscalls.rs b/src/proc/bin/starnix/fs/syscalls.rs
index 9ff1b4b..85d3762 100644
--- a/src/proc/bin/starnix/fs/syscalls.rs
+++ b/src/proc/bin/starnix/fs/syscalls.rs
@@ -229,10 +229,10 @@
return Ok(SUCCESS);
}
- // TODO: These access checks are not quite correct because they don't
- // consider the current uid and they don't consider GRO or OTH bits.
- // Really, these checks should be done by the auth system once that
- // exists.
+ // TODO(security): These access checks are not quite correct because
+ // they don't consider the current uid and they don't consider GRO or
+ // OTH bits. Really, these checks should be done by the auth system once
+ // that exists.
let stat = node.stat()?;
if mode & X_OK != 0 && stat.st_mode & S_IXUSR == 0 {
return Err(EACCES);
diff --git a/src/proc/bin/starnix/task/task.rs b/src/proc/bin/starnix/task/task.rs
index f9d4ea9..0f86ef4 100644
--- a/src/proc/bin/starnix/task/task.rs
+++ b/src/proc/bin/starnix/task/task.rs
@@ -454,7 +454,32 @@
parent.mknod(basename, FileMode::IFREG | access, 0)?
}
};
- node.open(flags)
+
+ let file = node.open(flags)?;
+
+ if flags.contains(OpenFlags::TRUNC) {
+ let node = file.node();
+ let mode = node.info().mode;
+ match mode.fmt() {
+ FileMode::IFREG => {
+ // You might think we should check file.can_write() at this
+ // point, which is what the docs suggest, but apparently we
+ // are supposed to truncate the file if this task can write
+ // to the underlying node, even if we are opening the file
+ // as read-only. See OpenTest.CanTruncateReadOnly.
+
+ // TODO(security): We should really do an access check for whether
+ // this task can write to this file.
+ if mode.contains(FileMode::IWUSR) {
+ node.truncate(0)?;
+ }
+ }
+ FileMode::IFDIR => return Err(EISDIR),
+ _ => (),
+ }
+ }
+
+ Ok(file)
}
/// A wrapper for FsContext::lookup_parent_at that resolves the given
diff --git a/src/proc/bin/starnix/types/file_mode.rs b/src/proc/bin/starnix/types/file_mode.rs
index 7e673f6..5c8a59b 100644
--- a/src/proc/bin/starnix/types/file_mode.rs
+++ b/src/proc/bin/starnix/types/file_mode.rs
@@ -20,6 +20,22 @@
pub const IFIFO: FileMode = FileMode(uapi::S_IFIFO);
pub const IFSOCK: FileMode = FileMode(uapi::S_IFSOCK);
+ pub const ISUID: FileMode = FileMode(uapi::S_ISUID);
+ pub const ISGID: FileMode = FileMode(uapi::S_ISGID);
+ pub const ISVTX: FileMode = FileMode(uapi::S_ISVTX);
+ pub const IRWXU: FileMode = FileMode(uapi::S_IRWXU);
+ pub const IRUSR: FileMode = FileMode(uapi::S_IRUSR);
+ pub const IWUSR: FileMode = FileMode(uapi::S_IWUSR);
+ pub const IXUSR: FileMode = FileMode(uapi::S_IXUSR);
+ pub const IRWXG: FileMode = FileMode(uapi::S_IRWXG);
+ pub const IRGRP: FileMode = FileMode(uapi::S_IRGRP);
+ pub const IWGRP: FileMode = FileMode(uapi::S_IWGRP);
+ pub const IXGRP: FileMode = FileMode(uapi::S_IXGRP);
+ pub const IRWXO: FileMode = FileMode(uapi::S_IRWXO);
+ pub const IROTH: FileMode = FileMode(uapi::S_IROTH);
+ pub const IWOTH: FileMode = FileMode(uapi::S_IWOTH);
+ pub const IXOTH: FileMode = FileMode(uapi::S_IXOTH);
+
pub const IFMT: FileMode = FileMode(uapi::S_IFMT);
pub const DEFAULT_UMASK: FileMode = FileMode(0o022);
@@ -34,6 +50,10 @@
self.0
}
+ pub fn contains(&self, other: FileMode) -> bool {
+ *self & other != FileMode::EMPTY
+ }
+
pub fn fmt(&self) -> FileMode {
FileMode(self.bits() & uapi::S_IFMT)
}
diff --git a/src/proc/tests/android/meta/open_test.cml b/src/proc/tests/android/meta/open_test.cml
index 380816a..7e14a85 100644
--- a/src/proc/tests/android/meta/open_test.cml
+++ b/src/proc/tests/android/meta/open_test.cml
@@ -2,7 +2,7 @@
include: [ "//src/sys/test_runners/starnix/default.shard.cml" ],
program: {
binary: "/data/tests/open_test",
- args: [ "--gunit_filter=*.OTruncAndReadOnlyFile:*.ReadOnly:*.WriteOnly:*.ReadWrite:*.RelPath:*.AbsPath:*.AtRelPath:*.AtAbsPath:*.OpenNoFollowStillFollowsLinksInPath:*.Fault:*.NameTooLong:*.DotsFromRoot:*.SymlinkDirectory" ],
+ args: [ "--gunit_filter=*.OTrunc:*.OTruncAndReadOnlyDir:*.OTruncAndReadOnlyFile:*.ReadOnly:*.WriteOnly:*.ReadWrite:*.RelPath:*.AbsPath:*.AtRelPath:*.AtAbsPath:*.OpenNoFollowStillFollowsLinksInPath:*.Fault:*.Truncate:*.NameTooLong:*.DotsFromRoot:*.SymlinkDirectory:*.CanTruncateReadOnly" ],
mounts: [
"/:remotefs:root",
"/data:remotefs:data",