From 2a4cb0f4d4de732ec10b4e7729c24b4c4fc41e2c Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Thu, 26 Sep 2013 11:30:54 +0300 Subject: [PATCH] Security plugin: plugin hooks code refactoring and improvment Change-Id: I4d44db47865dd5c83fcf28435ffc26a70164b69d --- plugins/msm-plugin.c | 514 ++++++++++++++++++-------------------------------- plugins/msm.h | 46 ++++- plugins/msmconfig.c | 139 ++++++++++++++ plugins/msmmanifest.c | 38 +++- plugins/msmxattr.c | 4 +- 5 files changed, 400 insertions(+), 341 deletions(-) diff --git a/plugins/msm-plugin.c b/plugins/msm-plugin.c index 569f9a2..2290ac2 100644 --- a/plugins/msm-plugin.c +++ b/plugins/msm-plugin.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -77,165 +76,179 @@ typedef struct packagecontext { struct smack_accesses *smack_accesses; /*!< handle to smack_accesses */ } packagecontext; -static rpmts ts = NULL; -static int rootSWSource= 0; -static manifest_x *root = NULL; /* pointer to device security policy file */ +static rpmts ts = NULL; /* rpm transaction */ +static manifest_x *dsp = NULL; /* pointer to device security policy file */ static packagecontext *context = NULL; static sw_source_x *current = NULL; static packagecontext *contextsHead = NULL; static packagecontext *contextsTail = NULL; static fileconflict *allfileconflicts = NULL; -static char* ownSmackLabel = NULL; -static int SmackEnabled = 0; +static char* ownSmackLabel = NULL; /* rpm smack security context */ +static int SmackEnabled = 0; /* indicates if Smack is enabled in kernel or not */ static magic_t cookie = NULL; static int package_created = 0; -static int copyFile(char *old_filename, char *new_filename) +/* Support functions */ + +/** + * Frees the given pointer and sets it to NULL + * @param ptr address of pointer to be freed + * @return NULL + */ +static packagecontext *msmFree(packagecontext *ctx) +{ + while (ctx) { + packagecontext *next = ctx->next; + msmFreePointer((void**)&ctx->data); + ctx->mfx = msmFreeManifestXml(ctx->mfx); + if (ctx->smack_accesses) smack_accesses_free(ctx->smack_accesses); + msmFreePointer((void**)&ctx); + ctx = next; + } + return NULL; +} + +/** + * Frees the given pointer and sets it to NULL + * @param ptr address of pointer to be freed + * @return + */ +void msmFreePointer(void** ptr) { - FD_t ptr_old, ptr_new; - int res; + if (*ptr) + free(*ptr); + *ptr = NULL; + return; +} + +/** + * Creates a new package context + * @param te rpm te struct + * @return created package context + */ +static packagecontext *msmNew(rpmte te) +{ + Header h; + struct rpmtd_s msm; + int count; + packagecontext *ctx = NULL; + const char *sw_source = NULL; + + rpmtdReset(&msm); + + h = rpmteHeader(te); + if (!h) return NULL; + + ctx = xcalloc(1, sizeof(*ctx)); + if (!ctx) { + goto exit1; + } + ctx->te = te; - ptr_old = Fopen(old_filename, "r.fdio"); - ptr_new = Fopen(new_filename, "w.fdio"); + if (!headerIsEntry(h, RPMTAG_SECMANIFEST)) { + goto exit1; + } - if ((ptr_old == NULL) || (Ferror(ptr_old))) { - return -1; + if (!headerGet(h, RPMTAG_SECMANIFEST, &msm, HEADERGET_MINMEM)) { + goto exit1; } - if ((ptr_new == NULL) || (Ferror(ptr_new))) { - Fclose(ptr_old); - return -1; + count = rpmtdCount(&msm); + if (count != 1) { + goto exit2; + } + + ctx->data = xstrdup(rpmtdNextString(&msm)); + rpmlog(RPMLOG_DEBUG, "%s manifest b64 data: %.40s...\n", + rpmteN(ctx->te), ctx->data); + exit2: + rpmtdFreeData(&msm); + exit1: + if (rpmteType(ctx->te) == TR_ADDED) { + /* Save sw_source name into database, we need it when package */ + /* is removed because signature verify is not called then. */ + if (current) sw_source = current->name; + if (!sw_source || !headerPutString(h, RPMTAG_SECSWSOURCE, sw_source)) { + rpmlog(RPMLOG_ERR, "Failed to save sw source for %s, sw_source: %s\n", + rpmteN(ctx->te), sw_source); + msmFreePointer((void**)&ctx->data); + msmFreePointer((void**)&ctx); + } } + headerFree(h); - res = ufdCopy(ptr_old, ptr_new); + return ctx; +} - Fclose(ptr_new); - Fclose(ptr_old); - return res; +/** + * Creates and adds a te package context to a context list + * @param te rpm te struct + * @return created and added package context + */ +static packagecontext *msmAddTE(rpmte te) +{ + packagecontext *ctx = msmNew(te); + if (ctx) { + /* add the new policy to the list */ + if (!contextsHead) { + contextsHead = ctx; + contextsTail = ctx; + } else { + if (rpmteType(te) == TR_ADDED) { + /* add to the end of the list */ + contextsTail->next = ctx; + contextsTail = ctx; + } else { + /* add to the beginning of the list */ + ctx->next = contextsHead; + contextsHead = ctx; + } + } + } + return ctx; } +/* -------------------- */ + +/* Implementation of hooks */ +/* Hooks are listed in the call sequence inside rpm code */ + rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *name, const char *opts) { ts = _ts; - char *fullPath = NULL, *fullPath1 = NULL; - char *defaultPolicyPath = NULL; - struct stat buf; if (!ts) return RPMRC_FAIL; - fullPath = rpmGenPath(ts->rootDir, DEVICE_SECURITY_POLICY, NULL); - rpmlog(RPMLOG_DEBUG, "fullPath %s\n", fullPath); - if (!fullPath) { - rpmlog(RPMLOG_ERR, "Building a full path failed for device security policy\n"); - goto plugin_error; - } + if (msmLoadDeviceSecurityPolicy(ts->rootDir, &dsp) == RPMRC_FAIL) + return RPMRC_FAIL; - if (stat(fullPath, &buf) != 0) { // the policy file is missing - if (ts->rootDir) { // we are running with --root option and policy is missing, need to copy it for now - // first create prefix for it - char *sysconfdir = rpmExpand("%{?_sysconfdir}", NULL); - if (!sysconfdir || !strcmp(sysconfdir, "")) { - rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n"); - goto plugin_error; - } - fullPath1 = rpmGenPath(ts->rootDir, sysconfdir, NULL); - rpmlog(RPMLOG_DEBUG, "fullPath1 %s\n", fullPath1); - msmFreePointer((void**)&sysconfdir); - if (!fullPath1) { - rpmlog(RPMLOG_ERR, "Building a full path for sysconfdir failed\n"); - goto plugin_error; - } - if (rpmioMkpath(fullPath1, 0755, getuid(), getgid()) != 0) { - rpmlog(RPMLOG_ERR, "Failed to create a path for policy file\n"); - goto plugin_error; - } - defaultPolicyPath = rpmExpand("%{?__transaction_msm_default_policy}", NULL); - if (!defaultPolicyPath || !strcmp(defaultPolicyPath, "")) { - rpmlog(RPMLOG_ERR, "Failed to expand transaction_msm_default_policy macro\n"); - goto plugin_error; - } - if(copyFile(defaultPolicyPath, fullPath) == -1) { - /* Do not allow plug-in to proceed without security policy existing */ - rpmlog(RPMLOG_ERR, "Failed to copy the policy outside of chroot. Abort installation.\n"); - goto plugin_error; - } - } else { - /* Do not allow plug-in to proceed without security policy existing */ - rpmlog(RPMLOG_ERR, "Policy file is missing at %s. Abort installation.\n", - fullPath); - goto plugin_error; - } - } + if (!dsp) + return RPMRC_FAIL; - rpmlog(RPMLOG_DEBUG, "reading device security policy from %s\n", fullPath); - root = msmProcessDevSecPolicyXml(fullPath); + /* smackfs path doesn't need to be prefixed with ts->rootDir + since it is only used for loading rules to kernel and libsmack will load it + by itself to the correct path */ - if (!root) { - rpmlog(RPMLOG_ERR, "Failed process sw sources from %s\n", fullPath); - goto plugin_error; + if (smack_smackfs_path() == NULL) { + rpmlog(RPMLOG_INFO, "Smackfs isn't mounted at %s. Going to the image build mode. \n", smack_smackfs_path()); + ownSmackLabel = strdup("_"); + SmackEnabled = 0; } else { - if (msmSetupSWSources(NULL, root, NULL)) { - rpmlog(RPMLOG_ERR, "Failed to setup security policy from %s\n",fullPath); - goto plugin_error; - } - } - - msmFreePointer((void**)&fullPath); - msmFreePointer((void**)&fullPath1); - msmFreePointer((void**)&defaultPolicyPath); - - fullPath = rpmGenPath(ts->rootDir, SMACK_LOAD_PATH, NULL); - rpmlog(RPMLOG_DEBUG, "fullPath for SMACK_LOAD_PATH %s\n", fullPath); - if (!fullPath) { - rpmlog(RPMLOG_ERR, "Building a full path for smack load failed\n"); - goto plugin_error; - } - - /* check its own security context and store it for the case when packages without manifest will be installed */ - if (stat(fullPath, &buf) == 0) { + /* check its own security context and store it for the case when packages without manifest will be installed */ int res = smack_new_label_from_self(&ownSmackLabel); SmackEnabled = 1; if (res < 0) { rpmlog(RPMLOG_ERR, "Failed to obtain rpm security context\n"); - goto plugin_error; - } - } else { - rpmlog(RPMLOG_INFO, "Smackfs isn't mounted at %s. Going to the image build mode. \n", fullPath); - ownSmackLabel = strdup("_"); - SmackEnabled = 0; - } - - msmFreePointer((void**)&fullPath); - fullPath = rpmGenPath(ts->rootDir, SMACK_RULES_PATH, NULL); - fullPath1 = rpmGenPath(ts->rootDir, SMACK_RULES_PATH_BEG, NULL); - rpmlog(RPMLOG_DEBUG, "fullPath for SMACK_RULES_PATH %s\n", fullPath); - rpmlog(RPMLOG_DEBUG, "fullPath1 for SMACK_RULES_PATH_BEG %s\n", fullPath1); - if ((!fullPath) || (!fullPath1)){ - rpmlog(RPMLOG_ERR, "Building a full path failed for smack rules path\n"); - goto plugin_error; - } - - if (stat(fullPath, &buf) != 0) { - rpmlog(RPMLOG_DEBUG, "A directory for writing smack rules is missing. Creating one.\n"); - mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH; // 644 -rwer--r-- - if (stat(fullPath1, &buf) != 0) { - if (mkdir(fullPath1, mode) != 0) { - rpmlog(RPMLOG_ERR, "Failed to create a sub-directory for smack rules\n"); - goto plugin_error; - } + return RPMRC_FAIL; } - if (mkdir(fullPath, mode) != 0){ - rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n"); - goto plugin_error; - } } - msmFreePointer((void**)&fullPath); - msmFreePointer((void**)&fullPath1); - rpmlog(RPMLOG_DEBUG, "rpm security context: %s\n", ownSmackLabel); + if (msmSetupSmackRulesDir(ts->rootDir) == RPMRC_FAIL) + return RPMRC_FAIL; + cookie = magic_open(0); if (!cookie) return RPMRC_FAIL; @@ -248,18 +261,6 @@ rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *name, const char *opts) } return RPMRC_OK; - -plugin_error: - msmFreePointer((void**)&fullPath); - msmFreePointer((void**)&fullPath1); - msmFreePointer((void**)&defaultPolicyPath); - return RPMRC_FAIL; -} - -static int findSWSourceByName(sw_source_x *sw_source, void *param, void* param2) -{ - const char *name = (const char *)param; - return strcmp(sw_source->name, name); } rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path, @@ -267,18 +268,23 @@ rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path, int rpmrc) { fileconflict *fc; - if (!path) + if ((!path) || (!dsp)) return rpmrc; - rpmlog(RPMLOG_DEBUG, "FILE_CONFLICT_FUNC hook path %s\n",path); + rpmlog(RPMLOG_DEBUG, "FILE_CONFLICT_FUNC hook path %s\n",path); + + /* uncomment this code if you wish that plugin obeys --replacefiles rpm flag + if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) { + return rpmrc; + } */ - const char *name = headerGetString(oldHeader, RPMTAG_SECSWSOURCE); + const char *sw_source_name = headerGetString(oldHeader, RPMTAG_SECSWSOURCE); const char *pkg_name = headerGetString(oldHeader, RPMTAG_NAME); - if (!name || !root || !pkg_name) { - return rpmrc; /* no sw source(s) or package name - abnormal state */ + if (!sw_source_name || !pkg_name) { + return rpmrc; /* no sw source or package name - abnormal state */ } - sw_source_x *sw_source = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL); + sw_source_x *sw_source = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)sw_source_name, NULL); if (!sw_source) return rpmrc; /* no old sw_source - abnormal state */ @@ -301,77 +307,25 @@ rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path, msmFreePointer((void**)&path); } - if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) { - /* Conflict has been noted, now return ok. It will be actually */ - /* resolved later when conflicting package signature is verified */ - /* and sw_source is known. */ - return rpmrc; - } return rpmrc; } rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts) { - if (!root) { - rpmlog(RPMLOG_DEBUG, "Policy is missing. Ending transaction\n"); + if (!dsp) { + rpmlog(RPMLOG_ERR, "Device security policy is missing. Unable to proceed\n"); return RPMRC_FAIL; } return RPMRC_OK; } -static int findSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2) -{ - origin_x *origin; - keyinfo_x *keyinfo; - pgpDigParams sig = (pgpDigParams)param; - DIGEST_CTX ctx = (DIGEST_CTX)param2; - pgpDigParams key = NULL; - - for (origin = sw_source->origins; origin; origin = origin->prev) { - for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) { - if (pgpPrtParams(keyinfo->keydata, keyinfo->keylen, PGPTAG_PUBLIC_KEY, &key)) { - rpmlog(RPMLOG_ERR, "invalid sw source key\n"); - return -1; - } - if (pgpVerifySignature(key, sig, ctx) == RPMRC_OK) { - return 0; - } - } - } - return 1; -} - rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, DIGEST_CTX ctx, int rpmrc) { current = NULL; -#if 0 - if (!root) { - if (rpmrc == RPMRC_NOKEY) { - rpmlog(RPMLOG_INFO, "package verified as root sw source\n"); - rootSWSource = 1; /* accept any signed package as root */ - return RPMRC_OK; - } - rpmlog(RPMLOG_ERR, "No device security policy, cannot verify signature\n"); - return rpmrc; - } - - // make currently that even non-signed package with root policy will be treated as trusted - - if (!root) { - rpmlog(RPMLOG_INFO, "package verified as root sw source\n"); - rootSWSource = 1; /* accept any signed package as root */ - return RPMRC_OK; - } - - //------------------ - -#endif - - if (!root) { + if (!dsp) { rpmlog(RPMLOG_ERR, "No device policy found\n"); - rootSWSource = 1; /* accept any signed package as root */ return rpmrc; } @@ -383,15 +337,15 @@ rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, if (rpmrc) { /* RPM failed to verify signature */ rpmlog(RPMLOG_ERR, "Invalid signature, cannot search sw source\n"); - return rpmrc; + goto exit; } if (sigtd->tag != RPMSIGTAG_RSA) { /* Not RSA, revert to unknown sw source. */ - rpmlog(RPMLOG_DEBUG, "no RSA signature, cannot search sw source\n"); + rpmlog(RPMLOG_DEBUG, "not an RSA signature, cannot search sw source\n"); goto exit; } - current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceBySignature, sig, ctx); + current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceBySignature, sig, ctx); if (current) rpmlog(RPMLOG_DEBUG, "signature matches sw source %s\n", current->name); else @@ -399,11 +353,11 @@ rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, exit: if (!current) { - current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL); + current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)"_default_", NULL); if (current) { rpmlog(RPMLOG_DEBUG, "using _default_ sw source\n"); } else { // for now in case default sw source isn't there yet, allow to think that it is coming from root - current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"root", NULL); + current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)"root", NULL); if (current) rpmlog(RPMLOG_DEBUG, "using _root_ sw source now for testing\n"); } @@ -412,85 +366,6 @@ rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, return rpmrc; } -static packagecontext *msmNew(rpmte te) -{ - Header h; - struct rpmtd_s msm; - int count; - packagecontext *ctx = NULL; - const char *sw_source = NULL; - - rpmtdReset(&msm); - - h = rpmteHeader(te); - if (!h) return NULL; - - ctx = xcalloc(1, sizeof(*ctx)); - if (!ctx) { - goto exit1; - } - ctx->te = te; - - if (!headerIsEntry(h, RPMTAG_SECMANIFEST)) { - goto exit1; - } - - if (!headerGet(h, RPMTAG_SECMANIFEST, &msm, HEADERGET_MINMEM)) { - goto exit1; - } - - count = rpmtdCount(&msm); - if (count != 1) { - goto exit2; - } - - ctx->data = xstrdup(rpmtdNextString(&msm)); - rpmlog(RPMLOG_DEBUG, "%s manifest b64 data: %.40s...\n", - rpmteN(ctx->te), ctx->data); - exit2: - rpmtdFreeData(&msm); - exit1: - if (rpmteType(ctx->te) == TR_ADDED) { - /* Save sw_source name into database, we need it when package */ - /* is removed because signature verify is not called then. */ - if (current) sw_source = current->name; - else if (rootSWSource) sw_source = rpmteN(ctx->te); - - if (!sw_source || !headerPutString(h, RPMTAG_SECSWSOURCE, sw_source)) { - rpmlog(RPMLOG_ERR, "Failed to save sw source for %s, sw_source: %s\n", - rpmteN(ctx->te), sw_source); - msmFreePointer((void**)&ctx->data); - msmFreePointer((void**)&ctx); - } - } - headerFree(h); - - return ctx; -} - -static packagecontext *msmAddTE(rpmte te) -{ - packagecontext *ctx = msmNew(te); - if (ctx) { - /* add the new policy to the list */ - if (!contextsHead) { - contextsHead = ctx; - contextsTail = ctx; - } else { - if (rpmteType(te) == TR_ADDED) { - /* add to the end of the list */ - contextsTail->next = ctx; - contextsTail = ctx; - } else { - /* add to the beginning of the list */ - ctx->next = contextsHead; - contextsHead = ctx; - } - } - } - return ctx; -} - rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) { packagecontext *ctx = NULL; @@ -502,18 +377,18 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) package_created = 0; - if (!root && !rootSWSource) { - /* no sw source config, just exit */ - goto exit; + if (!dsp) { + rpmlog(RPMLOG_ERR, "Device security policy is missing. Unable to proceed\n"); + return RPMRC_FAIL; } if (!current) { /* this means that verify hook has not been called */ - current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL); + current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)"_default_", NULL); if (current) { rpmlog(RPMLOG_DEBUG, "using _default_ sw source\n"); } else { - rpmlog(RPMLOG_ERR, "Default source isn't availiable. Package source can't be determined. Abort installation\n"); + rpmlog(RPMLOG_ERR, "Default source isn't avaliable. Package source can't be determined. Abort installation\n"); goto fail; } } @@ -531,7 +406,7 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) if (h) { const char *name = headerGetString(h, RPMTAG_SECSWSOURCE); if (name) { - current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL); + current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)name, NULL); rpmlog(RPMLOG_DEBUG, "removing %s from sw source %s\n", rpmteN(ctx->te), name); } @@ -590,11 +465,12 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) rpmlog(RPMLOG_DEBUG, "Installing the package\n"); package_x *package = NULL; - if (rootSWSource) { - /* this is the first package */ + /*if (rootSWSource) { + // this is the first package that brings the policy package = msmCreatePackage(mfx->name, mfx->sw_sources, mfx->provides, NULL); - } else if (mfx->sw_source) { + } else */ + if (mfx->sw_source) { /* all packages must have sw_source */ package = msmCreatePackage(mfx->name, mfx->sw_source, mfx->provides, NULL); @@ -628,15 +504,17 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) } package_created = 1; - if (rootSWSource) { - /* current is root */ - root = ctx->mfx; - } + + /*if (rootSWSource) { + // current configuration becomes dsp + dsp = ctx->mfx; + } */ rpmlog(RPMLOG_DEBUG, "Starting the security setup...\n"); unsigned int smackLabel = 0; - if (rootSWSource || ctx->mfx->sw_source) { + /*if (rootSWSource || ctx->mfx->sw_source) {*/ + if (ctx->mfx->sw_source) { if (ctx->mfx->sw_sources) { smackLabel = 1; /* setting this one on since this manifest doesn't have any define/request section */ ret = msmSetupSWSources(ctx->smack_accesses, ctx->mfx, ts); @@ -719,7 +597,7 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode) { - //check if there any conflicts that prevent file being written to the disk + /* Check if there any conflicts that prevent file being written to the disk */ fileconflict *fc; packagecontext *ctx = context; @@ -735,8 +613,6 @@ rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode) if (cleanedPath) *cleanedPath = '\0'; - //rpmlog(RPMLOG_DEBUG, "dupapth: %s\n", dupPath); - HASH_FIND(hh, allfileconflicts, dupPath, strlen(dupPath), fc); msmFreePointer((void**)&dupPath); @@ -761,13 +637,16 @@ rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode) rpmRC PLUGINHOOK_FSM_COMMIT_FUNC(const char* path, mode_t mode, int type) { + /* Setup xattrs for the given path */ + packagecontext *ctx = context; + + rpmlog(RPMLOG_DEBUG, "Started with FSM_COMMIT_FUNC hook for file: %s\n", path); + if (!ctx) return RPMRC_FAIL; if (!path) return RPMRC_FAIL; - /* the type is ignored for now */ - - rpmlog(RPMLOG_DEBUG, "Started with FSM_COMMIT_FUNC hook for file: %s\n", path); + /* the type option is ignored for now */ if (ctx->mfx) { file_x *file = xcalloc(1, sizeof(*file)); @@ -818,10 +697,10 @@ rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te, int rpmrc) return RPMRC_FAIL; } - if (rootSWSource) { - /* current is root */ - root = context->mfx; - } + /* if (rootSWSource) { + // current configuration becomes dsp + dsp = context->mfx; + } */ if (rpmteType(ctx->te) == TR_REMOVED) { if (ctx->mfx->sw_source) { @@ -847,27 +726,16 @@ rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int rpmrc) packagecontext *ctx = context; msmFreeInternalHashes(); // free hash structures first - if (root) { - msmSaveDeviceSecPolicyXml(root, ts->rootDir); - if (!rootSWSource) root = msmFreeManifestXml(root); + if (dsp) { + msmSaveDeviceSecPolicyXml(dsp, ts->rootDir); + /* if (!rootSWSource) dsp = msmFreeManifestXml(dsp); */ + dsp = msmFreeManifestXml(dsp); + } if (!ctx) return RPMRC_FAIL; return RPMRC_OK; } -static packagecontext *msmFree(packagecontext *ctx) -{ - while (ctx) { - packagecontext *next = ctx->next; - msmFreePointer((void**)&ctx->data); - ctx->mfx = msmFreeManifestXml(ctx->mfx); - if (ctx->smack_accesses) smack_accesses_free(ctx->smack_accesses); - msmFreePointer((void**)&ctx); - ctx = next; - } - return NULL; -} - rpmRC PLUGINHOOK_CLEANUP_FUNC(void) { @@ -891,11 +759,3 @@ rpmRC PLUGINHOOK_CLEANUP_FUNC(void) return RPMRC_OK; } - -void msmFreePointer(void** ptr) -{ - if (*ptr) - free(*ptr); - *ptr = NULL; - return; -} diff --git a/plugins/msm.h b/plugins/msm.h index 1a4853a..f1bdcc8 100644 --- a/plugins/msm.h +++ b/plugins/msm.h @@ -29,15 +29,12 @@ #ifndef MSM_H #define MSM_H -#define IMA "security.ima" -#define SMACK64TRANSMUTE "security.SMACK64TRANSMUTE" #define SMACK64 "security.SMACK64" #define SMACK64EXEC "security.SMACK64EXEC" +#define SMACK64TRANSMUTE "security.SMACK64TRANSMUTE" #define SMACK_RULES_PATH "/etc/smack/accesses.d/" -#define SMACK_RULES_PATH_BEG "/etc/smack/" #define DEVICE_SECURITY_POLICY "/etc/device-sec-policy" -#define SMACK_LOAD_PATH "/sys/fs/smackfs/load" #define SMACK_ISOLATED_LABEL "Isolated" @@ -312,6 +309,14 @@ void msmFreePointer(void **ptr); manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *current, const char *packagename); /** \ingroup msm + * Loads device security policy. + * @param rootDir --root rpm optional prefix + * @param dsp pointer to the loaded policy + * @return RPMRC_OK or RPMRC_FAIL + */ +rpmRC msmLoadDeviceSecurityPolicy(const char* rootDir, manifest_x **dsp); + +/** \ingroup msm * Process device security policy file. * @param filename file name * @return pointer to structure on success @@ -319,6 +324,13 @@ manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *cur manifest_x *msmProcessDevSecPolicyXml(const char *filename); /** \ingroup msm + * Creates a directory for the smack rules. + * @param rootDir --root rpm optional prefix + * @return RPMRC_OK or RPMRC_FAIL + */ +rpmRC msmSetupSmackRulesDir(const char* rootDir); + +/** \ingroup msm * Free all structures reserved during manifest processing. * @param mfx pointer to structure */ @@ -457,4 +469,30 @@ sw_source_x *msmSWSourceTreeTraversal(sw_source_x *sw_sources, int (func)(sw_sou * Free internal hashes. */ void msmFreeInternalHashes(void); + +/** \ingroup msm + * Finds a sw source by key info. + * @param sw_source sw source + * @param param searched param + * @return 0 if found + */ +int msmFindSWSourceByKey(sw_source_x *sw_source, void *param); + +/** \ingroup msm + * Finds a sw source by sw source name. + * @param sw_source sw source + * @param param searched param + * @return 0 if found + */ +int msmFindSWSourceByName(sw_source_x *sw_source, void *param); + +/** \ingroup msm + * Finds a sw source by sw source signature. + * @param sw_source sw source + * @param param searched param + * @param param2 searched param2 + * @return 0 if found + */ +int msmFindSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2); + #endif diff --git a/plugins/msmconfig.c b/plugins/msmconfig.c index 81462fe..1551c6e 100644 --- a/plugins/msmconfig.c +++ b/plugins/msmconfig.c @@ -30,6 +30,8 @@ #include "rpmio/rpmbase64.h" #include "rpmio/rpmlog.h" +#include "rpm/rpmfileutil.h" +#include #include "msm.h" @@ -273,3 +275,140 @@ rpmRC msmSaveDeviceSecPolicyXml(manifest_x *mfx, const char *rootDir) return rc; } +/** + * Copies a file + * @param old_filename old file name + * @param new_filename new file name + * @return result of copy or -1 on failure + */ +static int copyFile(char *old_filename, char *new_filename) +{ + FD_t ptr_old, ptr_new; + int res; + + ptr_old = Fopen(old_filename, "r.fdio"); + ptr_new = Fopen(new_filename, "w.fdio"); + + if ((ptr_old == NULL) || (Ferror(ptr_old))) { + return -1; + } + + if ((ptr_new == NULL) || (Ferror(ptr_new))) { + Fclose(ptr_old); + return -1; + } + + res = ufdCopy(ptr_old, ptr_new); + + Fclose(ptr_new); + Fclose(ptr_old); + return res; +} + +/** + * Loads device security policy. + * @param rootDir --root rpm optional prefix + * @param dsp pointer to the loaded policy + * @return RPMRC_OK or RPMRC_FAIL + */ +rpmRC msmLoadDeviceSecurityPolicy(const char* rootDir, manifest_x **dsp) +{ + char *dspFullPath = NULL, *dspFullPathDir = NULL; + char *defaultdspPath = NULL; + struct stat buf; + + dspFullPath = rpmGenPath(rootDir, (const char*)DEVICE_SECURITY_POLICY, NULL); + rpmlog(RPMLOG_DEBUG, "Device Security policy full path %s\n", dspFullPath); + if (!dspFullPath) { + rpmlog(RPMLOG_ERR, "Building a full path failed for the device security policy\n"); + goto ldsp_error; + } + + if (stat(dspFullPath, &buf) != 0) { // the policy file is missing + if (rootDir) { // we are running with --root option and policy is missing, need to copy it for now + // first create prefix for it + char *sysconfdir = rpmExpand((const char*)"%{?_sysconfdir}", NULL); + if (!sysconfdir || !strcmp(sysconfdir, "")) { + rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n"); + goto ldsp_error; + } + + dspFullPathDir = rpmGenPath(rootDir, sysconfdir, NULL); + rpmlog(RPMLOG_DEBUG, "Device Security policy full path dir %s\n", dspFullPathDir); + msmFreePointer((void**)&sysconfdir); + if (!dspFullPathDir) { + rpmlog(RPMLOG_ERR, "Building a full path for the device security policy dir failed\n"); + goto ldsp_error; + } + if (rpmioMkpath(dspFullPathDir, 0755, getuid(), getgid()) != 0) { + rpmlog(RPMLOG_ERR, "Failed to create a path for the device security policy dir\n"); + goto ldsp_error; + } + defaultdspPath = rpmExpand((const char*)"%{?__transaction_msm_default_policy}", NULL); + if (!defaultdspPath || !strcmp(defaultdspPath, "")) { + rpmlog(RPMLOG_ERR, "Failed to expand transaction_msm_default_policy macro\n"); + goto ldsp_error; + } + if(copyFile(defaultdspPath, dspFullPath) == -1) { + /* Do not allow plug-in to proceed without security policy existing */ + rpmlog(RPMLOG_ERR, "Failed to copy the device security policy to the chroot environment\n"); + goto ldsp_error; + } + } else { + /* Do not allow plug-in to proceed without security policy existing */ + rpmlog(RPMLOG_ERR, "Policy file is missing at %s\n", + dspFullPath); + goto ldsp_error; + } + } + + rpmlog(RPMLOG_DEBUG, "reading the device security policy from %s\n", dspFullPath); + *dsp = msmProcessDevSecPolicyXml(dspFullPath); + + if (!*dsp) { + rpmlog(RPMLOG_ERR, "Failed to process sw sources from %s\n", dspFullPath); + goto ldsp_error; + } else { + if (msmSetupSWSources(NULL, *dsp, NULL)) { + rpmlog(RPMLOG_ERR, "Failed to setup the device security policy from %s\n", dspFullPath); + goto ldsp_error; + } + } + + return RPMRC_OK; + +ldsp_error: + msmFreePointer((void**)&dspFullPath); + msmFreePointer((void**)&dspFullPathDir); + msmFreePointer((void**)&defaultdspPath); + return RPMRC_FAIL; +} + +/** + * Creates a directory for the smack rules. + * @param rootDir --root rpm optional prefix + * @return RPMRC_OK or RPMRC_FAIL + */ +rpmRC msmSetupSmackRulesDir(const char* rootDir) +{ + char *smackRulesFullPath = NULL; + rpmRC res = RPMRC_FAIL; + + smackRulesFullPath = rpmGenPath(rootDir, SMACK_RULES_PATH, NULL); + rpmlog(RPMLOG_DEBUG, "smackRulesFullPath for SMACK_RULES_PATH %s\n", smackRulesFullPath); + + if (!smackRulesFullPath){ + rpmlog(RPMLOG_ERR, "Building a full path failed for smack rules path\n"); + return res; + } + + if (rpmioMkpath(smackRulesFullPath, 0744, getuid(), getgid()) != 0) { + rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n"); + } else { + res = RPMRC_OK; + } + + msmFreePointer((void**)&smackRulesFullPath); + return res; +} + diff --git a/plugins/msmmanifest.c b/plugins/msmmanifest.c index c713923..d1f211b 100644 --- a/plugins/msmmanifest.c +++ b/plugins/msmmanifest.c @@ -822,7 +822,7 @@ static int msmProcessDefine(xmlTextReaderPtr reader, define_x *define, manifest_ return ret; } -static int findSWSourceByKey(sw_source_x *sw_source, void *param) +int msmFindSWSourceByKey(sw_source_x *sw_source, void *param) { origin_x *origin; keyinfo_x *keyinfo; @@ -839,6 +839,34 @@ static int findSWSourceByKey(sw_source_x *sw_source, void *param) return 1; } +int msmFindSWSourceByName(sw_source_x *sw_source, void *param) +{ + const char *name = (const char *)param; + return strcmp(sw_source->name, name); +} + +int msmFindSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2) +{ + origin_x *origin; + keyinfo_x *keyinfo; + pgpDigParams sig = (pgpDigParams)param; + DIGEST_CTX ctx = (DIGEST_CTX)param2; + pgpDigParams key = NULL; + + for (origin = sw_source->origins; origin; origin = origin->prev) { + for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) { + if (pgpPrtParams(keyinfo->keydata, keyinfo->keylen, PGPTAG_PUBLIC_KEY, &key)) { + rpmlog(RPMLOG_ERR, "invalid sw source key\n"); + return -1; + } + if (pgpVerifySignature(key, sig, ctx) == RPMRC_OK) { + return 0; + } + } + } + return 1; +} + static int msmProcessKeyinfo(xmlTextReaderPtr reader, origin_x *origin, sw_source_x *parent) { const xmlChar *keydata; @@ -858,7 +886,7 @@ static int msmProcessKeyinfo(xmlTextReaderPtr reader, origin_x *origin, sw_sourc } if (!ret) { // check that keys aren't matching - sw_source_x *old = msmSWSourceTreeTraversal(parent, findSWSourceByKey, (void *)keyinfo, NULL); + sw_source_x *old = msmSWSourceTreeTraversal(parent, msmFindSWSourceByKey, (void *)keyinfo, NULL); if (old) { rpmlog(RPMLOG_ERR, "SW source with this key has already been installed\n"); return -1; @@ -976,12 +1004,6 @@ static int msmProcessAllow(xmlTextReaderPtr reader, sw_source_x *sw_source) return ret; } -static int msmFindSWSourceByName(sw_source_x *sw_source, void *param) -{ - const char *name = (const char *)param; - return strcmp(sw_source->name, name); -} - static int msmProcessSWSource(xmlTextReaderPtr reader, sw_source_x *sw_source, const char *parentkey, manifest_x *mfx) { const xmlChar *name, *node, *rank, *rankkey; diff --git a/plugins/msmxattr.c b/plugins/msmxattr.c index eaf064d..0661ae3 100644 --- a/plugins/msmxattr.c +++ b/plugins/msmxattr.c @@ -1194,8 +1194,8 @@ int msmSetFileXAttributes(manifest_x *mfx, const char* filepath, magic_t cookie) } len = strlen(filesystem->path); rpmlog(RPMLOG_DEBUG, "filepath: %s, filesystem->type %s\n", filepath, filesystem->type); - rpmlog(RPMLOG_DEBUG, "filesystem->path: %s, length %d, match %d\n", filesystem->path, len, match); - rpmlog(RPMLOG_DEBUG, "filesystem->path + len - 1: %s\n", filesystem->path + len - 1); + //rpmlog(RPMLOG_DEBUG, "filesystem->path: %s, length %d, match %d\n", filesystem->path, len, match); + //rpmlog(RPMLOG_DEBUG, "filesystem->path + len - 1: %s\n", filesystem->path + len - 1); if (len > match) { if ((!strncmp(filepath, filesystem->path, len)) && (filesystem->type)) { /* partial match and the directory marked as transmutable*/ -- 2.7.4