All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
To: rostedt <rostedt@goodmis.org>
Cc: paulmck <paulmck@kernel.org>, Matt Mullins <mmullins@mmlx.us>,
	Ingo Molnar <mingo@redhat.com>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Dmitry Vyukov <dvyukov@google.com>,
	Martin KaFai Lau <kafai@fb.com>, Song Liu <songliubraving@fb.com>,
	Yonghong Song <yhs@fb.com>, Andrii Nakryiko <andriin@fb.com>,
	John Fastabend <john.fastabend@gmail.com>,
	KP Singh <kpsingh@chromium.org>,
	linux-kernel <linux-kernel@vger.kernel.org>,
	netdev <netdev@vger.kernel.org>, bpf <bpf@vger.kernel.org>
Subject: Re: [PATCH] bpf: don't fail kmalloc while releasing raw_tp
Date: Mon, 16 Nov 2020 16:34:41 -0500 (EST)	[thread overview]
Message-ID: <1368007646.46749.1605562481450.JavaMail.zimbra@efficios.com> (raw)
In-Reply-To: <20201116160218.3b705345@gandalf.local.home>

----- On Nov 16, 2020, at 4:02 PM, rostedt rostedt@goodmis.org wrote:

> On Mon, 16 Nov 2020 15:44:37 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
>> If you use a stub function, it shouldn't affect anything. And the worse
>> that would happen is that you have a slight overhead of calling the stub
>> until you can properly remove the callback.
> 
> Something like this:
> 
> (haven't compiled it yet, I'm about to though).
> 
> -- Steve
> 
> diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
> index 3f659f855074..8eab40f9d388 100644
> --- a/kernel/tracepoint.c
> +++ b/kernel/tracepoint.c
> @@ -53,10 +53,16 @@ struct tp_probes {
> 	struct tracepoint_func probes[];
> };
> 
> -static inline void *allocate_probes(int count)
> +/* Called in removal of a func but failed to allocate a new tp_funcs */
> +static void tp_stub_func(void)

I'm still not sure whether it's OK to call a (void) function with arguments.

> +{
> +	return;
> +}
> +
> +static inline void *allocate_probes(int count, gfp_t extra_flags)
> {
> 	struct tp_probes *p  = kmalloc(struct_size(p, probes, count),
> -				       GFP_KERNEL);
> +				       GFP_KERNEL | extra_flags);
> 	return p == NULL ? NULL : p->probes;
> }
> 
> @@ -150,7 +156,7 @@ func_add(struct tracepoint_func **funcs, struct
> tracepoint_func *tp_func,
> 		}
> 	}
> 	/* + 2 : one for new probe, one for NULL func */
> -	new = allocate_probes(nr_probes + 2);
> +	new = allocate_probes(nr_probes + 2, 0);
> 	if (new == NULL)
> 		return ERR_PTR(-ENOMEM);
> 	if (old) {
> @@ -188,8 +194,9 @@ static void *func_remove(struct tracepoint_func **funcs,
> 	/* (N -> M), (N > 1, M >= 0) probes */
> 	if (tp_func->func) {
> 		for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
> -			if (old[nr_probes].func == tp_func->func &&
> -			     old[nr_probes].data == tp_func->data)
> +			if ((old[nr_probes].func == tp_func->func &&
> +			     old[nr_probes].data == tp_func->data) ||
> +			    old[nr_probes].func == tp_stub_func)
> 				nr_del++;
> 		}
> 	}
> @@ -207,15 +214,20 @@ static void *func_remove(struct tracepoint_func **funcs,
> 		int j = 0;
> 		/* N -> M, (N > 1, M > 0) */
> 		/* + 1 for NULL */
> -		new = allocate_probes(nr_probes - nr_del + 1);
> -		if (new == NULL)
> -			return ERR_PTR(-ENOMEM);
> -		for (i = 0; old[i].func; i++)
> -			if (old[i].func != tp_func->func
> -					|| old[i].data != tp_func->data)
> -				new[j++] = old[i];
> -		new[nr_probes - nr_del].func = NULL;
> -		*funcs = new;
> +		new = allocate_probes(nr_probes - nr_del + 1, __GFP_NOFAIL);
> +		if (new) {
> +			for (i = 0; old[i].func; i++)
> +				if (old[i].func != tp_func->func
> +				    || old[i].data != tp_func->data)

as you point out in your reply, skip tp_stub_func here too.

> +					new[j++] = old[i];
> +			new[nr_probes - nr_del].func = NULL;
> +		} else {
> +			for (i = 0; old[i].func; i++)
> +				if (old[i].func == tp_func->func &&
> +				    old[i].data == tp_func->data)
> +					old[i].func = tp_stub_func;

I think you'll want a WRITE_ONCE(old[i].func, tp_stub_func) here, matched
with a READ_ONCE() in __DO_TRACE. This introduces a new situation where the
func pointer can be updated and loaded concurrently.

> +		}
> +		*funcs = old;

The line above seems wrong for the successful allocate_probe case. You will likely
want *funcs = new on successful allocation, and *funcs = old for the failure case.

Thanks,

Mathieu

> 	}
> 	debug_print_probes(*funcs);
> 	return old;
> @@ -300,6 +312,10 @@ static int tracepoint_remove_func(struct tracepoint *tp,
> 		return PTR_ERR(old);
> 	}
> 
> +	if (tp_funcs == old)
> +		/* Failed allocating new tp_funcs, replaced func with stub */
> +		return 0;
> +
> 	if (!tp_funcs) {
> 		/* Removed last function */
>  		if (tp->unregfunc && static_key_enabled(&tp->key))

-- 
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com

  parent reply	other threads:[~2020-11-16 21:35 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-02 11:54 KASAN: vmalloc-out-of-bounds Read in bpf_trace_run3 syzbot
2020-11-11 14:57 ` Dmitry Vyukov
2020-11-13  5:37   ` Matt Mullins
2020-11-13 16:08     ` Yonghong Song
2021-02-10 18:23       ` Eric Dumazet
2021-02-10 19:52         ` Steven Rostedt
2020-11-15  5:52 ` [PATCH] bpf: don't fail kmalloc while releasing raw_tp Matt Mullins
2020-11-16 17:19   ` Steven Rostedt
2020-11-16 20:37     ` Mathieu Desnoyers
2020-11-16 20:44       ` Steven Rostedt
2020-11-16 21:02         ` Steven Rostedt
2020-11-16 21:06           ` Steven Rostedt
2020-11-16 21:34           ` Mathieu Desnoyers [this message]
2020-11-16 22:10             ` Steven Rostedt
2020-11-17 23:05               ` Mathieu Desnoyers
2020-11-18  0:42                 ` Matt Mullins
2020-11-18  1:09                   ` Steven Rostedt
2020-11-18  4:57                     ` Paul E. McKenney
2020-11-16 21:21         ` Mathieu Desnoyers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1368007646.46749.1605562481450.JavaMail.zimbra@efficios.com \
    --to=mathieu.desnoyers@efficios.com \
    --cc=andriin@fb.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=dvyukov@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=kafai@fb.com \
    --cc=kpsingh@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=mmullins@mmlx.us \
    --cc=netdev@vger.kernel.org \
    --cc=paulmck@kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=songliubraving@fb.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.