diff options
| author | Hitendra Prajapati <hprajapati@mvista.com> | 2023-07-04 12:18:24 +0530 |
|---|---|---|
| committer | Armin Kuster <akuster808@gmail.com> | 2023-07-14 07:08:54 -0400 |
| commit | fbe2d05a159aa95f81de89bd0ae6401f036d31d6 (patch) | |
| tree | 31baf23c43bafb0bb9d5d24576e703b70eef7113 | |
| parent | 7ca27d5cf3ec147ec933a8660b252cf57d107a27 (diff) | |
| download | meta-openembedded-fbe2d05a159aa95f81de89bd0ae6401f036d31d6.tar.gz | |
ntp: backport patch for 5 CVEs CVE-2023-26551/2/3/4/5
Upstream-Status: Backport from https://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p15-3806-3807.patch
Patch taken from https://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p15-3806-3807.patch
It is linked as official patch for p15 in:
- https://www.ntp.org/support/securitynotice/ntpbug3807/
- https://www.ntp.org/support/securitynotice/ntpbug3806/
Small adaptation to build is needed because of how tests are built.
Backport fixes for:
CVE: CVE-2023-26551
CVE: CVE-2023-26552
CVE: CVE-2023-26553
CVE: CVE-2023-26554
CVE: CVE-2023-26555
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
| -rw-r--r-- | meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch | 340 | ||||
| -rw-r--r-- | meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb | 10 |
2 files changed, 349 insertions, 1 deletions
diff --git a/meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch b/meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch new file mode 100644 index 0000000000..734c6f197b --- /dev/null +++ b/meta-networking/recipes-support/ntp/ntp/CVE-2023-2655x.patch | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | ntp: backport patch for 5 CVEs CVE-2023-26551/2/3/4/5 | ||
| 2 | |||
| 3 | Upstream-Status: Backport [https://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p15-3806-3807.patch] | ||
| 4 | CVE: CVE-2023-26551 | ||
| 5 | CVE: CVE-2023-26552 | ||
| 6 | CVE: CVE-2023-26553 | ||
| 7 | CVE: CVE-2023-26554 | ||
| 8 | CVE: CVE-2023-26555 | ||
| 9 | |||
| 10 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 11 | Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> | ||
| 12 | --- | ||
| 13 | include/ntp_fp.h | 4 +- | ||
| 14 | libntp/mstolfp.c | 108 +++++++++++++++------------------------ | ||
| 15 | ntpd/refclock_palisade.c | 50 +++++++++++++++--- | ||
| 16 | tests/libntp/strtolfp.c | 33 +++++++----- | ||
| 17 | 4 files changed, 104 insertions(+), 91 deletions(-) | ||
| 18 | |||
| 19 | diff --git a/include/ntp_fp.h b/include/ntp_fp.h | ||
| 20 | index afd1f82..fe6e390 100644 | ||
| 21 | --- a/include/ntp_fp.h | ||
| 22 | +++ b/include/ntp_fp.h | ||
| 23 | @@ -195,9 +195,9 @@ typedef u_int32 u_fp; | ||
| 24 | do { \ | ||
| 25 | int32 add_f = (int32)(f); \ | ||
| 26 | if (add_f >= 0) \ | ||
| 27 | - M_ADD((r_i), (r_f), 0, (uint32)( add_f)); \ | ||
| 28 | + M_ADD((r_i), (r_f), 0, (u_int32)( add_f)); \ | ||
| 29 | else \ | ||
| 30 | - M_SUB((r_i), (r_f), 0, (uint32)(-add_f)); \ | ||
| 31 | + M_SUB((r_i), (r_f), 0, (u_int32)(-add_f)); \ | ||
| 32 | } while(0) | ||
| 33 | |||
| 34 | #define M_ISNEG(v_i) /* v < 0 */ \ | ||
| 35 | diff --git a/libntp/mstolfp.c b/libntp/mstolfp.c | ||
| 36 | index 3dfc4ef..a906d76 100644 | ||
| 37 | --- a/libntp/mstolfp.c | ||
| 38 | +++ b/libntp/mstolfp.c | ||
| 39 | @@ -14,86 +14,58 @@ mstolfp( | ||
| 40 | l_fp *lfp | ||
| 41 | ) | ||
| 42 | { | ||
| 43 | - register const char *cp; | ||
| 44 | - register char *bp; | ||
| 45 | - register const char *cpdec; | ||
| 46 | - char buf[100]; | ||
| 47 | + int ch, neg = 0; | ||
| 48 | + u_int32 q, r; | ||
| 49 | |||
| 50 | /* | ||
| 51 | * We understand numbers of the form: | ||
| 52 | * | ||
| 53 | * [spaces][-|+][digits][.][digits][spaces|\n|\0] | ||
| 54 | * | ||
| 55 | - * This is one enormous hack. Since I didn't feel like | ||
| 56 | - * rewriting the decoding routine for milliseconds, what | ||
| 57 | - * is essentially done here is to make a copy of the string | ||
| 58 | - * with the decimal moved over three places so the seconds | ||
| 59 | - * decoding routine can be used. | ||
| 60 | + * This is kinda hack. We use 'atolfp' to do the basic parsing | ||
| 61 | + * (after some initial checks) and then divide the result by | ||
| 62 | + * 1000. The original implementation avoided that by | ||
| 63 | + * hacking up the input string to move the decimal point, but | ||
| 64 | + * that needed string manipulations prone to buffer overruns. | ||
| 65 | + * To avoid that trouble we do the conversion first and adjust | ||
| 66 | + * the result. | ||
| 67 | */ | ||
| 68 | - bp = buf; | ||
| 69 | - cp = str; | ||
| 70 | - while (isspace((unsigned char)*cp)) | ||
| 71 | - cp++; | ||
| 72 | |||
| 73 | - if (*cp == '-' || *cp == '+') { | ||
| 74 | - *bp++ = *cp++; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - if (*cp != '.' && !isdigit((unsigned char)*cp)) | ||
| 78 | - return 0; | ||
| 79 | - | ||
| 80 | + while (isspace(ch = *(const unsigned char*)str)) | ||
| 81 | + ++str; | ||
| 82 | |||
| 83 | - /* | ||
| 84 | - * Search forward for the decimal point or the end of the string. | ||
| 85 | - */ | ||
| 86 | - cpdec = cp; | ||
| 87 | - while (isdigit((unsigned char)*cpdec)) | ||
| 88 | - cpdec++; | ||
| 89 | - | ||
| 90 | - /* | ||
| 91 | - * Found something. If we have more than three digits copy the | ||
| 92 | - * excess over, else insert a leading 0. | ||
| 93 | - */ | ||
| 94 | - if ((cpdec - cp) > 3) { | ||
| 95 | - do { | ||
| 96 | - *bp++ = (char)*cp++; | ||
| 97 | - } while ((cpdec - cp) > 3); | ||
| 98 | - } else { | ||
| 99 | - *bp++ = '0'; | ||
| 100 | + switch (ch) { | ||
| 101 | + case '-': neg = TRUE; | ||
| 102 | + case '+': ++str; | ||
| 103 | + default : break; | ||
| 104 | } | ||
| 105 | |||
| 106 | - /* | ||
| 107 | - * Stick the decimal in. If we've got less than three digits in | ||
| 108 | - * front of the millisecond decimal we insert the appropriate number | ||
| 109 | - * of zeros. | ||
| 110 | - */ | ||
| 111 | - *bp++ = '.'; | ||
| 112 | - if ((cpdec - cp) < 3) { | ||
| 113 | - size_t i = 3 - (cpdec - cp); | ||
| 114 | - do { | ||
| 115 | - *bp++ = '0'; | ||
| 116 | - } while (--i > 0); | ||
| 117 | - } | ||
| 118 | + if (!isdigit(ch = *(const unsigned char*)str) && (ch != '.')) | ||
| 119 | + return 0; | ||
| 120 | + if (!atolfp(str, lfp)) | ||
| 121 | + return 0; | ||
| 122 | |||
| 123 | - /* | ||
| 124 | - * Copy the remainder up to the millisecond decimal. If cpdec | ||
| 125 | - * is pointing at a decimal point, copy in the trailing number too. | ||
| 126 | + /* now do a chained/overlapping division by 1000 to get from | ||
| 127 | + * seconds to msec. 1000 is small enough to go with temporary | ||
| 128 | + * 32bit accus for Q and R. | ||
| 129 | */ | ||
| 130 | - while (cp < cpdec) | ||
| 131 | - *bp++ = (char)*cp++; | ||
| 132 | - | ||
| 133 | - if (*cp == '.') { | ||
| 134 | - cp++; | ||
| 135 | - while (isdigit((unsigned char)*cp)) | ||
| 136 | - *bp++ = (char)*cp++; | ||
| 137 | - } | ||
| 138 | - *bp = '\0'; | ||
| 139 | + q = lfp->l_ui / 1000u; | ||
| 140 | + r = lfp->l_ui - (q * 1000u); | ||
| 141 | + lfp->l_ui = q; | ||
| 142 | |||
| 143 | - /* | ||
| 144 | - * Check to make sure the string is properly terminated. If | ||
| 145 | - * so, give the buffer to the decoding routine. | ||
| 146 | - */ | ||
| 147 | - if (*cp != '\0' && !isspace((unsigned char)*cp)) | ||
| 148 | - return 0; | ||
| 149 | - return atolfp(buf, lfp); | ||
| 150 | + r = (r << 16) | (lfp->l_uf >> 16); | ||
| 151 | + q = r / 1000u; | ||
| 152 | + r = ((r - q * 1000) << 16) | (lfp->l_uf & 0x0FFFFu); | ||
| 153 | + lfp->l_uf = q << 16; | ||
| 154 | + q = r / 1000; | ||
| 155 | + lfp->l_uf |= q; | ||
| 156 | + r -= q * 1000u; | ||
| 157 | + | ||
| 158 | + /* fix sign */ | ||
| 159 | + if (neg) | ||
| 160 | + L_NEG(lfp); | ||
| 161 | + /* round */ | ||
| 162 | + if (r >= 500) | ||
| 163 | + L_ADDF(lfp, (neg ? -1 : 1)); | ||
| 164 | + return 1; | ||
| 165 | } | ||
| 166 | diff --git a/ntpd/refclock_palisade.c b/ntpd/refclock_palisade.c | ||
| 167 | index cb68255..15c21d8 100644 | ||
| 168 | --- a/ntpd/refclock_palisade.c | ||
| 169 | +++ b/ntpd/refclock_palisade.c | ||
| 170 | @@ -1225,9 +1225,9 @@ palisade_poll ( | ||
| 171 | return; /* using synchronous packet input */ | ||
| 172 | |||
| 173 | if(up->type == CLK_PRAECIS) { | ||
| 174 | - if(write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) | ||
| 175 | + if (write(peer->procptr->io.fd,"SPSTAT\r\n",8) < 0) { | ||
| 176 | msyslog(LOG_ERR, "Palisade(%d) write: %m:",unit); | ||
| 177 | - else { | ||
| 178 | + } else { | ||
| 179 | praecis_msg = 1; | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | @@ -1249,20 +1249,53 @@ praecis_parse ( | ||
| 183 | |||
| 184 | pp = peer->procptr; | ||
| 185 | |||
| 186 | - memcpy(buf+p,rbufp->recv_space.X_recv_buffer, rbufp->recv_length); | ||
| 187 | + if (p + rbufp->recv_length >= sizeof buf) { | ||
| 188 | + struct palisade_unit *up; | ||
| 189 | + up = pp->unitptr; | ||
| 190 | + | ||
| 191 | + /* | ||
| 192 | + * We COULD see if there is a \r\n in the incoming | ||
| 193 | + * buffer before it overflows, and then process the | ||
| 194 | + * current line. | ||
| 195 | + * | ||
| 196 | + * Similarly, if we already have a hunk of data that | ||
| 197 | + * we're now flushing, that will cause the line of | ||
| 198 | + * data we're in the process of collecting to be garbage. | ||
| 199 | + * | ||
| 200 | + * Since we now check for this overflow and log when it | ||
| 201 | + * happens, we're now in a better place to easily see | ||
| 202 | + * what's going on and perhaps better choices can be made. | ||
| 203 | + */ | ||
| 204 | + | ||
| 205 | + /* Do we need to log the size of the overflow? */ | ||
| 206 | + msyslog(LOG_ERR, "Palisade(%d) praecis_parse(): input buffer overflow", | ||
| 207 | + up->unit); | ||
| 208 | + | ||
| 209 | + p = 0; | ||
| 210 | + praecis_msg = 0; | ||
| 211 | + | ||
| 212 | + refclock_report(peer, CEVNT_BADREPLY); | ||
| 213 | + | ||
| 214 | + return; | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + memcpy(buf+p, rbufp->recv_buffer, rbufp->recv_length); | ||
| 218 | p += rbufp->recv_length; | ||
| 219 | |||
| 220 | - if(buf[p-2] == '\r' && buf[p-1] == '\n') { | ||
| 221 | + if ( p >= 2 | ||
| 222 | + && buf[p-2] == '\r' | ||
| 223 | + && buf[p-1] == '\n') { | ||
| 224 | buf[p-2] = '\0'; | ||
| 225 | record_clock_stats(&peer->srcadr, buf); | ||
| 226 | |||
| 227 | p = 0; | ||
| 228 | praecis_msg = 0; | ||
| 229 | |||
| 230 | - if (HW_poll(pp) < 0) | ||
| 231 | + if (HW_poll(pp) < 0) { | ||
| 232 | refclock_report(peer, CEVNT_FAULT); | ||
| 233 | - | ||
| 234 | + } | ||
| 235 | } | ||
| 236 | + return; | ||
| 237 | } | ||
| 238 | |||
| 239 | static void | ||
| 240 | @@ -1407,7 +1440,10 @@ HW_poll ( | ||
| 241 | |||
| 242 | /* Edge trigger */ | ||
| 243 | if (up->type == CLK_ACUTIME) | ||
| 244 | - write (pp->io.fd, "", 1); | ||
| 245 | + if (write (pp->io.fd, "", 1) != 1) | ||
| 246 | + msyslog(LOG_WARNING, | ||
| 247 | + "Palisade(%d) HW_poll: failed to send trigger: %m", | ||
| 248 | + up->unit); | ||
| 249 | |||
| 250 | if (ioctl(pp->io.fd, TIOCMSET, &x) < 0) { | ||
| 251 | #ifdef DEBUG | ||
| 252 | diff --git a/tests/libntp/strtolfp.c b/tests/libntp/strtolfp.c | ||
| 253 | index 6855d9b..9090159 100644 | ||
| 254 | --- a/tests/libntp/strtolfp.c | ||
| 255 | +++ b/tests/libntp/strtolfp.c | ||
| 256 | @@ -26,6 +26,13 @@ setUp(void) | ||
| 257 | return; | ||
| 258 | } | ||
| 259 | |||
| 260 | +static const char* fmtLFP(const l_fp *e, const l_fp *a) | ||
| 261 | +{ | ||
| 262 | + static char buf[100]; | ||
| 263 | + snprintf(buf, sizeof(buf), "e=$%08x.%08x, a=$%08x.%08x", | ||
| 264 | + e->l_ui, e->l_uf, a->l_ui, a->l_uf); | ||
| 265 | + return buf; | ||
| 266 | +} | ||
| 267 | |||
| 268 | void test_PositiveInteger(void) { | ||
| 269 | const char *str = "500"; | ||
| 270 | @@ -37,8 +44,8 @@ void test_PositiveInteger(void) { | ||
| 271 | TEST_ASSERT_TRUE(atolfp(str, &actual)); | ||
| 272 | TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms)); | ||
| 273 | |||
| 274 | - TEST_ASSERT_TRUE(IsEqual(expected, actual)); | ||
| 275 | - TEST_ASSERT_TRUE(IsEqual(expected, actual_ms)); | ||
| 276 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual)); | ||
| 277 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms)); | ||
| 278 | } | ||
| 279 | |||
| 280 | void test_NegativeInteger(void) { | ||
| 281 | @@ -54,8 +61,8 @@ void test_NegativeInteger(void) { | ||
| 282 | TEST_ASSERT_TRUE(atolfp(str, &actual)); | ||
| 283 | TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms)); | ||
| 284 | |||
| 285 | - TEST_ASSERT_TRUE(IsEqual(expected, actual)); | ||
| 286 | - TEST_ASSERT_TRUE(IsEqual(expected, actual_ms)); | ||
| 287 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual)); | ||
| 288 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms)); | ||
| 289 | } | ||
| 290 | |||
| 291 | void test_PositiveFraction(void) { | ||
| 292 | @@ -68,8 +75,8 @@ void test_PositiveFraction(void) { | ||
| 293 | TEST_ASSERT_TRUE(atolfp(str, &actual)); | ||
| 294 | TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms)); | ||
| 295 | |||
| 296 | - TEST_ASSERT_TRUE(IsEqual(expected, actual)); | ||
| 297 | - TEST_ASSERT_TRUE(IsEqual(expected, actual_ms)); | ||
| 298 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual)); | ||
| 299 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms)); | ||
| 300 | } | ||
| 301 | |||
| 302 | void test_NegativeFraction(void) { | ||
| 303 | @@ -85,8 +92,8 @@ void test_NegativeFraction(void) { | ||
| 304 | TEST_ASSERT_TRUE(atolfp(str, &actual)); | ||
| 305 | TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms)); | ||
| 306 | |||
| 307 | - TEST_ASSERT_TRUE(IsEqual(expected, actual)); | ||
| 308 | - TEST_ASSERT_TRUE(IsEqual(expected, actual_ms)); | ||
| 309 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual)); | ||
| 310 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms)); | ||
| 311 | } | ||
| 312 | |||
| 313 | void test_PositiveMsFraction(void) { | ||
| 314 | @@ -100,9 +107,8 @@ void test_PositiveMsFraction(void) { | ||
| 315 | TEST_ASSERT_TRUE(atolfp(str, &actual)); | ||
| 316 | TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms)); | ||
| 317 | |||
| 318 | - TEST_ASSERT_TRUE(IsEqual(expected, actual)); | ||
| 319 | - TEST_ASSERT_TRUE(IsEqual(expected, actual_ms)); | ||
| 320 | - | ||
| 321 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual)); | ||
| 322 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms)); | ||
| 323 | } | ||
| 324 | |||
| 325 | void test_NegativeMsFraction(void) { | ||
| 326 | @@ -118,9 +124,8 @@ void test_NegativeMsFraction(void) { | ||
| 327 | TEST_ASSERT_TRUE(atolfp(str, &actual)); | ||
| 328 | TEST_ASSERT_TRUE(mstolfp(str_ms, &actual_ms)); | ||
| 329 | |||
| 330 | - TEST_ASSERT_TRUE(IsEqual(expected, actual)); | ||
| 331 | - TEST_ASSERT_TRUE(IsEqual(expected, actual_ms)); | ||
| 332 | - | ||
| 333 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual), fmtLFP(&expected, &actual)); | ||
| 334 | + TEST_ASSERT_TRUE_MESSAGE(IsEqual(expected, actual_ms), fmtLFP(&expected, &actual_ms)); | ||
| 335 | } | ||
| 336 | |||
| 337 | void test_InvalidChars(void) { | ||
| 338 | -- | ||
| 339 | 2.25.1 | ||
| 340 | |||
diff --git a/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb b/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb index 7e168825e0..1a223db6fa 100644 --- a/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb +++ b/meta-networking/recipes-support/ntp/ntp_4.2.8p15.bb | |||
| @@ -22,8 +22,8 @@ SRC_URI = "http://www.eecis.udel.edu/~ntp/ntp_spool/ntp4/ntp-4.2/ntp-${PV}.tar.g | |||
| 22 | file://sntp.service \ | 22 | file://sntp.service \ |
| 23 | file://sntp \ | 23 | file://sntp \ |
| 24 | file://ntpd.list \ | 24 | file://ntpd.list \ |
| 25 | file://CVE-2023-2655x.patch \ | ||
| 25 | " | 26 | " |
| 26 | |||
| 27 | SRC_URI[sha256sum] = "f65840deab68614d5d7ceb2d0bb9304ff70dcdedd09abb79754a87536b849c19" | 27 | SRC_URI[sha256sum] = "f65840deab68614d5d7ceb2d0bb9304ff70dcdedd09abb79754a87536b849c19" |
| 28 | 28 | ||
| 29 | inherit autotools update-rc.d useradd systemd pkgconfig | 29 | inherit autotools update-rc.d useradd systemd pkgconfig |
| @@ -61,6 +61,14 @@ PACKAGECONFIG[debug] = "--enable-debugging,--disable-debugging" | |||
| 61 | PACKAGECONFIG[mdns] = "ac_cv_header_dns_sd_h=yes,ac_cv_header_dns_sd_h=no,mdns" | 61 | PACKAGECONFIG[mdns] = "ac_cv_header_dns_sd_h=yes,ac_cv_header_dns_sd_h=no,mdns" |
| 62 | PACKAGECONFIG[ipv6] = "--enable-ipv6,--disable-ipv6," | 62 | PACKAGECONFIG[ipv6] = "--enable-ipv6,--disable-ipv6," |
| 63 | 63 | ||
| 64 | do_configure_append() { | ||
| 65 | # tests are generated but also checked-in to source control | ||
| 66 | # when CVE-2023-2655x.patch changes timestamp of test source file, Makefile detects it and tries to regenerate it | ||
| 67 | # however it fails because of missing ruby interpretter; adding ruby-native as dependency fixes it | ||
| 68 | # since the regenerated file is identical to the one from source control, touch the generated file instead of adding heavy dependency | ||
| 69 | touch ${S}/tests/libntp/run-strtolfp.c | ||
| 70 | } | ||
| 71 | |||
| 64 | do_install_append() { | 72 | do_install_append() { |
| 65 | install -d ${D}${sysconfdir}/init.d | 73 | install -d ${D}${sysconfdir}/init.d |
| 66 | install -m 644 ${WORKDIR}/ntp.conf ${D}${sysconfdir} | 74 | install -m 644 ${WORKDIR}/ntp.conf ${D}${sysconfdir} |
