diff --git hadoop-common-project/hadoop-common/src/main/winutils/service.c hadoop-common-project/hadoop-common/src/main/winutils/service.c index 37b8628..8d328b4 100644 --- hadoop-common-project/hadoop-common/src/main/winutils/service.c +++ hadoop-common-project/hadoop-common/src/main/winutils/service.c @@ -30,6 +30,7 @@ #pragma comment(lib, "authz.lib") LPCWSTR NM_WSCE_ALLOWED = L"yarn.nodemanager.windows-secure-container-executor.allowed"; +LPCWSTR NM_WSCE_LOCAL_DIRS = L"yarn.nodemanager.windows-secure-container-executor.local-dirs"; #define SERVICE_ACCESS_MASK 0x00000001 @@ -40,6 +41,9 @@ HANDLE ghWaitObject = INVALID_HANDLE_VALUE; HANDLE ghEventLog = INVALID_HANDLE_VALUE; BOOL isListenning = FALSE; PSECURITY_DESCRIPTOR pAllowedSD = NULL; +LPWSTR* gLocalDirs = NULL; +size_t gLocalDirsCount = 0; +int* gCchLocalDir = NULL; VOID SvcError(DWORD dwError); VOID WINAPI SvcMain(DWORD dwArg, LPTSTR* lpszArgv); @@ -78,13 +82,12 @@ VOID CALLBACK SvcShutdown( if (RPC_S_OK != unwindStatus) { \ ReportSvcCheckError( \ EVENTLOG_WARNING_TYPE, \ - SERVICE_CATEGORY, \ + SERVICE_CATEGORY, \ unwindStatus, \ L#rpcCall); \ } \ } - //---------------------------------------------------------------------------- // Function: ReportSvcCheckError // @@ -166,6 +169,126 @@ VOID ReportSvcMessage(WORD type, WORD category, DWORD msgId) { } } +//---------------------------------------------------------------------------- +// Function: InitLocalDirs +// +// Description: +// Loads the configured local dirs +// +DWORD InitLocalDirs() { + DWORD dwError = ERROR_SUCCESS; + size_t len = 0; + LPCWSTR value = NULL; + int crt = 0; + + + dwError = GetConfigValue( + wsceConfigRelativePath, + NM_WSCE_LOCAL_DIRS, &len, &value); + CHECK_SVC_STATUS_DONE(dwError, L"GetConfigValue"); + + if (0 == len) { + dwError = ERROR_BAD_CONFIGURATION; + CHECK_SVC_STATUS_DONE(dwError, NM_WSCE_LOCAL_DIRS); + } + + dwError = SplitStringIgnoreSpaceW(len, value, L',', &gLocalDirsCount, &gLocalDirs); + CHECK_SVC_STATUS_DONE(dwError, L"SplitStringIgnoreSpaceW"); + + if (0 == gLocalDirsCount) { + dwError = ERROR_BAD_CONFIGURATION; + CHECK_SVC_STATUS_DONE(dwError, NM_WSCE_LOCAL_DIRS); + } + + gCchLocalDir = (int*) LocalAlloc(LPTR, sizeof(int) * gLocalDirsCount); + if (NULL == gCchLocalDir) { + dwError = ERROR_OUTOFMEMORY; + CHECK_SVC_STATUS_DONE(dwError, L"LocalAlloc"); + } + + for (crt = 0; crt < gLocalDirsCount; ++crt) { + gCchLocalDir[crt] = (int) wcsnlen(gLocalDirs[crt], MAX_PATH); + } + +done: + if (value) LocalFree(value); + + return dwError; +} + +//---------------------------------------------------------------------------- +// Function: ValidateLocalPath +// +// Description: +// Validates that a path is within the contained local dirs +// +DWORD ValidateLocalPath(LPCWSTR lpszPath) { + DWORD dwError = ERROR_SUCCESS; + int compareResult = 0; + int crt = 0; + int cchLocalBuffer = 0; + WCHAR localBuffer[MAX_PATH+1]; + BOOLEAN nullFound = FALSE; + + // Make a copy of the path and replace / with \ in the process + while(crt < MAX_PATH && !nullFound) { + switch(lpszPath[crt]) { + case L'/': + localBuffer[crt] = L'\\'; + ++crt; + break; + case L'\0': + // NULL terminator + nullFound = TRUE; + break; + default: + localBuffer[crt] = lpszPath[crt]; + ++crt; + break; + } + } + + if (FALSE == nullFound) { + dwError = ERROR_BUFFER_OVERFLOW; + CHECK_SVC_STATUS_DONE(dwError, L"localBuffer"); + } + + localBuffer[crt] = 0; + cchLocalBuffer = crt; + + for(crt = 0; crt < gLocalDirsCount; ++crt) { + + // use max len gCchLocalDir[crt] to see if it starts with this local dir + compareResult = CompareStringEx( + LOCALE_NAME_INVARIANT, + NORM_IGNORECASE, + localBuffer, gCchLocalDir[crt] <= cchLocalBuffer ? gCchLocalDir[crt] : cchLocalBuffer, + gLocalDirs[crt], gCchLocalDir[crt], + NULL, // lpVersionInformation + NULL, // lpReserved + NULL); // lParam + LogDebugMessage(L"VLP: %s %s %d\n", localBuffer, gLocalDirs[crt], compareResult); + + if (0 == compareResult) { + dwError = GetLastError(); + CHECK_SVC_STATUS_DONE(dwError, L"CompareStringEx"); + } + if (CSTR_EQUAL == compareResult) { + LogDebugMessage(L"ValidateLocalPath success: %s -> %s\n", localBuffer, gLocalDirs[crt]); + break; + } + } + + if (CSTR_EQUAL != compareResult) { + LogDebugMessage(L"ValidateLocalPath bad path: %s\n", lpszPath); + dwError = ERROR_BAD_PATHNAME; + } + +done: + return dwError; +} + + //---------------------------------------------------------------------------- // Function: RunService @@ -186,12 +309,6 @@ DWORD RunService(__in int argc, __in_ecount(argc) wchar_t *argv[]) { NULL, NULL } }; - dwError = AuthInit(); - if (ERROR_SUCCESS != dwError) { - SvcError(dwError); - goto done; - } - ghEventLog = RegisterEventSource(NULL, SVCNAME); if (NULL == ghEventLog) { dwError = GetLastError(); @@ -284,6 +401,20 @@ DWORD SvcInit() { goto done; } + dwError = AuthInit(); + if (ERROR_SUCCESS != dwError) { + LogDebugMessage(L"AuthInit failed: %d", dwError); + SvcError(dwError); + goto done; + } + + dwError = InitLocalDirs(); + if (ERROR_SUCCESS != dwError) { + LogDebugMessage(L"InitLocalDirs failed: %d", dwError); + SvcError(dwError); + goto done; + } + // Report running status when initialization is complete. ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 ); @@ -395,13 +526,19 @@ DWORD AuthInit() { CHECK_SVC_STATUS_DONE(dwError, L"GetConfigValue"); if (0 == len) { - CHECK_SVC_STATUS_DONE(ERROR_BAD_CONFIGURATION, NM_WSCE_ALLOWED); + dwError = ERROR_BAD_CONFIGURATION; + CHECK_SVC_STATUS_DONE(dwError, NM_WSCE_ALLOWED); } dwError = SplitStringIgnoreSpaceW(len, value, L',', &count, &tokens); CHECK_SVC_STATUS_DONE(dwError, L"SplitStringIgnoreSpaceW"); allowedSids = (PSID*) LocalAlloc(LPTR, sizeof(PSID) * count); + if (NULL == allowedSids) { + dwError = ERROR_OUTOFMEMORY; + CHECK_SVC_STATUS_DONE(dwError, L"LocalAlloc"); + } + for (crt = 0; crt < count; ++crt) { dwError = GetSidFromAcctNameW(tokens[crt], &allowedSids[crt]); CHECK_SVC_STATUS_DONE(dwError, L"GetSidFromAcctNameW"); @@ -882,6 +1019,9 @@ error_status_t WinutilsCreateFile( ZeroMemory( &saFile, sizeof(saFile)); + dwError = ValidateLocalPath(request->path); + CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->path"); + saFile.nLength = sizeof(SECURITY_ATTRIBUTES); saFile.bInheritHandle = TRUE; saFile.lpSecurityDescriptor = NULL; @@ -944,11 +1084,16 @@ error_status_t WinutilsMkDir( /* [in] */ handle_t IDL_handle, /* [in] */ MKDIR_REQUEST *request) { DWORD dwError = ERROR_SUCCESS; + + dwError = ValidateLocalPath(request->filePath); + CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->filePath"); + if (!CreateDirectory(request->filePath, NULL)) { dwError = GetLastError(); - ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY, - dwError, L"CreateDirectory"); + CHECK_SVC_STATUS_DONE(dwError, L"CreateDirectory"); } + +done: LogDebugMessage(L"WinutilsMkDir: %s :%d\n", request->filePath, dwError); return dwError; } @@ -957,11 +1102,14 @@ error_status_t WinutilsChown( /* [in] */ handle_t IDL_handle, /* [in] */ CHOWN_REQUEST *request) { DWORD dwError = ERROR_SUCCESS; + + dwError = ValidateLocalPath(request->filePath); + CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->filePath"); + dwError = ChownImpl(request->ownerName, request->groupName, request->filePath); - if (dwError) { - ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY, - dwError, L"ChownImpl"); - } + CHECK_SVC_STATUS_DONE(dwError, L"ChownImpl"); + +done: LogDebugMessage(L"WinutilsChown: %s %s %s :%d\n", request->ownerName, request->groupName, request->filePath, dwError); return dwError; @@ -971,11 +1119,14 @@ error_status_t WinutilsChmod( /* [in] */ handle_t IDL_handle, /* [in] */ CHMOD_REQUEST *request) { DWORD dwError = ERROR_SUCCESS; + + dwError = ValidateLocalPath(request->filePath); + CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->filePath"); + dwError = ChangeFileModeByMask(request->filePath, request->mode); - if (dwError) { - ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY, - dwError, L"ChangeFileModeByMask"); - } + CHECK_SVC_STATUS_DONE(dwError, L"ChangeFileModeByMask"); + +done: LogDebugMessage(L"WinutilsChmod: %s %o :%d\n", request->filePath, request->mode, dwError); return dwError; @@ -987,14 +1138,19 @@ error_status_t WinutilsMoveFile( DWORD dwError = ERROR_SUCCESS; DWORD flags = 0; + dwError = ValidateLocalPath(request->sourcePath); + CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->sourcePath"); + + dwError = ValidateLocalPath(request->destinationPath); + CHECK_SVC_STATUS_DONE(dwError,L"ValidateLocalPath request->destinationPath"); + switch (request->operation) { case MOVE_FILE: flags |= MOVEFILE_COPY_ALLOWED; if (request->replaceExisting) flags |= MOVEFILE_REPLACE_EXISTING; if (!MoveFileEx(request->sourcePath, request->destinationPath, flags)) { dwError = GetLastError(); - ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY, - dwError, L"MoveFileEx"); + CHECK_SVC_STATUS_DONE(dwError, L"MoveFileEx"); } break; case COPY_FILE: @@ -1005,10 +1161,11 @@ error_status_t WinutilsMoveFile( NULL, // pbCancel flags)) { dwError = GetLastError(); - ReportSvcCheckError(EVENTLOG_ERROR_TYPE, SERVICE_CATEGORY, - dwError, L"CopyFileEx"); + CHECK_SVC_STATUS_DONE(dwError, L"CopyFileEx"); } } + +done: LogDebugMessage(L"WinutilsMoveFile: %d: %s %s :%d\n", request->operation, request->sourcePath, request->destinationPath, dwError); return dwError; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm index 50ff345..b44c2b9 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/SecureContainer.apt.vm @@ -128,6 +128,12 @@ min.user.id=1000#Prevent other super-users yarn.nodemanager.windows-secure-container-executor.allowed nodemanager + + + yarn.nodemanager.windows-secure-container-executor.local-dirs + nm-local-dir, nm-log-dirs + + +---+ <<>> should contain the name of the service account running the @@ -138,6 +144,12 @@ min.user.id=1000#Prevent other super-users <<>> should contain users that are explictly forbiden from creating containers. hadoopwinutilsvc will refuse to impersonate these users. + + <<>> should contain the nodemanager local dirs. hadoopwinutilsvc will + allow only file operations under these directories. This should contain the same values as <<<${yarn.nodemanager.local-dirs}, ${yarn.nodemanager.log-dirs}>>> + but note that hadoopwinutilsvc XML configuration processing does not do substitutions so the value must be the final value. All paths + must be absolute and no environment variable substitution will be performed. The paths are compared LOCAL_INVARIANT case insensitive string comparison, + the file path validated must start with one of the paths listed in local-dirs configuration. Use comma as path separator:<<<,>>> *** Useful Links