Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Howells and committed by
James Morris
ee18d64c d0420c83

+409
+20
Documentation/keys.txt
··· 757 757 successful. 758 758 759 759 760 + (*) Install the calling process's session keyring on its parent. 761 + 762 + long keyctl(KEYCTL_SESSION_TO_PARENT); 763 + 764 + This functions attempts to install the calling process's session keyring 765 + on to the calling process's parent, replacing the parent's current session 766 + keyring. 767 + 768 + The calling process must have the same ownership as its parent, the 769 + keyring must have the same ownership as the calling process, the calling 770 + process must have LINK permission on the keyring and the active LSM module 771 + mustn't deny permission, otherwise error EPERM will be returned. 772 + 773 + Error ENOMEM will be returned if there was insufficient memory to complete 774 + the operation, otherwise 0 will be returned to indicate success. 775 + 776 + The keyring will be replaced next time the parent process leaves the 777 + kernel and resumes executing userspace. 778 + 779 + 760 780 =============== 761 781 KERNEL SERVICES 762 782 ===============
+2
arch/alpha/kernel/signal.c
··· 687 687 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 688 688 clear_thread_flag(TIF_NOTIFY_RESUME); 689 689 tracehook_notify_resume(regs); 690 + if (current->replacement_session_keyring) 691 + key_replace_session_keyring(); 690 692 } 691 693 }
+2
arch/arm/kernel/signal.c
··· 711 711 if (thread_flags & _TIF_NOTIFY_RESUME) { 712 712 clear_thread_flag(TIF_NOTIFY_RESUME); 713 713 tracehook_notify_resume(regs); 714 + if (current->replacement_session_keyring) 715 + key_replace_session_keyring(); 714 716 } 715 717 }
+2
arch/avr32/kernel/signal.c
··· 326 326 if (ti->flags & _TIF_NOTIFY_RESUME) { 327 327 clear_thread_flag(TIF_NOTIFY_RESUME); 328 328 tracehook_notify_resume(regs); 329 + if (current->replacement_session_keyring) 330 + key_replace_session_keyring(); 329 331 } 330 332 }
+2
arch/cris/kernel/ptrace.c
··· 40 40 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 41 41 clear_thread_flag(TIF_NOTIFY_RESUME); 42 42 tracehook_notify_resume(regs); 43 + if (current->replacement_session_keyring) 44 + key_replace_session_keyring(); 43 45 } 44 46 }
+2
arch/frv/kernel/signal.c
··· 572 572 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 573 573 clear_thread_flag(TIF_NOTIFY_RESUME); 574 574 tracehook_notify_resume(__frame); 575 + if (current->replacement_session_keyring) 576 + key_replace_session_keyring(); 575 577 } 576 578 577 579 } /* end do_notify_resume() */
+2
arch/h8300/kernel/signal.c
··· 556 556 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 557 557 clear_thread_flag(TIF_NOTIFY_RESUME); 558 558 tracehook_notify_resume(regs); 559 + if (current->replacement_session_keyring) 560 + key_replace_session_keyring(); 559 561 } 560 562 }
+2
arch/ia64/kernel/process.c
··· 192 192 if (test_thread_flag(TIF_NOTIFY_RESUME)) { 193 193 clear_thread_flag(TIF_NOTIFY_RESUME); 194 194 tracehook_notify_resume(&scr->pt); 195 + if (current->replacement_session_keyring) 196 + key_replace_session_keyring(); 195 197 } 196 198 197 199 /* copy user rbs to kernel rbs */
+2
arch/m32r/kernel/signal.c
··· 411 411 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 412 412 clear_thread_flag(TIF_NOTIFY_RESUME); 413 413 tracehook_notify_resume(regs); 414 + if (current->replacement_session_keyring) 415 + key_replace_session_keyring(); 414 416 } 415 417 416 418 clear_thread_flag(TIF_IRET);
+2
arch/mips/kernel/signal.c
··· 704 704 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 705 705 clear_thread_flag(TIF_NOTIFY_RESUME); 706 706 tracehook_notify_resume(regs); 707 + if (current->replacement_session_keyring) 708 + key_replace_session_keyring(); 707 709 } 708 710 }
+2
arch/mn10300/kernel/signal.c
··· 568 568 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 569 569 clear_thread_flag(TIF_NOTIFY_RESUME); 570 570 tracehook_notify_resume(__frame); 571 + if (current->replacement_session_keyring) 572 + key_replace_session_keyring(); 571 573 } 572 574 }
+2
arch/parisc/kernel/signal.c
··· 649 649 if (test_thread_flag(TIF_NOTIFY_RESUME)) { 650 650 clear_thread_flag(TIF_NOTIFY_RESUME); 651 651 tracehook_notify_resume(regs); 652 + if (current->replacement_session_keyring) 653 + key_replace_session_keyring(); 652 654 } 653 655 }
+2
arch/s390/kernel/signal.c
··· 536 536 { 537 537 clear_thread_flag(TIF_NOTIFY_RESUME); 538 538 tracehook_notify_resume(regs); 539 + if (current->replacement_session_keyring) 540 + key_replace_session_keyring(); 539 541 }
+2
arch/sh/kernel/signal_32.c
··· 640 640 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 641 641 clear_thread_flag(TIF_NOTIFY_RESUME); 642 642 tracehook_notify_resume(regs); 643 + if (current->replacement_session_keyring) 644 + key_replace_session_keyring(); 643 645 } 644 646 }
+2
arch/sh/kernel/signal_64.c
··· 772 772 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 773 773 clear_thread_flag(TIF_NOTIFY_RESUME); 774 774 tracehook_notify_resume(regs); 775 + if (current->replacement_session_keyring) 776 + key_replace_session_keyring(); 775 777 } 776 778 }
+2
arch/sparc/kernel/signal_32.c
··· 590 590 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 591 591 clear_thread_flag(TIF_NOTIFY_RESUME); 592 592 tracehook_notify_resume(regs); 593 + if (current->replacement_session_keyring) 594 + key_replace_session_keyring(); 593 595 } 594 596 } 595 597
+3
arch/sparc/kernel/signal_64.c
··· 613 613 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 614 614 clear_thread_flag(TIF_NOTIFY_RESUME); 615 615 tracehook_notify_resume(regs); 616 + if (current->replacement_session_keyring) 617 + key_replace_session_keyring(); 616 618 } 617 619 } 620 +
+2
arch/x86/kernel/signal.c
··· 869 869 if (thread_info_flags & _TIF_NOTIFY_RESUME) { 870 870 clear_thread_flag(TIF_NOTIFY_RESUME); 871 871 tracehook_notify_resume(regs); 872 + if (current->replacement_session_keyring) 873 + key_replace_session_keyring(); 872 874 } 873 875 874 876 #ifdef CONFIG_X86_32
+1
include/linux/cred.h
··· 152 152 extern void __put_cred(struct cred *); 153 153 extern void exit_creds(struct task_struct *); 154 154 extern int copy_creds(struct task_struct *, unsigned long); 155 + extern struct cred *cred_alloc_blank(void); 155 156 extern struct cred *prepare_creds(void); 156 157 extern struct cred *prepare_exec_creds(void); 157 158 extern struct cred *prepare_usermodehelper_creds(void);
+3
include/linux/key.h
··· 278 278 extern ctl_table key_sysctls[]; 279 279 #endif 280 280 281 + extern void key_replace_session_keyring(void); 282 + 281 283 /* 282 284 * the userspace interface 283 285 */ ··· 302 300 #define key_fsuid_changed(t) do { } while(0) 303 301 #define key_fsgid_changed(t) do { } while(0) 304 302 #define key_init() do { } while(0) 303 + #define key_replace_session_keyring() do { } while(0) 305 304 306 305 #endif /* CONFIG_KEYS */ 307 306 #endif /* __KERNEL__ */
+1
include/linux/keyctl.h
··· 52 52 #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ 53 53 #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ 54 54 #define KEYCTL_GET_SECURITY 17 /* get key security label */ 55 + #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ 55 56 56 57 #endif /* _LINUX_KEYCTL_H */
+1
include/linux/sched.h
··· 1292 1292 struct mutex cred_guard_mutex; /* guard against foreign influences on 1293 1293 * credential calculations 1294 1294 * (notably. ptrace) */ 1295 + struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */ 1295 1296 1296 1297 char comm[TASK_COMM_LEN]; /* executable name excluding path 1297 1298 - access with [gs]et_task_comm (which lock
+38
include/linux/security.h
··· 653 653 * manual page for definitions of the @clone_flags. 654 654 * @clone_flags contains the flags indicating what should be shared. 655 655 * Return 0 if permission is granted. 656 + * @cred_alloc_blank: 657 + * @cred points to the credentials. 658 + * @gfp indicates the atomicity of any memory allocations. 659 + * Only allocate sufficient memory and attach to @cred such that 660 + * cred_transfer() will not get ENOMEM. 656 661 * @cred_free: 657 662 * @cred points to the credentials. 658 663 * Deallocate and clear the cred->security field in a set of credentials. ··· 670 665 * @new points to the new credentials. 671 666 * @old points to the original credentials. 672 667 * Install a new set of credentials. 668 + * @cred_transfer: 669 + * @new points to the new credentials. 670 + * @old points to the original credentials. 671 + * Transfer data from original creds to new creds 673 672 * @kernel_act_as: 674 673 * Set the credentials for a kernel service to act as (subjective context). 675 674 * @new points to the credentials to be modified. ··· 1112 1103 * Return the length of the string (including terminating NUL) or -ve if 1113 1104 * an error. 1114 1105 * May also return 0 (and a NULL buffer pointer) if there is no label. 1106 + * @key_session_to_parent: 1107 + * Forcibly assign the session keyring from a process to its parent 1108 + * process. 1109 + * @cred: Pointer to process's credentials 1110 + * @parent_cred: Pointer to parent process's credentials 1111 + * @keyring: Proposed new session keyring 1112 + * Return 0 if permission is granted, -ve error otherwise. 1115 1113 * 1116 1114 * Security hooks affecting all System V IPC operations. 1117 1115 * ··· 1514 1498 int (*dentry_open) (struct file *file, const struct cred *cred); 1515 1499 1516 1500 int (*task_create) (unsigned long clone_flags); 1501 + int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp); 1517 1502 void (*cred_free) (struct cred *cred); 1518 1503 int (*cred_prepare)(struct cred *new, const struct cred *old, 1519 1504 gfp_t gfp); 1520 1505 void (*cred_commit)(struct cred *new, const struct cred *old); 1506 + void (*cred_transfer)(struct cred *new, const struct cred *old); 1521 1507 int (*kernel_act_as)(struct cred *new, u32 secid); 1522 1508 int (*kernel_create_files_as)(struct cred *new, struct inode *inode); 1523 1509 int (*kernel_module_request)(void); ··· 1657 1639 const struct cred *cred, 1658 1640 key_perm_t perm); 1659 1641 int (*key_getsecurity)(struct key *key, char **_buffer); 1642 + int (*key_session_to_parent)(const struct cred *cred, 1643 + const struct cred *parent_cred, 1644 + struct key *key); 1660 1645 #endif /* CONFIG_KEYS */ 1661 1646 1662 1647 #ifdef CONFIG_AUDIT ··· 1776 1755 int security_file_receive(struct file *file); 1777 1756 int security_dentry_open(struct file *file, const struct cred *cred); 1778 1757 int security_task_create(unsigned long clone_flags); 1758 + int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); 1779 1759 void security_cred_free(struct cred *cred); 1780 1760 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); 1781 1761 void security_commit_creds(struct cred *new, const struct cred *old); 1762 + void security_transfer_creds(struct cred *new, const struct cred *old); 1782 1763 int security_kernel_act_as(struct cred *new, u32 secid); 1783 1764 int security_kernel_create_files_as(struct cred *new, struct inode *inode); 1784 1765 int security_kernel_module_request(void); ··· 2309 2286 return 0; 2310 2287 } 2311 2288 2289 + static inline void security_cred_alloc_blank(struct cred *cred, gfp_t gfp) 2290 + { } 2291 + 2312 2292 static inline void security_cred_free(struct cred *cred) 2313 2293 { } 2314 2294 ··· 2324 2298 2325 2299 static inline void security_commit_creds(struct cred *new, 2326 2300 const struct cred *old) 2301 + { 2302 + } 2303 + 2304 + static inline void security_transfer_creds(struct cred *new, 2305 + const struct cred *old) 2327 2306 { 2328 2307 } 2329 2308 ··· 2954 2923 int security_key_permission(key_ref_t key_ref, 2955 2924 const struct cred *cred, key_perm_t perm); 2956 2925 int security_key_getsecurity(struct key *key, char **_buffer); 2926 + int security_key_session_to_parent(const struct cred *cred, 2927 + const struct cred *parent_cred, 2928 + struct key *key); 2957 2929 2958 2930 #else 2959 2931 ··· 2983 2949 *_buffer = NULL; 2984 2950 return 0; 2985 2951 } 2952 + 2953 + static inline int security_key_session_to_parent(const struct cred *cred, 2954 + const struct cred *parent_cred, 2955 + struct key *key); 2986 2956 2987 2957 #endif 2988 2958 #endif /* CONFIG_KEYS */
+43
kernel/cred.c
··· 199 199 validate_creds(cred); 200 200 alter_cred_subscribers(cred, -1); 201 201 put_cred(cred); 202 + 203 + cred = (struct cred *) tsk->replacement_session_keyring; 204 + if (cred) { 205 + tsk->replacement_session_keyring = NULL; 206 + validate_creds(cred); 207 + put_cred(cred); 208 + } 209 + } 210 + 211 + /* 212 + * Allocate blank credentials, such that the credentials can be filled in at a 213 + * later date without risk of ENOMEM. 214 + */ 215 + struct cred *cred_alloc_blank(void) 216 + { 217 + struct cred *new; 218 + 219 + new = kmem_cache_zalloc(cred_jar, GFP_KERNEL); 220 + if (!new) 221 + return NULL; 222 + 223 + #ifdef CONFIG_KEYS 224 + new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); 225 + if (!new->tgcred) { 226 + kfree(new); 227 + return NULL; 228 + } 229 + atomic_set(&new->tgcred->usage, 1); 230 + #endif 231 + 232 + atomic_set(&new->usage, 1); 233 + 234 + if (security_cred_alloc_blank(new, GFP_KERNEL) < 0) 235 + goto error; 236 + 237 + #ifdef CONFIG_DEBUG_CREDENTIALS 238 + new->magic = CRED_MAGIC; 239 + #endif 240 + return new; 241 + 242 + error: 243 + abort_creds(new); 244 + return NULL; 202 245 } 203 246 204 247 /**
+19
security/capability.c
··· 373 373 return 0; 374 374 } 375 375 376 + static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) 377 + { 378 + return 0; 379 + } 380 + 376 381 static void cap_cred_free(struct cred *cred) 377 382 { 378 383 } ··· 388 383 } 389 384 390 385 static void cap_cred_commit(struct cred *new, const struct cred *old) 386 + { 387 + } 388 + 389 + static void cap_cred_transfer(struct cred *new, const struct cred *old) 391 390 { 392 391 } 393 392 ··· 845 836 return 0; 846 837 } 847 838 839 + static int cap_key_session_to_parent(const struct cred *cred, 840 + const struct cred *parent_cred, 841 + struct key *key) 842 + { 843 + return 0; 844 + } 845 + 848 846 #endif /* CONFIG_KEYS */ 849 847 850 848 #ifdef CONFIG_AUDIT ··· 977 961 set_to_cap_if_null(ops, file_receive); 978 962 set_to_cap_if_null(ops, dentry_open); 979 963 set_to_cap_if_null(ops, task_create); 964 + set_to_cap_if_null(ops, cred_alloc_blank); 980 965 set_to_cap_if_null(ops, cred_free); 981 966 set_to_cap_if_null(ops, cred_prepare); 982 967 set_to_cap_if_null(ops, cred_commit); 968 + set_to_cap_if_null(ops, cred_transfer); 983 969 set_to_cap_if_null(ops, kernel_act_as); 984 970 set_to_cap_if_null(ops, kernel_create_files_as); 985 971 set_to_cap_if_null(ops, kernel_module_request); ··· 1081 1063 set_to_cap_if_null(ops, key_free); 1082 1064 set_to_cap_if_null(ops, key_permission); 1083 1065 set_to_cap_if_null(ops, key_getsecurity); 1066 + set_to_cap_if_null(ops, key_session_to_parent); 1084 1067 #endif /* CONFIG_KEYS */ 1085 1068 #ifdef CONFIG_AUDIT 1086 1069 set_to_cap_if_null(ops, audit_rule_init);
+3
security/keys/compat.c
··· 82 82 case KEYCTL_GET_SECURITY: 83 83 return keyctl_get_security(arg2, compat_ptr(arg3), arg4); 84 84 85 + case KEYCTL_SESSION_TO_PARENT: 86 + return keyctl_session_to_parent(); 87 + 85 88 default: 86 89 return -EOPNOTSUPP; 87 90 }
+1
security/keys/gc.c
··· 65 65 * - return true if we altered the keyring 66 66 */ 67 67 static bool key_gc_keyring(struct key *keyring, time_t limit) 68 + __releases(key_serial_lock) 68 69 { 69 70 struct keyring_list *klist; 70 71 struct key *key;
+1
security/keys/internal.h
··· 201 201 extern long keyctl_assume_authority(key_serial_t); 202 202 extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, 203 203 size_t buflen); 204 + extern long keyctl_session_to_parent(void); 204 205 205 206 /* 206 207 * debugging key validation
+102
security/keys/keyctl.c
··· 1228 1228 return ret; 1229 1229 } 1230 1230 1231 + /* 1232 + * attempt to install the calling process's session keyring on the process's 1233 + * parent process 1234 + * - the keyring must exist and must grant us LINK permission 1235 + * - implements keyctl(KEYCTL_SESSION_TO_PARENT) 1236 + */ 1237 + long keyctl_session_to_parent(void) 1238 + { 1239 + struct task_struct *me, *parent; 1240 + const struct cred *mycred, *pcred; 1241 + struct cred *cred, *oldcred; 1242 + key_ref_t keyring_r; 1243 + int ret; 1244 + 1245 + keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); 1246 + if (IS_ERR(keyring_r)) 1247 + return PTR_ERR(keyring_r); 1248 + 1249 + /* our parent is going to need a new cred struct, a new tgcred struct 1250 + * and new security data, so we allocate them here to prevent ENOMEM in 1251 + * our parent */ 1252 + ret = -ENOMEM; 1253 + cred = cred_alloc_blank(); 1254 + if (!cred) 1255 + goto error_keyring; 1256 + 1257 + cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); 1258 + keyring_r = NULL; 1259 + 1260 + me = current; 1261 + write_lock_irq(&tasklist_lock); 1262 + 1263 + parent = me->real_parent; 1264 + ret = -EPERM; 1265 + 1266 + /* the parent mustn't be init and mustn't be a kernel thread */ 1267 + if (parent->pid <= 1 || !parent->mm) 1268 + goto not_permitted; 1269 + 1270 + /* the parent must be single threaded */ 1271 + if (atomic_read(&parent->signal->count) != 1) 1272 + goto not_permitted; 1273 + 1274 + /* the parent and the child must have different session keyrings or 1275 + * there's no point */ 1276 + mycred = current_cred(); 1277 + pcred = __task_cred(parent); 1278 + if (mycred == pcred || 1279 + mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) 1280 + goto already_same; 1281 + 1282 + /* the parent must have the same effective ownership and mustn't be 1283 + * SUID/SGID */ 1284 + if (pcred-> uid != mycred->euid || 1285 + pcred->euid != mycred->euid || 1286 + pcred->suid != mycred->euid || 1287 + pcred-> gid != mycred->egid || 1288 + pcred->egid != mycred->egid || 1289 + pcred->sgid != mycred->egid) 1290 + goto not_permitted; 1291 + 1292 + /* the keyrings must have the same UID */ 1293 + if (pcred ->tgcred->session_keyring->uid != mycred->euid || 1294 + mycred->tgcred->session_keyring->uid != mycred->euid) 1295 + goto not_permitted; 1296 + 1297 + /* the LSM must permit the replacement of the parent's keyring with the 1298 + * keyring from this process */ 1299 + ret = security_key_session_to_parent(mycred, pcred, 1300 + key_ref_to_ptr(keyring_r)); 1301 + if (ret < 0) 1302 + goto not_permitted; 1303 + 1304 + /* if there's an already pending keyring replacement, then we replace 1305 + * that */ 1306 + oldcred = parent->replacement_session_keyring; 1307 + 1308 + /* the replacement session keyring is applied just prior to userspace 1309 + * restarting */ 1310 + parent->replacement_session_keyring = cred; 1311 + cred = NULL; 1312 + set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); 1313 + 1314 + write_unlock_irq(&tasklist_lock); 1315 + if (oldcred) 1316 + put_cred(oldcred); 1317 + return 0; 1318 + 1319 + already_same: 1320 + ret = 0; 1321 + not_permitted: 1322 + put_cred(cred); 1323 + return ret; 1324 + 1325 + error_keyring: 1326 + key_ref_put(keyring_r); 1327 + return ret; 1328 + } 1329 + 1231 1330 /*****************************************************************************/ 1232 1331 /* 1233 1332 * the key control system call ··· 1411 1312 return keyctl_get_security((key_serial_t) arg2, 1412 1313 (char __user *) arg3, 1413 1314 (size_t) arg4); 1315 + 1316 + case KEYCTL_SESSION_TO_PARENT: 1317 + return keyctl_session_to_parent(); 1414 1318 1415 1319 default: 1416 1320 return -EOPNOTSUPP;
+49
security/keys/process_keys.c
··· 17 17 #include <linux/fs.h> 18 18 #include <linux/err.h> 19 19 #include <linux/mutex.h> 20 + #include <linux/security.h> 20 21 #include <linux/user_namespace.h> 21 22 #include <asm/uaccess.h> 22 23 #include "internal.h" ··· 768 767 error: 769 768 abort_creds(new); 770 769 return ret; 770 + } 771 + 772 + /* 773 + * Replace a process's session keyring when that process resumes userspace on 774 + * behalf of one of its children 775 + */ 776 + void key_replace_session_keyring(void) 777 + { 778 + const struct cred *old; 779 + struct cred *new; 780 + 781 + if (!current->replacement_session_keyring) 782 + return; 783 + 784 + write_lock_irq(&tasklist_lock); 785 + new = current->replacement_session_keyring; 786 + current->replacement_session_keyring = NULL; 787 + write_unlock_irq(&tasklist_lock); 788 + 789 + if (!new) 790 + return; 791 + 792 + old = current_cred(); 793 + new-> uid = old-> uid; 794 + new-> euid = old-> euid; 795 + new-> suid = old-> suid; 796 + new->fsuid = old->fsuid; 797 + new-> gid = old-> gid; 798 + new-> egid = old-> egid; 799 + new-> sgid = old-> sgid; 800 + new->fsgid = old->fsgid; 801 + new->user = get_uid(old->user); 802 + new->group_info = get_group_info(old->group_info); 803 + 804 + new->securebits = old->securebits; 805 + new->cap_inheritable = old->cap_inheritable; 806 + new->cap_permitted = old->cap_permitted; 807 + new->cap_effective = old->cap_effective; 808 + new->cap_bset = old->cap_bset; 809 + 810 + new->jit_keyring = old->jit_keyring; 811 + new->thread_keyring = key_get(old->thread_keyring); 812 + new->tgcred->tgid = old->tgcred->tgid; 813 + new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); 814 + 815 + security_transfer_creds(new, old); 816 + 817 + commit_creds(new); 771 818 }
+17
security/security.c
··· 684 684 return security_ops->task_create(clone_flags); 685 685 } 686 686 687 + int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) 688 + { 689 + return security_ops->cred_alloc_blank(cred, gfp); 690 + } 691 + 687 692 void security_cred_free(struct cred *cred) 688 693 { 689 694 security_ops->cred_free(cred); ··· 702 697 void security_commit_creds(struct cred *new, const struct cred *old) 703 698 { 704 699 security_ops->cred_commit(new, old); 700 + } 701 + 702 + void security_transfer_creds(struct cred *new, const struct cred *old) 703 + { 704 + security_ops->cred_transfer(new, old); 705 705 } 706 706 707 707 int security_kernel_act_as(struct cred *new, u32 secid) ··· 1249 1239 int security_key_getsecurity(struct key *key, char **_buffer) 1250 1240 { 1251 1241 return security_ops->key_getsecurity(key, _buffer); 1242 + } 1243 + 1244 + int security_key_session_to_parent(const struct cred *cred, 1245 + const struct cred *parent_cred, 1246 + struct key *key) 1247 + { 1248 + return security_ops->key_session_to_parent(cred, parent_cred, key); 1252 1249 } 1253 1250 1254 1251 #endif /* CONFIG_KEYS */
+28
security/selinux/hooks.c
··· 3233 3233 } 3234 3234 3235 3235 /* 3236 + * allocate the SELinux part of blank credentials 3237 + */ 3238 + static 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 3251 * detach and free the LSM part of a set of credentials 3237 3252 */ 3238 3253 static void selinux_cred_free(struct cred *cred) ··· 3276 3261 3277 3262 new->security = tsec; 3278 3263 return 0; 3264 + } 3265 + 3266 + /* 3267 + * transfer the SELinux data to a blank set of creds 3268 + */ 3269 + static void selinux_cred_transfer(struct cred *new, const struct cred *old) 3270 + { 3271 + const struct task_security_struct *old_tsec = old->security; 3272 + struct task_security_struct *tsec = new->security; 3273 + 3274 + *tsec = *old_tsec; 3279 3275 } 3280 3276 3281 3277 /* ··· 5495 5469 .dentry_open = selinux_dentry_open, 5496 5470 5497 5471 .task_create = selinux_task_create, 5472 + .cred_alloc_blank = selinux_cred_alloc_blank, 5498 5473 .cred_free = selinux_cred_free, 5499 5474 .cred_prepare = selinux_cred_prepare, 5475 + .cred_transfer = selinux_cred_transfer, 5500 5476 .kernel_act_as = selinux_kernel_act_as, 5501 5477 .kernel_create_files_as = selinux_kernel_create_files_as, 5502 5478 .kernel_module_request = selinux_kernel_module_request,
+30
security/smack/smack_lsm.c
··· 1080 1080 */ 1081 1081 1082 1082 /** 1083 + * smack_cred_alloc_blank - "allocate" blank task-level security credentials 1084 + * @new: the new credentials 1085 + * @gfp: the atomicity of any memory allocations 1086 + * 1087 + * Prepare a blank set of credentials for modification. This must allocate all 1088 + * the memory the LSM module might require such that cred_transfer() can 1089 + * complete without error. 1090 + */ 1091 + static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) 1092 + { 1093 + cred->security = NULL; 1094 + return 0; 1095 + } 1096 + 1097 + 1098 + /** 1083 1099 * smack_cred_free - "free" task-level security credentials 1084 1100 * @cred: the credentials in question 1085 1101 * ··· 1130 1114 */ 1131 1115 static void smack_cred_commit(struct cred *new, const struct cred *old) 1132 1116 { 1117 + } 1118 + 1119 + /** 1120 + * smack_cred_transfer - Transfer the old credentials to the new credentials 1121 + * @new: the new credentials 1122 + * @old: the original credentials 1123 + * 1124 + * Fill in a set of blank credentials from another set of credentials. 1125 + */ 1126 + static void smack_cred_transfer(struct cred *new, const struct cred *old) 1127 + { 1128 + new->security = old->security; 1133 1129 } 1134 1130 1135 1131 /** ··· 3101 3073 .file_send_sigiotask = smack_file_send_sigiotask, 3102 3074 .file_receive = smack_file_receive, 3103 3075 3076 + .cred_alloc_blank = smack_cred_alloc_blank, 3104 3077 .cred_free = smack_cred_free, 3105 3078 .cred_prepare = smack_cred_prepare, 3106 3079 .cred_commit = smack_cred_commit, 3080 + .cred_transfer = smack_cred_transfer, 3107 3081 .kernel_act_as = smack_kernel_act_as, 3108 3082 .kernel_create_files_as = smack_kernel_create_files_as, 3109 3083 .task_setpgid = smack_task_setpgid,
+17
security/tomoyo/tomoyo.c
··· 14 14 #include "tomoyo.h" 15 15 #include "realpath.h" 16 16 17 + static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) 18 + { 19 + new->security = NULL; 20 + return 0; 21 + } 22 + 17 23 static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, 18 24 gfp_t gfp) 19 25 { ··· 29 23 */ 30 24 new->security = old->security; 31 25 return 0; 26 + } 27 + 28 + static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) 29 + { 30 + /* 31 + * Since "struct tomoyo_domain_info *" is a sharable pointer, 32 + * we don't need to duplicate. 33 + */ 34 + new->security = old->security; 32 35 } 33 36 34 37 static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) ··· 277 262 */ 278 263 static struct security_operations tomoyo_security_ops = { 279 264 .name = "tomoyo", 265 + .cred_alloc_blank = tomoyo_cred_alloc_blank, 280 266 .cred_prepare = tomoyo_cred_prepare, 267 + .cred_transfer = tomoyo_cred_transfer, 281 268 .bprm_set_creds = tomoyo_bprm_set_creds, 282 269 .bprm_check_security = tomoyo_bprm_check_security, 283 270 #ifdef CONFIG_SYSCTL