aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-09-02 04:14:21 -0400
committerJames Morris <jmorris@namei.org>2009-09-02 07:29:22 -0400
commitee18d64c1f632043a02e6f5ba5e045bb26a5465f (patch)
tree80b5a4d530ec7d5fd69799920f0db7b78aba6b9d /security/selinux/hooks.c
parentd0420c83f39f79afb82010c2d2cafd150eef651b (diff)
KEYS: Add a keyctl to install a process's session keyring on its parent [try #6]
Add a keyctl to install a process's session keyring onto its parent. This replaces the parent's session keyring. Because the COW credential code does not permit one process to change another process's credentials directly, the change is deferred until userspace next starts executing again. Normally this will be after a wait*() syscall. To support this, three new security hooks have been provided: cred_alloc_blank() to allocate unset security creds, cred_transfer() to fill in the blank security creds and key_session_to_parent() - which asks the LSM if the process may replace its parent's session keyring. The replacement may only happen if the process has the same ownership details as its parent, and the process has LINK permission on the session keyring, and the session keyring is owned by the process, and the LSM permits it. Note that this requires alteration to each architecture's notify_resume path. This has been done for all arches barring blackfin, m68k* and xtensa, all of which need assembly alteration to support TIF_NOTIFY_RESUME. This allows the replacement to be performed at the point the parent process resumes userspace execution. This allows the userspace AFS pioctl emulation to fully emulate newpag() and the VIOCSETTOK and VIOCSETTOK2 pioctls, all of which require the ability to alter the parent process's PAG membership. However, since kAFS doesn't use PAGs per se, but rather dumps the keys into the session keyring, the session keyring of the parent must be replaced if, for example, VIOCSETTOK is passed the newpag flag. This can be tested with the following program: #include <stdio.h> #include <stdlib.h> #include <keyutils.h> #define KEYCTL_SESSION_TO_PARENT 18 #define OSERROR(X, S) do { if ((long)(X) == -1) { perror(S); exit(1); } } while(0) int main(int argc, char **argv) { key_serial_t keyring, key; long ret; keyring = keyctl_join_session_keyring(argv[1]); OSERROR(keyring, "keyctl_join_session_keyring"); key = add_key("user", "a", "b", 1, keyring); OSERROR(key, "add_key"); ret = keyctl(KEYCTL_SESSION_TO_PARENT); OSERROR(ret, "KEYCTL_SESSION_TO_PARENT"); return 0; } Compiled and linked with -lkeyutils, you should see something like: [dhowells@andromeda ~]$ keyctl show Session Keyring -3 --alswrv 4043 4043 keyring: _ses 355907932 --alswrv 4043 -1 \_ keyring: _uid.4043 [dhowells@andromeda ~]$ /tmp/newpag [dhowells@andromeda ~]$ keyctl show Session Keyring -3 --alswrv 4043 4043 keyring: _ses 1055658746 --alswrv 4043 4043 \_ user: a [dhowells@andromeda ~]$ /tmp/newpag hello [dhowells@andromeda ~]$ keyctl show Session Keyring -3 --alswrv 4043 4043 keyring: hello 340417692 --alswrv 4043 4043 \_ user: a Where the test program creates a new session keyring, sticks a user key named 'a' into it and then installs it on its parent. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index c3bb31ecc5aa..134a9c0d2004 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3233,6 +3233,21 @@ static int selinux_task_create(unsigned long clone_flags)
3233} 3233}
3234 3234
3235/* 3235/*
3236 * allocate the SELinux part of blank credentials
3237 */
3238static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3239{
3240 struct task_security_struct *tsec;
3241
3242 tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3243 if (!tsec)
3244 return -ENOMEM;
3245
3246 cred->security = tsec;
3247 return 0;
3248}
3249
3250/*
3236 * detach and free the LSM part of a set of credentials 3251 * detach and free the LSM part of a set of credentials
3237 */ 3252 */
3238static void selinux_cred_free(struct cred *cred) 3253static void selinux_cred_free(struct cred *cred)
@@ -3264,6 +3279,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3264} 3279}
3265 3280
3266/* 3281/*
3282 * transfer the SELinux data to a blank set of creds
3283 */
3284static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3285{
3286 const struct task_security_struct *old_tsec = old->security;
3287 struct task_security_struct *tsec = new->security;
3288
3289 *tsec = *old_tsec;
3290}
3291
3292/*
3267 * set the security data for a kernel service 3293 * set the security data for a kernel service
3268 * - all the creation contexts are set to unlabelled 3294 * - all the creation contexts are set to unlabelled
3269 */ 3295 */
@@ -5469,8 +5495,10 @@ static struct security_operations selinux_ops = {
5469 .dentry_open = selinux_dentry_open, 5495 .dentry_open = selinux_dentry_open,
5470 5496
5471 .task_create = selinux_task_create, 5497 .task_create = selinux_task_create,
5498 .cred_alloc_blank = selinux_cred_alloc_blank,
5472 .cred_free = selinux_cred_free, 5499 .cred_free = selinux_cred_free,
5473 .cred_prepare = selinux_cred_prepare, 5500 .cred_prepare = selinux_cred_prepare,
5501 .cred_transfer = selinux_cred_transfer,
5474 .kernel_act_as = selinux_kernel_act_as, 5502 .kernel_act_as = selinux_kernel_act_as,
5475 .kernel_create_files_as = selinux_kernel_create_files_as, 5503 .kernel_create_files_as = selinux_kernel_create_files_as,
5476 .kernel_module_request = selinux_kernel_module_request, 5504 .kernel_module_request = selinux_kernel_module_request,