On Sun, May 8, 2011 at 7:58 AM, Jeff Trawick <traw...@gmail.com> wrote:
> a potential concern is that by doing it that way (really, that's the
> only way httpd can help out, whether the include of third-party code
> is in ap_hooks.h or elsewhere) the provider of the probe macros is "on
> the hook" to handle absolutely every hook, which can a bit tedious to
> do
>
> * having separate macros for every individual hook gives you type
> safety and the ability to ignore some or, in general, have different
> functionality for different hooks (e.g., connection-based vs.
> request-based, ignoring everything else); but that gets out of date
> (not a killer)
> * having common macros for all hooks breaks because of challenges with
> the parameter lists (a couple of hooks have 0 parameters!!!) and type
> safety (first parm isn't always a pointer, though you can look at the
> name of the hook)
> ** shall we give optional_fn_retrieve a server_rec & ?  (I suggested
> this previously on-list, but only niq responded, and not possitively
> IIRC)
> ** I forget what the other one was
the other one was mpm_name, not a likely candidate for a parameter

This patch disables hook probes for our two hooks which don't have args:

Index: server/config.c
===================================================================
--- server/config.c     (revision 1101166)
+++ server/config.c     (working copy)
@@ -167,6 +167,20 @@
 AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup),
                             (r, lookup), DECLINED)

+/* hooks with no args are implemented last, after disabling APR hook probes */
+#if defined(APR_HOOK_PROBES_ENABLED)
+#undef APR_HOOK_PROBES_ENABLED
+#undef APR_HOOK_PROBE_ENTRY
+#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args)
+#undef APR_HOOK_PROBE_RETURN
+#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
+#undef APR_HOOK_PROBE_INVOKE
+#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args)
+#undef APR_HOOK_PROBE_COMPLETE
+#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args)
+#undef APR_HOOK_INT_DCL_UD
+#define APR_HOOK_INT_DCL_UD
+#endif
 AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve, (void), ())

 /****************************************************************
Index: server/mpm_common.c
===================================================================
--- server/mpm_common.c (revision 1101166)
+++ server/mpm_common.c (working copy)
@@ -98,9 +98,6 @@
 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
                             (apr_time_t t, ap_mpm_callback_fn_t
*cbfn, void *baton),
                             (t, cbfn, baton), APR_ENOTIMPL)
-AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
-                            (void),
-                            (), NULL)
 AP_IMPLEMENT_HOOK_VOID(end_generation,
                        (server_rec *s, ap_generation_t gen),
                        (s, gen))
@@ -108,6 +105,24 @@
                        (server_rec *s, pid_t pid, ap_generation_t
gen, int slot, mpm_child_status status),
                        (s,pid,gen,slot,status))

+/* hooks with no args are implemented last, after disabling APR hook probes */
+#if defined(APR_HOOK_PROBES_ENABLED)
+#undef APR_HOOK_PROBES_ENABLED
+#undef APR_HOOK_PROBE_ENTRY
+#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args)
+#undef APR_HOOK_PROBE_RETURN
+#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
+#undef APR_HOOK_PROBE_INVOKE
+#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args)
+#undef APR_HOOK_PROBE_COMPLETE
+#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args)
+#undef APR_HOOK_INT_DCL_UD
+#define APR_HOOK_INT_DCL_UD
+#endif
+AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
+                            (void),
+                            (), NULL)
+
 typedef struct mpm_gen_info_t {
     APR_RING_ENTRY(mpm_gen_info_t) link;
     int gen;          /* which gen? */

ugly but effective

>
> but there's probably practical no way to individually select classes
> of hooks (e.g., it would be nice to enable only for connection-based
> and request-based) other than invasive preprocessor work within .c
> files
>
> should a distinction be made for core+bundled modules vs. third-party
> code?  maybe the define to include the third-party .h file is for
> internal CPPFLAGS only, so that it doesn't blow (or get the hook probe
> implementer on the hook to handle stuff she's never heard of) when
> building third-party modules against a probe-enabled build?

fixed now

>
> as far as potential bundled exploitation:
>
> * DTrace is one flavor (not kept out of date, horrible build changes
> never cleaned up/committed)
> * it would be cool to have some teaching/debugging mode available at
> configure time which resulted in a lot of crap written to the error
> log during hook execution which a script could create a nice display
> from, combining error and access log information
> ** perhaps enabled at runtime via -Dfoo
> * another flavor I've played with is just maintaining
> r->notes{"ActiveModule"} and r->notes{"RequestFailer"} for access from
> mod_whatkilledus or access log, respectively

I rehashed that with the latest code and the ugly no-arg-hook patch
above.  Attached is a .c file implementation and a corresponding
ap_hook_probes.h for this sample feature set.  The .c file has to be
included from some httpd source file to get it linked in.  It won't
work without the workaround for our two no-arg hooks.

What's a cleaner way to add the code to the server, assuming that
somebody implementing hook probes needs to add

1) a .h file that gets included by ap_hooks.h
2) a .c file that should be linked in to httpd

?

Maybe --enable-hook-probes=/path/to/ap_hook_probes.{c,h}

Alternately, the code that needs to get linked in could be implemented
with a drop-in modules/myprobes/{config.m4,mod_myprobes.c,etc.} and
then --enable the module statically.
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

void *ap_hook_probe_entry(const char *name)
{
    if (!strcmp(name, "fixups")
        || !strcmp(name, "access_checker")
        || !strcmp(name, "access_checker_ex")
        || !strcmp(name, "check_user_id")
        || !strcmp(name, "auth_checker")
        || !strcmp(name, "type_checker")
        || !strcmp(name, "map_to_storage")
        || !strcmp(name, "translate_name")
        || !strcmp(name, "post_read_request")
        || !strcmp(name, "quick_handler")
        || !strcmp(name, "handler")) {
        return (void *)1;
    }
    return NULL;
}

void ap_hook_probe_invoke(void *ud, const char *name, const char *src, const void *arg1)
{
    if (ud) {
        request_rec *r = (request_rec *)arg1;

        apr_table_set(r->notes, "ActiveModule",
                      apr_psprintf(r->pool, "%s/%s", src, name));
    }
}

void ap_hook_probe_complete(void *ud, const char *name, const char *src, void *rv, const void *arg1)
{
    if (ud) {
        int rc = (int)rv;
        request_rec *r = (request_rec *)arg1;

        apr_table_unset(r->notes, "ActiveModule");
        if (rc != HTTP_OK && rc != DECLINED && rc != OK) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                          "%s %s -> %d",
                          src, name, rc);
            apr_table_set(r->notes, "RequestFailer",
                          apr_psprintf(r->pool, "%s/%d/%s", src, rc, name));
        }
    }
}

const void *ap_hook_probe_arg1(const void *arg1, ...)
{
    return arg1;
}

/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef AP_HOOK_PROBES_H
#define AP_HOOK_PROBES_H

#undef APR_HOOK_INT_DCL_UD
#undef APR_HOOK_PROBE_ENTRY
#undef APR_HOOK_PROBE_RETURN
#undef APR_HOOK_PROBE_INVOKE
#undef APR_HOOK_PROBE_COMPLETE

#define APR_HOOK_INT_DCL_UD void *ud = NULL

#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args) \
    ud = ap_hook_probe_entry(#name)

#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args) \
    ap_hook_probe_invoke(ud, #name, src, ap_hook_probe_arg1 args)

#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args) \
    ap_hook_probe_complete(ud, #name, src, (void *)rv, ap_hook_probe_arg1 args)

#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)

void *ap_hook_probe_entry(const char *name);
void ap_hook_probe_complete(void *ud, const char *name, const char *src, void *rv, const void *arg1);
const void *ap_hook_probe_arg1(const void *arg1, ...);
void ap_hook_probe_invoke(void *ud, const char *name, const char *src, const void *arg1);

#endif /* AP_HOOK_PROBES_H */


Reply via email to