All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mark Rutland <mark.rutland@arm.com>
To: Alexander Potapenko <glider@google.com>
Cc: akpm@linux-foundation.org, alex.popov@linux.com,
	aryabinin@virtuozzo.com, quentin.casasnovas@oracle.com,
	dvyukov@google.com, andreyknvl@google.com, keescook@chromium.org,
	vegard.nossum@oracle.com, syzkaller@googlegroups.com,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 1/3] kcov: support comparison operands collection
Date: Mon, 9 Oct 2017 16:46:10 +0100	[thread overview]
Message-ID: <20171009154610.GA22534@leverpostej> (raw)
In-Reply-To: <20171009150521.82775-1-glider@google.com>

Hi,

I look forward to using this! :)

I just have afew comments below.

On Mon, Oct 09, 2017 at 05:05:19PM +0200, Alexander Potapenko wrote:
> +/*
> + * Defines the format for the types of collected comparisons.
> + */
> +enum kcov_cmp_type {
> +	/*
> +	 * LSB shows whether one of the arguments is a compile-time constant.
> +	 */
> +	KCOV_CMP_CONST = 1,
> +	/*
> +	 * Second and third LSBs contain the size of arguments (1/2/4/8 bytes).
> +	 */
> +	KCOV_CMP_SIZE1 = 0,
> +	KCOV_CMP_SIZE2 = 2,
> +	KCOV_CMP_SIZE4 = 4,
> +	KCOV_CMP_SIZE8 = 6,
> +	KCOV_CMP_SIZE_MASK = 6,
> +};

Given that LSB is meant to be OR-ed in, (and hence combinations of
values are meaningful) I don't think it makes sense for this to be an
enum. This would clearer as something like:

/*
 * The format for the types of collected comparisons.
 *
 * Bit 0 shows whether one of the arguments is a compile-time constant.
 * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes.
 */
#define	KCOV_CMP_CONST		(1 << 0)
#define KCOV_CMP_SIZE(n)	((n) << 1)
#define KCOV_CMP_MASK		KCOV_CMP_SIZE(3)

... I note that a few places in the kernel use a 128-bit type. Are
128-bit comparisons not instrumented?

[...]

> +static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
> +{
> +	enum kcov_mode mode;
> +
> +	/*
> +	 * We are interested in code coverage as a function of a syscall inputs,
> +	 * so we ignore code executed in interrupts.
> +	 */
> +	if (!t || !in_task())
> +		return false;

This !t check can go, as with the one in __sanitizer_cov_trace_pc, since
t is always current, and therefore cannot be NULL.

IIRC there's a patch queued for that, which this may conflict with.

> +	mode = READ_ONCE(t->kcov_mode);
> +	/*
> +	 * There is some code that runs in interrupts but for which
> +	 * in_interrupt() returns false (e.g. preempt_schedule_irq()).
> +	 * READ_ONCE()/barrier() effectively provides load-acquire wrt
> +	 * interrupts, there are paired barrier()/WRITE_ONCE() in
> +	 * kcov_ioctl_locked().
> +	 */
> +	barrier();
> +	if (mode != needed_mode)
> +		return false;
> +	return true;

This would be simpler as:
	
	return mode == needed_mode;

[...]

> +	area = t->kcov_area;
> +	/* The first 64-bit word is the number of subsequent PCs. */
> +	pos = READ_ONCE(area[0]) + 1;
> +	if (likely(pos < t->kcov_size)) {
> +		area[pos] = ip;
> +		WRITE_ONCE(area[0], pos);

Not a new problem, but if the area for one thread is mmap'd, and read by
another thread, these two writes could be seen out-of-order, since we
don't have an smp_wmb() between them.

I guess Syzkaller doesn't read the mmap'd kcov file from another thread?

>  	}
>  }
>  EXPORT_SYMBOL(__sanitizer_cov_trace_pc);
>  
> +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
> +static void write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip)
> +{
> +	struct task_struct *t;
> +	u64 *area;
> +	u64 count, start_index, end_pos, max_pos;
> +
> +	t = current;
> +	if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t))
> +		return;
> +
> +#ifdef CONFIG_RANDOMIZE_BASE
> +	ip -= kaslr_offset();
> +#endif

Given we have this in two places, it might make sense to have a helper
like:

unsigned long canonicalize_ip(unsigned long ip)
{
#ifdef CONFIG_RANDOMIZE_BASE
	ip -= kaslr_offset();
#endif
	return ip;
}

... to minimize the ifdeffery elsewhere.

> +
> +	/*
> +	 * We write all comparison arguments and types as u64.
> +	 * The buffer was allocated for t->kcov_size unsigned longs.
> +	 */
> +	area = (u64 *)t->kcov_area;
> +	max_pos = t->kcov_size * sizeof(unsigned long);
> +
> +	count = READ_ONCE(area[0]);
> +
> +	/* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
> +	start_index = 1 + count * KCOV_WORDS_PER_CMP;
> +	end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
> +	if (likely(end_pos <= max_pos)) {
> +		area[start_index] = type;
> +		area[start_index + 1] = arg1;
> +		area[start_index + 2] = arg2;
> +		area[start_index + 3] = ip;
> +		WRITE_ONCE(area[0], count + 1);

That ordering problem applies here, too.

Thanks,
Mark.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

WARNING: multiple messages have this Message-ID (diff)
From: Mark Rutland <mark.rutland@arm.com>
To: Alexander Potapenko <glider@google.com>
Cc: akpm@linux-foundation.org, alex.popov@linux.com,
	aryabinin@virtuozzo.com, quentin.casasnovas@oracle.com,
	dvyukov@google.com, andreyknvl@google.com, keescook@chromium.org,
	vegard.nossum@oracle.com, syzkaller@googlegroups.com,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 1/3] kcov: support comparison operands collection
Date: Mon, 9 Oct 2017 16:46:10 +0100	[thread overview]
Message-ID: <20171009154610.GA22534@leverpostej> (raw)
In-Reply-To: <20171009150521.82775-1-glider@google.com>

Hi,

I look forward to using this! :)

I just have afew comments below.

On Mon, Oct 09, 2017 at 05:05:19PM +0200, Alexander Potapenko wrote:
> +/*
> + * Defines the format for the types of collected comparisons.
> + */
> +enum kcov_cmp_type {
> +	/*
> +	 * LSB shows whether one of the arguments is a compile-time constant.
> +	 */
> +	KCOV_CMP_CONST = 1,
> +	/*
> +	 * Second and third LSBs contain the size of arguments (1/2/4/8 bytes).
> +	 */
> +	KCOV_CMP_SIZE1 = 0,
> +	KCOV_CMP_SIZE2 = 2,
> +	KCOV_CMP_SIZE4 = 4,
> +	KCOV_CMP_SIZE8 = 6,
> +	KCOV_CMP_SIZE_MASK = 6,
> +};

Given that LSB is meant to be OR-ed in, (and hence combinations of
values are meaningful) I don't think it makes sense for this to be an
enum. This would clearer as something like:

/*
 * The format for the types of collected comparisons.
 *
 * Bit 0 shows whether one of the arguments is a compile-time constant.
 * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes.
 */
#define	KCOV_CMP_CONST		(1 << 0)
#define KCOV_CMP_SIZE(n)	((n) << 1)
#define KCOV_CMP_MASK		KCOV_CMP_SIZE(3)

... I note that a few places in the kernel use a 128-bit type. Are
128-bit comparisons not instrumented?

[...]

> +static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
> +{
> +	enum kcov_mode mode;
> +
> +	/*
> +	 * We are interested in code coverage as a function of a syscall inputs,
> +	 * so we ignore code executed in interrupts.
> +	 */
> +	if (!t || !in_task())
> +		return false;

This !t check can go, as with the one in __sanitizer_cov_trace_pc, since
t is always current, and therefore cannot be NULL.

IIRC there's a patch queued for that, which this may conflict with.

> +	mode = READ_ONCE(t->kcov_mode);
> +	/*
> +	 * There is some code that runs in interrupts but for which
> +	 * in_interrupt() returns false (e.g. preempt_schedule_irq()).
> +	 * READ_ONCE()/barrier() effectively provides load-acquire wrt
> +	 * interrupts, there are paired barrier()/WRITE_ONCE() in
> +	 * kcov_ioctl_locked().
> +	 */
> +	barrier();
> +	if (mode != needed_mode)
> +		return false;
> +	return true;

This would be simpler as:
	
	return mode == needed_mode;

[...]

> +	area = t->kcov_area;
> +	/* The first 64-bit word is the number of subsequent PCs. */
> +	pos = READ_ONCE(area[0]) + 1;
> +	if (likely(pos < t->kcov_size)) {
> +		area[pos] = ip;
> +		WRITE_ONCE(area[0], pos);

Not a new problem, but if the area for one thread is mmap'd, and read by
another thread, these two writes could be seen out-of-order, since we
don't have an smp_wmb() between them.

I guess Syzkaller doesn't read the mmap'd kcov file from another thread?

>  	}
>  }
>  EXPORT_SYMBOL(__sanitizer_cov_trace_pc);
>  
> +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS
> +static void write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip)
> +{
> +	struct task_struct *t;
> +	u64 *area;
> +	u64 count, start_index, end_pos, max_pos;
> +
> +	t = current;
> +	if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t))
> +		return;
> +
> +#ifdef CONFIG_RANDOMIZE_BASE
> +	ip -= kaslr_offset();
> +#endif

Given we have this in two places, it might make sense to have a helper
like:

unsigned long canonicalize_ip(unsigned long ip)
{
#ifdef CONFIG_RANDOMIZE_BASE
	ip -= kaslr_offset();
#endif
	return ip;
}

... to minimize the ifdeffery elsewhere.

> +
> +	/*
> +	 * We write all comparison arguments and types as u64.
> +	 * The buffer was allocated for t->kcov_size unsigned longs.
> +	 */
> +	area = (u64 *)t->kcov_area;
> +	max_pos = t->kcov_size * sizeof(unsigned long);
> +
> +	count = READ_ONCE(area[0]);
> +
> +	/* Every record is KCOV_WORDS_PER_CMP 64-bit words. */
> +	start_index = 1 + count * KCOV_WORDS_PER_CMP;
> +	end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64);
> +	if (likely(end_pos <= max_pos)) {
> +		area[start_index] = type;
> +		area[start_index + 1] = arg1;
> +		area[start_index + 2] = arg2;
> +		area[start_index + 3] = ip;
> +		WRITE_ONCE(area[0], count + 1);

That ordering problem applies here, too.

Thanks,
Mark.

  parent reply	other threads:[~2017-10-09 15:47 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-09 15:05 [PATCH v2 1/3] kcov: support comparison operands collection Alexander Potapenko
2017-10-09 15:05 ` Alexander Potapenko
2017-10-09 15:05 ` [PATCH v2 2/3] Makefile: support flag -fsanitizer-coverage=trace-cmp Alexander Potapenko
2017-10-09 15:05   ` Alexander Potapenko
2017-10-09 15:53   ` Andrey Ryabinin
2017-10-09 15:53     ` Andrey Ryabinin
2017-10-10 15:28     ` Alexander Potapenko
2017-10-10 15:28       ` Alexander Potapenko
2017-10-10 21:53   ` kbuild test robot
2017-10-09 15:05 ` [PATCH v2 3/3] kcov: update documentation Alexander Potapenko
2017-10-09 15:05   ` Alexander Potapenko
2017-10-09 15:46 ` Mark Rutland [this message]
2017-10-09 15:46   ` [PATCH v2 1/3] kcov: support comparison operands collection Mark Rutland
2017-10-09 18:15   ` Dmitry Vyukov
2017-10-09 18:15     ` Dmitry Vyukov
2017-10-09 18:37     ` Mark Rutland
2017-10-09 18:37       ` Mark Rutland
2017-10-09 18:46       ` Dmitry Vyukov
2017-10-09 18:46         ` Dmitry Vyukov
2017-10-10  9:56         ` Mark Rutland
2017-10-10  9:56           ` Mark Rutland
2017-10-10 15:28   ` Alexander Potapenko
2017-10-10 15:28     ` Alexander Potapenko
2017-10-10 15:34     ` Dmitry Vyukov
2017-10-10 15:34       ` Dmitry Vyukov
2017-10-11  9:56       ` Alexander Potapenko
2017-10-11  9:56         ` Alexander Potapenko

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=20171009154610.GA22534@leverpostej \
    --to=mark.rutland@arm.com \
    --cc=akpm@linux-foundation.org \
    --cc=alex.popov@linux.com \
    --cc=andreyknvl@google.com \
    --cc=aryabinin@virtuozzo.com \
    --cc=dvyukov@google.com \
    --cc=glider@google.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=quentin.casasnovas@oracle.com \
    --cc=syzkaller@googlegroups.com \
    --cc=vegard.nossum@oracle.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.