From: "Thomas Weißschuh" <linux@weissschuh.net>
To: Roberto Sassu <roberto.sassu@huaweicloud.com>
Cc: zohar@linux.ibm.com, dmitry.kasatkin@gmail.com,
eric.snowberg@oracle.com, corbet@lwn.net, mcgrof@kernel.org,
petr.pavlu@suse.com, samitolvanen@google.com,
da.gomez@samsung.com, akpm@linux-foundation.org,
paul@paul-moore.com, jmorris@namei.org, serge@hallyn.com,
shuah@kernel.org, mcoquelin.stm32@gmail.com,
alexandre.torgue@foss.st.com, linux-integrity@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-api@vger.kernel.org, linux-modules@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kselftest@vger.kernel.org, wufan@linux.microsoft.com,
pbrobinson@gmail.com, zbyszek@in.waw.pl, hch@lst.de,
mjg59@srcf.ucam.org, pmatilai@redhat.com, jannh@google.com,
dhowells@redhat.com, jikos@kernel.org, mkoutny@suse.com,
ppavlu@suse.com, petr.vorel@gmail.com, mzerqung@0pointer.de,
kgold@linux.ibm.com, Roberto Sassu <roberto.sassu@huawei.com>
Subject: Re: [PATCH v6 01/15] lib: Add TLV parser
Date: Tue, 21 Jan 2025 14:29:17 +0100 [thread overview]
Message-ID: <c316b1be-d18f-4bb0-8434-bcc9236619df@t-8ch.de> (raw)
In-Reply-To: <20241119104922.2772571-2-roberto.sassu@huaweicloud.com>
Hi Robert,
On 2024-11-19 11:49:08+0100, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Add a parser of a generic Type-Length-Value (TLV) format:
>
> +--------------+--+---------+--------+---------+
> | field1 (u16) | len1 (u32) | value1 (u8 len1) |
> +--------------+------------+------------------+
> | ... | ... | ... |
> +--------------+------------+------------------+
> | fieldN (u16) | lenN (u32) | valueN (u8 lenN) |
> +--------------+------------+------------------+
Should mention that its big endian.
> Each adopter can define its own fields. The TLV parser does not need to be
> aware of those, but lets the adopter obtain the data and decide how to
"adopter" -> "user".
> continue.
>
> After processing a TLV entry, call the callback function also with the
> callback data provided by the adopter. The latter can decide how to
> interpret the TLV entry depending on the field ID.
>
> Nesting TLVs is also possible, the callback function can call tlv_parse()
> to parse the inner structure.
Given that we already have the netlink data structures, helpers and
infrastructure, what is the advantage over those?
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> ---
> MAINTAINERS | 8 +++
> include/linux/tlv_parser.h | 32 ++++++++++++
> include/uapi/linux/tlv_parser.h | 41 ++++++++++++++++
> lib/Kconfig | 3 ++
> lib/Makefile | 2 +
> lib/tlv_parser.c | 87 +++++++++++++++++++++++++++++++++
> lib/tlv_parser.h | 18 +++++++
> 7 files changed, 191 insertions(+)
> create mode 100644 include/linux/tlv_parser.h
> create mode 100644 include/uapi/linux/tlv_parser.h
> create mode 100644 lib/tlv_parser.c
> create mode 100644 lib/tlv_parser.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a097afd76ded..1f7ffa1c9dbd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23388,6 +23388,14 @@ W: http://sourceforge.net/projects/tlan/
> F: Documentation/networking/device_drivers/ethernet/ti/tlan.rst
> F: drivers/net/ethernet/ti/tlan.*
>
> +TLV PARSER
> +M: Roberto Sassu <roberto.sassu@huawei.com>
> +L: linux-kernel@vger.kernel.org
> +S: Maintained
> +F: include/linux/tlv_parser.h
> +F: include/uapi/linux/tlv_parser.h
> +F: lib/tlv_parser.*
> +
> TMIO/SDHI MMC DRIVER
> M: Wolfram Sang <wsa+renesas@sang-engineering.com>
> L: linux-mmc@vger.kernel.org
> diff --git a/include/linux/tlv_parser.h b/include/linux/tlv_parser.h
> new file mode 100644
> index 000000000000..0c72742af548
> --- /dev/null
> +++ b/include/linux/tlv_parser.h
> @@ -0,0 +1,32 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
> + *
> + * Author: Roberto Sassu <roberto.sassu@huawei.com>
> + *
> + * Header file of TLV parser.
> + */
> +
> +#ifndef _LINUX_TLV_PARSER_H
> +#define _LINUX_TLV_PARSER_H
> +
> +#include <uapi/linux/tlv_parser.h>
> +
> +/**
> + * typedef callback - Callback after parsing TLV entry
> + * @callback_data: Opaque data to supply to the callback function
> + * @field: Field identifier
> + * @field_data: Field data
> + * @field_len: Length of @field_data
> + *
> + * This callback is invoked after a TLV entry is parsed.
> + *
> + * Return: Zero on success, a negative value on error.
It's not explained what happens on error.
> + */
> +typedef int (*callback)(void *callback_data, __u16 field,
> + const __u8 *field_data, __u32 field_len);
No need for __underscore types in kernel-only signatures.
> +
> +int tlv_parse(callback callback, void *callback_data, const __u8 *data,
> + size_t data_len, const char **fields, __u32 num_fields);
> +
> +#endif /* _LINUX_TLV_PARSER_H */
> diff --git a/include/uapi/linux/tlv_parser.h b/include/uapi/linux/tlv_parser.h
> new file mode 100644
> index 000000000000..171d0cfd2c4c
> --- /dev/null
> +++ b/include/uapi/linux/tlv_parser.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +/*
> + * Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
> + *
> + * Author: Roberto Sassu <roberto.sassu@huawei.com>
> + *
> + * Implement the user space interface for the TLV parser.
> + */
Can you explain in the commit message where this will be exposed to
userspace as binary?
> +
> +#ifndef _UAPI_LINUX_TLV_PARSER_H
> +#define _UAPI_LINUX_TLV_PARSER_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * TLV format:
> + *
> + * +--------------+--+---------+--------+---------+
> + * | field1 (u16) | len1 (u32) | value1 (u8 len1) |
> + * +--------------+------------+------------------+
> + * | ... | ... | ... |
> + * +--------------+------------+------------------+
> + * | fieldN (u16) | lenN (u32) | valueN (u8 lenN) |
> + * +--------------+------------+------------------+
> + */
> +
> +/**
> + * struct tlv_entry - Entry of TLV format
> + * @field: Field identifier
> + * @length: Data length
> + * @data: Data
> + *
> + * This structure represents an entry of the TLV format.
> + */
> +struct tlv_entry {
> + __u16 field;
> + __u32 length;
Use __be16 and __be32 here.
> + __u8 data[];
__counted_by()?
Not sure how this interacts with __be.
> +} __attribute__((packed));
> +
> +#endif /* _UAPI_LINUX_TLV_PARSER_H */
> diff --git a/lib/Kconfig b/lib/Kconfig
> index b38849af6f13..9141dcfc1704 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -777,3 +777,6 @@ config POLYNOMIAL
>
> config FIRMWARE_TABLE
> bool
> +
> +config TLV_PARSER
> + bool
> diff --git a/lib/Makefile b/lib/Makefile
> index 773adf88af41..630de494eab5 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -393,5 +393,7 @@ obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
> obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
>
> obj-$(CONFIG_FIRMWARE_TABLE) += fw_table.o
> +obj-$(CONFIG_TLV_PARSER) += tlv_parser.o
> +CFLAGS_tlv_parser.o += -I lib
Does this work with out of tree builds?
>
> subdir-$(CONFIG_FORTIFY_SOURCE) += test_fortify
> diff --git a/lib/tlv_parser.c b/lib/tlv_parser.c
> new file mode 100644
> index 000000000000..dbbe08018b4d
> --- /dev/null
> +++ b/lib/tlv_parser.c
> @@ -0,0 +1,87 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
> + *
> + * Author: Roberto Sassu <roberto.sassu@huawei.com>
> + *
> + * Implement the TLV parser.
> + */
> +
> +#define pr_fmt(fmt) "tlv_parser: "fmt
> +#include <tlv_parser.h>
This should be "tlv_parser.h",
but the header files looks unnecessary in the first place.
> +
> +/**
> + * tlv_parse - Parse TLV data
> + * @callback: Callback function to call to parse the entries
> + * @callback_data: Opaque data to supply to the callback function
> + * @data: Data to parse
> + * @data_len: Length of @data
> + * @fields: Array of field strings
> + * @num_fields: Number of elements of @fields
> + *
> + * Parse the TLV data format and call the supplied callback function for each
> + * entry, passing also the opaque data pointer.
> + *
> + * The callback function decides how to process data depending on the field.
Mention that a callback return an error will abort the whole parsing.
> + *
> + * Return: Zero on success, a negative value on error.
> + */
> +int tlv_parse(callback callback, void *callback_data, const __u8 *data,
> + size_t data_len, const char **fields, __u32 num_fields)
No need for __underscore types in kernel-only functions.
"num_fields" and "fields" are accessed without checking for validity.
"fields" is only every used for debug logging, so can be removed.
"num_fields" probably, too.
> +{
> + const __u8 *data_ptr = data;
> + struct tlv_entry *entry;
This comes from the input data, should also be const.
> + __u16 parsed_field;
> + __u32 len;
field_len
> + int ret;
> +
> + if (data_len > U32_MAX) {
> + pr_debug("Data too big, size: %zd\n", data_len);
> + return -E2BIG;
> + }
> +
> + while (data_len) {
> + if (data_len < sizeof(*entry))
> + return -EBADMSG;
> +
> + entry = (struct tlv_entry *)data_ptr;
> + data_ptr += sizeof(*entry);
> + data_len -= sizeof(*entry);
> +
> + parsed_field = __be16_to_cpu(entry->field);
This doesn't seem to handle invalid alignment, some architectures will
trap unaligned accesses.
Depending on the size and usage patterns it may make sense to document
some alignment recommendations/requirements.
(Not sure how big of a performance difference it would make)
> + if (parsed_field >= num_fields) {
> + pr_debug("Invalid field %u, max: %u\n",
> + parsed_field, num_fields - 1);
> + return -EBADMSG;
> + }
> +
> + len = __be32_to_cpu(entry->length);
> +
> + if (data_len < len)
> + return -EBADMSG;
> +
> + pr_debug("Data: field: %s, len: %u\n", fields[parsed_field],
> + len);
> +
> + if (!len)
> + continue;
Empty fields are discarded silently, is this intentional?
It should be documented. Those fields could be useful for flag data.
> +
> + ret = callback(callback_data, parsed_field, data_ptr, len);
> + if (ret < 0) {
> + pr_debug("Parsing of field %s failed, ret: %d\n",
> + fields[parsed_field], ret);
> + return ret;
> + }
> +
> + data_ptr += len;
> + data_len -= len;
> + }
> +
> + if (data_len) {
Can this ever happen?
The check at the beginning of the loop should have caught it already.
> + pr_debug("Excess data: %zu bytes\n", data_len);
> + return -EBADMSG;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(tlv_parse);
Some kunit tests would be great.
> diff --git a/lib/tlv_parser.h b/lib/tlv_parser.h
> new file mode 100644
> index 000000000000..e663966deac5
> --- /dev/null
> +++ b/lib/tlv_parser.h
> @@ -0,0 +1,18 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023-2024 Huawei Technologies Duesseldorf GmbH
> + *
> + * Author: Roberto Sassu <roberto.sassu@huawei.com>
> + *
> + * Header file of TLV parser.
> + */
> +
> +#ifndef _LIB_TLV_PARSER_H
> +#define _LIB_TLV_PARSER_H
> +
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/limits.h>
> +#include <linux/tlv_parser.h>
The #includes should move to the .c file and the header be removed.
> +
> +#endif /* _LIB_TLV_PARSER_H */
> --
> 2.47.0.118.gfd3785337b
>
next prev parent reply other threads:[~2025-01-21 13:29 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-19 10:49 [PATCH v6 00/15] integrity: Introduce the Integrity Digest Cache Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 01/15] lib: Add TLV parser Roberto Sassu
2024-11-19 16:51 ` Randy Dunlap
2025-01-21 13:29 ` Thomas Weißschuh [this message]
2025-01-21 13:48 ` Roberto Sassu
2025-01-21 14:21 ` Thomas Weißschuh
2025-01-21 14:29 ` Roberto Sassu
2025-01-21 14:55 ` Roberto Sassu
2025-01-21 21:42 ` Thomas Weißschuh
2024-11-19 10:49 ` [PATCH v6 02/15] module: Introduce ksys_finit_module() Roberto Sassu
2024-11-19 12:14 ` Christoph Hellwig
2024-11-19 14:33 ` Roberto Sassu
2024-11-19 20:10 ` Luis Chamberlain
2024-11-20 9:16 ` Roberto Sassu
2024-11-20 9:18 ` Roberto Sassu
2024-11-25 23:40 ` Luis Chamberlain
2024-11-26 7:56 ` Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 03/15] integrity: Introduce the Integrity Digest Cache Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 04/15] digest_cache: Initialize digest caches Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 05/15] digest_cache: Add securityfs interface Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 06/15] digest_cache: Add hash tables and operations Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 07/15] digest_cache: Allow registration of digest list parsers Roberto Sassu
2024-11-19 16:46 ` Randy Dunlap
2024-11-19 16:48 ` Roberto Sassu
2024-11-25 23:53 ` Luis Chamberlain
2024-11-26 10:25 ` Roberto Sassu
2024-11-26 19:04 ` Luis Chamberlain
2024-11-27 9:51 ` Roberto Sassu
2024-11-27 19:53 ` Luis Chamberlain
2024-11-28 8:23 ` Roberto Sassu
2024-11-28 20:40 ` Luis Chamberlain
2024-11-29 8:30 ` Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 08/15] digest_cache: Parse tlv digest lists Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 09/15] digest_cache: Populate the digest cache from a digest list Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 10/15] digest_cache: Add management of verification data Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 11/15] digest_cache: Add support for directories Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 12/15] digest cache: Prefetch digest lists if requested Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 13/15] digest_cache: Reset digest cache on file/directory change Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 14/15] selftests/digest_cache: Add selftests for the Integrity Digest Cache Roberto Sassu
2024-11-19 10:49 ` [PATCH v6 15/15] docs: Add documentation of " Roberto Sassu
2024-11-19 20:03 ` [PATCH v6 00/15] integrity: Introduce " Luis Chamberlain
2024-11-26 0:13 ` Eric Snowberg
2024-11-26 10:41 ` Roberto Sassu
2024-12-03 20:06 ` Eric Snowberg
2024-12-04 10:44 ` Roberto Sassu
2024-12-05 0:57 ` Eric Snowberg
2024-12-05 8:53 ` Roberto Sassu
2024-12-05 16:16 ` Roberto Sassu
2024-12-05 19:41 ` Eric Snowberg
2024-12-06 10:06 ` Roberto Sassu
2024-12-06 15:15 ` Eric Snowberg
2024-12-06 15:26 ` Roberto Sassu
2024-11-27 17:30 ` Dr. Greg
2024-11-27 17:56 ` Roberto Sassu
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=c316b1be-d18f-4bb0-8434-bcc9236619df@t-8ch.de \
--to=linux@weissschuh.net \
--cc=akpm@linux-foundation.org \
--cc=alexandre.torgue@foss.st.com \
--cc=corbet@lwn.net \
--cc=da.gomez@samsung.com \
--cc=dhowells@redhat.com \
--cc=dmitry.kasatkin@gmail.com \
--cc=eric.snowberg@oracle.com \
--cc=hch@lst.de \
--cc=jannh@google.com \
--cc=jikos@kernel.org \
--cc=jmorris@namei.org \
--cc=kgold@linux.ibm.com \
--cc=linux-api@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=mcoquelin.stm32@gmail.com \
--cc=mjg59@srcf.ucam.org \
--cc=mkoutny@suse.com \
--cc=mzerqung@0pointer.de \
--cc=paul@paul-moore.com \
--cc=pbrobinson@gmail.com \
--cc=petr.pavlu@suse.com \
--cc=petr.vorel@gmail.com \
--cc=pmatilai@redhat.com \
--cc=ppavlu@suse.com \
--cc=roberto.sassu@huawei.com \
--cc=roberto.sassu@huaweicloud.com \
--cc=samitolvanen@google.com \
--cc=serge@hallyn.com \
--cc=shuah@kernel.org \
--cc=wufan@linux.microsoft.com \
--cc=zbyszek@in.waw.pl \
--cc=zohar@linux.ibm.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®