aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:24 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:24 -0500
commita6f76f23d297f70e2a6b3ec607f7aeeea9e37e8d (patch)
tree8f95617996d0974507f176163459212a7def8b9a /include/linux
parentd84f4f992cbd76e8f39c488cf0c5d123843923b1 (diff)
CRED: Make execve() take advantage of copy-on-write credentials
Make execve() take advantage of copy-on-write credentials, allowing it to set up the credentials in advance, and then commit the whole lot after the point of no return. This patch and the preceding patches have been tested with the LTP SELinux testsuite. This patch makes several logical sets of alteration: (1) execve(). The credential bits from struct linux_binprm are, for the most part, replaced with a single credentials pointer (bprm->cred). This means that all the creds can be calculated in advance and then applied at the point of no return with no possibility of failure. I would like to replace bprm->cap_effective with: cap_isclear(bprm->cap_effective) but this seems impossible due to special behaviour for processes of pid 1 (they always retain their parent's capability masks where normally they'd be changed - see cap_bprm_set_creds()). The following sequence of events now happens: (a) At the start of do_execve, the current task's cred_exec_mutex is locked to prevent PTRACE_ATTACH from obsoleting the calculation of creds that we make. (a) prepare_exec_creds() is then called to make a copy of the current task's credentials and prepare it. This copy is then assigned to bprm->cred. This renders security_bprm_alloc() and security_bprm_free() unnecessary, and so they've been removed. (b) The determination of unsafe execution is now performed immediately after (a) rather than later on in the code. The result is stored in bprm->unsafe for future reference. (c) prepare_binprm() is called, possibly multiple times. (i) This applies the result of set[ug]id binaries to the new creds attached to bprm->cred. Personality bit clearance is recorded, but now deferred on the basis that the exec procedure may yet fail. (ii) This then calls the new security_bprm_set_creds(). This should calculate the new LSM and capability credentials into *bprm->cred. This folds together security_bprm_set() and parts of security_bprm_apply_creds() (these two have been removed). Anything that might fail must be done at this point. (iii) bprm->cred_prepared is set to 1. bprm->cred_prepared is 0 on the first pass of the security calculations, and 1 on all subsequent passes. This allows SELinux in (ii) to base its calculations only on the initial script and not on the interpreter. (d) flush_old_exec() is called to commit the task to execution. This performs the following steps with regard to credentials: (i) Clear pdeath_signal and set dumpable on certain circumstances that may not be covered by commit_creds(). (ii) Clear any bits in current->personality that were deferred from (c.i). (e) install_exec_creds() [compute_creds() as was] is called to install the new credentials. This performs the following steps with regard to credentials: (i) Calls security_bprm_committing_creds() to apply any security requirements, such as flushing unauthorised files in SELinux, that must be done before the credentials are changed. This is made up of bits of security_bprm_apply_creds() and security_bprm_post_apply_creds(), both of which have been removed. This function is not allowed to fail; anything that might fail must have been done in (c.ii). (ii) Calls commit_creds() to apply the new credentials in a single assignment (more or less). Possibly pdeath_signal and dumpable should be part of struct creds. (iii) Unlocks the task's cred_replace_mutex, thus allowing PTRACE_ATTACH to take place. (iv) Clears The bprm->cred pointer as the credentials it was holding are now immutable. (v) Calls security_bprm_committed_creds() to apply any security alterations that must be done after the creds have been changed. SELinux uses this to flush signals and signal handlers. (f) If an error occurs before (d.i), bprm_free() will call abort_creds() to destroy the proposed new credentials and will then unlock cred_replace_mutex. No changes to the credentials will have been made. (2) LSM interface. A number of functions have been changed, added or removed: (*) security_bprm_alloc(), ->bprm_alloc_security() (*) security_bprm_free(), ->bprm_free_security() Removed in favour of preparing new credentials and modifying those. (*) security_bprm_apply_creds(), ->bprm_apply_creds() (*) security_bprm_post_apply_creds(), ->bprm_post_apply_creds() Removed; split between security_bprm_set_creds(), security_bprm_committing_creds() and security_bprm_committed_creds(). (*) security_bprm_set(), ->bprm_set_security() Removed; folded into security_bprm_set_creds(). (*) security_bprm_set_creds(), ->bprm_set_creds() New. The new credentials in bprm->creds should be checked and set up as appropriate. bprm->cred_prepared is 0 on the first call, 1 on the second and subsequent calls. (*) security_bprm_committing_creds(), ->bprm_committing_creds() (*) security_bprm_committed_creds(), ->bprm_committed_creds() New. Apply the security effects of the new credentials. This includes closing unauthorised files in SELinux. This function may not fail. When the former is called, the creds haven't yet been applied to the process; when the latter is called, they have. The former may access bprm->cred, the latter may not. (3) SELinux. SELinux has a number of changes, in addition to those to support the LSM interface changes mentioned above: (a) The bprm_security_struct struct has been removed in favour of using the credentials-under-construction approach. (c) flush_unauthorized_files() now takes a cred pointer and passes it on to inode_has_perm(), file_has_perm() and dentry_open(). Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/audit.h16
-rw-r--r--include/linux/binfmts.h16
-rw-r--r--include/linux/cred.h3
-rw-r--r--include/linux/key.h2
-rw-r--r--include/linux/security.h103
5 files changed, 48 insertions, 92 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0b2fcb698a63..e8ce2c4c7ac7 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -508,22 +508,6 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
508 return 0; 508 return 0;
509} 509}
510 510
511/*
512 * ieieeeeee, an audit function without a return code!
513 *
514 * This function might fail! I decided that it didn't matter. We are too late
515 * to fail the syscall and the information isn't REQUIRED for any purpose. It's
516 * just nice to have. We should be able to look at past audit logs to figure
517 * out this process's current cap set along with the fcaps from the PATH record
518 * and use that to come up with the final set. Yeah, its ugly, but all the info
519 * is still in the audit log. So I'm not going to bother mentioning we failed
520 * if we couldn't allocate memory.
521 *
522 * If someone changes their mind they could create the aux record earlier and
523 * then search here and use that earlier allocation. But I don't wanna.
524 *
525 * -Eric
526 */
527static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, 511static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
528 const struct cred *new, 512 const struct cred *new,
529 const struct cred *old) 513 const struct cred *old)
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 7394b5b349ff..6cbfbe297180 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -35,16 +35,20 @@ struct linux_binprm{
35 struct mm_struct *mm; 35 struct mm_struct *mm;
36 unsigned long p; /* current top of mem */ 36 unsigned long p; /* current top of mem */
37 unsigned int sh_bang:1, 37 unsigned int sh_bang:1,
38 misc_bang:1; 38 misc_bang:1,
39 cred_prepared:1,/* true if creds already prepared (multiple
40 * preps happen for interpreters) */
41 cap_effective:1;/* true if has elevated effective capabilities,
42 * false if not; except for init which inherits
43 * its parent's caps anyway */
39#ifdef __alpha__ 44#ifdef __alpha__
40 unsigned int taso:1; 45 unsigned int taso:1;
41#endif 46#endif
42 unsigned int recursion_depth; 47 unsigned int recursion_depth;
43 struct file * file; 48 struct file * file;
44 int e_uid, e_gid; 49 struct cred *cred; /* new credentials */
45 kernel_cap_t cap_post_exec_permitted; 50 int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
46 bool cap_effective; 51 unsigned int per_clear; /* bits to clear in current->personality */
47 void *security;
48 int argc, envc; 52 int argc, envc;
49 char * filename; /* Name of binary as seen by procps */ 53 char * filename; /* Name of binary as seen by procps */
50 char * interp; /* Name of the binary really executed. Most 54 char * interp; /* Name of the binary really executed. Most
@@ -101,7 +105,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
101 int executable_stack); 105 int executable_stack);
102extern int bprm_mm_init(struct linux_binprm *bprm); 106extern int bprm_mm_init(struct linux_binprm *bprm);
103extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm); 107extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
104extern void compute_creds(struct linux_binprm *binprm); 108extern void install_exec_creds(struct linux_binprm *bprm);
105extern int do_coredump(long signr, int exit_code, struct pt_regs * regs); 109extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
106extern int set_binfmt(struct linux_binfmt *new); 110extern int set_binfmt(struct linux_binfmt *new);
107extern void free_bprm(struct linux_binprm *); 111extern void free_bprm(struct linux_binprm *);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index eaf6fa695a04..8edb4d1d5427 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -84,8 +84,6 @@ struct thread_group_cred {
84 struct key *process_keyring; /* keyring private to this process */ 84 struct key *process_keyring; /* keyring private to this process */
85 struct rcu_head rcu; /* RCU deletion hook */ 85 struct rcu_head rcu; /* RCU deletion hook */
86}; 86};
87
88extern void release_tgcred(struct cred *cred);
89#endif 87#endif
90 88
91/* 89/*
@@ -144,6 +142,7 @@ struct cred {
144extern void __put_cred(struct cred *); 142extern void __put_cred(struct cred *);
145extern int copy_creds(struct task_struct *, unsigned long); 143extern int copy_creds(struct task_struct *, unsigned long);
146extern struct cred *prepare_creds(void); 144extern struct cred *prepare_creds(void);
145extern struct cred *prepare_exec_creds(void);
147extern struct cred *prepare_usermodehelper_creds(void); 146extern struct cred *prepare_usermodehelper_creds(void);
148extern int commit_creds(struct cred *); 147extern int commit_creds(struct cred *);
149extern void abort_creds(struct cred *); 148extern void abort_creds(struct cred *);
diff --git a/include/linux/key.h b/include/linux/key.h
index 69ecf0934b02..21d32a142c00 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -278,7 +278,6 @@ extern ctl_table key_sysctls[];
278 * the userspace interface 278 * the userspace interface
279 */ 279 */
280extern int install_thread_keyring_to_cred(struct cred *cred); 280extern int install_thread_keyring_to_cred(struct cred *cred);
281extern int exec_keys(struct task_struct *tsk);
282extern void key_fsuid_changed(struct task_struct *tsk); 281extern void key_fsuid_changed(struct task_struct *tsk);
283extern void key_fsgid_changed(struct task_struct *tsk); 282extern void key_fsgid_changed(struct task_struct *tsk);
284extern void key_init(void); 283extern void key_init(void);
@@ -294,7 +293,6 @@ extern void key_init(void);
294#define make_key_ref(k, p) NULL 293#define make_key_ref(k, p) NULL
295#define key_ref_to_ptr(k) NULL 294#define key_ref_to_ptr(k) NULL
296#define is_key_possessed(k) 0 295#define is_key_possessed(k) 0
297#define exec_keys(t) do { } while(0)
298#define key_fsuid_changed(t) do { } while(0) 296#define key_fsuid_changed(t) do { } while(0)
299#define key_fsgid_changed(t) do { } while(0) 297#define key_fsgid_changed(t) do { } while(0)
300#define key_init() do { } while(0) 298#define key_init() do { } while(0)
diff --git a/include/linux/security.h b/include/linux/security.h
index 68be11251447..56a0eed65673 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -57,8 +57,7 @@ extern int cap_capset(struct cred *new, const struct cred *old,
57 const kernel_cap_t *effective, 57 const kernel_cap_t *effective,
58 const kernel_cap_t *inheritable, 58 const kernel_cap_t *inheritable,
59 const kernel_cap_t *permitted); 59 const kernel_cap_t *permitted);
60extern int cap_bprm_set_security(struct linux_binprm *bprm); 60extern int cap_bprm_set_creds(struct linux_binprm *bprm);
61extern int cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
62extern int cap_bprm_secureexec(struct linux_binprm *bprm); 61extern int cap_bprm_secureexec(struct linux_binprm *bprm);
63extern int cap_inode_setxattr(struct dentry *dentry, const char *name, 62extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
64 const void *value, size_t size, int flags); 63 const void *value, size_t size, int flags);
@@ -110,7 +109,7 @@ extern unsigned long mmap_min_addr;
110struct sched_param; 109struct sched_param;
111struct request_sock; 110struct request_sock;
112 111
113/* bprm_apply_creds unsafe reasons */ 112/* bprm->unsafe reasons */
114#define LSM_UNSAFE_SHARE 1 113#define LSM_UNSAFE_SHARE 1
115#define LSM_UNSAFE_PTRACE 2 114#define LSM_UNSAFE_PTRACE 2
116#define LSM_UNSAFE_PTRACE_CAP 4 115#define LSM_UNSAFE_PTRACE_CAP 4
@@ -154,36 +153,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
154 * 153 *
155 * Security hooks for program execution operations. 154 * Security hooks for program execution operations.
156 * 155 *
157 * @bprm_alloc_security: 156 * @bprm_set_creds:
158 * Allocate and attach a security structure to the @bprm->security field.
159 * The security field is initialized to NULL when the bprm structure is
160 * allocated.
161 * @bprm contains the linux_binprm structure to be modified.
162 * Return 0 if operation was successful.
163 * @bprm_free_security:
164 * @bprm contains the linux_binprm structure to be modified.
165 * Deallocate and clear the @bprm->security field.
166 * @bprm_apply_creds:
167 * Compute and set the security attributes of a process being transformed
168 * by an execve operation based on the old attributes (current->security)
169 * and the information saved in @bprm->security by the set_security hook.
170 * Since this function may return an error, in which case the process will
171 * be killed. However, it can leave the security attributes of the
172 * process unchanged if an access failure occurs at this point.
173 * bprm_apply_creds is called under task_lock. @unsafe indicates various
174 * reasons why it may be unsafe to change security state.
175 * @bprm contains the linux_binprm structure.
176 * @bprm_post_apply_creds:
177 * Runs after bprm_apply_creds with the task_lock dropped, so that
178 * functions which cannot be called safely under the task_lock can
179 * be used. This hook is a good place to perform state changes on
180 * the process such as closing open file descriptors to which access
181 * is no longer granted if the attributes were changed.
182 * Note that a security module might need to save state between
183 * bprm_apply_creds and bprm_post_apply_creds to store the decision
184 * on whether the process may proceed.
185 * @bprm contains the linux_binprm structure.
186 * @bprm_set_security:
187 * Save security information in the bprm->security field, typically based 157 * Save security information in the bprm->security field, typically based
188 * on information about the bprm->file, for later use by the apply_creds 158 * on information about the bprm->file, for later use by the apply_creds
189 * hook. This hook may also optionally check permissions (e.g. for 159 * hook. This hook may also optionally check permissions (e.g. for
@@ -196,15 +166,30 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
196 * @bprm contains the linux_binprm structure. 166 * @bprm contains the linux_binprm structure.
197 * Return 0 if the hook is successful and permission is granted. 167 * Return 0 if the hook is successful and permission is granted.
198 * @bprm_check_security: 168 * @bprm_check_security:
199 * This hook mediates the point when a search for a binary handler will 169 * This hook mediates the point when a search for a binary handler will
200 * begin. It allows a check the @bprm->security value which is set in 170 * begin. It allows a check the @bprm->security value which is set in the
201 * the preceding set_security call. The primary difference from 171 * preceding set_creds call. The primary difference from set_creds is
202 * set_security is that the argv list and envp list are reliably 172 * that the argv list and envp list are reliably available in @bprm. This
203 * available in @bprm. This hook may be called multiple times 173 * hook may be called multiple times during a single execve; and in each
204 * during a single execve; and in each pass set_security is called 174 * pass set_creds is called first.
205 * first.
206 * @bprm contains the linux_binprm structure. 175 * @bprm contains the linux_binprm structure.
207 * Return 0 if the hook is successful and permission is granted. 176 * Return 0 if the hook is successful and permission is granted.
177 * @bprm_committing_creds:
178 * Prepare to install the new security attributes of a process being
179 * transformed by an execve operation, based on the old credentials
180 * pointed to by @current->cred and the information set in @bprm->cred by
181 * the bprm_set_creds hook. @bprm points to the linux_binprm structure.
182 * This hook is a good place to perform state changes on the process such
183 * as closing open file descriptors to which access will no longer be
184 * granted when the attributes are changed. This is called immediately
185 * before commit_creds().
186 * @bprm_committed_creds:
187 * Tidy up after the installation of the new security attributes of a
188 * process being transformed by an execve operation. The new credentials
189 * have, by this point, been set to @current->cred. @bprm points to the
190 * linux_binprm structure. This hook is a good place to perform state
191 * changes on the process such as clearing out non-inheritable signal
192 * state. This is called immediately after commit_creds().
208 * @bprm_secureexec: 193 * @bprm_secureexec:
209 * Return a boolean value (0 or 1) indicating whether a "secure exec" 194 * Return a boolean value (0 or 1) indicating whether a "secure exec"
210 * is required. The flag is passed in the auxiliary table 195 * is required. The flag is passed in the auxiliary table
@@ -1301,13 +1286,11 @@ struct security_operations {
1301 int (*settime) (struct timespec *ts, struct timezone *tz); 1286 int (*settime) (struct timespec *ts, struct timezone *tz);
1302 int (*vm_enough_memory) (struct mm_struct *mm, long pages); 1287 int (*vm_enough_memory) (struct mm_struct *mm, long pages);
1303 1288
1304 int (*bprm_alloc_security) (struct linux_binprm *bprm); 1289 int (*bprm_set_creds) (struct linux_binprm *bprm);
1305 void (*bprm_free_security) (struct linux_binprm *bprm);
1306 int (*bprm_apply_creds) (struct linux_binprm *bprm, int unsafe);
1307 void (*bprm_post_apply_creds) (struct linux_binprm *bprm);
1308 int (*bprm_set_security) (struct linux_binprm *bprm);
1309 int (*bprm_check_security) (struct linux_binprm *bprm); 1290 int (*bprm_check_security) (struct linux_binprm *bprm);
1310 int (*bprm_secureexec) (struct linux_binprm *bprm); 1291 int (*bprm_secureexec) (struct linux_binprm *bprm);
1292 void (*bprm_committing_creds) (struct linux_binprm *bprm);
1293 void (*bprm_committed_creds) (struct linux_binprm *bprm);
1311 1294
1312 int (*sb_alloc_security) (struct super_block *sb); 1295 int (*sb_alloc_security) (struct super_block *sb);
1313 void (*sb_free_security) (struct super_block *sb); 1296 void (*sb_free_security) (struct super_block *sb);
@@ -1569,12 +1552,10 @@ int security_settime(struct timespec *ts, struct timezone *tz);
1569int security_vm_enough_memory(long pages); 1552int security_vm_enough_memory(long pages);
1570int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); 1553int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
1571int security_vm_enough_memory_kern(long pages); 1554int security_vm_enough_memory_kern(long pages);
1572int security_bprm_alloc(struct linux_binprm *bprm); 1555int security_bprm_set_creds(struct linux_binprm *bprm);
1573void security_bprm_free(struct linux_binprm *bprm);
1574int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
1575void security_bprm_post_apply_creds(struct linux_binprm *bprm);
1576int security_bprm_set(struct linux_binprm *bprm);
1577int security_bprm_check(struct linux_binprm *bprm); 1556int security_bprm_check(struct linux_binprm *bprm);
1557void security_bprm_committing_creds(struct linux_binprm *bprm);
1558void security_bprm_committed_creds(struct linux_binprm *bprm);
1578int security_bprm_secureexec(struct linux_binprm *bprm); 1559int security_bprm_secureexec(struct linux_binprm *bprm);
1579int security_sb_alloc(struct super_block *sb); 1560int security_sb_alloc(struct super_block *sb);
1580void security_sb_free(struct super_block *sb); 1561void security_sb_free(struct super_block *sb);
@@ -1812,32 +1793,22 @@ static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
1812 return cap_vm_enough_memory(mm, pages); 1793 return cap_vm_enough_memory(mm, pages);
1813} 1794}
1814 1795
1815static inline int security_bprm_alloc(struct linux_binprm *bprm) 1796static inline int security_bprm_set_creds(struct linux_binprm *bprm)
1816{
1817 return 0;
1818}
1819
1820static inline void security_bprm_free(struct linux_binprm *bprm)
1821{ }
1822
1823static inline int security_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
1824{ 1797{
1825 return cap_bprm_apply_creds(bprm, unsafe); 1798 return cap_bprm_set_creds(bprm);
1826} 1799}
1827 1800
1828static inline void security_bprm_post_apply_creds(struct linux_binprm *bprm) 1801static inline int security_bprm_check(struct linux_binprm *bprm)
1829{ 1802{
1830 return; 1803 return 0;
1831} 1804}
1832 1805
1833static inline int security_bprm_set(struct linux_binprm *bprm) 1806static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
1834{ 1807{
1835 return cap_bprm_set_security(bprm);
1836} 1808}
1837 1809
1838static inline int security_bprm_check(struct linux_binprm *bprm) 1810static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
1839{ 1811{
1840 return 0;
1841} 1812}
1842 1813
1843static inline int security_bprm_secureexec(struct linux_binprm *bprm) 1814static inline int security_bprm_secureexec(struct linux_binprm *bprm)