Discussion:
P2: Several Clarifications
(too old to reply)
Daniel Ramsbrock
2005-09-28 01:19:05 UTC
Permalink
Here is a list of project 2 items I'd like to have clarified, preferably
by a TA or Dr. Hicks. Most of them should be straightforward answers,
and I think the whole class will benefit from the answers:

1. SIGCHLD: Do we add code to the Exit() function in kthread.c to send
SIGCHLD to our parent? Obviously, we send SIGCHLD to the parent when
killing a child. Are there any other times when a SIGCHLD should be
generated?

2. Do we need to check the validity of the pointers being passed into
Sys_Signal and Sys_RegDeliver (i.e. should we run them through
Validate_User_Memory)?

3. When calling Complete_Handler from Sys_ReturnSignal, do we pass the
variable 'state' as the second parameter (esp)?

4. What is the purpose of the second parameter (esp) of Setup_Frame and
Complete_Handler? I don't use it in either one--should I be using it
somehow? I only use kthread->esp, which is the stack pointer of the
thread in question.

5. Whenever we call Copy_To_User, we don't have to check that enough
user memory is available, correct? As far as I can tell,
Validate_User_Memory, which gets called from Copy_To_User, takes care of
this automatically. Along those same lines, should we be checking the
return code of Copy_To/From_User in Setup_Frame and Complete_Handler to
make sure the stack was copied OK? If so, what action(s) should we take
on failure?--both return void, so we would have to modify that in order
to return an appropriate error code.

6. If any of the syscalls Sys_Signal, Sys_RegDeliver, and
Sys_ReturnSignal are called by a kernel thread (i.e.
g_currentThread->userContext == NULL), they should fail with EACCESS or
something like that, right?

7. On the other hand, Sys_Kill and Sys_WaitNoPID should work even if the
caller is a kernel thread, right?

8. Is it OK to reset the 'pending' flag for a signal at the end of
Setup_Frame (i.e. as soon as the EIP has been set to the proper handling
address)? This way, if the same signal is received again while it's
being handled, the handler would be called again.

9. Accessing user space: Many people have been talking about converting
all kinds of things between user and kernel address space. To me, it
seems like the only time this is necessary is when copying the
Interrupt_State struct from the kernel stack to the user stack (in
Setup_Frame) and back from the user stack to the kernel stack (in
Complete_Handler). I see no reason to convert the handler addresses back
and forth--even though the addresses are being passed to syscalls, the
handlers are being invoked from within a user process. When setting the
EIP of the user process (in Setup_Frame), this address would have to be
in user address space anyway since that's where the user process will
resume execution. In other words, my implementation works fine by
leaving the passed-in handler address alone, storing it in userContext,
and then copying that value to the Interrupt_State->eip field on the
kernel stack when Setup_Frame is called.

Sorry for all the questions--hopefully most of them are indeed easy
answers. Thanks,

Daniel
Saurabh Srivastava
2005-09-28 05:27:10 UTC
Permalink
| 1. SIGCHLD: Do we add code to the Exit() function in kthread.c to send
| SIGCHLD to our parent? Obviously, we send SIGCHLD to the parent when
| killing a child. Are there any other times when a SIGCHLD should be
| generated?

yes. a SIGCHLD should be sent to the parent whenever a child process dies.
either through a kill or a normal exit.

| 2. Do we need to check the validity of the pointers being passed into
| Sys_Signal and Sys_RegDeliver (i.e. should we run them through
| Validate_User_Memory)?

yes. that is essential.

| 3. When calling Complete_Handler from Sys_ReturnSignal, do we pass the
| variable 'state' as the second parameter (esp)?

again, yes. that is the interrupt state at that point in time.

| 4. What is the purpose of the second parameter (esp) of Setup_Frame and
| Complete_Handler? I don't use it in either one--should I be using it
| somehow? I only use kthread->esp, which is the stack pointer of the
| thread in question.

the interrupt state gets passed around as an explicit parameter and so you
should use that to do all your computation.

| 5. Whenever we call Copy_To_User, we don't have to check that enough
| user memory is available, correct? As far as I can tell,
| Validate_User_Memory, which gets called from Copy_To_User, takes care of
| this automatically. Along those same lines, should we be checking the
| return code of Copy_To/From_User in Setup_Frame and Complete_Handler to
| make sure the stack was copied OK? If so, what action(s) should we take
| on failure?--both return void, so we would have to modify that in order
| to return an appropriate error code.

not being able to store the interrupt state or something as critical as
that cannot be recovered from. it would mean that you could not context
switch properly. Just KASSERT for it. the kernel will(should) crash in the
event of a failure to properly do any of what you mention.

| 6. If any of the syscalls Sys_Signal, Sys_RegDeliver, and
| Sys_ReturnSignal are called by a kernel thread (i.e.
| g_currentThread->userContext == NULL), they should fail with EACCESS or
| something like that, right?

Again, kernel threads are critical pieces of code that should not do
stupid things like this. KASSERT to prevent bugs. nothing more.

| 7. On the other hand, Sys_Kill and Sys_WaitNoPID should work even if the
| caller is a kernel thread, right?

makes sense.

| 8. Is it OK to reset the 'pending' flag for a signal at the end of
| Setup_Frame (i.e. as soon as the EIP has been set to the proper handling
| address)? This way, if the same signal is received again while it's
| being handled, the handler would be called again.

actually, since you would not send a signal to yourself (you being the
user process that just got context switched to); it cannot be the case
that the process gets another signal just after having gone through
Setup_Frame and before Complete_Handler. So resetting it in
Complete_Handler makes more sense since that is actually when you complete
handling the signal.

| 9. Accessing user space: Many people have been talking about converting
| all kinds of things between user and kernel address space. To me, it
| seems like the only time this is necessary is when copying the
| Interrupt_State struct from the kernel stack to the user stack (in
| Setup_Frame) and back from the user stack to the kernel stack (in
| Complete_Handler). I see no reason to convert the handler addresses back
| and forth--even though the addresses are being passed to syscalls, the
| handlers are being invoked from within a user process. When setting the
| EIP of the user process (in Setup_Frame), this address would have to be
| in user address space anyway since that's where the user process will
| resume execution. In other words, my implementation works fine by
| leaving the passed-in handler address alone, storing it in userContext,
| and then copying that value to the Interrupt_State->eip field on the
| kernel stack when Setup_Frame is called.

yes. you are right. my reply to some post earlier said this and you have
spelled it out in probably a little too much detail. :)
David Marcin
2005-09-28 18:42:45 UTC
Permalink
Post by Saurabh Srivastava
| 2. Do we need to check the validity of the pointers being passed into
| Sys_Signal and Sys_RegDeliver (i.e. should we run them through
| Validate_User_Memory)?
yes. that is essential.
If you do not check the memory will this result in a segmentation
fault? If so, why should we penalize kernel efficiency for a process
who is more than likely being malicious by passing invalid memory
addresses to Sys_Signal when it will just die anyway?
c***@CSIC.UMD.EDU
2005-09-29 12:33:33 UTC
Permalink
Because the process that will die will not be the malicious
process, but instead the process the malicious process sent the
signal to.
David Marcin
2005-09-29 13:46:19 UTC
Permalink
Post by c***@CSIC.UMD.EDU
Because the process that will die will not be the malicious
process, but instead the process the malicious process sent the
signal to.
I'm pretty sure that's wrong. In order for that to happen the malicious
process would need to register a signal handler for a -different-
process. You're only allowed to register a signal handler for yourself.
If you screw up and register a meaningless signal handler for yourself,
another process can hardly be termed malicious for sending you a
perfectly legitimate signal.

If you could register signal handlers for other processes there would be
loads of other problems beyond simple segmentation of memory.
Saurabh Srivastava
2005-09-30 04:16:47 UTC
Permalink
it is correct that an invalid handler will only cause the initiating
process to die (but only, later when it attempts to branch to it on a
signal). The efficiency issue that you are talking about is trivial: it is
only the overhead of doing a memory check.

Returning an error in the case of invalid memory being passed will conform
to the requirements (and specification) of the system call. It would be
wierd to return the syscall with a success code when it actually failed
(in terms of putting the system in an invalid state).

Also, it is not always the case that such invalid pointers be passed by a
malicious process. imagine a scenario in which some library routines are
registering handlers on behalf of a process! A bug in the library could
cause invalid pointers to be passed and we would want to ensure that the
syscall does not complete as requested.

| > Because the process that will die will not be the malicious
| > process, but instead the process the malicious process sent the
| > signal to.
|
| I'm pretty sure that's wrong. In order for that to happen the malicious
| process would need to register a signal handler for a -different-
| process. You're only allowed to register a signal handler for yourself.
| If you screw up and register a meaningless signal handler for yourself,
| another process can hardly be termed malicious for sending you a
| perfectly legitimate signal.
|
| If you could register signal handlers for other processes there would be
| loads of other problems beyond simple segmentation of memory.
|
|
|
cs412042
2005-09-30 08:25:14 UTC
Permalink
If you've made an official ruling the Validate_User_Memory must be used to
detect errors in Sys_RegDeliver, then it's simple: we need to do it.

I think it's worth noting that processes can attempt to jump to whatever
memory they want, even without the kernel's help via signal handlers.

David Renie
Saurabh Srivastava
2005-09-30 18:38:13 UTC
Permalink
| If you've made an official ruling the Validate_User_Memory must be used to
| detect errors in Sys_RegDeliver, then it's simple: we need to do it.
|
| I think it's worth noting that processes can attempt to jump to whatever
| memory they want, even without the kernel's help via signal handlers.

completely agree. and i never said otherwise. my point was just that the
syscall completing successfully when it actually hasnt done its work
seemed a bit off.

additionally, its more a matter of requirements than anything else; make
sure that you are able to handle the last point in 'handling errors' in
the grading criterion.
cs412042
2005-09-30 20:28:53 UTC
Permalink
Post by Saurabh Srivastava
additionally, its more a matter of requirements than anything else; make
sure that you are able to handle the last point in 'handling errors' in
the grading criterion.
You are a reasonable man.

David

Continue reading on narkive:
Loading...