From: Alexander Nyberg <alexn@dsv.su.se>
To: linux-kernel@vger.kernel.org
Cc: akpm@osdl.org
Subject: Capabilities across execve
Date: Sat, 12 Mar 2005 12:42:28 +0100 [thread overview]
Message-ID: <1110627748.2376.6.camel@boxen> (raw)
[-- Attachment #1: Type: text/plain, Size: 4121 bytes --]
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;
}
[-- Attachment #2: cap_test.c --]
[-- Type: text/x-csrc, Size: 1729 bytes --]
#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;
}
next reply other threads:[~2005-03-12 11:42 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-12 11:42 Alexander Nyberg [this message]
2005-03-13 3:21 ` Capabilities across execve Chris Wright
2005-03-15 14:46 ` Alexander Nyberg
2005-03-15 21:57 ` Russell King
2005-03-15 22:42 ` Chris Wright
2005-03-15 23:41 ` Alexander Nyberg
2005-03-15 23:58 ` Chris Wright
2005-03-16 0:34 ` Alexander Nyberg
2005-03-19 0:02 ` Olaf Dietsche
2005-03-13 18:32 ` Pavel Machek
-- strict thread matches above, loose matches on Subject: below --
2005-03-16 0:04 Albert Cahalan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1110627748.2376.6.camel@boxen \
--to=alexn@dsv.su.se \
--cc=akpm@osdl.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.