Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use unguessable PipelineIds and FrameIds #14283

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Make PipelineIds and FrameIds unguessable

  • Loading branch information
cbrewster committed Jan 11, 2017
commit de128ad868f784941d39f99e2b540877940f8861

Some generated files are not rendered by default. Learn more.

@@ -18,7 +18,7 @@ use gleam::gl::types::{GLint, GLsizei};
use image::{DynamicImage, ImageFormat, RgbImage};
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
use msg::constellation_msg::{Key, KeyModifiers, KeyState, CONTROL};
use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId, TraversalDirection};
use msg::constellation_msg::{PipelineId, TraversalDirection};
use net_traits::image::base::{Image, PixelFormat};
use profile_traits::time::{self, ProfilerCategory, profile};
use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg};
@@ -67,8 +67,7 @@ trait ConvertPipelineIdFromWebRender {
impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId {
fn from_webrender(&self) -> PipelineId {
PipelineId {
namespace_id: PipelineNamespaceId(self.0),
index: PipelineIndex(self.1),
id: self.0,
}
}
}
@@ -84,7 +84,7 @@ use layout_traits::LayoutThreadFactory;
use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
use msg::constellation_msg::{FrameId, FrameType, PipelineId};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
use msg::constellation_msg::TraversalDirection;
use net_traits::{self, IpcSend, ResourceThreads};
use net_traits::image_cache_thread::ImageCacheThread;
use net_traits::pub_domains::reg_host;
@@ -256,10 +256,6 @@ pub struct Constellation<Message, LTF, STF> {
/// The currently focused pipeline for key events.
focus_pipeline_id: Option<PipelineId>,

/// Pipeline IDs are namespaced in order to avoid name collisions,
/// and the namespaces are allocated by the constellation.
next_pipeline_namespace_id: PipelineNamespaceId,

/// The size of the top-level window.
window_size: WindowSizeData,

@@ -489,8 +485,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>

let swmanager_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(swmanager_receiver);

PipelineNamespace::install(PipelineNamespaceId(0));

let mut constellation: Constellation<Message, LTF, STF> = Constellation {
script_sender: ipc_script_sender,
layout_sender: ipc_layout_sender,
@@ -512,8 +506,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
pipelines: HashMap::new(),
frames: HashMap::new(),
pending_frames: vec!(),
// We initialize the namespace at 1, since we reserved namespace 0 for the constellation
next_pipeline_namespace_id: PipelineNamespaceId(1),
root_frame_id: FrameId::new(),
focus_pipeline_id: None,
time_profiler_chan: state.time_profiler_chan,
@@ -560,14 +552,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.handle_shutdown();
}

/// Generate a new pipeline id namespace.
fn next_pipeline_namespace_id(&mut self) -> PipelineNamespaceId {
let namespace_id = self.next_pipeline_namespace_id;
let PipelineNamespaceId(ref mut i) = self.next_pipeline_namespace_id;
*i += 1;
namespace_id
}

/// Helper function for creating a pipeline
fn new_pipeline(&mut self,
pipeline_id: PipelineId,
@@ -647,7 +631,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
event_loop: event_loop,
load_data: load_data,
device_pixel_ratio: self.window_size.device_pixel_ratio,
pipeline_namespace_id: self.next_pipeline_namespace_id(),
prev_visibility: prev_visibility,
webrender_api_sender: self.webrender_api_sender.clone(),
is_private: is_private,
@@ -15,7 +15,7 @@ use gfx_traits::DevicePixel;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use layout_traits::LayoutThreadFactory;
use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespaceId};
use msg::constellation_msg::{FrameId, FrameType, PipelineId};
use net_traits::{IpcSend, ResourceThreads};
use net_traits::image_cache_thread::ImageCacheThread;
use profile_traits::mem as profile_mem;
@@ -159,9 +159,6 @@ pub struct InitialPipelineState {
/// Information about the page to load.
pub load_data: LoadData,

/// The ID of the pipeline namespace for this script thread.
pub pipeline_namespace_id: PipelineNamespaceId,

/// Pipeline visibility to be inherited
pub prev_visibility: Option<bool>,

@@ -265,7 +262,6 @@ impl Pipeline {
opts: (*opts::get()).clone(),
prefs: PREFS.cloned(),
pipeline_port: pipeline_port,
pipeline_namespace_id: state.pipeline_namespace_id,
layout_content_process_shutdown_chan: layout_content_process_shutdown_chan,
layout_content_process_shutdown_port: layout_content_process_shutdown_port,
script_content_process_shutdown_chan: script_content_process_shutdown_chan,
@@ -468,7 +464,6 @@ pub struct UnprivilegedPipelineContent {
opts: Opts,
prefs: HashMap<String, Pref>,
pipeline_port: IpcReceiver<LayoutControlMsg>,
pipeline_namespace_id: PipelineNamespaceId,
layout_content_process_shutdown_chan: IpcSender<()>,
layout_content_process_shutdown_port: IpcReceiver<()>,
script_content_process_shutdown_chan: IpcSender<()>,
@@ -499,7 +494,6 @@ impl UnprivilegedPipelineContent {
mem_profiler_chan: self.mem_profiler_chan.clone(),
devtools_chan: self.devtools_chan,
window_size: self.window_size,
pipeline_namespace_id: self.pipeline_namespace_id,
content_process_shutdown_chan: self.script_content_process_shutdown_chan,
webvr_thread: self.webvr_thread
}, self.load_data.clone());
@@ -17,6 +17,8 @@ heapsize_derive = "0.1"
plugins = {path = "../plugins"}
serde = "0.8"
serde_derive = "0.8"
servo_rand = {path = "../rand"}
uuid = { version = "0.3.1", features = ["v4", "serde"] }

This comment has been minimized.

@asajeffrey

asajeffrey Jan 20, 2017

Member

Can we use uuid = { version = "0.3.1", default-features = false, features = ["serde"] } to make sure we're not using rand?


[dependencies.webrender_traits]
git = "https://github.com/servo/webrender"
@@ -7,6 +7,9 @@

use std::cell::Cell;
use std::fmt;
use uuid::{Uuid, NAMESPACE_URL};
use servo_rand;
use servo_rand::Rand;
use webrender_traits;

#[derive(PartialEq, Eq, Copy, Clone, Debug, Deserialize, Serialize)]
@@ -162,117 +165,58 @@ pub enum TraversalDirection {
Back(usize),
}

/// Each pipeline ID needs to be unique. However, it also needs to be possible to
/// generate the pipeline ID from an iframe element (this simplifies a lot of other
/// code that makes use of pipeline IDs).
/// Each pipeline ID needs to be unique and unguessable to prevent spoofing.
/// It also needs to be possible to generate the pipeline ID from an iframe
/// element (this simplifies a lot of other code that makes use of pipeline IDs).
///
/// To achieve this, each pipeline index belongs to a particular namespace. There is
/// a namespace for the constellation thread, and also one for every script thread.
/// This allows pipeline IDs to be generated by any of those threads without conflicting
/// with pipeline IDs created by other script threads or the constellation. The
/// constellation is the only code that is responsible for creating new *namespaces*.
/// This ensures that namespaces are always unique, even when using multi-process mode.
///
/// It may help conceptually to think of the namespace ID as an identifier for the
/// thread that created this pipeline ID - however this is really an implementation
/// detail so shouldn't be relied upon in code logic. It's best to think of the
/// pipeline ID as a simple unique identifier that doesn't convey any more information.
#[derive(Clone, Copy)]
pub struct PipelineNamespace {
id: PipelineNamespaceId,
index: u32,
}

impl PipelineNamespace {
pub fn install(namespace_id: PipelineNamespaceId) {
PIPELINE_NAMESPACE.with(|tls| {
assert!(tls.get().is_none());
tls.set(Some(PipelineNamespace {
id: namespace_id,
index: 0,
}));
});
}

fn next_index(&mut self) -> u32 {
let result = self.index;
self.index = result + 1;
result
}

fn next_pipeline_id(&mut self) -> PipelineId {
PipelineId {
namespace_id: self.id,
index: PipelineIndex(self.next_index()),
}
}

fn next_frame_id(&mut self) -> FrameId {
FrameId {
namespace_id: self.id,
index: FrameIndex(self.next_index()),
}
}
}

thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct PipelineNamespaceId(pub u32);

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct PipelineIndex(pub u32);

/// To achieve this, each pipeline ID is a v4 UUID, which is an opaque 128 bit random token.
/// They are generated via a cryptographically-secure RNG, which provides the key properties
/// of uniqueness and unguessability that together make pipeline IDs unforgeable.
/// Uniqueness can be provided by any RNG with a sufficiently large period,
/// which will prevent the same pipeline ID from being generated more than once.
/// However, in order for the RNG output to be unguessable (i.e. an attacker
/// cannot predict the next output based on previous outputs, or reconstruct
/// previous outputs if (part of) the internal RNG state is revealed), the RNG
/// must be cryptographically secure.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct PipelineId {
pub namespace_id: PipelineNamespaceId,
pub index: PipelineIndex
#[ignore_heap_size_of = "no heapsize for uuid"]

This comment has been minimized.

@asajeffrey

asajeffrey Jan 10, 2017

Member

It would be nice if we could get a heap size for uuid.

pub id: Uuid,
}

impl PipelineId {
pub fn new() -> PipelineId {
PIPELINE_NAMESPACE.with(|tls| {
let mut namespace = tls.get().expect("No namespace set for this thread!");
let new_pipeline_id = namespace.next_pipeline_id();
tls.set(Some(namespace));
new_pipeline_id
})
let mut rng = servo_rand::thread_rng();
PipelineId {
id: Uuid::rand(&mut rng),

This comment has been minimized.

@asajeffrey

asajeffrey Jan 20, 2017

Member

Nit: might be easier to read as servo_rand::thread_rng()::gen()?

}
}

pub fn to_webrender(&self) -> webrender_traits::PipelineId {
let PipelineNamespaceId(namespace_id) = self.namespace_id;
let PipelineIndex(index) = self.index;
webrender_traits::PipelineId(namespace_id, index)
webrender_traits::PipelineId(self.id)
}
}

impl fmt::Display for PipelineId {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let PipelineNamespaceId(namespace_id) = self.namespace_id;
let PipelineIndex(index) = self.index;
write!(fmt, "({},{})", namespace_id, index)
self.id.simple().fmt(fmt)
}
}

thread_local!(pub static TOP_LEVEL_FRAME_ID: Cell<Option<FrameId>> = Cell::new(None));

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct FrameIndex(pub u32);

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct FrameId {
pub namespace_id: PipelineNamespaceId,
pub index: FrameIndex
#[ignore_heap_size_of = "no heapsize for uuid"]
pub id: Uuid,
}

impl FrameId {
pub fn new() -> FrameId {
PIPELINE_NAMESPACE.with(|tls| {
let mut namespace = tls.get().expect("No namespace set for this thread!");
let new_frame_id = namespace.next_frame_id();
tls.set(Some(namespace));
new_frame_id
})
let mut rng = servo_rand::thread_rng();
FrameId {
id: Uuid::rand(&mut rng),

This comment has been minimized.

}
}

/// Each script and layout thread should have the top-level frame id installed,
@@ -288,18 +232,13 @@ impl FrameId {

impl fmt::Display for FrameId {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let PipelineNamespaceId(namespace_id) = self.namespace_id;
let FrameIndex(index) = self.index;
write!(fmt, "({},{})", namespace_id, index)
self.id.simple().fmt(fmt)
}
}

// We provide ids just for unit testing.
pub const TEST_NAMESPACE: PipelineNamespaceId = PipelineNamespaceId(1234);
pub const TEST_PIPELINE_INDEX: PipelineIndex = PipelineIndex(5678);
pub const TEST_PIPELINE_ID: PipelineId = PipelineId { namespace_id: TEST_NAMESPACE, index: TEST_PIPELINE_INDEX };
pub const TEST_FRAME_INDEX: FrameIndex = FrameIndex(8765);
pub const TEST_FRAME_ID: FrameId = FrameId { namespace_id: TEST_NAMESPACE, index: TEST_FRAME_INDEX };
pub const TEST_PIPELINE_ID: PipelineId = PipelineId { id: NAMESPACE_URL };
pub const TEST_FRAME_ID: FrameId = FrameId { id: NAMESPACE_URL };

#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub enum FrameType {
@@ -15,6 +15,8 @@ extern crate heapsize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate servo_rand;
extern crate uuid;
extern crate webrender_traits;

pub mod constellation_msg;
@@ -70,7 +70,7 @@ use js::jsval::UndefinedValue;
use js::rust::Runtime;
use layout_wrapper::ServoLayoutNode;
use mem::heap_size_of_self_and_children;
use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace};
use msg::constellation_msg::{FrameId, FrameType, PipelineId};
use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener};
use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
@@ -527,7 +527,6 @@ impl ScriptThreadFactory for ScriptThread {
let layout_chan = sender.clone();
thread::Builder::new().name(format!("ScriptThread {:?}", state.id)).spawn(move || {
thread_state::initialize(thread_state::SCRIPT);
PipelineNamespace::install(state.pipeline_namespace_id);
FrameId::install(state.top_level_frame_id);
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
@@ -57,7 +57,7 @@ use hyper::method::Method;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use libc::c_void;
use msg::constellation_msg::{FrameId, FrameType, Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection};
use msg::constellation_msg::{PipelineId, TraversalDirection};
use net_traits::{ReferrerPolicy, ResourceThreads};
use net_traits::image::base::Image;
use net_traits::image_cache_thread::ImageCacheThread;
@@ -479,8 +479,6 @@ pub struct InitialScriptState {
pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// Information about the initial window size.
pub window_size: Option<WindowSizeData>,
/// The ID of the pipeline namespace for this script thread.
pub pipeline_namespace_id: PipelineNamespaceId,
/// A ping will be sent on this channel once the script thread shuts down.
pub content_process_shutdown_chan: IpcSender<()>,
/// A channel to the webvr thread, if available.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.