diff options
Diffstat (limited to 'lib/libc')
38 files changed, 614 insertions, 260 deletions
diff --git a/lib/libc/Makefile b/lib/libc/Makefile index d0c254e33396..8705568f6d34 100644 --- a/lib/libc/Makefile +++ b/lib/libc/Makefile @@ -109,7 +109,6 @@ NOASM= .include "${LIBC_SRCTOP}/inet/Makefile.inc" .include "${LIBC_SRCTOP}/isc/Makefile.inc" .include "${LIBC_SRCTOP}/locale/Makefile.inc" -.include "${LIBC_SRCTOP}/md/Makefile.inc" .include "${LIBC_SRCTOP}/nameser/Makefile.inc" .include "${LIBC_SRCTOP}/net/Makefile.inc" .include "${LIBC_SRCTOP}/nls/Makefile.inc" diff --git a/lib/libc/Versions.def b/lib/libc/Versions.def index 184e107d225a..1c7b34bef35b 100644 --- a/lib/libc/Versions.def +++ b/lib/libc/Versions.def @@ -42,6 +42,10 @@ FBSD_1.7 { FBSD_1.8 { } FBSD_1.7; +# This version was first added to 16.0-current. +FBSD_1.9 { +} FBSD_1.8; + # This is our private namespace. Any global interfaces that are # strictly for use only by other FreeBSD applications and libraries # are listed here. We use a separate namespace so we can write @@ -49,4 +53,4 @@ FBSD_1.8 { # # Please do NOT increment the version of this namespace. FBSDprivate_1.0 { -} FBSD_1.8; +} FBSD_1.9; diff --git a/lib/libc/aarch64/string/timingsafe_memcmp.S b/lib/libc/aarch64/string/timingsafe_memcmp.S index 28fdd911a387..4cc10a152aa8 100644 --- a/lib/libc/aarch64/string/timingsafe_memcmp.S +++ b/lib/libc/aarch64/string/timingsafe_memcmp.S @@ -114,4 +114,4 @@ ENTRY(timingsafe_memcmp) csetm w0, lo csinc w0, w0, wzr, ls ret -END(timingsafe_bcmp) +END(timingsafe_memcmp) diff --git a/lib/libc/gen/_rand48.c b/lib/libc/gen/_rand48.c index 990e2c86949b..114c1595b33d 100644 --- a/lib/libc/gen/_rand48.c +++ b/lib/libc/gen/_rand48.c @@ -13,34 +13,6 @@ #include "rand48.h" -unsigned short _rand48_seed[3] = { - RAND48_SEED_0, - RAND48_SEED_1, - RAND48_SEED_2 -}; -unsigned short _rand48_mult[3] = { - RAND48_MULT_0, - RAND48_MULT_1, - RAND48_MULT_2 -}; -unsigned short _rand48_add = RAND48_ADD; - -void -_dorand48(unsigned short xseed[3]) -{ - unsigned long accu; - unsigned short temp[2]; - - accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] + - (unsigned long) _rand48_add; - temp[0] = (unsigned short) accu; /* lower 16 bits */ - accu >>= sizeof(unsigned short) * 8; - accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] + - (unsigned long) _rand48_mult[1] * (unsigned long) xseed[0]; - temp[1] = (unsigned short) accu; /* middle 16 bits */ - accu >>= sizeof(unsigned short) * 8; - accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0]; - xseed[0] = temp[0]; - xseed[1] = temp[1]; - xseed[2] = (unsigned short) accu; -} +uint48 _rand48_seed = RAND48_SEED; +uint48 _rand48_mult = RAND48_MULT; +uint48 _rand48_add = RAND48_ADD; diff --git a/lib/libc/gen/drand48.c b/lib/libc/gen/drand48.c index cec04a6a2425..f7f43ff20468 100644 --- a/lib/libc/gen/drand48.c +++ b/lib/libc/gen/drand48.c @@ -13,10 +13,10 @@ #include "rand48.h" -extern unsigned short _rand48_seed[3]; - double drand48(void) { - return erand48(_rand48_seed); + ERAND48_BEGIN; + _DORAND48(_rand48_seed); + ERAND48_END(_rand48_seed); } diff --git a/lib/libc/gen/erand48.c b/lib/libc/gen/erand48.c index 286904c27839..38d4774a9fe6 100644 --- a/lib/libc/gen/erand48.c +++ b/lib/libc/gen/erand48.c @@ -16,8 +16,9 @@ double erand48(unsigned short xseed[3]) { - _dorand48(xseed); - return ldexp((double) xseed[0], -48) + - ldexp((double) xseed[1], -32) + - ldexp((double) xseed[2], -16); + uint48 tmp; + + ERAND48_BEGIN; + DORAND48(tmp, xseed); + ERAND48_END(tmp); } diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c index f87cabf085f7..62a1e0a81f62 100644 --- a/lib/libc/gen/fts-compat.c +++ b/lib/libc/gen/fts-compat.c @@ -44,9 +44,9 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include "gen-compat.h" #include "fts-compat.h" #include "un-namespace.h" +#include "gen-compat.h" #include "gen-private.h" diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c index 0351ce5ac690..5abb378f5f08 100644 --- a/lib/libc/gen/fts-compat11.c +++ b/lib/libc/gen/fts-compat11.c @@ -43,9 +43,9 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include "gen-compat.h" #include "fts-compat11.h" #include "un-namespace.h" +#include "gen-compat.h" #include "gen-private.h" diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index ee558b892c8c..da304e59ee72 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 30, 2025 +.Dd October 6, 2025 .Dt FTS 3 .Os .Sh NAME @@ -69,14 +69,15 @@ on a file hierarchy, which is then supplied to the other .Nm functions. -The function +The .Fn fts_read -returns a pointer to a structure describing one of the files in the file -hierarchy. -The function +function returns a pointer to a structure describing one of the files +in the file hierarchy. +The .Fn fts_children -returns a pointer to a linked list of structures, each of which describes -one of the files contained in a directory in the hierarchy. +function returns a pointer to a linked list of structures, each of +which describes one of the files contained in a directory in the +hierarchy. In general, directories are visited two distinguishable times; in pre-order (before any of their descendants are visited) and in post-order (after all of their descendants have been visited). @@ -376,7 +377,44 @@ The .Fa fts_name field is always .Dv NUL Ns -terminated . -.Sh FTS_OPEN +.Ss Thread Safety +The +.Nm +functions can safely be used in multi-threaded programs provided no +two threads access the same +.Vt FTS +or +.Vt FTSENT +structure simultaneously. +However, unless the +.Dv FTS_NOCHDIR +flag was passed to +.Fn fts_open +or +.Fn fts_open_b , +calls to +.Fn fts_read +and +.Fn fts_children +may change the current working directory, which will affect all +threads. +Conversely, changing the current working directory either during or +between calls to +.Fn fts_read +or +.Fn fts_children +(even in a single-thread program) may cause +.Nm +to malfunction unless the +.Dv FTS_NOCHDIR +flag was passed to +.Fn fts_open +or +.Fn fts_open_b +and all paths in +.Va path_argv +were absolute. +.Ss Fn fts_open The .Fn fts_open function takes a pointer to an array of character pointers naming one @@ -507,10 +545,10 @@ from descending into directories that have a different device number than the file from which the descent began. .El .Pp -The argument -.Fn compar -specifies a user-defined function which may be used to order the traversal -of the hierarchy. +The +.Fa compar +argument points to a user-defined function which may be used to order +the traversal of the hierarchy. It takes two pointers to pointers to .Vt FTSENT @@ -545,7 +583,7 @@ the directory traversal order is in the order listed in .Fa path_argv for the root paths, and in the order listed in the directory for everything else. -.Sh FTS_OPEN_B +.Ss Fn fts_open_b The .Fn fts_open_b function is identical to @@ -554,7 +592,7 @@ except that it takes a block pointer instead of a function pointer. The block is copied before .Fn fts_open_b returns, so the original can safely go out of scope or be released. -.Sh FTS_READ +.Ss Fn fts_read The .Fn fts_read function returns a pointer to an @@ -588,6 +626,15 @@ structure is returned, and .Va errno may or may not have been set (see .Fa fts_info ) . +Note that +.Fn fts_read +will not set +.Va errno +to 0 if called again with the same +.Fa ftsp +argument after the +.Dv FTS_STOP +flag has been set or the end of the stream has been reached. .Pp The .Vt FTSENT @@ -602,10 +649,10 @@ directory, in which case they will not be overwritten until after a call to .Fn fts_read after the .Vt FTSENT -structure has been returned by the function +structure has been returned by the .Fn fts_read -in post-order. -.Sh FTS_CHILDREN +function in post-order. +.Ss Fn fts_children The .Fn fts_children function returns a pointer to an @@ -679,11 +726,11 @@ and .Fa fts_namelen fields. .El -.Sh FTS_SET -The function +.Ss Fn fts_set +The .Fn fts_set -allows the user application to determine further processing for the -file +function allows the user application to determine further processing +for the file .Fa f of the stream .Fa ftsp . @@ -749,7 +796,40 @@ The file may be one of those most recently returned by either or .Fn fts_read . .El -.Sh FTS_CLOSE +.Ss Fn fts_set_clientptr , Fn fts_get_clientptr +The +.Fn fts_set_clientptr +function sets the client data pointer for the stream +.Fa ftsp +to +.Fa clientdata . +The +.Fn fts_get_clientptr +function returns the client data pointer associated with +.Fa ftsp . +This can be used to pass per-stream data to the comparison function. +.Pp +For performance reasons, +.Fn fts_get_clientptr +may be shadowed by a preprocessor macro. +.Ss Fn fts_get_stream +The +.Fn fts_get_stream +function returns the +.Nm +stream associated with the file entry +.Fa f . +A typical use for this would be for a comparison function to first call +.Fn fts_get_stream +on one of its arguments, then call +.Fn fts_get_clientptr +to obtain the client data pointer, which in turn points to information +necessary to correctly order the two entries. +.Pp +For performance reasons, +.Fn fts_get_stream +may be shadowed by a preprocessor macro. +.Ss Fn fts_close The .Fn fts_close function closes a file hierarchy stream @@ -760,6 +840,75 @@ or .Fn fts_open_b was called to open .Fa ftsp . +.Sh RETURN VALUES +The +.Fn fts_open +and +.Fn fts_open_b +functions return a pointer to the new +.Nm +stream on success and +.Dv NULL +on failure. +.Pp +The +.Fn fts_read +function returns a pointer to the next file entry on success, or if an +error occurs that relates specifically to that file entry. +On reaching the end of the file hierarchy, it returns +.Dv NULL +and sets the external variable +.Va errno +to 0. +On failure, it returns +.Dv NULL +and sets +.Va errno +to an appropriate non-zero value. +If called again after the +.Dv FTS_STOP +flag has been set or the end of the stream has been reached, +.Fn fts_read +returns +.Dv NULL +and leaves +.Va errno +untouched. +.Pp +The +.Fn fts_children +function returns a pointer to a linked list of file entries on +success. +On reaching the end of the file hierarchy, it returns +.Dv NULL +and sets the external variable +.Va errno +to 0. +On failure, it returns +.Dv NULL +and sets +.Va errno +to an appropriate non-zero value. +.Pp +The +.Fn fts_set +function returns 0 on success and \-1 if its +.Fa instr +argument is invalid. +.Pp +The +.Fn fts_get_clientptr +function returns the client data pointer associated with its argument, +or +.Dv NULL +if none has been set. +.Pp +The +.Fn fts_get_stream +function returns a pointer to the +.Nm +stream associated with its argument. +.Pp The .Fn fts_close function @@ -816,7 +965,7 @@ functions may fail and set as follows: .Bl -tag -width Er .It Bq Er EINVAL -The options were invalid, or the list were empty. +The options were invalid, or the list was empty. .El .Sh SEE ALSO .Xr find 1 , diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index cce959ba836a..4aa386d777cd 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -106,7 +106,6 @@ struct _fts_private { * This assumption only holds for UFS-like filesystems that implement * links and directories this way, so we must punt for others. */ - static const char *ufslike_filesystems[] = { "ufs", "zfs", @@ -679,7 +678,6 @@ fts_children(FTS *sp, int instr) void * (fts_get_clientptr)(FTS *sp) { - return (fts_get_clientptr(sp)); } @@ -696,7 +694,6 @@ FTS * void fts_set_clientptr(FTS *sp, void *clientptr) { - sp->fts_clientptr = clientptr; } diff --git a/lib/libc/gen/gen-compat.h b/lib/libc/gen/gen-compat.h index 74678301af6f..19b9addb4321 100644 --- a/lib/libc/gen/gen-compat.h +++ b/lib/libc/gen/gen-compat.h @@ -40,24 +40,50 @@ struct freebsd11_statfs; struct freebsd11_dirent *freebsd11_readdir(DIR *); int freebsd11_readdir_r(DIR *, struct freebsd11_dirent *, struct freebsd11_dirent **); -int freebsd11_stat(const char *, struct freebsd11_stat *); -int freebsd11_lstat(const char *, struct freebsd11_stat *); -int freebsd11_fstat(int, struct freebsd11_stat *); -int freebsd11_fstatat(int, const char *, struct freebsd11_stat *, int); -int freebsd11_statfs(const char *, struct freebsd11_statfs *); -int freebsd11_getfsstat(struct freebsd11_statfs *, long, int); int freebsd11_getmntinfo(struct freebsd11_statfs **, int); char *freebsd11_devname(__uint32_t dev, __mode_t type); -char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf, int len); +char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf, + int len); -#define F14SG int freebsd14_setgroups(int gidsize, const __gid_t *gidset) +/* + * We want freebsd11_fstat in C source to result in resolution to + * - fstat@FBSD_1.0 for libc.so (but we do not need the _definition_ + * of this fstat, it is provided by libsys.so which we want to use). + * - freebsd11_fstat for libc.a (since if we make it fstat@FBSD_1.0 + * for libc.a, then final linkage into static object ignores version + * and would reference fstat, which is the current syscall, not the + * compat syscall). libc.a provides the freebsd11_fstat implementation. + * Note that freebsd11_fstat from libc.a is not used for anything, but + * we make it correct nonetheless, just in case it would. + * This is arranged by COMPAT_SYSCALL, and libc can just use freebsd11_fstat. + */ #ifdef PIC -static F14SG __attribute__((__weakref__("setgroups@FBSD_1.0"))); +#define COMPAT_SYSCALL(rtype, fun, args, sym, ver) \ + rtype fun args; __sym_compat(sym, fun, ver); #else -F14SG; +#define COMPAT_SYSCALL(rtype, fun, args, sym, ver) \ + rtype fun args; #endif -#undef F14SG + +COMPAT_SYSCALL(int, freebsd11_stat, (const char *, struct freebsd11_stat *), + stat, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_lstat, (const char *, struct freebsd11_stat *), + lstat, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_fstat, (int, struct freebsd11_stat *), + fstat, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_fstatat, (int, const char *, + struct freebsd11_stat *, int), fstatat, FBSD_1.1); + +COMPAT_SYSCALL(int, freebsd11_statfs, (const char *, + struct freebsd11_statfs *), statfs, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_getfsstat, (struct freebsd11_statfs *, long, + int), getfsstat, FBSD_1.0); + +COMPAT_SYSCALL(int, freebsd14_setgroups, (int gidsize, const __gid_t *gidset), + setgroups, FBSD_1.0); + +#undef COMPAT_SYSCALL #endif /* _GEN_COMPAT_H_ */ diff --git a/lib/libc/gen/jrand48.c b/lib/libc/gen/jrand48.c index 0a9f780a9e5c..93442439d49e 100644 --- a/lib/libc/gen/jrand48.c +++ b/lib/libc/gen/jrand48.c @@ -11,14 +11,13 @@ * to anyone/anything when using this software. */ -#include <stdint.h> - #include "rand48.h" long jrand48(unsigned short xseed[3]) { + uint48 tmp; - _dorand48(xseed); - return ((int32_t)(((uint32_t)xseed[2] << 16) | (uint32_t)xseed[1])); + DORAND48(tmp, xseed); + return ((int)((tmp >> 16) & 0xffffffff)); } diff --git a/lib/libc/gen/lcong48.c b/lib/libc/gen/lcong48.c index f13826b3d3f3..871b2110ed94 100644 --- a/lib/libc/gen/lcong48.c +++ b/lib/libc/gen/lcong48.c @@ -13,18 +13,10 @@ #include "rand48.h" -extern unsigned short _rand48_seed[3]; -extern unsigned short _rand48_mult[3]; -extern unsigned short _rand48_add; - void lcong48(unsigned short p[7]) { - _rand48_seed[0] = p[0]; - _rand48_seed[1] = p[1]; - _rand48_seed[2] = p[2]; - _rand48_mult[0] = p[3]; - _rand48_mult[1] = p[4]; - _rand48_mult[2] = p[5]; + LOADRAND48(_rand48_seed, &p[0]); + LOADRAND48(_rand48_mult, &p[3]); _rand48_add = p[6]; } diff --git a/lib/libc/gen/lrand48.c b/lib/libc/gen/lrand48.c index a3d0111cf4d5..cc07044b8af9 100644 --- a/lib/libc/gen/lrand48.c +++ b/lib/libc/gen/lrand48.c @@ -13,11 +13,9 @@ #include "rand48.h" -extern unsigned short _rand48_seed[3]; - long lrand48(void) { - _dorand48(_rand48_seed); - return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1); + _DORAND48(_rand48_seed); + return (_rand48_seed >> 17) & 0x7fffffff; } diff --git a/lib/libc/gen/mrand48.c b/lib/libc/gen/mrand48.c index 15b0bfb1bd6e..f9128a6d4188 100644 --- a/lib/libc/gen/mrand48.c +++ b/lib/libc/gen/mrand48.c @@ -15,13 +15,9 @@ #include "rand48.h" -extern unsigned short _rand48_seed[3]; - long mrand48(void) { - - _dorand48(_rand48_seed); - return ((int32_t)(((uint32_t)_rand48_seed[2] << 16) | - (uint32_t)_rand48_seed[1])); + _DORAND48(_rand48_seed); + return ((int)((_rand48_seed >> 16) & 0xffffffff)); } diff --git a/lib/libc/gen/nrand48.c b/lib/libc/gen/nrand48.c index 6c54065e7e0f..f6f4e231105c 100644 --- a/lib/libc/gen/nrand48.c +++ b/lib/libc/gen/nrand48.c @@ -16,6 +16,8 @@ long nrand48(unsigned short xseed[3]) { - _dorand48(xseed); - return ((long) xseed[2] << 15) + ((long) xseed[1] >> 1); + uint48 tmp; + + DORAND48(tmp, xseed); + return ((tmp >> 17) & 0x7fffffff); } diff --git a/lib/libc/gen/psignal.3 b/lib/libc/gen/psignal.3 index 098b7b02a9b9..bf6a99b4b113 100644 --- a/lib/libc/gen/psignal.3 +++ b/lib/libc/gen/psignal.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 10, 2025 +.Dd September 23, 2025 .Dt PSIGNAL 3 .Os .Sh NAME @@ -141,6 +141,13 @@ The name in can be either the name of the signal, with or without the .Dq SIG prefix, or a decimal number. +.Sh RETURN VALUES +The +.Fn sig2str +and +.Fn str2sig +return 0 on success and -1 on translation failure. +In the latter case the memory to store the translation result is left intact. .Sh SEE ALSO .Xr sigaction 2 , .Xr perror 3 , diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3 index 1e47c843058e..3ea649354270 100644 --- a/lib/libc/gen/rand48.3 +++ b/lib/libc/gen/rand48.3 @@ -9,7 +9,7 @@ .\" of any kind. I shall in no event be liable for anything that happens .\" to anyone/anything when using this software. .\" -.Dd September 4, 2012 +.Dd September 11, 2025 .Dt RAND48 3 .Os .Sh NAME @@ -183,5 +183,8 @@ generator calls. .Xr arc4random 3 , .Xr rand 3 , .Xr random 3 +.Sh STANDARDS +The functions described in this page are expected to conform to +.St -p1003.1-2008 . .Sh AUTHORS .An Martin Birgmeier diff --git a/lib/libc/gen/rand48.h b/lib/libc/gen/rand48.h index 9861e99683cb..d3326e851491 100644 --- a/lib/libc/gen/rand48.h +++ b/lib/libc/gen/rand48.h @@ -14,10 +14,11 @@ #ifndef _RAND48_H_ #define _RAND48_H_ +#include <sys/types.h> #include <math.h> #include <stdlib.h> -void _dorand48(unsigned short[3]); +#include "fpmath.h" #define RAND48_SEED_0 (0x330e) #define RAND48_SEED_1 (0xabcd) @@ -27,4 +28,62 @@ void _dorand48(unsigned short[3]); #define RAND48_MULT_2 (0x0005) #define RAND48_ADD (0x000b) +typedef uint64_t uint48; + +extern uint48 _rand48_seed; +extern uint48 _rand48_mult; +extern uint48 _rand48_add; + +#define TOUINT48(x, y, z) \ + ((uint48)(x) + (((uint48)(y)) << 16) + (((uint48)(z)) << 32)) + +#define RAND48_SEED TOUINT48(RAND48_SEED_0, RAND48_SEED_1, RAND48_SEED_2) +#define RAND48_MULT TOUINT48(RAND48_MULT_0, RAND48_MULT_1, RAND48_MULT_2) + +#define LOADRAND48(l, x) do { \ + (l) = TOUINT48((x)[0], (x)[1], (x)[2]); \ +} while (0) + +#define STORERAND48(l, x) do { \ + (x)[0] = (unsigned short)(l); \ + (x)[1] = (unsigned short)((l) >> 16); \ + (x)[2] = (unsigned short)((l) >> 32); \ +} while (0) + +#define _DORAND48(l) do { \ + (l) = (l) * _rand48_mult + _rand48_add; \ +} while (0) + +#define DORAND48(l, x) do { \ + LOADRAND48(l, x); \ + _DORAND48(l); \ + STORERAND48(l, x); \ +} while (0) + +#define ERAND48_BEGIN \ + union { \ + union IEEEd2bits ieee; \ + uint64_t u64; \ + } u; \ + int s + +/* + * Optimization for speed: assume doubles are IEEE 754 and use bit fiddling + * rather than converting to double. Specifically, clamp the result to 48 bits + * and convert to a double in [0.0, 1.0) via division by 2^48. Normalize by + * shifting the most significant bit into the implicit one position and + * adjusting the exponent accordingly. The store to the exponent field + * overwrites the implicit one. + */ +#define ERAND48_END(x) do { \ + u.u64 = ((x) & 0xffffffffffffULL); \ + if (u.u64 == 0) \ + return (0.0); \ + u.u64 <<= 5; \ + for (s = 0; !(u.u64 & (1LL << 52)); s++, u.u64 <<= 1) \ + ; \ + u.ieee.bits.exp = 1022 - s; \ + return (u.ieee.d); \ +} while (0) + #endif /* _RAND48_H_ */ diff --git a/lib/libc/gen/seed48.c b/lib/libc/gen/seed48.c index 258c4bac3c9f..f57656ce1121 100644 --- a/lib/libc/gen/seed48.c +++ b/lib/libc/gen/seed48.c @@ -13,24 +13,14 @@ #include "rand48.h" -extern unsigned short _rand48_seed[3]; -extern unsigned short _rand48_mult[3]; -extern unsigned short _rand48_add; - unsigned short * seed48(unsigned short xseed[3]) { static unsigned short sseed[3]; - sseed[0] = _rand48_seed[0]; - sseed[1] = _rand48_seed[1]; - sseed[2] = _rand48_seed[2]; - _rand48_seed[0] = xseed[0]; - _rand48_seed[1] = xseed[1]; - _rand48_seed[2] = xseed[2]; - _rand48_mult[0] = RAND48_MULT_0; - _rand48_mult[1] = RAND48_MULT_1; - _rand48_mult[2] = RAND48_MULT_2; + STORERAND48(_rand48_seed, sseed); + LOADRAND48(_rand48_seed, xseed); + _rand48_mult = RAND48_MULT; _rand48_add = RAND48_ADD; - return sseed; + return (sseed); } diff --git a/lib/libc/gen/srand48.c b/lib/libc/gen/srand48.c index fd369a094c51..4b82ece72db8 100644 --- a/lib/libc/gen/srand48.c +++ b/lib/libc/gen/srand48.c @@ -13,18 +13,11 @@ #include "rand48.h" -extern unsigned short _rand48_seed[3]; -extern unsigned short _rand48_mult[3]; -extern unsigned short _rand48_add; - void srand48(long seed) { - _rand48_seed[0] = RAND48_SEED_0; - _rand48_seed[1] = (unsigned short) seed; - _rand48_seed[2] = (unsigned short) (seed >> 16); - _rand48_mult[0] = RAND48_MULT_0; - _rand48_mult[1] = RAND48_MULT_1; - _rand48_mult[2] = RAND48_MULT_2; + _rand48_seed = TOUINT48(RAND48_SEED_0, (unsigned short)seed, + (unsigned short)(seed >> 16)); + _rand48_mult = RAND48_MULT; _rand48_add = RAND48_ADD; } diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c index 66562d0e29f0..b5b732eed05d 100644 --- a/lib/libc/gen/sysconf.c +++ b/lib/libc/gen/sysconf.c @@ -51,7 +51,7 @@ #include "un-namespace.h" #include "../stdlib/atexit.h" -#include "tzdir.h" /* from ../../../contrib/tzcode/stdtime */ +#include "tzdir.h" /* from ../../../contrib/tzcode */ #include "libc_private.h" #define _PATH_ZONEINFO TZDIR /* from tzfile.h */ diff --git a/lib/libc/include/port_before.h b/lib/libc/include/port_before.h index cfc43c53f157..aa2cd394104a 100644 --- a/lib/libc/include/port_before.h +++ b/lib/libc/include/port_before.h @@ -5,7 +5,6 @@ #define _LIBC 1 #define DO_PTHREADS 1 #define USE_POLL 1 -#define HAVE_MD5 1 #define ISC_SOCKLEN_T socklen_t #define ISC_FORMAT_PRINTF(fmt, args) \ diff --git a/lib/libc/md/Makefile.inc b/lib/libc/md/Makefile.inc deleted file mode 100644 index 82c5f0670485..000000000000 --- a/lib/libc/md/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -.PATH: ${SRCTOP}/sys/kern - -SRCS+= md5c.c diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc index f26e04c187a5..c211026aba72 100644 --- a/lib/libc/nls/Makefile.inc +++ b/lib/libc/nls/Makefile.inc @@ -12,6 +12,11 @@ MAN+= catclose.3 catgets.3 catopen.3 # for translators. NLSNAME= libc +# We don't want libc's NLS catalogues to be installed in the clibs package. +# Put them in locales instead, since anyone interested in NLS will have +# that installed. +NLSPACKAGE= locales + NLS+= be_BY.UTF-8 NLS+= ca_ES.ISO8859-1 NLS+= de_DE.ISO8859-1 diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map index 6b9c43298fb5..26daecbe2eff 100644 --- a/lib/libc/resolv/Symbol.map +++ b/lib/libc/resolv/Symbol.map @@ -103,6 +103,5 @@ FBSD_1.0 { }; FBSD_1.4 { - __res_rndinit; __res_nrandomid; }; diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c index 71ab2dcb7038..5a2fce013c8c 100644 --- a/lib/libc/resolv/res_init.c +++ b/lib/libc/resolv/res_init.c @@ -86,19 +86,6 @@ #include <unistd.h> #include <netdb.h> -#ifndef HAVE_MD5 -# include "../dst/md5.h" -#else -# ifdef SOLARIS2 -# include <sys/md5.h> -# elif _LIBC -# include <md5.h> -# endif -#endif -#ifndef _MD5_H_ -# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */ -#endif - #include "un-namespace.h" #include "port_after.h" @@ -184,8 +171,6 @@ __res_vinit(res_state statp, int preinit) { statp->options = RES_DEFAULT; } - statp->_rnd = malloc(16); - res_rndinit(statp); statp->id = res_nrandomid(statp); memset(u, 0, sizeof(u)); @@ -733,48 +718,18 @@ net_mask(struct in_addr in) /*!< XXX - should really use system's version of th } #endif -static u_char srnd[16]; - void -res_rndinit(res_state statp) +freebsd15_res_rndinit(res_state statp) { - struct timeval now; - u_int32_t u32; - u_int16_t u16; - u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd; - - gettimeofday(&now, NULL); - u32 = now.tv_sec; - memcpy(rnd, &u32, 4); - u32 = now.tv_usec; - memcpy(rnd + 4, &u32, 4); - u32 += now.tv_sec; - memcpy(rnd + 8, &u32, 4); - u16 = getpid(); - memcpy(rnd + 12, &u16, 2); + (void)statp; } +__sym_compat(__res_rndinit, freebsd15_res_rndinit, FBSD_1.4); u_int res_nrandomid(res_state statp) { - struct timeval now; - u_int16_t u16; - MD5_CTX ctx; - u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd; - - gettimeofday(&now, NULL); - u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec); - memcpy(rnd + 14, &u16, 2); -#ifndef HAVE_MD5 - MD5_Init(&ctx); - MD5_Update(&ctx, rnd, 16); - MD5_Final(rnd, &ctx); -#else - MD5Init(&ctx); - MD5Update(&ctx, rnd, 16); - MD5Final(rnd, &ctx); -#endif - memcpy(&u16, rnd + 14, 2); - return ((u_int) u16); + (void) statp; + + return ((u_int)(arc4random() & 0xffff)); } /*% @@ -808,10 +763,6 @@ res_ndestroy(res_state statp) { free(statp->_u._ext.ext); statp->_u._ext.ext = NULL; } - if (statp->_rnd != NULL) { - free(statp->_rnd); - statp->_rnd = NULL; - } statp->options &= ~RES_INIT; } diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c index 0e563f6a5996..8019f2d8f236 100644 --- a/lib/libc/rpc/rpc_generic.c +++ b/lib/libc/rpc/rpc_generic.c @@ -610,6 +610,10 @@ __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) return NULL; break; #endif + case AF_NETLINK: + if (asprintf(&ret, "%s", (char *)nbuf->buf) < 0) + return NULL; + break; case AF_LOCAL: sun = nbuf->buf; if (asprintf(&ret, "%.*s", (int)(sun->sun_len - diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index ca199a669be1..e7b9955b9646 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -10,7 +10,7 @@ MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \ merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c qsort_r_compat.c \ qsort_s.c quick_exit.c radixsort.c rand.c \ - random.c reallocarray.c reallocf.c realpath.c remque.c \ + random.c reallocarray.c reallocf.c realpath.c recallocarray.c remque.c \ set_constraint_handler_s.c strfmon.c strtoimax.c \ strtol.c strtold.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \ strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c @@ -76,6 +76,7 @@ MLINKS+=random.3 initstate.3 \ random.3 srandom.3 \ random.3 srandomdev.3 MLINKS+=radixsort.3 sradixsort.3 +MLINKS+=reallocarray.3 recallocarray.3 MLINKS+=set_constraint_handler_s.3 abort_handler_s.3 MLINKS+=set_constraint_handler_s.3 ignore_handler_s.3 MLINKS+=strfmon.3 strfmon_l.3 diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map index 2b79ca2ece8b..53d71bcafb7d 100644 --- a/lib/libc/stdlib/Symbol.map +++ b/lib/libc/stdlib/Symbol.map @@ -131,6 +131,10 @@ FBSD_1.8 { getenv_r; }; +FBSD_1.9 { + recallocarray; +}; + FBSDprivate_1.0 { __system; _system; diff --git a/lib/libc/stdlib/reallocarray.3 b/lib/libc/stdlib/reallocarray.3 index 80035c67a497..9a2ab5c7a840 100644 --- a/lib/libc/stdlib/reallocarray.3 +++ b/lib/libc/stdlib/reallocarray.3 @@ -26,7 +26,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 1, 2015 +.Dd October 2, 2025 .Dt REALLOCARRAY 3 .Os .Sh NAME @@ -38,6 +38,8 @@ .In stdlib.h .Ft void * .Fn reallocarray "void *ptr" "size_t nmemb" "size_t size" +.Ft void * +.Fn recallocarray "void *ptr" "size_t oldnmeb" "size_t nmemb" size_t size" .Sh DESCRIPTION The .Fn reallocarray @@ -52,6 +54,33 @@ and checks for integer overflow in the calculation .Fa nmemb * .Fa size . +.Pp +The +.Fn recallocarray +function is similar to the +.Fn reallocarray +function +except it ensures newly allocated memory is cleared similar to +.Fn calloc . +If +.Fa ptr +is +.Dv NULL , +.Fa oldnmemb +is ignored and the call is equivalent to +.Fn calloc . +If +.Fa ptr +is not +.Dv NULL , +.Fa oldnmemb +must be a value such that +.Fa oldnmemb +* +.Fa size +is the size of the earlier allocation that returned +.Fa ptr , +otherwise the behaviour is undefined. .Sh RETURN VALUES The .Fn reallocarray @@ -142,3 +171,9 @@ function first appeared in .Ox 5.6 and .Fx 11.0 . +The +.Fn recallocarray +function first appeared in +.Ox 6.1 +and +.Fx 16.0 . diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c index 0868804486cc..3632734c84de 100644 --- a/lib/libc/stdlib/reallocarray.c +++ b/lib/libc/stdlib/reallocarray.c @@ -17,23 +17,19 @@ #include <sys/types.h> #include <errno.h> +#include <stdckdint.h> #include <stdint.h> #include <stdlib.h> -/* - * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX - * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW - */ -#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) - void * reallocarray(void *optr, size_t nmemb, size_t size) { + size_t nbytes; - if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - nmemb > 0 && SIZE_MAX / nmemb < size) { + if (ckd_mul(&nbytes, nmemb, size)) { errno = ENOMEM; return (NULL); } - return (realloc(optr, size * nmemb)); + + return (realloc(optr, nbytes)); } diff --git a/lib/libc/stdlib/recallocarray.c b/lib/libc/stdlib/recallocarray.c new file mode 100644 index 000000000000..cbf1fb2470cf --- /dev/null +++ b/lib/libc/stdlib/recallocarray.c @@ -0,0 +1,73 @@ +/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ +/* + * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <stdckdint.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +void *recallocarray(void *, size_t, size_t, size_t); + +void * +recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) +{ + size_t oldsize, newsize; + void *newptr; + + if (ptr == NULL) + return calloc(newnmemb, size); + + if (ckd_mul(&newsize, newnmemb, size)) { + errno = ENOMEM; + return NULL; + } + + if (ckd_mul(&oldsize, oldnmemb, size)) { + errno = EINVAL; + return NULL; + } + + /* + * Don't bother too much if we're shrinking just a bit, + * we do not shrink for series of small steps, oh well. + */ + if (newsize <= oldsize) { + size_t d = oldsize - newsize; + + if (d < oldsize / 2 && d < (size_t)getpagesize()) { + memset((char *)ptr + newsize, 0, d); + return ptr; + } + } + + newptr = malloc(newsize); + if (newptr == NULL) + return NULL; + + if (newsize > oldsize) { + memcpy(newptr, ptr, oldsize); + memset((char *)newptr + oldsize, 0, newsize - oldsize); + } else + memcpy(newptr, ptr, newsize); + + explicit_bzero(ptr, oldsize); + free(ptr); + + return newptr; +} diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc index 647cbe6f40ba..1baa39a6c0a6 100644 --- a/lib/libc/stdtime/Makefile.inc +++ b/lib/libc/stdtime/Makefile.inc @@ -32,4 +32,5 @@ MLINKS+=strftime.3 strftime_l.3 MLINKS+=strptime.3 strptime_l.3 MLINKS+=time2posix.3 posix2time.3 MLINKS+=tzset.3 daylight.3 \ - tzset.3 timezone.3 + tzset.3 timezone.3 \ + tzset.3 tzname.3 diff --git a/lib/libc/stdtime/ctime.3 b/lib/libc/stdtime/ctime.3 index 96b7f775535a..6384e8bd959b 100644 --- a/lib/libc/stdtime/ctime.3 +++ b/lib/libc/stdtime/ctime.3 @@ -27,7 +27,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 26, 2024 +.Dd September 23, 2025 .Dt CTIME 3 .Os .Sh NAME @@ -41,6 +41,8 @@ .Nm localtime , .Nm localtime_r , .Nm mktime , +.Nm offtime , +.Nm offtime_r , .Nm timegm .Nd transform binary date and time values .Sh LIBRARY @@ -68,14 +70,19 @@ .Fn localtime_r "const time_t *clock" "struct tm *result" .Ft time_t .Fn mktime "struct tm *tm" +.Ft struct tm * +.Fn offtime "const time_t *clock" "long offset" +.Ft struct tm * +.Fn offtime_r "const time_t *clock" "long offset" "struct tm *result" .Ft time_t .Fn timegm "struct tm *tm" .Sh DESCRIPTION The .Fn ctime , .Fn gmtime , +.Fn localtime , and -.Fn localtime +.Fn offtime functions all take as argument a pointer to a time value representing the time in seconds since the Epoch (00:00:00 UTC on January 1, 1970; see @@ -123,6 +130,18 @@ adjustment, and returns a pointer to a .Vt struct tm . .Pp The +.Fn offtime +function similarly converts the time value with a time zone adjustment +corresponding to the provided +.Fa offset , +which is expressed in seconds, with positive values indicating a time +zone ahead of UTC (east of the Prime Meridian). +It does not call +.Xr tzset 3 +or modify +.Va tzname . +.Pp +The .Fn ctime function adjusts the time value for the current time zone in the same manner as @@ -155,13 +174,15 @@ except the caller must provide the output buffer .Fa buf , which must be at least 26 characters long, to store the result in. The -.Fn localtime_r +.Fn localtime_r , +.Fn gmtime_r , and -.Fn gmtime_r +.Fn offtime_r functions provide the same functionality as -.Fn localtime +.Fn localtime , +.Fn gmtime , and -.Fn gmtime +.Fn offtime respectively, except the caller must provide the output buffer .Fa result . .Pp @@ -368,6 +389,12 @@ and .Fn localtime_r functions have been available since .Fx 8.0 . +The +.Fn offtime +and +.Fn offtime_r +functions were added in +.Fx 15.0 . .Sh BUGS Except for .Fn difftime , diff --git a/lib/libc/stdtime/tzset.3 b/lib/libc/stdtime/tzset.3 index 94ccbec9aba7..33e6a556306d 100644 --- a/lib/libc/stdtime/tzset.3 +++ b/lib/libc/stdtime/tzset.3 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 25, 2023 +.Dd September 30, 2025 .Dt TZSET 3 .Os .Sh NAME @@ -58,8 +58,8 @@ specifies how this is done. .Pp If .Ev TZ -does not appear in the environment, the best available approximation to -local wall clock time, as specified by the +does not appear in the environment, the best available approximation +to local wall clock time, as specified by the .Xr tzfile 5 Ns -format file .Pa /etc/localtime @@ -68,9 +68,7 @@ is used. If .Ev TZ appears in the environment but its value is a null string, Coordinated -Universal Time -.Pq Tn UTC -is used (without leap second correction). +Universal Time (UTC) is used (without leap second correction). .Pp If .Ev TZ @@ -81,13 +79,12 @@ the rest of its value is used as a pathname of a file from which to read the time conversion information. If the first character of the pathname is a slash .Pq Ql / -it is used as -an absolute pathname; otherwise, it is used as a pathname relative to -the system time conversion information directory. +it is used as an absolute pathname; otherwise, it is used as a +pathname relative to the system time conversion information directory. .Pp -If its value does not begin with a colon, it is first used as the pathname -of a file (as described above) from which to read the time conversion -information. +If its value does not begin with a colon, it is first used as the +pathname of a file (as described above) from which to read the time +conversion information. If that file cannot be read, the value is then interpreted as a direct specification (the format is described below) of the time conversion information. @@ -96,24 +93,23 @@ If the .Ev TZ environment variable does not specify a .Xr tzfile 5 Ns -format -file and cannot be interpreted as a direct specification, -.Tn UTC -is used. +file and cannot be interpreted as a direct specification, UTC is used. .Pp After the first call to .Nm tzset , the .Vt timezone -variable is set to the difference, in seconds, between Coordinated Universal -Time (UTC) and the local time. +variable is set to the difference, in seconds, between Coordinated +Universal Time (UTC) and the local time. The .Vt daylight variable is set to 0 if the local timezone is observing standard time. -It is set to 1 if the local timezone ever observes an alternate time, such as summer time. +It is set to 1 if the local timezone ever observes an alternate time, +such as summer time. The first element of the .Vt tzname -array is the timezone name of standard time, while the second element is the -name of the altnerative time zone. +array is the timezone name of standard time, while the second element +is the name of the altnerative time zone. .Sh SPECIFICATION FORMAT When .Ev TZ @@ -151,8 +147,7 @@ minus .Pq Ql \- , plus .Pq Ql + , -and -.Tn ASCII +and ASCII .Dv NUL are allowed. .It Em offset @@ -294,10 +289,8 @@ by the file .Em posixrules in the system time conversion information directory are used, with the -standard and summer time offsets from -.Tn UTC -replaced by those specified by -the +standard and summer time offsets from UTC replaced by those specified +by the .Em offset values in .Ev TZ . @@ -315,20 +308,14 @@ local time zone file .It Pa /usr/share/zoneinfo time zone directory .It Pa /usr/share/zoneinfo/posixrules -rules for -.Tn POSIX Ns -style -.Tn TZ Ns 's +rules for POSIX-style TZs .It Pa /usr/share/zoneinfo/Etc/GMT -for -.Tn UTC -leap seconds +for UTC leap seconds .El .Pp If the file .Pa /usr/share/zoneinfo/UTC -does not exist, -.Tn UTC -leap seconds are loaded from +does not exist, UTC leap seconds are loaded from .Pa /usr/share/zoneinfo/posixrules . .Sh SEE ALSO .Xr date 1 , diff --git a/lib/libc/tests/stdtime/Makefile b/lib/libc/tests/stdtime/Makefile index 6b9068e1641b..590dea22da31 100644 --- a/lib/libc/tests/stdtime/Makefile +++ b/lib/libc/tests/stdtime/Makefile @@ -3,6 +3,7 @@ ATF_TESTS_C+= strptime_test ATF_TESTS_C+= detect_tz_changes_test +CFLAGS.detect_tz_changes_test+= -I${SRCTOP}/contrib/tzcode .if ${MK_DETECT_TZ_CHANGES} != "no" CFLAGS.detect_tz_changes_test+= -DDETECT_TZ_CHANGES .endif diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c index 6648d8498cc5..06c31c9fbc3d 100644 --- a/lib/libc/tests/stdtime/detect_tz_changes_test.c +++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c @@ -20,12 +20,16 @@ #include <time.h> #include <unistd.h> +#include "tzdir.h" + #include <atf-c.h> -static const struct tzcase { +struct tzcase { const char *tzfn; const char *expect; -} tzcases[] = { +}; + +static const struct tzcase tzcases[] = { /* * A handful of time zones and the expected result of * strftime("%z (%Z)", tm) when that time zone is active @@ -41,7 +45,8 @@ static const struct tzcase { { "UTC", "+0000 (UTC)" }, { 0 }, }; - +static const struct tzcase utc = { "UTC", "+0000 (UTC)" }; +static const struct tzcase invalid = { "invalid", "+0000 (-00)" }; static const time_t then = 1751328000; /* 2025-07-01 00:00:00 UTC */ static bool debugging; @@ -62,9 +67,9 @@ debug(const char *fmt, ...) static void change_tz(const char *tzn) { - static const char *zfn = "/usr/share/zoneinfo"; - static const char *tfn = "root/etc/.localtime"; - static const char *dfn = "root/etc/localtime"; + static const char *zfn = TZDIR; + static const char *tfn = "root" TZDEFAULT ".tmp"; + static const char *dfn = "root" TZDEFAULT; ssize_t clen; int zfd, sfd, dfd; @@ -96,6 +101,50 @@ test_tz(const char *expect) ATF_CHECK_STREQ(expect, buf); } +ATF_TC(tz_default); +ATF_TC_HEAD(tz_default, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test default zone"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(tz_default, tc) +{ + /* prepare chroot with no /etc/localtime */ + ATF_REQUIRE_EQ(0, mkdir("root", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755)); + /* enter chroot */ + ATF_REQUIRE_EQ(0, chroot("root")); + ATF_REQUIRE_EQ(0, chdir("/")); + /* check timezone */ + unsetenv("TZ"); + test_tz("+0000 (UTC)"); +} + +ATF_TC(tz_invalid_file); +ATF_TC_HEAD(tz_invalid_file, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test invalid zone file"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(tz_invalid_file, tc) +{ + static const char *dfn = "root/etc/localtime"; + int fd; + + /* prepare chroot with bogus /etc/localtime */ + ATF_REQUIRE_EQ(0, mkdir("root", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755)); + ATF_REQUIRE((fd = open(dfn, O_RDWR | O_CREAT, 0644)) >= 0); + ATF_REQUIRE_EQ(8, write(fd, "invalid\n", 8)); + ATF_REQUIRE_EQ(0, close(fd)); + /* enter chroot */ + ATF_REQUIRE_EQ(0, chroot("root")); + ATF_REQUIRE_EQ(0, chdir("/")); + /* check timezone */ + unsetenv("TZ"); + test_tz(invalid.expect); +} + ATF_TC(thin_jail); ATF_TC_HEAD(thin_jail, tc) { @@ -320,6 +369,30 @@ test_tz_env(const char *tzval, const char *expect) test_tz(expect); } +static void +tz_env_common(void) +{ + char path[MAXPATHLEN]; + const struct tzcase *tzcase = tzcases; + int len; + + /* relative path */ + for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) + test_tz_env(tzcase->tzfn, tzcase->expect); + /* absolute path */ + for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) { + len = snprintf(path, sizeof(path), "%s/%s", TZDIR, tzcase->tzfn); + ATF_REQUIRE(len > 0 && (size_t)len < sizeof(path)); + test_tz_env(path, tzcase->expect); + } + /* absolute path with additional slashes */ + for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) { + len = snprintf(path, sizeof(path), "%s/////%s", TZDIR, tzcase->tzfn); + ATF_REQUIRE(len > 0 && (size_t)len < sizeof(path)); + test_tz_env(path, tzcase->expect); + } +} + ATF_TC(tz_env); ATF_TC_HEAD(tz_env, tc) { @@ -327,10 +400,22 @@ ATF_TC_HEAD(tz_env, tc) } ATF_TC_BODY(tz_env, tc) { - const struct tzcase *tzcase; + tz_env_common(); + /* escape from TZDIR is permitted when not setugid */ + test_tz_env("../zoneinfo/UTC", utc.expect); +} - for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) - test_tz_env(tzcase->tzfn, tzcase->expect); + +ATF_TC(tz_invalid_env); +ATF_TC_HEAD(tz_invalid_env, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test invalid TZ value"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(tz_invalid_env, tc) +{ + test_tz_env("invalid", invalid.expect); + test_tz_env(":invalid", invalid.expect); } ATF_TC(setugid); @@ -367,23 +452,25 @@ ATF_TC_HEAD(tz_env_setugid, tc) } ATF_TC_BODY(tz_env_setugid, tc) { - const struct tzcase *tzcase = tzcases; - ATF_REQUIRE_EQ(0, seteuid(UID_NOBODY)); ATF_REQUIRE(issetugid()); - for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) - test_tz_env(tzcase->tzfn, tzcase->expect); + tz_env_common(); + /* escape from TZDIR is not permitted when setugid */ + test_tz_env("../zoneinfo/UTC", invalid.expect); } ATF_TP_ADD_TCS(tp) { debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") && isatty(STDERR_FILENO); + ATF_TP_ADD_TC(tp, tz_default); + ATF_TP_ADD_TC(tp, tz_invalid_file); ATF_TP_ADD_TC(tp, thin_jail); #ifdef DETECT_TZ_CHANGES ATF_TP_ADD_TC(tp, detect_tz_changes); #endif /* DETECT_TZ_CHANGES */ ATF_TP_ADD_TC(tp, tz_env); + ATF_TP_ADD_TC(tp, tz_invalid_env); ATF_TP_ADD_TC(tp, setugid); ATF_TP_ADD_TC(tp, tz_env_setugid); return (atf_no_error()); |