Add serialization for syscall args (XCC)
authorKevin Klues <klueska@cs.berkeley.edu>
Fri, 10 Jul 2015 08:39:38 +0000 (01:39 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 14 Jul 2015 14:33:16 +0000 (10:33 -0400)
commitd5340f1931d74d95ca45f4367125c435b51c0d94
treeceda4585b86a3bcb04df9e8ae81c5fe6c070745f
parentc8284572a4d41654151e6342da7be027e713f7e4
Add serialization for syscall args (XCC)

It is useful to be able to serialize data into a single buffer for
passing data to the kernel.  The first use case of this is serializing
the data pointed to by argv and envp along with their pointers.
Currently, we use procinfo to serialize this data and pass it to the
kernel. This is unnecessarily limiting (procinfo is read-only and
limited in size), and there may be other data we would like serialized
in the future. It would be unreasonable to keep expanding procinfo every
time we had a new data structure we wanted to serialize to the kernel.

This commit introduces a new struct serialized_data, which contains
nothing more than a size and an unbounded buffer. Serialization routines
can be written around this type to serialize their input and return a
newly allocated buffer with all of the serialized data contained in it.
All pointers in the data structure must be relative to the base of the
argument buffer itself (rather than absolute pointers).  I've written a
serializer for the argv and envp stuff to pack all of their data into a
single buffer. The plan is to use this new serialized representation to
replace the existing procinfo approach to passing this data into the
kernel (though that will come in a subsequent commit).  More serializers
can be written following this pattern as desired in the future.

I toyed around with the idea of not serializing the argv and envp data
at all, and just passing their pointers directly to the kernel. However,
this approach proved to get increasingly complicated as I started to
reason through what needed to be done to verify all of the user memory
while walking these data structures in the kernel. It's obviously doable
(linux does it this way, for example), but it is unnecessarily
complicated, and likely safer, to just pass the serialized data in.

By serializing the data, we can pass a single pointer and a
length to the kernel (similar to how we do for our path strings), and
the kernel can do a quick check to verify that all of the memory to be
accessed is mapped in and within bounds. I very much like this pattern,
moving forward, for all complicated data structures we may need to pass
to the kernel. We may not always be able to get away with it, but it
makes sense to use it when we can.

In terms of implementing this stuff, I put the actual code in glibc and
the header file in parlib. Ideally I would have put it all in parlib
(since it's not really a part of glibc), but I already know that
sys_exec will need access to these functions, and there may be others in
the future.  The header file belongs where it is though, as this really
is a parlib operation.

As part of this, I also wrote a simple test that demonstrates how the
serialization of argv and envp works. It is called serialize_test.
tests/serialize_test.c [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Makefile
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Versions
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/serialize.c [new file with mode: 0644]
user/parlib/include/serialize.h [new file with mode: 0644]