Committer: Mircea Gherzan <mircea.gherzan@xxxxxxxxxxxxxx> Date: 02/05/2010 at 03:51:51 Revision: 4448 Revision-id: mircea.gherzan@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Branch nick: trunk Log: Add kernel module unloading for PRIVSEP. This implies adding a new capability to the list. The removal function is now called at the end of the exit routine. Modified: M hipd/init.c M lib/core/hip_capability.c === modified file 'hipd/init.c' --- hipd/init.c 2010-04-29 09:26:03 +0000 +++ hipd/init.c 2010-05-02 00:49:12 +0000 @@ -11,10 +11,13 @@ #include <limits.h> #include <stdlib.h> +#include <string.h> #include <errno.h> -#include <sys/prctl.h> +//#include <sys/prctl.h> +#include <sys/syscall.h> #include <sys/types.h> #include <netinet/icmp6.h> +#include <linux/unistd.h> #include "config.h" #include "hipd.h" @@ -271,12 +274,12 @@ } /** CryptoAPI cipher and hashe modules */ -static char *kernel_crypto_mod[] = { +static const char *kernel_crypto_mod[] = { "crypto_null", "aes", "des" }; /** Tunneling, IPsec, interface and control modules */ -static char *kernel_net_mod[] = { +static const char *kernel_net_mod[] = { "xfrm4_mode_beet", "xfrm6_mode_beet", "ip4_tunnel", "ip6_tunnel", "esp4", "esp6", @@ -328,25 +331,59 @@ return 0; } +#if defined(CONFIG_HIP_PRIVSEP) || defined(CONFIG_HIP_ALTSEP) +/** + * Remove a single module from the kernel, rmmod style (not modprobe). + * @param name name of the module + * @return 0 on success, negative otherwise + */ +static inline int hip_rmmod(const char *name) +{ + return syscall(__NR_delete_module, name, O_NONBLOCK); +} + +#endif + /** * Cleanup/unload the kernel modules on hipd exit. * Unused for now because of unprivileged executions. * @todo Make hip_exit call it with root privileges in order to clean up. */ -static void __attribute__((unused)) hip_remove_kernel_modules(void) +static void hip_remove_kernel_modules(void) { - char **mods[] = {kernel_crypto_mod, kernel_net_mod}; + /* some net modules depend on crypto, so keep net modules first */ + const char **mods[] = {kernel_net_mod, kernel_crypto_mod}; + int count[2], type, i, ret; +#if ! (defined(CONFIG_HIP_PRIVSEP) || defined(CONFIG_HIP_ALTSEP)) char cmd[MODPROBE_MAX_LINE]; - int count[2], type, i; +#endif - count[0] = sizeof(kernel_crypto_mod) / sizeof(kernel_crypto_mod[0]); - count[1] = sizeof(kernel_net_mod) / sizeof(kernel_net_mod[0]); + count[0] = sizeof(kernel_net_mod) / sizeof(kernel_net_mod[0]); + count[1] = sizeof(kernel_crypto_mod) / sizeof(kernel_crypto_mod[0]); for (type = 0; type < 2; type++) { for (i = 0; i < count[type]; i++) { - snprintf(cmd, sizeof(cmd), "/sbin/modprobe -r %s", mods[type][i]); - if (system(cmd)) { - HIP_DEBUG("Unable to remove the %s module!\n", mods[type][i]); +#if defined(CONFIG_HIP_PRIVSEP) || defined(CONFIG_HIP_ALTSEP) + /* Although we still retain the CAP_SYS_MODULE capability, + * because of the new (post-2.6.24) rules governing capability + * inheritance (i.e. "permitted" and "effective") on execve + * we cannot call modprobe or rmmod, because their thread + * will run without CAP_SYS_MODULE and thus fail to do the job. + * Not as good as 'modprobe -r', but (way) better that nothing. + */ + ret = hip_rmmod(mods[type][i]); +#else + /* no privilege separation whatsoever, we are almighty */ + snprintf(cmd, sizeof(cmd), "/sbin/modprobe -r %s 2> /dev/null", + mods[type][i]); + ret = system(cmd); +#endif + if (ret) { + /* the errno is relevant in the hip_rmmod() case */ + HIP_DEBUG("Unable to remove the %s module: %s.\n", + mods[type][i], strerror(errno)); + } else { + HIP_DEBUG("Removed the %s module.\n", mods[type][i]); } } } @@ -800,7 +837,7 @@ hip_dht_queue_uninit(); - return; + hip_remove_kernel_modules(); } /** === modified file 'lib/core/hip_capability.c' --- lib/core/hip_capability.c 2010-05-01 22:29:58 +0000 +++ lib/core/hip_capability.c 2010-05-02 00:49:12 +0000 @@ -142,12 +142,15 @@ data.effective, data.permitted, data.inheritable); HIP_DEBUG("Going to clear all capabilities except the ones needed\n"); data.effective = data.permitted = data.inheritable = 0; - // for CAP_NET_RAW capability + /* for CAP_NET_RAW capability */ data.effective |= (1 << CAP_NET_RAW); data.permitted |= (1 << CAP_NET_RAW); - // for CAP_NET_ADMIN capability + /* for CAP_NET_ADMIN capability */ data.effective |= (1 << CAP_NET_ADMIN); data.permitted |= (1 << CAP_NET_ADMIN); + /* kernel module loading and removal capability */ + data.effective |= (1 << CAP_SYS_MODULE); + data.permitted |= (1 << CAP_SYS_MODULE); HIP_IFEL(hip_capset(&header, &data), -1, "error in capset (do you have capabilities kernel module?)"); @@ -159,8 +162,8 @@ #else /* ! ALTSEP */ - cap_value_t cap_list[] = {CAP_NET_RAW, CAP_NET_ADMIN }; - int ncap_list = 2; + cap_value_t cap_list[] = {CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_MODULE}; + int ncap_list = sizeof(cap_list) / sizeof(cap_list[0]); cap_t cap_p = NULL; char *cap_s = NULL; char *name = NULL;