[squeak-dev] FFI | ByteArrays: Authentic or Fabricated? :-)

David T. Lewis lewis at mail.msen.com
Thu May 21 02:08:09 UTC 2020


On Wed, May 20, 2020 at 06:53:37PM +0200, Marcel Taeumel wrote:
> Hi, all!
> 
> How can I figure out, whether the handle of an external object -- if it is a byte array -- was fabricated in the image or whether it is actually something creating in the external library? For actual instances of ExternalAddress, it is obvious that those are meant to point to external memory. But what about instances of ByteArray being stored in the "handle" instVar?
> 
> I tried Object >> #isPinned. :-D Did not work. I am looking at all the primitives in ByteArray.
> 
> ... is there actually a difference? Or are all byte arrays that I find in the image actually in the object memory?
> 
> Best,
> Marcel
> 

There is no simple answer.

A good illustration is this:

	SourceFiles first fileID

On a 64-bit VM, you will see a ByteArray of size 24. On a 32-bit VM, it
is a shorter ByteArray. In either case, the ByteArray instance exists
entirely within the object memory.

The byte values within that ByteArray happen to be the value of a C pointer,
which is the address in the process virtual memory of a data structure that
lives in FilePlugin within the VM. That data structure contains various things,
including (on a Unix VM) another pointer to a FILE struct that lives in the
C runtime library.

None of those pointers or internal things have any meaning within the image
or within the object memory itself. It is best to think of the fileID field
as an opaque handle to something in the external world, and the fact that
the bytes just happen to be a C pointer is something that you are supposed
to not notice.

I really wish that Andreas could be here to comment. I clearly recall his
shock and dismay on finding out that I was using the actual byte contents of
a fileID to do things in the OSProcess plugin. We had slightly different
perspectives on that topic, but if you were at all interested in issues of
security for the Squeak execution environment (as Andreas was), then you would
want to hear his perspective.

So in some sense, you should not really be able to know if a ByteArray contains
a pointer to something elsewhere in the virtual memory of the VM. On the
other hand, if you already know that you are doing something dangerous and
insecure, then it would be really convenient to be able to answer the question
that you are asking - does this ByteArray object in the object memory contain
a reference to some external thing outside of the object memory, and if so
is it safe for me to use it?

I don't know that there could ever be a safe answer to that question. The
image and the VM have no way of knowing what happens to things at the other
end of that C pointer. So for example in the case of fileID, you really need
to keep track of when a FileStream refers to invalid addresses. Thus the
data structure is:

  /* squeak file record; see sqFilePrims.c for details */
  typedef struct {
    int                    sessionID;     /* ikp: must be first */
    void                  *file;
    squeakFileOffsetType   fileSize;      /* 64-bits we hope. */
  #if defined(ACORN)
  // ACORN has to have 'lastOp' as at least a 32 bit field in order to work
    int lastOp; // actually used to save file position
    char writable;
    char lastChar;
    char isStdioStream;
  #else
    char                   writable;
    char                   lastOp; /* 0 = uncommitted, 1 = read, 2 = write */
    char                   lastChar;
    char                   isStdioStream;
  #endif
  } SQFile;

The first field of the struture is sessionID, which is a value associated with
the currently running VM program. If you save your image and start it again,
the sessionID in the new VM instance will now be different, which allows the
FilePlugin to figure out that the pointer to the FILE struct (or to a HANDLE
on Windows) is not valid, and therefore it should not attempt to dereference
that pointer (VM crash).

This is just one example, but it illustrates that general case, which is that
the VM cannot be expected to keep track of what people are doing on the other
end of those C pointers, and the image in turn cannot be expected to know if
a ByteArray that contains a C pointer is referring to anything useful or
safe on the other end of the pointer that was saved in the ByteArray.

In specific cases, you can consider handling this by keeping track of the
known valid external references. If you look at the Windows FilePlugin, you
will see that Andreas did this by maintaining a registry of known valid
HANDLE values, and failing the primitives when an unregistered HANDLE was
passed, e.g. by my WindowsOSProcessPlugin which attempted to pass unregistered
HANDLE values for anonymous pipes.

This was an annoyance for me because I could not pursue my OSProcess hacks
on Windows (and I abandoned the effort). But from a security and system
integrity point of view, Andreas was right. To this day, I do not have
any good answer for how to handle this.

So it is not a easy problem.

Dave



More information about the Squeak-dev mailing list