Bug Summary

File:build-scan/../src/nspawn/nspawn-expose-ports.c
Warning:line 78, column 17
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nspawn-expose-ports.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 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/nspawn/libnspawn-core.a.p -I src/nspawn -I ../src/nspawn -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/nspawn/nspawn-expose-ports.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "sd-netlink.h"
4
5#include "alloc-util.h"
6#include "fd-util.h"
7#include "firewall-util.h"
8#include "in-addr-util.h"
9#include "local-addresses.h"
10#include "netlink-util.h"
11#include "nspawn-expose-ports.h"
12#include "parse-util.h"
13#include "socket-util.h"
14#include "string-util.h"
15#include "util.h"
16
17int expose_port_parse(ExposePort **l, const char *s) {
18
19 const char *split, *e;
20 uint16_t container_port, host_port;
21 int protocol;
22 ExposePort *p;
23 int r;
24
25 assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("l"), "../src/nspawn/nspawn-expose-ports.c"
, 25, __PRETTY_FUNCTION__); } while (0)
;
26 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/nspawn/nspawn-expose-ports.c"
, 26, __PRETTY_FUNCTION__); } while (0)
;
27
28 if ((e = startswith(s, "tcp:")))
29 protocol = IPPROTO_TCPIPPROTO_TCP;
30 else if ((e = startswith(s, "udp:")))
31 protocol = IPPROTO_UDPIPPROTO_UDP;
32 else {
33 e = s;
34 protocol = IPPROTO_TCPIPPROTO_TCP;
35 }
36
37 split = strchr(e, ':');
38 if (split) {
39 char v[split - e + 1];
40
41 memcpy(v, e, split - e);
42 v[split - e] = 0;
43
44 r = parse_ip_port(v, &host_port);
45 if (r < 0)
46 return -EINVAL22;
47
48 r = parse_ip_port(split + 1, &container_port);
49 } else {
50 r = parse_ip_port(e, &container_port);
51 host_port = container_port;
52 }
53
54 if (r < 0)
55 return -EINVAL22;
56
57 LIST_FOREACH(ports, p, *l)for ((p) = (*l); (p); (p) = (p)->ports_next)
58 if (p->protocol == protocol && p->host_port == host_port)
59 return -EEXIST17;
60
61 p = new(ExposePort, 1)((ExposePort*) malloc_multiply(sizeof(ExposePort), (1)));
62 if (!p)
63 return -ENOMEM12;
64
65 p->protocol = protocol;
66 p->host_port = host_port;
67 p->container_port = container_port;
68
69 LIST_PREPEND(ports, *l, p)do { typeof(*(*l)) **_head = &(*l), *_item = (p); do { if
((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("_item"), "../src/nspawn/nspawn-expose-ports.c"
, 69, __PRETTY_FUNCTION__); } while (0); if ((_item->ports_next
= *_head)) _item->ports_next->ports_prev = _item; _item
->ports_prev = ((void*)0); *_head = _item; } while (0)
;
70
71 return 0;
72}
73
74void expose_port_free_all(ExposePort *p) {
75
76 while (p) {
1
Loop condition is true. Entering loop body
10
Loop condition is true. Entering loop body
77 ExposePort *q = p;
78 LIST_REMOVE(ports, p, q)do { typeof(*(p)) **_head = &(p), *_item = (q); do { if (
(__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("_item"), "../src/nspawn/nspawn-expose-ports.c", 78, __PRETTY_FUNCTION__
); } while (0); if (_item->ports_next) _item->ports_next
->ports_prev = _item->ports_prev; if (_item->ports_prev
) _item->ports_prev->ports_next = _item->ports_next;
else { do { if ((__builtin_expect(!!(!(*_head == _item)),0))
) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/nspawn/nspawn-expose-ports.c", 78, __PRETTY_FUNCTION__
); } while (0); *_head = _item->ports_next; } _item->ports_next
= _item->ports_prev = ((void*)0); } while (0)
;
2
Taking false branch
3
Loop condition is false. Exiting loop
4
Assuming field 'ports_next' is null
5
Taking false branch
6
Assuming field 'ports_prev' is non-null
7
Taking true branch
8
Loop condition is false. Exiting loop
11
Taking false branch
12
Loop condition is false. Exiting loop
13
Use of memory after it is freed
79 free(q);
9
Memory is released
80 }
81}
82
83int expose_port_flush(ExposePort* l, union in_addr_union *exposed) {
84 ExposePort *p;
85 int r, af = AF_INET2;
86
87 assert(exposed)do { if ((__builtin_expect(!!(!(exposed)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("exposed"), "../src/nspawn/nspawn-expose-ports.c"
, 87, __PRETTY_FUNCTION__); } while (0)
;
88
89 if (!l)
90 return 0;
91
92 if (in_addr_is_null(af, exposed))
93 return 0;
94
95 log_debug("Lost IP address.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 95, __func__, "Lost IP address."
) : -abs(_e); })
;
96
97 LIST_FOREACH(ports, p, l)for ((p) = (l); (p); (p) = (p)->ports_next) {
98 r = fw_add_local_dnat(false0,
99 af,
100 p->protocol,
101 NULL((void*)0),
102 NULL((void*)0), 0,
103 NULL((void*)0), 0,
104 p->host_port,
105 exposed,
106 p->container_port,
107 NULL((void*)0));
108 if (r < 0)
109 log_warning_errno(r, "Failed to modify firewall: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 109, __func__, "Failed to modify firewall: %m"
) : -abs(_e); })
;
110 }
111
112 *exposed = IN_ADDR_NULL((union in_addr_union) {});
113 return 0;
114}
115
116int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *exposed) {
117 _cleanup_free___attribute__((cleanup(freep))) struct local_address *addresses = NULL((void*)0);
118 _cleanup_free___attribute__((cleanup(freep))) char *pretty = NULL((void*)0);
119 union in_addr_union new_exposed;
120 ExposePort *p;
121 bool_Bool add;
122 int af = AF_INET2, r;
123
124 assert(exposed)do { if ((__builtin_expect(!!(!(exposed)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("exposed"), "../src/nspawn/nspawn-expose-ports.c"
, 124, __PRETTY_FUNCTION__); } while (0)
;
125
126 /* Invoked each time an address is added or removed inside the
127 * container */
128
129 if (!l)
130 return 0;
131
132 r = local_addresses(rtnl, 0, af, &addresses);
133 if (r < 0)
134 return log_error_errno(r, "Failed to enumerate local addresses: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 134, __func__, "Failed to enumerate local addresses: %m"
) : -abs(_e); })
;
135
136 add = r > 0 &&
137 addresses[0].family == af &&
138 addresses[0].scope < RT_SCOPE_LINK;
139
140 if (!add)
141 return expose_port_flush(l, exposed);
142
143 new_exposed = addresses[0].address;
144 if (in_addr_equal(af, exposed, &new_exposed))
145 return 0;
146
147 in_addr_to_string(af, &new_exposed, &pretty);
148 log_debug("New container IP is %s.", strna(pretty))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 148, __func__, "New container IP is %s."
, strna(pretty)) : -abs(_e); })
;
149
150 LIST_FOREACH(ports, p, l)for ((p) = (l); (p); (p) = (p)->ports_next) {
151
152 r = fw_add_local_dnat(true1,
153 af,
154 p->protocol,
155 NULL((void*)0),
156 NULL((void*)0), 0,
157 NULL((void*)0), 0,
158 p->host_port,
159 &new_exposed,
160 p->container_port,
161 in_addr_is_null(af, exposed) ? NULL((void*)0) : exposed);
162 if (r < 0)
163 log_warning_errno(r, "Failed to modify firewall: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 163, __func__, "Failed to modify firewall: %m"
) : -abs(_e); })
;
164 }
165
166 *exposed = new_exposed;
167 return 0;
168}
169
170int expose_port_send_rtnl(int send_fd) {
171 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
172 int r;
173
174 assert(send_fd >= 0)do { if ((__builtin_expect(!!(!(send_fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("send_fd >= 0"), "../src/nspawn/nspawn-expose-ports.c"
, 174, __PRETTY_FUNCTION__); } while (0)
;
175
176 fd = socket(PF_NETLINK16, SOCK_RAWSOCK_RAW|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, NETLINK_ROUTE0);
177 if (fd < 0)
178 return log_error_errno(errno, "Failed to allocate container netlink: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/nspawn/nspawn-expose-ports.c", 178
, __func__, "Failed to allocate container netlink: %m") : -abs
(_e); })
;
179
180 /* Store away the fd in the socket, so that it stays open as
181 * long as we run the child */
182 r = send_one_fd(send_fd, fd, 0)send_one_fd_iov_sa(send_fd, fd, ((void*)0), 0, ((void*)0), 0,
0)
;
183 if (r < 0)
184 return log_error_errno(r, "Failed to send netlink fd: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 184, __func__, "Failed to send netlink fd: %m"
) : -abs(_e); })
;
185
186 return 0;
187}
188
189int expose_port_watch_rtnl(
190 sd_event *event,
191 int recv_fd,
192 sd_netlink_message_handler_t handler,
193 union in_addr_union *exposed,
194 sd_netlink **ret) {
195 _cleanup_(sd_netlink_unrefp)__attribute__((cleanup(sd_netlink_unrefp))) sd_netlink *rtnl = NULL((void*)0);
196 int fd, r;
197
198 assert(event)do { if ((__builtin_expect(!!(!(event)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("event"), "../src/nspawn/nspawn-expose-ports.c"
, 198, __PRETTY_FUNCTION__); } while (0)
;
199 assert(recv_fd >= 0)do { if ((__builtin_expect(!!(!(recv_fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("recv_fd >= 0"), "../src/nspawn/nspawn-expose-ports.c"
, 199, __PRETTY_FUNCTION__); } while (0)
;
200 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/nspawn/nspawn-expose-ports.c"
, 200, __PRETTY_FUNCTION__); } while (0)
;
201
202 fd = receive_one_fd(recv_fd, 0);
203 if (fd < 0)
204 return log_error_errno(fd, "Failed to recv netlink fd: %m")({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 204, __func__, "Failed to recv netlink fd: %m"
) : -abs(_e); })
;
205
206 r = sd_netlink_open_fd(&rtnl, fd);
207 if (r < 0) {
208 safe_close(fd);
209 return log_error_errno(r, "Failed to create rtnl object: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 209, __func__, "Failed to create rtnl object: %m"
) : -abs(_e); })
;
210 }
211
212 r = sd_netlink_add_match(rtnl, RTM_NEWADDRRTM_NEWADDR, handler, exposed);
213 if (r < 0)
214 return log_error_errno(r, "Failed to subscribe to RTM_NEWADDR messages: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 214, __func__, "Failed to subscribe to RTM_NEWADDR messages: %m"
) : -abs(_e); })
;
215
216 r = sd_netlink_add_match(rtnl, RTM_DELADDRRTM_DELADDR, handler, exposed);
217 if (r < 0)
218 return log_error_errno(r, "Failed to subscribe to RTM_DELADDR messages: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 218, __func__, "Failed to subscribe to RTM_DELADDR messages: %m"
) : -abs(_e); })
;
219
220 r = sd_netlink_attach_event(rtnl, event, 0);
221 if (r < 0)
222 return log_error_errno(r, "Failed to add to even loop: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/nspawn/nspawn-expose-ports.c", 222, __func__, "Failed to add to even loop: %m"
) : -abs(_e); })
;
223
224 *ret = TAKE_PTR(rtnl)({ typeof(rtnl) _ptr_ = (rtnl); (rtnl) = ((void*)0); _ptr_; }
)
;
225
226 return 0;
227}