File: | build-scan/../src/nspawn/nspawn-expose-ports.c |
Warning: | line 78, column 17 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
17 | int 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 | ||||
74 | void expose_port_free_all(ExposePort *p) { | |||
75 | ||||
76 | while (p) { | |||
| ||||
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); | |||
| ||||
79 | free(q); | |||
80 | } | |||
81 | } | |||
82 | ||||
83 | int 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 | ||||
116 | int 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 | ||||
170 | int 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 | ||||
189 | int 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 | } |