stevegrubb / libcap-ng Goto Github PK
View Code? Open in Web Editor NEWLibcap-ng is a library for Linux that makes using posix capabilities easy.
License: GNU General Public License v2.0
Libcap-ng is a library for Linux that makes using posix capabilities easy.
License: GNU General Public License v2.0
At the moment, these are enum
s instead of preprocessor symbols, so I cannot just do this:
#ifdef CAPNG_SELECT_ALL
capng_clear(CAPNG_SELECT_ALL);
#else
capng_clear(CAPNG_SELECT_BOTH);
#endif
Would you prefer to convert these to macros, or to provide a #define CAPNG_SUPPORTS_AMBIENT 1
in 0.8.1
?
Looks like something is wrong
+ cd libcap-ng-0.8.4
+ autoreconf -fiv
autoreconf: export WARNINGS=
autoreconf: Entering directory '.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: running: libtoolize --copy --force
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
autoreconf: configure.ac: not using Intltool
autoreconf: configure.ac: not using Gtkdoc
autoreconf: running: aclocal --force -I m4
autoreconf: running: /usr/bin/autoconf --force
autoreconf: running: /usr/bin/autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:42: installing './compile'
configure.ac:40: installing './config.guess'
configure.ac:40: installing './config.sub'
configure.ac:41: installing './install-sh'
configure.ac:41: installing './missing'
Makefile.am: error: required file './NEWS' not found
bindings/python3/Makefile.am: installing './depcomp'
bindings/python3/Makefile.am:31: installing './py-compile'
parallel-tests: installing './test-driver'
bindings/src/Makefile.am:24: warning: variable 'SWIG_SOURCES' is defined but no program or
bindings/src/Makefile.am:24: library has 'SWIG' as canonical name (possible typo)
autoreconf: error: automake failed with exit status: 1
It does not work with autoconf 2.71 and 2.72.
Building on some distros (openSUSE 15.1) requires the addition of -lpthread in order to build successfully:
make[2]: Entering directory '/home/trevor/devel/extern/libcap-ng/_build/utils'
/bin/sh ../libtool --tag=CC --mode=link gcc -W -Wall -Wshadow -Wformat -Wundef -D_GNU_SOURCE -g -O2 -o pscap pscap.o -L../src -lcap-ng
libtool: link: gcc -W -Wall -Wshadow -Wformat -Wundef -D_GNU_SOURCE -g -O2 -o .libs/pscap pscap.o -L../src /home/trevor/devel/extern/libcap-ng/_build/src/.libs/libcap-ng.so
/usr/lib64/gcc/x86_64-suse-linux/8/../../../../x86_64-suse-linux/bin/ld: /home/trevor/devel/extern/libcap-ng/_build/src/.libs/libcap-ng.so: undefined reference to `pthread_atfork'
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:488: pscap] Error 1
make[2]: Leaving directory '/home/trevor/devel/extern/libcap-ng/_build/utils'
make[1]: *** [Makefile:448: all-recursive] Error 1
make[1]: Leaving directory '/home/trevor/devel/extern/libcap-ng/_build'
make: *** [Makefile:380: all] Error 2
I noticed this with 0.7.10, but the issue also exists on master.
I can build successfully if I do:
$ make LDFLAGS="-lpthread"
I am testing rebuild of SWIG dependencies against version 4.2.0 in Fedora rawhide/40.
The build of libcap-ng-0.8.4
is failing with this version.
swig -o capng_wrap.c -python -I. -I../.. -I/usr/include/python3.12 -I/usr/include/python3.12 ./../src/capng_swig.i
make[4]: Leaving directory '/builddir/build/BUILD/libcap-ng-0.8.4/bindings/python3'
./../src/capng_swig.i:33: Error: Unknown directive '%except'.
make[4]: *** [Makefile:878: capng_wrap.c] Error 1
make[3]: *** [Makefile:595: all-recursive] Error 1
make[2]: *** [Makefile:390: all-recursive] Error 1
make[1]: *** [Makefile:441: all-recursive] Error 1
make: *** [Makefile:373: all] Error 2
error: Bad exit status from /var/tmp/rpm-tmp.98V4Nl (%build)
The reason is that features deprecated in SWIG 1.x and 2.x was removed. Instead %except
should be replaced by using %exception
.
Here apache 2.4.33 segfaults on graceful reload in some conditions (like php pgsql or curl loaded)
0.7.8 - works fine
0.7.9 - segfault
I guess "Use pthread_atfork to optionally reset the pid and related info on fork" is problematic.
Core was generated by `/usr/sbin/httpd -f /etc/httpd/apache.conf'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007fd94d9a36a0 in ?? ()
(gdb) bt
#0 0x00007fd94d9a36a0 in ?? ()
#1 0x00007fd961a8b52e in __libc_fork () at ../sysdeps/nptl/fork.c:204
#2 0x00007fd95dcc1a55 in ?? () from /etc/httpd/modules/mod_mpm_prefork.so
#3 0x00007fd95dcc2a3e in ?? () from /etc/httpd/modules/mod_mpm_prefork.so
#4 0x00000000004356c3 in ap_run_mpm ()
#5 0x000000000042e06c in main ()
glibc fork.c part is
197 /* Reset the lock the dynamic loader uses to protect its data. */
198 __rtld_lock_initialize (GL(dl_load_lock));
199
200 /* Run the handlers registered for the child. */
201 while (allp != NULL)
202 {
203 if (allp->handler->child_handler != NULL)
204 allp->handler->child_handler ();
205
206 /* Note that we do not have to wake any possible waiter.
207 This is the only thread in the new process. The count
208 may have been bumped up by other threads doing a fork.
209 We reset it to 1, to avoid waiting for non-existing
210 thread(s) to release the count. */
211 allp->handler->refcntr = 1;
apache isn't directly using libcap-ng but is loading php->pgsql->postgresql-libs->openldap-libs->cyrus-sasl/audit-libs->libcap-ng, so after all libcap-ng code is used
That could explain things:
https://sourceware.org/bugzilla/show_bug.cgi?id=13502
as graceful apache restart reloads modules.
Looks like using pthread_atfork isn't good choice: "the whole concept of pthread_atfork was a mistake, and this is largely acknowledged in the Rationale section for pthread_atfork in POSIX."
This is mostly for build environments and automated handling / downloading.
people.redhat.com is currently having issues. Redhat internal tracking ID: INC2158974
https://www.ssllabs.com/ssltest/analyze.html?d=people.redhat.com
The certificate chain is incomplete, leading to download issues if the certificate chain isn't ignored.
I was thinking of moving the libcap-ng download URL to github, but the github tarballs don't hash the same as the release tarballs.
I suspect these ones distributed here are just source balls, not "make dist" ones.
Either way, it currently causes a bit of a headache.
If it's an option, could you please distribute the proper release tarballs on github and make it a permanent hosting place?
The following code resulted in the wrong capabilities
capng.capng_updatev(capng.CAPNG_ADD, capng.CAPNG_EFFECTIVE|capng.CAPNG_PERMITTED, capng.CAP_SYS_BOOT, capng.CAP_SYS_TIME, -1)
capng.capng_change_id(pwent.pw_uid, pwent.pw_gid, capng.CAPNG_CLEAR_BOUNDING)
I expected sys_boot and sys_time in the capabilities of my running Python process, but ...
> pscap
1191 5634 ted python3 chown, sys_boot
I ended up instead with the following
for c in [ capng.CAP_SYS_BOOT, capng.CAP_SYS_TIME ]:
capng.capng_update(capng.CAPNG_ADD, capng.CAPNG_EFFECTIVE|capng.CAPNG_PERMITTED, c)
capng.capng_change_id(pwent.pw_uid, pwent.pw_gid, capng.CAPNG_CLEAR_BOUNDING)
which worked fine:
> pscap
1207 5634 ted python3 sys_boot, sys_time
Linux kernel version is 5.4.51. Host is armv7l. libcap-ng version 0.7.10
arguments "uid" and "gid" of capng_change_id should be changed to uid_t and gid_t.
should i submit a pull request?
Hi,
I've got a heavily sandbox'd daemon that runs something like:
a) Sandbox
b) Create more threads
c) Do stuff in threads
The sandbox includes a mount namespace setup where it doesn't have /proc.
capng_get_caps_process calls get_bounding_set which reads /proc/.../state - which fails.
That's not a problem with yee oldee libcaps, it only uses capget.
So now I have a problem how to setup each thread; the current guess is to do a capng_save_state before the sandboxing, and then do a restore state somewhere in each thread.
Which is kind of OK except for restore_state freeing stuff; so I'm going to have to do a dance of restore_state/save_state to keep a copy.
It feels like there should be a better way.
This will leave the ambient caps unset:
capng_clear(CAPNG_SELECT_ALL); // traditional, bounding, ambient
capng_update(
CAPNG_ADD,
CAPNG_EFFECTIVE | CAPNG_PERMITTED | CAPNG_INHERITABLE
| CAPNG_BOUNDING_SET | CAPNG_AMBIENT,
CAP_CHOWN
);
capng_apply(CAPNG_SELECT_ALL); // traditional, bounding, ambient
I.e. /proc/self/status
will have:
CapInh: 0000000000000001
CapPrm: 0000000000000001
CapEff: 0000000000000001
CapBnd: 0000000000000001
CapAmb: 0000000000000000
But if you double up the capng_apply
, you get the desired result:
capng_apply(CAPNG_SELECT_ALL); // traditional, bounding
capng_apply(CAPNG_SELECT_ALL); // ambient
I think this happens because of the line in capabilities (7)
that says:
The ambient capability set obeys the invariant that no capability can ever be ambient if it is not both permitted and inheritable.
The issue I'm facing is that I have containers build with 5.x kernel headers, and the kernel versions I need to support for actual deployment is ranging between 4.1 - 5.x, which is a mix of kernels that may and may not support PR_CAP_AMBIENT.
Building the support of PR_CAP_AMBIENT then run libcap-ng on kernel without actual support would fail almost every function. Build different versions of containers with different kernel headers is not ideal.
If we can detect the support of PR_CAP_AMBIENT at runtime instead of compile time then we can conditionally run code related to PR_CAP_AMBIENT, thus a single build of libcap-ng using new kernel headers can run on both old and new kernel without causing problem.
I'm not really a C programmer, but I imagine we can do something like this:
#ifdef PR_CAPBSET_DROP
int has_capbset_drop = 1;
rc = prctl(PR_CAPBSET_READ, 0, 0, 0, 0);
if (rc < 0 && errno == EINVAL) { // EINVAL -> kernel does not support PR_CAPBSET_DROP
has_capbset_drop = 0;
}
if (has_capbset_drop) {
...
}
#endif
#ifdef PR_CAP_AMBIENT
int has_ambient = 1;
rc = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, 0, 0, 0);
if (rc < 0 && errno == EINVAL) { // EINVAL -> kernel does not support PR_CAP_AMBIENT
has_ambient = 0;
}
if (has_ambient) {
...
}
#endif
I'd happy to make a PR, but I want to hear some thoughts before I proceed.
I think that after+ y it would be good to release new code base :)
I have an application which redistributes libdrop_ambient 0.0.0. Under the terms of the GPL source code needs to be included. However there is no release with that version.
I would be grateful for guidance.
On my Debian systems, I get the following when trying to fetch the tarball with wget:
alex@alex-lx-laptop:~$ wget https://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.8.5.tar.gz
--2024-08-06 16:49:47-- https://people.redhat.com/sgrubb/libcap-ng/libcap-ng-0.8.5.tar.gz
Resolving people.redhat.com (people.redhat.com)... 209.132.178.26
Connecting to people.redhat.com (people.redhat.com)|209.132.178.26|:443... connected.
ERROR: The certificate of ‘people.redhat.com’ is not trusted.
ERROR: The certificate of ‘people.redhat.com’ doesn't have a known issuer.
Although python3
binary was detected as valid interpreter, install still failed due to missing python
binary:
../../py-compile[155]: python: inaccessible or not found
make[4]: *** [Makefile:551: install-pyexecPYTHON] Error 127
Version: 0.8.5
During compilation of libcap-ng 0.7.10 for OpenWrt, I noticed these warnings and I think that it could be good that you will know about them.
In file lookup_table.c
lookup_table.c: In function 'capng_capability_to_name':
lookup_table.c:35:27: warning: comparison of integer expressions of different signedness: 'unsigned int' and 'int' [-Wsign-compare]
#define cap_valid(x) ((x) <= last_cap)
^~
lookup_table.c:114:7: note: in expansion of macro 'cap_valid'
if (!cap_valid(capability))
^~~~~~~~~
lookup_table.c:117:6: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
ptr = capng_lookup_number(captab, captab_msgstr.str,
In file lookup_table.c
cap-ng.c: In function 'capng_update':
cap-ng.c:72:27: warning: comparison of integer expressions of different signedness: 'unsigned int' and 'int' [-Wsign-compare]
#define cap_valid(x) ((x) <= last_cap)
^~
cap-ng.c:452:7: note: in expansion of macro 'cap_valid'
if (!cap_valid(capability)) {
^~~~~~~~~
cap-ng.c: In function 'capng_updatev':
cap-ng.c:72:27: warning: comparison of integer expressions of different signedness: 'unsigned int' and 'int' [-Wsign-compare]
#define cap_valid(x) ((x) <= last_cap)
^~
cap-ng.c:499:9: note: in expansion of macro 'cap_valid'
while (cap_valid(cap)) {
^~~~~~~~~
cap-ng.c: In function 'capng_have_capability':
cap-ng.c:72:27: warning: comparison of integer expressions of different signedness: 'unsigned int' and 'int' [-Wsign-compare]
#define cap_valid(x) ((x) <= last_cap)
^~
cap-ng.c:883:7: note: in expansion of macro 'cap_valid'
if (!cap_valid(capability))
^~~~~~~~~
A complete ready-to-go repro is here:
https://gist.github.com/snarkmaster/4d019ab39e9adbe4fd7269f4f9812692
The short story is this:
/proc/PID/status
is ff
capsh --drop=cap_chown --
-- the last byte is now fe
capsh run a
libcap-ng` program which tries to set the bounding set to full againcapng_apply
succeedscapng_have_capability(CAPNG_BOUNDING_SET, CAP_CHOWN)
-- the result is 1procfs
, the last byte still ends in fe
(of course).--- configure.ac.orig 2023-04-27 22:18:57.659402571 -0400
+++ configure.ac 2023-04-27 22:19:07.173321549 -0400
@@ -60,7 +60,7 @@
[AC_SEARCH_LIBS(pthread_atfork, pthread)],
[AC_MSG_WARN(pthread.h not found, disabling pthread_atfork.)])
AC_CHECK_HEADERS(sys/vfs.h, [
- AC_CHECK_HEADERS(linux/magic.h, [] [AC_MSG_WARN(linux/magic.h is required in order to verify procfs.)])
+ AC_CHECK_HEADERS(linux/magic.h, [], [AC_MSG_WARN(linux/magic.h is required in order to verify procfs.)])
], [AC_MSG_WARN(sys/vfs.h is required in order to verify procfs.)])
AC_ARG_WITH([capability_header],
This service:
/etc/systemd/system/servers.service
[Unit]
Description=mount-servers systemd service.
[Service]
Type=simple
ExecStart=/bin/bash /usr/local/bin/mount-servers.sh
[Install]
WantedBy=multi-user.target
This script:
#!/bin/bash
mount -t cifs //192.168.1.200/Drive_E /mnt/server-e -o credentials=/root/.smbcredentials_server,nounix,dir_mode=0777,file_mode=0777
mount -t cifs //192.168.1.200/Drive_E/Dropbox /mnt/dropbox -o credentials=/root/.smbcredentials_server,nounix,dir_mode=0777,file_mode=0777
mount -t cifs //192.168.1.200/Drive_D /mnt/server-d -o credentials=/root/.smbcredentials_server,nounix,dir_mode=0777,file_mode=0777
systemctl status servers
× servers.service - mount-servers systemd service.
Loaded: loaded (/usr/local/lib/systemd/system/servers.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Tue 2021-09-07 17:30:38 PDT; 44min ago
Process: 13728 ExecStart=/bin/bash /usr/local/bin/mount-servers.sh (code=exited, status=32)
Main PID: 13728 (code=exited, status=32)
CPU: 15ms
Sep 07 17:30:38 fedora bash[13735]: mount error(16): Device or resource busy
Sep 07 17:30:38 fedora bash[13735]: Refer to the mount.cifs(8) manual page (e.g. man mount.cifs) and kernel log messages (dmesg)
Sep 07 17:30:38 fedora mount.cifs[13739]: libcap-ng used by "/usr/sbin/mount.cifs" failed due to not having CAP_SETPCAP in capng_apply
Sep 07 17:30:38 fedora bash[13738]: mount error(16): Device or resource busy
Sep 07 17:30:38 fedora bash[13738]: Refer to the mount.cifs(8) manual page (e.g. man mount.cifs) and kernel log messages (dmesg)
Sep 07 17:30:38 fedora bash[13740]: mount: /mnt/data: /dev/sdb1 already mounted on /mnt/backup.
Sep 07 17:30:38 fedora bash[13741]: mount: /mnt/backup: /dev/sdc1 already mounted on /mnt/data.
Sep 07 17:30:38 fedora bash[13742]: mount: /mnt/timeshift: /dev/sdd1 already mounted on /mnt/timeshift.
Sep 07 17:30:38 fedora systemd[1]: servers.service: Main process exited, code=exited, status=32/n/a
Sep 07 17:30:38 fedora systemd[1]: servers.service: Failed with result 'exit-code'.
Sep 07 17:30:38 fedora bash[13735]: mount error(16): Device or resource busy
Sep 07 17:30:38 fedora bash[13735]: Refer to the mount.cifs(8) manual page (e.g>
Sep 07 17:30:38 fedora mount.cifs[13739]: libcap-ng used by "/usr/sbin/mount.ci>
Sep 07 17:30:38 fedora bash[13738]: mount error(16): Device or resource busy
Sep 07 17:30:38 fedora bash[13738]: Refer to the mount.cifs(8) manual page (e.g>
Sep 07 17:30:38 fedora bash[13740]: mount: /mnt/data: /dev/sdb1 already mounted>
Sep 07 17:30:38 fedora bash[13741]: mount: /mnt/backup: /dev/sdc1 already mount>
Sep 07 17:30:38 fedora bash[13742]: mount: /mnt/timeshift: /dev/sdd1 already mo>
Sep 07 17:30:38 fedora systemd[1]: servers.service: Main process exited, code=e>
Sep 07 17:30:38 fedora systemd[1]: servers.service: Failed with result 'exit-co>
lines 1-17/17 (END)
libcap-ng seems to have some problem with namespaces. I am working with a container infrastructure like docker and i have written code to drop capabilites inside the container. It doesn't work when i enable both namespaces and resources. But it works when i do resource-only.
In cap-ng.c all uses of PR_CAP_AMBIENT are protected by #ifdef PR_CAP_AMBIENT
but libdrop_ambient.c does not have the check. Of course libdrop_ambient is useless on platforms that don't have ambient capability support, but I propose just adding the ifdef there instead of trying to tinker the autotools files to skip building the library altogether when the support is missing (which shoould be pretty rare case by now).
What do you think? Would you accept a pull request for something like this?
--- a/src/libdrop_ambient.c 2020-11-18 10:39:31.000000000 -0800
+++ b/src/libdrop_ambient.c 2020-12-02 15:59:10.977235659 -0800
@@ -25,6 +25,8 @@
void __attribute__ ((constructor)) init(void)
{
+#ifdef PR_CAP_AMBIENT
prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+#endif
}
In C code,the parameters of capng_updatev are parsed as 'unsigned int' like this:
int capng_updatev(capng_act_t action, capng_type_t type,
unsigned int capability, ...)
{
int rc;
unsigned int cap;
va_list ap;
rc = capng_update(action, type, capability);
if (rc)
return rc;
va_start(ap, capability);
cap = va_arg(ap, unsigned int);
while (cap_valid(cap)) {
rc = capng_update(action, type, cap);
if (rc)
break;
cap = va_arg(ap, unsigned int);
}
va_end(ap);
// See if planned exit or invalid
if (cap == (unsigned)-1)
rc = 0;
else {
rc = -1;
errno = EINVAL;
}
return rc;
}
In the commit 2906fb0 ,they were changed to signed, Why to modify capng_updatev parameter type to signed for python bindings?
After upgrading libcap-ng to the freshly released version 0.8.1, attempting to start GNOME Keyring fails with an error message:
$ gnome-keyring-daemon --start
gnome-keyring-daemon: error dropping process capabilities, aborting
I have bisected this to commit 6a24a9c ("capng_apply error update"), so apparently GNOME Keyring does not expect capng_apply
to fail in this situation. The relevant capability handling code in GNOME Keyring looks as follows:
capng_clear (CAPNG_SELECT_BOTH);
if (capng_update (CAPNG_ADD,
CAPNG_EFFECTIVE|CAPNG_PERMITTED,
CAP_IPC_LOCK) != 0)
early_error ("error dropping process capabilities");
if (capng_apply (CAPNG_SELECT_BOTH) != 0)
early_error ("error dropping process capabilities");
Downstream Arch Linux bug report: FS#68664
Hi! I'm developing some changes in util-linux ( util-linux/util-linux#1187 ) for how they detect the last cap from the kernel, and I would like to know if you'd accept a PR to add the same changes here.
Also, do you think a capng_get_last_cap
call could be added to the API?
While working on adding capability support for openvpn, we discovered a very problematic possible failure case of capng_change_id():
In case capng_update_id() fails, maybe due to missing capabilities, rampant SElinux, or whatever other reason, we fall back to the classic codepath, which just calls setgid() + setuid().
Now, if capng_change_id() fails after
Line 994 in 423a1af
Line 1041 in 423a1af
This results in our fallback setuid() leaving the permitted capabilities set. This is a very unexpected and potentially dangerous if it's a security critical process that is expected to have no capabilities.
Is this behaviour expected? As in, we should always terminate in case capng_change_id() failed, since the state cannot be guaranteed?
Or would it be possible to reset the PR_SET_KEEPCAPS flags on failure? Or maybe set it much later, so there's not so much stuff that can fail in between it and the actual setuid?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.