aboutsummaryrefslogtreecommitdiff
path: root/depends/libcap/libcap/cap_file.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-02-10 19:05:02 +0100
committerdec05eba <dec05eba@protonmail.com>2024-02-11 02:11:41 +0100
commit667a6b3b1bc20516d1bf7d8a4611cd3a4d3f3bc6 (patch)
tree2770b29323939cec51670dd0d1aebd39a8041914 /depends/libcap/libcap/cap_file.c
Initial commit, done
Diffstat (limited to 'depends/libcap/libcap/cap_file.c')
-rw-r--r--depends/libcap/libcap/cap_file.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/depends/libcap/libcap/cap_file.c b/depends/libcap/libcap/cap_file.c
new file mode 100644
index 0000000..0bc07f7
--- /dev/null
+++ b/depends/libcap/libcap/cap_file.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 1997,2007,2016 Andrew G Morgan <morgan@kernel.org>
+ *
+ * This file deals with getting/setting capabilities from/on files.
+ */
+
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/*
+ * We hardcode the prototypes for the Linux system calls here since
+ * there are no libcap library APIs that expose the user to these
+ * details, and that way we don't need to force clients to link any
+ * other libraries to access them.
+ */
+extern ssize_t getxattr(const char *, const char *, void *, size_t);
+extern ssize_t fgetxattr(int, const char *, void *, size_t);
+extern int setxattr(const char *, const char *, const void *, size_t, int);
+extern int fsetxattr(int, const char *, const void *, size_t, int);
+extern int removexattr(const char *, const char *);
+extern int fremovexattr(int, const char *);
+
+/*
+ * This public API was moved to include/uapi/linux/xattr.h . For just
+ * these definitions, it isn't really worth managing this in our build
+ * system with yet another copy of a header file. We just, provide
+ * fallback definitions here.
+ */
+#ifndef XATTR_CAPS_SUFFIX
+#define XATTR_CAPS_SUFFIX "capability"
+#endif
+#ifndef XATTR_SECURITY_PREFIX
+#define XATTR_SECURITY_PREFIX "security."
+#endif
+#ifndef XATTR_NAME_CAPS
+#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
+#endif
+
+#include "libcap.h"
+
+#ifdef VFS_CAP_U32
+
+#if VFS_CAP_U32 != __CAP_BLKS
+# error VFS representation of capabilities is not the same size as kernel
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define FIXUP_32BITS(x) bswap_32(x)
+#else
+#define FIXUP_32BITS(x) (x)
+#endif
+
+static cap_t _fcaps_load(struct vfs_ns_cap_data *rawvfscap, cap_t result,
+ int bytes)
+{
+ __u32 magic_etc;
+ unsigned tocopy, i;
+
+ magic_etc = FIXUP_32BITS(rawvfscap->magic_etc);
+ switch (magic_etc & VFS_CAP_REVISION_MASK) {
+ case VFS_CAP_REVISION_1:
+ tocopy = VFS_CAP_U32_1;
+ bytes -= XATTR_CAPS_SZ_1;
+ break;
+
+ case VFS_CAP_REVISION_2:
+ tocopy = VFS_CAP_U32_2;
+ bytes -= XATTR_CAPS_SZ_2;
+ break;
+
+ case VFS_CAP_REVISION_3:
+ tocopy = VFS_CAP_U32_3;
+ bytes -= XATTR_CAPS_SZ_3;
+ result->rootid = FIXUP_32BITS(rawvfscap->rootid);
+ break;
+
+ default:
+ cap_free(result);
+ result = NULL;
+ return result;
+ }
+
+ /*
+ * Verify that we loaded exactly the right number of bytes
+ */
+ if (bytes != 0) {
+ cap_free(result);
+ result = NULL;
+ return result;
+ }
+
+ for (i=0; i < tocopy; i++) {
+ result->u[i].flat[CAP_INHERITABLE]
+ = FIXUP_32BITS(rawvfscap->data[i].inheritable);
+ result->u[i].flat[CAP_PERMITTED]
+ = FIXUP_32BITS(rawvfscap->data[i].permitted);
+ if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
+ result->u[i].flat[CAP_EFFECTIVE]
+ = result->u[i].flat[CAP_INHERITABLE]
+ | result->u[i].flat[CAP_PERMITTED];
+ }
+ }
+ while (i < __CAP_BLKS) {
+ result->u[i].flat[CAP_INHERITABLE]
+ = result->u[i].flat[CAP_PERMITTED]
+ = result->u[i].flat[CAP_EFFECTIVE] = 0;
+ i++;
+ }
+
+ return result;
+}
+
+static int _fcaps_save(struct vfs_ns_cap_data *rawvfscap, cap_t cap_d,
+ int *bytes_p)
+{
+ __u32 eff_not_zero, magic;
+ unsigned tocopy, i;
+
+ if (!good_cap_t(cap_d)) {
+ errno = EINVAL;
+ return -1;
+ }
+ _cap_mu_lock(&cap_d->mutex);
+
+ switch (cap_d->head.version) {
+ case _LINUX_CAPABILITY_VERSION_1:
+ magic = VFS_CAP_REVISION_1;
+ tocopy = VFS_CAP_U32_1;
+ *bytes_p = XATTR_CAPS_SZ_1;
+ break;
+
+ case _LINUX_CAPABILITY_VERSION_2:
+ case _LINUX_CAPABILITY_VERSION_3:
+ magic = VFS_CAP_REVISION_2;
+ tocopy = VFS_CAP_U32_2;
+ *bytes_p = XATTR_CAPS_SZ_2;
+ break;
+
+ default:
+ errno = EINVAL;
+ _cap_mu_unlock_return(&cap_d->mutex, -1);
+ }
+
+ if (cap_d->rootid != 0) {
+ if (cap_d->head.version < _LINUX_CAPABILITY_VERSION_3) {
+ _cap_debug("namespaces with non-0 rootid unsupported by kernel");
+ errno = EINVAL;
+ _cap_mu_unlock_return(&cap_d->mutex, -1);
+ }
+ magic = VFS_CAP_REVISION_3;
+ tocopy = VFS_CAP_U32_3;
+ *bytes_p = XATTR_CAPS_SZ_3;
+ rawvfscap->rootid = FIXUP_32BITS(cap_d->rootid);
+ }
+
+ _cap_debug("setting named file capabilities");
+
+ for (eff_not_zero = 0, i = 0; i < tocopy; i++) {
+ eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE];
+ }
+ while (i < __CAP_BLKS) {
+ if ((cap_d->u[i].flat[CAP_EFFECTIVE]
+ || cap_d->u[i].flat[CAP_INHERITABLE]
+ || cap_d->u[i].flat[CAP_PERMITTED])) {
+ /*
+ * System does not support these capabilities
+ */
+ errno = EINVAL;
+ _cap_mu_unlock_return(&cap_d->mutex, -1);
+ }
+ i++;
+ }
+
+ for (i=0; i < tocopy; i++) {
+ rawvfscap->data[i].permitted
+ = FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]);
+ rawvfscap->data[i].inheritable
+ = FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]);
+
+ if (eff_not_zero
+ && ((~(cap_d->u[i].flat[CAP_EFFECTIVE]))
+ & (cap_d->u[i].flat[CAP_PERMITTED]
+ | cap_d->u[i].flat[CAP_INHERITABLE]))) {
+ errno = EINVAL;
+ _cap_mu_unlock_return(&cap_d->mutex, -1);
+ }
+ }
+
+ if (eff_not_zero == 0) {
+ rawvfscap->magic_etc = FIXUP_32BITS(magic);
+ } else {
+ rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE);
+ }
+
+ _cap_mu_unlock_return(&cap_d->mutex, 0); /* success */
+}
+
+/*
+ * Get the capabilities of an open file, as specified by its file
+ * descriptor.
+ */
+
+cap_t cap_get_fd(int fildes)
+{
+ cap_t result;
+
+ /* allocate a new capability set */
+ result = cap_init();
+ if (result) {
+ struct vfs_ns_cap_data rawvfscap;
+ int sizeofcaps;
+
+ _cap_debug("getting fildes capabilities");
+
+ /* fill the capability sets via a system call */
+ sizeofcaps = fgetxattr(fildes, XATTR_NAME_CAPS,
+ &rawvfscap, sizeof(rawvfscap));
+ if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
+ cap_free(result);
+ result = NULL;
+ } else {
+ result = _fcaps_load(&rawvfscap, result, sizeofcaps);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Get the capabilities from a named file.
+ */
+
+cap_t cap_get_file(const char *filename)
+{
+ cap_t result;
+
+ /* allocate a new capability set */
+ result = cap_init();
+ if (result) {
+ struct vfs_ns_cap_data rawvfscap;
+ int sizeofcaps;
+
+ _cap_debug("getting filename capabilities");
+
+ /* fill the capability sets via a system call */
+ sizeofcaps = getxattr(filename, XATTR_NAME_CAPS,
+ &rawvfscap, sizeof(rawvfscap));
+ if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) {
+ cap_free(result);
+ result = NULL;
+ } else {
+ result = _fcaps_load(&rawvfscap, result, sizeofcaps);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Get rootid as seen in the current user namespace for the file capability
+ * sets.
+ */
+
+uid_t cap_get_nsowner(cap_t cap_d)
+{
+ uid_t nsowner;
+ if (!good_cap_t(cap_d)) {
+ errno = EINVAL;
+ return -1;
+ }
+ _cap_mu_lock(&cap_d->mutex);
+ nsowner = cap_d->rootid;
+ _cap_mu_unlock(&cap_d->mutex);
+ return nsowner;
+}
+
+/*
+ * Set the capabilities of an open file, as specified by its file
+ * descriptor.
+ */
+
+int cap_set_fd(int fildes, cap_t cap_d)
+{
+ struct vfs_ns_cap_data rawvfscap;
+ int sizeofcaps;
+ struct stat buf;
+
+ if (fstat(fildes, &buf) != 0) {
+ _cap_debug("unable to stat file descriptor %d", fildes);
+ return -1;
+ }
+ if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
+ _cap_debug("file descriptor %d for non-regular file", fildes);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cap_d == NULL) {
+ _cap_debug("deleting fildes capabilities");
+ return fremovexattr(fildes, XATTR_NAME_CAPS);
+ } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
+ return -1;
+ }
+
+ _cap_debug("setting fildes capabilities");
+
+ return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
+}
+
+/*
+ * Set the capabilities of a named file.
+ */
+
+int cap_set_file(const char *filename, cap_t cap_d)
+{
+ struct vfs_ns_cap_data rawvfscap;
+ int sizeofcaps;
+ struct stat buf;
+
+ if (lstat(filename, &buf) != 0) {
+ _cap_debug("unable to stat file [%s]", filename);
+ return -1;
+ }
+ if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) {
+ _cap_debug("file [%s] is not a regular file", filename);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (cap_d == NULL) {
+ _cap_debug("removing filename capabilities");
+ return removexattr(filename, XATTR_NAME_CAPS);
+ } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) {
+ return -1;
+ }
+
+ _cap_debug("setting filename capabilities");
+ return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0);
+}
+
+/*
+ * Set nsowner for the file capability set.
+ */
+int cap_set_nsowner(cap_t cap_d, uid_t rootuid)
+{
+ if (!good_cap_t(cap_d)) {
+ errno = EINVAL;
+ return -1;
+ }
+ _cap_mu_lock(&cap_d->mutex);
+ cap_d->rootid = rootuid;
+ _cap_mu_unlock_return(&cap_d->mutex, 0);
+}
+
+#else /* ie. ndef VFS_CAP_U32 */
+
+cap_t cap_get_fd(int fildes)
+{
+ errno = EINVAL;
+ return NULL;
+}
+
+cap_t cap_get_file(const char *filename)
+{
+ errno = EINVAL;
+ return NULL;
+}
+
+uid_t cap_get_nsowner(cap_t cap_d)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int cap_set_fd(int fildes, cap_t cap_d)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int cap_set_file(const char *filename, cap_t cap_d)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int cap_set_nsowner(cap_t cap_d, uid_t rootuid)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+#endif /* def VFS_CAP_U32 */