Compare commits

...

13 Commits
0.5.0 ... 0.6.0

Author SHA1 Message Date
Guillem Jover
119417462e Release libbsd 0.6.0 2013-07-14 13:34:07 +02:00
Guillem Jover
948bcf1db8 Warn when setproctitle() gets called before initialization
Try to give a helpful message in case the program is not initializing
the setproctitle() machinery.
2013-07-14 13:34:07 +02:00
Guillem Jover
c5b9590287 Move setproctitle() automatic initialization to its own library
The automatic initialization cannot be part of the main shared library,
because there is no thread-safe way to change the environ global
variable. This is not a problem if the initializaion happens just at
program load time, but becomes one if the shared library is directly or
indirectly dlopen()ed during the execution of the program, which could
have either kept references to the old environ or could change it in
some other thread. This has been observed for example on systems using
Samba NSS modules.

To avoid any other possible fallout, the constructor is split into a
new static library that needs to be linked explicitly into programs
using setproctitle(). As an additional safety measure the pkg-config
linker flags will mark the program as not allowing to be dlopen()ed
so that we avoid the problem described above.

Reported-by: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=66679
2013-07-14 13:32:11 +02:00
Guillem Jover
3077d2fffc build: Move version ABI from Makefile to configure.ac
It's easier to find there, and the value can be reused in case we have
to provide another shared library.
2013-07-14 10:27:25 +02:00
Guillem Jover
1bf0a55579 Release libbsd 0.5.2 2013-06-08 18:26:04 +02:00
Guillem Jover
ad613d9d09 Create a shallow copy of environ before replacing it in setproctitle()
Because clearenv() or setenv() might free the environ array of pointers,
we should make sure to copy it so that we can access it later on when
doing the deep copy via setenv().

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=65470
2013-06-08 18:26:04 +02:00
Guillem Jover
e084ce3fa7 Specify setproctitle_stub() signature manually if typeof is missing
Do not stop exporting the function in the version node even if typeof
is not available, as that would break ABI.
2013-06-08 18:09:36 +02:00
Guillem Jover
50e4c55afd Try to check if setproctitle() constructor got passed arguments 2013-06-08 18:09:36 +02:00
Guillem Jover
6faea4d2a0 Force setproctitle() into .init_array section
The GNU .init_array support is an extension over the standard System V
ABI .init_array support, which passes the main() arguments to the init
function.

This support comes in three parts. First the dynamic linker (from glibc)
needs to support it. Then function pointers need to be placed in the
section, for example by using __attribute__((constructor)), that the
compiler (gcc or clang for example) might place in section .ctors and
the linker (from binutils) will move to .init_array on the output
object, or by placing them directly into .init_array by the compiler
when compiling. If this does not happen and the function pointers end
up in .ctors, then they will not get passed the main() arguments, which
we do really need in this case.

But this relies on recent binutils or gcc having native .init_array
support, and not having it disabled through --disable-initfini-array.

To guarantee we get the correct behaviour, let's just place the function
pointer in the .init_array section directly, so we only require a recent
enough glibc.

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=65029
2013-06-08 18:09:29 +02:00
Guillem Jover
367e036537 test: Try setting and getting an environment variable after setproctitle() 2013-06-08 18:08:58 +02:00
Guillem Jover
dc8b09783f build: Ignore automake 1.13+ test suite generated files 2013-05-30 04:09:25 +02:00
Guillem Jover
4663364783 Release libbsd 0.5.1 2013-05-27 06:52:05 +02:00
Guillem Jover
df5aebd7e1 test: Mark a literal integer as long long
This fixes build failures on 32-bit architectures.
2013-05-27 06:51:15 +02:00
13 changed files with 221 additions and 20 deletions

2
.gitignore vendored
View File

@@ -5,6 +5,8 @@ ChangeLog
*.o
*.so*
*.a
*.log
*.trs
.deps/
.libs/
Makefile

View File

@@ -66,7 +66,7 @@ for man/arc4random.3, man/tree.3 and man/getprogname.3.
The rest of the licenses apply to code and/or man pages.
Copyright © 2004-2006, 2008-2012 Guillem Jover <guillem@hadrons.org>
Copyright © 2004-2006, 2008-2013 Guillem Jover <guillem@hadrons.org>
Copyright © 2005 Hector Garcia Alvarez
Copyright © 2005 Aurelien Jarno
Copyright © 2006 Robert Millan

View File

@@ -11,6 +11,13 @@ AM_INIT_AUTOMAKE([1.8 foreign nostdinc no-dist-gzip dist-xz])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
[AC_SUBST([AM_DEFAULT_VERBOSITY], [1])])
LIBBSD_ABI_MAJOR=0
LIBBSD_ABI_MINOR=6
LIBBSD_ABI_PATCH=0
LIBBSD_ABI="$LIBBSD_ABI_MAJOR:$LIBBSD_ABI_MINOR:$LIBBSD_ABI_PATCH"
AC_SUBST([LIBBSD_ABI])
# Check and store if we got user supplied variables
user_CFLAGS=${CFLAGS-unset}
@@ -53,6 +60,51 @@ AC_CHECK_DECL([F_CLOSEM],
[#include <limits.h>
#include <fcntl.h>])
AC_CACHE_CHECK(
[for GNU .init_array section support],
[libbsd_cv_gnu_init_array_support],
[AC_RUN_IFELSE(
[AC_LANG_SOURCE(
[[
static int rc = 1;
static void init(int argc) { if (argc == 1) rc = 0; }
void (*init_func)(int argc) __attribute__((section(".init_array"))) = init;
int main() { return rc; }
]]
)],
[libbsd_cv_gnu_init_array_support=yes],
[libbsd_cv_gnu_init_array_support=no],
[AC_PREPROC_IFELSE(
[AC_LANG_SOURCE(
[[
/* Look for a known libc that supports .init_array with the GNU extension
* to pass main() arguments to the init functions. */
#include <stdlib.h>
#if defined __GLIBC_PREREQ
# if __GLIBC_PREREQ(2, 4)
/* glibc supports GNU .init_array since 2.4. */
# else
# error glibc does not support GNU .init_array
# endif
#else
/*
* Basic SysV ABI .init_array support, init functions do not get arguments:
* - Bionic since its inception.
* - uClibc since 0.9.29.
*/
# error unknown whether libc supports GNU .init_array
#endif
]]
)],
[libbsd_cv_gnu_init_array_support=yes],
[libbsd_cv_gnu_init_array_support=no])
]
)]
)
if test "$libbsd_cv_gnu_init_array_support" = no; then
AC_MSG_ERROR([missing required GNU .init_array section support])
fi
# Checks for library functions.
AC_MSG_CHECKING([for program_invocation_short_name])
AC_LINK_IFELSE(
@@ -80,6 +132,7 @@ AC_CONFIG_FILES([
man/Makefile
src/Makefile
src/libbsd.pc
src/libbsd-ctor.pc
src/libbsd-overlay.pc
test/Makefile
])

View File

@@ -56,6 +56,10 @@ void *setmode(const char *mode_str);
void closefrom(int lowfd);
/* Compatibility with sendmail implementations. */
#define initsetproctitle(c, a, e) setproctitle_init((c), (a), (e))
void setproctitle_init(int argc, char *argv[], char *envp[]);
void setproctitle(const char *fmt, ...);
int getpeereid(int s, uid_t *euid, gid_t *egid);

View File

@@ -33,6 +33,8 @@
.In sys/types.h
.In bsd/unistd.h
.Ft void
.Fn setproctitle_init "int argc" "char *argv[]" "char *envp[]"
.Ft void
.Fn setproctitle "const char *fmt" "..."
.Sh DESCRIPTION
The
@@ -41,6 +43,15 @@ library routine sets the process title that appears on the
.Xr ps 1
command.
.Pp
The
.Fn setproctitle_init
library routine only needs to be called (before any call to
.Fn setproctitle
and with
.Fn main
arguments), if the automatic constructor support has not
been linked in through the libbsd-ctor pkg-config file.
.Pp
The title is set from the executable's name, followed by the
result of a
.Xr printf 3
@@ -101,6 +112,11 @@ first appeared in
.Fx 2.2 .
Other operating systems have
similar functions.
.Pp
The
.Fn setproctitle_init
function is a libbsd extension not present on the BSDs, avoid using it
in portable code.
.Sh AUTHORS
.An -nosplit
.An Peter Wemm Aq peter@FreeBSD.org

View File

@@ -10,6 +10,7 @@ AM_CPPFLAGS = \
EXTRA_DIST = \
libbsd.map \
libbsd.pc.in \
libbsd-ctor.pc.in \
libbsd-overlay.pc.in \
hash/helper.c \
$(nil)
@@ -21,10 +22,12 @@ CLEANFILES = \
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
libbsd.pc \
libbsd-ctor.pc \
libbsd-overlay.pc \
$(nil)
lib_LTLIBRARIES = libbsd.la
lib_LIBRARIES = libbsd-ctor.a
hash/md5hl.c: $(srcdir)/hash/helper.c
$(AM_V_at) $(MKDIR_P) hash
@@ -34,7 +37,7 @@ libbsd_la_DEPENDENCIES = \
libbsd.map
libbsd_la_LDFLAGS = \
-Wl,--version-script=$(srcdir)/libbsd.map \
-version-number 0:5:0
-version-number $(LIBBSD_ABI)
libbsd_la_SOURCES = \
arc4random.c \
bsd_getopt.c \
@@ -75,6 +78,10 @@ libbsd_la_SOURCES = \
wcslcpy.c \
$(nil)
libbsd_ctor_a_SOURCES = \
setproctitle_ctor.c \
$(nil)
runtimelibdir = $(libdir)
install-exec-hook:

12
src/libbsd-ctor.pc.in Normal file
View File

@@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libbsd-ctor
Description: Automatic constructor functions for libbsd
Version: @VERSION@
URL: http://libbsd.freedesktop.org/
Cflags: -I${includedir}
Libs: -L${libdir} -Wl,-z,nodlopen -Wl,-u,libbsd_init_func -lbsd-ctor
Requires: libbsd

View File

@@ -105,3 +105,8 @@ LIBBSD_0.5 {
wcslcat;
wcslcpy;
} LIBBSD_0.4;
LIBBSD_0.6 {
/* Exported to cope with the constructor+dlopen+threads mess. */
setproctitle_init;
} LIBBSD_0.5;

View File

@@ -1,6 +1,6 @@
/*
* Copyright © 2010 William Ahern
* Copyright © 2012 Guillem Jover <guillem@hadrons.org>
* Copyright © 2012-2013 Guillem Jover <guillem@hadrons.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -28,6 +28,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
#include <string.h>
@@ -41,6 +42,7 @@ static struct {
/* Pointer to original nul character within base. */
char *nul;
bool warned;
bool reset;
int error;
} SPT;
@@ -76,36 +78,60 @@ spt_clearenv(void)
}
static int
spt_copyenv(char *oldenv[])
spt_copyenv(int envc, char *envp[])
{
char **envcopy;
char *eq;
int envsize;
int i, error;
if (environ != oldenv)
if (environ != envp)
return 0;
/* Make a copy of the old environ array of pointers, in case
* clearenv() or setenv() is implemented to free the internal
* environ array, because we will need to access the old environ
* contents to make the new copy. */
envsize = (envc + 1) * sizeof(char *);
envcopy = malloc(envsize);
if (envcopy == NULL)
return errno;
memcpy(envcopy, envp, envsize);
error = spt_clearenv();
if (error) {
environ = oldenv;
environ = envp;
free(envcopy);
return error;
}
for (i = 0; oldenv[i]; i++) {
eq = strchr(oldenv[i], '=');
for (i = 0; envcopy[i]; i++) {
eq = strchr(envcopy[i], '=');
if (eq == NULL)
continue;
*eq = '\0';
if (setenv(oldenv[i], eq + 1, 1) < 0)
if (setenv(envcopy[i], eq + 1, 1) < 0)
error = errno;
*eq = '=';
if (error) {
environ = oldenv;
#ifdef HAVE_CLEARENV
/* Because the old environ might not be available
* anymore we will make do with the shallow copy. */
environ = envcopy;
#else
environ = envp;
free(envcopy);
#endif
return error;
}
}
/* Dispose of the shallow copy, now that we've finished transfering
* the old environment. */
free(envcopy);
return 0;
}
@@ -129,11 +155,15 @@ spt_copyargs(int argc, char *argv[])
return 0;
}
static void __attribute__((constructor))
spt_init(int argc, char *argv[], char *envp[])
void
setproctitle_init(int argc, char *argv[], char *envp[])
{
char *base, *end, *nul, *tmp;
int i, error;
int i, envc, error;
/* Try to make sure we got called with main() arguments. */
if (argc < 0)
return;
base = argv[0];
if (base == NULL)
@@ -155,6 +185,7 @@ spt_init(int argc, char *argv[], char *envp[])
end = envp[i] + strlen(envp[i]) + 1;
}
envc = i;
SPT.arg0 = strdup(argv[0]);
if (SPT.arg0 == NULL) {
@@ -169,7 +200,7 @@ spt_init(int argc, char *argv[], char *envp[])
}
setprogname(tmp);
error = spt_copyenv(envp);
error = spt_copyenv(envc, envp);
if (error) {
SPT.error = error;
return;
@@ -199,8 +230,14 @@ setproctitle_impl(const char *fmt, ...)
char *nul;
int len;
if (SPT.base == NULL)
if (SPT.base == NULL) {
if (!SPT.warned) {
warnx("setproctitle not initialized, please either call "
"setproctitle_init() or link against libbsd-ctor.");
SPT.warned = true;
}
return;
}
if (fmt) {
if (fmt[0] == '-') {
@@ -245,11 +282,14 @@ setproctitle_impl(const char *fmt, ...)
}
__asm__(".symver setproctitle_impl,setproctitle@@LIBBSD_0.5");
#ifdef HAVE_TYPEOF
/* The original function introduced in 0.2 was a stub, it only got implemented
* in 0.5, make the implementation available in the old version as an alias
* for code linking against that version, and change the default to use the
* new version, so that new code depends on the implemented version. */
#ifdef HAVE_TYPEOF
extern typeof(setproctitle_impl) setproctitle_stub __attribute__((alias("setproctitle_impl")));
__asm__(".symver setproctitle_stub,setproctitle@LIBBSD_0.2");
#else
void setproctitle_stub(const char *fmt, ...)
__attribute__((alias("setproctitle_impl")));
#endif
__asm__(".symver setproctitle_stub,setproctitle@LIBBSD_0.2");

52
src/setproctitle_ctor.c Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright © 2013 Guillem Jover <guillem@hadrons.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <unistd.h>
/*
* The automatic initialization cannot be part of the main shared library,
* because there is no thread-safe way to change the environ global
* variable. This is not a problem if the initializaion happens just at
* program load time, but becomes one if the shared library is directly or
* indirectly dlopen()ed during the execution of the program, which could
* have either kept references to the old environ or could change it in
* some other thread. This has been observed for example on systems using
* Samba NSS modules.
*
* To avoid any other possible fallout, the constructor is split into a
* new static library that needs to be linked explicitly into programs
* using setproctitle(). As an additional safety measure the pkg-config
* linker flags will mark the program as not allowing to be dlopen()ed
* so that we make sure to avoid the problem described above.
*/
/*
* Force setproctitle_init() function into the .init_array section instead of
* expecting either the compiler to place constructors there or the linker to
* move them from .ctors to .init_array.
*/
void (*libbsd_init_func)(int argc, char *argv[], char *envp[])
__attribute__((section(".init_array"))) = setproctitle_init;

View File

@@ -18,6 +18,10 @@ check_PROGRAMS = \
humanize_LDFLAGS = $(top_builddir)/src/libbsd.la
fgetln_LDFLAGS = $(top_builddir)/src/libbsd.la
proctitle_LDFLAGS = $(top_builddir)/src/libbsd.la
proctitle_LDFLAGS = \
-Wl,-u,libbsd_init_func \
$(top_builddir)/src/libbsd-ctor.a \
$(top_builddir)/src/libbsd.la \
$(nil)
TESTS = $(check_PROGRAMS)

View File

@@ -58,7 +58,7 @@ main(int argc, char **argv)
assert(val == 20971520);
assert(dehumanize_number("-3G", &val) == 0);
assert(val == -3221225472);
assert(val == -3221225472LL);
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2012 Guillem Jover <guillem@hadrons.org>
* Copyright © 2012-2013 Guillem Jover <guillem@hadrons.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,6 +35,7 @@ main(int argc, char **argv)
{
const char newtitle_base[] = "test arg1 arg2";
char *newtitle_full;
char *envvar;
setproctitle("-test %s arg2", "arg1");
assert(strcmp(argv[0], newtitle_base) == 0);
@@ -44,5 +45,10 @@ main(int argc, char **argv)
assert(strcmp(argv[0], newtitle_full) == 0);
free(newtitle_full);
assert(setenv("LIBBSD_TEST", "test value", 1) == 0);
envvar = getenv("LIBBSD_TEST");
assert(envvar != NULL);
assert(strcmp(envvar, "test value") == 0);
return 0;
}