Observations

Marius Aamodt Eriksen
event_yield()
Thu Mar 25, 2004

i've discussed this with niels a few times. but basically, a nice interface for libevent would be event_yield() which would return when the event passed to it becomes active. in the meantime, the main event loop is executing. to do this properly, you'd probably have to longjump back and forth from the event loop and event_yield(). i'll do it when i've time!

security by compiler
Thu Mar 25, 2004

here are some ideas i shared with evan, adlr and paul for their 583 project.

the first is to do some code analysis to figure out where privileges in a program is needed. for example, if at a point in the codepath, no future potential codepaths require privileged operations, you can drop privileges. furthermore, you can make efforts to actually perform some form of privilege separation by separating out priveliged and unpriveliged code. of course, this is very tricky, and would likely be very heuristic (for example, if the result of a priveliged operation is a file descriptor, we need to do file descriptor passing). niels points out that dawn song already did it.

second, to have the compiler generate systrace policies for a binary by inspecting the system calls it makes, and doing some sort of analysis as to what the range of their arguments are. this is the tricky part. whenever the range cannot be figured out, it can resort to some system-wide policy on that specific system call.

NIDS
Thu Mar 25, 2004

stick this on the wire: a decompiler/disassembler, try to make a instruction stream out of payloads, then have some heuristics like looking for certain system calls which trigger alerts. also, if the code is somehow obfuscated and includes de-obfuscation code, we can check whether the code operates on itself (for example by PC offsets).

protected memory interface
Wed Mar 24, 2004

how do you design a good protected memory interface?
  -General-

We should probably assume that encrypted swap is in place.  It's
much easier to deal with than to actually attempt to pin memory.

  -Encryption/Decryption Logistics-

1. Do it in-place.  This is where it's done by the application
   itself, specifically in a loaded shared module.  Signalling here
   will be a little tricky as to not interfere with other
   application semantics.

2. Do it in the kernel.  Very easy.  But does encryption belong in
   the kernel?

3. Map all candidate memory into a dedicated daemon.  This makes
   the encryption and key management much more portable and easier
   to work with.  We'll need some kernel support, however, to map
   the memory, which should not be too bad.  Think about
   whole-image encryption here, though.  It seems like it will be
   tricky to do that.

  -The Interface-

This is an important part to get right.  It has to be easy to use.
In terms of the API, perhaps something as simple as:

   void *memcrypt_malloc(size_t nbytes);
   void *memcrypt_free(void *p);

Should we allow the application to encrypt at will, too?  Or just
on-demand from the user?

   int memcrypt_encrypt(void *p);   /* NULL to encrypt all memory? */
   int memcrypt_decrypt(void *p);   /* NULL to decrypt all memory? */

NOTE: passing a NULL pointer to encrypt/decrypt all memory is
probably a bad idea from an interface perspective.  How about

   int memcrypt_encrypt_all(void);
   int memcrypt_decrypt_all(void);

  -The Dedicated Daemon Approach-

There is a daemon that runs on a per-user basis.  This daemon
handles all key management and cryptographic operations.

There is a thin kernel layer that provides a device,
/dev/memcrypt.  The daemon sleeps (select()) on this device, and
the kernel layer passes messages down.

The "application" is the client application utilizing the protected
memory scheme.  The "daemon" is the daemon handling key management
and cryptographic operations.

When an application allocates protected memory, the memory is first
allocated, and the kernel is notified (through a syscall, or
ioctl() on /dev/memcrypt).  The kernel in turn notifies the daemon
that there is a new memory area to be protected, and the
daemon  requests for that memory to be mapped into its address
space.  When this process completes and the memory is mapped into
the daemon's address space, the system call or ioctl() on
/dev/memcrypt from the application returns, and execution resumes
as usual.  

If the daemon dies:  All applications with protected memory are
stopped, all the protected memory is scribbled, and the
applications are killed.

When the user requests encryption, the user provides some key
material to the daemon, and the daemon SIGSTOPs each client
application, and proceeds to encrypt its memory.  When the user
wishes to decrypt the memory, the user again provides the necessary
key material to perform the decryption, and the daemon then
proceeds to decrypt the processes' protected memory, and then
SIGCONTs each process.  The key used for decryption can be stored
until the user encrypts again, that way it only has to be provided
initially and on each decryption.

"E-Patents"
Wed Feb 18, 2004

patents are an important part of our modern society. however, it seems many software patents should have been rejected by patent examinors under usc 35 sec. 103. specifically, a patent should be not be "obvious at the time the invention was made to a person having ordinary skill in the art." clearly, certain software patents such as using exclusive or to write a cursor onto a screen (patent # 4,197,590 held by Cadtrak) are not only obvious, but was used at least 5 years before the patent application.

To do or to Have? That Is the Question.
Wed Feb 18, 2004

research suggests that experiental investments are more valuable than material ones.