Bug Summary

File:programs/pluto/ikev2_liveness.c
Warning:line 69, column 2
Value stored to 'delay' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ikev2_liveness.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 -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mdisable-fp-elim -relaxed-aliasing -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib64/clang/8.0.0 -D TimeZoneOffset=timezone -D linux -D PIE -D NSS_IPSEC_PROFILE -D XFRM_SUPPORT -D USE_XFRM_INTERFACE -D USE_DNSSEC -D DEFAULT_DNSSEC_ROOTKEY_FILE="/var/lib/unbound/root.key" -D HAVE_LABELED_IPSEC -D HAVE_SECCOMP -D LIBCURL -D USE_LINUX_AUDIT -D USE_SYSTEMD_WATCHDOG -D HAVE_NM -D XAUTH_HAVE_PAM -D USE_3DES -D USE_AES -D USE_CAMELLIA -D USE_CHACHA -D USE_DH31 -D USE_MD5 -D USE_SHA1 -D USE_SHA2 -D USE_PRF_AES_XCBC -D DEFAULT_RUNDIR="/run/pluto" -D IPSEC_CONF="/etc/ipsec.conf" -D IPSEC_CONFDDIR="/etc/ipsec.d" -D IPSEC_NSSDIR="/etc/ipsec.d" -D IPSEC_CONFDIR="/etc" -D IPSEC_EXECDIR="/usr/local/libexec/ipsec" -D IPSEC_SBINDIR="/usr/local/sbin" -D IPSEC_VARDIR="/var" -D POLICYGROUPSDIR="/etc/ipsec.d/policies" -D IPSEC_SECRETS_FILE="/etc/ipsec.secrets" -D FORCE_PR_ASSERT -D USE_FORK=1 -D USE_VFORK=0 -D USE_DAEMON=0 -D USE_PTHREAD_SETSCHEDPRIO=1 -D GCC_LINT -D HAVE_LIBCAP_NG -I . -I ../../OBJ.linux.x86_64/programs/pluto -I ../../include -I /usr/include/nss3 -I /usr/include/nspr4 -I /home/build/libreswan/programs/pluto/linux-copy -D HERE_BASENAME="ikev2_liveness.c" -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/8.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-missing-field-initializers -std=gnu99 -fdebug-compilation-dir /home/build/libreswan/programs/pluto -ferror-limit 19 -fmessage-length 0 -stack-protector 3 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /tmp/scan-build-2020-09-09-193337-25440-1 -x c /home/build/libreswan/programs/pluto/ikev2_liveness.c -faddrsig
1/* IKEv2 LIVENESS probe
2 *
3 * Copyright (C) 1997 Angelos D. Keromytis.
4 * Copyright (C) 1998-2001 D. Hugh Redelmeier.
5 * Copyright (C) 2005-2008 Michael Richardson <mcr@xelerance.com>
6 * Copyright (C) 2008-2010 Paul Wouters <paul@xelerance.com>
7 * Copyright (C) 2009 David McCullough <david_mccullough@securecomputing.com>
8 * Copyright (C) 2012 Avesh Agarwal <avagarwa@redhat.com>
9 * Copyright (C) 2012-2019 Paul Wouters <pwouters@redhat.com>
10 * Copyright (C) 2013 Matt Rogers <mrogers@redhat.com>
11 * Copyright (C) 2017 Antony Antony <antony@phenome.org>
12 * Copyright (C) 2017-2019 Andrew Cagney <cagney@gnu.org>
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25#include "defs.h"
26#include "state.h"
27#include "log.h"
28#include "connections.h"
29#include "iface.h"
30#include "kernel.h"
31#include "ikev2_send.h"
32#include "pluto_stats.h"
33#include "timer.h"
34#include "server.h"
35#include "ikev2.h" /* for struct state_v2_microcode */
36#include "ikev2_liveness.h"
37#include "state_db.h" /* for state_by_serialno() */
38#include "ikev2_states.h"
39
40static stf_status send_v2_liveness_request(struct ike_sa *ike,
41 struct child_sa *child UNUSED__attribute__ ((unused)),
42 struct msg_digest *md UNUSED__attribute__ ((unused)))
43{
44 /*
45 * XXX: What does it mean to send a liveness probe for a CHILD
46 * SA? Since the packet contents are empty there's nothing
47 * for the other end to identify which child this is for!
48 *
49 * XXX: See record 'n'_send for how screwed up all this is:
50 * need to pass in the CHILD SA so that it's liveness
51 * timestamp (and not the IKE) gets updated.
52 */
53 pstats_ike_dpd_sent++;
54 stf_status e = record_v2_informational_request("liveness probe informational request",
55 ike, &ike->sa/*sender*/,
56 NULL((void*)0)/*no payloads to emit*/);
57 if (e != STF_OK) {
58 return STF_INTERNAL_ERROR;
59 }
60 return STF_OK;
61}
62
63static void schedule_liveness(struct child_sa *child, deltatime_t time_since_last_contact,
64 const char *reason)
65{
66 struct connection *c = child->sa.st_connection;
67 deltatime_t delay = c->dpd_delay;
68 /* reduce wait if contact was by some other means */
69 delay = deltatime_sub(delay, time_since_last_contact);
Value stored to 'delay' is never read
70 /* in case above screws up? */
71 delay = deltatime_max(c->dpd_delay, deltatime(MIN_LIVENESS1));
72 LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 <<
(DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[(
(size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_
= ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf
), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf
= ((void*)0)) for (; buf != ((void*)0); jambuf_to_debug_stream
(buf), buf = ((void*)0))
{
73 deltatime_buf db;
74 endpoint_buf remote_buf;
75 jam(buf, "liveness: #%lu scheduling next check for %s in %s seconds",
76 child->sa.st_serialno,
77 str_endpoint(&child->sa.st_remote_endpoint, &remote_buf),
78 str_deltatime(delay, &db));
79 if (deltatime_cmp(time_since_last_contact, !=, deltatime(0))(deltatime_cmp_sign(time_since_last_contact, deltatime(0)) !=
0)
) {
80 deltatime_buf lcb;
81 jam(buf, " (%s was %s seconds ago)",
82 reason, str_deltatime(time_since_last_contact, &lcb));
83 } else {
84 jam(buf, " (%s)", reason);
85 }
86 }
87 event_schedule(EVENT_v2_LIVENESS, delay, &child->sa);
88}
89
90/* note: this mutates *st by calling get_sa_info */
91void liveness_check(struct state *st)
92{
93 passert(st->st_ike_version == IKEv2){ _Bool assertion__ = st->st_ike_version == IKEv2; if (!assertion__
) { lsw_passert_fail((where_t) { .func = __func__, .basename =
"ikev2_liveness.c" , .line = 93}, "%s", "st->st_ike_version == IKEv2"
); } }
;
94 struct state *pst = state_by_serialno(st->st_clonedfrom);
95 if (pst == NULL((void*)0)) {
96 /*
97 * When the retransmits timeout the IKE SA gets
98 * deleted, but not the child.
99 *
100 * XXX: might need to tone this down.
101 */
102 dbg("liveness: state #%lu has no IKE SA; deleting orphaned child",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: state #%lu has no IKE SA; deleting orphaned child"
, st->st_serialno); } }
103 st->st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: state #%lu has no IKE SA; deleting orphaned child"
, st->st_serialno); } }
;
104 event_delete(EVENT_SO_DISCARD, st);
105 event_schedule(EVENT_SO_DISCARD, deltatime(0), st);
106 return;
107 }
108 struct ike_sa *ike = pexpect_ike_sa(pst);
109
110 struct child_sa *child = pexpect_child_sa(st);
111 if (child == NULL((void*)0)) {
112 return;
113 }
114 struct connection *c = child->sa.st_connection;
115 struct v2_msgid_window *our = &ike->sa.st_v2_msgid_windows.initiator;
116 /* if nothing else this is when the state was created */
117 pexpect(!is_monotime_epoch(our->last_contact))({ _Bool assertion__ = !is_monotime_epoch(our->last_contact
); if (!assertion__) { log_pexpect((where_t) { .func = __func__
, .basename = "ikev2_liveness.c" , .line = 117}, "%s", "!is_monotime_epoch(our->last_contact)"
); } assertion__; })
;
118 monotime_t now = mononow();
119
120 /*
121 * If the child is lingering (replaced but not yet deleted),
122 * don't do liveness.
123 */
124 if (c->newest_ipsec_sa != child->sa.st_serialno) {
125 dbg("liveness: #%lu was replaced by #%lu so not needed",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu was replaced by #%lu so not needed"
, child->sa.st_serialno, c->newest_ipsec_sa); } }
126 child->sa.st_serialno, c->newest_ipsec_sa){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu was replaced by #%lu so not needed"
, child->sa.st_serialno, c->newest_ipsec_sa); } }
;
127 return;
128 }
129
130 /*
131 * If there's been traffic flowing through the CHILD SA and it
132 * was less than .dpd_delay ago then re-schedule the probe.
133 *
134 * XXX: is this useful? Liveness should be checking
135 * round-trip but this is just looking at incoming data -
136 * outgoing data could lost and this traffic is all
137 * re-transmit requests ...
138 */
139 deltatime_t time_since_last_message;
140 if (get_sa_info(&child->sa, true1, &time_since_last_message) &&
141 /* time_since_last_message < .dpd_delay */
142 deltatime_cmp(time_since_last_message, <, c->dpd_delay)(deltatime_cmp_sign(time_since_last_message, c->dpd_delay)
< 0)
) {
143 /*
144 * Update .st_liveness_last, with the time of this
145 * traffic (unless other traffic is more recent).
146 */
147 monotime_t last_contact = monotime_sub(now, time_since_last_message);
148 if (monobefore(our->last_contact, last_contact)) {
149 monotime_buf m0, m1;
150 dbg("liveness: #%lu updating #%lu last contact from %s to %s (last IPsec traffic flow)",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu updating #%lu last contact from %s to %s (last IPsec traffic flow)"
, child->sa.st_serialno, ike->sa.st_serialno, str_monotime
(our->last_contact, &m0), str_monotime(last_contact, &
m1)); } }
151 child->sa.st_serialno, ike->sa.st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu updating #%lu last contact from %s to %s (last IPsec traffic flow)"
, child->sa.st_serialno, ike->sa.st_serialno, str_monotime
(our->last_contact, &m0), str_monotime(last_contact, &
m1)); } }
152 str_monotime(our->last_contact, &m0),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu updating #%lu last contact from %s to %s (last IPsec traffic flow)"
, child->sa.st_serialno, ike->sa.st_serialno, str_monotime
(our->last_contact, &m0), str_monotime(last_contact, &
m1)); } }
153 str_monotime(last_contact, &m1)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu updating #%lu last contact from %s to %s (last IPsec traffic flow)"
, child->sa.st_serialno, ike->sa.st_serialno, str_monotime
(our->last_contact, &m0), str_monotime(last_contact, &
m1)); } }
;
154 our->last_contact = last_contact;
155 }
156 /*
157 * schedule in .dpd_delay seconds, but adjust for:
158 * time since last traffic, and min liveness vis
159 *
160 * max(dpd_delay - time_since_last_message, * deltatime(MIN_LIVENESS))
161 */
162 schedule_liveness(child, time_since_last_message, "recent IPsec traffic");
163 return;
164 }
165
166 /*
167 * If there's already a message request outstanding assume it
168 * will succeed - if it doesn't the entire family will be
169 * killed.
170 *
171 * No probe is needed for another .dpd_delay seconds.
172 */
173 if (v2_msgid_request_outstanding(ike)) {
174 schedule_liveness(child, deltatime(0), "request outstanding");
175 return;
176 }
177
178 /*
179 * If there's an exchange pending; assume it will succeed (for
180 * instance last exchange just finished, next exchange about
181 * to start), reschedule the probe.
182 */
183 if (v2_msgid_request_pending(ike)) {
184 schedule_liveness(child, deltatime(0), "request pending");
185 return;
186 }
187
188 /*
189 * If was a successful exchange less than .dpd_delay ago,
190 * reschedule the probe.
191 */
192 deltatime_t time_since_last_contact = monotimediff(now, our->last_contact);
193 if (deltatime_cmp(time_since_last_contact, <, c->dpd_delay)(deltatime_cmp_sign(time_since_last_contact, c->dpd_delay)
< 0)
) {
194 schedule_liveness(child, time_since_last_contact, "successful exchange");
195 return;
196 }
197
198 endpoint_buf remote_buf;
199 struct state *handler = &ike->sa;
200 dbg("liveness: #%lu queueing liveness probe for %s using #%lu",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu queueing liveness probe for %s using #%lu"
, child->sa.st_serialno, str_endpoint(&child->sa.st_remote_endpoint
, &remote_buf), handler->st_serialno); } }
201 child->sa.st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu queueing liveness probe for %s using #%lu"
, child->sa.st_serialno, str_endpoint(&child->sa.st_remote_endpoint
, &remote_buf), handler->st_serialno); } }
202 str_endpoint(&child->sa.st_remote_endpoint, &remote_buf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu queueing liveness probe for %s using #%lu"
, child->sa.st_serialno, str_endpoint(&child->sa.st_remote_endpoint
, &remote_buf), handler->st_serialno); } }
203 handler->st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("liveness: #%lu queueing liveness probe for %s using #%lu"
, child->sa.st_serialno, str_endpoint(&child->sa.st_remote_endpoint
, &remote_buf), handler->st_serialno); } }
;
204 initiate_v2_liveness(child->sa.st_logger, ike);
205
206 /* in case above screws up? */
207 schedule_liveness(child, deltatime(0), "backup for liveness probe");
208}
209
210/*
211 * XXX: where to put this?
212 */
213
214static const struct state_v2_microcode v2_liveness_probe = {
215 .story = "liveness probe",
216 .state = STATE_V2_ESTABLISHED_IKE_SA,
217 .next_state = STATE_V2_ESTABLISHED_IKE_SA,
218 .send = MESSAGE_REQUEST,
219 .processor = send_v2_liveness_request,
220 .timeout_event = EVENT_RETAIN,
221 .flags = SMF2_SUPPRESS_SUCCESS_LOG,
222};
223
224void initiate_v2_liveness(struct logger *logger, struct ike_sa *ike)
225{
226 const struct state_v2_microcode *transition = &v2_liveness_probe;
227 if (ike->sa.st_state->kind != transition->state) {
228 log_message(RC_LOG, logger,
229 "liveness: #%lu unexpectedly in state %s; should be %s",
230 ike->sa.st_serialno, ike->sa.st_state->short_name,
231 finite_states[transition->state]->short_name);
232 return;
233 }
234
235 v2_msgid_queue_initiator(ike, &ike->sa, ISAKMP_v2_INFORMATIONAL,
236 transition, NULL((void*)0));
237}