static void do_caps(capng_type_t type, const char *caps) { char *my_caps = xstrdup(caps); char *c; while ((c = strsep(&my_caps, ","))) { capng_act_t action; if (*c == '+') action = CAPNG_ADD; else if (*c == '-') action = CAPNG_DROP; else errx(EXIT_FAILURE, _("bad capability string")); if (!strcmp(c + 1, "all")) { int i; /* It would be really bad if -all didn't drop all * caps. It's better to just fail. */ if (real_cap_last_cap() > CAP_LAST_CAP) errx(SETPRIV_EXIT_PRIVERR, _("libcap-ng is too old for \"all\" caps")); for (i = 0; i <= CAP_LAST_CAP; i++) capng_update(action, type, i); } else { int cap = capng_name_to_capability(c + 1); if (0 <= cap) capng_update(action, type, cap); else errx(EXIT_FAILURE, _("unknown capability \"%s\""), c + 1); } } free(my_caps); }
void secure_capng_update(capng_act_t action, capng_type_t type,unsigned int capability) { if (!( (action==CAPNG_DROP)||(action==CAPNG_ADD) )) { std::ostringstream oss; oss<<"Error: " << "invalid input" << " in " << __func__ << ": action="<<action<<"." ; throw capmodpp_error(oss.str()); } if (!( (type==CAPNG_EFFECTIVE)||(type==CAPNG_PERMITTED)||(type==CAPNG_INHERITABLE)||(type==CAPNG_BOUNDING_SET) )) { std::ostringstream oss; oss<<"Error: " << "invalid input" << " in " << __func__ << ": type="<<type<<"." ; throw capmodpp_error(oss.str()); } if (!( (capability<=get_last_cap_nr()) )) { static_assert(std::numeric_limits<decltype(capability)>::is_signed==false, "This must be unsigned (as we do not test for >=0)"); std::ostringstream oss; oss<<"Error: " << "invalid input" << " in " << __func__ << ": capability="<<capability<<"."; throw capmodpp_error(oss.str()); } auto ret = int { capng_update(action,type,capability) }; bool fail = (ret!=0); bool badval = false; if (fail||badval) { std::ostringstream oss; oss<<"Error: " << (fail ? "FAILED":"") << " " << (badval ? "BAD-VALUE":"") << " (ret="<<ret<<") in " << __func__ << " for action="<<action<<",type="<<type<<"capability="<<capability; // WARNING: output only values that are valid enough throw capmodpp_error(oss.str()); } }
static int cap_update(capng_act_t action, enum cap_type type, unsigned int cap) { switch (type) { case CAP_TYPE_EFFECTIVE: case CAP_TYPE_BOUNDING: case CAP_TYPE_INHERITABLE: case CAP_TYPE_PERMITTED: return capng_update(action, (capng_type_t) type, cap); case CAP_TYPE_AMBIENT: { int ret; if (action == CAPNG_ADD) ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long) cap, 0UL, 0UL); else ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, (unsigned long) cap, 0UL, 0UL); return ret; } default: errx(EXIT_FAILURE, _("unsupported capability type")); return -1; } }
/* Linux specific implementation of daemon_become_new_user() * using libcap-ng. */ static void daemon_become_new_user_linux(bool access_datapath OVS_UNUSED) { #if defined __linux__ && HAVE_LIBCAPNG int ret; ret = capng_get_caps_process(); if (!ret) { if (capng_have_capabilities(CAPNG_SELECT_CAPS) > CAPNG_NONE) { const capng_type_t cap_sets = CAPNG_EFFECTIVE|CAPNG_PERMITTED; capng_clear(CAPNG_SELECT_BOTH); ret = capng_update(CAPNG_ADD, cap_sets, CAP_IPC_LOCK) || capng_update(CAPNG_ADD, cap_sets, CAP_NET_BIND_SERVICE); if (access_datapath && !ret) { ret = capng_update(CAPNG_ADD, cap_sets, CAP_NET_ADMIN) || capng_update(CAPNG_ADD, cap_sets, CAP_NET_RAW) || capng_update(CAPNG_ADD, cap_sets, CAP_NET_BROADCAST); } } else { ret = -1; } } if (!ret) { /* CAPNG_INIT_SUPP_GRP will be a better choice than * CAPNG_DROP_SUPP_GRP. However this enum value is only defined * with libcap-ng higher than version 0.7.4, which is not wildly * available on many Linux distributions yet. Taking a more * conservative approach to make sure OVS behaves consistently. * * XXX We may change this for future OVS releases. */ ret = capng_change_id(uid, gid, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING); } if (ret) { VLOG_FATAL("%s: libcap-ng fail to switch to user and group " "%d:%d, aborting", pidfile, uid, gid); } #endif }
// Update the capabilities of the running process to include the given // capability in the Ambient set. static void set_ambient_cap(cap_value_t cap) { capng_get_caps_process(); if (capng_update(CAPNG_ADD, CAPNG_INHERITABLE, (unsigned long) cap)) { perror("cannot raise the capability into the Inheritable set\n"); exit(1); } capng_apply(CAPNG_SELECT_CAPS); if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long) cap, 0, 0)) { perror("cannot raise the capability into the Ambient set\n"); exit(1); } }
void SCDropCaps(ThreadVars *tv) { #if 0 capng_clear(CAPNG_SELECT_BOTH); capng_apply(CAPNG_SELECT_BOTH); if (tv->cap_flags & SC_CAP_IPC_LOCK) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_IPC_LOCK); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_IPC_LOCK has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_ADMIN) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_ADMIN); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_ADMIN has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_BIND_SERVICE) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BIND_SERVICE); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_BIND_SERVICE has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_BROADCAST) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_BROADCAST); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_BROADCAST has been set", tv->name); } if (tv->cap_flags & SC_CAP_NET_RAW) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_NET_RAW); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_NET_RAW has been set", tv->name); } if (tv->cap_flags & SC_CAP_SYS_ADMIN) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_ADMIN); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_SYS_ADMIN has been set", tv->name); } if (tv->cap_flags & SC_CAP_SYS_RAW_IO) { capng_update(CAPNG_ADD, (capng_type_t) (CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SYS_RAWIO); capng_apply(CAPNG_SELECT_CAPS); SCLogDebug("For thread \"%s\" CAP_SYS_RAWIO has been set", tv->name); } #endif }
/*! \brief POSIX 1003.1e capabilities. */ static void setup_capabilities(void) { #ifdef HAVE_CAP_NG_H /* Drop all capabilities. */ if (capng_have_capability(CAPNG_EFFECTIVE, CAP_SETPCAP)) { capng_clear(CAPNG_SELECT_BOTH); /* Retain ability to set capabilities and FS access. */ capng_type_t tp = CAPNG_EFFECTIVE|CAPNG_PERMITTED; capng_update(CAPNG_ADD, tp, CAP_SETPCAP); capng_update(CAPNG_ADD, tp, CAP_DAC_OVERRIDE); capng_update(CAPNG_ADD, tp, CAP_CHOWN); /* Storage ownership. */ /* Allow binding to privileged ports. * (Not inheritable) */ capng_update(CAPNG_ADD, tp, CAP_NET_BIND_SERVICE); /* Allow setuid/setgid. */ capng_update(CAPNG_ADD, tp, CAP_SETUID); capng_update(CAPNG_ADD, tp, CAP_SETGID); /* Allow priorities changing. */ capng_update(CAPNG_ADD, tp, CAP_SYS_NICE); /* Apply. */ if (capng_apply(CAPNG_SELECT_BOTH) < 0) { log_error("failed to set process capabilities (%s)", strerror(errno)); } } else { log_info("user UID %d is not allowed to set capabilities, " "skipping", getuid()); } #endif /* HAVE_CAP_NG_H */ }
int main(int argc, char *argv[]) { char *unikernel; enum { QEMU, KVM, UKVM, UNIX } hypervisor; if (argc < 3) { fprintf(stderr, "usage: runner HYPERVISOR UNIKERNEL [ ARGS... ]\n"); fprintf(stderr, "HYPERVISOR: qemu | kvm | ukvm | unix\n"); return 1; } if (strcmp(argv[1], "qemu") == 0) hypervisor = QEMU; else if (strcmp(argv[1], "kvm") == 0) hypervisor = KVM; else if (strcmp(argv[1], "ukvm") == 0) hypervisor = UKVM; else if (strcmp(argv[1], "unix") == 0) hypervisor = UNIX; else { warnx("error: Invalid hypervisor: %s", argv[1]); return 1; } unikernel = argv[2]; /* * Remaining arguments are to be passed on to the unikernel. */ argv += 3; argc -= 3; /* * Check we have CAP_NET_ADMIN. */ if (capng_get_caps_process() != 0) { warnx("error: capng_get_caps_process() failed"); return 1; } if (!capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_ADMIN)) { warnx("error: CAP_NET_ADMIN is required"); return 1; } /* * Connect to netlink, load link cache from kernel. */ struct nl_sock *sk; struct nl_cache *link_cache; int err; sk = nl_socket_alloc(); assert(sk); err = nl_connect(sk, NETLINK_ROUTE); if (err < 0) { warnx("nl_connect() failed: %s", nl_geterror(err)); return 1; } err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache); if (err < 0) { warnx("rtnl_link_alloc_cache() failed: %s", nl_geterror(err)); return 1; } /* * Retrieve container network configuration -- IP address and * default gateway. */ struct rtnl_link *l_veth; l_veth = rtnl_link_get_by_name(link_cache, VETH_LINK_NAME); if (l_veth == NULL) { warnx("error: Could not get link information for %s", VETH_LINK_NAME); return 1; } struct nl_addr *veth_addr; err = get_link_inet_addr(sk, l_veth, &veth_addr); if (err) { warnx("error: Unable to determine IP address of %s", VETH_LINK_NAME); return 1; } struct nl_addr *gw_addr; err = get_default_gw_inet_addr(sk, &gw_addr); if (err) { warnx("error: get_deGfault_gw_inet_addr() failed"); return 1; } if (gw_addr == NULL) { warnx("error: No default gateway found. This is currently " "not supported"); return 1; } /* * Create bridge and tap interface, enslave veth and tap interfaces to * bridge. */ err = create_bridge_link(sk, BRIDGE_LINK_NAME); if (err < 0) { warnx("create_bridge_link(%s) failed: %s", BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } int tap_fd; if (hypervisor == UKVM) err = create_tap_link(TAP_LINK_NAME, &tap_fd); else err = create_tap_link(TAP_LINK_NAME, NULL); if (err != 0) { warnx("create_tap_link(%s) failed: %s", TAP_LINK_NAME, strerror(err)); return 1; } /* Refill link cache with newly-created interfaces */ nl_cache_refill(sk, link_cache); struct rtnl_link *l_bridge; l_bridge = rtnl_link_get_by_name(link_cache, BRIDGE_LINK_NAME); if (l_bridge == NULL) { warnx("error: Could not get link information for %s", BRIDGE_LINK_NAME); return 1; } struct rtnl_link *l_tap; l_tap = rtnl_link_get_by_name(link_cache, TAP_LINK_NAME); if (l_tap == NULL) { warnx("error: Could not get link information for %s", TAP_LINK_NAME); return 1; } err = rtnl_link_enslave(sk, l_bridge, l_veth); if (err < 0) { warnx("error: Unable to enslave %s to %s: %s", VETH_LINK_NAME, BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } err = rtnl_link_enslave(sk, l_bridge, l_tap); if (err < 0) { warnx("error: Unable to enslave %s to %s: %s", TAP_LINK_NAME, BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } /* * Flush all IPv4 addresses from the veth interface. This is now safe * as we are good to commit and have retrieved the existing configuration. */ struct rtnl_addr *flush_addr; flush_addr = rtnl_addr_alloc(); assert(flush_addr); rtnl_addr_set_ifindex(flush_addr, rtnl_link_get_ifindex(l_veth)); rtnl_addr_set_family(flush_addr, AF_INET); rtnl_addr_set_local(flush_addr, veth_addr); err = rtnl_addr_delete(sk, flush_addr, 0); if (err < 0) { warnx("error: Could not flush addresses on %s: %s", VETH_LINK_NAME, nl_geterror(err)); return 1; } rtnl_addr_put(flush_addr); /* * Bring up the tap and bridge interfaces. */ struct rtnl_link *l_up; l_up = rtnl_link_alloc(); assert(l_up); /* You'd think set_operstate was the thing to do here. It's not. */ rtnl_link_set_flags(l_up, IFF_UP); err = rtnl_link_change(sk, l_tap, l_up, 0); if (err < 0) { warnx("error: rtnl_link_change(%s, UP) failed: %s", TAP_LINK_NAME, nl_geterror(err)); return 1; } err = rtnl_link_change(sk, l_bridge, l_up, 0); if (err < 0) { warnx("error: rtnl_link_change(%s, UP) failed: %s", BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } rtnl_link_put(l_up); /* * Collect network configuration data. */ char ip[AF_INET_BUFSIZE]; if (inet_ntop(AF_INET, nl_addr_get_binary_addr(veth_addr), ip, sizeof ip) == NULL) { perror("inet_ntop()"); return 1; } char uarg_ip[AF_INET_BUFSIZE]; unsigned int prefixlen = nl_addr_get_prefixlen(veth_addr); snprintf(uarg_ip, sizeof uarg_ip, "%s/%u", ip, prefixlen); char uarg_gw[AF_INET_BUFSIZE]; if (inet_ntop(AF_INET, nl_addr_get_binary_addr(gw_addr), uarg_gw, sizeof uarg_gw) == NULL) { perror("inet_ntop()"); return 1; } /* * Build unikernel and hypervisor arguments. */ ptrvec* uargpv = pvnew(); char *uarg_buf; /* * QEMU/KVM: * /usr/bin/qemu-system-x86_64 <qemu args> -kernel <unikernel> -append "<unikernel args>" */ if (hypervisor == QEMU || hypervisor == KVM) { pvadd(uargpv, "/usr/bin/qemu-system-x86_64"); pvadd(uargpv, "-nodefaults"); pvadd(uargpv, "-no-acpi"); pvadd(uargpv, "-display"); pvadd(uargpv, "none"); pvadd(uargpv, "-serial"); pvadd(uargpv, "stdio"); pvadd(uargpv, "-m"); pvadd(uargpv, "512"); if (hypervisor == KVM) { pvadd(uargpv, "-enable-kvm"); pvadd(uargpv, "-cpu"); pvadd(uargpv, "host"); } else { /* * Required for AESNI use in Mirage. */ pvadd(uargpv, "-cpu"); pvadd(uargpv, "Westmere"); } pvadd(uargpv, "-device"); char *guest_mac = generate_mac(); assert(guest_mac); err = asprintf(&uarg_buf, "virtio-net-pci,netdev=n0,mac=%s", guest_mac); assert(err != -1); pvadd(uargpv, uarg_buf); pvadd(uargpv, "-netdev"); err = asprintf(&uarg_buf, "tap,id=n0,ifname=%s,script=no,downscript=no", TAP_LINK_NAME); assert(err != -1); pvadd(uargpv, uarg_buf); pvadd(uargpv, "-kernel"); pvadd(uargpv, unikernel); pvadd(uargpv, "-append"); /* * TODO: Replace any occurences of ',' with ',,' in -append, because * QEMU arguments are insane. */ char cmdline[1024]; char *cmdline_p = cmdline; size_t cmdline_free = sizeof cmdline; for (; *argv; argc--, argv++) { size_t alen = snprintf(cmdline_p, cmdline_free, "%s%s", *argv, (argc > 1) ? " " : ""); if (alen >= cmdline_free) { warnx("error: Command line too long"); return 1; } cmdline_free -= alen; cmdline_p += alen; } size_t alen = snprintf(cmdline_p, cmdline_free, "--ipv4=%s --ipv4-gateway=%s", uarg_ip, uarg_gw); if (alen >= cmdline_free) { warnx("error: Command line too long"); return 1; } pvadd(uargpv, cmdline); } /* * UKVM: * /unikernel/ukvm <ukvm args> <unikernel> -- <unikernel args> */ else if (hypervisor == UKVM) { pvadd(uargpv, "/unikernel/ukvm"); err = asprintf(&uarg_buf, "--net=@%d", tap_fd); assert(err != -1); pvadd(uargpv, uarg_buf); pvadd(uargpv, "--"); pvadd(uargpv, unikernel); for (; *argv; argc--, argv++) { pvadd(uargpv, *argv); } err = asprintf(&uarg_buf, "--ipv4=%s", uarg_ip); assert(err != -1); pvadd(uargpv, uarg_buf); err = asprintf(&uarg_buf, "--ipv4-gateway=%s", uarg_gw); assert(err != -1); pvadd(uargpv, uarg_buf); } /* * UNIX: * <unikernel> <unikernel args> */ else if (hypervisor == UNIX) { pvadd(uargpv, unikernel); err = asprintf(&uarg_buf, "--interface=%s", TAP_LINK_NAME); assert(err != -1); pvadd(uargpv, uarg_buf); for (; *argv; argc--, argv++) { pvadd(uargpv, *argv); } err = asprintf(&uarg_buf, "--ipv4=%s", uarg_ip); assert(err != -1); pvadd(uargpv, uarg_buf); err = asprintf(&uarg_buf, "--ipv4-gateway=%s", uarg_gw); assert(err != -1); pvadd(uargpv, uarg_buf); } char **uargv = (char **)pvfinal(uargpv); /* * Done with netlink, free all resources and close socket. */ rtnl_link_put(l_veth); rtnl_link_put(l_bridge); rtnl_link_put(l_tap); nl_addr_put(veth_addr); nl_addr_put(gw_addr); nl_cache_free(link_cache); nl_close(sk); nl_socket_free(sk); /* * Drop all capabilities except CAP_NET_BIND_SERVICE. */ capng_clear(CAPNG_SELECT_BOTH); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED | CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); if (capng_apply(CAPNG_SELECT_BOTH) != 0) { warnx("error: Could not drop capabilities"); return 1; } /* * Run the unikernel. */ err = execv(uargv[0], uargv); warn("error: execv() of %s failed", uargv[0]); return 1; }
static void bump_cap(unsigned int cap) { if (capng_have_capability(CAPNG_PERMITTED, cap)) capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, cap); }
/*! * \brief Thread entrypoint function. * * When a thread is created and started, it immediately enters this function. * Depending on thread state, it either enters runnable or * blocks until it is awakened. * * This function also handles "ThreadIdle" state to quickly suspend and resume * threads and mitigate thread creation costs. Also, thread runnable may * be changed to alter the thread behavior on runtime */ static void *thread_ep(void *data) { // Check data dthread_t *thread = (dthread_t *)data; if (thread == 0) { return 0; } // Check if is a member of unit dt_unit_t *unit = thread->unit; if (unit == 0) { return 0; } // Unblock SIGALRM sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGALRM); pthread_sigmask(SIG_UNBLOCK, &mask, NULL); rcu_register_thread(); dbg_dt("dthreads: [%p] entered ep\n", thread); /* Drop capabilities except FS access. */ #ifdef HAVE_CAP_NG_H if (capng_have_capability(CAPNG_EFFECTIVE, CAP_SETPCAP)) { capng_type_t tp = CAPNG_EFFECTIVE|CAPNG_PERMITTED; capng_clear(CAPNG_SELECT_BOTH); capng_update(CAPNG_ADD, tp, CAP_DAC_OVERRIDE); capng_apply(CAPNG_SELECT_BOTH); } #endif /* HAVE_CAP_NG_H */ // Run loop for (;;) { // Check thread state lock_thread_rw(thread); if (thread->state == ThreadDead) { dbg_dt("dthreads: [%p] marked as dead\n", thread); unlock_thread_rw(thread); break; } // Update data thread->data = thread->_adata; runnable_t _run = thread->run; // Start runnable if thread is marked Active if ((thread->state == ThreadActive) && (thread->run != 0)) { unlock_thread_rw(thread); dbg_dt("dthreads: [%p] entering runnable\n", thread); _run(thread); dbg_dt("dthreads: [%p] exited runnable\n", thread); } else { unlock_thread_rw(thread); } // If the runnable was cancelled, start new iteration lock_thread_rw(thread); if (thread->state & ThreadCancelled) { dbg_dt("dthreads: [%p] cancelled\n", thread); thread->state &= ~ThreadCancelled; unlock_thread_rw(thread); continue; } unlock_thread_rw(thread); // Runnable finished without interruption, mark as Idle pthread_mutex_lock(&unit->_notify_mx); lock_thread_rw(thread); if (thread->state & ThreadActive) { thread->state &= ~ThreadActive; thread->state |= ThreadIdle; } // Go to sleep if idle if (thread->state & ThreadIdle) { unlock_thread_rw(thread); // Signalize state change unit_signalize_change(unit); // Wait for notification from unit dbg_dt("dthreads: [%p] going idle\n", thread); pthread_cond_wait(&unit->_notify, &unit->_notify_mx); pthread_mutex_unlock(&unit->_notify_mx); dbg_dt("dthreads: [%p] resumed from idle\n", thread); } else { unlock_thread_rw(thread); pthread_mutex_unlock(&unit->_notify_mx); } } // Thread destructor if (thread->destruct) { dbg_dt("dthreads: [%p] entering destructor\n", thread); thread->destruct(thread); dbg_dt("dthreads: [%p] exited destructor\n", thread); } // Report thread state change dbg_dt("dthreads: [%p] thread finished\n", thread); unit_signalize_change(unit); dbg_dt("dthreads: [%p] thread exited ep\n", thread); lock_thread_rw(thread); thread->state |= ThreadJoinable; unlock_thread_rw(thread); rcu_unregister_thread(); // Return return 0; }
/** * Changes the user and group the bus is running as. * * @param user the user to become * @param error return location for errors * @returns #FALSE on failure */ dbus_bool_t _dbus_change_to_daemon_user (const char *user, DBusError *error) { dbus_uid_t uid; dbus_gid_t gid; DBusString u; _dbus_string_init_const (&u, user); if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) { dbus_set_error (error, DBUS_ERROR_FAILED, "User '%s' does not appear to exist?", user); return FALSE; } /* If we were root */ if (_dbus_geteuid () == 0) { int rc; int have_audit_write; have_audit_write = capng_have_capability (CAPNG_PERMITTED, CAP_AUDIT_WRITE); capng_clear (CAPNG_SELECT_BOTH); /* Only attempt to retain CAP_AUDIT_WRITE if we had it when * starting. See: * https://bugs.freedesktop.org/show_bug.cgi?id=49062#c9 */ if (have_audit_write) capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, CAP_AUDIT_WRITE); rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP); if (rc) { switch (rc) { default: dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to drop capabilities: %s\n", _dbus_strerror (errno)); break; case -4: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set GID to %lu: %s", gid, _dbus_strerror (errno)); break; case -5: _dbus_warn ("Failed to drop supplementary groups: %s\n", _dbus_strerror (errno)); break; case -6: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to set UID to %lu: %s", uid, _dbus_strerror (errno)); break; case -7: dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to unset keep-capabilities: %s\n", _dbus_strerror (errno)); break; } return FALSE; } } return TRUE; }
int main(int argc, char *argv[]) { int which = 0, i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--text") == 0) text = 1; else if (strcmp(argv[i], "--no-child") == 0) no_child = 1; else if (strcmp(argv[i], "--lock") == 0) lock = 1; else if (strcmp(argv[i], "--drop-all") == 0) which = 1; else if (strcmp(argv[i], "--drop-caps") == 0) which = 2; else if (strcmp(argv[i], "--id") == 0) which = 3; else if (strcmp(argv[i], "--init-grp") == 0) which = 4; else { usage(); return 0; } } switch (which) { case 1: capng_clear(CAPNG_SELECT_BOTH); if (lock) capng_lock(); capng_apply(CAPNG_SELECT_BOTH); report(); break; case 2: capng_clear(CAPNG_SELECT_CAPS); if (lock) capng_lock(); capng_apply(CAPNG_SELECT_CAPS); report(); break; case 3: case 4: { int rc; capng_clear(CAPNG_SELECT_BOTH); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_CHOWN); if (which == 4) rc = capng_change_id(99, 99, CAPNG_INIT_SUPP_GRP | CAPNG_CLEAR_BOUNDING); else rc = capng_change_id(99, 99, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING); if (rc < 0) { printf("Error changing uid: %d\n", rc); capng_print_caps_text(CAPNG_PRINT_STDOUT, CAPNG_EFFECTIVE); printf("\n"); exit(1); } printf("Keeping CAP_CHOWN to show capabilities across uid change.\n"); report(); } break; case 0: if (lock) capng_lock(); report(); break; } return 0; }
int main(void) { int rc, i, len, last = get_last_cap(); char *text; void *saved; puts("Doing basic bit tests..."); capng_clear(CAPNG_SELECT_BOTH); if (capng_have_capabilities(CAPNG_SELECT_BOTH) != CAPNG_NONE) { puts("Failed clearing capabilities"); abort(); } saved = capng_save_state(); capng_fill(CAPNG_SELECT_BOTH); if (capng_have_capabilities(CAPNG_SELECT_BOTH) != CAPNG_FULL) { puts("Failed filling capabilities"); abort(); } // Need to detect if version 1 or 2 capabilities text = capng_print_caps_numeric(CAPNG_PRINT_BUFFER, CAPNG_SELECT_CAPS); len = strlen(text); free(text); if (len < 80 && last > 30) // The kernel & headers are mismatched last = 30; // Now test that restore still works capng_restore_state(&saved); if (capng_have_capabilities(CAPNG_SELECT_BOTH) != CAPNG_NONE) { puts("Failed restoring capabilities"); abort(); } printf("Doing advanced bit tests for %d capabilities...\n", last); for (i=0; i<=last; i++) { const char *name; capng_clear(CAPNG_SELECT_BOTH); rc = capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i); if (rc) { puts("Failed update test 1"); abort(); } rc = capng_have_capability(CAPNG_EFFECTIVE, i); if (rc == 0) { puts("Failed have capability test 1"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_CAPS); abort(); } if(capng_have_capabilities(CAPNG_SELECT_CAPS)!=CAPNG_PARTIAL){ puts("Failed have capabilities test 1"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_CAPS); abort(); } #if CAP_LAST_CAP > 31 rc = capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i); if (rc) { puts("Failed bset update test 2"); abort(); } rc = capng_have_capability(CAPNG_BOUNDING_SET, i); if (rc == 0) { puts("Failed bset have capability test 2"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_BOTH); abort(); } if(capng_have_capabilities(CAPNG_SELECT_BOUNDS)!=CAPNG_PARTIAL){ puts("Failed bset have capabilities test 2"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_BOTH); abort(); } #endif text=capng_print_caps_text(CAPNG_PRINT_BUFFER, CAPNG_EFFECTIVE); if (text == NULL) { puts("Failed getting print text to buffer"); abort(); } name = capng_capability_to_name(i); if (name == NULL) { printf("Failed converting capability %d to name\n", i); abort(); } if (strcmp(text, name)) { puts("Failed print text comparison"); printf("%s != %s\n", text, name); abort(); } free(text); // Now make sure the mask part is working capng_fill(CAPNG_SELECT_BOTH); rc = capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, i); if (rc) { puts("Failed update test 3"); abort(); } // Should be partial if(capng_have_capabilities(CAPNG_SELECT_CAPS)!=CAPNG_PARTIAL){ puts("Failed have capabilities test 3"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_CAPS); abort(); } // Add back the bit and should be full capabilities rc = capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i); if (rc) { puts("Failed update test 4"); abort(); } if (capng_have_capabilities(CAPNG_SELECT_CAPS) != CAPNG_FULL){ puts("Failed have capabilities test 4"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_CAPS); abort(); } } // Now test the updatev function capng_clear(CAPNG_SELECT_BOTH); rc = capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_CHOWN, CAP_FOWNER, CAP_KILL, -1); if (rc) { puts("Failed updatev test"); abort(); } rc = capng_have_capability(CAPNG_EFFECTIVE, CAP_CHOWN) && capng_have_capability(CAPNG_EFFECTIVE, CAP_FOWNER) && capng_have_capability(CAPNG_EFFECTIVE, CAP_KILL); if (rc == 0) { puts("Failed have updatev capability test"); capng_print_caps_numeric(CAPNG_PRINT_STDOUT, CAPNG_SELECT_CAPS); abort(); } return EXIT_SUCCESS; }