Bug Summary

File:src/usr.bin/bgplg/bgplgsh/../bgplgsh.c
Warning:line 268, column 3
Potential leak of memory pointed to by 'argp'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name bgplgsh.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/bgplg/bgplgsh/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.bin/bgplg/bgplgsh -I /usr/src/usr.bin/bgplg/bgplgsh/../../lib/libedit -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/bgplg/bgplgsh/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/bgplg/bgplgsh/../bgplgsh.c
1/* $OpenBSD: bgplgsh.c,v 1.8 2015/12/09 17:52:24 mmcc Exp $ */
2
3/*
4 * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/stat.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <signal.h>
25#include <string.h>
26#include <unistd.h>
27#include <limits.h>
28#include <ctype.h>
29#include <errno(*__errno()).h>
30#include <fcntl.h>
31
32#include <readline/readline.h>
33#include <readline/history.h>
34
35#include "bgplg.h"
36
37#define BGPDSOCK"/var/www/run/bgpd.rsock" "/var/www/run/bgpd.rsock"
38#define BGPCTL"/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock" "/usr/sbin/bgpctl", "-s", BGPDSOCK"/var/www/run/bgpd.rsock"
39#define PING"/sbin/ping" "/sbin/ping"
40#define TRACEROUTE"/usr/sbin/traceroute" "/usr/sbin/traceroute"
41#define PING6"/sbin/ping6" "/sbin/ping6"
42#define TRACEROUTE6"/usr/sbin/traceroute6" "/usr/sbin/traceroute6"
43
44static volatile int quit;
45
46static struct cmd cmds[] = CMDS{ { "show ip bgp", 1, 1, "&lt;prefix&gt;", { "/usr/sbin/bgpctl"
, "-s", "/var/www/run/bgpd.rsock", "show", "ip", "bgp", ((void
*)0) } }, { "show ip bgp as", 1, 1, "&lt;asnum&gt;",
{ "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock", "show"
, "ip", "bgp", "as", ((void *)0) } }, { "show ip bgp source-as"
, 1, 1, "&lt;asnum&gt;", { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "ip", "bgp", "source-as", ((void *)0) } }, { "show ip bgp transit-as"
, 1, 1, "&lt;asnum&gt;", { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "ip", "bgp", "transit-as", ((void *)0) } }, { "show ip bgp peer-as"
, 1, 1, "&lt;asnum&gt;", { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "ip", "bgp", "peer-as", ((void *)0) } }, { "show ip bgp empty-as"
, 0, 0, ((void *)0), { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "ip", "bgp", "empty-as", ((void *)0) } }, { "show ip bgp summary"
, 0, 0, ((void *)0), { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "ip", "bgp", "summary", ((void *)0) } }, { "show ip bgp community"
, 1, 1, "&lt;community&gt;", { "/usr/sbin/bgpctl", "-s"
, "/var/www/run/bgpd.rsock", "show","ip", "bgp", "community",
((void *)0) } }, { "show ip bgp detail community", 1, 1, "&lt;community&gt;"
, { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock", "show"
,"ip", "bgp", "detail", "community", ((void *)0) } }, { "show ip bgp ext-community"
, 2, 2, "&lt;ext-community&gt;", { "/usr/sbin/bgpctl"
, "-s", "/var/www/run/bgpd.rsock", "show","ip", "bgp", "ext-community"
, ((void *)0) } }, { "show ip bgp detail ext-community", 2, 2
, "&lt;ext-community&gt;", { "/usr/sbin/bgpctl", "-s"
, "/var/www/run/bgpd.rsock", "show","ip", "bgp", "detail", "ext-community"
, ((void *)0) } }, { "show ip bgp large-community", 1, 1, "&lt;large-community&gt;"
, { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock", "show"
,"ip", "bgp", "large-community", ((void *)0) } }, { "show ip bgp detail large-community"
, 1, 1, "&lt;large-community&gt;", { "/usr/sbin/bgpctl"
, "-s", "/var/www/run/bgpd.rsock", "show","ip", "bgp", "detail"
, "large-community", ((void *)0) } }, { "show ip bgp detail",
1, 1, "&lt;prefix&gt;", { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show","ip", "bgp", "detail", ((void *)0) } }, { "show ip bgp detail as"
, 1, 1, "&lt;asnum&gt;", { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show","ip", "bgp", "detail", "as", ((void *)0) } }, { "show ip bgp in"
, 1, 1, "&lt;neighbor&gt;", { "/usr/sbin/bgpctl", "-s"
, "/var/www/run/bgpd.rsock", "show","ip", "bgp", "in", "neighbor"
, ((void *)0) } }, { "show ip bgp out", 1, 1, "&lt;neighbor&gt;"
, { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock", "show"
,"ip", "bgp", "out", "neighbor", ((void *)0) } }, { "show ip bgp ovs"
, 1, 1, "&lt;state&gt;", { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show","ip", "bgp", "ovs", ((void *)0) } }, { "show ip bgp memory"
, 0, 0, ((void *)0), { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "ip", "bgp", "memory", ((void *)0) } }, { "show neighbor"
, 0, 1, ((void *)0), { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "neighbor", ((void *)0) } }, { "show nexthop", 0, 0
, ((void *)0), { "/usr/sbin/bgpctl", "-s", "/var/www/run/bgpd.rsock"
, "show", "nexthop", ((void *)0) } }, { "traceroute", 1, 1, "&lt;address&gt;"
, { "/usr/sbin/traceroute", "-ASl", ((void *)0) } }, { "ping"
, 1, 1, "&lt;address&gt;", { "/sbin/ping", "-c4", "-w2"
, ((void *)0) } }, { "traceroute6", 1, 1, "&lt;address&gt;"
, { "/usr/sbin/traceroute6", "-Al", ((void *)0) } }, { "ping6"
, 1, 1, "&lt;address&gt;", { "/sbin/ping6", "-c4", "-i2"
, ((void *)0) } }, { "help", 0, 0, ((void *)0), { ((void *)0)
}, lg_help }, { ((void *)0) } }
;
47
48char **lg_arg2argv(char *, int *);
49char **lg_argextra(char **, int, int, struct cmd *);
50int lg_checkarg(char *);
51int lg_checkcmd(int, char **, int *, struct cmd *);
52char *lg_completion(const char *, int);
53
54int
55lg_checkarg(char *arg)
56{
57 size_t len;
58 u_int i;
59
60 if (!(len = strlen(arg)))
61 return (0);
62
63#define allowed_in_string(_x) \
64 ((isalnum((unsigned char)_x) || isprint((unsigned char)_x)) && \
65 (_x != '%' && _x != '\\' && _x != ';' && _x != '&' && _x != '|'))
66
67 for (i = 0; i < len; i++) {
68 if (!allowed_in_string(arg[i])) {
69 fprintf(stderr(&__sF[2]), "invalid character in input\n");
70 return (EPERM1);
71 }
72 }
73#undef allowed_in_string
74 return (0);
75}
76
77char **
78lg_arg2argv(char *arg, int *argc)
79{
80 char **argv, *ptr = arg;
81 size_t len;
82 u_int i, c = 1;
83
84 if (lg_checkarg(arg) != 0)
17
Taking false branch
85 return (NULL((void *)0));
86 if (!(len = strlen(arg)))
18
Assuming 'len' is not equal to 0
19
Taking false branch
87 return (NULL((void *)0));
88
89 /* Count elements */
90 for (i = 0; i < len; i++) {
20
Loop condition is true. Entering loop body
22
Loop condition is false. Execution continues on line 101
91 if (isspace((unsigned char)arg[i])) {
21
Taking false branch
92 /* filter out additional options */
93 if (arg[i + 1] == '-') {
94 printf("invalid input\n");
95 return (NULL((void *)0));
96 }
97 arg[i] = '\0';
98 c++;
99 }
100 }
101 if (arg[0] == '\0')
23
Taking false branch
102 return (NULL((void *)0));
103
104 /* Generate array */
105 if ((argv = calloc(c + 1, sizeof(char *))) == NULL((void *)0)) {
24
Memory is allocated
25
Assuming the condition is false
26
Taking false branch
106 printf("fatal error: %s\n", strerror(errno(*__errno())));
107 return (NULL((void *)0));
108 }
109
110 argv[c] = NULL((void *)0);
111 *argc = c;
112
113 /* Fill array */
114 for (i = c = 0; i < len; i++) {
27
Loop condition is true. Entering loop body
30
Loop condition is false. Execution continues on line 122
115 if (arg[i] == '\0' || i
27.1
'i' is equal to 0
== 0) {
28
Taking true branch
116 if (i
28.1
'i' is equal to 0
!= 0)
29
Taking false branch
117 ptr = &arg[i + 1];
118 argv[c++] = ptr;
119 }
120 }
121
122 return (argv);
123}
124
125char **
126lg_argextra(char **argv, int argc, int off, struct cmd *cmdp)
127{
128 char **new_argv;
129 int i, c = 0, n;
130
131 if ((n = argc - off) < 0)
132 return (NULL((void *)0));
133
134 /* Count elements */
135 for (i = 0; cmdp->earg[i] != NULL((void *)0); i++)
136 c++;
137
138 /* Generate array */
139 if ((new_argv = calloc(c + n + 1, sizeof(char *))) == NULL((void *)0)) {
140 printf("fatal error: %s\n", strerror(errno(*__errno())));
141 return (NULL((void *)0));
142 }
143
144 /* Fill array */
145 for (i = c = 0; cmdp->earg[i] != NULL((void *)0); i++)
146 new_argv[c++] = cmdp->earg[i];
147
148 /* Append old array */
149 for (i = n; i < argc; i++)
150 new_argv[c++] = argv[i];
151
152 new_argv[c] = NULL((void *)0);
153
154 free(argv);
155
156 return (new_argv);
157}
158
159int
160lg_checkcmd(int argc, char **argv, int *off, struct cmd *cmd)
161{
162 char **cmdp = NULL((void *)0), *cmdstr = NULL((void *)0);
163 int i, ncmd, v, ret = -1;
164
165 if ((cmdstr = strdup(cmd->name)) == NULL((void *)0))
166 goto done;
167 if ((cmdp = lg_arg2argv(cmdstr, &ncmd)) == NULL((void *)0))
168 goto done;
169 if (ncmd > argc || argc > (ncmd + cmd->maxargs))
170 goto done;
171
172 for (i = 0; i < ncmd; i++)
173 if (strcmp(argv[i], cmdp[i]) != 0)
174 goto done;
175
176 if ((v = argc - ncmd) < 0 ||
177 (*off != -1 && *off < v))
178 goto done;
179 if (cmd->minargs && v < cmd->minargs) {
180 ret = EINVAL22;
181 goto done;
182 }
183 *off = v;
184 ret = 0;
185
186 done:
187 free(cmdp);
188 free(cmdstr);
189 return (ret);
190}
191
192char *
193lg_completion(const char *str, int state)
194{
195 static int lg_complidx, len;
196 const char *name;
197
198 if (state == 0) {
199 len = strlen(str);
200 lg_complidx = 0;
201 }
202 while ((name = cmds[lg_complidx].name) != NULL((void *)0)) {
203 lg_complidx++;
204 if (strncmp(name, str, len) == 0)
205 return (strdup(name));
206 }
207
208 return (NULL((void *)0));
209}
210
211int
212main(void)
213{
214 struct cmd *cmd = NULL((void *)0);
215 char prompt[HOST_NAME_MAX255+1], *line, **argp = NULL((void *)0);
216 int ncmd, ret, v = -1;
217 u_int i;
218
219 rl_readline_name = NAME"bgplg";
220 rl_completion_entry_function = lg_completion;
221
222 /* Ignore the whitespace character */
223 rl_basic_word_break_characters = "\t\n\"\\'`@$><=;|&{(";
224
225 while (!quit) {
1
Assuming 'quit' is 0
2
Loop condition is true. Entering loop body
8
Assuming 'quit' is 0
9
Loop condition is true. Entering loop body
226 v = -1;
227 gethostname(prompt, sizeof(prompt) - 2);
228 strlcat(prompt, "> ", sizeof(prompt));
229
230 if ((line = readline(prompt)) == NULL((void *)0)) {
3
Assuming the condition is false
4
Taking false branch
10
Assuming the condition is false
11
Taking false branch
231 printf("\n");
232 lg_help(cmds, NULL((void *)0));
233 continue;
234 }
235 if (!lg_strip(line))
5
Assuming the condition is true
6
Taking true branch
12
Assuming the condition is false
13
Taking false branch
236 goto next;
7
Control jumps to line 268
237 if (strcmp(line, "exit") == 0) {
14
Assuming the condition is false
15
Taking false branch
238 quit = 1;
239 goto next;
240 }
241
242 add_history(line);
243
244 if ((argp = lg_arg2argv(line, &ncmd)) == NULL((void *)0))
16
Calling 'lg_arg2argv'
31
Returned allocated memory
32
Taking false branch
245 goto next;
246
247 for (i = 0; cmds[i].name != NULL((void *)0); i++) {
33
Assuming field 'name' is not equal to NULL
34
Loop condition is true. Entering loop body
36
Assuming field 'name' is equal to NULL
37
Loop condition is false. Execution continues on line 257
248 ret = lg_checkcmd(ncmd, argp, &v, &cmds[i]);
249 if (ret
34.1
'ret' is equal to 0
== 0)
35
Taking true branch
250 cmd = &cmds[i];
251 else if (ret == EINVAL22) {
252 printf("invalid number of arguments\n");
253 goto next;
254 }
255 }
256
257 if (cmd
37.1
'cmd' is not equal to NULL
== NULL((void *)0)) {
38
Taking false branch
258 printf("invalid command\n");
259 } else if (cmd->func != NULL((void *)0)) {
39
Assuming field 'func' is equal to NULL
40
Taking false branch
260 cmd->func(cmds, argp);
261 } else {
262 if ((argp = lg_argextra(argp, ncmd, v, cmd)) == NULL((void *)0))
41
Taking true branch
263 goto next;
42
Control jumps to line 268
264 lg_exec(cmd->earg[0], argp);
265 }
266
267 next:
268 free(argp);
43
Potential leak of memory pointed to by 'argp'
269 argp = NULL((void *)0);
270 free(line);
271 line = NULL((void *)0);
272 cmd = NULL((void *)0);
273 }
274
275 return (0);
276}