From 8c79bbcff8e226374eceab5204de013e949f5211 Mon Sep 17 00:00:00 2001 From: Irek Fakhrutdinov Date: Mon, 3 Jun 2024 09:55:53 +0200 Subject: [PATCH] Add support for longer cross-memory server parameters This commit extends the config cross-memory service and cross-memory server's structures responsible for storing parameters to support parameter names and values longer than 72 and 128 characters respectively. Backward compatibility is provided by introducing and using a version field in the config service's parameter list. Fixes: zowe/zss#684 Signed-off-by: Irek Fakhrutdinov --- CHANGELOG.md | 2 + c/crossmemory.c | 193 +++++++++++++++++++++++++++++++++++++++++++----- h/crossmemory.h | 58 ++++++++++++++- 3 files changed, 235 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0c4b3cc..74d46a874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## `3.0.0` - Add support for LE 64-bit in isgenq.c (#422). +- Bugfix: support cross-memory server parameters longer than 128 characters + (zowe/zss#684) - Bugfix: IARV64 results must be checked for 0x7FFFF000 (#474) - Bugfix: SLH should not ABEND when MEMLIMIT is reached (additional NULL check) diff --git a/c/crossmemory.c b/c/crossmemory.c index d7f132f17..5ddc6199e 100644 --- a/c/crossmemory.c +++ b/c/crossmemory.c @@ -43,6 +43,8 @@ #include "utils.h" #include "zvt.h" +#define CMS_STATIC_ASSERT($expr) typedef char p[($expr) ? 1 : -1] + #define CROSS_MEMORY_SERVER_MIN_NAME_LENGTH 4 #define CROSS_MEMORY_SERVER_MAX_NAME_LENGTH 16 @@ -598,12 +600,32 @@ typedef struct CrossMemoryServerConfigServiceParm_tag { char eyecatcher[8]; #define CMS_CONFIG_SERVICE_PARM_EYECATCHER "RSCMSCSY" char nameNullTerm[CMS_CONFIG_PARM_MAX_NAME_LENGTH + 1]; - char padding[7]; - CrossMemoryServerConfigParm result; + uint8_t version; +#define CMS_CONFIG_SERVICE_PARM_VERSION_0 0 +#define CMS_CONFIG_SERVICE_PARM_VERSION_2 2 +#define CMS_CONFIG_SERVICE_PARM_SIZE_V0 227 +#define CMS_CONFIG_SERVICE_PARM_SIZE_V2 227 +#define CMS_CONFIG_SERVICE_PARM_VERSION CMS_CONFIG_SERVICE_PARM_VERSION_2 + char padding[6]; + union { + CrossMemoryServerConfigParm result; + struct { // only for versions >= 2 + int32_t nameLength; + int32_t valueBufferLength; + PAD_LONG(0, const char *name); + PAD_LONG(1, void *valueBuffer); + CrossMemoryServerConfigParmExt result; + } ext; + }; } CrossMemoryServerConfigServiceParm; ZOWE_PRAGMA_PACK_RESET +CMS_STATIC_ASSERT(CMS_CONFIG_SERVICE_PARM_SIZE_V0 == + sizeof(CrossMemoryServerConfigServiceParm)); +CMS_STATIC_ASSERT(CMS_CONFIG_SERVICE_PARM_SIZE_V2 == + sizeof(CrossMemoryServerConfigServiceParm)); + static void initLogMessagePrefix(LogMessagePrefix *prefix) { LogTimestamp currentTime; getCurrentLogTimestamp(¤tTime); @@ -984,7 +1006,7 @@ int cmsAddConfigParm(CrossMemoryServer *server, ShortLivedHeap *slh = server->slh; size_t keyLength = strlen(name); - if (keyLength > CMS_CONFIG_PARM_MAX_NAME_LENGTH) { + if (keyLength > CMS_CONFIG_PARM_EXT_MAX_NAME_LENGTH) { return RC_CMS_CONFIG_PARM_NAME_TOO_LONG; } @@ -995,16 +1017,17 @@ int cmsAddConfigParm(CrossMemoryServer *server, strcpy(keyNullTerm, name); - CrossMemoryServerConfigParm *parm = - (CrossMemoryServerConfigParm *)SLHAlloc( + CrossMemoryServerConfigParmExt *parm = + (CrossMemoryServerConfigParmExt *)SLHAlloc( slh, - sizeof(CrossMemoryServerConfigParm) + sizeof(CrossMemoryServerConfigParmExt) ); if (parm == NULL) { return RC_CMS_SLH_ALLOC_FAILED; } - memcpy(parm->eyecatcher, CMS_PARM_EYECATCHER, sizeof(parm->eyecatcher)); + memcpy(parm->eyecatcher, CMS_CONFIG_PARM_EXT_EYECATCHER, + sizeof(parm->eyecatcher)); parm->type = type; switch (type) { @@ -1012,11 +1035,15 @@ int cmsAddConfigParm(CrossMemoryServer *server, { const char *charValueNullTerm = value; size_t valueLength = strlen(charValueNullTerm); - if (valueLength > sizeof(parm->charValueNullTerm) - 1) { + if (valueLength > CMS_CONFIG_PARM_EXT_MAX_VALUE_SIZE) { return RC_CMS_CHAR_PARM_TOO_LONG; } parm->valueLength = valueLength; - strcpy(parm->charValueNullTerm, charValueNullTerm); + parm->value = SLHAlloc(slh, valueLength + 1); + if (parm->value == NULL) { + return RC_CMS_SLH_ALLOC_FAILED; + } + strcpy(parm->value, charValueNullTerm); } break; default: @@ -1784,6 +1811,9 @@ static int handleConfigService(CrossMemoryServer *server, return RC_CMS_STDSVC_PARM_NULL; } + // Copying different versions using the same size is fine because both v0 and + // v2 have the same size, but, if this changes in the future, more complicated + // logic would need to be implemented. CrossMemoryServerConfigServiceParm localParm; cmCopyFromSecondaryWithCallerKey(&localParm, callerParm, sizeof(CrossMemoryServerConfigServiceParm)); @@ -1793,16 +1823,58 @@ static int handleConfigService(CrossMemoryServer *server, return RC_CMS_STDSVC_PARM_BAD_EYECATCHER; } - localParm.nameNullTerm[sizeof(localParm.nameNullTerm) - 1] = '\0'; - - CrossMemoryServerConfigParm *configParm = - htGet(server->configParms, localParm.nameNullTerm); - if (configParm == NULL) { - return RC_CMS_CONFIG_PARM_NOT_FOUND; + if (localParm.version != CMS_CONFIG_SERVICE_PARM_VERSION_0 && + localParm.version != CMS_CONFIG_SERVICE_PARM_VERSION_2) { + return RC_CMS_STDSVC_PARM_BAD_VERSION; } - cmCopyToSecondaryWithCallerKey(&callerParm->result, configParm, - sizeof(callerParm->result)); + if (localParm.version == CMS_CONFIG_SERVICE_PARM_VERSION_0) { + localParm.nameNullTerm[sizeof(localParm.nameNullTerm) - 1] = '\0'; + CrossMemoryServerConfigParmExt *configParm = htGet(server->configParms, + localParm.nameNullTerm); + if (configParm == NULL) { + return RC_CMS_CONFIG_PARM_NOT_FOUND; + } + size_t valueCopyLength = configParm->type == CMS_CONFIG_PARM_TYPE_CHAR ? + configParm->valueLength + 1 : configParm->valueLength; + if (valueCopyLength > sizeof(localParm.result.charValueNullTerm)) { + return RC_CMS_CONFIG_VALUE_BUF_TOO_SMALL; + } + localParm.result = (CrossMemoryServerConfigParm) { + .eyecatcher = CMS_PARM_EYECATCHER, + .valueLength = configParm->valueLength, + .type = configParm->type, + }; + memcpy(localParm.result.charValueNullTerm, configParm->value, + valueCopyLength); + cmCopyToSecondaryWithCallerKey(callerParm, &localParm, + CMS_CONFIG_SERVICE_PARM_SIZE_V0); + } else { + char nameLocalBuffer[CMS_CONFIG_PARM_EXT_MAX_NAME_LENGTH + 1]; + if (localParm.ext.nameLength > sizeof(nameLocalBuffer) - 1) { + return RC_CMS_CONFIG_PARM_NAME_TOO_LONG; + } + cmCopyFromSecondaryWithCallerKey(nameLocalBuffer, localParm.ext.name, + localParm.ext.nameLength); + nameLocalBuffer[localParm.ext.nameLength] = '\0'; + CrossMemoryServerConfigParmExt *configParm = htGet(server->configParms, + nameLocalBuffer); + if (configParm == NULL) { + return RC_CMS_CONFIG_PARM_NOT_FOUND; + } + size_t valueCopyLength = configParm->type == CMS_CONFIG_PARM_TYPE_CHAR ? + configParm->valueLength + 1 : configParm->valueLength; + localParm.ext.result = *configParm; + localParm.ext.result.value = localParm.ext.valueBuffer; + cmCopyToSecondaryWithCallerKey(callerParm, &localParm, + CMS_CONFIG_SERVICE_PARM_SIZE_V2); + if (valueCopyLength > localParm.ext.valueBufferLength) { + return RC_CMS_CONFIG_VALUE_BUF_TOO_SMALL; + } + cmCopyToSecondaryWithCallerKey(localParm.ext.valueBuffer, + configParm->value, + valueCopyLength); + } return RC_CMS_OK; } @@ -5335,6 +5407,7 @@ int cmsGetConfigParm(const CrossMemoryServerName *serverName, const char *name, memcpy(parmList.eyecatcher, CMS_CONFIG_SERVICE_PARM_EYECATCHER, sizeof(parmList.eyecatcher)); memcpy(parmList.nameNullTerm, name, nameLength); + parmList.version = CMS_CONFIG_SERVICE_PARM_VERSION_0; int serviceRC = cmsCallService( serverName, @@ -5364,6 +5437,7 @@ int cmsGetConfigParmUnchecked(const CrossMemoryServerName *serverName, memcpy(parmList.eyecatcher, CMS_CONFIG_SERVICE_PARM_EYECATCHER, sizeof(parmList.eyecatcher)); memcpy(parmList.nameNullTerm, name, nameLength); + parmList.version = CMS_CONFIG_SERVICE_PARM_VERSION_0; CrossMemoryServerGlobalArea *cmsGA = NULL; int getGlobalAreaRC = cmsGetGlobalArea(serverName, &cmsGA); @@ -5387,6 +5461,91 @@ int cmsGetConfigParmUnchecked(const CrossMemoryServerName *serverName, return RC_CMS_OK; } +int cmsGetConfigParmExt(const CrossMemoryServerName *serverName, + const char *name, + void *valueBuffer, + int valueBufferSize, + CrossMemoryServerConfigParmExt *parm, + int *rsn) { + + size_t nameLength = strlen(name); + if (nameLength > CMS_CONFIG_PARM_EXT_MAX_NAME_LENGTH) { + return RC_CMS_CONFIG_PARM_NAME_TOO_LONG; + } + + CrossMemoryServerConfigServiceParm parmList = { + .eyecatcher = CMS_CONFIG_SERVICE_PARM_EYECATCHER, + .version = CMS_CONFIG_SERVICE_PARM_VERSION, + .ext.nameLength = nameLength, + .ext.name = name, + .ext.valueBufferLength = valueBufferSize, + .ext.valueBuffer = valueBuffer, + }; + + int serviceRC = cmsCallService( + serverName, + CROSS_MEMORY_SERVER_CONFIG_SERVICE_ID, + &parmList, + rsn + ); + if (serviceRC != RC_CMS_OK) { + if (serviceRC == RC_CMS_CONFIG_VALUE_BUF_TOO_SMALL) { + *parm = parmList.ext.result; + } + return serviceRC; + } + + *parm = parmList.ext.result; + + return RC_CMS_OK; +} + +int cmsGetConfigParmExtUnchecked(const CrossMemoryServerName *serverName, + const char *name, + void *valueBuffer, + int valueBufferSize, + CrossMemoryServerConfigParmExt *parm, + int *rsn) { + + size_t nameLength = strlen(name); + if (nameLength > CMS_CONFIG_PARM_EXT_MAX_NAME_LENGTH) { + return RC_CMS_CONFIG_PARM_NAME_TOO_LONG; + } + + CrossMemoryServerConfigServiceParm parmList = { + .eyecatcher = CMS_CONFIG_SERVICE_PARM_EYECATCHER, + .version = CMS_CONFIG_SERVICE_PARM_VERSION, + .ext.nameLength = nameLength, + .ext.name = name, + .ext.valueBufferLength = valueBufferSize, + .ext.valueBuffer = valueBuffer, + }; + + CrossMemoryServerGlobalArea *cmsGA = NULL; + int getGlobalAreaRC = cmsGetGlobalArea(serverName, &cmsGA); + if (getGlobalAreaRC != RC_CMS_OK) { + return getGlobalAreaRC; + } + + int serviceRC = cmsCallService3( + cmsGA, + CROSS_MEMORY_SERVER_CONFIG_SERVICE_ID, + &parmList, + CMS_CALL_FLAG_NO_SAF_CHECK, + rsn + ); + if (serviceRC != RC_CMS_OK) { + if (serviceRC == RC_CMS_CONFIG_VALUE_BUF_TOO_SMALL) { + *parm = parmList.ext.result; + } + return serviceRC; + } + + *parm = parmList.ext.result; + + return RC_CMS_OK; +} + int cmsGetPCLogLevel(const CrossMemoryServerName *serverName) { int logLevel = ZOWE_LOG_NA; diff --git a/h/crossmemory.h b/h/crossmemory.h index 6fe0bad9e..aa4c14637 100644 --- a/h/crossmemory.h +++ b/h/crossmemory.h @@ -142,7 +142,9 @@ #define RC_CMS_NO_ROOM_FOR_CMS_GETTER 91 #define RC_CMS_LANC_NOT_LOCKED 92 #define RC_CMS_LANC_NOT_RELEASED 93 -#define RC_CMS_MAX_RC 93 +#define RC_CMS_STDSVC_PARM_BAD_VERSION 94 +#define RC_CMS_CONFIG_VALUE_BUF_TOO_SMALL 95 +#define RC_CMS_MAX_RC 95 extern const char *CMS_RC_DESCRIPTION[]; @@ -377,9 +379,11 @@ typedef struct CrossMemoryServerParmList_tag { PAD_LONG(1, void *callerData); } CrossMemoryServerParmList; +#pragma enum(1) typedef enum CrossMemoryServerParmType_tag { CMS_CONFIG_PARM_TYPE_CHAR } CrossMemoryServerParmType; +#pragma enum(reset) #define CMS_CONFIG_PARM_MAX_NAME_LENGTH 72 #define CMS_CONFIG_PARM_MAX_VALUE_SIZE 128 @@ -394,6 +398,19 @@ typedef struct CrossMemoryServerConfigParm_tag { }; } CrossMemoryServerConfigParm; +typedef struct CrossMemoryServerConfigParmExt_tag { + char eyecatcher[8]; +#define CMS_CONFIG_PARM_EXT_EYECATCHER "RSCMSCFX" + uint8_t version; +#define CMS_CONFIG_PARM_EXT_VERSION 1 + CrossMemoryServerParmType type; + char padding0[2]; +#define CMS_CONFIG_PARM_EXT_MAX_NAME_LENGTH 1024 +#define CMS_CONFIG_PARM_EXT_MAX_VALUE_SIZE INT32_MAX + int32_t valueLength; + PAD_LONG(0, void *value); +} CrossMemoryServerConfigParmExt; + typedef struct CrossMemoryServerStatus_tag { int cmsRC; char descriptionNullTerm[64]; @@ -424,6 +441,8 @@ ZOWE_PRAGMA_PACK_RESET #define cmsHexDump CMHEXDMP #define cmsGetConfigParm CMGETPRM #define cmsGetConfigParmUnchecked CMGETPRU +#define cmsGetConfigParmExt CMGETPRX +#define cmsGetConfigParmExtUnchecked CMGETPUX #define cmsGetPCLogLevel CMGETLOG #define cmsGetStatus CMGETSTS #define cmsMakeServerName CMMKSNAM @@ -559,6 +578,43 @@ int cmsGetConfigParm(const CrossMemoryServerName *serverName, const char *name, int cmsGetConfigParmUnchecked(const CrossMemoryServerName *serverName, const char *name, CrossMemoryServerConfigParm *parm); +/** + * @brief Get a parameter from the cross-memory server's PARMLIB + * @param[in] serverName Cross-memory server whose parameter is to be read + * @param[in] name Name of the parameter + * @param[out] valueBuffer Buffer for the result value + * @param[out] valueBufferSize Size of the value buffer + * @param[out] parm Result parameter entry + * @param[out] rsn Reason code provided by the service in case of a failure + * @return RC_CMS_OK in case of success, and one of the RC_CMS_nn values in + * case of failure + */ +int cmsGetConfigParmExt(const CrossMemoryServerName *serverName, + const char *name, + void *valueBuffer, + int valueBufferSize, + CrossMemoryServerConfigParmExt *parm, + int *rsn); + + +/** + * @brief Get a parameter from the cross-memory server's PARMLIB without the + * authorization check (the caller must be SUP or system key) + * @param[in] serverName Cross-memory server whose parameter is to be read + * @param[in] name Name of the parameter + * @param[out] valueBuffer Buffer for the result value + * @param[out] valueBufferSize Size of the value buffer + * @param[out] parm Result parameter entry + * @param[out] rsn Reason code provided by the service in case of a failure + * @return RC_CMS_OK in case of success, and one of the RC_CMS_nn values in + * case of failure + */ +int cmsGetConfigParmExtUnchecked(const CrossMemoryServerName *serverName, + const char *name, + void *valueBuffer, + int valueBufferSize, + CrossMemoryServerConfigParmExt *parm, + int *rsn); int cmsGetPCLogLevel(const CrossMemoryServerName *serverName); CrossMemoryServerStatus cmsGetStatus(const CrossMemoryServerName *serverName);