]> sourceware.org Git - glibc.git/blame - misc/syslog.c
syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6246)
[glibc.git] / misc / syslog.c
CommitLineData
790aa1f2
UD
1/*
2 * Copyright (c) 1983, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if defined(LIBC_SCCS) && !defined(lint)
31static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94";
32#endif /* LIBC_SCCS and not lint */
33
0cc15f45 34#include <libio/libioP.h>
790aa1f2 35#include <paths.h>
0cc15f45
AZ
36#include <stdarg.h>
37#include <stdlib.h>
790aa1f2
UD
38#include <stdio.h>
39#include <stdio_ext.h>
0cc15f45
AZ
40#include <sys/socket.h>
41#include <sys/uio.h>
42#include <sys/un.h>
43#include <syslog.h>
37233df9 44
0cc15f45
AZ
45static int LogType = SOCK_DGRAM; /* type of socket connection */
46static int LogFile = -1; /* fd for log */
47static bool connected; /* have done connect */
48static int LogStat; /* status bits, set by openlog() */
790aa1f2 49static const char *LogTag; /* string to tag the entry with */
0cc15f45
AZ
50static int LogFacility = LOG_USER; /* default facility code */
51static int LogMask = 0xff; /* mask of priorities to be logged */
52extern char *__progname; /* Program name, from crt0. */
790aa1f2
UD
53
54/* Define the lock. */
55__libc_lock_define_initialized (static, syslog_lock)
0cc15f45
AZ
56static void openlog_internal (const char *, int, int);
57static void closelog_internal (void);
790aa1f2
UD
58
59struct cleanup_arg
60{
61 void *buf;
62 struct sigaction *oldaction;
63};
64
65static void
66cancel_handler (void *ptr)
67{
790aa1f2
UD
68 /* Restore the old signal handler. */
69 struct cleanup_arg *clarg = (struct cleanup_arg *) ptr;
70
c4e4b2e1 71 if (clarg != NULL)
ded3cef3
AZ
72 /* Free the memstream buffer, */
73 free (clarg->buf);
c4e4b2e1 74
790aa1f2
UD
75 /* Free the lock. */
76 __libc_lock_unlock (syslog_lock);
77}
78
79
80/*
81 * syslog, vsyslog --
82 * print message on log file; output is intended for syslogd(8).
83 */
84void
0cc15f45 85__syslog (int pri, const char *fmt, ...)
790aa1f2 86{
0cc15f45 87 va_list ap;
790aa1f2 88
0cc15f45
AZ
89 va_start (ap, fmt);
90 __vsyslog_internal (pri, fmt, ap, 0);
91 va_end (ap);
790aa1f2 92}
c6251f03
RM
93ldbl_hidden_def (__syslog, syslog)
94ldbl_strong_alias (__syslog, syslog)
790aa1f2 95
124fc732 96void
0cc15f45 97__vsyslog (int pri, const char *fmt, va_list ap)
124fc732 98{
0cc15f45 99 __vsyslog_internal (pri, fmt, ap, 0);
124fc732
ZW
100}
101ldbl_weak_alias (__vsyslog, vsyslog)
102
790aa1f2 103void
ba745eff 104___syslog_chk (int pri, int flag, const char *fmt, ...)
29c21e49 105{
0cc15f45 106 va_list ap;
29c21e49 107
0cc15f45
AZ
108 va_start (ap, fmt);
109 __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
110 va_end (ap);
29c21e49 111}
ba745eff
FB
112ldbl_hidden_def (___syslog_chk, __syslog_chk)
113ldbl_strong_alias (___syslog_chk, __syslog_chk)
29c21e49
UD
114
115void
0cc15f45 116__vsyslog_chk (int pri, int flag, const char *fmt, va_list ap)
124fc732 117{
0cc15f45 118 __vsyslog_internal (pri, fmt, ap, (flag > 0) ? PRINTF_FORTIFY : 0);
124fc732
ZW
119}
120
121void
0cc15f45
AZ
122__vsyslog_internal (int pri, const char *fmt, va_list ap,
123 unsigned int mode_flags)
790aa1f2 124{
a583b6ad
AZ
125 /* Try to use a static buffer as an optimization. */
126 char bufs[1024];
6bd0e4ef
AS
127 char *buf = bufs;
128 size_t bufsize;
129
f9f5c70e 130 int msgoff;
0cc15f45 131 int saved_errno = errno;
0cc15f45
AZ
132
133#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
134 /* Check for invalid bits. */
135 if (pri & ~(LOG_PRIMASK | LOG_FACMASK))
136 {
137 syslog (INTERNALLOG, "syslog: unknown facility/priority: %x", pri);
138 pri &= LOG_PRIMASK | LOG_FACMASK;
139 }
140
141 /* Prepare for multiple users. We have to take care: most syscalls we are
142 using are cancellation points. */
f9f5c70e 143 struct cleanup_arg clarg = { NULL, NULL };
0cc15f45
AZ
144 __libc_cleanup_push (cancel_handler, &clarg);
145 __libc_lock_lock (syslog_lock);
146
147 /* Check priority against setlogmask values. */
148 if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0)
149 goto out;
150
151 /* Set default facility if none specified. */
152 if ((pri & LOG_FACMASK) == 0)
153 pri |= LogFacility;
154
a583b6ad
AZ
155 pid_t pid = LogStat & LOG_PID ? __getpid () : 0;
156
157 /* "%b %e %H:%M:%S " */
158 char timestamp[sizeof "MMM DD hh:mm:ss "];
ac0d208b 159 __time64_t now = time64_now ();
a583b6ad 160 struct tm now_tm;
ac0d208b
AZ
161 struct tm *now_tmp = __localtime64_r (&now, &now_tm);
162 bool has_ts = now_tmp != NULL;
163
164 /* In the unlikely case of localtime_r failure (tm_year out of int range)
165 skip the hostname so the message is handled as valid PRI but without
166 TIMESTAMP or invalid TIMESTAMP (which should force the relay to add the
167 timestamp itself). */
168 if (has_ts)
169 __strftime_l (timestamp, sizeof timestamp, "%h %e %T ", now_tmp,
170 _nl_C_locobj_ptr);
a583b6ad
AZ
171
172#define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \
45459476 173 "<%d>%s%n%s%s%.0d%s: ", \
a583b6ad
AZ
174 __pri, __timestamp, __msgoff, \
175 LogTag == NULL ? __progname : LogTag, \
176 "[" + (pid == 0), pid, "]" + (pid == 0)
177
ac0d208b
AZ
178#define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \
179 "<%d>: %n", __pri, __msgoff
180
6bd0e4ef 181 int l, vl;
ac0d208b
AZ
182 if (has_ts)
183 l = __snprintf (bufs, sizeof bufs,
184 SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
185 else
186 l = __snprintf (bufs, sizeof bufs,
187 SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
6bd0e4ef
AS
188
189 char *pos;
190 size_t len;
191
a583b6ad 192 if (0 <= l && l < sizeof bufs)
0cc15f45 193 {
6bd0e4ef
AS
194 /* At this point, there is still a chance that we can print the
195 remaining part of the log into bufs and use that. */
196 pos = bufs + l;
197 len = sizeof (bufs) - l;
198 }
199 else
200 {
201 buf = NULL;
202 /* We already know that bufs is too small to use for this log message.
203 The next vsnprintf into bufs is used only to calculate the total
204 required buffer length. We will discard bufs contents and allocate
205 an appropriately sized buffer later instead. */
206 pos = bufs;
207 len = sizeof (bufs);
208 }
a583b6ad 209
6bd0e4ef
AS
210 {
211 va_list apc;
212 va_copy (apc, ap);
0cc15f45 213
6bd0e4ef
AS
214 /* Restore errno for %m format. */
215 __set_errno (saved_errno);
0cc15f45 216
6bd0e4ef
AS
217 vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
218
219 if (!(0 <= vl && vl < len))
220 buf = NULL;
221
222 bufsize = l + vl;
223 va_end (apc);
224 }
a583b6ad
AZ
225
226 if (buf == NULL)
f9f5c70e 227 {
52a5be0d 228 buf = malloc ((bufsize + 1) * sizeof (char));
a583b6ad
AZ
229 if (buf != NULL)
230 {
231 /* Tell the cancellation handler to free this buffer. */
232 clarg.buf = buf;
233
ac0d208b 234 if (has_ts)
52a5be0d 235 __snprintf (buf, l + 1,
ac0d208b
AZ
236 SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
237 else
52a5be0d 238 __snprintf (buf, l + 1,
ac0d208b 239 SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
52a5be0d
AZ
240
241 va_list apc;
242 va_copy (apc, ap);
243 __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
244 mode_flags);
245 va_end (apc);
a583b6ad
AZ
246 }
247 else
248 {
249 /* Nothing much to do but emit an error message. */
250 bufsize = __snprintf (bufs, sizeof bufs,
251 "out of memory[%d]", __getpid ());
252 buf = bufs;
253 }
f9f5c70e 254 }
0cc15f45
AZ
255
256 /* Output to stderr if requested. */
257 if (LogStat & LOG_PERROR)
f9f5c70e
AZ
258 __dprintf (STDERR_FILENO, "%s%s", buf + msgoff,
259 "\n" + (buf[bufsize - 1] == '\n'));
0cc15f45
AZ
260
261 /* Get connected, output the message to the local logger. */
262 if (!connected)
263 openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility);
264
265 /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record
266 terminator. */
267 if (LogType == SOCK_STREAM)
268 ++bufsize;
269
270 if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0)
271 {
272 if (connected)
273 {
274 /* Try to reopen the syslog connection. Maybe it went down. */
275 closelog_internal ();
276 openlog_internal (NULL, LogStat | LOG_NDELAY, LogFacility);
790aa1f2
UD
277 }
278
0cc15f45
AZ
279 if (!connected || __send (LogFile, buf, bufsize, MSG_NOSIGNAL) < 0)
280 {
281 closelog_internal (); /* attempt re-open next time */
282 /*
283 * Output the message to the console; don't worry
284 * about blocking, if console blocks everything will.
285 * Make sure the error reported is the one from the
286 * syslogd failure.
287 */
f9f5c70e 288 int fd;
0cc15f45
AZ
289 if (LogStat & LOG_CONS &&
290 (fd = __open (_PATH_CONSOLE, O_WRONLY | O_NOCTTY
291 | O_CLOEXEC, 0)) >= 0)
292 {
293 __dprintf (fd, "%s\r\n", buf + msgoff);
294 __close (fd);
295 }
296 }
297 }
298
299out:
300 /* End of critical section. */
301 __libc_cleanup_pop (0);
302 __libc_lock_unlock (syslog_lock);
303
a583b6ad 304 if (buf != bufs)
0cc15f45 305 free (buf);
790aa1f2 306}
790aa1f2 307
5ad1a81c
AZ
308/* AF_UNIX address of local logger */
309static const struct sockaddr_un SyslogAddr =
310 {
311 .sun_family = AF_UNIX,
312 .sun_path = _PATH_LOG
313 };
790aa1f2
UD
314
315static void
0cc15f45 316openlog_internal (const char *ident, int logstat, int logfac)
790aa1f2 317{
0cc15f45
AZ
318 if (ident != NULL)
319 LogTag = ident;
320 LogStat = logstat;
321 if ((logfac & ~LOG_FACMASK) == 0)
322 LogFacility = logfac;
323
324 int retry = 0;
325 while (retry < 2)
326 {
327 if (LogFile == -1)
328 {
329 if (LogStat & LOG_NDELAY)
330 {
331 LogFile = __socket (AF_UNIX, LogType | SOCK_CLOEXEC, 0);
332 if (LogFile == -1)
333 return;
334 }
335 }
336 if (LogFile != -1 && !connected)
337 {
338 int old_errno = errno;
339 if (__connect (LogFile, &SyslogAddr, sizeof (SyslogAddr)) == -1)
340 {
341 int saved_errno = errno;
342 int fd = LogFile;
343 LogFile = -1;
344 __close (fd);
345 __set_errno (old_errno);
346 if (saved_errno == EPROTOTYPE)
790aa1f2 347 {
0cc15f45
AZ
348 /* retry with the other type: */
349 LogType = LogType == SOCK_DGRAM ? SOCK_STREAM : SOCK_DGRAM;
350 ++retry;
351 continue;
790aa1f2 352 }
0cc15f45
AZ
353 }
354 else
355 connected = true;
790aa1f2 356 }
0cc15f45
AZ
357 break;
358 }
790aa1f2
UD
359}
360
361void
362openlog (const char *ident, int logstat, int logfac)
363{
364 /* Protect against multiple users and cancellation. */
365 __libc_cleanup_push (cancel_handler, NULL);
366 __libc_lock_lock (syslog_lock);
367
368 openlog_internal (ident, logstat, logfac);
369
370 __libc_cleanup_pop (1);
371}
372
790aa1f2 373static void
60d2f8f3 374closelog_internal (void)
790aa1f2
UD
375{
376 if (!connected)
377 return;
378
379 __close (LogFile);
380 LogFile = -1;
7cb10381 381 connected = false;
790aa1f2
UD
382}
383
384void
60d2f8f3 385closelog (void)
790aa1f2
UD
386{
387 /* Protect against multiple users and cancellation. */
388 __libc_cleanup_push (cancel_handler, NULL);
389 __libc_lock_lock (syslog_lock);
390
391 closelog_internal ();
392 LogTag = NULL;
393 LogType = SOCK_DGRAM; /* this is the default */
394
395 /* Free the lock. */
396 __libc_cleanup_pop (1);
397}
398
399/* setlogmask -- set the log mask level */
400int
9d46370c 401setlogmask (int pmask)
790aa1f2 402{
0cc15f45 403 int omask;
790aa1f2 404
0cc15f45
AZ
405 /* Protect against multiple users. */
406 __libc_lock_lock (syslog_lock);
c4e4b2e1 407
0cc15f45
AZ
408 omask = LogMask;
409 if (pmask != 0)
410 LogMask = pmask;
c4e4b2e1 411
0cc15f45 412 __libc_lock_unlock (syslog_lock);
c4e4b2e1 413
0cc15f45 414 return (omask);
790aa1f2 415}
This page took 0.416763 seconds and 5 git commands to generate.