Fix issues found by gcc -fanalyze
Subsystems (2)
cover Fix issues found by gcc -fanalyze
This patch series provides updates to correct issues found by gcc -fanalyze. The issues were found by specifying the following flags when building:
CFLAGS="-march=native -O2 -pipe -fanalyzer -Werror=analyzer-va-arg-type-mismatch
-Werror=analyzer-va-list-exhausted -Werror=analyzer-va-list-leak -Werror=analyzer-va-list-use-after-va-end"
CXXCFLAGS="-march=native -O2 -pipe -fanalyzer
-Werror=analyzer-va-arg-type-mismatch -Werror=analyzer-va-list-exhausted -Werror=analyzer-va-list-leak -Werror=analyzer-va-list-use-after-va-end"
LDFLAGS="-Wl,-O1 -Wl,--as-needed"
GCC version is gcc (Gentoo 13.1.0-r1 p1) 13.1.0
Nicholas Vinson (3):
Update FAM syntax to conform to std C.
Fix reported memory leak.
Fix potentinal null-pointer derference issues.
ethtool.c | 24 +++++++++++++----------- netlink/features.c | 24 ++++++++++++++++++------ 2 files changed, 31 insertions(+), 17 deletions(-)
Signature · 1 line
2.40.1
PATCH 1/3 Update FAM syntax to conform to std C.
Found via gcc -fanalyzer. When using the non-standard FAM syntax:
uint32_t req_mask[0];
gcc-13 with the -fanalyzer flag generates an internal compiler error. Updating the syntax to use the standard C syntax:
uint32_t req_mask[];
works around the gcc bug.
--- netlink/features.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
netlink/features.c +1 -1
@@ -266,7 +266,7 @@ int nl_gfeatures(struct cmd_context *ctx)struct sfeatures_context {bool nothing_changed; -uint32_t req_mask[0 ]; +uint32_t req_mask[]; }; static int find_feature(const char *name,
Signature · 1 line
2.40.1
PATCH 2/3 Fix reported memory leak.
In reply to Nicholas VinsonFound via gcc -fanalyzer. In the function nl_sfeatures() malloc() is called to allocate a block of memory; however, that memory block is never explictily freed.
--- netlink/features.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
netlink/features.c +17 -5
@@ -534,24 +534,36 @@ int nl_sfeatures(struct cmd_context *ctx) nlctx->devname = ctx->devname; ret =msg_init (nlctx, msgbuff,ETHTOOL_MSG_FEATURES_SET ,NLM_F_REQUEST |NLM_F_ACK ); -if (ret <0 ) +if (ret <0 ) { +free (sfctx);return 2 ; + }if (ethnla_fill_header (msgbuff,ETHTOOL_A_FEATURES_HEADER , ctx->devname, -ETHTOOL_FLAG_COMPACT_BITSETS )) +ETHTOOL_FLAG_COMPACT_BITSETS )) { +free (sfctx);return -EMSGSIZE ; + } ret =fill_sfeatures_bitmap (nlctx, feature_names); -if (ret <0 ) +if (ret <0 ) { +free (sfctx);return ret; + } ret =nlsock_sendmsg (nlsk,NULL ); -if (ret <0 ) +if (ret <0 ) { +free (sfctx);return 92 ; + } ret =nlsock_process_reply (nlsk, sfeatures_reply_cb, nlctx);if (sfctx->nothing_changed) {fprintf (stderr,"Could not change any device features\n" ); +free (sfctx);return nlctx->exit_code ?:1 ; } -if (ret ==0 ) +if (ret ==0 ) { +free (sfctx);return 0 ; + } +free (sfctx);return nlctx->exit_code ?:92 ; }
Signature · 1 line
2.40.1
PATCH 3/3 Fix potentinal null-pointer derference issues.
In reply to Nicholas VinsonFound via gcc -fanalyzer. Analyzer claims that it's possible certain functions may receive a NULL pointer when handling CLI arguments. Adding NULL pointer checks to correct the issues.
--- ethtool.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
ethtool.c +13 -11
@@ -6182,16 +6182,18 @@ static int find_option(char *arg)size_t len;int k; -for (k =1 ; args[k].opts; k++) { - opt = args[k].opts; -for (;;) { - len =strcspn (opt,"|" ); -if (strncmp (arg, opt, len) ==0 && arg[len] ==0 ) -return k; - -if (opt[len] ==0 ) -break ; - opt += len +1 ; +if (arg) { +for (k =1 ; args[k].opts; k++) { + opt = args[k].opts; +for (;;) { + len =strcspn (opt,"|" ); +if (strncmp (arg, opt, len) ==0 && arg[len] ==0 ) +return k; + +if (opt[len] ==0 ) +break ; + opt += len +1 ; + } } }
@@ -6457,7 +6459,7 @@ int main(int argc, char **argp) argp++; argc--; }else { -if ((*argp)[0 ] =='-' ) +if (!*argp || (*argp)[0 ] =='-' )exit_bad_args (); k =0 ; }
Signature · 1 line
2.40.1
Re: [PATCH ethtool 3/3] Fix potentinal null-pointer derference issues.
Quoted 5 lines · Nicholas Vinson
Found via gcc -fanalyzer. Analyzer claims that it's possible certain functions may receive a NULL pointer when handling CLI arguments. Adding NULL pointer checks to correct the issues.
Signed-off-by Nicholas Vinson <[email protected]>
A similar theoretical issue was discussed recently:
https://patchwork.kernel.org/project/netdevbpf/patch/[email protected]/
My position is still the same: argv[] members cannot be actually null unless there is a serious kernel bug (see the link above for an explanation). I'm not opposed to doing a sanity check just in case but if we do, I believe we should check the whole argv[] array right at the beginning and be done with it rather than add specific checks to random places inside parser code.
Quoted 19 lines
ethtool.c +5
-10@@ -6182,16 +6182,18 @@ static int find_option(char *arg)size_t len;int k; -for (k =1 ; args[k].opts; k++) { - opt = args[k].opts; -for (;;) { - len =strcspn (opt,"|" ); -if (strncmp (arg, opt, len) ==0 && arg[len] ==0 ) -return k; - -if (opt[len] ==0 ) -break ; - opt += len +1 ; +if (arg) { +for (k =1 ; args[k].opts; k++) { + opt = args[k].opts; +for (;;) { + len =strcspn (opt,"|" );
ethtool.c static int find_option(char *arg) · line 6199
Quoted 10 lines
ethtool.c +7
-0+if (strncmp (arg, opt, len) ==0 && arg[len] ==0 ) +return k; + +if (opt[len] ==0 ) +break ; + opt += len +1 ; + } } }
I would rather prefer a simple
if (!arg) return -1;
to avoid closing almost all of the function body inside an if block.
Michal
Re: [PATCH ethtool 3/3] Fix potentinal null-pointer derference issues.
Quoted 8 lines · Michal Kubecek
Quoted 5 lines · Nicholas Vinson
Found via gcc -fanalyzer. Analyzer claims that it's possible certain functions may receive a NULL pointer when handling CLI arguments. Adding NULL pointer checks to correct the issues.
Signed-off-by Nicholas Vinson <[email protected]>A similar theoretical issue was discussed recently:
Quoted 8 lines
https://patchwork.kernel.org/project/netdevbpf/patch/[email protected]/My position is still the same: argv[] members cannot be actually null unless there is a serious kernel bug (see the link above for an explanation). I'm not opposed to doing a sanity check just in case but if we do, I believe we should check the whole argv[] array right at the beginning and be done with it rather than add specific checks to random places inside parser code.
By convention and POSIX standard, the last argv[] member is always set to NULL and is accessed from main(int argc, char **argp) via argp[argc] (see https://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html). It's also possible for argc to be zero. In such a case, find_option(NULL) would get called.
However, after reviewing main(), I recommend changing:
if (argc == 0)
exit_bad_args();
to
if (argc <= 0 || !*argp)
exit_bad_args();
as this fixes the potential issue of main()'s argc being 0 (argc would be -1 at this point in such cases), and "!*argp" silences gcc's built-in analyzer (and should silence all other SA with respect to the reported issue) as the SA doesn't recognize that it would take a buggy execve implementation to allow argp to be NULL at this point ).
If you don't have any objections to this change, I can draft an updated patch to make this change.
Thanks,
Nicholas Vinson
Quoted 37 lines
Quoted 19 lines
ethtool.c +5
-10@@ -6182,16 +6182,18 @@ static int find_option(char *arg)size_t len;int k; -for (k =1 ; args[k].opts; k++) { - opt = args[k].opts; -for (;;) { - len =strcspn (opt,"|" ); -if (strncmp (arg, opt, len) ==0 && arg[len] ==0 ) -return k; - -if (opt[len] ==0 ) -break ; - opt += len +1 ; +if (arg) { +for (k =1 ; args[k].opts; k++) { + opt = args[k].opts; +for (;;) { + len =strcspn (opt,"|" );ethtool.c static int find_option(char *arg) · line 6199
Quoted 10 lines
ethtool.c +7
-0+if (strncmp (arg, opt, len) ==0 && arg[len] ==0 ) +return k; + +if (opt[len] ==0 ) +break ; + opt += len +1 ; + } } }I would rather prefer a simple
if (!arg) return -1;to avoid closing almost all of the function body inside an if block.
Michal
Re: [PATCH ethtool 3/3] Fix potentinal null-pointer derference issues.
Quoted 19 lines · Nicholas Vinson
Quoted 8 lines · Michal Kubecek
Quoted 5 lines · Nicholas Vinson
Found via gcc -fanalyzer. Analyzer claims that it's possible certain functions may receive a NULL pointer when handling CLI arguments. Adding NULL pointer checks to correct the issues.
Signed-off-by Nicholas Vinson <[email protected]>A similar theoretical issue was discussed recently:
Quoted 8 lines
https://patchwork.kernel.org/project/netdevbpf/patch/[email protected]/My position is still the same: argv[] members cannot be actually null unless there is a serious kernel bug (see the link above for an explanation). I'm not opposed to doing a sanity check just in case but if we do, I believe we should check the whole argv[] array right at the beginning and be done with it rather than add specific checks to random places inside parser code.
Quoted 5 lines
By convention and POSIX standard, the last argv[] member is always set to NULL and is accessed from
main(int argc, char **argp)via argp[argc] (see
https://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html).
It's also possible for argc to be zero. In such a case,find_option(NULL)would get called.
Please note that ethtool is not a utility for a general POSIX system. It is a very specific utility which works and makes sense only on Linux. That's why it can and does take many assumptions which are only guaranteed on Linux but may not be true on other POSIX systems.
Quoted 13 lines
However, after reviewing
main(), I recommend changing:if (argc == 0)
exit_bad_args();to
if (argc <= 0 || !*argp)
exit_bad_args();
Quoted 8 lines
as this fixes the potential issue of main()'s argc being 0 (argc would be -1 at this point in such cases), and "!*argp" silences gcc's built-in analyzer (and should silence all other SA with respect to the reported issue) as the SA doesn't recognize that it would take a buggy execve implementation to allow argp to be NULL at this point ).
If you don't have any objections to this change, I can draft an updated patch to make this change.
As I said before, I do not object to adding a sanity check of argc/argv, I only objected to adding random checks inside the parser code just to make static checkers happy. If you want to add (or strengthen) a sanity check right at the beginning of the program, before any parsing, I have no problem with that.
Michal
Re: [PATCH ethtool 3/3] Fix potentinal null-pointer derference issues.
Quoted 47 lines · Michal Kubecek
Quoted 17 lines · Nicholas Vinson
Quoted 8 lines · Michal Kubecek
Quoted 5 lines · Nicholas Vinson
Found via gcc -fanalyzer. Analyzer claims that it's possible certain functions may receive a NULL pointer when handling CLI arguments. Adding NULL pointer checks to correct the issues.
Signed-off-by Nicholas Vinson <[email protected]>A similar theoretical issue was discussed recently:
Quoted 8 lines
https://patchwork.kernel.org/project/netdevbpf/patch/[email protected]/My position is still the same: argv[] members cannot be actually null unless there is a serious kernel bug (see the link above for an explanation). I'm not opposed to doing a sanity check just in case but if we do, I believe we should check the whole argv[] array right at the beginning and be done with it rather than add specific checks to random places inside parser code.
Quoted 5 lines
By convention and POSIX standard, the last argv[] member is always set to NULL and is accessed from
main(int argc, char **argp)via argp[argc] (see
https://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html).
It's also possible for argc to be zero. In such a case,find_option(NULL)would get called.Please note that ethtool is not a utility for a general POSIX system. It is a very specific utility which works and makes sense only on Linux. That's why it can and does take many assumptions which are only guaranteed on Linux but may not be true on other POSIX systems.
Quoted 19 lines
However, after reviewing
main(), I recommend changing:if (argc == 0)
exit_bad_args();to
if (argc <= 0 || !*argp)
exit_bad_args();as this fixes the potential issue of main()'s argc being 0 (argc would be -1 at this point in such cases), and "!*argp" silences gcc's built-in analyzer (and should silence all other SA with respect to the reported issue) as the SA doesn't recognize that it would take a buggy execve implementation to allow argp to be NULL at this point ).
Quoted 7 lines
Quoted 2 lines
If you don't have any objections to this change, I can draft an updated patch to make this change.
As I said before, I do not object to adding a sanity check of argc/argv, I only objected to adding random checks inside the parser code just to make static checkers happy. If you want to add (or strengthen) a sanity check right at the beginning of the program, before any parsing, I have no problem with that.
I am abandoning this patch in favor of a new one with the subject line "[PATCH ethtool] Fix argc and argp handling issues".
Thanks,
Nicholas Vinson
Quoted 1 line
Michal
This series was applied to ethtool/ethtool.git (master) by Michal Kubecek <[email protected]>:
Hello:
This series was applied to ethtool/ethtool.git (master) by Michal Kubecek <[email protected]>:
Quoted 8 lines · On Sun, 30 Apr 2023 18:50:49 -0400 you wrote:
This patch series provides updates to correct issues found by gcc -fanalyze. The issues were found by specifying the following flags when building:
CFLAGS="-march=native -O2 -pipe -fanalyzer -Werror=analyzer-va-arg-type-mismatch
-Werror=analyzer-va-list-exhausted -Werror=analyzer-va-list-leak -Werror=analyzer-va-list-use-after-va-end"[...]
Here is the summary with links:
- [ethtool,1/3] Update FAM syntax to conform to std C.
https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=77599cf04110 - [ethtool,2/3] Fix reported memory leak. https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=7de97fb99868
- [ethtool,3/3] Fix potentinal null-pointer derference issues. (no matching commit)
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html