Re: [Rpm-maint] First attempt for the patch on extending the plugin interface for rpm
>>Ok, that'd be good. I was actually wondering why its done the way it is now - >>if there is an actual reason (such insufficient information available at that >>point), I'd like to understand it. > >My understanding before was that in the current implementation you are able to >skip the installation of conflicting files without failing the whole package, >but now when I think of this it doesn't seem like a right thing to do. I have >"inherited" these hooks from Tero (in CC now) and while I have done quite some >changes to them (some I actually still need to sync to open repo that you get >to see them too), I haven't touched the conflict hook at all. > >@Tero, do you still remember the reason why the conflict hook was done in this >way? Why wasn't it better to check the conflicts before the transaction and >fail the whole transaction if conflicts are seen? I'm not quite sure about the context you are talking about here, but I'll tell what I remember. File conflict hook is called early inside rpmtsPrepare when the security plugin doesn't yet know much about the package. File conflict hook just records the conflict and the decision to go ahead takes place in the FSM hook. Overwriting the conflicting file is allowed if package comes from a higher more trusted domain. If it's not allowed, then FSM hook returns an error and package processing is canceled. Btw, there are module tests for different conflict situations here: http://meego.gitorious.org/meego-platform-security/rpm/blobs/taho_dev-4.9.x/tests/rpmmssf.at This link points to the old MeeGo repository since I didn't find these tests in your repo. tero ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint
[Rpm-maint] [PATCH 1/2] Extending rpm plugin interface, part 1
This change adds a new type of the rpm plugin, called transaction plugin and a set of initial hooks for this plugin. The hooks are: PLUGINHOOK_TSM_PRE Pre-transaction hook that is called before an rpm transaction begins PLUGINHOOK_TSM_POST Post-transaction hook that is called after an rpm transaction ends PLUGINHOOK_PSM_PRE Pre-transaction-element hook that is called before an rpm transaction-element is processed PLUGINHOOK_PSM_POST Post-transaction-element hook that is called after an rpm transaction-element is processed PLUGINHOOK_SCRIPT_SETUP Per-script hook that is called once for each rpm mainainers script that is present in the package Each hook is called for every plugin that have this hook registered. The avaliable transaction plugins can be specified in macros.in via transaction_plugins element. --- lib/psm.c |3 +- lib/rpmplugins.c | 118 + lib/rpmplugins.h | 64 - lib/rpmscript.c | 17 +--- lib/rpmscript.h |2 +- lib/rpmte.c | 14 ++- lib/transaction.c | 39 ++ plugins/plugin.h | 14 +++ 8 files changed, 260 insertions(+), 11 deletions(-) diff --git a/lib/psm.c b/lib/psm.c index 8f5376d..1a0c27e 100644 --- a/lib/psm.c +++ b/lib/psm.c @@ -23,6 +23,7 @@ #include "lib/rpmfi_internal.h" /* XXX replaced/states... */ #include "lib/rpmte_internal.h"/* XXX internal apis */ #include "lib/rpmdb_internal.h" /* rpmdbAdd/Remove */ +#include "lib/rpmts_internal.h" /* ts->plugins */ #include "lib/rpmscript.h" #include "debug.h" @@ -421,7 +422,7 @@ static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes, rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0); rc = rpmScriptRun(script, arg1, arg2, sfd, - prefixes, warn_only, selinux); + prefixes, warn_only, selinux, psm->ts->plugins); rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0); /* Map warn-only errors to "notfound" for script stop callback */ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c index 9098aa5..bb44f34 100644 --- a/lib/rpmplugins.c +++ b/lib/rpmplugins.c @@ -110,6 +110,39 @@ rpmRC rpmpluginsAddCollectionPlugin(rpmPlugins plugins, const char *name) return rc; } +rpmRC rpmpluginsAddTransactionPlugin(rpmPlugins plugins, const char *name) +{ +char *path; +char *options; +int rc = RPMRC_FAIL; + +path = rpmExpand("%{?__transaction_",name, "}", NULL); +if (!path || rstreq(path, "")) { + rpmlog(RPMLOG_INFO, _("Failed to expand %%__transaction_%s macro\n"), name); + goto exit; +} + +/* split the options from the path */ +#define SKIPSPACE(s){ while (*(s) && risspace(*(s))) (s)++; } +#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; } +options = path; +SKIPNONSPACE(options); +if (risspace(*options)) { + *options = '\0'; + options++; + SKIPSPACE(options); +} +if (*options == '\0') { + options = NULL; +} + +rc = rpmpluginsAdd(plugins, name, path, options); + + exit: +_free(path); +return rc; +} + rpmPlugins rpmpluginsFree(rpmPlugins plugins) { int i; @@ -195,3 +228,88 @@ rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char *name) RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_PRE_REMOVE); return hookFunc(); } + +rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts) +{ +rpmRC (*hookFunc)(rpmts); +int i; +rpmRC rc = RPMRC_OK; +const char *name = NULL; + +for (i = 0; i < plugins->count; i++) { + name = plugins->names[i]; + RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_PRE); + if ( hookFunc(ts) == RPMRC_FAIL ) + rc = RPMRC_FAIL; +} + +return rc; +} + +rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts) +{ +rpmRC (*hookFunc)(rpmts); +int i; +rpmRC rc = RPMRC_OK; +const char *name = NULL; + +for (i = 0; i < plugins->count; i++) { + name = plugins->names[i]; + RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_POST); + if ( hookFunc(ts) == RPMRC_FAIL ) + rc = RPMRC_FAIL; +} + +return rc; +} + +rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te) +{ +rpmRC (*hookFunc)(rpmte); +int i; +rpmRC rc = RPMRC_OK; +const char *name = NULL; + +for (i = 0; i < plugins->count; i++) { + name = plugins->names[i]; + RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_PRE); + if ( hookFunc(te) == RPMRC_FAIL ) + rc = RPMRC_FAIL; +} + +return rc; +} + +rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te) +{ +rpmRC (*hookFunc)(rpmte); +int i; +rpmRC rc = RPMRC_OK; +const char *name = NULL; + +for (i = 0; i < plugins->count; i++) { + name = plugins->names[i]; + RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_POST); + if ( hookFunc(te) == RPMRC_FAIL ) + rc = RPMRC_FAIL; +} + +
[Rpm-maint] [PATCH 2/2] Sample plugin example for testing
This patch contains a simple sample transaction plugin (sampleplugin) with empty hooks. --- macros.in |6 ++ plugins/Makefile.am |5 + plugins/sample-plugin.c | 47 +++ 3 files changed, 58 insertions(+) create mode 100644 plugins/sample-plugin.c diff --git a/macros.in b/macros.in index f55dcbe..bf49c0b 100644 --- a/macros.in +++ b/macros.in @@ -1031,6 +1031,12 @@ done \ %__collection_sepolicy_flags 1 #-- +# Transaction specific macros +%__transaction_plugins sampleplugin +%__plugindir %{_libdir}/rpm-plugins +%__transaction_sampleplugin%{__plugindir}/sampleplugin.so + +#-- # Macros for further automated spec %setup and patch application # default to plain patch diff --git a/plugins/Makefile.am b/plugins/Makefile.am index a9c962c..838c21e 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -24,3 +24,8 @@ sepolicy_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmi plugins_LTLIBRARIES += sepolicy.la endif + +sampleplugin_la_SOURCES = plugin.h sample-plugin.c +sampleplugin_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la + +plugins_LTLIBRARIES += sampleplugin.la diff --git a/plugins/sample-plugin.c b/plugins/sample-plugin.c new file mode 100644 index 000..df38960 --- /dev/null +++ b/plugins/sample-plugin.c @@ -0,0 +1,47 @@ +#include "plugin.h" + +rpmPluginHook PLUGIN_HOOKS = \ + PLUGINHOOK_INIT | \ + PLUGINHOOK_CLEANUP | \ +PLUGINHOOK_TSM_PRE | \ +PLUGINHOOK_TSM_POST | \ +PLUGINHOOK_PSM_PRE | \ +PLUGINHOOK_PSM_POST | \ +PLUGINHOOK_SCRIPT_SETUP; + +rpmRC PLUGINHOOK_INIT_FUNC(rpmts ts, const char *name, const char *opts) +{ +return RPMRC_OK; +} + +rpmRC PLUGINHOOK_CLEANUP_FUNC(void) +{ +return RPMRC_OK; +} + +rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts) +{ +return RPMRC_OK; +} + +rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts) +{ +return RPMRC_OK; +} + +rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te) +{ +return RPMRC_OK; +} + +rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te) +{ +return RPMRC_OK; +} + +rpmRC PLUGINHOOK_SCRIPT_SETUP_FUNC(char* path) +{ +rpmlog(RPMLOG_INFO, "Executable path: %s\n", path); +return RPMRC_OK; +} + -- 1.7.9.5 ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint
[Rpm-maint] [PATCH 0/2] First five rpm transaction plugin hooks
Hi, This patch set contains the transaction plugin definition and the first set of new plugin hooks. The second patch also has the test plugin that can be used to verify the new plugin and its hooks. The second patch is just for demostration purpose only. Best Regards, Elena. Elena Reshetova (2): Extending rpm plugin interface, part 1 Sample plugin example for testing lib/psm.c |3 +- lib/rpmplugins.c| 118 +++ lib/rpmplugins.h| 64 - lib/rpmscript.c | 17 --- lib/rpmscript.h |2 +- lib/rpmte.c | 14 +- lib/transaction.c | 39 macros.in |6 +++ plugins/Makefile.am |5 ++ plugins/plugin.h| 14 ++ plugins/sample-plugin.c | 47 +++ 11 files changed, 318 insertions(+), 11 deletions(-) create mode 100644 plugins/sample-plugin.c -- 1.7.9.5 ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint
Re: [Rpm-maint] First attempt for the patch on extending the plugin interface for rpm
On 10/17/2012 11:17 AM, Reshetova, Elena wrote: @Tero, do you still remember the reason why the conflict hook was done in this way? Why wasn't it better to check the conflicts before the transaction and fail the whole transaction if conflicts are seen? I'm not quite sure about the context you are talking about here, but I'll tell what I remember. File conflict hook is called early inside rpmtsPrepare when the security plugin doesn't yet know much about the package. File conflict hook just records the conflict and the decision to go ahead takes place in the FSM hook. Overwriting the conflicting file is allowed if package comes from a higher more trusted domain. If it's not allowed, then FSM hook returns an error and package processing is canceled. The problem is that while failure in FSM is always a possibility, *planning* to fail there is bad as it breaks the one promise rpm gives about transactions: transaction will not start when there are known problems. File conflicts need to be handled early, either by resolving them or aborting the entire transaction before it really even starts. Otherwise various calculations will be off, and by the time a package ends ups in the FSM, some scripts have already been run causing modifications to the system that can't be undone, plus it can cause broken dependencies to other packages. Do you happen to remember what information is missing the conflict resolution stage? I'd guess that would be something internal to the plugin as from rpm POV, pretty much everything that is known about the packages is available in rpmtsPrepare(). Thank you Tero for clarifying! This reminded me the actual reason why decision can't be made in conflict hook for us. I think I just was too tired yesterday because I miss the obvious thing. The information we are missing is the package source (we identify it based on package signature). So, suppose there is a new package X that is about to be installed. It brings file A that conflicts with the previously installed file from package Y. At this moment the verify hook for this package hasn't been called yet, so the plugin doesn't know who signed package X and can't make a decision if it is ok to overwrite a file or not. I wonder if we can somehow pass the package signature to this hook then... I will look into this. Good, this is just the kind of information and understanding I was looking for, and it sounds like a solvable problem - signatures have long since been read and verified so its more a matter of remembering them in some form that can be accessed from here. Whether by remembering the signature itself or the signature -> other id (source or whatever) mapping done earlier. It does also sound like something that could use structural changes to rpm itself... and here we are back to the ad-hoc nature of the conflict hook arguments (which are the way they are because that's all thats available from rpm) :) I mentioned plans to do some pretty fundamental changes to rpm internals that would also affect this: one of those things would a unified package "object" that can represent both both already installed packages and the to-be-installed packages. So where you currently have an rpmte and a header, you'd get two objects of the same type, and those package objects could (and would) carry information that's not currently present in either rpmte and/or header. The details of how all this will end up looking are hazy atm, but just so you know... - Panu - ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint
Re: [Rpm-maint] First attempt for the patch on extending the plugin interface for rpm
On 10/16/2012 07:31 PM, Reshetova, Elena wrote: Hi, Obviously there needs to be some way of loading the plugins... What kinda bothers me here is the notion of "security plugin" - except for perhaps the signature/conflict hooks, there's nothing inherently security-specific here. The two immediate candidates *are* security-oriented, but they're very, very different in what they do and how they affect the system. Eg if you disable SELinux labeling on a system where SELinux is enabled, you'll pretty much just shoot yourself in the foot (by ending up with a rather screwed up system) >rather than fundametally bypass system security. "Transaction plugin" or something to that effect would seem to be more appropriate as these hooks could be used for all sorts of purposes (additional logging / interaction with other systems like dbus notifications for somebody ... whatever). Ok, let's call it indeed a "transaction plugin" because security plugin can be considered as a particular case of transaction plugin. I will rename it. Thanks. That's the way I see it as well: additional security is just one possible application for transaction plugins. The script setup hook is fairly obvious too, just forgot to mention it. The one question with that is (again) the argument(s) it receives: currently its ARGV_t, but does it actually need the entire argv or would just the actual executable path suffice for the setup? I am fine with just the path, but looking to SELinux code, the rpm_execcon() func needs the whole argv struct. @ Stephen, do you know how mandatory for SELinux is to have the whole argv struct? Is it just because of rpm_execcon() API or? Like Stephen already replied, the entire argv is only needed for the performing the actual exec through rpm_execcon(). Another possibility might be passing an rpmScript "object" (which would need exporting and probably added interfaces, but that's kinda in the plans anyway at some point). But perhaps that's best left for later. Yes, I guess there is always a possibility to change these things when better objects/structs are available. I am quite sure I can make these changes later since I will be responsible for introducing these hooks at the first place :) I don't just plan to dump this on you once and go away! Good to hear :) I dunno... There are s many different options and API flags that affect these things, attempting to enforce things from the inside of rpm seems hopelessly futile: practically every aspect of rpm's behavior is overridable via cli, API and configuration. Including the paths where rpm loads its configuration >from. You'd need to have a hard-wired list of mandatory plugins and theirr non-macro paths compiled rpm to enforce anything at all. And even then, if you have cli access as root, what's to prevent the user from just replacing the executable/libraries with something that doesn't enforce anything? We can prevent user or malicious app from modifying the rpm itself, its plugins, configuration files by using the MAC (as selinux or smack) in run-time and integrity protection (as IMA/EVM) for offline protection. Using librpm directly by user or program actually should be quite safe, because user or malicious app won't get any powerful permissions in the most restrictive setup (no classical root, no posix capabilities). There normally would be some higher level package manager on top of rpm that would have needed permissions and would execute rpm (which would inherit the permissions in this case) with a proper set of cli arguments and environment. If everything goes well, then we don't need to worry that rpm would install smth without a plugin being run. But what if the system gets damaged somehow (not even necessary attacked) and plugin binary happen to disappear? In this case given that we are relying on additional checks for the plugin, it is a very bad idea to proceed without it. It would indeed make the whole system unsecure and in addition also unusable, and this is all even without user understanding that system got corrupted. So, this was the idea behind having this "plugin present" check and stop if failed in place. I was looking at it as some kind of analogy to sysinit that can make checks during the boot process that needed services (example from security: device lock daemon) are up and if they aren't up, then it can stop the boot and actually go to some recovery mode. Does this explanation makes a bit more sense? So its more of a sanity check than an actual security measure. Nothing wrong with sanity checks, and I'm fine with having *any* configured but missing transaction plugin abort the transaction. It's the case of non-configured plugin(s) somehow aborting that I find troublesome. The notion of mandatory plugins seems a bit alien to me, especially since rpm certainly does not *need* any transaction plugins to function as it always has. That's the reason I suggested the reverse setup where rpm is just t
Re: [Rpm-maint] First attempt for the patch on extending the plugin interface for rpm
>> @Tero, do you still remember the reason why the conflict hook was >> done in this way? Why wasn't it better to check the conflicts before >> the transaction and fail the whole transaction if conflicts are seen? > > I'm not quite sure about the context you are talking about here, but > I'll tell what I remember. File conflict hook is called early inside > rpmtsPrepare when the security plugin doesn't yet know much about the > package. File conflict hook just records the conflict and the decision > to go ahead takes place in the FSM hook. Overwriting the conflicting > file is allowed if package comes from a higher more trusted domain. If it's not allowed, then FSM hook returns an error and package processing is canceled. >The problem is that while failure in FSM is always a possibility, >*planning* to fail there is bad as it breaks the one promise rpm gives about transactions: transaction will not start when there are known problems. File conflicts need to be handled early, either by resolving them or aborting the entire transaction before it really even starts. >Otherwise various calculations will be off, and by the time a package ends ups in the FSM, some scripts have already been run causing modifications to the system that can't be undone, plus it can cause broken dependencies to other packages. >Do you happen to remember what information is missing the conflict resolution stage? I'd guess that would be something internal to the plugin as from rpm POV, pretty much everything that is known about the packages is available in rpmtsPrepare(). Thank you Tero for clarifying! This reminded me the actual reason why decision can't be made in conflict hook for us. I think I just was too tired yesterday because I miss the obvious thing. The information we are missing is the package source (we identify it based on package signature). So, suppose there is a new package X that is about to be installed. It brings file A that conflicts with the previously installed file from package Y. At this moment the verify hook for this package hasn't been called yet, so the plugin doesn't know who signed package X and can't make a decision if it is ok to overwrite a file or not. I wonder if we can somehow pass the package signature to this hook then... I will look into this. Best Regards, Elena. smime.p7s Description: S/MIME cryptographic signature ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint
Re: [Rpm-maint] First attempt for the patch on extending the plugin interface for rpm
>On Tue, Oct 16, 2012 at 7:51 PM, Stephen Smalley wrote: >> >> @ Stephen, do you know how mandatory for SELinux is to have the whole argv >> struct? Is it just because of rpm_execcon() API or? > > It is because presently rpm_execcon() performs the exec call. If the > exec call is handled by the caller, then we only need the executable > path. Likewise with envp; we do not need it if the caller performs the > exec. We would just move the remaining logic to set up the exec context > from libselinux rpm_execcon() into the rpm selinux plugin code; as rpm > is the only user of it, there is no real reason for it to live in > libselinux vs being part of an rpm plugin. Good, thank you for clarifying this! This is what I was hoping can be the case. I will change the hook to have only path passed for now. Best Regards, Elena. ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint
Re: [Rpm-maint] First attempt for the patch on extending the plugin interface for rpm
On 10/17/2012 07:49 AM, Tero Aho wrote: Ok, that'd be good. I was actually wondering why its done the way it is now - if there is an actual reason (such insufficient information available at that point), I'd like to understand it. My understanding before was that in the current implementation you are able to skip the installation of conflicting files without failing the whole package, but now when I think of this it doesn't seem like a right thing to do. I have "inherited" these hooks from Tero (in CC now) and while I have done quite some changes to them (some I actually still need to sync to open repo that you get to see them too), I haven't touched the conflict hook at all. @Tero, do you still remember the reason why the conflict hook was done in this way? Why wasn't it better to check the conflicts before the transaction and fail the whole transaction if conflicts are seen? I'm not quite sure about the context you are talking about here, but I'll tell what I remember. File conflict hook is called early inside rpmtsPrepare when the security plugin doesn't yet know much about the package. File conflict hook just records the conflict and the decision to go ahead takes place in the FSM hook. Overwriting the conflicting file is allowed if package comes from a higher more trusted domain. If it's not allowed, then FSM hook returns an error and package processing is canceled. The problem is that while failure in FSM is always a possibility, *planning* to fail there is bad as it breaks the one promise rpm gives about transactions: transaction will not start when there are known problems. File conflicts need to be handled early, either by resolving them or aborting the entire transaction before it really even starts. Otherwise various calculations will be off, and by the time a package ends ups in the FSM, some scripts have already been run causing modifications to the system that can't be undone, plus it can cause broken dependencies to other packages. Do you happen to remember what information is missing the conflict resolution stage? I'd guess that would be something internal to the plugin as from rpm POV, pretty much everything that is known about the packages is available in rpmtsPrepare(). - Panu - ___ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint