Re: [systemd-devel] offline updates

2015-07-21 Thread Will Woods
On Tue, 2015-07-21 at 03:27 +, Zbigniew Jędrzejewski-Szmek wrote:

 fedup-system-upgrade.service uses an additional flag file which is
 checked with ConditionPathExists so it will not run if 'dnf fedup 
 reboot'
 did not create the flag, even if we go into system-upgrade.target.
 
 packagekit-offline-update.service does not have anything like this, 
 and
 is always run in system-upgrade.target.

Strange - from what I can tell from the source, pk-offline-update is
supposed to bail out unless the update was prepared by PackageKit
itself[1]? Perhaps your system was also trying to install new updates
via PackageKit at the time?

Maybe packagekit-offline-update.service also needs a
ConditionPathExists..

 Running two upgrade mechanisms in parallel does not seem like a good
 idea. (Even if they use a lock file to prevent concurrent access to
 the rpm database, they are bound to interfere with one another: the
 first finishes and decides to reboot, or the first updates some
 packages and messes up the state for the second one...) It seems that
 *some* mechanism to run only one upgrade mechanism is wanted. The 
 approach
 that dnf-plugin-fedup uses seems reasonable: it creates the file only 
 when
 a reboot with 'dnf fedup reboot' is requested.
 As an alternative we could allow only one upgrade mechanism to be 
 enabled.
 Dunno.

How would that be enforced, though? Special handling for system
-updates.target?

Or: does systemd need some convention/support for handling the general
problem of choosing one of multiple (mutually-exclusive) services that
provide the same functionality?

 Also, which is a minor thing, but related: OnFailure=reboot.target
 seems inferior to FailureAction=reboot. IIRC, the second one uses
 irreversible transaction and should be more robust. It also is a
 higher level setting in some sense.  OnFailure=reboot.target is taken
 directly from the spec, so should be changed there first.

I'll add a note about this to the fedup-system-upgrade.service, I
guess, and if the spec changes I'll change it there too.

 So maybe tmpfiles snippet should be used to remove the link. Such a
 change would mean that the update services should not depend on the
 symlink being present, and should instead look for their
 installation data in their own state directory.

Right - this is what dnf-plugin-fedup does, since pk-offline-update
might run first and remove the symlink before we get there.


 To summarize, following changes to the spec are proposed:
 - use Condition* or similar to conditionalize whether a specific
   upgrade mechanism should run
 - use Action=reboot

FailureAction=reboot, I guess?

 - use Type=oneshot

This is the default, correct? Should it be explicitly listed in the
unit file, or should I rely on the default behavior?

 - check that logind.Reboot() is not called on failure by the service
 - services should not look for /systemd-update symlink,
   and the symlink should be removed by tmpfiles before we even get to
   the upgrade.

These all seem reasonable to me. I'll happily make changes to dnf
-plugin-fedup to follow any changes to the spec, once consensus is
reached and the spec is changed.

Thanks for testing this!

-w


[1] https://github.com/hughsie/PackageKit/blob/PACKAGEKIT_1_0_7/client/
pk-offline-update.c#L404
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH] selinux: fix SEGV during switch-root if SELinux policy loaded

2015-03-13 Thread Will Woods
If you've got SELinux policy loaded, label_hnd is your labeling handle.
When systemd is shutting down, we free that handle via mac_selinux_finish().

But: switch_root() calls mkdir_p_label(), which tries to look up a label
using that freed handle, and so we get a bunch of garbage and eventually
SEGV in libselinux.

(This doesn't happen in the switch-root from initramfs to real root because
there's no SELinux policy loaded in initramfs, so label_hnd is NULL and we
never attempt any lookups.)

So: make sure that mac_selinux_finish() actually sets label_hnd to NULL, so
nobody tries to use it after it becomes invalid.

Resolves: RHBZ#1185604
---
 src/shared/selinux-util.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c
index a8d5fc4..7c58985 100644
--- a/src/shared/selinux-util.c
+++ b/src/shared/selinux-util.c
@@ -116,6 +116,7 @@ void mac_selinux_finish(void) {
 return;
 
 selabel_close(label_hnd);
+label_hnd = NULL;
 #endif
 }
 
-- 
2.1.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH] core: let selinux_setup() load policy more than once

2014-04-28 Thread Will Woods
On Fri, 2014-04-25 at 18:26 -0400, Will Woods wrote:
 Currently, systemd refuses to load SELinux policy more than once.
 
 Normal systems don't care, because they either:
 a) have initramfs without policy, then load policy after switch-root, or
 b) load policy in initramfs, and never switch-root out.
 
 But if you *do* switch-root more than once - which fedup does! - you're
 supposed to run selinux_init_load_policy() afterward to ensure that you set up
 selinuxfs and load the new SELinux policy correctly.

For reference, here's the thread from seli...@tycho.nsa.gov where this
was discussed:

  http://marc.info/?l=selinuxm=139782596307221w=2

The upshot is: yes, we're supposed to do selinux_init_load_policy()
after *every* switch-root.

-w

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH] core: let selinux_setup() load policy more than once

2014-04-25 Thread Will Woods
Hey all,

Currently, systemd refuses to load SELinux policy more than once.

Normal systems don't care, because they either:
a) have initramfs without policy, then load policy after switch-root, or
b) load policy in initramfs, and never switch-root out.

But if you *do* switch-root more than once - which fedup does! - you're
supposed to run selinux_init_load_policy() afterward to ensure that you set up
selinuxfs and load the new SELinux policy correctly.

So: this patchset fixes some weird and subtle upgrade bugs[1] by allowing
systemd to load policy after each switch-root.


The first patch is cosmetic: selinux-setup.c was indented 7 spaces (!?) and it
bothered me too much to leave it alone.

The second patch makes systemd try to load policy regardless of whether or not
SELinux is already initialized.

It also changes the failure behavior slightly: normally if policy load fails
and the user requested enforcing, we freeze the system rather than running
without policy. But if SELinux was already initialized, then we *do* have
policy, so we don't have to freeze.


Diffstat ignoring whitespace:

 src/core/ima-setup.c |  0
 src/core/selinux-setup.c | 10 --
 2 files changed, 4 insertions(+), 6 deletions(-)


Thanks,

-w


[1] Here's one weird and subtle bug:
https://bugzilla.redhat.com/show_bug.cgi?id=1045864

It turns out there's actually a race between systemd-cryptsetup and
systemd-ask-password-*.path to create /run/systemd/ask-password.

If systemd wins, it labels the directory correctly, but systemd-cryptsetup
doesn't do label_init(), so it doesn't know how to label the directory.

Normally that doesn't matter, because systemd relabels /run after it reloads
policy... but if it doesn't load policy, it doesn't relabel /run, the
directory keeps the wrong label, and then the password agent can't read files
from there, and your boot hangs forever waiting for a password...

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH 1/2] core: reindent {selinux, ima, smack}-setup.c

2014-04-25 Thread Will Woods
7-space indentation is just too weird to leave alone.
Make it 8 spaces, as per CODING_STYLE. No other changes.
---
 src/core/ima-setup.c | 110 +-
 src/core/selinux-setup.c | 152 +++
 2 files changed, 131 insertions(+), 131 deletions(-)

diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index ed65096..7bffd8d 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -44,63 +44,63 @@
 int ima_setup(void) {
 
 #ifdef HAVE_IMA
-   struct stat st;
-   ssize_t policy_size = 0, written = 0;
-   char *policy;
-   _cleanup_close_ int policyfd = -1, imafd = -1;
-   int result = 0;
-
-   if (stat(IMA_POLICY_PATH, st)  0)
-   return 0;
-
-   policy_size = st.st_size;
-   if (stat(IMA_SECFS_DIR, st)  0) {
-   log_debug(IMA support is disabled in the kernel, ignoring.);
-   return 0;
-   }
-
-   if (stat(IMA_SECFS_POLICY, st)  0) {
-   log_error(Another IMA custom policy has already been loaded, 
- ignoring.);
-   return 0;
-   }
-
-   policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
-   if (policyfd  0) {
-   log_error(Failed to open the IMA custom policy file %s (%m), 
- ignoring., IMA_POLICY_PATH);
-   return 0;
-   }
-
-   imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
-   if (imafd  0) {
-   log_error(Failed to open the IMA kernel interface %s (%m), 
- ignoring., IMA_SECFS_POLICY);
-   goto out;
-   }
-
-   policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
-   if (policy == MAP_FAILED) {
-   log_error(mmap() failed (%m), freezing);
-   result = -errno;
-   goto out;
-   }
-
-   written = loop_write(imafd, policy, (size_t)policy_size, false);
-   if (written != policy_size) {
-   log_error(Failed to load the IMA custom policy file %s (%m), 
- ignoring., IMA_POLICY_PATH);
-   goto out_mmap;
-   }
-
-   log_info(Successfully loaded the IMA custom policy %s.,
-IMA_POLICY_PATH);
+struct stat st;
+ssize_t policy_size = 0, written = 0;
+char *policy;
+_cleanup_close_ int policyfd = -1, imafd = -1;
+int result = 0;
+
+if (stat(IMA_POLICY_PATH, st)  0)
+return 0;
+
+policy_size = st.st_size;
+if (stat(IMA_SECFS_DIR, st)  0) {
+log_debug(IMA support is disabled in the kernel, ignoring.);
+return 0;
+}
+
+if (stat(IMA_SECFS_POLICY, st)  0) {
+log_error(Another IMA custom policy has already been loaded, 
+  ignoring.);
+return 0;
+}
+
+policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
+if (policyfd  0) {
+log_error(Failed to open the IMA custom policy file %s (%m), 
+  ignoring., IMA_POLICY_PATH);
+return 0;
+}
+
+imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
+if (imafd  0) {
+log_error(Failed to open the IMA kernel interface %s (%m), 
+  ignoring., IMA_SECFS_POLICY);
+goto out;
+}
+
+policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
+if (policy == MAP_FAILED) {
+log_error(mmap() failed (%m), freezing);
+result = -errno;
+goto out;
+}
+
+written = loop_write(imafd, policy, (size_t)policy_size, false);
+if (written != policy_size) {
+log_error(Failed to load the IMA custom policy file %s (%m), 
+  ignoring., IMA_POLICY_PATH);
+goto out_mmap;
+}
+
+log_info(Successfully loaded the IMA custom policy %s.,
+ IMA_POLICY_PATH);
 out_mmap:
-   munmap(policy, policy_size);
+munmap(policy, policy_size);
 out:
-   if (result)
-return result;
+if (result)
+ return result;
 #endif /* HAVE_IMA */
 
-   return 0;
+return 0;
 }
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index 9a5d6b2..6d8bc89 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -46,82 +46,82 @@ static int null_log(int type, const char *fmt, ...) {
 int selinux_setup(bool *loaded_policy) {
 
 #ifdef HAVE_SELINUX
-   int enforce = 0;
-   usec_t before_load, after_load;
-   security_context_t con;
-   int r;
-   union selinux_callback cb;
-
-   assert(loaded_policy);
-
-   /* Turn off all of SELinux' own logging, we want to do that */
-   cb.func_log = null_log;
-   

[systemd-devel] [PATCH 2/2] core: let selinux_setup() load policy more than once

2014-04-25 Thread Will Woods
When you switch-root into a new root that has SELinux policy, you're
supposed to to run selinux_init_load_policy() to set up SELinux and load
policy. Normally this gets handled by selinux_setup().

But if SELinux was already initialized, selinux_setup() skips loading
policy and returns 0. So if you load policy normally, and then you
switch-root to a new root that has new policy, selinux_setup() never
loads the new policy. What gives?

As far as I can tell, this check is an artifact of how selinux_setup()
worked when it was first written (see commit c4dcdb9 / systemd v12):

  * when systemd starts, run selinux_setup()
  * if selinux_setup() loads policy OK, restart systemd

So the if policy already loaded, skip load and return 0 check was
there to prevent an infinite re-exec loop.

Modern systemd only calls selinux_setup() on initial load and after
switch-root, and selinux_setup() no longer restarts systemd, so we don't
need that check to guard against the infinite loop anymore.

So: this patch removes the return 0, thus allowing selinux_setup() to
actually perform SELinux setup after switch-root.

We still want to check to see if SELinux is initialized, because if
selinux_init_load_policy() fails *but* SELinux is initialized that means
we still have (old) policy active. So we don't need to halt if
enforce=1.
---
 src/core/selinux-setup.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index 6d8bc89..578a18f 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -51,6 +51,7 @@ int selinux_setup(bool *loaded_policy) {
 security_context_t con;
 int r;
 union selinux_callback cb;
+bool initialized = false;
 
 assert(loaded_policy);
 
@@ -68,13 +69,8 @@ int selinux_setup(bool *loaded_policy) {
 /* Already initialized by somebody else? */
 r = getcon_raw(con);
 if (r == 0) {
-bool initialized;
-
 initialized = !streq(con, kernel);
 freecon(con);
-
-if (initialized)
-return 0;
 }
 
 /* Make sure we have no fds open while loading the policy and
@@ -115,9 +111,11 @@ int selinux_setup(bool *loaded_policy) {
 } else {
 log_open();
 
-if (enforce  0) {
+if ((enforce  0)  (!initialized)) {
 log_error(Failed to load SELinux policy. Freezing.);
 return -EIO;
+} else if (enforce  0) {
+log_warning(Failed to load new SELinux policy. 
Continuing with old policy.);
 } else
 log_debug(Unable to load SELinux policy. Ignoring.);
 }
-- 
1.9.0

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


Re: [systemd-devel] [PATCH] selinux: Only attempt to load policy exactly once, in the real root

2014-04-04 Thread Will Woods
On Thu, 2014-02-20 at 18:17 +, Colin Walters wrote:
 I think both of these (particularly the second) are worse than my
 patch - we don't (to my knowledge) support putting policy in the
 initramfs now with Fedora or Red Hat Enterprise Linux, so attempting
 to find it there by default on every bootup is wrong.  
 
 
 To turn it around, what is the possible value in also probing the
 initramfs?  Does anyone out there load policy from it with systemd?

Oof. I'm late, but: actually, yes. Fedup does this during upgrades.

We ship the new system's policy in upgrade.img in an attempt to ensure
that files written during the upgrade get the right labels.

(For example: if you're upgrading F19-F20, we load F20 policy during
initramfs, then switch_root to the F19 system to get disks mounted, then
switch_root back to initramfs to run the upgrade.)

Loading policy in initramfs seems to have some unfortunate side-effects,
though. For example, every process runs with kernel_t, and all the files
outside of /run and /dev are root_t. 

Also, something seems racy - sometimes /run/systemd/ask-password ends up
init_var_run_t, which keeps us from unlocking /home later. Ugh.

It'd probably be better to load F19 policy first, then load F20 policy
after the second switch_root *back* to initramfs.. except systemd won't
do that either.

I'm open to any ideas about how to make sure that the upgrade runs with
the right policy loaded (or, really, how to be sure that files written
during the upgrade get the correct labels for the new system). 

Otherwise, this patch will probably interfere with upgrades to F21.

-w

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel


[systemd-devel] [PATCH] mount: make sure m-where is set before unit_add_exec_dependencies()

2012-10-16 Thread Will Woods
If you enter unit_add_exec_dependencies with m-where = NULL, you'll
very likely end up aborting somewhere under socket_needs_mount.

(When systemd goes to check to see if the journald socket requires your
mount, it'll do path_startswith(path, m-where)... *kaboom*)

This patch should ensure that:

a) both branches in mount_add_one() set m-where, and
b) mount_add_extras() calls unit_add_exec_dependencies() *after*
   setting m-where.
---
 src/core/mount.c | 16 
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/core/mount.c b/src/core/mount.c
index e1c240e..14f4863 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -547,10 +547,6 @@ static int mount_add_extras(Mount *m) {
 Unit *u = UNIT(m);
 int r;
 
-r = unit_add_exec_dependencies(u, m-exec_context);
-if (r  0)
-return r;
-
 if (UNIT(m)-fragment_path)
 m-from_fragment = true;
 
@@ -562,6 +558,10 @@ static int mount_add_extras(Mount *m) {
 
 path_kill_slashes(m-where);
 
+r = unit_add_exec_dependencies(u, m-exec_context);
+if (r  0)
+return r;
+
 if (!UNIT(m)-description) {
 r = unit_set_description(u, m-where);
 if (r  0)
@@ -1459,6 +1459,14 @@ static int mount_add_one(
 delete = false;
 free(e);
 
+if (!MOUNT(u)-where) {
+MOUNT(u)-where = strdup(where);
+if (!MOUNT(u)-where) {
+r = -ENOMEM;
+goto fail;
+}
+}
+
 if (u-load_state == UNIT_ERROR) {
 u-load_state = UNIT_LOADED;
 u-load_error = 0;
-- 
1.7.11.7

___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel