Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/shared/Communication.cpp

Issue 5792731695677440: Fix named pipe security on Windows 7 (Closed)
Patch Set: Refactor to eliminate the corrupt ACL bug. Address comments. Created July 2, 2014, 9:47 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/shared/Utils.cpp » ('j') | src/shared/Utils.cpp » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #include <Windows.h> 1 #include <Windows.h>
2 #include <Lmcons.h> 2 #include <Lmcons.h>
3 #include <Sddl.h> 3 #include <Sddl.h>
4 #include <aclapi.h> 4 #include <aclapi.h>
5 #include <strsafe.h> 5 #include <strsafe.h>
6 6
7 #include "AutoHandle.h" 7 #include "AutoHandle.h"
8 #include "Communication.h" 8 #include "Communication.h"
9 #include "Utils.h" 9 #include "Utils.h"
10 10
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 { 66 {
67 EXPLICIT_ACCESSW explicitAccess[2] = {}; 67 EXPLICIT_ACCESSW explicitAccess[2] = {};
68 68
69 explicitAccess[0].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RI GHTS_ALL; 69 explicitAccess[0].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RI GHTS_ALL;
70 explicitAccess[0].grfAccessMode = SET_ACCESS; 70 explicitAccess[0].grfAccessMode = SET_ACCESS;
71 explicitAccess[0].grfInheritance= NO_INHERITANCE; 71 explicitAccess[0].grfInheritance= NO_INHERITANCE;
72 explicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; 72 explicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
73 explicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_USER; 73 explicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
74 explicitAccess[0].Trustee.ptstrName = static_cast<LPWSTR>(logonSid); 74 explicitAccess[0].Trustee.ptstrName = static_cast<LPWSTR>(logonSid);
75 75
76 std::tr1::shared_ptr<SID> sharedAllAppContainersSid;
77
78 // Create a well-known SID for the all appcontainers group. 76 // Create a well-known SID for the all appcontainers group.
79 // We need to allow access to all AppContainers, since, apparently, 77 // We need to allow access to all AppContainers, since, apparently,
80 // giving access to specific AppContainer (for example AppContainer of IE) 78 // giving access to specific AppContainer (for example AppContainer of IE)
81 // tricks Windows into thinking that token is IN AppContainer. 79 // tricks Windows into thinking that token is IN AppContainer.
82 // Which blocks all the calls from outside, making it impossible to commun icate 80 // Which blocks all the calls from outside, making it impossible to commun icate
83 // with the engine when IE is launched with different security settings. 81 // with the engine when IE is launched with different security settings.
84 PSID allAppContainersSid = 0; 82 PSID allAppContainersSid = 0;
85 SID_IDENTIFIER_AUTHORITY applicationAuthority = SECURITY_APP_PACKAGE_AUTHO RITY; 83 SID_IDENTIFIER_AUTHORITY applicationAuthority = SECURITY_APP_PACKAGE_AUTHO RITY;
86 84
87 AllocateAndInitializeSid(&applicationAuthority, 85 AllocateAndInitializeSid(&applicationAuthority,
88 SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT, 86 SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT,
89 SECURITY_APP_PACKAGE_BASE_RID, 87 SECURITY_APP_PACKAGE_BASE_RID,
90 SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE, 88 SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE,
91 0, 0, 0, 0, 0, 0, 89 0, 0, 0, 0, 0, 0,
92 &allAppContainersSid); 90 &allAppContainersSid);
93 sharedAllAppContainersSid.reset(static_cast<SID*>(allAppContainersSid), Fr eeSid); // Just to simplify cleanup 91 std::tr1::shared_ptr<SID> sharedAllAppContainersSid(static_cast<SID*>(allA ppContainersSid), FreeSid); // Just to simplify cleanup
94 92
95 explicitAccess[1].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RI GHTS_ALL; 93 explicitAccess[1].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RI GHTS_ALL;
96 explicitAccess[1].grfAccessMode = SET_ACCESS; 94 explicitAccess[1].grfAccessMode = SET_ACCESS;
97 explicitAccess[1].grfInheritance= NO_INHERITANCE; 95 explicitAccess[1].grfInheritance= NO_INHERITANCE;
98 explicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; 96 explicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
99 explicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; 97 explicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
100 explicitAccess[1].Trustee.ptstrName = static_cast<LPWSTR>(allAppContainers Sid); 98 explicitAccess[1].Trustee.ptstrName = static_cast<LPWSTR>(allAppContainers Sid);
101 99
102 PACL acl = 0; 100 PACL acl = 0;
101 // acl has to be released after this
Felix Dahlke 2014/07/03 13:38:07 I don't really understand, it has to be released a
Oleksandr 2014/07/03 13:51:49 1. This allocates a new ACL, so it has to be relea
Felix Dahlke 2014/07/03 13:56:33 The comment is on top of "SetEntries", so I presum
103 if (SetEntriesInAcl(2, explicitAccess, 0, &acl) != ERROR_SUCCESS) 102 if (SetEntriesInAcl(2, explicitAccess, 0, &acl) != ERROR_SUCCESS)
104 return std::auto_ptr<SECURITY_DESCRIPTOR>(0); 103 return std::auto_ptr<SECURITY_DESCRIPTOR>(0);
105 std::tr1::shared_ptr<ACL> sharedAcl(static_cast<ACL*>(acl), LocalFree); // Just to simplify cleanup
106 104
105 // This only references the acl, not copies it
Felix Dahlke 2014/07/03 13:38:07 I think this is not necessary, the official docs s
Oleksandr 2014/07/03 13:51:49 I don't really understand your point here. Could y
Felix Dahlke 2014/07/03 13:56:33 My point is that the Microsoft documentation says
Oleksandr 2014/07/15 14:16:55 This comment is quite important, IMHO. It's pretty
Felix Dahlke 2014/07/16 14:40:03 Alright.
107 if (!SetSecurityDescriptorDacl(securityDescriptor.get(), TRUE, acl, FALSE) ) 106 if (!SetSecurityDescriptorDacl(securityDescriptor.get(), TRUE, acl, FALSE) )
108 return std::auto_ptr<SECURITY_DESCRIPTOR>(0); 107 return std::auto_ptr<SECURITY_DESCRIPTOR>(0);
109
110 } 108 }
111 109
112 // Create a dummy security descriptor with low integrirty preset and copy it s SACL into ours 110 // Create a dummy security descriptor with low integrirty preset and copy it s SACL into ours
113 LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)"; 111 LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)";
114 PSECURITY_DESCRIPTOR dummySecurityDescriptorLow; 112 PSECURITY_DESCRIPTOR dummySecurityDescriptorLow;
115 ConvertStringSecurityDescriptorToSecurityDescriptorW(accessControlEntry, SDD L_REVISION_1, &dummySecurityDescriptorLow, 0); 113 ConvertStringSecurityDescriptorToSecurityDescriptorW(accessControlEntry, SDD L_REVISION_1, &dummySecurityDescriptorLow, 0);
116 std::tr1::shared_ptr<SECURITY_DESCRIPTOR> sharedDummySecurityDescriptor(stat ic_cast<SECURITY_DESCRIPTOR*>(dummySecurityDescriptorLow), LocalFree); // Just t o simplify cleanup 114 std::tr1::shared_ptr<SECURITY_DESCRIPTOR> sharedDummySecurityDescriptor(stat ic_cast<SECURITY_DESCRIPTOR*>(dummySecurityDescriptorLow), LocalFree); // Just t o simplify cleanup
117 BOOL saclPresent = FALSE; 115 BOOL saclPresent = FALSE;
118 BOOL saclDefaulted = FALSE; 116 BOOL saclDefaulted = FALSE;
119 PACL sacl; 117 PACL sacl;
120 GetSecurityDescriptorSacl(dummySecurityDescriptorLow, &saclPresent, &sacl, & saclDefaulted); 118 GetSecurityDescriptorSacl(dummySecurityDescriptorLow, &saclPresent, &sacl, & saclDefaulted);
121 if (saclPresent) 119 if (saclPresent)
122 { 120 {
123 if (!SetSecurityDescriptorSacl(securityDescriptor.get(), TRUE, sacl, FALSE )) 121 if (!SetSecurityDescriptorSacl(securityDescriptor.get(), TRUE, sacl, FALSE ))
124 { 122 {
125 DWORD err = GetLastError(); 123 DWORD err = GetLastError();
126 return std::auto_ptr<SECURITY_DESCRIPTOR>(0); 124 return std::auto_ptr<SECURITY_DESCRIPTOR>(0);
127 } 125 }
128 } 126 }
129 127
130 return securityDescriptor; 128 return securityDescriptor;
131 } 129 }
132 } 130 }
133 131
132 // Releases the DACL structure in the provided security descriptor
Felix Dahlke 2014/07/03 13:38:07 I think the function name communicates this quite
133 void ReleaseDacl(PSECURITY_DESCRIPTOR securityDescriptor)
134 {
135 BOOL aclPresent = FALSE;
136 BOOL aclDefaulted = FALSE;
137 PACL acl;
138 GetSecurityDescriptorDacl(securityDescriptor, &aclPresent, &acl, &aclDefault ed);
139 if (aclPresent)
140 {
141 LocalFree(acl);
142 }
143 }
134 const std::wstring Communication::pipeName = L"\\\\.\\pipe\\adblockplusengine_" + GetUserName(); 144 const std::wstring Communication::pipeName = L"\\\\.\\pipe\\adblockplusengine_" + GetUserName();
135 145
136 void Communication::InputBuffer::CheckType(Communication::ValueType expectedType ) 146 void Communication::InputBuffer::CheckType(Communication::ValueType expectedType )
137 { 147 {
138 if (!hasType) 148 if (!hasType)
139 ReadBinary(currentType); 149 ReadBinary(currentType);
140 150
141 if (currentType != expectedType) 151 if (currentType != expectedType)
142 { 152 {
143 // Make sure we don't attempt to read the type again 153 // Make sure we don't attempt to read the type again
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 Communication::Pipe::Pipe(const std::wstring& pipeName, Communication::Pipe::Mod e mode) 185 Communication::Pipe::Pipe(const std::wstring& pipeName, Communication::Pipe::Mod e mode)
176 { 186 {
177 pipe = INVALID_HANDLE_VALUE; 187 pipe = INVALID_HANDLE_VALUE;
178 if (mode == MODE_CREATE) 188 if (mode == MODE_CREATE)
179 { 189 {
180 SECURITY_ATTRIBUTES securityAttributes = {}; 190 SECURITY_ATTRIBUTES securityAttributes = {};
181 securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); 191 securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
182 securityAttributes.bInheritHandle = TRUE; 192 securityAttributes.bInheritHandle = TRUE;
183 193
184 std::tr1::shared_ptr<SECURITY_DESCRIPTOR> sharedSecurityDescriptor; // Just to simplify cleanup 194 std::tr1::shared_ptr<SECURITY_DESCRIPTOR> sharedSecurityDescriptor; // Just to simplify cleanup
185 195
Felix Dahlke 2014/07/03 13:38:07 Whitespace change?
186 AutoHandle token; 196 AutoHandle token;
187 OpenProcessToken(GetCurrentProcess(), TOKEN_READ, token); 197 OpenProcessToken(GetCurrentProcess(), TOKEN_READ, token);
188 198
189 if (IsWindowsVistaOrLater()) 199 if (IsWindowsVistaOrLater())
190 { 200 {
191 std::auto_ptr<SID> logonSid = GetLogonSid(token); 201 std::auto_ptr<SID> logonSid = GetLogonSid(token);
192 // Create a SECURITY_DESCRIPTOR that has both Low Integrity and allows acc ess to all AppContainers 202 // Create a SECURITY_DESCRIPTOR that has both Low Integrity and allows acc ess to all AppContainers
193 // This is needed since IE likes to jump out of Enhanced Protected Mode fo r specific pages (bing.com) 203 // This is needed since IE likes to jump out of Enhanced Protected Mode fo r specific pages (bing.com)
204
205 // ATTENTION: DACL in the returned securityDescriptor has to be manually r eleased by ReleaseDacl
194 std::auto_ptr<SECURITY_DESCRIPTOR> securityDescriptor = CreateSecurityDesc riptor(logonSid.get()); 206 std::auto_ptr<SECURITY_DESCRIPTOR> securityDescriptor = CreateSecurityDesc riptor(logonSid.get());
207
195 securityAttributes.lpSecurityDescriptor = securityDescriptor.release(); 208 securityAttributes.lpSecurityDescriptor = securityDescriptor.release();
196 sharedSecurityDescriptor.reset(static_cast<SECURITY_DESCRIPTOR*>(securityA ttributes.lpSecurityDescriptor)); 209 sharedSecurityDescriptor.reset(static_cast<SECURITY_DESCRIPTOR*>(securityA ttributes.lpSecurityDescriptor));
197 } 210 }
198 pipe = CreateNamedPipeW(pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MES SAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 211 pipe = CreateNamedPipeW(pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MES SAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
199 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSize, 0, &securityAttributes); 212 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSize, 0, &securityAttributes);
213
214 if (IsWindowsVistaOrLater())
215 {
216 ReleaseDacl(securityAttributes.lpSecurityDescriptor);
Felix Dahlke 2014/07/03 13:38:07 Wouldn't it'd be cleaner to put this in a custom f
217 }
200 } 218 }
201 else 219 else
202 { 220 {
203 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPE N_EXISTING, 0, 0); 221 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPE N_EXISTING, 0, 0);
204 if (pipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) 222 if (pipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY)
205 { 223 {
206 if (!WaitNamedPipeW(pipeName.c_str(), 10000)) 224 if (!WaitNamedPipeW(pipeName.c_str(), 10000))
207 throw PipeBusyError(); 225 throw PipeBusyError();
208 226
209 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, O PEN_EXISTING, 0, 0); 227 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, O PEN_EXISTING, 0, 0);
210 } 228 }
211 } 229 }
212 230
213 if (pipe == INVALID_HANDLE_VALUE) 231 if (pipe == INVALID_HANDLE_VALUE)
214 throw PipeConnectionError(); 232 throw PipeConnectionError();
215 233
216 DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; 234 DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
217 if (!SetNamedPipeHandleState(pipe, &pipeMode, 0, 0)) 235 if (!SetNamedPipeHandleState(pipe, &pipeMode, 0, 0))
218 throw std::runtime_error("SetNamedPipeHandleState failed: error " + GetLastE rror()); 236 throw std::runtime_error(AppendErrorCode("SetNamedPipeHandleState failed"));
219 237
220 if (mode == MODE_CREATE && !ConnectNamedPipe(pipe, 0)) 238 if (mode == MODE_CREATE && !ConnectNamedPipe(pipe, 0))
221 { 239 {
222 DWORD err = GetLastError(); 240 DWORD err = GetLastError();
223 throw std::runtime_error("Client failed to connect: error " + GetLastError() ); 241 throw std::runtime_error(AppendErrorCode("Client failed to connect"));
224 } 242 }
225 } 243 }
226 244
227 Communication::Pipe::~Pipe() 245 Communication::Pipe::~Pipe()
228 { 246 {
229 CloseHandle(pipe); 247 CloseHandle(pipe);
230 } 248 }
231 249
232 Communication::InputBuffer Communication::Pipe::ReadMessage() 250 Communication::InputBuffer Communication::Pipe::ReadMessage()
233 { 251 {
(...skipping 25 matching lines...) Expand all
259 return Communication::InputBuffer(stream.str()); 277 return Communication::InputBuffer(stream.str());
260 } 278 }
261 279
262 void Communication::Pipe::WriteMessage(Communication::OutputBuffer& message) 280 void Communication::Pipe::WriteMessage(Communication::OutputBuffer& message)
263 { 281 {
264 DWORD bytesWritten; 282 DWORD bytesWritten;
265 std::string data = message.Get(); 283 std::string data = message.Get();
266 if (!WriteFile(pipe, data.c_str(), static_cast<DWORD>(data.length()), &bytesWr itten, 0)) 284 if (!WriteFile(pipe, data.c_str(), static_cast<DWORD>(data.length()), &bytesWr itten, 0))
267 throw std::runtime_error("Failed to write to pipe"); 285 throw std::runtime_error("Failed to write to pipe");
268 } 286 }
OLDNEW
« no previous file with comments | « no previous file | src/shared/Utils.cpp » ('j') | src/shared/Utils.cpp » ('J')

Powered by Google App Engine
This is Rietveld