Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/sys/windows/svc: EventType always 0 for SessionChange #25660

Closed
cpowski opened this issue May 31, 2018 · 18 comments
Closed

x/sys/windows/svc: EventType always 0 for SessionChange #25660

cpowski opened this issue May 31, 2018 · 18 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Milestone

Comments

@cpowski
Copy link

cpowski commented May 31, 2018

What version of Go are you using (go version)?

1.9.2

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

windows 10, windows server 2008 r2 / amd64

What did you do?

I'm writing a windows service using the example project found at:

https://github.com/golang/sys/tree/master/windows/svc/example

In the service Execute function I've added AcceptSessionChange to the accepted commands and added a case to the switch statement:

case svc.SessionChange:
  elog.Info(1, fmt.Sprintf(
    "cmd <%d> type <%d> data <%d> ", c.Cmd, c.EventType, c.EventData))

  changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}    

These are the only changes made to the example project.

What did you expect to see?

EventType populated with status code indicating the event type, as described in:

https://msdn.microsoft.com/en-us/library/aa383828(v=vs.85).aspx

EventData populated with SessionID of event.

What did you see instead?

EventType is always 0
EventData is correct

@agnivade agnivade changed the title EventType always 0 for SessionChange using golang.org/x/sys/windows/svc x/sys/windows/svc: EventType always 0 for SessionChange May 31, 2018
@gopherbot gopherbot added this to the Unreleased milestone May 31, 2018
@agnivade
Copy link
Contributor

/cc @alexbrainman

@agnivade agnivade added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label May 31, 2018
@alexbrainman
Copy link
Member

@cpowski I do not understand what your problem is.

Please, provide full small program that I could run here. And tell me what your program does wrong.

Thank you.

Alex

@cpowski
Copy link
Author

cpowski commented Jun 2, 2018

Hi @alexbrainman, the program I'm writing is a windows service that detects logon/off events. I've started with the windows service example in the golang docs. I've combined the 5 files from that project into one and shared it on play.golang.org. The example project does not handle SessionChange events so I've made the following additions:

  • line 88: Added | svc.AcceptSessionChange
  • line 99/100: Commented out the beep logs to keep the event log clean
  • line 116-121: Added a case to handle the SessionChange event and log the details to the event log.

The rest of the file is unchanged from the sample project. Once built, the executable needs to be installed as as service and started with ./<executable> install and ./<executable> start. This process is successful and the start up message appears in the windows event log.

I log in/out of a test profile on my machine to trigger a session change event. In the logs I see this:

SessionChange cmd <14> type <0> data <3>

The cmd is correct (SessionChange) and the data contains the associated SessionID. All good. The problem is the EventType. This should represent the reason for the event, however it always reports as 0, which is not a valid status code.

I've tested on windows 10 and windows server 2008 r2 with the same result. I have a c++ service running on the same machines, with the same configuration/service account. It's doing the same thing and successfully receiving the event type.

Let me know if you need any more info.

@alexbrainman
Copy link
Member

shared it on play.golang.org

Thank you. I will try and run it here.

I have a c++ service running on the same machines, with the same configuration/service account. It's doing the same thing and successfully receiving the event type.

I will need the source code for that service too. I have never written code that does something similar. So C++ example would be helpful for me to debug Go code.

Thank you.

Alex

@Green7
Copy link

Green7 commented Jun 12, 2018

I have this same problem.
When I handle svc.SessionChange in service EventType should be one of WTS_CONSOLE_XXX values (from http://msdn.microsoft.com/en-us/library/aa383828(v=vs.85).aspx) and EventData should be a pointer to WTSSESSION_NOTIFICATION structure
But EventType is always 0 and EventData usually has values from 1 to 8.

What is important: when I build my sample service as 32 bit application everything works fine! EventType and EventData have valid values and I can for example read WTSSESSION_NOTIFICATION structure.

So parameters are passed incorrectly only in 64 bit code: EventType is 0, EventData have value from EventType and pointer to WTSSESSION_NOTIFICATION is missing.

@Green7
Copy link

Green7 commented Jun 12, 2018

I log in/out of a test profile on my machine to trigger a session change event. In the logs I see this:

SessionChange cmd <14> type <0> data <3>
The cmd is correct (SessionChange) and the data contains the associated SessionID. All good. The >problem is the EventType. This should represent the reason for the event, however it always reports as >0, which is not a valid status code.

I think you are wrong. Look at: https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms683241%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 for SERVICE_CONTROL_SESSIONCHANGE EventType is one of WTS_CONSOLE_XXX values and EventData is a pointer to a WTSSESSION_NOTIFICATION structure.
So your EventData does not contain sessionID. SessionID should be readed from WTSSESSION_NOTIFICATION structure.

@Green7
Copy link

Green7 commented Aug 3, 2018

Any news ?

I also noted problems in 32 bit application. In some cases sessionID is invalid (in my tests has value 4784210).
It is go problem in C++ app everything works. I think that the problem is in sys_386.s, sys_amd64.s asm code so it is hard to fix for me....

@niallnsec
Copy link

I think I am having a similar issue and may have found a solution.

For a svc.SessionChange event the parameters passed from windows to the callback seem to be off by one. The handler defined in service.go:318 does receive the correct information just in the wrong parameters.
ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr

The evtype value is always zero, the evdata value contains what should be stored in evtype and the context value stores the value which should be in evdata.
I tested this by changing the handler so that it puts context into the eventdata field like so:
e := ctlEvent{cmd: Cmd(ctl), eventType: evtype, eventData: context}
Note: I have no idea if making this change will break other notification types as I have only test with the Session Change notification.

After doing this, I can cast the returned value to a pointer to a WTSSESSION_NOTIFICATION structure and read the session ID from there.

type WTSSESSION_NOTIFICATION struct {
	Size      uint32
	SessionId uint32
}
...
case svc.SessionChange:
	elog.Info(1, fmt.Sprintf("Session change: 0x%08x : %+v", c.EventData, c))
	sd := (*WTSSESSION_NOTIFICATION)(unsafe.Pointer(c.EventData))
	elog.Info(1, fmt.Sprintf("Session change: %d", sd.SessionId))

I'm guessing this issue is specifically related to the Go assembly files since the parameters seem to have been shifted but unfortunately I am not familiar enough with it to spot the error.

For reference I am using Go 1.10.7 amd64 on a fully updated Windows 10 machine.

@alexbrainman
Copy link
Member

The handler defined in service.go:318 does receive the correct information just in the wrong parameters.
ctlHandler := func(ctl uint32, evtype uint32, evdata uintptr, context uintptr) uintptr

The evtype value is always zero, the evdata value contains what should be stored in evtype and the context value stores the value which should be in evdata.

Maybe you are correct, and there is a bug here. Maybe Windows passes ctl and evtype parameters as 4 byte each, but Go function reserves 8 bytes for each argument.

If that was broken forever, how would other services work? If someone can provide me with some reproducible example of this problem, that would make my investigation quicker.

Thank you very much.

Alex

@niallnsec
Copy link

Thanks for the quick response! I have created a gist which contains two files.

The first is a modified version of svc\example\service.go which has been changed to write two messages to the Application event log when a session change event occurs. The first log entry is a dump of the contents of the ChangeRequest structure and the second is the Session ID.

The second file is a modified version of svc\service.go which is changed only to pass the context parameter through to the service example program. This is to show that it does have a value and appears to be pointing to a valid WTSSESSION_NOTIFICATION structure.

After installing and starting the example service, to test I have been locking my session and then unlocking, this creates log entries similar to the following:
{Cmd:14 EventType:0 EventData:8 CurrentStatus:{State:4 Accepts:135 CheckPoint:0 WaitHint:0} Context:824256}
Session ID: 2

As for why this has not been brought up before, I would imagine that not a lot of people are using the SessionChange notification in their services. But I could of course be wrong on that not having any real statistics to look at.

I hope this helps, if you need anything more I am happy to try and assist as best I can.

@Green7
Copy link

Green7 commented Jan 10, 2019

I can confirm that niallnsec sample shows problem.
But when is compiled as 32 bit the problem does not exist, EvenType and EventData are ok.

@alexbrainman
Copy link
Member

I have created a gist which contains two files.

Thank you very much. I will see what I can do with that, when I have free time.

Alex

@gopherbot
Copy link

Change https://golang.org/cl/158698 mentions this issue: windows/svc: align ctlHandler parameters

@gopherbot
Copy link

Change https://golang.org/cl/158697 mentions this issue: windows/svc: add Context to ChangeRequest

@alexbrainman
Copy link
Member

@cpowski, @Green7 and @niallnsec please test my change

https://go-review.googlesource.com/c/sys/+/158698

Thank you.

Alex

@Green7
Copy link

Green7 commented Jan 21, 2019

It works for me.

@niallnsec
Copy link

Thanks for the fix @alexbrainman
I have tested it on 64 and 32 bit Windows 10 and 64 bit Windows 7 and it seems to be working perfectly!

@alexbrainman
Copy link
Member

Thanks for checking. Now we need to wait for review.

Alex

gopherbot pushed a commit to golang/sys that referenced this issue Mar 2, 2019
New Context field will be used in the following CL to test
ctlHandler parameter alignments.

Also adjust TestExample to pass hard coded Context value of 123456
to test service, and verify that correct value is logged. Final
part of the test is commented out, and will be adjusted in the next
CL.

Updates golang/go#25660

Change-Id: Iad2896ae497ee1edc0d62655eaf08671ec2651c5
Reviewed-on: https://go-review.googlesource.com/c/158697
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@golang golang locked and limited conversation to collaborators Mar 1, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Projects
None yet
Development

No branches or pull requests

6 participants