cgo pam module signal handling

232 views
Skip to first unread message

Chandrasekhar R

unread,
Aug 11, 2023, 2:52:03 PM8/11/23
to golang-nuts
Hey community,

I am planning on using a pam module written in Go (specifically https://github.com/uber/pam-ussh) . When I run a script which calls sudo continuously with an echo command, I am noticing zombie/defunct processes starting to pop up.

On doing strace, I noticed that the SIGCHLD gets delivered to one of the threads created when Go gets initialized (i.e. the shared object gets loaded).

I tried to add one level of indirection by having a separate C code which creates a new thread, sets the signal mask to block SIGCHLD and then use dlopen to open the shared object created using cgo. I am still facing the same issue, is there any pointer on how to fix this issue? I think this would be a wide issue across all PAM modules written using cgo.

Ian Lance Taylor

unread,
Aug 12, 2023, 1:05:48 AM8/12/23
to Chandrasekhar R, golang-nuts
As far as I know the specific thread that receives a SIGCHLD signal is
fairly random. What matters is not the thread that receives the
signal, but the signal handler that is installed. Signal handlers are
process-wide. What signal handler is running when you get a SIGCHLD?
What signal handler do you expect to run?

Ian

Chandrasekhar R

unread,
Aug 14, 2023, 3:02:15 PM8/14/23
to golang-nuts
My understanding currently is sudo sets up a signal handler in pre_exec and another signal handler later on which is tied into its main event loop.
Go gets initialized when the pre_exec signal handler is used and it adds rt_sigaction(SIGCHLD..) with the SA_ONSTACK flag as mentioned here
Then after the sudo command (echo) gets executed, the SIGCHLD is received by one of the go threads which then runs the pre_exec signal handler which is the old and nonexistent signal handler.

My approach is to block the Go threads from receiving the SIGCHLD signal and thus not let the signal to be handled by the old signal handler.

Ian Lance Taylor

unread,
Aug 14, 2023, 3:17:34 PM8/14/23
to Chandrasekhar R, golang-nuts
On Mon, Aug 14, 2023 at 12:02 PM Chandrasekhar R <crama...@gmail.com> wrote:
>
> My understanding currently is sudo sets up a signal handler in pre_exec and another signal handler later on which is tied into its main event loop.
> Go gets initialized when the pre_exec signal handler is used and it adds rt_sigaction(SIGCHLD..) with the SA_ONSTACK flag as mentioned here.
> Then after the sudo command (echo) gets executed, the SIGCHLD is received by one of the go threads which then runs the pre_exec signal handler which is the old and nonexistent signal handler.
>
> My approach is to block the Go threads from receiving the SIGCHLD signal and thus not let the signal to be handled by the old signal handler.

I don't quite understand the scenario you are describing. What
matters is the signal handler. When Go adds the SA_ONSTACK flag, it
doesn't change the signal handler. Which thread a signal is delivered
to does not affect which signal handler gets run.

Ian


> On Friday, August 11, 2023 at 10:05:48 PM UTC-7 Ian Lance Taylor wrote:
>>
>> On Fri, Aug 11, 2023 at 11:51 AM Chandrasekhar R <crama...@gmail.com> wrote:
>> >
>> > I am planning on using a pam module written in Go (specifically https://github.com/uber/pam-ussh) . When I run a script which calls sudo continuously with an echo command, I am noticing zombie/defunct processes starting to pop up.
>> >
>> > On doing strace, I noticed that the SIGCHLD gets delivered to one of the threads created when Go gets initialized (i.e. the shared object gets loaded).
>> >
>> > I tried to add one level of indirection by having a separate C code which creates a new thread, sets the signal mask to block SIGCHLD and then use dlopen to open the shared object created using cgo. I am still facing the same issue, is there any pointer on how to fix this issue? I think this would be a wide issue across all PAM modules written using cgo.
>>
>> As far as I know the specific thread that receives a SIGCHLD signal is
>> fairly random. What matters is not the thread that receives the
>> signal, but the signal handler that is installed. Signal handlers are
>> process-wide. What signal handler is running when you get a SIGCHLD?
>> What signal handler do you expect to run?
>>
>> Ian
>
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/7b395394-da12-4b19-9e07-5c8f7e91dcabn%40googlegroups.com.

Chandrasekhar R

unread,
Aug 14, 2023, 7:52:24 PM8/14/23
to golang-nuts
The scenario is:
1) sudo starts and sets up a signal handler for SIGCHLD 
2) pam modules gets loaded
3) Go gets initialized and sets the SA_ONSTACK flag specifically by calling rt_sigaction with a pointer to the existing signal handler in sa_handler field.
4) Sudo initialized a new signal handler for SIGCHLD
5) After the command is run and SIGCHLD signal is received by a Go created thread instead of the parent sudo thread then it goes to the signal handler created in step 1.

I believe this is the current set of events happening. I can share a strace dump if it would help.

Ian Lance Taylor

unread,
Aug 15, 2023, 7:55:21 PM8/15/23
to Chandrasekhar R, golang-nuts
On Mon, Aug 14, 2023 at 4:52 PM Chandrasekhar R <crama...@gmail.com> wrote:
>
> The scenario is:
> 1) sudo starts and sets up a signal handler for SIGCHLD
> 2) pam modules gets loaded
> 3) Go gets initialized and sets the SA_ONSTACK flag specifically by calling rt_sigaction with a pointer to the existing signal handler in sa_handler field.
> 4) Sudo initialized a new signal handler for SIGCHLD
> 5) After the command is run and SIGCHLD signal is received by a Go created thread instead of the parent sudo thread then it goes to the signal handler created in step 1.
>
> I believe this is the current set of events happening. I can share a strace dump if it would help.

Thanks for the outline. That series of events doesn't make sense to
me. Signal handlers are process-wide. When in step 4 sudo sets a
signal handler for SIGCHLD, that is the signal handler for all threads
in the process. When in step 5 a SIGCHLD signal is received, it will
go to the signal handler installed in step 4, not the signal handler
installed in step 1.

Yes, an strace dump would help clarify this. Thanks.

Ian
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/216fb89f-ba9c-41e6-ba90-485b9174a0a5n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages