aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/security.h
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/security.h
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/security.h')
-rw-r--r--include/linux/security.h103
1 files changed, 37 insertions, 66 deletions
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)