Issue metadata
Sign in to add a comment
|
Security: GPU process MailboxManagerImpl double-reads |
||||||||||||||||||||||
Issue description
This template is ONLY for reporting security bugs. If you are reporting a
Download Protection Bypass bug, please use the "Security - Download
Protection" template. For all other reports, please use a different
template.
Please see the following link for instructions on filing security bugs:
http://www.chromium.org/Home/chromium-security/reporting-security-bugs
VULNERABILITY DETAILS
Several functions in the GPU command buffer service interact with the GPU
mailbox manager (gpu/command_buffer/service/mailbox_manager_impl.cc), passing a reference to shared memory as the mailbox argument.
MailboxManagerImpl does not expect this mailbox argument to be malleable in this way, and it is in several places copied and passed to various stl functions, resulting in unexpected behaviour resulting from double-reads when an attacker modifies the mailbox name mid function.
The attached POC uses the GPU command' ProduceTextureDirectCHROMIUMImmediate' to trigger a use-after-free but other commands that interact with the mailbox manager should also be vulnerable in a similar way.
error::Error GLES2DecoderImpl::HandleProduceTextureDirectCHROMIUMImmediate(
uint32_t immediate_data_size,
const void* cmd_data) {
const gles2::cmds::ProduceTextureDirectCHROMIUMImmediate& c =
*static_cast<const gles2::cmds::ProduceTextureDirectCHROMIUMImmediate*>(
cmd_data);
(void)c;
GLuint texture = c.texture;
GLenum target = static_cast<GLenum>(c.target);
uint32_t data_size;
if (!ComputeDataSize(1, sizeof(GLbyte), 64, &data_size)) {
return error::kOutOfBounds;
}
if (data_size > immediate_data_size) {
return error::kOutOfBounds;
}
// ** mailbox is a pointer into our shared memory buffer **
const GLbyte* mailbox =
GetImmediateDataAs<const GLbyte*>(c, data_size, immediate_data_size);
if (!validators_->texture_bind_target.IsValid(target)) {
LOCAL_SET_GL_ERROR_INVALID_ENUM("glProduceTextureDirectCHROMIUM", target,
"target");
return error::kNoError;
}
if (mailbox == NULL) {
return error::kOutOfBounds;
}
DoProduceTextureDirectCHROMIUM(texture, target, mailbox);
return error::kNoError;
}
void GLES2DecoderImpl::DoProduceTextureDirectCHROMIUM(GLuint client_id,
GLenum target, const GLbyte* data) {
TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoProduceTextureDirectCHROMIUM",
"context", logger_.GetLogPrefix(),
"mailbox[0]", static_cast<unsigned char>(data[0]));
ProduceTextureRef("glProduceTextureDirectCHROMIUM", GetTexture(client_id),
target, data);
}
void GLES2DecoderImpl::ProduceTextureRef(const char* func_name,
TextureRef* texture_ref,
GLenum target,
const GLbyte* data) {
// ** mailbox is still a pointer to shared memory **
const Mailbox& mailbox = *reinterpret_cast<const Mailbox*>(data);
DLOG_IF(ERROR, !mailbox.Verify()) << func_name << " was passed a "
"mailbox that was not generated by "
"GenMailboxCHROMIUM.";
if (!texture_ref) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, func_name, "unknown texture for target");
return;
}
Texture* produced = texture_manager()->Produce(texture_ref);
if (!produced) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, func_name, "invalid texture");
return;
}
if (produced->target() != target) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION, func_name, "invalid target");
return;
}
group_->mailbox_manager()->ProduceTexture(mailbox, produced);
}
void MailboxManagerImpl::ProduceTexture(const Mailbox& mailbox,
Texture* texture) {
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
if (it != mailbox_to_textures_.end()) {
if (it->second->first == texture)
return;
TextureToMailboxMap::iterator texture_it = it->second;
mailbox_to_textures_.erase(it);
textures_to_mailboxes_.erase(texture_it);
}
InsertTexture(mailbox, texture);
}
void MailboxManagerImpl::InsertTexture(const Mailbox& mailbox,
Texture* texture) {
texture->SetMailboxManager(this);
TextureToMailboxMap::iterator texture_it =
textures_to_mailboxes_.insert(std::make_pair(texture, mailbox));
// ** modify mailbox at this point **
mailbox_to_textures_.insert(std::make_pair(mailbox, texture_it));
DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
}
We can leverage this for memory corruption in the GPU process by a slightly roundabout route; since each entry in the mailbox_to_textures_ has an iterator to an entry in textures_to_mailboxes_, and it is an expected invariant that both of these entries have the same mailbox name. By starting to create a mailbox named aaaa...aaaa and waiting until the first insert is complete before changing the mailbox name to AAAA...aaaa, then adding a second entry with the same texture reference but with the actual name aaaa...aaaa we get the following situation (example trace through the code from ProduceTexture with InsertTexture call inlined):
// first entry - mailbox.name = 'aaaa...aaaa', texture = t1
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
// if body not executed
if (it != mailbox_to_textures_.end()) {}
texture->SetMailboxManager(this);
TextureToMailboxMap::iterator texture_it =
textures_to_mailboxes_.insert(std::make_pair(texture, mailbox));
// modify - mailbox.name = 'AAAA...aaaa'
mailbox_to_textures_.insert(std::make_pair(mailbox, texture_it));
DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
// mailbox_to_textures_ textures_to_mailboxes_
// AAAA...aaaa, it ------------------------------> aaaa...aaaa, t1
// second entry - mailbox.name = 'aaaa...aaaa', texture = t1
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
// if body not executed (since 'AAAA...aaaa' != 'aaaa...aaaa')
if (it != mailbox_to_textures_.end()) {}
texture->SetMailboxManager(this);
TextureToMailboxMap::iterator texture_it =
textures_to_mailboxes_.insert(std::make_pair(texture, mailbox));
// texture_it is the same as before; since there already exists the pair
// 'aaaa...aaaa', t1* in textures_to_mailboxes, the insert returns an iterator
// to the existing element.
mailbox_to_textures_.insert(std::make_pair(mailbox, texture_it));
DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
// mailbox_to_textures_ textures_to_mailboxes_
// AAAA...aaaa, it ------------------------------> aaaa...aaaa, t1
// aaaa...aaaa, it -----------/
// so both entries in mailbox_to_textures_ have the same iterator.
// third entry - mailbox.name = 'aaaa...aaaa', texture = t2
MailboxToTextureMap::iterator it = mailbox_to_textures_.find(mailbox);
// this time we find an entry
if (it != mailbox_to_textures_.end()) {
// t1 != t2
if (it->second->first == texture)
return;
// so we remove the previous entry for aaaa...aaaa
TextureToMailboxMap::iterator texture_it = it->second;
mailbox_to_textures_.erase(it);
textures_to_mailboxes_.erase(texture_it);
}
// mailbox_to_textures_ textures_to_mailboxes_
// AAAA...aaaa, it ------------------------------> ??
// aaaa...aaaa, it ------------------------------> aaaa...aaaa, t2
Leaving mailbox AAAA...aaaa with a dangling reference to a no-longer valid
iterator into textures_to_mailboxes_; (std::map and std::multimap iterators are invalidated by a call to erase() the element that they reference). The attached poc then calls some further methods on the mailbox to trigger a use-after-free of the dangling iterator that is detectable by ASAN.
This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.
VERSION
Chrome Version: Tested on 50.0.2661.49 (64-bit)
Operating System: Linux x64
REPRODUCTION CASE
Please include a demonstration of the security bug, such as an attached
HTML or binary file that reproduces the bug when loaded in Chrome. PLEASE
make the file as small as possible and remove any content not required to
demonstrate the bug.
FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION
Type of crash: GPU process
Crash State: See attached mailbox_asan.txt
Client ID (if relevant): [see link above]
,
Mar 24 2016
I'll take a look now.
,
Mar 24 2016
+piman Maybe we should copy some things on the stack in the autogenerated layer (gles2_cmd_decoder_autogen.h). There are two ways to pass arrays: through shared memory or in-line in the command ringbuffer. We use out-of-line shared memory for larger things (textures, buffer data) which is generally data that does not need to be validated and we don't want to copy. While we use 'immediate' for smaller things which mostly tend to be arrays of handles. Speaking of which, I think all the immediate Gen/Delete functions look prone to at least breaking our internal state tracking if modified by the client (and who knows what else might be exploitable there). Maybe the code generator should copy small arrays onto the stack. And for then Gen/Delete immediate/inline mode handlers, maybe we should always copy them onto the stack. I'm not sure if we would further then want to worry about robustness for when the client passes in a very large array of handles (maybe it's fine to crash the GPU process if the stack frame can't be allocated, or maybe we want to loop through them or put them onto the heap?).
,
Mar 24 2016
A couple other things that the generator could look at: - is the array size fixed (see 'count' field in build_gles2_cmd_buffer.py) - the type (GLEnum, and maybe GLByte and int vs. GLfloat for example) And we could further make the logic conservative: these things go on the stack by default unless overriden in the generator to be 'plain data i.e. non-handle type'.
,
Mar 24 2016
Yes, we should copy the mailbox onto the stack. Ditto for Gen/Delete. And agreed, we should do that in the code generator. Something that would be good to do is to mark the mapped client memory as volatile: 1- in theory compilers can elide copying things onto the stack if they can make sufficient analysis. They don't today, but volatile would prevent it from doing so. 2- it would help spot these problems with clear semantics: if memory is volatile, there can be TOCTOU issues; if it's not, it's safe. This is a fair amount of work though, due to the sheer number of entrypoints.
,
Mar 24 2016
So I think we can deal with the cases where ComputeDataSize(..) can be replaced with an expression (which includes the mentioned mailbox apis here) fairly easily by just having the code generator put an array on the stack and copy the data. For the ones where the number of elements is dynamic, we can either - put a fixed size (like |64 * sizeof(T)|) on the stack and then loop the command over it in the right way - or maintain a staging buffer on the heap that we grow (and shrink?) dynamically
,
Mar 24 2016
Or we could have the client use out-of-band memory if the total size becomes too big.
,
Mar 24 2016
Sorry heap I meant. But the client doesn't even need to know. We could just have a big enough stack frame for normal use cases and fall back to malloc/free when the data passed in is too big.
,
Mar 24 2016
Right, for large Gen/Delete, the cost of the allocation is probably negligible compared to the cost of the iteration (which will itself do allocations anyway).
,
Mar 25 2016
,
Mar 25 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/ff5407f8d6d71116e01d6ea18db75a4f8d1e0692 commit ff5407f8d6d71116e01d6ea18db75a4f8d1e0692 Author: sievers <sievers@chromium.org> Date: Fri Mar 25 22:07:52 2016 gpu: Pull some variables onto the stack in the decoder CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel BUG= 597636 , 597625 Review URL: https://codereview.chromium.org/1836603002 Cr-Commit-Position: refs/heads/master@{#383379} [modify] https://crrev.com/ff5407f8d6d71116e01d6ea18db75a4f8d1e0692/gpu/command_buffer/service/common_decoder.cc [modify] https://crrev.com/ff5407f8d6d71116e01d6ea18db75a4f8d1e0692/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 28 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/1feead4b00c2c275af33c7b9d161c92647f7e4ab commit 1feead4b00c2c275af33c7b9d161c92647f7e4ab Author: sievers <sievers@chromium.org> Date: Mon Mar 28 19:32:16 2016 gpu: Fix glitch with https://codereview.chromium.org/1836603002/ BUG= 597636 , 597625 CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel;tryserver.chromium.mac:mac_optional_gpu_tests_rel NOTRY=True Review URL: https://codereview.chromium.org/1835333002 Cr-Commit-Position: refs/heads/master@{#383539} [modify] https://crrev.com/1feead4b00c2c275af33c7b9d161c92647f7e4ab/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 31 2016
,
Mar 31 2016
,
Mar 31 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/fa022ffa4d5e7006d6bf9e59c8496118c08b084a commit fa022ffa4d5e7006d6bf9e59c8496118c08b084a Author: Daniel Sievers <sievers@chromium.org> Date: Thu Mar 31 18:46:50 2016 gpu: Pull some variables onto the stack in the decoder CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel BUG= 597636 , 597625 Review URL: https://codereview.chromium.org/1836603002 Cr-Commit-Position: refs/heads/master@{#383379} (cherry picked from commit ff5407f8d6d71116e01d6ea18db75a4f8d1e0692) Review URL: https://codereview.chromium.org/1843663007 . Cr-Commit-Position: refs/branch-heads/2661@{#449} Cr-Branched-From: ef6f6ae5e4c96622286b563658d5cd62a6cf1197-refs/heads/master@{#378081} [modify] https://crrev.com/fa022ffa4d5e7006d6bf9e59c8496118c08b084a/gpu/command_buffer/service/common_decoder.cc [modify] https://crrev.com/fa022ffa4d5e7006d6bf9e59c8496118c08b084a/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 31 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/770a1a07c0b04c1a40df1384fff41d227b38b7ae commit 770a1a07c0b04c1a40df1384fff41d227b38b7ae Author: Daniel Sievers <sievers@chromium.org> Date: Thu Mar 31 18:51:35 2016 gpu: Fix glitch with https://codereview.chromium.org/1836603002/ BUG= 597636 , 597625 CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel;tryserver.chromium.mac:mac_optional_gpu_tests_rel NOTRY=True Review URL: https://codereview.chromium.org/1835333002 Cr-Commit-Position: refs/heads/master@{#383539} (cherry picked from commit 1feead4b00c2c275af33c7b9d161c92647f7e4ab) Review URL: https://codereview.chromium.org/1845273003 . Cr-Commit-Position: refs/branch-heads/2661@{#450} Cr-Branched-From: ef6f6ae5e4c96622286b563658d5cd62a6cf1197-refs/heads/master@{#378081} [modify] https://crrev.com/770a1a07c0b04c1a40df1384fff41d227b38b7ae/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 31 2016
Please mark security bugs as fixed as soon as the fix lands, and before requesting merges. - Your friendly ClusterFuzz
,
Apr 1 2016
,
May 16 2016
,
Jun 9 2016
Hey, just checking that this (and the other similar issues) have been fixed in a stable release? I didn't see a reference to it in the security notes, and I want to tag our tracker appropriately with the fix date.
,
Jun 9 2016
Patch landed on 51.0.2691.0, so it should be in 51 stable (51.0.2704.*)
,
Jul 8 2016
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Aug 24 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/a17d2bcbccfda0480ed429897f243ca908dd6c15 commit a17d2bcbccfda0480ed429897f243ca908dd6c15 Author: piman <piman@chromium.org> Date: Wed Aug 24 03:05:29 2016 Command buffers: ensure we only read immediate data once Fizes various issues where we may be reading some immediate data twice: - Gen*, Delete* - InvalidateFramebuffer and friends - DrawBuffersEXT - Some Uniform* and VertexAttrib* - Mailbox functions BUG= 597625 , 597636 CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel Review-Url: https://codereview.chromium.org/2264253003 Cr-Commit-Position: refs/heads/master@{#413962} [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/build_gles2_cmd_buffer.py [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/context_group.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
,
Sep 6 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/a728ad1c1b56c5c81c516ad11fead19e569b046e commit a728ad1c1b56c5c81c516ad11fead19e569b046e Author: piman <piman@chromium.org> Date: Tue Sep 06 16:48:08 2016 Make command buffer commands and immediate data volatile Because command buffer commands and immediate data live in shared memory that can be modified by an untrusted process, the data must be tagged as volatile to ensure that compiler does not optimize the service-side checks in a way that could cause double reads / TOCTOU issues. Additionally, this provides a good indication that pointers reference attacker-controlled memory. BUG= 597625 , 597636 CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel Review-Url: https://codereview.chromium.org/2275203002 Cr-Commit-Position: refs/heads/master@{#416646} [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/build_gles2_cmd_buffer.py [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/client/ring_buffer_test.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/cmd_buffer_common.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/gles2_cmd_format_autogen.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/gles2_cmd_utils.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/mailbox.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/cmd_parser.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/cmd_parser.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/common_decoder.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/common_decoder.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/common_decoder_unittest.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_mock.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/mocks.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/mocks.h
,
Oct 1 2016
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Oct 2 2016
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Oct 2 2016
|
|||||||||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||||||||
Comment 1 by wfh@chromium.org
, Mar 24 2016Components: Internals>GPU>Internals Internals>GPU
Labels: Security_Severity-High Security_Impact-Stable OS-All Pri-1
Owner: siev...@chromium.org
Status: Assigned (was: Unconfirmed)