On 07/23, Oleg Nesterov wrote:
>
> On 07/22, Roland McGrath wrote:
> >
> > > Who will kfree() engine->data ?
> > >
> > > sys_ptrace(PTRACE_DETACH) can do this. But what if the tracer exits
> > > and detaches? Or release_task() does untrace.
> >
> > All of these are some ptrace.c path that has to use UTRACE_DETACH,
> ...
>
> Hmm. Yes, looks like you are right... Not sure what I was worried
> about. I did have some concerns, but I guess I was wrong. Good!

Now I recall why I was worried. And in fact, I think that without
some change utrace->engine is hardly useable.

Let's consider ptrace, but of course it is not special. We introduce
struct ptrace_context {...} and change ptrace_attach() to setup
engine->data to be a pointer to ptrace_context.

Now. we should make sure that every user of UTRACE_DETACH frees
engine->data. And, we have to introduce ptrace_report_reap() which
should free it too.

Note that this itself adds some complications. But the real problem
is: the tracer can never safely dereference engine->data, the tracee
can be killed/released at any moment.

Sure. We can protect ->data by RCU, or add refcounting, etc. But
this is nightmire. This is complex and (I bet) will lead to numerous
bugs.

I strongly believe that ->data should be freed by utrace_engine_put().
If you have the reference to engine, engine->data must be stable.


So, this patch adds engine->dtor and utrace_engine_set_dtor() helper.
It would be better to pass dtor as yet another argument to
utrace_attach_task(). But this means more changes, and in this case
it is better to have utrace_attach_create() and utrace_attach_lookup(),
the new argument is only needed with UTRACE_ATTACH_CREATE.

Afaics, unless a module intentionally leaks utrace_engine, it can safely
use ->dtor() which lives in ->module_core. But at least it can always
use ->dtor = kfree.

Thoughts?

Signed-off-by: Oleg Nesterov <o...@redhat.com>
---


--- __UTRACE/include/linux/utrace.h~4_DTOR      2009-08-14 11:58:05.000000000 
+0200
+++ __UTRACE/include/linux/utrace.h     2009-08-14 16:44:27.000000000 +0200
@@ -322,6 +322,7 @@ static inline enum utrace_syscall_action
 struct utrace_engine {
 /* private: */
        struct kref kref;
+       void (*dtor)(void *data);
        struct list_head entry;
 
 /* public: */
@@ -342,6 +343,15 @@ static inline void utrace_engine_get(str
        kref_get(&engine->kref);
 }
 
+/**
+ * utrace_engine_set_dtor - setup the destructor for ->data
+ */
+static inline void utrace_engine_set_dtor(struct utrace_engine *engine,
+                                               void (*dtor)(void *))
+{
+       engine->dtor = dtor;
+}
+
 void __utrace_engine_release(struct kref *);
 
 /**
@@ -349,7 +359,8 @@ void __utrace_engine_release(struct kref
  * @engine:    &struct utrace_engine pointer
  *
  * You must hold a reference on @engine, and you lose that reference.
- * If it was the last one, @engine becomes an invalid pointer.
+ * If it was the last one, @engine->dtor(@engine->data) is called and
+ * @engine becomes an invalid pointer.
  */
 static inline void utrace_engine_put(struct utrace_engine *engine)
 {
--- __UTRACE/kernel/utrace.c~4_DTOR     2009-08-14 13:54:54.000000000 +0200
+++ __UTRACE/kernel/utrace.c    2009-08-14 16:29:37.000000000 +0200
@@ -79,6 +79,8 @@ void __utrace_engine_release(struct kref
        struct utrace_engine *engine = container_of(kref, struct utrace_engine,
                                                    kref);
        BUG_ON(!list_empty(&engine->entry));
+       if (engine->dtor)
+               engine->dtor(engine->data);
        kmem_cache_free(utrace_engine_cachep, engine);
 }
 EXPORT_SYMBOL_GPL(__utrace_engine_release);

Reply via email to