Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lirc ioctl decoding #208

Merged
merged 1 commit into from Feb 21, 2022
Merged

Add lirc ioctl decoding #208

merged 1 commit into from Feb 21, 2022

Conversation

seanyoung
Copy link
Contributor

it would be useful to decode read/write on the chardev too, but this would require tracking what lirc mode the file is in (from the ioctls), and having a hook on read/write. Not sure that is something strace can do.

Copy link
Member

@ldv-alt ldv-alt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution, but the decoder looks too old-fashioned,
please have a look at other ioctl decoders, e.g. src/gpio_ioctl.c and tests/gpio.

src/lirc.c Outdated Show resolved Hide resolved
src/lirc.c Outdated
Comment on lines 10 to 26
static const struct features {
int flag;
const char *name;
} features[] = {
{ LIRC_CAN_REC_SCANCODE, "LIRC_CAN_REC_SCANCODE" },
{ LIRC_CAN_REC_MODE2, "LIRC_CAN_REC_MODE2" },
{ LIRC_CAN_GET_REC_RESOLUTION, "LIRC_CAN_GET_REC_RESOLUTION" },
{ LIRC_CAN_SEND_PULSE, "LIRC_CAN_SEND_PULSE" },
{ LIRC_CAN_SET_TRANSMITTER_MASK, "LIRC_CAN_SET_TRANSMITTER_MASK" },
{ LIRC_CAN_SET_SEND_CARRIER, "LIRC_CAN_SET_SEND_CARRIER" },
{ LIRC_CAN_SET_SEND_DUTY_CYCLE, "LIRC_CAN_SET_SEND_DUTY_CYCLE" },
{ LIRC_CAN_SET_REC_CARRIER, "LIRC_CAN_SET_REC_CARRIER" },
{ LIRC_CAN_SET_REC_CARRIER_RANGE, "LIRC_CAN_SET_REC_CARRIER_RANGE" },
{ LIRC_CAN_USE_WIDEBAND_RECEIVER, "LIRC_CAN_USE_WIDEBAND_RECEIVER" },
{ LIRC_CAN_MEASURE_CARRIER, "LIRC_CAN_MEASURE_CARRIER" },
{ LIRC_CAN_SET_REC_TIMEOUT, "LIRC_CAN_SET_REC_TIMEOUT" },
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We replaced this approach with xlat files roughly 8 years ago, please create a xlat file instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done this using xlat now. This is much nicer

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that linux/lirc.h is bundled, there is no need to test LIRC_* constants,
so please add #unconditional to these xlat files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

src/lirc.c Outdated Show resolved Hide resolved
src/lirc.c Outdated Show resolved Hide resolved
src/lirc.c Outdated
Comment on lines 26 to 41
switch (code) {
case LIRC_GET_FEATURES:
printflags(lirc_features, value, "LIRC_CAN_???");
break;
case LIRC_GET_SEND_MODE:
case LIRC_GET_REC_MODE:
case LIRC_SET_SEND_MODE:
case LIRC_SET_REC_MODE:
printxval(lirc_modes, value, "LIRC_MODE_???");
break;
default:
PRINT_VAL_D(value);
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since value is obtained from tracee's memory, its printing should be wrapped with

tprint_indirect_begin();
...
tprint_indirect_end();

See e.g. decode_fs_ioc_flags as an example.

Also, tprint_arg_next(); should precede any printing, this includes umove_or_printaddr.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, done

@seanyoung
Copy link
Contributor Author

Ready for review

Copy link
Member

@ldv-alt ldv-alt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very impressive for a first time test.
See my comments above.

tests/gen_tests.in Show resolved Hide resolved
printf("ioctl(-1, %s, [LIRC_MODE_LIRCCODE]) = %s\n",
XLAT_STR(LIRC_SET_REC_MODE), errstr);

// read ioctl
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/* read ioctls */

To make the test work in case of no syscall tampering,
the return value of do_ioctl should be tested and acted appropriately,
see, for eexample, tests/ioctl_gpio.c

also, please add do_ioctl(LIRC_GET_FEATURES, 0); or something like this to cover the true branch of if (umove_or_printaddr(tcp, arg, &value)).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, there is ioctl(-1, LIRC_GET_FEATURES, 0) in INJECT_RETVAL variant, it's probably enough.
At least the coverage test reports that all lines are covered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this case. Please let me know what you think.

@codecov
Copy link

codecov bot commented Feb 3, 2022

Codecov Report

Merging #208 (8da7ffb) into master (83a18e2) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #208   +/-   ##
=======================================
  Coverage   89.96%   89.96%           
=======================================
  Files         287      288    +1     
  Lines       24049    24073   +24     
=======================================
+ Hits        21635    21658   +23     
- Misses       2414     2415    +1     
Impacted Files Coverage Δ
src/defs.h 100.00% <ø> (ø)
src/ioctl.c 81.67% <100.00%> (+0.14%) ⬆️
src/lirc_ioctl.c 100.00% <100.00%> (ø)
src/pidns.c 94.44% <0.00%> (-0.51%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 83a18e2...8da7ffb. Read the comment docs.

@seanyoung
Copy link
Contributor Author

I've also changed the decoding to printing the unsigned value. That's how the kernel interprets the value.

@@ -200,6 +200,8 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
ioctl_kd-success-s1024-Xabbrev \
ioctl_kd-success-s1024-Xraw \
ioctl_kd-success-s1024-Xverbose \
ioctl_lirc \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ioctl_lirc is redundant in this list because it's listed in pure_executables.list;
ioctl_lirc-success has to be kept here, see below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -209,6 +209,8 @@ ioctl_hdio-v-Xabbrev
ioctl_hdio-v-Xraw
ioctl_hdio-v-Xverbose
ioctl_inotify
ioctl_lirc
ioctl_lirc-success
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*-success executables shouldn't be listed here because they are not pure enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@seanyoung
Copy link
Contributor Author

Ready for the next round of review

@esyr
Copy link
Member

esyr commented Feb 7, 2022

A copy of an e-mail with Message-ID: <20220204061024.GA10415@obsidian>[1] that for whatever reason hasn't been forwarded to github:

On Thu, Feb 03, 2022 at 07:51:18AM -0800, Sean Young via Strace-devel wrote:
> Ready for the next round of review

On Wed, Jan 26, 2022 at 10:22:01AM +0000, Sean Young wrote:
> Signed-off-by: Sean Young <sean@mess.org>
> ---
>  NEWS                                    |   1 +
>  bundled/Makefile.am                     |   1 +
>  bundled/linux/include/uapi/linux/lirc.h | 232 ++++++++++++++++++++++++++++++++
>  src/Makefile.am                         |   1 +
>  src/defs.h                              |   1 +
>  src/ioctl.c                             |   2 +
>  src/lirc.c                              |  46 +++++++
>  src/xlat/lirc_features.in               |  13 ++
>  src/xlat/lirc_modes.in                  |   6 +
>  tests/.gitignore                        |   2 +
>  tests/Makefile.am                       |   1 +
>  tests/gen_tests.in                      |   2 +
>  tests/ioctl_lirc-success.c              |   2 +
>  tests/ioctl_lirc.c                      | 173 ++++++++++++++++++++++++
>  tests/pure_executables.list             |   1 +
>  15 files changed, 484 insertions(+)
>  create mode 100644 bundled/linux/include/uapi/linux/lirc.h
>  create mode 100644 src/lirc.c
>  create mode 100644 src/xlat/lirc_features.in
>  create mode 100644 src/xlat/lirc_modes.in
>  create mode 100644 tests/ioctl_lirc-success.c
>  create mode 100644 tests/ioctl_lirc.c
> 
> diff --git a/NEWS b/NEWS
> index 6c8f859..c933d11 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -12,6 +12,7 @@ Noteworthy changes in release ?.?? (????-??-??)
>    * Implemented decoding of PR_SET_VMA operation of prctl syscall.
>    * Updated lists of FAN_*, IORING_*, IOSQE_*, KVM_*, MODULE_INIT_*, TCA_ACT_*,
>      and *_MAGIC constants.
> +  * Implemented decoding of lirc ioctl commands.

"LIRC", maybe?  I've thought it's an abbreviation.

> diff --git a/src/Makefile.am b/src/Makefile.am
> index dc9fd93..c000593 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -184,6 +184,7 @@ libstrace_a_SOURCES =	\
>  	link.c		\
>  	linux/x32/asm_stat.h \
>  	linux/x86_64/asm_stat.h \
> +	lirc.c		\

I think for ioctl interfaces the naming is *_ioctl.c as of late,
but I have no strong preference here (and there are files like dm.c).

> diff --git a/src/lirc.c b/src/lirc.c
> new file mode 100644
> index 0000000..6459dc2
> --- /dev/null
> +++ b/src/lirc.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright (c) 2022 Sean Young <sean@mess.org>
> + *
> + * SPDX-License-Identifier: LGPL-2.1-or-later
> + */
> +
> +#include "defs.h"
> +#include <linux/lirc.h>
> +#include "xlat/lirc_features.h"
> +#include "xlat/lirc_modes.h"
> +
> +int
> +lirc_ioctl(struct tcb *const tcp, const unsigned int code,
> +	   const kernel_ulong_t arg)
> +{
> +	unsigned int value;
> +

> +	if (_IOC_DIR(code) == _IOC_READ && entering(tcp))
> +		return 0;
> +
> +	tprint_arg_next();
> +

It is nicer to return after printing the comma (even though it leads
to a bit more ugly code), as this leads to

    scname(arg1, <unfinished...>
    <resumed scname> arg2...

output instead of

    scname(arg1<unfinished>
    <resumed scname> , arg2...

> +	switch (code) {
> +	case LIRC_GET_FEATURES:
> +		printflags(lirc_features, value, "LIRC_CAN_???");
> +		break;
> +	case LIRC_GET_SEND_MODE:
> +	case LIRC_GET_REC_MODE:
> +	case LIRC_SET_SEND_MODE:
> +	case LIRC_SET_REC_MODE:
> +		printxval(lirc_modes, value, "LIRC_MODE_???");
> +		break;
> +	default:
> +		PRINT_VAL_U(value);

The main issue here is that this code assumes that only LIRC_* ioctls
have 'i' IOC type, which is generally not true (it is shared with i8k,
IPMI, IIO and a couple of i915 ioctl commands).  This can be approached
either by performing early filtering by ioctl cmd (like it is done in
dm), or by explicitly listing all supported ioctls in the decoding switch
statements and returning RVAL_DECODED in the default case (as it is done
in seccomp and kd ioctl decoders, for example).  Both options will lead
to some duplication, though, either with listing all of the LIRC
commands, or re-factoring code to handle tracee memory reading and
printing inside 

I think that at least LIRC_SET_TRANSMITTER_MASK command argument is worth
printing in hexadecimal and not decimal as it seems to be a bit mask.

There is a set of functions for printing an integer referenced
by an address, printnum_*, but I'm not sure if it is worth using here.

> diff --git a/src/xlat/lirc_features.in b/src/xlat/lirc_features.in
> new file mode 100644
> index 0000000..6bd45a4
> --- /dev/null
> +++ b/src/xlat/lirc_features.in
> @@ -0,0 +1,13 @@
> +#unconditional
> +LIRC_CAN_REC_SCANCODE
> +LIRC_CAN_REC_MODE2
> +LIRC_CAN_GET_REC_RESOLUTION
> +LIRC_CAN_SEND_PULSE
> +LIRC_CAN_SET_TRANSMITTER_MASK
> +LIRC_CAN_SET_SEND_CARRIER
> +LIRC_CAN_SET_SEND_DUTY_CYCLE
> +LIRC_CAN_SET_REC_CARRIER
> +LIRC_CAN_SET_REC_CARRIER_RANGE
> +LIRC_CAN_USE_WIDEBAND_RECEIVER
> +LIRC_CAN_MEASURE_CARRIER
> +LIRC_CAN_SET_REC_TIMEOUT

I'm unable grok the order of this xlat;  usually, flags are sorted from the
LSB to MSB, unless there are reasons to have a different order (usually,
when a symbolic value represents a combination of flags).  There are also
LIRC_CAN_SEND_RAW, LIRC_CAN_SEND_MODE2, LIRC_CAN_SEND_SCANCODE,
LIRC_CAN_SEND_LIRCCODE, LIRC_CAN_REC_RAW, LIRC_CAN_REC_PULSE,
LIRC_CAN_REC_LIRCCODE, LIRC_CAN_SET_REC_FILTER, LIRC_CAN_GET_REC_RESOLUTION,
and LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE flags seem to be missing.

> diff --git a/tests/ioctl_lirc.c b/tests/ioctl_lirc.c
> new file mode 100644
> index 0000000..6f7fdc0
> --- /dev/null
> +++ b/tests/ioctl_lirc.c

> +	value = 12000;
> +	do_ioctl(LIRC_SET_REC_TIMEOUT, &value);
> +	printf("ioctl(-1, %s, [12000]) = %s\n",
> +	       XLAT_STR(LIRC_SET_REC_TIMEOUT), errstr);

XLAT_STR macro is used for generating a string in accordance with
XLAT_VERBOSE and XLAT_RAW macro constant settings, which are used
for testing output of strace with different xlat verbosity settings (see
*-X{abbrev,raw,verbose}.c tests for an example), otherwise it is
useless.  On the other hand, having such tests would be nice
for a decoder that prints named constants, even though xlat usage
in the lirc decoder currently rather trivial.

It is also worth checking strace behaviour when the memory can't
be accessed or the pointer is NULL.

> +	value = 40000;
> +	do_ioctl(LIRC_SET_REC_CARRIER_RANGE, &value);
> +	printf("ioctl(-1, IPMICTL_SET_MAINTENANCE_MODE_CMD or %s, [40000]) = %s\n",
> +	       XLAT_STR(LIRC_SET_REC_CARRIER_RANGE), errstr);

This will generate incorrect if ether XLAT_VERBOSE or XLAT_RAW are set.

Also, this output probably signifies the issue with assuming that
every command is a LIRC command, as IPMICTL_SET_MAINTENANCE_MODE_CMD
argument is a named constant (IPMI_MAINTENANCE_MODE_*).  But, alas,
strace doesn't currently implement capabilities that would allow
to narrow down the ioctl cmd selection based on ioctl fd.

> +	value = 2;
> +	do_ioctl(LIRC_SET_SEND_MODE, &value);
> +	printf("ioctl(-1, %s, [LIRC_MODE_PULSE]) = %s\n",
> +	       XLAT_STR(LIRC_SET_SEND_MODE), errstr);

Either LIRC_MODE_PULSE is to be wrapped within XLAT_STR in order to
enable proper string generation in different xla modes, or XLAT_STR
usage for LIRC_SET_SEND_MODE is redundant.  Also, it is worth checking
that 3 (and probably some other values) is decoded as an unknown mode
and not a combination of LIRC_MODE_RAW and LIRC_MODE_PULSE: it is not
uncommon to mix up printxlat and printflags usage.

Also, LIRC_SET_TRANSMITTER_MASK doesn't seem to be checked.

> +	// read ioctl

C++-style comments are not generally used in strace code.

Also, it is worth checking decoding of the read ioctl command when they
can't read (due to non-zero syscall return value) as well, to avoid accidentally
decoding of an argument on entering when it is supposed to be decoded in exiting.

> +#ifdef INJECT_RETVAL
> +	value = LIRC_CAN_SEND_PULSE | LIRC_CAN_SET_SEND_DUTY_CYCLE | LIRC_CAN_GET_REC_RESOLUTION | LIRC_CAN_USE_WIDEBAND_RECEIVER;
> +	do_ioctl(LIRC_GET_FEATURES, &value);
> +	printf("ioctl(-1, %s, [LIRC_CAN_GET_REC_RESOLUTION|LIRC_CAN_SEND_PULSE|LIRC_CAN_SET_SEND_DUTY_CYCLE|LIRC_CAN_USE_WIDEBAND_RECEIVER]) = %s\n",
> +	       XLAT_STR(LIRC_GET_FEATURES), errstr);

For flag sets, it is also worth checking how 0 or unknown flags are
decoded.

Also, these lines are over-length, strace source code tends to keep
line length under 80.

> +	value = 1;
> +	do_ioctl(LIRC_GET_REC_MODE, &value);
> +	printf("ioctl(-1, %s, [LIRC_MODE_RAW]) = %s\n",
> +	       XLAT_STR(LIRC_GET_REC_MODE), errstr);
> +
> +	do_ioctl(LIRC_GET_SEND_MODE, &value);
> +	printf("ioctl(-1, %s, [LIRC_MODE_PULSE]) = %s\n",
> +	       XLAT_STR(LIRC_GET_SEND_MODE), errstr);
> +
> +	value = 120;
> +	do_ioctl(LIRC_GET_REC_RESOLUTION, &value);
> +	printf("ioctl(-1, %s, [120]) = %s\n",
> +	       XLAT_STR(LIRC_GET_REC_RESOLUTION), errstr);
> +
> +	value = 120000;
> +	do_ioctl(LIRC_GET_REC_TIMEOUT, &value);
> +	printf("ioctl(-1, %s, [120000]) = %s\n",
> +	       XLAT_STR(LIRC_GET_REC_TIMEOUT), errstr);
> +
> +	value = 1100;
> +	do_ioctl(LIRC_GET_MIN_TIMEOUT, &value);
> +	printf("ioctl(-1, I2OVALIDATE or %s, [1100]) = %s\n",
> +	       XLAT_STR(LIRC_GET_MIN_TIMEOUT), errstr);
> +
> +	value = 10100;
> +	do_ioctl(LIRC_GET_MAX_TIMEOUT, &value);
> +	printf("ioctl(-1, %s, [10100]) = %s\n",
> +	       XLAT_STR(LIRC_GET_MAX_TIMEOUT), errstr);

LIRC_GET_LENGTH commands doesn't seem to be checked.

[1] https://lists.strace.io/pipermail/strace-devel/2022-February/010957.html

@seanyoung
Copy link
Contributor Author

A copy of an e-mail with Message-ID: <20220204061024.GA10415@obsidian>[1] that for whatever reason hasn't been forwarded to github:

On Thu, Feb 03, 2022 at 07:51:18AM -0800, Sean Young via Strace-devel wrote:
> Ready for the next round of review

On Wed, Jan 26, 2022 at 10:22:01AM +0000, Sean Young wrote:
> Signed-off-by: Sean Young <sean@mess.org>
> ---
>  NEWS                                    |   1 +
>  bundled/Makefile.am                     |   1 +
>  bundled/linux/include/uapi/linux/lirc.h | 232 ++++++++++++++++++++++++++++++++
>  src/Makefile.am                         |   1 +
>  src/defs.h                              |   1 +
>  src/ioctl.c                             |   2 +
>  src/lirc.c                              |  46 +++++++
>  src/xlat/lirc_features.in               |  13 ++
>  src/xlat/lirc_modes.in                  |   6 +
>  tests/.gitignore                        |   2 +
>  tests/Makefile.am                       |   1 +
>  tests/gen_tests.in                      |   2 +
>  tests/ioctl_lirc-success.c              |   2 +
>  tests/ioctl_lirc.c                      | 173 ++++++++++++++++++++++++
>  tests/pure_executables.list             |   1 +
>  15 files changed, 484 insertions(+)
>  create mode 100644 bundled/linux/include/uapi/linux/lirc.h
>  create mode 100644 src/lirc.c
>  create mode 100644 src/xlat/lirc_features.in
>  create mode 100644 src/xlat/lirc_modes.in
>  create mode 100644 tests/ioctl_lirc-success.c
>  create mode 100644 tests/ioctl_lirc.c
> 
> diff --git a/NEWS b/NEWS
> index 6c8f859..c933d11 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -12,6 +12,7 @@ Noteworthy changes in release ?.?? (????-??-??)
>    * Implemented decoding of PR_SET_VMA operation of prctl syscall.
>    * Updated lists of FAN_*, IORING_*, IOSQE_*, KVM_*, MODULE_INIT_*, TCA_ACT_*,
>      and *_MAGIC constants.
> +  * Implemented decoding of lirc ioctl commands.

"LIRC", maybe?  I've thought it's an abbreviation.

Fixed.

diff --git a/src/Makefile.am b/src/Makefile.am
index dc9fd93..c000593 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -184,6 +184,7 @@ libstrace_a_SOURCES =
link.c
linux/x32/asm_stat.h
linux/x86_64/asm_stat.h \

  • lirc.c \

I think for ioctl interfaces the naming is *_ioctl.c as of late,
but I have no strong preference here (and there are files like dm.c).

Rernamed to lirc_ioctl.c

diff --git a/src/lirc.c b/src/lirc.c
new file mode 100644
index 0000000..6459dc2
--- /dev/null
+++ b/src/lirc.c
@@ -0,0 +1,46 @@
+/*

    • SPDX-License-Identifier: LGPL-2.1-or-later
  • */

+#include "defs.h"
+#include <linux/lirc.h>
+#include "xlat/lirc_features.h"
+#include "xlat/lirc_modes.h"
+
+int
+lirc_ioctl(struct tcb *const tcp, const unsigned int code,

  •  const kernel_ulong_t arg)
    

+{

  • unsigned int value;
  • if (_IOC_DIR(code) == _IOC_READ && entering(tcp))
  •   return 0;
    
  • tprint_arg_next();

It is nicer to return after printing the comma (even though it leads
to a bit more ugly code), as this leads to

scname(arg1, <unfinished...>
<resumed scname> arg2...

output instead of

scname(arg1<unfinished>
<resumed scname> , arg2...

If I tried to fix this, the output of:

        do_ioctl(LIRC_GET_FEATURES, (unsigned int*)0x40000);

becomes

ioctl(-1, LIRC_GET_FEATURES, , 0x40000) 

Which we don't want.

  • switch (code) {
  • case LIRC_GET_FEATURES:
  •   printflags(lirc_features, value, "LIRC_CAN_???");
    
  •   break;
    
  • case LIRC_GET_SEND_MODE:
  • case LIRC_GET_REC_MODE:
  • case LIRC_SET_SEND_MODE:
  • case LIRC_SET_REC_MODE:
  •   printxval(lirc_modes, value, "LIRC_MODE_???");
    
  •   break;
    
  • default:
  •   PRINT_VAL_U(value);
    

The main issue here is that this code assumes that only LIRC_* ioctls
have 'i' IOC type, which is generally not true (it is shared with i8k,
IPMI, IIO and a couple of i915 ioctl commands). This can be approached
either by performing early filtering by ioctl cmd (like it is done in
dm), or by explicitly listing all supported ioctls in the decoding switch
statements and returning RVAL_DECODED in the default case (as it is done
in seccomp and kd ioctl decoders, for example). Both options will lead
to some duplication, though, either with listing all of the LIRC
commands, or re-factoring code to handle tracee memory reading and
printing inside

I've added an early switch like dm does.

I think that at least LIRC_SET_TRANSMITTER_MASK command argument is worth
printing in hexadecimal and not decimal as it seems to be a bit mask.

Fixed. Binary would be nicer than hex though.

There is a set of functions for printing an integer referenced
by an address, printnum_*, but I'm not sure if it is worth using here.

diff --git a/src/xlat/lirc_features.in b/src/xlat/lirc_features.in
new file mode 100644
index 0000000..6bd45a4
--- /dev/null
+++ b/src/xlat/lirc_features.in
@@ -0,0 +1,13 @@
+#unconditional
+LIRC_CAN_REC_SCANCODE
+LIRC_CAN_REC_MODE2
+LIRC_CAN_GET_REC_RESOLUTION
+LIRC_CAN_SEND_PULSE
+LIRC_CAN_SET_TRANSMITTER_MASK
+LIRC_CAN_SET_SEND_CARRIER
+LIRC_CAN_SET_SEND_DUTY_CYCLE
+LIRC_CAN_SET_REC_CARRIER
+LIRC_CAN_SET_REC_CARRIER_RANGE
+LIRC_CAN_USE_WIDEBAND_RECEIVER
+LIRC_CAN_MEASURE_CARRIER
+LIRC_CAN_SET_REC_TIMEOUT

I'm unable grok the order of this xlat; usually, flags are sorted from the
LSB to MSB, unless there are reasons to have a different order (usually,
when a symbolic value represents a combination of flags).

There was no order. I've ordered them.

There are also
LIRC_CAN_SEND_RAW, LIRC_CAN_SEND_MODE2, LIRC_CAN_SEND_SCANCODE,
LIRC_CAN_SEND_LIRCCODE, LIRC_CAN_REC_RAW, LIRC_CAN_REC_PULSE,
LIRC_CAN_REC_LIRCCODE, LIRC_CAN_SET_REC_FILTER, LIRC_CAN_GET_REC_RESOLUTION,
and LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE flags seem to be missing.

I've added LIRC_CAN_REC_LIRCCODE, LIRC_CAN_SEND_LIRCCODE (may be used in
pre-4.16 kernels) and LIRC_CAN_GET_REC_RESOLUTION was just missing. The other
onces were never implemented, out-of-tree or not. They should have never
been added to the header in the first place.

diff --git a/tests/ioctl_lirc.c b/tests/ioctl_lirc.c
new file mode 100644
index 0000000..6f7fdc0
--- /dev/null
+++ b/tests/ioctl_lirc.c

  • value = 12000;
  • do_ioctl(LIRC_SET_REC_TIMEOUT, &value);
  • printf("ioctl(-1, %s, [12000]) = %s\n",
  •      XLAT_STR(LIRC_SET_REC_TIMEOUT), errstr);
    

XLAT_STR macro is used for generating a string in accordance with
XLAT_VERBOSE and XLAT_RAW macro constant settings, which are used
for testing output of strace with different xlat verbosity settings (see
*-X{abbrev,raw,verbose}.c tests for an example), otherwise it is
useless. On the other hand, having such tests would be nice
for a decoder that prints named constants, even though xlat usage
in the lirc decoder currently rather trivial.

Removed XLAT_STR()

It is also worth checking strace behaviour when the memory can't
be accessed or the pointer is NULL.

Added tests.

  • value = 40000;
  • do_ioctl(LIRC_SET_REC_CARRIER_RANGE, &value);
  • printf("ioctl(-1, IPMICTL_SET_MAINTENANCE_MODE_CMD or %s, [40000]) = %s\n",
  •      XLAT_STR(LIRC_SET_REC_CARRIER_RANGE), errstr);
    

This will generate incorrect if ether XLAT_VERBOSE or XLAT_RAW are set.

Also, this output probably signifies the issue with assuming that
every command is a LIRC command, as IPMICTL_SET_MAINTENANCE_MODE_CMD
argument is a named constant (IPMI_MAINTENANCE_MODE_*). But, alas,
strace doesn't currently implement capabilities that would allow
to narrow down the ioctl cmd selection based on ioctl fd.

Alas.

  • value = 2;
  • do_ioctl(LIRC_SET_SEND_MODE, &value);
  • printf("ioctl(-1, %s, [LIRC_MODE_PULSE]) = %s\n",
  •      XLAT_STR(LIRC_SET_SEND_MODE), errstr);
    

Either LIRC_MODE_PULSE is to be wrapped within XLAT_STR in order to
enable proper string generation in different xla modes, or XLAT_STR
usage for LIRC_SET_SEND_MODE is redundant.

XLAT_STR() removed.

Also, it is worth checking
that 3 (and probably some other values) is decoded as an unknown mode
and not a combination of LIRC_MODE_RAW and LIRC_MODE_PULSE: it is not
uncommon to mix up printxlat and printflags usage.

Add tests for this.

Also, LIRC_SET_TRANSMITTER_MASK doesn't seem to be checked.

  • // read ioctl

C++-style comments are not generally used in strace code.

I've changed to 80s style comments.

Also, it is worth checking decoding of the read ioctl command when they
can't read (due to non-zero syscall return value) as well, to avoid accidentally
decoding of an argument on entering when it is supposed to be decoded in exiting.

I think that is tested now.

+#ifdef INJECT_RETVAL

  • value = LIRC_CAN_SEND_PULSE | LIRC_CAN_SET_SEND_DUTY_CYCLE | LIRC_CAN_GET_REC_RESOLUTION | LIRC_CAN_USE_WIDEBAND_RECEIVER;
  • do_ioctl(LIRC_GET_FEATURES, &value);
  • printf("ioctl(-1, %s, [LIRC_CAN_GET_REC_RESOLUTION|LIRC_CAN_SEND_PULSE|LIRC_CAN_SET_SEND_DUTY_CYCLE|LIRC_CAN_USE_WIDEBAND_RECEIVER]) = %s\n",
  •      XLAT_STR(LIRC_GET_FEATURES), errstr);
    

For flag sets, it is also worth checking how 0 or unknown flags are
decoded.

Tests added.

Also, these lines are over-length, strace source code tends to keep
line length under 80.

Fixed.

  • value = 1;
  • do_ioctl(LIRC_GET_REC_MODE, &value);
  • printf("ioctl(-1, %s, [LIRC_MODE_RAW]) = %s\n",
  •      XLAT_STR(LIRC_GET_REC_MODE), errstr);
    
  • do_ioctl(LIRC_GET_SEND_MODE, &value);
  • printf("ioctl(-1, %s, [LIRC_MODE_PULSE]) = %s\n",
  •      XLAT_STR(LIRC_GET_SEND_MODE), errstr);
    
  • value = 120;
  • do_ioctl(LIRC_GET_REC_RESOLUTION, &value);
  • printf("ioctl(-1, %s, [120]) = %s\n",
  •      XLAT_STR(LIRC_GET_REC_RESOLUTION), errstr);
    
  • value = 120000;
  • do_ioctl(LIRC_GET_REC_TIMEOUT, &value);
  • printf("ioctl(-1, %s, [120000]) = %s\n",
  •      XLAT_STR(LIRC_GET_REC_TIMEOUT), errstr);
    
  • value = 1100;
  • do_ioctl(LIRC_GET_MIN_TIMEOUT, &value);
  • printf("ioctl(-1, I2OVALIDATE or %s, [1100]) = %s\n",
  •      XLAT_STR(LIRC_GET_MIN_TIMEOUT), errstr);
    
  • value = 10100;
  • do_ioctl(LIRC_GET_MAX_TIMEOUT, &value);
  • printf("ioctl(-1, %s, [10100]) = %s\n",
  •      XLAT_STR(LIRC_GET_MAX_TIMEOUT), errstr);
    

LIRC_GET_LENGTH commands doesn't seem to be checked.

Yes, this is true. LIRC_GET_LENGTH is not a thing anymore since kernel v4.16,
however I've added a test.

@seanyoung
Copy link
Contributor Author

Ready for review again.

@ldv-alt
Copy link
Member

ldv-alt commented Feb 7, 2022 via email

@seanyoung
Copy link
Contributor Author

Could you try this: if (entering(tcp)) { tprint_arg_next(); if (_IOC_DIR(code) == _IOC_READ) return 0; }

That works, done.

@esyr
Copy link
Member

esyr commented Feb 10, 2022 via email

@esyr
Copy link
Member

esyr commented Feb 10, 2022 via email

@seanyoung
Copy link
Contributor Author

On Mon, Feb 07, 2022 at 10:58:01AM -0800, Sean Young wrote: > There are also > LIRC_CAN_SEND_RAW, LIRC_CAN_SEND_MODE2, LIRC_CAN_SEND_SCANCODE, > LIRC_CAN_SEND_LIRCCODE, LIRC_CAN_REC_RAW, LIRC_CAN_REC_PULSE, > LIRC_CAN_REC_LIRCCODE, LIRC_CAN_SET_REC_FILTER, LIRC_CAN_GET_REC_RESOLUTION, > and LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE flags seem to be missing. I've added LIRC_CAN_REC_LIRCCODE, LIRC_CAN_SEND_LIRCCODE (may be used in pre-4.16 kernels) and LIRC_CAN_GET_REC_RESOLUTION was just missing. The other onces were never implemented, out-of-tree or not. They should have never been added to the header in the first place.
Generally it is worth adding such constants to the xlat file in comments (with a reason why they were omitted), so those who are looking at it afterwards won't spend too much time to figure out they are missing (as it is not pointed out in the kernel header explicitly, only in the documentation).

I'm (slowly) removing these entries, see https://www.spinics.net/lists/linux-media/msg206895.html and https://git.linuxtv.org/media_stage.git/commit/?id=b2a90f4fcb146d0e033203ab646f0fd22cfa947f

@seanyoung
Copy link
Contributor Author

In strace, string literals tend to be wrapped to be under 80 columns
as well:

I've fixed the formatting issues and added your Reviewed-by: tag.

Thanks!

* NEWS: Mention this change.
* bundled/linux/include/uapi/linux/lirc.h: New file.
* bundled/Makefile.am (EXTRA_DIST): Add it.
* src/lirc_ioctl.c: New file.
* src/Makefile.am (libstrace_a_SOURCES): Add it.
* src/defs.h (DECL_IOCTL(lirc)): New declaration.
* src/ioctl.c (ioctl_decode) <case 'i'>: Call kd_ioctl.
* src/xlat/lirc_features.in: New file.
* src/xlat/lirc_modes.in: Likewise.
* tests/ioctl_lirc.c: New file.
* tests/ioctl_lirc-success.c: Likewise.
* tests/Makefile.am (check_PROGRAMS): Add ioctl_lirc-success.
* tests/gen_tests.in (ioctl_lirc, ioctl_lirc-success): New tests.
* tests/pure_executables.list: Add ioctl_lirc.
* tests/.gitignore: Add ioctl_lirc and ioctl_lirc-success.

Reviewed-by: Eugene Syromyatnikov <evgsyr@gmail.com>
Signed-off-by: Sean Young <sean@mess.org>
Reviewed-by: Dmitry V. Levin <ldv@strace.io>
@ldv-alt ldv-alt merged commit 8da7ffb into strace:master Feb 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants