In this lesson,
it talks about the subprocess environment in some detail.
The first thing are the file descriptors.
As you recall, this is what you get when
you open a file using the system called open.
In windows, it would be equivalent to a file handle.
When you do a fork,
the file descriptor is not closed,
and when you do an exec to overlay
something new onto that process,
the file descriptor is still open.
So here's the threat.
The parent process is privileged but
the child processes has all of its privileges removed.
So the parent files opens up sensitive file,
reads part of it, fires up the child.
The child can now read from that file descriptor and
read more of that sensitive file.
Furthermore, can do a seek to move the pointer,
it's back to the beginning of the file.
If the parent closes the file descriptor,
the child has a copy of the file descriptor so it
remains open until the child closes it.
That's basically what this slide is saying.
If the child is as privileged as the parent this
is no big deal because the parent can read it.
If the child has the same privileges
so the child can read it.
Where it comes into play is if the parent has
the child drop privileges before the exec.
In that case, the child
would not be able to open the file for reading.
But it doesn't have to because it is the file descriptor.
So here's an example of this.
This is a very simple program
which opens a privileged file for reading,
and the file descriptor becomes fd.
Now, normally when you open a file,
it gets the lowest available file descriptor.
In this program, zero is the,
well rather in all programs,
zero is the standard input.
One is the standard output,
two is the standard here,
so this would get file descriptor three.
Now, in this case I want
to make sure I know the number of the file descriptor.
I don't really need that Dupline.
But if there are other files that are opened and closed,
then they need to dup that fd to value,
to a file descriptor that the child knows.
So in this case I'm going to
assume there were some other files opened and closed,
and so I can no longer be sure that
print files file descriptor is three,
it's just some number.
So I do the dup, and now I know the parent
has the file descriptor fd.
It also is nine,
which refers to the same file object.
When I run system,
system does a fork.
So file descriptor fd and file descriptor nine,
even in the child refer to
the same thing they did in the parent.
Then it overlays a shell in sh,
and that shell inherits those variables.
So file descriptor nine in the shell now refers to
the file that the parent had opened.
So now all I have to do is get to
the contents of file descriptor nine from that shell.
That's what the next line does,
the line under the type this to the Bourne shell.
Cat, and then the left arrow ampersand nine says,
take the input for cat from file descriptor nine.
So even if I have dropped privileges,
which is the assumption that I'm doing,
I'd still be able to get
whatever is in file descriptor nine,
which is the privilege file of course.
So how do you avoid this?
Well, the next slide shows you how.
There is an ioctl or an argumentic open or an fcntl,
which allows you to tell the parent,
look, when you spawn a child process,
when you do the fork and then do an exec,
close the file descriptors that are open.
So which one you use depends on which system you're on.
On FreeBSD, you'd use FC and you could use any of those.
The flag you would use on the first and third,
is FD_CCLOEXEC, which means close on exec.
Actually, for the open you do O_CLOEXEC.
Then on the other CT, I'll do FIOCLEX.
Similar options for those system calls on
every system that's similar to Unix at
all and also on Windows systems as well.
Now, the second issue of how files and programs interact,
the files and processes interact, is that,
when a file is opened,
the operating system checks the permissions.
Can the process read this file?
Can the process write this file? And so forth.
However, once it's open,
even if the owner of the file turns off permissions,
the process can still access the file.
In other words, permissions are
only checked during the open.
Possession of the file descriptor gives
you that type of access to the file.
This is traditionally what's called the capability.
It's different than the Linux notion
of capabilities, but traditionally,
a capability is something
that when you have possession of it,
gives you certain rights,
and that's what this does.
It sounds like this is a bad thing but it turns out
to be extremely useful in certain cases.
For example,
let's say I want to write information to a log file,
and the log file has to be,
can only be written by, only be appended to buy root.
So I fire up my child process and draw privileges.
I then do an exec.
If the exec fails,
I want to write an error message to the log file.
If it succeeds, then I want
the log output to go to that particular file.
So what I do is I open the log file.
Then when the process forks the child inherits it.
When there's an execve, the process
is overlaid by some other command.
If that fails, the child
continues and writes the information to the log file.
Similarly, if I'm not doing an exec,
and I simply do the fork,
I can still write to the log file.
The other way in which this is useful too,
is if you need a temporary file that you don't
want lying around after the program begins.
What you do is you open the file in read write mode,
and then you unlink it using the system called unlink.
As long as the file descriptor is open,
that file exists, it's just
not visible in the file hierarchy.
When you close that file descriptor,
that file goes away.
So it's a very cheap way of getting a temporary file,
that's guaranteed to be
deleted when your process is done.
It may not zero out the disk blocks of course,
but that's true of any deletion.
Another variable that's inherited
is what's called the Umask.
The Umask, you can think of as a protection mask.
The Umask is similar to
the protection bits used in chmod.
It has nine octal bits.
The first being read,
the second being write,
and the third being execute in
each of the three positions,
and the three positions correspond to
owner group and everyone else.
If a bit on the Umask is set,
when you create a file,
that bit in the file permissions will be cleared.
So for example, if I try to create
a file Mode 777 so anybody can do anything to it.
My Umask is octal 22,
then that [inaudible] is the write bit,
the middle bit, the number two bit for the group and
the world and so only the owner will be able to read it.
So this in a way protects,
is if you like, additional protection.
The issue here is,
you want to prevent world-readable and writable files.
If you don't, it's going to enable
some attacks as you will see in a little bit.
More generally, we focused on file descriptors in Umasks,
but more generally the next slide.
A general observation shows what's inherited.
The UID and the GIDs,
group IDs the Umask and the open file descriptors.
But also there's a notion
of root of the file system by the process.
Normally, this is slash,
but if you jail the process,
then it's going to be, not slash.
It'll be something else.
The current directory of the process and that's
also included as network information,
control terminal name, process name, and all that stuff.
Basically, look at the protection state of the system,
and anything that affects that state.
That is essentially what the process will inherit,
the protection state of the system as it sees it,
and anything that could affect that state