aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorSerge E. Hallyn <serue@us.ibm.com>2007-10-17 02:31:36 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:43:07 -0400
commitb53767719b6cd8789392ea3e7e2eb7b8906898f0 (patch)
treea0279dc93c79b94d3865b0f19f6b7b353e20608c /security/commoncap.c
parent57c521ce6125e15e99e56c902cb8da96bee7b36d (diff)
Implement file posix capabilities
Implement file posix capabilities. This allows programs to be given a subset of root's powers regardless of who runs them, without having to use setuid and giving the binary all of root's powers. This version works with Kaigai Kohei's userspace tools, found at http://www.kaigai.gr.jp/index.php. For more information on how to use this patch, Chris Friedhoff has posted a nice page at http://www.friedhoff.org/fscaps.html. Changelog: Nov 27: Incorporate fixes from Andrew Morton (security-introduce-file-caps-tweaks and security-introduce-file-caps-warning-fix) Fix Kconfig dependency. Fix change signaling behavior when file caps are not compiled in. Nov 13: Integrate comments from Alexey: Remove CONFIG_ ifdef from capability.h, and use %zd for printing a size_t. Nov 13: Fix endianness warnings by sparse as suggested by Alexey Dobriyan. Nov 09: Address warnings of unused variables at cap_bprm_set_security when file capabilities are disabled, and simultaneously clean up the code a little, by pulling the new code into a helper function. Nov 08: For pointers to required userspace tools and how to use them, see http://www.friedhoff.org/fscaps.html. Nov 07: Fix the calculation of the highest bit checked in check_cap_sanity(). Nov 07: Allow file caps to be enabled without CONFIG_SECURITY, since capabilities are the default. Hook cap_task_setscheduler when !CONFIG_SECURITY. Move capable(TASK_KILL) to end of cap_task_kill to reduce audit messages. Nov 05: Add secondary calls in selinux/hooks.c to task_setioprio and task_setscheduler so that selinux and capabilities with file cap support can be stacked. Sep 05: As Seth Arnold points out, uid checks are out of place for capability code. Sep 01: Define task_setscheduler, task_setioprio, cap_task_kill, and task_setnice to make sure a user cannot affect a process in which they called a program with some fscaps. One remaining question is the note under task_setscheduler: are we ok with CAP_SYS_NICE being sufficient to confine a process to a cpuset? It is a semantic change, as without fsccaps, attach_task doesn't allow CAP_SYS_NICE to override the uid equivalence check. But since it uses security_task_setscheduler, which elsewhere is used where CAP_SYS_NICE can be used to override the uid equivalence check, fixing it might be tough. task_setscheduler note: this also controls cpuset:attach_task. Are we ok with CAP_SYS_NICE being used to confine to a cpuset? task_setioprio task_setnice sys_setpriority uses this (through set_one_prio) for another process. Need same checks as setrlimit Aug 21: Updated secureexec implementation to reflect the fact that euid and uid might be the same and nonzero, but the process might still have elevated caps. Aug 15: Handle endianness of xattrs. Enforce capability version match between kernel and disk. Enforce that no bits beyond the known max capability are set, else return -EPERM. With this extra processing, it may be worth reconsidering doing all the work at bprm_set_security rather than d_instantiate. Aug 10: Always call getxattr at bprm_set_security, rather than caching it at d_instantiate. [morgan@kernel.org: file-caps clean up for linux/capability.h] [bunk@kernel.org: unexport cap_inode_killpriv] Signed-off-by: Serge E. Hallyn <serue@us.ibm.com> Cc: Stephen Smalley <sds@tycho.nsa.gov> Cc: James Morris <jmorris@namei.org> Cc: Chris Wright <chrisw@sous-sol.org> Cc: Andrew Morgan <morgan@kernel.org> Signed-off-by: Andrew Morgan <morgan@kernel.org> Signed-off-by: Adrian Bunk <bunk@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c244
1 files changed, 228 insertions, 16 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 0f8a2ce3f3a6..afca6dd4ae69 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -22,6 +22,7 @@
22#include <linux/ptrace.h> 22#include <linux/ptrace.h>
23#include <linux/xattr.h> 23#include <linux/xattr.h>
24#include <linux/hugetlb.h> 24#include <linux/hugetlb.h>
25#include <linux/mount.h>
25 26
26int cap_netlink_send(struct sock *sk, struct sk_buff *skb) 27int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
27{ 28{
@@ -108,14 +109,130 @@ void cap_capset_set (struct task_struct *target, kernel_cap_t *effective,
108 target->cap_permitted = *permitted; 109 target->cap_permitted = *permitted;
109} 110}
110 111
112static inline void bprm_clear_caps(struct linux_binprm *bprm)
113{
114 cap_clear(bprm->cap_inheritable);
115 cap_clear(bprm->cap_permitted);
116 bprm->cap_effective = false;
117}
118
119#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
120
121int cap_inode_need_killpriv(struct dentry *dentry)
122{
123 struct inode *inode = dentry->d_inode;
124 int error;
125
126 if (!inode->i_op || !inode->i_op->getxattr)
127 return 0;
128
129 error = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
130 if (error <= 0)
131 return 0;
132 return 1;
133}
134
135int cap_inode_killpriv(struct dentry *dentry)
136{
137 struct inode *inode = dentry->d_inode;
138
139 if (!inode->i_op || !inode->i_op->removexattr)
140 return 0;
141
142 return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
143}
144
145static inline int cap_from_disk(__le32 *caps, struct linux_binprm *bprm,
146 int size)
147{
148 __u32 magic_etc;
149
150 if (size != XATTR_CAPS_SZ)
151 return -EINVAL;
152
153 magic_etc = le32_to_cpu(caps[0]);
154
155 switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
156 case VFS_CAP_REVISION:
157 if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
158 bprm->cap_effective = true;
159 else
160 bprm->cap_effective = false;
161 bprm->cap_permitted = to_cap_t( le32_to_cpu(caps[1]) );
162 bprm->cap_inheritable = to_cap_t( le32_to_cpu(caps[2]) );
163 return 0;
164 default:
165 return -EINVAL;
166 }
167}
168
169/* Locate any VFS capabilities: */
170static int get_file_caps(struct linux_binprm *bprm)
171{
172 struct dentry *dentry;
173 int rc = 0;
174 __le32 v1caps[XATTR_CAPS_SZ];
175 struct inode *inode;
176
177 if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
178 bprm_clear_caps(bprm);
179 return 0;
180 }
181
182 dentry = dget(bprm->file->f_dentry);
183 inode = dentry->d_inode;
184 if (!inode->i_op || !inode->i_op->getxattr)
185 goto out;
186
187 rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &v1caps,
188 XATTR_CAPS_SZ);
189 if (rc == -ENODATA || rc == -EOPNOTSUPP) {
190 /* no data, that's ok */
191 rc = 0;
192 goto out;
193 }
194 if (rc < 0)
195 goto out;
196
197 rc = cap_from_disk(v1caps, bprm, rc);
198 if (rc)
199 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
200 __FUNCTION__, rc, bprm->filename);
201
202out:
203 dput(dentry);
204 if (rc)
205 bprm_clear_caps(bprm);
206
207 return rc;
208}
209
210#else
211int cap_inode_need_killpriv(struct dentry *dentry)
212{
213 return 0;
214}
215
216int cap_inode_killpriv(struct dentry *dentry)
217{
218 return 0;
219}
220
221static inline int get_file_caps(struct linux_binprm *bprm)
222{
223 bprm_clear_caps(bprm);
224 return 0;
225}
226#endif
227
111int cap_bprm_set_security (struct linux_binprm *bprm) 228int cap_bprm_set_security (struct linux_binprm *bprm)
112{ 229{
113 /* Copied from fs/exec.c:prepare_binprm. */ 230 int ret;
114 231
115 /* We don't have VFS support for capabilities yet */ 232 ret = get_file_caps(bprm);
116 cap_clear (bprm->cap_inheritable); 233 if (ret)
117 cap_clear (bprm->cap_permitted); 234 printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n",
118 cap_clear (bprm->cap_effective); 235 __FUNCTION__, ret, bprm->filename);
119 236
120 /* To support inheritance of root-permissions and suid-root 237 /* To support inheritance of root-permissions and suid-root
121 * executables under compatibility mode, we raise all three 238 * executables under compatibility mode, we raise all three
@@ -131,9 +248,10 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
131 cap_set_full (bprm->cap_permitted); 248 cap_set_full (bprm->cap_permitted);
132 } 249 }
133 if (bprm->e_uid == 0) 250 if (bprm->e_uid == 0)
134 cap_set_full (bprm->cap_effective); 251 bprm->cap_effective = true;
135 } 252 }
136 return 0; 253
254 return ret;
137} 255}
138 256
139void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) 257void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
@@ -149,6 +267,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
149 if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || 267 if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
150 !cap_issubset (new_permitted, current->cap_permitted)) { 268 !cap_issubset (new_permitted, current->cap_permitted)) {
151 set_dumpable(current->mm, suid_dumpable); 269 set_dumpable(current->mm, suid_dumpable);
270 current->pdeath_signal = 0;
152 271
153 if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { 272 if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
154 if (!capable(CAP_SETUID)) { 273 if (!capable(CAP_SETUID)) {
@@ -170,8 +289,8 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
170 * capability rules */ 289 * capability rules */
171 if (!is_init(current)) { 290 if (!is_init(current)) {
172 current->cap_permitted = new_permitted; 291 current->cap_permitted = new_permitted;
173 current->cap_effective = 292 current->cap_effective = bprm->cap_effective ?
174 cap_intersect (new_permitted, bprm->cap_effective); 293 new_permitted : 0;
175 } 294 }
176 295
177 /* AUD: Audit candidate if current->cap_effective is set */ 296 /* AUD: Audit candidate if current->cap_effective is set */
@@ -181,11 +300,15 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
181 300
182int cap_bprm_secureexec (struct linux_binprm *bprm) 301int cap_bprm_secureexec (struct linux_binprm *bprm)
183{ 302{
184 /* If/when this module is enhanced to incorporate capability 303 if (current->uid != 0) {
185 bits on files, the test below should be extended to also perform a 304 if (bprm->cap_effective)
186 test between the old and new capability sets. For now, 305 return 1;
187 it simply preserves the legacy decision algorithm used by 306 if (!cap_isclear(bprm->cap_permitted))
188 the old userland. */ 307 return 1;
308 if (!cap_isclear(bprm->cap_inheritable))
309 return 1;
310 }
311
189 return (current->euid != current->uid || 312 return (current->euid != current->uid ||
190 current->egid != current->gid); 313 current->egid != current->gid);
191} 314}
@@ -193,7 +316,11 @@ int cap_bprm_secureexec (struct linux_binprm *bprm)
193int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, 316int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
194 size_t size, int flags) 317 size_t size, int flags)
195{ 318{
196 if (!strncmp(name, XATTR_SECURITY_PREFIX, 319 if (!strcmp(name, XATTR_NAME_CAPS)) {
320 if (!capable(CAP_SETFCAP))
321 return -EPERM;
322 return 0;
323 } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
197 sizeof(XATTR_SECURITY_PREFIX) - 1) && 324 sizeof(XATTR_SECURITY_PREFIX) - 1) &&
198 !capable(CAP_SYS_ADMIN)) 325 !capable(CAP_SYS_ADMIN))
199 return -EPERM; 326 return -EPERM;
@@ -202,7 +329,11 @@ int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
202 329
203int cap_inode_removexattr(struct dentry *dentry, char *name) 330int cap_inode_removexattr(struct dentry *dentry, char *name)
204{ 331{
205 if (!strncmp(name, XATTR_SECURITY_PREFIX, 332 if (!strcmp(name, XATTR_NAME_CAPS)) {
333 if (!capable(CAP_SETFCAP))
334 return -EPERM;
335 return 0;
336 } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
206 sizeof(XATTR_SECURITY_PREFIX) - 1) && 337 sizeof(XATTR_SECURITY_PREFIX) - 1) &&
207 !capable(CAP_SYS_ADMIN)) 338 !capable(CAP_SYS_ADMIN))
208 return -EPERM; 339 return -EPERM;
@@ -299,6 +430,83 @@ int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
299 return 0; 430 return 0;
300} 431}
301 432
433#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
434/*
435 * Rationale: code calling task_setscheduler, task_setioprio, and
436 * task_setnice, assumes that
437 * . if capable(cap_sys_nice), then those actions should be allowed
438 * . if not capable(cap_sys_nice), but acting on your own processes,
439 * then those actions should be allowed
440 * This is insufficient now since you can call code without suid, but
441 * yet with increased caps.
442 * So we check for increased caps on the target process.
443 */
444static inline int cap_safe_nice(struct task_struct *p)
445{
446 if (!cap_issubset(p->cap_permitted, current->cap_permitted) &&
447 !__capable(current, CAP_SYS_NICE))
448 return -EPERM;
449 return 0;
450}
451
452int cap_task_setscheduler (struct task_struct *p, int policy,
453 struct sched_param *lp)
454{
455 return cap_safe_nice(p);
456}
457
458int cap_task_setioprio (struct task_struct *p, int ioprio)
459{
460 return cap_safe_nice(p);
461}
462
463int cap_task_setnice (struct task_struct *p, int nice)
464{
465 return cap_safe_nice(p);
466}
467
468int cap_task_kill(struct task_struct *p, struct siginfo *info,
469 int sig, u32 secid)
470{
471 if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
472 return 0;
473
474 if (secid)
475 /*
476 * Signal sent as a particular user.
477 * Capabilities are ignored. May be wrong, but it's the
478 * only thing we can do at the moment.
479 * Used only by usb drivers?
480 */
481 return 0;
482 if (cap_issubset(p->cap_permitted, current->cap_permitted))
483 return 0;
484 if (capable(CAP_KILL))
485 return 0;
486
487 return -EPERM;
488}
489#else
490int cap_task_setscheduler (struct task_struct *p, int policy,
491 struct sched_param *lp)
492{
493 return 0;
494}
495int cap_task_setioprio (struct task_struct *p, int ioprio)
496{
497 return 0;
498}
499int cap_task_setnice (struct task_struct *p, int nice)
500{
501 return 0;
502}
503int cap_task_kill(struct task_struct *p, struct siginfo *info,
504 int sig, u32 secid)
505{
506 return 0;
507}
508#endif
509
302void cap_task_reparent_to_init (struct task_struct *p) 510void cap_task_reparent_to_init (struct task_struct *p)
303{ 511{
304 p->cap_effective = CAP_INIT_EFF_SET; 512 p->cap_effective = CAP_INIT_EFF_SET;
@@ -336,6 +544,10 @@ EXPORT_SYMBOL(cap_bprm_secureexec);
336EXPORT_SYMBOL(cap_inode_setxattr); 544EXPORT_SYMBOL(cap_inode_setxattr);
337EXPORT_SYMBOL(cap_inode_removexattr); 545EXPORT_SYMBOL(cap_inode_removexattr);
338EXPORT_SYMBOL(cap_task_post_setuid); 546EXPORT_SYMBOL(cap_task_post_setuid);
547EXPORT_SYMBOL(cap_task_kill);
548EXPORT_SYMBOL(cap_task_setscheduler);
549EXPORT_SYMBOL(cap_task_setioprio);
550EXPORT_SYMBOL(cap_task_setnice);
339EXPORT_SYMBOL(cap_task_reparent_to_init); 551EXPORT_SYMBOL(cap_task_reparent_to_init);
340EXPORT_SYMBOL(cap_syslog); 552EXPORT_SYMBOL(cap_syslog);
341EXPORT_SYMBOL(cap_vm_enough_memory); 553EXPORT_SYMBOL(cap_vm_enough_memory);