From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v5 2/8] treewide: Comply with CERT C rule ERR33-C for snprintf()
Date: Wed, 30 Oct 2024 19:45:50 +1100 [thread overview]
Message-ID: <ZyHyPlct3-5pDtWu@zatzit> (raw)
In-Reply-To: <20241030080909.2781504-3-sbrivio@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 8989 bytes --]
On Wed, Oct 30, 2024 at 09:09:03AM +0100, Stefano Brivio wrote:
> clang-tidy, starting from LLVM version 16, up to at least LLVM version
> 19, now checks that we detect and handle errors for snprintf() as
> requested by CERT C rule ERR33-C. These warnings were logged with LLVM
> version 19.1.2 (at least Debian and Fedora match):
>
> /home/sbrivio/passt/arch.c:43:3: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 43 | snprintf(new_path, PATH_MAX + sizeof(".avx2"), "%s.avx2", exe);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /home/sbrivio/passt/arch.c:43:3: note: cast the expression to void to silence this warning
> /home/sbrivio/passt/conf.c:577:4: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 577 | snprintf(netns, PATH_MAX, "/proc/%ld/ns/net", pidval);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /home/sbrivio/passt/conf.c:577:4: note: cast the expression to void to silence this warning
> /home/sbrivio/passt/conf.c:579:5: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 579 | snprintf(userns, PATH_MAX, "/proc/%ld/ns/user",
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 580 | pidval);
> | ~~~~~~~
> /home/sbrivio/passt/conf.c:579:5: note: cast the expression to void to silence this warning
> /home/sbrivio/passt/pasta.c:105:2: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 105 | snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /home/sbrivio/passt/pasta.c:105:2: note: cast the expression to void to silence this warning
> /home/sbrivio/passt/pasta.c:242:2: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 242 | snprintf(uidmap, BUFSIZ, "0 %u 1", uid);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /home/sbrivio/passt/pasta.c:242:2: note: cast the expression to void to silence this warning
> /home/sbrivio/passt/pasta.c:243:2: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 243 | snprintf(gidmap, BUFSIZ, "0 %u 1", gid);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /home/sbrivio/passt/pasta.c:243:2: note: cast the expression to void to silence this warning
> /home/sbrivio/passt/tap.c:1155:4: error: the value returned by this function should not be disregarded; neglecting it may lead to errors [cert-err33-c,-warnings-as-errors]
> 1155 | snprintf(path, UNIX_PATH_MAX - 1, UNIX_SOCK_PATH, i);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /home/sbrivio/passt/tap.c:1155:4: note: cast the expression to void to silence this warning
>
> Don't silence the warnings as they might actually have some merit. Add
> an snprintf_check() function, instead, checking that we're not
> truncating messages while printing to buffers, and terminate if the
> check fails.
>
> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> arch.c | 6 +++++-
> conf.c | 13 +++++++++----
> pasta.c | 11 ++++++++---
> tap.c | 5 +++--
> util.c | 30 ++++++++++++++++++++++++++++++
> util.h | 2 ++
> 6 files changed, 57 insertions(+), 10 deletions(-)
>
> diff --git a/arch.c b/arch.c
> index 04bebfc..d1dfb73 100644
> --- a/arch.c
> +++ b/arch.c
> @@ -19,6 +19,7 @@
> #include <unistd.h>
>
> #include "log.h"
> +#include "util.h"
>
> /**
> * arch_avx2_exec() - Switch to AVX2 build if supported
> @@ -40,7 +41,10 @@ void arch_avx2_exec(char **argv)
> if (__builtin_cpu_supports("avx2")) {
> char new_path[PATH_MAX + sizeof(".avx2")];
>
> - snprintf(new_path, PATH_MAX + sizeof(".avx2"), "%s.avx2", exe);
> + if (snprintf_check(new_path, PATH_MAX + sizeof(".avx2"),
> + "%s.avx2", exe))
> + die_perror("Can't build AVX2 executable path");
> +
> execve(new_path, argv, environ);
> warn_perror("Can't run AVX2 build, using non-AVX2 version");
> }
> diff --git a/conf.c b/conf.c
> index b3b5342..fa5cec3 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -574,10 +574,15 @@ static void conf_pasta_ns(int *netns_only, char *userns, char *netns,
> if (pidval < 0 || pidval > INT_MAX)
> die("Invalid PID %s", argv[optind]);
>
> - snprintf(netns, PATH_MAX, "/proc/%ld/ns/net", pidval);
> - if (!*userns)
> - snprintf(userns, PATH_MAX, "/proc/%ld/ns/user",
> - pidval);
> + if (snprintf_check(netns, PATH_MAX,
> + "/proc/%ld/ns/net", pidval))
> + die_perror("Can't build netns path");
> +
> + if (!*userns) {
> + if (snprintf_check(userns, PATH_MAX,
> + "/proc/%ld/ns/user", pidval))
> + die_perror("Can't build userns path");
> + }
> }
> }
>
> diff --git a/pasta.c b/pasta.c
> index 307fb4a..a117704 100644
> --- a/pasta.c
> +++ b/pasta.c
> @@ -102,7 +102,9 @@ static int pasta_wait_for_ns(void *arg)
> int flags = O_RDONLY | O_CLOEXEC;
> char ns[PATH_MAX];
>
> - snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid);
> + if (snprintf_check(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid))
> + die_perror("Can't build netns path");
> +
> do {
> while ((c->pasta_netns_fd = open(ns, flags)) < 0) {
> if (errno != ENOENT)
> @@ -239,8 +241,11 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid,
> c->quiet = 1;
>
> /* Configure user and group mappings */
> - snprintf(uidmap, BUFSIZ, "0 %u 1", uid);
> - snprintf(gidmap, BUFSIZ, "0 %u 1", gid);
> + if (snprintf_check(uidmap, BUFSIZ, "0 %u 1", uid))
> + die_perror("Can't build uidmap");
> +
> + if (snprintf_check(gidmap, BUFSIZ, "0 %u 1", gid))
> + die_perror("Can't build gidmap");
>
> if (write_file("/proc/self/uid_map", uidmap) ||
> write_file("/proc/self/setgroups", "deny") ||
> diff --git a/tap.c b/tap.c
> index c53a39b..cfb82e9 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -1151,8 +1151,9 @@ int tap_sock_unix_open(char *sock_path)
>
> if (*sock_path)
> memcpy(path, sock_path, UNIX_PATH_MAX);
> - else
> - snprintf(path, UNIX_PATH_MAX - 1, UNIX_SOCK_PATH, i);
> + else if (snprintf_check(path, UNIX_PATH_MAX - 1,
> + UNIX_SOCK_PATH, i))
> + die_perror("Can't build UNIX domain socket path");
>
> ex = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
> if (ex < 0)
> diff --git a/util.c b/util.c
> index eba7d52..21ce0a8 100644
> --- a/util.c
> +++ b/util.c
> @@ -749,3 +749,33 @@ void close_open_files(int argc, char **argv)
> if (rc)
> die_perror("Failed to close files leaked by parent");
> }
> +
> +/**
> + * snprintf_check() - snprintf() wrapper, checking for truncation and errors
> + * @str: Output buffer
> + * @size: Maximum size to write to @str
> + * @format: Message
> + *
> + * Return: false on success, true on truncation or error, sets errno on failure
> + */
> +bool snprintf_check(char *str, size_t size, const char *format, ...)
> +{
> + va_list ap;
> + int rc;
> +
> + va_start(ap, format);
> + rc = vsnprintf(str, size, format, ap);
> + va_end(ap);
> +
> + if (rc < 0) {
> + errno = EIO;
> + return true;
> + }
> +
> + if ((size_t)rc >= size) {
> + errno = ENOBUFS;
> + return true;
> + }
> +
> + return false;
> +}
> diff --git a/util.h b/util.h
> index 2c1e08e..96f178c 100644
> --- a/util.h
> +++ b/util.h
> @@ -11,6 +11,7 @@
> #include <stdbool.h>
> #include <stddef.h>
> #include <stdint.h>
> +#include <stdio.h>
> #include <string.h>
> #include <signal.h>
> #include <arpa/inet.h>
> @@ -200,6 +201,7 @@ int write_file(const char *path, const char *buf);
> int write_all_buf(int fd, const void *buf, size_t len);
> int write_remainder(int fd, const struct iovec *iov, size_t iovcnt, size_t skip);
> void close_open_files(int argc, char **argv);
> +bool snprintf_check(char *str, size_t size, const char *format, ...);
>
> /**
> * af_name() - Return name of an address family
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2024-10-30 8:46 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-30 8:09 [PATCH v5 0/8] Take care of clang-tidy warnings with LLVM >= 16 Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 1/8] Makefile: Exclude qrap.c from clang-tidy checks Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 2/8] treewide: Comply with CERT C rule ERR33-C for snprintf() Stefano Brivio
2024-10-30 8:45 ` David Gibson [this message]
2024-10-30 8:09 ` [PATCH v5 3/8] treewide: Silence cert-err33-c clang-tidy warnings for fprintf() Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 4/8] Makefile: Disable readability-math-missing-parentheses clang-tidy check Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 5/8] treewide: Suppress clang-tidy warning if we already use O_CLOEXEC Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 6/8] treewide: Address cert-err33-c clang-tidy warnings for clock and timer functions Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 7/8] udp: Take care of cert-int09-c clang-tidy warning for enum udp_iov_idx Stefano Brivio
2024-10-30 8:09 ` [PATCH v5 8/8] util: Don't use errno after a successful call in __daemon() Stefano Brivio
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=ZyHyPlct3-5pDtWu@zatzit \
--to=david@gibson.dropbear.id.au \
--cc=passt-dev@passt.top \
--cc=sbrivio@redhat.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.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).