From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202410 header.b=GNJqrLFM; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 225635A004E for ; Fri, 25 Oct 2024 02:52:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202410; t=1729817532; bh=rLPrRZwro6QkgX9/z7qLXsz/LsUZ4opiSc7xXwnZI/M=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=GNJqrLFMD6LsOhnquP5/9OUvdxyztSwcM9SYdAc/ftkKQoL8k+MHRuZRvVuxGQbfT /mTMk8NuVZEkl9DdM2KiPuTIqQ5vfoyyLJeQQ2vKo8FNgB/UDVFcWYWBVe9Vata5kq puYEIOzCiO0HCZZmL76ZFFMTAXegy5FLsjBQD7mWHYnq//5fTkO0n/rferWyNnfLVW b6zZmi2bv5n6/6uU/i/C95Q2RgI4IG4iVJH70tAokNBmRIZvGWnwN/TXDsLUHLwnul xA6sDiJgbEEFzCiTWLh/OH1wVrAMtFIb/IiqAnwzoas8gPbxYfF1xazuXHa6Vc1g2U Iv/pZSvQKdEpQ== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4XZPPm3Vm8z4x33; Fri, 25 Oct 2024 11:52:12 +1100 (AEDT) Date: Fri, 25 Oct 2024 11:48:55 +1100 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH 2/8] treewide: Comply with CERT C rule ERR33-C for snprintf() Message-ID: References: <20241024230438.3192725-1-sbrivio@redhat.com> <20241024230438.3192725-3-sbrivio@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="Sg0MFWmBqJmHk92H" Content-Disposition: inline In-Reply-To: <20241024230438.3192725-3-sbrivio@redhat.com> Message-ID-Hash: SEYZJZRM3BNF55D5WCIIAEXJXO5CHYK4 X-Message-ID-Hash: SEYZJZRM3BNF55D5WCIIAEXJXO5CHYK4 X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-dev@passt.top X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: --Sg0MFWmBqJmHk92H Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Fri, Oct 25, 2024 at 01:04:32AM +0200, 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): >=20 > /home/sbrivio/passt/arch.c:43:3: error: the value returned by this functi= on 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 sil= ence this warning > /home/sbrivio/passt/conf.c:577:4: error: the value returned by this funct= ion should not be disregarded; neglecting it may lead to errors [cert-err33= -c,-warnings-as-errors] > 577 | snprintf(netns, PATH_MAX, "/proc/%ld/ns/n= et", pidval); > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~~ > /home/sbrivio/passt/conf.c:577:4: note: cast the expression to void to si= lence this warning > /home/sbrivio/passt/conf.c:579:5: error: the value returned by this funct= ion 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 si= lence this warning > /home/sbrivio/passt/pasta.c:105:2: error: the value returned by this func= tion should not be disregarded; neglecting it may lead to errors [cert-err3= 3-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 s= ilence this warning > /home/sbrivio/passt/pasta.c:242:2: error: the value returned by this func= tion should not be disregarded; neglecting it may lead to errors [cert-err3= 3-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 s= ilence this warning > /home/sbrivio/passt/pasta.c:243:2: error: the value returned by this func= tion should not be disregarded; neglecting it may lead to errors [cert-err3= 3-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 s= ilence this warning > /home/sbrivio/passt/tap.c:1155:4: error: the value returned by this funct= ion should not be disregarded; neglecting it may lead to errors [cert-err33= -c,-warnings-as-errors] > 1155 | snprintf(path, UNIX_PATH_MAX - 1, UNIX_SO= CK_PATH, i); > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~= ~~~~~~~~~~~ > /home/sbrivio/passt/tap.c:1155:4: note: cast the expression to void to si= lence this warning >=20 > 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 terminating if we > do. Huh, I wonder why I wasn't seeing these with clang 18.1.8.1. Still, LGTM except for a couple of nits. >=20 > Signed-off-by: Stefano Brivio > --- > arch.c | 4 +++- > conf.c | 11 +++++++---- > pasta.c | 7 ++++--- > tap.c | 8 +++++--- > util.c | 22 ++++++++++++++++++++++ > util.h | 3 +++ > 6 files changed, 44 insertions(+), 11 deletions(-) >=20 > diff --git a/arch.c b/arch.c > index 04bebfc..edbe666 100644 > --- a/arch.c > +++ b/arch.c > @@ -19,6 +19,7 @@ > #include > =20 > #include "log.h" > +#include "util.h" > =20 > /** > * arch_avx2_exec() - Switch to AVX2 build if supported > @@ -40,7 +41,8 @@ void arch_avx2_exec(char **argv) > if (__builtin_cpu_supports("avx2")) { > char new_path[PATH_MAX + sizeof(".avx2")]; > =20 > - snprintf(new_path, PATH_MAX + sizeof(".avx2"), "%s.avx2", exe); > + snprintf_check("Can't build AVX2 executable path", new_path, For all of these messages I'd suggest "XXX path is too long" rather than just "Can't build XXX path" in order to be more explicit and give users a clue to a workaround. > + PATH_MAX + sizeof(".avx2"), "%s.avx2", exe); > 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..2122600 100644 > --- a/conf.c > +++ b/conf.c > @@ -574,10 +574,13 @@ static void conf_pasta_ns(int *netns_only, char *us= erns, char *netns, > if (pidval < 0 || pidval > INT_MAX) > die("Invalid PID %s", argv[optind]); > =20 > - snprintf(netns, PATH_MAX, "/proc/%ld/ns/net", pidval); > - if (!*userns) > - snprintf(userns, PATH_MAX, "/proc/%ld/ns/user", > - pidval); > + snprintf_check("Can't build netns path", netns, > + PATH_MAX, "/proc/%ld/ns/net", pidval); > + if (!*userns) { > + snprintf_check("Can't build userns path", > + userns, PATH_MAX, > + "/proc/%ld/ns/user", pidval); > + } > } > } > =20 > diff --git a/pasta.c b/pasta.c > index 307fb4a..ce9ae7a 100644 > --- a/pasta.c > +++ b/pasta.c > @@ -102,7 +102,8 @@ static int pasta_wait_for_ns(void *arg) > int flags =3D O_RDONLY | O_CLOEXEC; > char ns[PATH_MAX]; > =20 > - snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid); > + snprintf_check("Can't build netns path", ns, > + PATH_MAX, "/proc/%i/ns/net", pasta_child_pid); > do { > while ((c->pasta_netns_fd =3D open(ns, flags)) < 0) { > if (errno !=3D ENOENT) > @@ -239,8 +240,8 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t g= id, > c->quiet =3D 1; > =20 > /* Configure user and group mappings */ > - snprintf(uidmap, BUFSIZ, "0 %u 1", uid); > - snprintf(gidmap, BUFSIZ, "0 %u 1", gid); > + snprintf_check("Can't build uidmap", uidmap, BUFSIZ, "0 %u 1", uid); > + snprintf_check("Can't build gidmap", gidmap, BUFSIZ, "0 %u 1", gid); > =20 > if (write_file("/proc/self/uid_map", uidmap) || > write_file("/proc/self/setgroups", "deny") || > diff --git a/tap.c b/tap.c > index c53a39b..51eb134 100644 > --- a/tap.c > +++ b/tap.c > @@ -1149,10 +1149,12 @@ int tap_sock_unix_open(char *sock_path) > char *path =3D addr.sun_path; > int ex, ret; > =20 > - if (*sock_path) > + if (*sock_path) { > memcpy(path, sock_path, UNIX_PATH_MAX); > - else > - snprintf(path, UNIX_PATH_MAX - 1, UNIX_SOCK_PATH, i); > + } else { > + snprintf_check("Can't build UNIX domain path", path, I'd suggest explicitly saying "Unix domain _socket_", > + UNIX_PATH_MAX - 1, UNIX_SOCK_PATH, i); > + } > =20 > ex =3D socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); > if (ex < 0) > diff --git a/util.c b/util.c > index eba7d52..eff6787 100644 > --- a/util.c > +++ b/util.c > @@ -749,3 +749,25 @@ void close_open_files(int argc, char **argv) > if (rc) > die_perror("Failed to close files leaked by parent"); > } > + > +/** > + * snprintf_check() - snprintf() wrapper, terminating on truncation > + * @errmsg: Error string to be printed while terminating > + * @str: Output buffer > + * @size: Maximum size to write to @str > + * @format: Message > + */ > +void snprintf_check(const char *errstr, > + char *str, size_t size, const char *format, ...) YMMV, but I always find passing a format / error string into a function that's not primarily about error handling kind of clunky. How much bulkier would it be to make this wrapper return a boolean and do an explicit: if (!sprintf_check(...)) die("blah blah blah"); at the call sites? It might make the control flow a little more obvious, and means we could add parameters to the error message if there are cases where that makes sense. > +{ > + va_list ap; > + int rc; > + > + va_start(ap, format); > + > + rc =3D snprintf(str, size, format, ap); > + if (rc < 0 || (size_t)rc >=3D size) > + die("%s", errstr); > + > + va_end(ap); > +} > diff --git a/util.h b/util.h > index 2c1e08e..8449d00 100644 > --- a/util.h > +++ b/util.h > @@ -11,6 +11,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -200,6 +201,8 @@ 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); > +void snprintf_check(const char *errstr, > + char *str, size_t size, const char *format, ...); > =20 > /** > * af_name() - Return name of an address family --=20 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 --Sg0MFWmBqJmHk92H Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmca6vYACgkQzQJF27ox 2Gey8g/9HnDlyxfzzZ4TjlIxWhcAvmzduR/hfXK5EW9X2nZ6SVWCYVTv8mZbkjGp 0ArDTiAb4ClTI/uYvseX+cjHw+ZRSrqpaF3rzUO44Gp9zrKDnzgENxYKjrdQjwMj nehewcQhV3D50h2x+53LdzjHSvbvevYrD/04xjRpHlmxgyFmi7aroxnqmKRsaErl kgBkVE9gSC6IRCFEYlW3jpwE8yYYRu+BDuRje98zYi0Kg7Pf9ELBtsNfH4lZPlox Mq5EooL66KdGC9qeuk2wxln7lasUibSpd3eDB3+47c5l4N69KX51veHk3aetYE+z lONizCd+CEQ4W8nJle+qDvACC8mpWgJiARrkWSn3fHQdyd/DzttXHk1gnkzL9HGQ d9JvZ1DAJzPQLxcJJhsJ/+/hxTiavxQmMU47BKeGT8SOACJK5uLBfId7CaRyUpib gPtRJLl6P55phPoqeh6cqZ8ThF+d4B2H4zuwkT5GKhi998WfgYxZhWlplDLsqYBB SzKyWmZMamHRHhYBzxJQKXzE/NpRuggAS/1ZKGT23sscWWZRYSYowknHD459iLEj CL5NKINbnvGWnsx+HAFFGbmuCXfKP/KMUY7eXL3FqhH8oSWp29TK+X0ecvntze0r 5ffUJ+Vh6MPo7Zwwg84Sb5Q0AXsr6NcaZnQb6n6WBGzUIIlWwfI= =1UmO -----END PGP SIGNATURE----- --Sg0MFWmBqJmHk92H--