Before reading the n_samples field of the MANUAL_LIST reply, check if it is actually contained in the received message. This does not change the outcome of the client's length check as the returned length was always larger than the length of the truncated reply and it was dropped anyway, but it prevents the client from reading uninitialized memory.
223 lines
9.1 KiB
C
223 lines
9.1 KiB
C
/*
|
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
|
|
|
**********************************************************************
|
|
* Copyright (C) Richard P. Curnow 1997-2002
|
|
* Copyright (C) Miroslav Lichvar 2014-2016
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
**********************************************************************
|
|
|
|
=======================================================================
|
|
|
|
Routines to compute the expected length of a command or reply packet.
|
|
These operate on the RAW NETWORK packets, from the point of view of
|
|
integer endianness within the structures.
|
|
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include "sysincl.h"
|
|
|
|
#include "util.h"
|
|
#include "pktlength.h"
|
|
|
|
#define PADDING_LENGTH_(request_length, reply_length) \
|
|
(uint16_t)((request_length) < (reply_length) ? (reply_length) - (request_length) : 0)
|
|
|
|
#define PADDING_LENGTH(request_data, reply_data) \
|
|
PADDING_LENGTH_(offsetof(CMD_Request, request_data), offsetof(CMD_Reply, reply_data))
|
|
|
|
#define REQ_LENGTH_ENTRY(request_data_field, reply_data_field) \
|
|
{ offsetof(CMD_Request, data.request_data_field.EOR), \
|
|
PADDING_LENGTH(data.request_data_field.EOR, data.reply_data_field.EOR) }
|
|
|
|
#define RPY_LENGTH_ENTRY(reply_data_field) \
|
|
offsetof(CMD_Reply, data.reply_data_field.EOR)
|
|
|
|
/* ================================================== */
|
|
|
|
struct request_length {
|
|
uint16_t command;
|
|
uint16_t padding;
|
|
};
|
|
|
|
static const struct request_length request_lengths[] = {
|
|
REQ_LENGTH_ENTRY(null, null), /* NULL */
|
|
REQ_LENGTH_ENTRY(online, null), /* ONLINE */
|
|
REQ_LENGTH_ENTRY(offline, null), /* OFFLINE */
|
|
REQ_LENGTH_ENTRY(burst, null), /* BURST */
|
|
REQ_LENGTH_ENTRY(modify_minpoll, null), /* MODIFY_MINPOLL */
|
|
REQ_LENGTH_ENTRY(modify_maxpoll, null), /* MODIFY_MAXPOLL */
|
|
REQ_LENGTH_ENTRY(dump, null), /* DUMP */
|
|
REQ_LENGTH_ENTRY(modify_maxdelay, null), /* MODIFY_MAXDELAY */
|
|
REQ_LENGTH_ENTRY(modify_maxdelayratio, null), /* MODIFY_MAXDELAYRATIO */
|
|
REQ_LENGTH_ENTRY(modify_maxupdateskew, null), /* MODIFY_MAXUPDATESKEW */
|
|
REQ_LENGTH_ENTRY(logon, null), /* LOGON */
|
|
REQ_LENGTH_ENTRY(settime, manual_timestamp), /* SETTIME */
|
|
{ 0, 0 }, /* LOCAL */
|
|
REQ_LENGTH_ENTRY(manual, null), /* MANUAL */
|
|
REQ_LENGTH_ENTRY(null, n_sources), /* N_SOURCES */
|
|
REQ_LENGTH_ENTRY(source_data, source_data), /* SOURCE_DATA */
|
|
REQ_LENGTH_ENTRY(null, null), /* REKEY */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* ALLOW */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* ALLOWALL */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* DENY */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* DENYALL */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* CMDALLOW */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* CMDALLOWALL */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* CMDDENY */
|
|
REQ_LENGTH_ENTRY(allow_deny, null), /* CMDDENYALL */
|
|
REQ_LENGTH_ENTRY(ac_check, null), /* ACCHECK */
|
|
REQ_LENGTH_ENTRY(ac_check, null), /* CMDACCHECK */
|
|
{ 0, 0 }, /* ADD_SERVER */
|
|
{ 0, 0 }, /* ADD_PEER */
|
|
REQ_LENGTH_ENTRY(del_source, null), /* DEL_SOURCE */
|
|
REQ_LENGTH_ENTRY(null, null), /* WRITERTC */
|
|
REQ_LENGTH_ENTRY(dfreq, null), /* DFREQ */
|
|
REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET */
|
|
REQ_LENGTH_ENTRY(null, tracking), /* TRACKING */
|
|
REQ_LENGTH_ENTRY(sourcestats, sourcestats), /* SOURCESTATS */
|
|
REQ_LENGTH_ENTRY(null, rtc), /* RTCREPORT */
|
|
REQ_LENGTH_ENTRY(null, null), /* TRIMRTC */
|
|
REQ_LENGTH_ENTRY(null, null), /* CYCLELOGS */
|
|
{ 0, 0 }, /* SUBNETS_ACCESSED - not supported */
|
|
{ 0, 0 }, /* CLIENT_ACCESSES - not supported */
|
|
{ 0, 0 }, /* CLIENT_ACCESSES_BY_INDEX - not supported */
|
|
REQ_LENGTH_ENTRY(null, manual_list), /* MANUAL_LIST */
|
|
REQ_LENGTH_ENTRY(manual_delete, null), /* MANUAL_DELETE */
|
|
REQ_LENGTH_ENTRY(null, null), /* MAKESTEP */
|
|
REQ_LENGTH_ENTRY(null, activity), /* ACTIVITY */
|
|
REQ_LENGTH_ENTRY(modify_minstratum, null), /* MODIFY_MINSTRATUM */
|
|
REQ_LENGTH_ENTRY(modify_polltarget, null), /* MODIFY_POLLTARGET */
|
|
REQ_LENGTH_ENTRY(modify_maxdelaydevratio, null), /* MODIFY_MAXDELAYDEVRATIO */
|
|
REQ_LENGTH_ENTRY(null, null), /* RESELECT */
|
|
REQ_LENGTH_ENTRY(reselect_distance, null), /* RESELECTDISTANCE */
|
|
REQ_LENGTH_ENTRY(modify_makestep, null), /* MODIFY_MAKESTEP */
|
|
REQ_LENGTH_ENTRY(null, smoothing), /* SMOOTHING */
|
|
REQ_LENGTH_ENTRY(smoothtime, null), /* SMOOTHTIME */
|
|
REQ_LENGTH_ENTRY(null, null), /* REFRESH */
|
|
REQ_LENGTH_ENTRY(null, server_stats), /* SERVER_STATS */
|
|
REQ_LENGTH_ENTRY(client_accesses_by_index,
|
|
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
|
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
|
|
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
|
|
{ 0, 0 }, /* ADD_SERVER2 */
|
|
{ 0, 0 }, /* ADD_PEER2 */
|
|
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER3 */
|
|
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER3 */
|
|
};
|
|
|
|
static const uint16_t reply_lengths[] = {
|
|
0, /* empty slot */
|
|
RPY_LENGTH_ENTRY(null), /* NULL */
|
|
RPY_LENGTH_ENTRY(n_sources), /* N_SOURCES */
|
|
RPY_LENGTH_ENTRY(source_data), /* SOURCE_DATA */
|
|
0, /* MANUAL_TIMESTAMP */
|
|
RPY_LENGTH_ENTRY(tracking), /* TRACKING */
|
|
RPY_LENGTH_ENTRY(sourcestats), /* SOURCESTATS */
|
|
RPY_LENGTH_ENTRY(rtc), /* RTC */
|
|
0, /* SUBNETS_ACCESSED - not supported */
|
|
0, /* CLIENT_ACCESSES - not supported */
|
|
0, /* CLIENT_ACCESSES_BY_INDEX - not supported */
|
|
0, /* MANUAL_LIST - variable length */
|
|
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
|
|
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
|
|
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
|
|
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
|
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
|
|
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
|
|
};
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
PKL_CommandLength(CMD_Request *r)
|
|
{
|
|
uint32_t type;
|
|
int command_length;
|
|
|
|
assert(sizeof (request_lengths) / sizeof (request_lengths[0]) == N_REQUEST_TYPES);
|
|
|
|
type = ntohs(r->command);
|
|
if (type >= N_REQUEST_TYPES)
|
|
return 0;
|
|
|
|
command_length = request_lengths[type].command;
|
|
if (!command_length)
|
|
return 0;
|
|
|
|
return command_length + PKL_CommandPaddingLength(r);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
PKL_CommandPaddingLength(CMD_Request *r)
|
|
{
|
|
uint32_t type;
|
|
|
|
if (r->version < PROTO_VERSION_PADDING)
|
|
return 0;
|
|
|
|
type = ntohs(r->command);
|
|
|
|
if (type >= N_REQUEST_TYPES)
|
|
return 0;
|
|
|
|
return request_lengths[ntohs(r->command)].padding;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
PKL_ReplyLength(CMD_Reply *r, int read_length)
|
|
{
|
|
uint32_t type;
|
|
|
|
assert(sizeof (reply_lengths) / sizeof (reply_lengths[0]) == N_REPLY_TYPES);
|
|
|
|
if (read_length < (int)offsetof(CMD_Reply, data))
|
|
return 0;
|
|
|
|
type = ntohs(r->reply);
|
|
|
|
/* Note that reply type codes start from 1, not 0 */
|
|
if (type < 1 || type >= N_REPLY_TYPES)
|
|
return 0;
|
|
|
|
/* Length of MANUAL_LIST depends on number of samples stored in it */
|
|
if (type == RPY_MANUAL_LIST) {
|
|
uint32_t ns;
|
|
|
|
if (r->status != htons(STT_SUCCESS))
|
|
return offsetof(CMD_Reply, data);
|
|
|
|
if (read_length < (int)offsetof(CMD_Reply, data.manual_list.samples))
|
|
return 0;
|
|
|
|
ns = ntohl(r->data.manual_list.n_samples);
|
|
if (ns > MAX_MANUAL_LIST_SAMPLES)
|
|
return 0;
|
|
|
|
return offsetof(CMD_Reply, data.manual_list.samples) +
|
|
ns * sizeof (RPY_ManualListSample);
|
|
}
|
|
|
|
return reply_lengths[type];
|
|
}
|
|
|
|
/* ================================================== */
|
|
|