Re: [mod_fcgid PATCH] catch errors from setuid()/seteuid()

2010-01-21 Thread Jeff Trawick
On Wed, Jan 20, 2010 at 8:19 PM, pqf p...@mailtech.cn wrote:
 I man seteuid in my Linux box, there are two types of errors:
 ERRORS
       The seteuid() function shall fail if:

       EINVAL The value of the uid argument is invalid and is not supported by 
 the implementation.

       EPERM  The  process  does not have appropriate privileges and uid does 
 not match the real group ID or the saved set-group-
              ID.

 If directly pass 0 in setuid(), EINVAL may not happend
 If this process is seteuid from root, EPERM may not happend

 so, I think the check is just a textbook logic check?

yes, until somebody changes code or some other bug results in this
being called in a different environment

 just call _exit(1) if it fail?

two concerns with that minimal change:

1. seteuid() works once then fails n times now (at least on Solaris),
so some extra logic is needed
2. even if these calls never fail, the presence of the exit() without
a log message may cause somebody to lose a lot of time investigating a
mysterious disappearance of the new process

--/--

I'll punt on this until after 2.3.5 since I'd like to spend the time
to watch it work on another platform or two.  (suexec is not something
I use more than once every ~3 years, so it is worth setting up in
multiple environments.)


Re: [mod_fcgid PATCH] catch errors from setuid()/seteuid()

2010-01-21 Thread pqf
Hi, Jeff
Your concerns are right, +1 for your patch :)

Thanks

--
From: Jeff Trawick traw...@gmail.com
Sent: Thursday, January 21, 2010 9:23 PM
To: dev@httpd.apache.org
Subject: Re: [mod_fcgid PATCH] catch errors from setuid()/seteuid()

 On Wed, Jan 20, 2010 at 8:19 PM, pqf p...@mailtech.cn wrote:
 I man seteuid in my Linux box, there are two types of errors:
 ERRORS
   The seteuid() function shall fail if:

   EINVAL The value of the uid argument is invalid and is not supported 
 by the implementation.

   EPERM  The  process  does not have appropriate privileges and uid does 
 not match the real group ID or the saved set-group-
  ID.

 If directly pass 0 in setuid(), EINVAL may not happend
 If this process is seteuid from root, EPERM may not happend

 so, I think the check is just a textbook logic check?
 
 yes, until somebody changes code or some other bug results in this
 being called in a different environment
 
 just call _exit(1) if it fail?
 
 two concerns with that minimal change:
 
 1. seteuid() works once then fails n times now (at least on Solaris),
 so some extra logic is needed
 2. even if these calls never fail, the presence of the exit() without
 a log message may cause somebody to lose a lot of time investigating a
 mysterious disappearance of the new process
 
 --/--
 
 I'll punt on this until after 2.3.5 since I'd like to spend the time
 to watch it work on another platform or two.  (suexec is not something
 I use more than once every ~3 years, so it is worth setting up in
 multiple environments.)
 

[mod_fcgid PATCH] catch errors from setuid()/seteuid()

2010-01-20 Thread Jeff Trawick
During the last hackathon, Paul was kind enough to run the clang/llvm
static analysis on mod_fcgid
(http://zeus.kimaker.com/~chip/fcgid-scan/).  That pointed out these
setuid()/seteuid() calls that aren't checked prior to running a child.

The error checking itself is simple enough, but there's an ugly aspect
of the implementation that results in trying to switch effective/real
uids multiple times that I worked around.  (See the FIXME text in the
patch.  I'm not aware of a simple solution, especially one simple
enough to get into 2.3.5)  The seteuid() call would otherwise fail on
subsequent invocations for the same child.

IIRC Joe thought that the seteuid() wasn't needed at all, but the
setuid() fails without it on Solaris.

Concerns?

Is there some reason that testing on Linux and Solaris wouldn't be sufficient?
Index: modules/fcgid/fcgid_proc_unix.c
===
--- modules/fcgid/fcgid_proc_unix.c (revision 901320)
+++ modules/fcgid/fcgid_proc_unix.c (working copy)
@@ -160,10 +160,44 @@
 return APR_SUCCESS;
 }
 
+static void log_setid_failure(const char *id_type,
+   uid_t user_id)
+{
+char errno_desc[120];
+char errmsg[240];
+
+apr_strerror(errno, errno_desc, sizeof errno_desc);
+apr_snprintf(errmsg, sizeof errmsg,
+ (%d)%s: mod_fcgid child unable to set %s to %ld\n,
+ errno, errno_desc, id_type, (long)user_id);
+write(STDERR_FILENO, errmsg, strlen(errmsg));
+}
+
+/* FIXME 
+ * When using suexec, mod_fcgid registers this child cleanup
+ * with the pool for every FastCGI application as a way of
+ * switching user ids in the child before running suexec.
+ * But such a cleanup will be run for every such pool.  IOW,
+ * when creating the third FastCGI application process this
+ * cleanup will run three times before exec-ing.
+ * ap_unixd_config.user_id is invariant, so this does not
+ * cause an operational problem.  Note that seteuid(0) only
+ * works the first time, or until the first setuid(), so skip
+ * subsequent calls by checking the uid.
+ */
 static apr_status_t exec_setuid_cleanup(void *dummy)
 {
-seteuid(0);
-setuid(ap_unixd_config.user_id);
+if (getuid() != ap_unixd_config.user_id) {
+if (seteuid(0) == -1) {
+log_setid_failure(effective uid, 0);
+_exit(1);
+}
+
+if (setuid(ap_unixd_config.user_id) == -1) {
+log_setid_failure(uid, ap_unixd_config.user_id);
+_exit(1);
+}
+}
 return APR_SUCCESS;
 }
 
@@ -227,7 +261,10 @@
 return errno;
 }
 
-/* Unlink it when process exit */
+/* Register a cleanup to
+ * 1. Unlink the socket when the process exits
+ * 2. (suexec mode only, in the child cleanup) Switch to the configured uid
+ */
 if (ap_unixd_config.suexec_enabled) {
 apr_pool_cleanup_register(procnode-proc_pool,
   procnode, socket_file_cleanup,


Re: [mod_fcgid PATCH] catch errors from setuid()/seteuid()

2010-01-20 Thread pqf
I man seteuid in my Linux box, there are two types of errors:
ERRORS
   The seteuid() function shall fail if:

   EINVAL The value of the uid argument is invalid and is not supported by 
the implementation.

   EPERM  The  process  does not have appropriate privileges and uid does 
not match the real group ID or the saved set-group-
  ID.

If directly pass 0 in setuid(), EINVAL may not happend
If this process is seteuid from root, EPERM may not happend

so, I think the check is just a textbook logic check? just call _exit(1) if it 
fail? 


--
From: Jeff Trawick traw...@gmail.com
Sent: Thursday, January 21, 2010 5:38 AM
To: dev@httpd.apache.org
Subject: [mod_fcgid PATCH] catch errors from setuid()/seteuid()

 During the last hackathon, Paul was kind enough to run the clang/llvm
 static analysis on mod_fcgid
 (http://zeus.kimaker.com/~chip/fcgid-scan/).  That pointed out these
 setuid()/seteuid() calls that aren't checked prior to running a child.
 
 The error checking itself is simple enough, but there's an ugly aspect
 of the implementation that results in trying to switch effective/real
 uids multiple times that I worked around.  (See the FIXME text in the
 patch.  I'm not aware of a simple solution, especially one simple
 enough to get into 2.3.5)  The seteuid() call would otherwise fail on
 subsequent invocations for the same child.
 
 IIRC Joe thought that the seteuid() wasn't needed at all, but the
 setuid() fails without it on Solaris.
 
 Concerns?
 
 Is there some reason that testing on Linux and Solaris wouldn't be sufficient?