|
|
|
date: Tue, 05 Aug 2008 09:27:34 -0700,
group: microsoft.public.platformsdk.shell
back
Problems with CreatEnvironmentBlock in 64-bit Vista
I hope this is the right forum for this. If not, I'd appreciate a
suggestion on where to post it.
CreateEnvironmentBlock appears to have a bug in 64-bit Vista. Because
of the bug, Protected Mode 32-bit iexplore will fail to launch fully
(including not show a window) if iexplore is launched using
CreateEnvironmentBlock + CreateProcessAsUser in a 32-bit service and
if ieuser is not already running.
Details:
When CreateEnvironmentBlock is called without inheriting environment
variables from the current process, the returned environment block is
missing the following environment variables: CommonProgramFiles(x86),
CommonProgramW6432, ProgramFiles(x86), ProgramW6432. Then if iexplore
is launched using that environment block, iexplore is unable to launch
ieuser, probably because it cannot expand the path to ieuser found
under ieuser's classid ("%ProgramFiles(x86)%\Internet
Explorer\IEUser.exe"). Substituting a simple exe for iexplore, it is
easy to confirm that those missing environment variables are missing
within the iexplore process (and not added later, for example, inside
the CreateProcessAsUser call or inside the WoW 32-bit subsystem). It
is also easy to confirm that those environment variables are present
when a process is launched from Windows Explorer (or, naturally, from
CreateProcess within a process launched from Windows Explorer).
Simplified sample code:
// build with UNICODE strings
// run from the explorer shell at medium integrity
// Paths are hard coded in the following two strings for simiplicity.
static const TCHAR missing_environment_variables[] =
_T("CommonProgramFiles(x86)=C:\\Program Files (x86)\\Common Files\0")
_T("CommonProgramW6432=C:\\Program Files\\Common Files\0")
_T("ProgramFiles(x86)=C:\\Program Files (x86)\0")
_T("ProgramW6432=C:\\Program Files\0\0");
static const TCHAR iexplore_command_line[] =
_T("\"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\" ")
_T("http://www.nytimes.com/");
// Get size of a multi-string. Include all 0 characters in the returned
size.
int GetMultzStringSize(const WCHAR* string) {
int length = 0;
// Determine length to final two 0 characters.
for(; L'\0' != string[length] || L'\0' != string[length+1]; length++) {
}
// Add two to include the final two 0 characters.
return sizeof(WCHAR)*(length + 2);
}
void testCreateProcessAsUser() {
// Get a token for the current user.
HANDLE process_token = NULL;
if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE |
TOKEN_QUERY,
&process_token))
return;
HANDLE user_token = NULL;
BOOL token_duplicated = DuplicateTokenEx(process_token,
TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE,
NULL, SecurityImpersonation, TokenPrimary, &user_token);
CloseHandle(process_token);
if (!token_duplicated || INVALID_HANDLE_VALUE == user_token)
return;
STARTUPINFO startup_info = {0};
startup_info.cb = sizeof(startup_info);
// Setting the desktop does not help.
//startup_info.lpDesktop = _T("winsta0\\default");
PROCESS_INFORMATION process_info;
// Impersonating the user does not help.
// bool impersonating_user = !!ImpersonateLoggedOnUser(user_token);
// Create a key for storing experiment results. Could not get results by
// debugging remotely since debugger did not show the entirety of the
// environment blocks.
HKEY key;
if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER,
_T("SOFTWARE\\Google\\experiment"), 0,
NULL, 0, KEY_ALL_ACCESS, NULL,
&key, NULL))
return;
DWORD creation_flags(0);
void* environment_block(NULL);
BYTE* fixed_environment_block(NULL);
if (CreateEnvironmentBlock(&environment_block, user_token, FALSE)) {
creation_flags |= CREATE_UNICODE_ENVIRONMENT;
int size = GetMultzStringSize((const WCHAR*)environment_block);
// Write out contents of environment block.
RegSetValueEx(key, _T("failing_environment"), 0, REG_MULTI_SZ,
reinterpret_cast<const BYTE *>(environment_block), size);
// Subtract out the final 0 character.
size -= sizeof(WCHAR);
// Append missing environment variables to end
fixed_environment_block =
new BYTE[size + sizeof(missing_environment_variables)];
memcpy(fixed_environment_block, environment_block, size);
memcpy(fixed_environment_block + size, missing_environment_variables,
sizeof(missing_environment_variables));
size = GetMultzStringSize((const WCHAR*)fixed_environment_block);
// Write out contents of fixed environment block.
RegSetValueEx(key, _T("failing_environment_fixed"), 0, REG_MULTI_SZ,
reinterpret_cast<const BYTE
*>(fixed_environment_block), size);
}
void* inherited_environment_block(NULL);
CreateEnvironmentBlock(&inherited_environment_block, user_token, TRUE);
if (inherited_environment_block) {
int size = GetMultzStringSize((const WCHAR*)inherited_environment_block);
// Write out contents of environment block that inherits from current
// process.
RegSetValueEx(key, _T("inherited_environment"), 0, REG_MULTI_SZ,
reinterpret_cast<const BYTE
*>(inherited_environment_block),
size);
DestroyEnvironmentBlock(inherited_environment_block);
}
LPTCH environment_strings = GetEnvironmentStrings();
if (NULL != environment_strings) {
int size = GetMultzStringSize((const WCHAR*)environment_strings);
// Write out current environment.
RegSetValueEx(key, _T("current_environment"), 0, REG_MULTI_SZ,
reinterpret_cast<const BYTE *>(environment_strings), size);
FreeEnvironmentStrings(environment_strings);
}
TCHAR command_line[500];
// For simplicity, use hard coded path to 32-bit iexplore.
wcscpy(command_line, iexplore_command_line);
// Launch iexplore using failing environment block.
if (!CreateProcessAsUser(user_token, 0, command_line, 0, 0, FALSE,
creation_flags, environment_block, 0,
&startup_info, &process_info)) {
DWORD last_error = GetLastError();
} else {
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
}
MessageBox(NULL, _T("Pause after failed iexplore launch"),
_T("Test Impersonation"), MB_OK);
// Launch iexplore using fixed environment block.
if (!CreateProcessAsUser(user_token, 0, command_line, 0, 0, FALSE,
creation_flags, fixed_environment_block, 0,
&startup_info, &process_info)) {
DWORD last_error = GetLastError();
} else {
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
}
if (environment_block)
DestroyEnvironmentBlock(environment_block);
delete [] fixed_environment_block;
// if (impersonating_user)
// RevertToSelf();
RegCloseKey(key);
CloseHandle(user_token);
}
int WINAPI _tWinMain(HINSTANCE instance, HINSTANCE, TCHAR*
command_line_string,
int show) {
MessageBox(NULL, _T("Pause before test\nBefore continuing, kill ieuser"),
_T("Test Impersonation"), MB_OK);
testCreateProcessAsUser();
return 0;
}
date: Tue, 05 Aug 2008 09:27:34 -0700
author: Albert Bodenhamer am
RE: Problems with CreatEnvironmentBlock in 64-bit Vista
Good morning Albert. Welcome to Microsoft Newsgroup Support Service! My
name is Jialiang Ge [MSFT]. It's my pleasure to work with you on this issue.
This is a quick note to let you know that I am building a Vista x64
environment to test your code snippet. Before the env is set up, I queried
the symptom in the product group's database that CreateEnvironmentBlock()
fails to set %CommonProgramFiles(x86)% and %CommonProgramFiles(x86)% and
%ProgramFiles(x86)% for 32bit application running in WOW64 of Windows
Vista, and found a relevant bug report:
--- BRIEF DESCRIPTION ---
Applications fail to run when SQL Agent is running in a 32bit environment
and tries to launch the App on a x64 Vista system with SQL installed in WOW
mode. It internally calls
CreateEnvironmentBlock(bInherit = FALSE)
and the app fails to launch as it is unable to locate ole32db.dll (and
other dlls which have %CommonProgramFiles(x86)% in the path for the dll).
Essentially, com applications fail because kernel32's load library function
is unable to locate dlls since %CommonProgramFiles(x86)% is not defined in
the environment
--- CAUSE ---
The problem indicates that kernel32's load library function is unable to
locate dlls. This is because %CommonProgramFiles(x86)% and
%ProgramFiles(x86)% are not defined for 32bit application running in WOW64.
The root cause is: on a 64bit box, if an application (both 32bit and 64bit)
created a 32-bit child without inherit:
CreateEnvironmentBlock(bInherit = FALSE)
the child's environment variables got changed a lot, including that it will
lose %CommonProgramFiles(x86)% and %ProgramFiles(x86)%, and there are many
other changes as well. To fix it, on x64, we need to add
%CommonProgramFiles(x86)% and %ProgramFiles(x86)% back to 32bit child
without inherit, that is, it will perform the same as when a parent creates
a 32-bit child with inherit, and also the same as when a parent creates a
64-bit child with and without inherit. The bug is at CreateEnviromentBlock,
however, the product team currently does not have the plan to fix it in
Vista though the fix has been checked into the next version of Windows.
Based on the above issue description, I assume that the possible
resolutions in your code will be:
SOLUTION1.
Set the hInherit parameter of CreateEnvironmentBlock to TRUE if this fits
your product environment:
http://msdn.microsoft.com/en-us/library/bb762270(VS.85).aspx
CreateEnvironmentBlock(&environment_block, user_token, TRUE))
SOLUTION2.
If the first solution is not helpful, you may want to try this one:
%CommonProgramFiles% and %ProgramFiles% environment variable (without (x86)
version) are always pointing to right location, according to binary types
(32bit or 64bit) and not depending on if it is inherited and not. Thus, we
can use these environment variables to find the right path. Also, the
application can add the environment variable %CommonProgramFiles(x86)% to
the value of %CommonProgramFiles% to avoid hard-coding
_T("CommonProgramFiles(x86)=C:\\Program Files (x86)\\Common Files\0").
These two points are my current assumption of the resolution. I need to
prove them after I build up the environment. Albert, you may also want to
test them on your side if my env cannot be set up timely.
Best Regards,
Jialiang Ge (jialge@online.microsoft.com, remove 'online.')
Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msdnmg@microsoft.com.
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
date: Wed, 06 Aug 2008 05:37:53 GMT
author: (Jialiang Ge [MSFT])
RE: Problems with CreatEnvironmentBlock in 64-bit Vista
Hello Albert,
I've built up a Windows Vista x64 environment and tested your code snippet
in it. Below is my analysis:
1. failing_environment
Test Result: 31items
Environment Variables like CommonProgramFiles(x86), CommonProgramW6432 are
lost.
Cause
This is indeed a bug of CreateEnvironmentBlock(bInherit = FALSE). I've
attached the detailed information of this issue to my last reply's "CAUSE"
section. According to the product group's responses, it has been fixed in
the next version of Windows. However, they currently do not have plan to
check the fix into Vista.
2. current_environment
Test Result: 37 items
Because I tested your code in a Win32 console application. The current
environment includes the variables like CommonProgramFiles(x86),
CommonProgramW6432.
3. inherited_environment
Test Result: 37 items
The test result depends on the current environment. Because my current
environment includes the variables like CommonProgramFiles(x86),
CommonProgramW6432. They are not lost in the inherited_environment.
4. failing_environment_fixed
Test Result: 35 items
The result of failing_environment_fixed is not as complete as
current_environment. The fixed environment is enough to run IE smoothly.
==================
In conclusion, whether my solutions in the initial reply are helpful to you
depends.
SOLUTION1. Set the hInherit parameter of CreateEnvironmentBlock to TRUE
It depends on the current environment of the process. If
current_environment is complete, this solution is useful.
SOLUTION2. Add the environment variable %CommonProgramFiles(x86)% to the
value of %CommonProgramFiles% to avoid hard-coding:
static const TCHAR missing_environment_variables[] =
_T("CommonProgramFiles(x86)=C:\\Program Files (x86)\\Common Files\0")
_T("CommonProgramW6432=C:\\Program Files\\Common Files\0")
_T("ProgramFiles(x86)=C:\\Program Files (x86)\0")
_T("ProgramW6432=C:\\Program Files\0\0");
Albert, what do you think about these solutions and my analysis of the
issue? If you have any other concerns or questions, please DON'T hesitate
to tell me.
And again, thank you very much for reporting this product issue to us.
Have a great day!
Regards,
Jialiang Ge (jialge@online.microsoft.com, remove 'online.')
Microsoft Online Community Support
=================================================
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msdnmg@microsoft.com.
This posting is provided "AS IS" with no warranties, and confers no rights.
=================================================
date: Thu, 07 Aug 2008 11:32:34 GMT
author: (Jialiang Ge [MSFT])
|
|