Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 157346
b: refs/heads/master
c: ee18d64
h: refs/heads/master
v: v3
  • Loading branch information
David Howells authored and James Morris committed Sep 2, 2009
1 parent 71e29e1 commit 4fdbd1f
Show file tree
Hide file tree
Showing 35 changed files with 410 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d0420c83f39f79afb82010c2d2cafd150eef651b
refs/heads/master: ee18d64c1f632043a02e6f5ba5e045bb26a5465f
20 changes: 20 additions & 0 deletions trunk/Documentation/keys.txt
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,26 @@ The keyctl syscall functions are:
successful.


(*) Install the calling process's session keyring on its parent.

long keyctl(KEYCTL_SESSION_TO_PARENT);

This functions attempts to install the calling process's session keyring
on to the calling process's parent, replacing the parent's current session
keyring.

The calling process must have the same ownership as its parent, the
keyring must have the same ownership as the calling process, the calling
process must have LINK permission on the keyring and the active LSM module
mustn't deny permission, otherwise error EPERM will be returned.

Error ENOMEM will be returned if there was insufficient memory to complete
the operation, otherwise 0 will be returned to indicate success.

The keyring will be replaced next time the parent process leaves the
kernel and resumes executing userspace.


===============
KERNEL SERVICES
===============
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/alpha/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,5 +687,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/arm/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,5 +711,7 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
if (thread_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/avr32/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,5 +326,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
if (ti->flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/cris/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ void do_notify_resume(int canrestart, struct pt_regs *regs,
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/frv/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,8 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(__frame);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}

} /* end do_notify_resume() */
2 changes: 2 additions & 0 deletions trunk/arch/h8300/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -556,5 +556,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/ia64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
if (test_thread_flag(TIF_NOTIFY_RESUME)) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(&scr->pt);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}

/* copy user rbs to kernel rbs */
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/m32r/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,8 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}

clear_thread_flag(TIF_IRET);
Expand Down
2 changes: 2 additions & 0 deletions trunk/arch/mips/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -704,5 +704,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/mn10300/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,5 +568,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(__frame);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/parisc/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,5 +649,7 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall)
if (test_thread_flag(TIF_NOTIFY_RESUME)) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/s390/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,4 +536,6 @@ void do_notify_resume(struct pt_regs *regs)
{
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
2 changes: 2 additions & 0 deletions trunk/arch/sh/kernel/signal_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,5 +640,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/sh/kernel/signal_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -772,5 +772,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}
2 changes: 2 additions & 0 deletions trunk/arch/sparc/kernel/signal_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}

Expand Down
3 changes: 3 additions & 0 deletions trunk/arch/sparc/kernel/signal_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,5 +613,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}

2 changes: 2 additions & 0 deletions trunk/arch/x86/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}

#ifdef CONFIG_X86_32
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct cred {
extern void __put_cred(struct cred *);
extern void exit_creds(struct task_struct *);
extern int copy_creds(struct task_struct *, unsigned long);
extern struct cred *cred_alloc_blank(void);
extern struct cred *prepare_creds(void);
extern struct cred *prepare_exec_creds(void);
extern struct cred *prepare_usermodehelper_creds(void);
Expand Down
3 changes: 3 additions & 0 deletions trunk/include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ static inline key_serial_t key_serial(struct key *key)
extern ctl_table key_sysctls[];
#endif

extern void key_replace_session_keyring(void);

/*
* the userspace interface
*/
Expand All @@ -300,6 +302,7 @@ extern void key_init(void);
#define key_fsuid_changed(t) do { } while(0)
#define key_fsgid_changed(t) do { } while(0)
#define key_init() do { } while(0)
#define key_replace_session_keyring() do { } while(0)

#endif /* CONFIG_KEYS */
#endif /* __KERNEL__ */
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/keyctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@
#define KEYCTL_SET_TIMEOUT 15 /* set key timeout */
#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */
#define KEYCTL_GET_SECURITY 17 /* get key security label */
#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */

#endif /* _LINUX_KEYCTL_H */
1 change: 1 addition & 0 deletions trunk/include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,7 @@ struct task_struct {
struct mutex cred_guard_mutex; /* guard against foreign influences on
* credential calculations
* (notably. ptrace) */
struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */

char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
Expand Down
38 changes: 38 additions & 0 deletions trunk/include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* manual page for definitions of the @clone_flags.
* @clone_flags contains the flags indicating what should be shared.
* Return 0 if permission is granted.
* @cred_alloc_blank:
* @cred points to the credentials.
* @gfp indicates the atomicity of any memory allocations.
* Only allocate sufficient memory and attach to @cred such that
* cred_transfer() will not get ENOMEM.
* @cred_free:
* @cred points to the credentials.
* Deallocate and clear the cred->security field in a set of credentials.
Expand All @@ -665,6 +670,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @new points to the new credentials.
* @old points to the original credentials.
* Install a new set of credentials.
* @cred_transfer:
* @new points to the new credentials.
* @old points to the original credentials.
* Transfer data from original creds to new creds
* @kernel_act_as:
* Set the credentials for a kernel service to act as (subjective context).
* @new points to the credentials to be modified.
Expand Down Expand Up @@ -1103,6 +1112,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Return the length of the string (including terminating NUL) or -ve if
* an error.
* May also return 0 (and a NULL buffer pointer) if there is no label.
* @key_session_to_parent:
* Forcibly assign the session keyring from a process to its parent
* process.
* @cred: Pointer to process's credentials
* @parent_cred: Pointer to parent process's credentials
* @keyring: Proposed new session keyring
* Return 0 if permission is granted, -ve error otherwise.
*
* Security hooks affecting all System V IPC operations.
*
Expand Down Expand Up @@ -1498,10 +1514,12 @@ struct security_operations {
int (*dentry_open) (struct file *file, const struct cred *cred);

int (*task_create) (unsigned long clone_flags);
int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp);
void (*cred_free) (struct cred *cred);
int (*cred_prepare)(struct cred *new, const struct cred *old,
gfp_t gfp);
void (*cred_commit)(struct cred *new, const struct cred *old);
void (*cred_transfer)(struct cred *new, const struct cred *old);
int (*kernel_act_as)(struct cred *new, u32 secid);
int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
int (*kernel_module_request)(void);
Expand Down Expand Up @@ -1639,6 +1657,9 @@ struct security_operations {
const struct cred *cred,
key_perm_t perm);
int (*key_getsecurity)(struct key *key, char **_buffer);
int (*key_session_to_parent)(const struct cred *cred,
const struct cred *parent_cred,
struct key *key);
#endif /* CONFIG_KEYS */

#ifdef CONFIG_AUDIT
Expand Down Expand Up @@ -1755,9 +1776,11 @@ int security_file_send_sigiotask(struct task_struct *tsk,
int security_file_receive(struct file *file);
int security_dentry_open(struct file *file, const struct cred *cred);
int security_task_create(unsigned long clone_flags);
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
void security_cred_free(struct cred *cred);
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
void security_commit_creds(struct cred *new, const struct cred *old);
void security_transfer_creds(struct cred *new, const struct cred *old);
int security_kernel_act_as(struct cred *new, u32 secid);
int security_kernel_create_files_as(struct cred *new, struct inode *inode);
int security_kernel_module_request(void);
Expand Down Expand Up @@ -2286,6 +2309,9 @@ static inline int security_task_create(unsigned long clone_flags)
return 0;
}

static inline void security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{ }

static inline void security_cred_free(struct cred *cred)
{ }

Expand All @@ -2301,6 +2327,11 @@ static inline void security_commit_creds(struct cred *new,
{
}

static inline void security_transfer_creds(struct cred *new,
const struct cred *old)
{
}

static inline int security_kernel_act_as(struct cred *cred, u32 secid)
{
return 0;
Expand Down Expand Up @@ -2923,6 +2954,9 @@ void security_key_free(struct key *key);
int security_key_permission(key_ref_t key_ref,
const struct cred *cred, key_perm_t perm);
int security_key_getsecurity(struct key *key, char **_buffer);
int security_key_session_to_parent(const struct cred *cred,
const struct cred *parent_cred,
struct key *key);

#else

Expand Down Expand Up @@ -2950,6 +2984,10 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
return 0;
}

static inline int security_key_session_to_parent(const struct cred *cred,
const struct cred *parent_cred,
struct key *key);

#endif
#endif /* CONFIG_KEYS */

Expand Down
43 changes: 43 additions & 0 deletions trunk/kernel/cred.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,49 @@ void exit_creds(struct task_struct *tsk)
validate_creds(cred);
alter_cred_subscribers(cred, -1);
put_cred(cred);

cred = (struct cred *) tsk->replacement_session_keyring;
if (cred) {
tsk->replacement_session_keyring = NULL;
validate_creds(cred);
put_cred(cred);
}
}

/*
* Allocate blank credentials, such that the credentials can be filled in at a
* later date without risk of ENOMEM.
*/
struct cred *cred_alloc_blank(void)
{
struct cred *new;

new = kmem_cache_zalloc(cred_jar, GFP_KERNEL);
if (!new)
return NULL;

#ifdef CONFIG_KEYS
new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL);
if (!new->tgcred) {
kfree(new);
return NULL;
}
atomic_set(&new->tgcred->usage, 1);
#endif

atomic_set(&new->usage, 1);

if (security_cred_alloc_blank(new, GFP_KERNEL) < 0)
goto error;

#ifdef CONFIG_DEBUG_CREDENTIALS
new->magic = CRED_MAGIC;
#endif
return new;

error:
abort_creds(new);
return NULL;
}

/**
Expand Down
Loading

0 comments on commit 4fdbd1f

Please sign in to comment.