From sochotnicky at redhat.com Tue Feb 15 15:12:45 2011 From: sochotnicky at redhat.com (Stanislav Ochotnicky) Date: Tue, 15 Feb 2011 15:12:45 +0100 Subject: [PATCH] Fix curses running as root on tty of other user Message-ID: <1297779166-2674-1-git-send-email-sochotnicky@redhat.com> I have recently received bug report where running pinentry as root with tty set was failing. After some strac-ing, I found the culprit in dialog_run function inside pinentry-curses.c. It tries to open current tty if it is set, but it fails because pinentry removes all capabilities except ipc_lock. I created a patch fixing this behaviour by keeping dac_override capability until after we open ttys. I also fixed another one small capability issue that I believe was present. See the patch for details on this. To reproduce do this: 1. login as normal user 2. su - 3. ls -l `tty` should show you original user as owner 4. gpg2 --symmetric .bashrc With this patch last command succeeds, otherwise it fails diffstat: pinentry/pinentry-curses.c | 24 +++++++++++++++++++++++- secmem/secmem.c | 6 ++++-- 2 files changed, 27 insertions(+), 3 deletions(-) From sochotnicky at redhat.com Tue Feb 15 15:12:46 2011 From: sochotnicky at redhat.com (Stanislav Ochotnicky) Date: Tue, 15 Feb 2011 15:12:46 +0100 Subject: [PATCH] Fix curses running as root on tty of other user In-Reply-To: <1297779166-2674-1-git-send-email-sochotnicky@redhat.com> References: <1297779166-2674-1-git-send-email-sochotnicky@redhat.com> Message-ID: <1297779166-2674-2-git-send-email-sochotnicky@redhat.com> After doing "su -", ownership of current tty stays with original user. If we drop all capabilities we will not be able to open current tty to setup curses screen. So we keep ipc_lock together with dac_override capabilities until we open tty for R/W, then we drop dac_override capability. This patch also fixes second cap_set_proc call in lock_pool that was originally "cap_ipc_lock+p", but should probably be "cap_ipc_lock-e". Original call had no effect because ipc_lock capability was already permitted. Instead it was supposed to drop effective capability enabled in first call. See https://bugzilla.redhat.com/show_bug.cgi?id=676034 for details and reproducer --- pinentry/pinentry-curses.c | 25 ++++++++++++++++++++++++- secmem/secmem.c | 6 ++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/pinentry/pinentry-curses.c b/pinentry/pinentry-curses.c index 76ddbdd..bfc5013 100644 --- a/pinentry/pinentry-curses.c +++ b/pinentry/pinentry-curses.c @@ -93,6 +93,21 @@ struct dialog }; typedef struct dialog *dialog_t; +/* When pinentry-curses runs as root, current tty can be owned by + original user (before doing "su -"). We need to preserve + dac_override capability to be able to read/write on tty */ +static int tty_cap_setup(int init) +{ +#if defined(USE_CAPABILITIES) + if (init) + cap_set_proc( cap_from_text("cap_dac_override+ep") ); + else + cap_set_proc ( cap_from_text("cap_ipc_lock=p") ); +#endif + return 0; +} + + /* Return the next line up to MAXLEN columns wide in START and LEN. The first invocation should have 0 as *LEN. If the line ends with @@ -635,17 +650,25 @@ dialog_run (pinentry_t pinentry, const char *tty_name, const char *tty_type) /* Open the desired terminal if necessary. */ if (tty_name) { + tty_cap_setup(1); ttyfi = fopen (tty_name, "r"); if (!ttyfi) - return -1; + { + int err = errno; + tty_cap_setup(0); + errno = err; + return -1; + } ttyfo = fopen (tty_name, "w"); if (!ttyfo) { int err = errno; fclose (ttyfi); + tty_cap_setup(0); errno = err; return -1; } + tty_cap_setup(0); screen = newterm (tty_type, ttyfo, ttyfi); set_term (screen); } diff --git a/secmem/secmem.c b/secmem/secmem.c index fed7e97..b31e270 100644 --- a/secmem/secmem.c +++ b/secmem/secmem.c @@ -130,11 +130,13 @@ lock_pool( void *p, size_t n ) #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK) int err; - cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); + /* we have to preserve dac_override to be able to open current tty + * even if it is owned by other user (usually after doing su) */ + cap_set_proc( cap_from_text("cap_ipc_lock+ep cap_dac_override+p") ); err = mlock( p, n ); if( err && errno ) err = errno; - cap_set_proc( cap_from_text("cap_ipc_lock+p") ); + cap_set_proc( cap_from_text("cap_ipc_lock-e cap_dac_override+p") ); if( err ) { if( errno != EPERM -- 1.7.4 From sochotnicky at redhat.com Wed Feb 16 16:11:26 2011 From: sochotnicky at redhat.com (Stanislav Ochotnicky) Date: Wed, 16 Feb 2011 16:11:26 +0100 Subject: [PATCH] Fix curses running as root on tty of other user In-Reply-To: <1297779166-2674-2-git-send-email-sochotnicky@redhat.com> References: <1297779166-2674-1-git-send-email-sochotnicky@redhat.com> <1297779166-2674-2-git-send-email-sochotnicky@redhat.com> Message-ID: <4D5BE91E.7040703@redhat.com> On 02/15/2011 03:12 PM, Stanislav Ochotnicky wrote: > After doing "su -", ownership of current tty stays with original > user. If we drop all capabilities we will not be able to open current > tty to setup curses screen. > > So we keep ipc_lock together with dac_override capabilities until we > open tty for R/W, then we drop dac_override capability. > > This patch also fixes second cap_set_proc call in lock_pool that was > originally "cap_ipc_lock+p", but should probably be > "cap_ipc_lock-e". Original call had no effect because ipc_lock > capability was already permitted. Instead it was supposed to drop > effective capability enabled in first call. One more thing to note here is that I don't really see why we should keep cap_ipc_lock after calling mlock at all. It seems unnecessary since memory is already locked, but I am probably missing some nuance of capabilities and/or mlock-ing. Attached patch is my attempt number two. Original had: + if (init) + cap_set_proc( cap_from_text("cap_dac_override+ep") ); + else + cap_set_proc ( cap_from_text("cap_ipc_lock=p") ); This would drop the cap_ipc_lock from permitted and so we wouldn't be able to set it when restoring capability. Now it's: + if (init) + cap_set_proc( cap_from_text("cap_dac_override+ep cap_ipc_lock=p") ); + else + cap_set_proc ( cap_from_text("cap_ipc_lock=p") ); However like I said in previous paragraph, even the original version shouldn't cause any problems since no code path uses ipc_lock capability after setting up secure memory AFAIK (well before tty initialisation). > See https://bugzilla.redhat.com/show_bug.cgi?id=676034 for details and > reproducer If the patch needs work, let me know and I'll fix it up. -- Stanislav Ochotnicky Associate Software Engineer - Base Operating Systems Brno PGP: 7B087241 Red Hat Inc. http://cz.redhat.com -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: 0001-Fix-curses-running-as-root-on-tty-of-other-user.patch URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: OpenPGP digital signature URL: From wk at gnupg.org Thu Feb 17 18:38:16 2011 From: wk at gnupg.org (Werner Koch) Date: Thu, 17 Feb 2011 18:38:16 +0100 Subject: [PATCH] Fix curses running as root on tty of other user In-Reply-To: <1297779166-2674-1-git-send-email-sochotnicky@redhat.com> (Stanislav Ochotnicky's message of "Tue, 15 Feb 2011 15:12:45 +0100") References: <1297779166-2674-1-git-send-email-sochotnicky@redhat.com> Message-ID: <87wrky5zp3.fsf@vigenere.g10code.de> On Tue, 15 Feb 2011 15:12, sochotnicky at redhat.com said: > I have recently received bug report where running pinentry as root > with tty set was failing. After some strac-ing, I found the culprit in > dialog_run function inside pinentry-curses.c. It tries to open current > tty if it is set, but it fails because pinentry removes all > capabilities except ipc_lock. Capabilities? Hmmm, I just checked and figured that there is use enabled by default. The code is more than 10 years old and I was not aware that it still works. For about the same time there is no need for capabilities because at least Linux allows to mlock a few packages without running under uid 0 (or with the respective capability). The fix is to configure --without-libcap to disable the whole code and best remove the code completely and update the secmem code to the one used today by Libgcrypt or gpg 1.4. Shalom-Salam, Werner -- Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz.