So, suppose I''m trying to dump data in a user-land process and have no opportunity to catch that data in a system call (e.g., write(2)). Specifically I''m trying to dump a DER-encoded Kerberos V ''Authenticator'' before/after it is encrypted/decrypted. I know where to find this data. E.g., it''s output through a krb5_data ** argument to encode_krb5_authenticator(). typedef struct _krb5_data { krb5_magic magic; unsigned int length; char *data; } krb5_data; I can save the krb5_data ** value in arg1 on entry to encode_krb5_authenticator(). But what do I when that returns to actually follow all the pointer values to get at the buffer pointed by the data field of the krb5_data? And once I have done a copyinto(), how do I hexdump the buffer? This, and various variants I''ve been trying doesn''t work: pid$target::encode_krb5_authenticator:entry { trace(1); self->trace_asn1_eui = 1; self->codepp = (krb5_data **)arg1; } pid$target::encode_krb5_authenticator:return { trace(0); self->trace_asn1_eui = 0; this->codep = (krb5_data *)copyin((uintptr_t)self->codepp, 4); this->buf = (char *)copyin((uintptr_t)this->codep+2, 4); /* We''ve only done one dereference... */ printf("The authenticator is at krb5_data ** %p, krb5_data * %p\n", self->codepp, this->codep); } Nico --
Nicolas Williams wrote:> So, suppose I''m trying to dump data in a user-land process and have no > opportunity to catch that data in a system call (e.g., write(2)). > > Specifically I''m trying to dump a DER-encoded Kerberos V ''Authenticator'' > before/after it is encrypted/decrypted. > > I know where to find this data. E.g., it''s output through a krb5_data > ** argument to encode_krb5_authenticator(). > > typedef struct _krb5_data { > krb5_magic magic; > unsigned int length; > char *data; > } krb5_data; > > > I can save the krb5_data ** value in arg1 on entry to > encode_krb5_authenticator(). But what do I when that returns to > actually follow all the pointer values to get at the buffer pointed by > the data field of the krb5_data? > > And once I have done a copyinto(), how do I hexdump the buffer? > > This, and various variants I''ve been trying doesn''t work: > > pid$target::encode_krb5_authenticator:entry > { > trace(1); self->trace_asn1_eui = 1; > self->codepp = (krb5_data **)arg1; > } > > pid$target::encode_krb5_authenticator:returnNicolas, You want a predicate here: /self->trace_asn1_eui/ But that''s not the problem...> { > trace(0); self->trace_asn1_eui = 0; > this->codep = (krb5_data *)copyin((uintptr_t)self->codepp, 4);OK, so now you have a ptr to a krb5_data (assuming the app is 32-bit). Simply "teach" DTrace what a krb_data is by #including the proper header files and use the -C option, or cut-and-paste the structure definition into your script. Then reference the ''data'' element to perform a tracemem() from: tracemem (copyin (this->codep->data, 100), 100); or however many bytes you want to dump. Jim> this->buf = (char *)copyin((uintptr_t)this->codep+2, 4); > /* We''ve only done one dereference... */ > printf("The authenticator is at krb5_data ** %p, krb5_data * %p\n", > self->codepp, this->codep); > } > > > Nico
On Tue, Aug 01, 2006 at 06:44:33PM -0400, Jim Fiori wrote:> Nicolas Williams wrote: > >pid$target::encode_krb5_authenticator:entry > >{ > > trace(1); self->trace_asn1_eui = 1; > > self->codepp = (krb5_data **)arg1; > >} > > > >pid$target::encode_krb5_authenticator:return > > Nicolas, > > You want a predicate here: > > /self->trace_asn1_eui/I was showing only a bit of a larger script -- the predicate is not necessary here.> But that''s not the problem...It isn''t.> >{ > > trace(0); self->trace_asn1_eui = 0; > > this->codep = (krb5_data *)copyin((uintptr_t)self->codepp, 4); > > OK, so now you have a ptr to a krb5_data (assuming the app is 32-bit).Right, as I said, it''s a 32-bit app.> Simply "teach" DTrace what a krb_data is by #including the proper header > files and use the -C option, or cut-and-paste the structure definition into > your script. Then reference the ''data'' element to perform a tracemem() from:Interesting -- I can''t define krb5_data on the command-line. OK, so into a file it goes.> tracemem (copyin (this->codep->data, 100), 100);But codep here points to something in user-land. Is DTrace smart enough to figure out to evaluate that pointer derefence as a copyin? That is surprising, or would be, if I could get it to work. When I try this: typedef struct _krb5_data { krb5_magic magic; unsigned int length; char *data; } krb5_data; ... pid$target::encode_krb5_authenticator:entry { self->codepp = (krb5_data **)arg1; } pid$target::encode_krb5_authenticator:return { this->len = (uint32)copyin((*(self->codepp))->length, 4); printf("The authenticator is %d bytes long\n", this->len); } I get this error: dtrace: error on enabled probe ID 11 (ID 46671: pid24408:mech_krb5.so.1:encode_krb5_authenticator:return): invalid address (0x8045c18) in action #1 at DIF offset 4 And this gets me a bogus address for the krb5_data struct in user-land: pid$target::encode_krb5_authenticator:entry { trace(0); self->codepp = (krb5_data **)arg1; } pid$target::encode_krb5_authenticator:return { trace(1); this->codep = (krb5_data *)copyin((uintptr_t)self->codepp, 4); printf("The authenticator is at krb5_data ** %p, krb5_data * %p\n", self->codepp, this->codep); } ... 0 46671 encode_krb5_authenticator:return 1The authenticator is at krb5_data ** 8045c18, krb5_data * fffffe8de9752030 ... fffffe8de9752030 is clearly not right. So, let''s try and be cute and copyin 4 bytes and cast them as an unsigned integer: this->codep = (uint32)copyin((uintptr_t)self->codepp, 4); printf("The authenticator is at krb5_data ** %p, krb5_data * %x\n", self->codepp, this->codep); this->len = (uint32)copyin((uintptr_t)(this->codep+4), 4); printf("The authenticator is %d bytes long\n", this->len); then I get this: dtrace: error on enabled probe ID 10 (ID 46671: pid24420:mech_krb5.so.1:encode_krb5_authenticator:return): invalid address (0xeef1d024) in action #4 at DIF offset 48 OK, let''s get cuter, let''s show that this cast didn''t break the pointer: this->codep = (uint32)copyin((uintptr_t)self->codepp, 4); this->ptr_as_uint = (uint32)self->codepp; this->codep2 = (uint32)copyin((uintptr_t)this->ptr_as_uint, 4); this->codep3 = (uint32)copyin((uintptr_t)self->codepp, 4); printf("self->codepp %p, this->ptr_as_uint %x, \n\tthis->codep %x, this->codep2 %x, this->codep3 %x\n", self->codepp, this->ptr_as_uint, this->codep, this->codep2, this->codep3); This shows: self->codepp 8045c18, this->ptr_as_uint 8045c18, this->codep ffdca048, this->codep2 ffdca050, this->codep3 ffdca058 So, the pointer at 8045c18 changed from ffdca048, to ffdca050 and then ffdca058?! So, how do I dereference the krb5_data ** correctly? I must be doing something really wrong. Nico --
> > Simply "teach" DTrace what a krb_data is by #including the proper header > > files and use the -C option, or cut-and-paste the structure definition into > > your script. Then reference the ''data'' element to perform a tracemem() from: > > Interesting -- I can''t define krb5_data on the command-line. OK, so > into a file it goes. > > > tracemem (copyin (this->codep->data, 100), 100); > > But codep here points to something in user-land. Is DTrace smart enough > to figure out to evaluate that pointer derefence as a copyin?No -- DTrace can''t chase pointers through user-land.> pid$target::encode_krb5_authenticator:entry > { > self->codepp = (krb5_data **)arg1; > } > pid$target::encode_krb5_authenticator:return > { > this->len = (uint32)copyin((*(self->codepp))->length, 4); > printf("The authenticator is %d bytes long\n", this->len); > } > > I get this error: > > dtrace: error on enabled probe ID 11 (ID 46671: pid24408:mech_krb5.so.1:encode_krb5_authenticator:return): invalid address (0x8045c18) in action #1 at DIF offset 4You''re getting hooked by a classic: remember that copyin() returns a _pointer_ to the data that was copied in -- not the data itself. So you don''t want to cast it to a uint32, but rather to a (uint32 *) and dereference the pointer to get the actual int. See Slide 19 of the "DTrace Tips, Tricks & Gotchas" presentation for an example of this: http://blogs.sun.com/roller/resources/bmc/dtrace_tips.pdf - Bryan -------------------------------------------------------------------------- Bryan Cantrill, Solaris Kernel Development. http://blogs.sun.com/bmc
On Tue, Aug 01, 2006 at 08:40:51PM -0700, Bryan Cantrill wrote:> > > tracemem (copyin (this->codep->data, 100), 100); > > > > But codep here points to something in user-land. Is DTrace smart enough > > to figure out to evaluate that pointer derefence as a copyin? > > No -- DTrace can''t chase pointers through user-land.I didn''t think it could. That''d be some very neat syntactic sugar though. this->len = chase("*%p->length", this->pp);> > I get this error: > > > > dtrace: error on enabled probe ID 11 (ID 46671: pid24408:mech_krb5.so.1:encode_krb5_authenticator:return): invalid address (0x8045c18) in action #1 at DIF offset 4 > > You''re getting hooked by a classic: remember that copyin() returns a > _pointer_ to the data that was copied in -- not the data itself. So you > don''t want to cast it to a uint32, but rather to a (uint32 *) and > dereference the pointer to get the actual int. See Slide 19 of the "DTrace > Tips, Tricks & Gotchas" presentation for an example of this:D''oh! I get it. And now I can capture this data. Thanks. Nico --