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