Skip to content

Commit

Permalink
Merge pull request #16252 from electron/miniak/guest-view-manager
Browse files Browse the repository at this point in the history
fix: security: improve IPC validation in guest-view-manager
  • Loading branch information
nornagon committed Jan 5, 2019
2 parents 9cc3fba + a0cdcc5 commit 959c7a7
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 18 deletions.
52 changes: 36 additions & 16 deletions lib/browser/guest-view-manager.js
Expand Up @@ -184,9 +184,12 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
const guestInstance = guestInstances[guestInstanceId]
// If this isn't a valid guest instance then do nothing.
if (!guestInstance) {
return
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
}
const { guest } = guestInstance
if (guest.hostWebContents !== event.sender) {
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`)
}

// If this guest is already attached to an element then remove it
if (guestInstance.elementInstanceId) {
Expand Down Expand Up @@ -351,26 +354,35 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST_SYNC', function (event,
})

handleMessage('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, guestInstanceId) {
const guest = getGuest(guestInstanceId)
if (guest) {
try {
const guest = getGuestForWebContents(guestInstanceId, event.sender)
guest.destroy()
} catch (error) {
console.error(`Guest destroy failed: ${error}`)
}
})

handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embedderFrameId, elementInstanceId, guestInstanceId, params) {
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
try {
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params)
} catch (error) {
console.error(`Guest attach failed: ${error}`)
}
})

handleMessage('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
event.sender.emit('focus-change', {}, focus, guestInstanceId)
// this message is sent by the actual <webview>
ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
const guest = getGuest(guestInstanceId)
if (guest === event.sender) {
event.sender.emit('focus-change', {}, focus, guestInstanceId)
} else {
console.error(`focus-change for guestInstanceId: ${guestInstanceId}`)
}
})

handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', function (event, requestId, guestInstanceId, method, args, hasCallback) {
new Promise(resolve => {
const guest = getGuest(guestInstanceId)
if (guest.hostWebContents !== event.sender) {
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
}
const guest = getGuestForWebContents(guestInstanceId, event.sender)
if (!asyncMethods.has(method)) {
throw new Error(`Invalid method: ${method}`)
}
Expand All @@ -390,10 +402,7 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ASYNC_CALL', function (event, request

handleMessage('ELECTRON_GUEST_VIEW_MANAGER_SYNC_CALL', function (event, guestInstanceId, method, args) {
try {
const guest = getGuest(guestInstanceId)
if (guest.hostWebContents !== event.sender) {
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
}
const guest = getGuestForWebContents(guestInstanceId, event.sender)
if (!syncMethods.has(method)) {
throw new Error(`Invalid method: ${method}`)
}
Expand All @@ -403,6 +412,18 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_SYNC_CALL', function (event, guestIns
}
})

// Returns WebContents from its guest id hosted in given webContents.
const getGuestForWebContents = function (guestInstanceId, contents) {
const guest = getGuest(guestInstanceId)
if (!guest) {
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`)
}
if (guest.hostWebContents !== contents) {
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`)
}
return guest
}

// Returns WebContents from its guest id.
const getGuest = function (guestInstanceId) {
const guestInstance = guestInstances[guestInstanceId]
Expand All @@ -415,5 +436,4 @@ const getEmbedder = function (guestInstanceId) {
if (guestInstance != null) return guestInstance.embedder
}

exports.getGuest = getGuest
exports.getEmbedder = getEmbedder
exports.getGuestForWebContents = getGuestForWebContents
5 changes: 3 additions & 2 deletions lib/browser/rpc-server.js
Expand Up @@ -13,6 +13,7 @@ const { isPromise } = electron

const ipcMain = require('@electron/internal/browser/ipc-main-internal')
const objectsRegistry = require('@electron/internal/browser/objects-registry')
const guestViewManager = require('@electron/internal/browser/guest-view-manager')
const bufferUtils = require('@electron/internal/common/buffer-utils')
const errorUtils = require('@electron/internal/common/error-utils')

Expand Down Expand Up @@ -411,8 +412,8 @@ handleRemoteCommand('ELECTRON_BROWSER_CONTEXT_RELEASE', (event, contextId) => {
})

handleRemoteCommand('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId) {
const guestViewManager = require('@electron/internal/browser/guest-view-manager')
return valueToMeta(event.sender, contextId, guestViewManager.getGuest(guestInstanceId))
const guest = guestViewManager.getGuestForWebContents(guestInstanceId, event.sender)
return valueToMeta(event.sender, contextId, guest)
})

// Implements window.close()
Expand Down

0 comments on commit 959c7a7

Please sign in to comment.