Skip to content

Commit b7e0c8d

Browse files
Add -dont_restart_as_admin to command line when restarting as admin
This prevents endless loop of RestartAsAdministrator() if we fail to enable SeDebugPrivilege after the first restart. See issue #94
1 parent a83ac5d commit b7e0c8d

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed

PresentMon/OutputThread.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ static ProcessInfo* GetProcessInfo(uint32_t processId)
163163
// In ETL capture, we should have gotten an NTProcessEvent for this
164164
// process updated via UpdateNTProcesses(), so this path should only
165165
// happen in realtime capture.
166+
//
167+
// Try to open a limited handle into the process in order to query its
168+
// name and also periodically check if it has terminated. This will
169+
// fail (with GetLastError() == ERROR_ACCESS_DENIED) if the process was
170+
// run on another account, unless we're running with SeDebugPrivilege.
166171
auto const& args = GetCommandLineArgs();
167172
HANDLE handle = NULL;
168173
char const* processName = "<error>";

PresentMon/Privilege.cpp

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -121,32 +121,60 @@ int RestartAsAdministrator(
121121
int argc,
122122
char** argv)
123123
{
124+
// Get the exe path
124125
char exe_path[MAX_PATH] = {};
125126
GetModuleFileNameA(NULL, exe_path, sizeof(exe_path));
126127

127-
// Combine arguments into single array
128-
char args[1024] = {};
129-
for (int idx = 0, i = 1; i < argc && (size_t) idx < sizeof(args); ++i) {
130-
if (idx >= sizeof(args)) {
131-
fprintf(stderr, "internal error: command line arguments too long.\n");
132-
return false; // was truncated
128+
// Combine arguments into single char* and add -dont_restart_as_admin to
129+
// prevent an endless loop if the escalation fails.
130+
char* args = nullptr;
131+
{
132+
static char const* const extra_args = "-dont_restart_as_admin";
133+
size_t idx = strlen(extra_args);
134+
size_t len = idx + 1;
135+
for (int i = 1; i < argc; ++i) {
136+
len += strlen(argv[i]) + 2 + 1; // +2 for possible quotes, +1 for space or null
133137
}
134138

135-
if (argv[i][0] != '\"' && strchr(argv[i], ' ')) {
136-
idx += snprintf(args + idx, sizeof(args) - idx, " \"%s\"", argv[i]);
137-
} else {
138-
idx += snprintf(args + idx, sizeof(args) - idx, " %s", argv[i]);
139+
args = new char [len];
140+
memcpy(args, extra_args, idx + 1);
141+
for (int i = 1; i < argc; ++i) {
142+
auto addQuotes = argv[i][0] != '\"' && strchr(argv[i], ' ') != nullptr;
143+
auto n = strlen(argv[i]);
144+
145+
args[idx] = ' ';
146+
147+
if (addQuotes) {
148+
args[idx + 1] = '\"';
149+
memcpy(args + idx + 2, argv[i], n);
150+
args[idx + n + 2] = '\"';
151+
args[idx + n + 3] = '\0';
152+
idx += 2;
153+
} else {
154+
memcpy(args + idx + 1, argv[i], n + 1);
155+
}
156+
157+
idx += n + 1;
139158
}
140159
}
141160

161+
// Re-run the process with the runas verb
162+
DWORD code = 2;
163+
142164
SHELLEXECUTEINFOA info = {};
143165
info.cbSize = sizeof(info);
144-
info.fMask = SEE_MASK_NOCLOSEPROCESS;
166+
info.fMask = SEE_MASK_NOCLOSEPROCESS; // return info.hProcess for explicit wait
145167
info.lpVerb = "runas";
146168
info.lpFile = exe_path;
147169
info.lpParameters = args;
148-
info.nShow = SW_SHOW;
149-
if (!ShellExecuteExA(&info) || info.hProcess == NULL) {
170+
info.nShow = SW_SHOWDEFAULT;
171+
auto ok = ShellExecuteExA(&info);
172+
delete[] args;
173+
if (ok) {
174+
WaitForSingleObject(info.hProcess, INFINITE);
175+
GetExitCodeProcess(info.hProcess, &code);
176+
CloseHandle(info.hProcess);
177+
} else {
150178
fprintf(stderr, "error: failed to elevate privilege ");
151179
int e = GetLastError();
152180
switch (e) {
@@ -159,17 +187,8 @@ int RestartAsAdministrator(
159187
case ERROR_SHARING_VIOLATION: fprintf(stderr, "(sharing violation).\n"); break;
160188
default: fprintf(stderr, "(%u).\n", e); break;
161189
}
162-
return 2;
163190
}
164191

165-
WaitForSingleObject(info.hProcess, INFINITE);
166-
167-
DWORD code = 0;
168-
GetExitCodeProcess(info.hProcess, &code);
169-
int e = GetLastError();
170-
(void) e;
171-
CloseHandle(info.hProcess);
172-
173192
return code;
174193
}
175194

0 commit comments

Comments
 (0)