REB wrote:
>  No, Dan made a typo, he wrote /wsvn/ instead of /svn/ 

Blasphemy. Dan does not make mistakes ;)

In this case, I had used the recommended best practice of MoinMoin interwiki 
links: I never typed wsvn or svn at all; instead, what I had written was:

    [[JSvn:DanBron/trunk/general/unlock.ijs|unlock.ijs]]

The “JSvn:” interwiki shortcut is a layer of indirection which is supposed to 
protect Wiki editors from volatile URLs (while at the same time offering typing 
shortcuts which make linking more convenient).

However, in this case, the Interwiki repository has not been kept up to date.  
In http://www.jsoftware.com/jwiki/InterWiki 
<http://www.jsoftware.com/jwiki/InterWiki>, we see that JSvn is still mapped to 
http://www.jsoftware.com/wsvn/ <http://www.jsoftware.com/wsvn/>, though svn has 
been rebased to /svn/ (as you said) since. 

I’m not a MoinMoin administrator, so I can’t change the official Interwiki 
page, so I hard-coded the direct /svn/ link in the Unlock page.  I don’t have 
the time or will to go through other pages I control to make more systematic 
changes.  Better for Chris or some other MoinMoin admin to update all the 
/wsvn/ links on the central Interwiki page*. 

Pascal (originally) asked:
>  does the unlock script need access to the locked file, or 
>  does it do everything in memory?

It does everything in memory, but it relies on an exploit that (I believe) has 
since been patched. In short, this used to produce the definition of the quoted 
name, even when locked:

        'pwdcheck' f.
     pwdcheck

As you can see, as of J803 (at most), it no longer does.

The only other trick the unlock script exploited was 4!:5, used precisely as 
intended: to discover which names a script defines. That’s necessary because 
the “interesting” parts of a script may not be exposed in the documented 
interface.  

> Dan alluded that he could attack it in memory with undocumented 15!:6

The unlock script depended only on the (now patched) exploit  ‘name’ f.  . It 
didn’t make any use of 15!:6 .  

But you’re right that I made the claim:

>  I want to stress that the exploit above isn't the problem, only an 
>  demonstration of it. Even if Roger "fixed" f. and 4!:5, other
>  approaches are possible. For example, I could use 15!:6 and 15!:7. 

So, now that the very situation I described has occurred (i.e. Roger fixed f.), 
can I carry out my threat?

Well … not with a simple application of 15!:6 **.  However unintentional, that 
foreign can no longer be applied to pro-verbs, pro-adverbs, or pro-conjunctions 
[1]. It can only be used to get the address of pro-nouns these days.  Which has 
frustrated me on more than one occasion (see a list of personal utilities this 
change broke in the postscript to [2]).

However, while the easy paths have been closed, the point still remains: 3!:6 
doesn’t encrypt files, it merely encodes them.  As I said in the original 
message (and Wiki page), and others have pointed out in this very thread, it is 
not possible keep secrets from a user when the user himself holds the key.  

If you’re not entering a key, personally, every time a name is unlocked, 
someone else is. In this case, that someone is your user (via J).

With all that said, Raul and the others are right: security is a matter of 
degree, not binary, and J itself is a kind of encoding layer which will 
dissuade all but the most persistent of snoopers. Add a bit of 3!:6 encoding on 
top, and I’d call that “secure enough” for non-critical secrets.

-Dan

[1] J602 introduces breaking change to undocumented foreign 15!:6 :
    http://www.jsoftware.com/pipermail/general/2008-November/032554.html 
<http://www.jsoftware.com/pipermail/general/2008-November/032554.html>

[2] List of personal utilities the change to 15!:6 broke for me 
    (see postscript of this message):
    http://www.jsoftware.com/pipermail/programming/2013-October/033760.html 
<http://www.jsoftware.com/pipermail/programming/2013-October/033760.html>

 * Upon investigation, it appears that /wsvn/ is also a valid URL, but only for 
web-browsing, i.e. prettified, for a subset of repositories hosted at /svn/.

** Argh, ok.  I don’t like to make assertions I can’t back up; I don’t want to 
develop a reputation for making empty threats.  So…

Earlier, Roger had said he didn’t know what had changed in J602 that made it 
stop working for proverbs etc [3], so I had a little look in the source.  
Here’s what I found:

    x.c (foreign definitions), line 201:
    
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/x.c#L201
 
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/x.c#L201>

      case XC(15,6):  R SDERIV(CIBEAM,jtdllsymget,0,RMAX,0,0);

    s.c (symbol table), line 222:
    
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L222
 
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L222>

      F1(jtdllsymget){R dllsymaddr(w,0);}

    and line 207:
    
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L207
 
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L207>

      static A jtdllsymaddr(J jt,A w,C flag){A*wv,x,y,z;I i,n,wd,*zv;L*v;
       RZ(w);
       n=AN(w); wv=AAV(w); wd=(I)w*ARELATIVE(w);
       ASSERT(!n||BOX&AT(w),EVDOMAIN);
       GA(z,INT,n,AR(w),AS(w)); zv=AV(z); 
       for(i=0;i<n;++i){
        x=WVR(i); v=syrd(nfs(AN(x),CAV(x)),0L); 
        ASSERT(v,EVVALUE);
        y=v->val;
        ASSERT(NOUN&AT(y),EVDOMAIN);              
        zv[i]=flag?(I)AV(y):(I)v;
       }
       R z;
      }    /* 15!:6 (0=flag) or 15!:14 (1=flag) */

So the culprit here is line 216:

        ASSERT(NOUN&AT(y),EVDOMAIN);              

That is, J has the answer I want in-hand already — it just refuses to give it 
to me. (To interpret this line, one must understand that there’s only one 
single data structure in the J engine, which is used to represent nouns, verbs, 
adverbs, conjunctions, and even some other stuff.  The NOUN&(AT) part says 
“throw an error unless this data structure is representing a noun".)

Now, since 15!:6 was originally introduced for the purposes of passing J data 
to other processes, it makes sense, and is a reasonable safety check, to 
restrict its use to nouns. But I have other uses for this function, which are 
hampered by this restriction.

So what can we do about it? J will refuse to return the address of any name 
which is not a noun. But we want the address of a verb.  Somehow we need to 
pass 15!:6 a verb, but have J believe it’s a noun.

Our mind first wanders to things like PWDCHECK=:’pwdcheck’, but then we realize 
nothing along those lines will work (the string ‘pwdcheck’ is just 
coincidentally spelled the same as the name of a function, but 15!:6 won’t be 
able to make that connection; it will just return the address of the literal 
noun ‘pwdcheck’ - wherever those 8 characters are stored in memory).

Then we remember the “disaster which smells like a breakthrough”, as Tracy so 
eloquently put it on Twitter [4]. Let’s use Marshall’s discovery [5] that that 
“breakthrough” permits us to box verbs:

        PWDCHECK =: (<'pwdcheck') <@]^:(1:`(<'@.')) 0

        PWDCHECK
     +--------+
     |pwdcheck|
     +--------+

        type'PWDCHECK'
     +----+
     |noun|
     +----+

        PWDCHECKOPENED=:>pwdcheck

        type'PWDCHECKOPENED'
     +----+
     |verb|
     +----+

        (>PWDCHECK) 'password'
     1
        (>PWDCHECK) 'not the password'
     0

Ok, here we have it. A verb cloaked as a noun, so that it can pass the test 
ASSERT(NOUN&AT(y),EVDOMAIN) .  Let’s try it:

        15!:6 <'PWDCHECK'
     140618867255944

No domain error. Great. But now we have to remember that 140618867255944 is the 
address of the box which contains the verb pwdcheck, not the verb pwdcheck 
itself.  What we need is the value of the first element of the boxed array, 
which, going off the comment on the final line of the function jtdllsymaddr(), 
looks like we can get using the (also undocumented) foreign 15!:14 (the macro 
AV(x) returns the address of the “ravel”, or value, of the struct x):

              15!:14 <'PWDCHECK'
           140618884704072

But this being a box, that address itself probably contains a pointer to the 
header of the function pwdcheck:

              memr (15!:14 <'PWDCHECK'), 0, 1, JINT
           140618882427152

Which looks like a reasonable address, not far from the block which contains 
PWDCHECK itself (which makes sense).

Indeed, if we use 15!:7 to set a new symbol pointing to this address:

              ‘someothername' =:15!:7 {. memr (15!:14 <'PWDCHECK'), 0, 1, JINT
              someothername
           pwdcheck

So we’re on the right track, for sure.  But of course we’re not home yet - 
we’re pointing ‘someothername’ right back to the _name_ ‘pwdcheck’, which 
doesn’t get us anywhere.

The next step would be to chase pointers to the value underlying ‘pwdcheck’ and 
manipulate the “flags” field to turn off the VLOCK flag (bit #16), as in:

              (memw~ (26 b. VLOCK=:65536) 17 b. memr) CORRECT_POINTER, 8,1,JINT 

Unfortunately, I’ve run out of time for pointer-chasing today. Nevertheless, in 
my mind the rest of this is mere stamp-collecting: we have the beginning of the 
thread, now we only need to pull it carefully to unravel the whole sweater.

[3] Roger on the change to 15!:6:
    http://www.jsoftware.com/pipermail/programming/2010-January/017946.html 
<http://www.jsoftware.com/pipermail/programming/2010-January/017946.html>

[4] Tracy on twitter:
    https://twitter.com/kaleidic/status/296101561459953664 
<https://twitter.com/kaleidic/status/296101561459953664>

[5] Marshall discovers that the stupid ^:(<‘@.’) trick allows us to box verbs:
    http://www.jsoftware.com/pipermail/programming/2013-January/031260.html 
<http://www.jsoftware.com/pipermail/programming/2013-January/031260.html>


----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to