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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox