lkml.org 
[lkml]   [2005]   [Mar]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
SubjectCapabilities across execve
From
Date
This makes it possible for a root-task to pass capabilities to
nonroot-task across execve. The root-task needs to change it's
cap_inheritable mask and set prctl(PR_SET_KEEPCAPS, 1) to pass on
capabilities.
At execve time the capabilities will be passed on to the new
nonroot-task and any non-inheritable effective and permitted
capabilities will be masked out.
The effective capability of the new nonroot-task will be set to the
maximum permitted.

>From here on the inheritable mask will be passed on unchanged to the new
tasks children unless told otherwise (effectively the complete
capability state is passed on).

With a small insert of prctl(PR_SET_KEEPCAPS, 1) into pam_cap.c at the
correct place this makes pam_cap work as expected. I'm also attaching a
test-case that tests capabilities across setuid => execve (makes the new
task inherit CAP_CHOWN).


Signed-off-by: Alexander Nyberg <alexn@dsv.su.se>

===== security/commoncap.c 1.15 vs edited =====
--- 1.15/security/commoncap.c 2005-01-11 02:29:23 +01:00
+++ edited/security/commoncap.c 2005-03-12 12:04:34 +01:00
@@ -111,13 +111,19 @@ void cap_capset_set (struct task_struct

int cap_bprm_set_security (struct linux_binprm *bprm)
{
- /* Copied from fs/exec.c:prepare_binprm. */
-
- /* We don't have VFS support for capabilities yet */
- cap_clear (bprm->cap_inheritable);
- cap_clear (bprm->cap_permitted);
- cap_clear (bprm->cap_effective);
+ struct task_struct *p = current;

+ /*
+ * Mask out the non-inheritable capabilities.
+ * Note: init has a zero mask of cap_inheritable, so a root-task will not
+ * pass on any capabilities unless explicitly told to do so. If a non-zero
+ * inheritable mask is passed to a positive uid task it will then pass on
+ * its inheritable mask to all children unless told otherwise.
+ */
+ bprm->cap_permitted = cap_intersect(p->cap_permitted, p->cap_inheritable);
+ bprm->cap_effective = cap_intersect(p->cap_effective, p->cap_inheritable);
+ bprm->cap_inheritable = p->cap_inheritable;
+
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise all three
* capability sets for the file.
@@ -127,7 +133,7 @@ int cap_bprm_set_security (struct linux_
*/

if (!issecure (SECURE_NOROOT)) {
- if (bprm->e_uid == 0 || current->uid == 0) {
+ if (bprm->e_uid == 0 || p->uid == 0) {
cap_set_full (bprm->cap_inheritable);
cap_set_full (bprm->cap_permitted);
}
@@ -139,13 +145,9 @@ int cap_bprm_set_security (struct linux_

void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- /* Derived from fs/exec.c:compute_creds. */
- kernel_cap_t new_permitted, working;
+ kernel_cap_t new_permitted;

new_permitted = cap_intersect (bprm->cap_permitted, cap_bset);
- working = cap_intersect (bprm->cap_inheritable,
- current->cap_inheritable);
- new_permitted = cap_combine (new_permitted, working);

if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset (new_permitted, current->cap_permitted)) {
@@ -166,14 +168,9 @@ void cap_bprm_apply_creds (struct linux_
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;

- /* For init, we want to retain the capabilities set
- * in the init_task struct. Thus we skip the usual
- * capability rules */
- if (current->pid != 1) {
- current->cap_permitted = new_permitted;
- current->cap_effective =
- cap_intersect (new_permitted, bprm->cap_effective);
- }
+ current->cap_permitted = new_permitted;
+ current->cap_effective =
+ cap_intersect (new_permitted, bprm->cap_effective);

/* AUD: Audit candidate if current->cap_effective is set */

@@ -249,9 +246,9 @@ static inline void cap_emulate_setxuid (
cap_clear (current->cap_permitted);
cap_clear (current->cap_effective);
}
- if (old_euid == 0 && current->euid != 0) {
+ if (old_euid == 0 && current->euid != 0 && !current->keep_capabilities)
cap_clear (current->cap_effective);
- }
+
if (old_euid != 0 && current->euid == 0) {
current->cap_effective = current->cap_permitted;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/capability.h>
#include <sys/prctl.h>

struct caph {
int version;
int pid;
};

struct capd {
__u32 effective;
__u32 permitted;
__u32 inheritable;
};

gid_t gid = 1000;
uid_t uid = 1000;


void printcap(char *str)
{
int ret;
struct caph caph;
struct capd capd;

memset(&capd, 0, sizeof(capd));

caph.version = 0x19980330;
caph.pid = getpid();

ret = capget(&caph, &capd);
if (ret < 0)
perror("capget");
printf("%s: ", str);
printf("eff:%u perm:%u inh:%u\n", capd.effective, capd.permitted, capd.inheritable);
}

void lower_uid()
{
int ret;
gid_t gidlist[1];

gidlist[0] = gid;
ret = setgroups(1, gidlist);
if (ret < 0)
perror("setgroups");
if (setgid(gid))
perror("setgid");
if (setuid(uid))
perror("setuid");
}

const char *bash[] = { "bash", NULL };

int main(int argc, char **argv)
{
int ret;
struct caph caph;
struct capd capd;

if (argc == 3) {
uid = strtoul(argv[1], NULL, 0);
gid = strtoul(argv[2], NULL, 0);
} else {
printf("Usage: \"./program uid gid\" where uid & gid\n");
printf("are the ids you want to change to (then run bash)\n");
exit(1);
}

printcap("caps when started");

memset(&capd, 0, sizeof(capd));

caph.version = 0x19980330;
caph.pid = getpid();

ret = capget(&caph, &capd);
if (ret < 0)
perror("capget");

capd.inheritable |= (1 << CAP_CHOWN);

ret = capset(&caph, &capd);
if (ret < 0)
perror("capset");

printf("new inheritable mask: %u\n", capd.inheritable);

ret = prctl(PR_SET_KEEPCAPS, 1);
if (ret)
perror("prctl");

lower_uid();

printcap("after setuid");

ret = execv("/bin/bash", bash);
if (ret < 0)
perror("execve");

return 0;
}
\
 
 \ /
  Last update: 2005-03-22 14:11    [W:0.068 / U:0.404 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site