blob: 33f7d37591ae65486f3cf524649eb49baa1a0cde [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Common utilities for pseudo file implementations
use {
fidl_fuchsia_io::{
MODE_PROTECTION_MASK, MODE_TYPE_DIRECTORY, MODE_TYPE_FILE, OPEN_FLAG_APPEND,
OPEN_FLAG_DESCRIBE, OPEN_FLAG_DIRECTORY, OPEN_FLAG_NODE_REFERENCE, OPEN_FLAG_NOT_DIRECTORY,
OPEN_FLAG_POSIX, OPEN_FLAG_POSIX_EXECUTABLE, OPEN_FLAG_POSIX_WRITABLE, OPEN_FLAG_TRUNCATE,
OPEN_RIGHT_READABLE, OPEN_RIGHT_WRITABLE,
},
fuchsia_zircon::Status,
};
/// Validate that the requested flags for a new connection are valid. This validates flags against
/// the flags of the parent connection, as well as whether or not the pseudo file is readable or
/// writable at all (e.g. if an on_read or on_write function was provided, respectively). On success,
/// it returns the validated flags, with some ambiguities cleaned up. On failure, it returns a
/// [`Status`] indicating the problem.
///
/// Changing this function can be dangerous! Not only does it have obvious security implications, but
/// connections currently rely on it to reject unsupported functionality, such as attempting to read
/// from a file when `on_read` is `None`.
pub fn new_connection_validate_flags(
mut flags: u32,
mode: u32,
readable: bool,
writable: bool,
) -> Result<u32, Status> {
// There should be no MODE_TYPE_* flags set, except for, possibly, MODE_TYPE_FILE when the
// target is a pseudo file.
if (mode & !MODE_PROTECTION_MASK) & !MODE_TYPE_FILE != 0 {
if (mode & !MODE_PROTECTION_MASK) & MODE_TYPE_DIRECTORY != 0 {
return Err(Status::NOT_DIR);
} else {
return Err(Status::INVALID_ARGS);
};
}
if flags & OPEN_FLAG_NODE_REFERENCE != 0 {
flags &= !OPEN_FLAG_NODE_REFERENCE;
flags &= OPEN_FLAG_DIRECTORY | OPEN_FLAG_DESCRIBE;
}
if flags & OPEN_FLAG_DIRECTORY != 0 {
return Err(Status::NOT_DIR);
}
if flags & OPEN_FLAG_NOT_DIRECTORY != 0 {
flags &= !OPEN_FLAG_NOT_DIRECTORY;
}
// For files all OPEN_FLAG_POSIX flags are ignored as they have meaning only for directories.
flags &= !(OPEN_FLAG_POSIX | OPEN_FLAG_POSIX_WRITABLE | OPEN_FLAG_POSIX_EXECUTABLE);
let allowed_flags = OPEN_FLAG_DESCRIBE
| if readable { OPEN_RIGHT_READABLE } else { 0 }
| if writable { OPEN_RIGHT_WRITABLE | OPEN_FLAG_TRUNCATE } else { 0 };
let prohibited_flags = (0 | if readable {
OPEN_FLAG_TRUNCATE
} else {
0
} | if writable {
OPEN_FLAG_APPEND
} else {
0
})
// allowed_flags takes precedence over prohibited_flags.
& !allowed_flags;
if !readable && flags & OPEN_RIGHT_READABLE != 0 {
return Err(Status::ACCESS_DENIED);
}
if !writable && flags & OPEN_RIGHT_WRITABLE != 0 {
return Err(Status::ACCESS_DENIED);
}
if flags & prohibited_flags != 0 {
return Err(Status::INVALID_ARGS);
}
if flags & !allowed_flags != 0 {
return Err(Status::NOT_SUPPORTED);
}
Ok(flags)
}