diff options
-rw-r--r-- | fs/attr.c | 9 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 4 | ||||
-rw-r--r-- | fs/open.c | 3 | ||||
-rw-r--r-- | fs/splice.c | 13 | ||||
-rw-r--r-- | include/linux/binfmts.h | 3 | ||||
-rw-r--r-- | include/linux/capability.h | 48 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/linux/security.h | 40 | ||||
-rw-r--r-- | mm/filemap.c | 14 | ||||
-rw-r--r-- | security/Kconfig | 10 | ||||
-rw-r--r-- | security/capability.c | 6 | ||||
-rw-r--r-- | security/commoncap.c | 244 | ||||
-rw-r--r-- | security/dummy.c | 12 | ||||
-rw-r--r-- | security/security.c | 10 | ||||
-rw-r--r-- | security/selinux/hooks.c | 74 |
15 files changed, 418 insertions, 73 deletions
@@ -116,6 +116,15 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
116 | attr->ia_atime = now; | 116 | attr->ia_atime = now; |
117 | if (!(ia_valid & ATTR_MTIME_SET)) | 117 | if (!(ia_valid & ATTR_MTIME_SET)) |
118 | attr->ia_mtime = now; | 118 | attr->ia_mtime = now; |
119 | if (ia_valid & ATTR_KILL_PRIV) { | ||
120 | attr->ia_valid &= ~ATTR_KILL_PRIV; | ||
121 | ia_valid &= ~ATTR_KILL_PRIV; | ||
122 | error = security_inode_need_killpriv(dentry); | ||
123 | if (error > 0) | ||
124 | error = security_inode_killpriv(dentry); | ||
125 | if (error) | ||
126 | return error; | ||
127 | } | ||
119 | if (ia_valid & ATTR_KILL_SUID) { | 128 | if (ia_valid & ATTR_KILL_SUID) { |
120 | attr->ia_valid &= ~ATTR_KILL_SUID; | 129 | attr->ia_valid &= ~ATTR_KILL_SUID; |
121 | if (mode & S_ISUID) { | 130 | if (mode & S_ISUID) { |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 1d72f993b66..819545d2167 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -368,7 +368,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
368 | 368 | ||
369 | /* Revoke setuid/setgid bit on chown/chgrp */ | 369 | /* Revoke setuid/setgid bit on chown/chgrp */ |
370 | if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) | 370 | if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) |
371 | iap->ia_valid |= ATTR_KILL_SUID; | 371 | iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV; |
372 | if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) | 372 | if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) |
373 | iap->ia_valid |= ATTR_KILL_SGID; | 373 | iap->ia_valid |= ATTR_KILL_SGID; |
374 | 374 | ||
@@ -937,7 +937,7 @@ out: | |||
937 | static void kill_suid(struct dentry *dentry) | 937 | static void kill_suid(struct dentry *dentry) |
938 | { | 938 | { |
939 | struct iattr ia; | 939 | struct iattr ia; |
940 | ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID; | 940 | ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; |
941 | 941 | ||
942 | mutex_lock(&dentry->d_inode->i_mutex); | 942 | mutex_lock(&dentry->d_inode->i_mutex); |
943 | notify_change(dentry, &ia); | 943 | notify_change(dentry, &ia); |
@@ -658,7 +658,8 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | |||
658 | newattrs.ia_gid = group; | 658 | newattrs.ia_gid = group; |
659 | } | 659 | } |
660 | if (!S_ISDIR(inode->i_mode)) | 660 | if (!S_ISDIR(inode->i_mode)) |
661 | newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID; | 661 | newattrs.ia_valid |= |
662 | ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; | ||
662 | mutex_lock(&inode->i_mutex); | 663 | mutex_lock(&inode->i_mutex); |
663 | error = notify_change(dentry, &newattrs); | 664 | error = notify_change(dentry, &newattrs); |
664 | mutex_unlock(&inode->i_mutex); | 665 | mutex_unlock(&inode->i_mutex); |
diff --git a/fs/splice.c b/fs/splice.c index 59a941d404d..6bdcb6107bc 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -824,13 +824,18 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
824 | { | 824 | { |
825 | struct address_space *mapping = out->f_mapping; | 825 | struct address_space *mapping = out->f_mapping; |
826 | struct inode *inode = mapping->host; | 826 | struct inode *inode = mapping->host; |
827 | int killsuid, killpriv; | ||
827 | ssize_t ret; | 828 | ssize_t ret; |
828 | int err; | 829 | int err = 0; |
829 | 830 | ||
830 | err = should_remove_suid(out->f_path.dentry); | 831 | killpriv = security_inode_need_killpriv(out->f_path.dentry); |
831 | if (unlikely(err)) { | 832 | killsuid = should_remove_suid(out->f_path.dentry); |
833 | if (unlikely(killsuid || killpriv)) { | ||
832 | mutex_lock(&inode->i_mutex); | 834 | mutex_lock(&inode->i_mutex); |
833 | err = __remove_suid(out->f_path.dentry, err); | 835 | if (killpriv) |
836 | err = security_inode_killpriv(out->f_path.dentry); | ||
837 | if (!err && killsuid) | ||
838 | err = __remove_suid(out->f_path.dentry, killsuid); | ||
834 | mutex_unlock(&inode->i_mutex); | 839 | mutex_unlock(&inode->i_mutex); |
835 | if (err) | 840 | if (err) |
836 | return err; | 841 | return err; |
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 3a6512f8ec9..b7fc55ec8d4 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h | |||
@@ -37,7 +37,8 @@ struct linux_binprm{ | |||
37 | int sh_bang; | 37 | int sh_bang; |
38 | struct file * file; | 38 | struct file * file; |
39 | int e_uid, e_gid; | 39 | int e_uid, e_gid; |
40 | kernel_cap_t cap_inheritable, cap_permitted, cap_effective; | 40 | kernel_cap_t cap_inheritable, cap_permitted; |
41 | bool cap_effective; | ||
41 | void *security; | 42 | void *security; |
42 | int argc, envc; | 43 | int argc, envc; |
43 | char * filename; /* Name of binary as seen by procps */ | 44 | char * filename; /* Name of binary as seen by procps */ |
diff --git a/include/linux/capability.h b/include/linux/capability.h index 2dfa5855593..8961e7fb755 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h | |||
@@ -1,14 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * This is <linux/capability.h> | 2 | * This is <linux/capability.h> |
3 | * | 3 | * |
4 | * Andrew G. Morgan <morgan@transmeta.com> | 4 | * Andrew G. Morgan <morgan@kernel.org> |
5 | * Alexander Kjeldaas <astor@guardian.no> | 5 | * Alexander Kjeldaas <astor@guardian.no> |
6 | * with help from Aleph1, Roland Buresund and Andrew Main. | 6 | * with help from Aleph1, Roland Buresund and Andrew Main. |
7 | * | 7 | * |
8 | * See here for the libcap library ("POSIX draft" compliance): | 8 | * See here for the libcap library ("POSIX draft" compliance): |
9 | * | 9 | * |
10 | * ftp://linux.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.2/ | 10 | * ftp://linux.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/ |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef _LINUX_CAPABILITY_H | 13 | #ifndef _LINUX_CAPABILITY_H |
14 | #define _LINUX_CAPABILITY_H | 14 | #define _LINUX_CAPABILITY_H |
@@ -28,23 +28,41 @@ struct task_struct; | |||
28 | following structure to such a composite is better handled in a user | 28 | following structure to such a composite is better handled in a user |
29 | library since the draft standard requires the use of malloc/free | 29 | library since the draft standard requires the use of malloc/free |
30 | etc.. */ | 30 | etc.. */ |
31 | 31 | ||
32 | #define _LINUX_CAPABILITY_VERSION 0x19980330 | 32 | #define _LINUX_CAPABILITY_VERSION 0x19980330 |
33 | 33 | ||
34 | typedef struct __user_cap_header_struct { | 34 | typedef struct __user_cap_header_struct { |
35 | __u32 version; | 35 | __u32 version; |
36 | int pid; | 36 | int pid; |
37 | } __user *cap_user_header_t; | 37 | } __user *cap_user_header_t; |
38 | 38 | ||
39 | typedef struct __user_cap_data_struct { | 39 | typedef struct __user_cap_data_struct { |
40 | __u32 effective; | 40 | __u32 effective; |
41 | __u32 permitted; | 41 | __u32 permitted; |
42 | __u32 inheritable; | 42 | __u32 inheritable; |
43 | } __user *cap_user_data_t; | 43 | } __user *cap_user_data_t; |
44 | |||
45 | #ifdef __KERNEL__ | ||
46 | 44 | ||
47 | #include <asm/current.h> | 45 | #define XATTR_CAPS_SUFFIX "capability" |
46 | #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX | ||
47 | |||
48 | #define XATTR_CAPS_SZ (3*sizeof(__le32)) | ||
49 | #define VFS_CAP_REVISION_MASK 0xFF000000 | ||
50 | #define VFS_CAP_REVISION_1 0x01000000 | ||
51 | |||
52 | #define VFS_CAP_REVISION VFS_CAP_REVISION_1 | ||
53 | |||
54 | #define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK | ||
55 | #define VFS_CAP_FLAGS_EFFECTIVE 0x000001 | ||
56 | |||
57 | struct vfs_cap_data { | ||
58 | __u32 magic_etc; /* Little endian */ | ||
59 | struct { | ||
60 | __u32 permitted; /* Little endian */ | ||
61 | __u32 inheritable; /* Little endian */ | ||
62 | } data[1]; | ||
63 | }; | ||
64 | |||
65 | #ifdef __KERNEL__ | ||
48 | 66 | ||
49 | /* #define STRICT_CAP_T_TYPECHECKS */ | 67 | /* #define STRICT_CAP_T_TYPECHECKS */ |
50 | 68 | ||
@@ -59,7 +77,7 @@ typedef struct kernel_cap_struct { | |||
59 | typedef __u32 kernel_cap_t; | 77 | typedef __u32 kernel_cap_t; |
60 | 78 | ||
61 | #endif | 79 | #endif |
62 | 80 | ||
63 | #define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) | 81 | #define _USER_CAP_HEADER_SIZE (2*sizeof(__u32)) |
64 | #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) | 82 | #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) |
65 | 83 | ||
@@ -67,7 +85,7 @@ typedef __u32 kernel_cap_t; | |||
67 | 85 | ||
68 | 86 | ||
69 | /** | 87 | /** |
70 | ** POSIX-draft defined capabilities. | 88 | ** POSIX-draft defined capabilities. |
71 | **/ | 89 | **/ |
72 | 90 | ||
73 | /* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this | 91 | /* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this |
@@ -87,7 +105,7 @@ typedef __u32 kernel_cap_t; | |||
87 | defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */ | 105 | defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */ |
88 | 106 | ||
89 | #define CAP_DAC_READ_SEARCH 2 | 107 | #define CAP_DAC_READ_SEARCH 2 |
90 | 108 | ||
91 | /* Overrides all restrictions about allowed operations on files, where | 109 | /* Overrides all restrictions about allowed operations on files, where |
92 | file owner ID must be equal to the user ID, except where CAP_FSETID | 110 | file owner ID must be equal to the user ID, except where CAP_FSETID |
93 | is applicable. It doesn't override MAC and DAC restrictions. */ | 111 | is applicable. It doesn't override MAC and DAC restrictions. */ |
@@ -257,7 +275,7 @@ typedef __u32 kernel_cap_t; | |||
257 | /* Override reserved space on ext2 filesystem */ | 275 | /* Override reserved space on ext2 filesystem */ |
258 | /* Modify data journaling mode on ext3 filesystem (uses journaling | 276 | /* Modify data journaling mode on ext3 filesystem (uses journaling |
259 | resources) */ | 277 | resources) */ |
260 | /* NOTE: ext2 honors fsuid when checking for resource overrides, so | 278 | /* NOTE: ext2 honors fsuid when checking for resource overrides, so |
261 | you can override using fsuid too */ | 279 | you can override using fsuid too */ |
262 | /* Override size restrictions on IPC message queues */ | 280 | /* Override size restrictions on IPC message queues */ |
263 | /* Allow more than 64hz interrupts from the real-time clock */ | 281 | /* Allow more than 64hz interrupts from the real-time clock */ |
@@ -289,8 +307,10 @@ typedef __u32 kernel_cap_t; | |||
289 | 307 | ||
290 | #define CAP_AUDIT_CONTROL 30 | 308 | #define CAP_AUDIT_CONTROL 30 |
291 | 309 | ||
310 | #define CAP_SETFCAP 31 | ||
311 | |||
292 | #ifdef __KERNEL__ | 312 | #ifdef __KERNEL__ |
293 | /* | 313 | /* |
294 | * Bounding set | 314 | * Bounding set |
295 | */ | 315 | */ |
296 | extern kernel_cap_t cap_bset; | 316 | extern kernel_cap_t cap_bset; |
@@ -298,7 +318,7 @@ extern kernel_cap_t cap_bset; | |||
298 | /* | 318 | /* |
299 | * Internal kernel functions only | 319 | * Internal kernel functions only |
300 | */ | 320 | */ |
301 | 321 | ||
302 | #ifdef STRICT_CAP_T_TYPECHECKS | 322 | #ifdef STRICT_CAP_T_TYPECHECKS |
303 | 323 | ||
304 | #define to_cap_t(x) { x } | 324 | #define to_cap_t(x) { x } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 365586a4c4d..e3fc5dbb224 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -329,6 +329,7 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, | |||
329 | #define ATTR_KILL_SUID 2048 | 329 | #define ATTR_KILL_SUID 2048 |
330 | #define ATTR_KILL_SGID 4096 | 330 | #define ATTR_KILL_SGID 4096 |
331 | #define ATTR_FILE 8192 | 331 | #define ATTR_FILE 8192 |
332 | #define ATTR_KILL_PRIV 16384 | ||
332 | 333 | ||
333 | /* | 334 | /* |
334 | * This is the Inode Attributes structure, used for notify_change(). It | 335 | * This is the Inode Attributes structure, used for notify_change(). It |
diff --git a/include/linux/security.h b/include/linux/security.h index a300a3f2fe6..df591d289ec 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -51,8 +51,14 @@ extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe); | |||
51 | extern int cap_bprm_secureexec(struct linux_binprm *bprm); | 51 | extern int cap_bprm_secureexec(struct linux_binprm *bprm); |
52 | extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags); | 52 | extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags); |
53 | extern int cap_inode_removexattr(struct dentry *dentry, char *name); | 53 | extern int cap_inode_removexattr(struct dentry *dentry, char *name); |
54 | extern int cap_inode_need_killpriv(struct dentry *dentry); | ||
55 | extern int cap_inode_killpriv(struct dentry *dentry); | ||
54 | extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); | 56 | extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags); |
55 | extern void cap_task_reparent_to_init (struct task_struct *p); | 57 | extern void cap_task_reparent_to_init (struct task_struct *p); |
58 | extern int cap_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid); | ||
59 | extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp); | ||
60 | extern int cap_task_setioprio (struct task_struct *p, int ioprio); | ||
61 | extern int cap_task_setnice (struct task_struct *p, int nice); | ||
56 | extern int cap_syslog (int type); | 62 | extern int cap_syslog (int type); |
57 | extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); | 63 | extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); |
58 | 64 | ||
@@ -413,6 +419,18 @@ struct request_sock; | |||
413 | * is specified by @buffer_size. @buffer may be NULL to request | 419 | * is specified by @buffer_size. @buffer may be NULL to request |
414 | * the size of the buffer required. | 420 | * the size of the buffer required. |
415 | * Returns number of bytes used/required on success. | 421 | * Returns number of bytes used/required on success. |
422 | * @inode_need_killpriv: | ||
423 | * Called when an inode has been changed. | ||
424 | * @dentry is the dentry being changed. | ||
425 | * Return <0 on error to abort the inode change operation. | ||
426 | * Return 0 if inode_killpriv does not need to be called. | ||
427 | * Return >0 if inode_killpriv does need to be called. | ||
428 | * @inode_killpriv: | ||
429 | * The setuid bit is being removed. Remove similar security labels. | ||
430 | * Called with the dentry->d_inode->i_mutex held. | ||
431 | * @dentry is the dentry being changed. | ||
432 | * Return 0 on success. If error is returned, then the operation | ||
433 | * causing setuid bit removal is failed. | ||
416 | * | 434 | * |
417 | * Security hooks for file operations | 435 | * Security hooks for file operations |
418 | * | 436 | * |
@@ -1239,6 +1257,8 @@ struct security_operations { | |||
1239 | int (*inode_getxattr) (struct dentry *dentry, char *name); | 1257 | int (*inode_getxattr) (struct dentry *dentry, char *name); |
1240 | int (*inode_listxattr) (struct dentry *dentry); | 1258 | int (*inode_listxattr) (struct dentry *dentry); |
1241 | int (*inode_removexattr) (struct dentry *dentry, char *name); | 1259 | int (*inode_removexattr) (struct dentry *dentry, char *name); |
1260 | int (*inode_need_killpriv) (struct dentry *dentry); | ||
1261 | int (*inode_killpriv) (struct dentry *dentry); | ||
1242 | const char *(*inode_xattr_getsuffix) (void); | 1262 | const char *(*inode_xattr_getsuffix) (void); |
1243 | int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err); | 1263 | int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err); |
1244 | int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); | 1264 | int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); |
@@ -1496,6 +1516,8 @@ void security_inode_post_setxattr(struct dentry *dentry, char *name, | |||
1496 | int security_inode_getxattr(struct dentry *dentry, char *name); | 1516 | int security_inode_getxattr(struct dentry *dentry, char *name); |
1497 | int security_inode_listxattr(struct dentry *dentry); | 1517 | int security_inode_listxattr(struct dentry *dentry); |
1498 | int security_inode_removexattr(struct dentry *dentry, char *name); | 1518 | int security_inode_removexattr(struct dentry *dentry, char *name); |
1519 | int security_inode_need_killpriv(struct dentry *dentry); | ||
1520 | int security_inode_killpriv(struct dentry *dentry); | ||
1499 | const char *security_inode_xattr_getsuffix(void); | 1521 | const char *security_inode_xattr_getsuffix(void); |
1500 | int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err); | 1522 | int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err); |
1501 | int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags); | 1523 | int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags); |
@@ -1891,6 +1913,16 @@ static inline int security_inode_removexattr (struct dentry *dentry, char *name) | |||
1891 | return cap_inode_removexattr(dentry, name); | 1913 | return cap_inode_removexattr(dentry, name); |
1892 | } | 1914 | } |
1893 | 1915 | ||
1916 | static inline int security_inode_need_killpriv(struct dentry *dentry) | ||
1917 | { | ||
1918 | return cap_inode_need_killpriv(dentry); | ||
1919 | } | ||
1920 | |||
1921 | static inline int security_inode_killpriv(struct dentry *dentry) | ||
1922 | { | ||
1923 | return cap_inode_killpriv(dentry); | ||
1924 | } | ||
1925 | |||
1894 | static inline const char *security_inode_xattr_getsuffix (void) | 1926 | static inline const char *security_inode_xattr_getsuffix (void) |
1895 | { | 1927 | { |
1896 | return NULL ; | 1928 | return NULL ; |
@@ -2035,12 +2067,12 @@ static inline int security_task_setgroups (struct group_info *group_info) | |||
2035 | 2067 | ||
2036 | static inline int security_task_setnice (struct task_struct *p, int nice) | 2068 | static inline int security_task_setnice (struct task_struct *p, int nice) |
2037 | { | 2069 | { |
2038 | return 0; | 2070 | return cap_task_setnice(p, nice); |
2039 | } | 2071 | } |
2040 | 2072 | ||
2041 | static inline int security_task_setioprio (struct task_struct *p, int ioprio) | 2073 | static inline int security_task_setioprio (struct task_struct *p, int ioprio) |
2042 | { | 2074 | { |
2043 | return 0; | 2075 | return cap_task_setioprio(p, ioprio); |
2044 | } | 2076 | } |
2045 | 2077 | ||
2046 | static inline int security_task_getioprio (struct task_struct *p) | 2078 | static inline int security_task_getioprio (struct task_struct *p) |
@@ -2058,7 +2090,7 @@ static inline int security_task_setscheduler (struct task_struct *p, | |||
2058 | int policy, | 2090 | int policy, |
2059 | struct sched_param *lp) | 2091 | struct sched_param *lp) |
2060 | { | 2092 | { |
2061 | return 0; | 2093 | return cap_task_setscheduler(p, policy, lp); |
2062 | } | 2094 | } |
2063 | 2095 | ||
2064 | static inline int security_task_getscheduler (struct task_struct *p) | 2096 | static inline int security_task_getscheduler (struct task_struct *p) |
@@ -2075,7 +2107,7 @@ static inline int security_task_kill (struct task_struct *p, | |||
2075 | struct siginfo *info, int sig, | 2107 | struct siginfo *info, int sig, |
2076 | u32 secid) | 2108 | u32 secid) |
2077 | { | 2109 | { |
2078 | return 0; | 2110 | return cap_task_kill(p, info, sig, secid); |
2079 | } | 2111 | } |
2080 | 2112 | ||
2081 | static inline int security_task_wait (struct task_struct *p) | 2113 | static inline int security_task_wait (struct task_struct *p) |
diff --git a/mm/filemap.c b/mm/filemap.c index 4fb1546bbad..79f24a969cb 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1627,12 +1627,18 @@ int __remove_suid(struct dentry *dentry, int kill) | |||
1627 | 1627 | ||
1628 | int remove_suid(struct dentry *dentry) | 1628 | int remove_suid(struct dentry *dentry) |
1629 | { | 1629 | { |
1630 | int kill = should_remove_suid(dentry); | 1630 | int killsuid = should_remove_suid(dentry); |
1631 | int killpriv = security_inode_need_killpriv(dentry); | ||
1632 | int error = 0; | ||
1631 | 1633 | ||
1632 | if (unlikely(kill)) | 1634 | if (killpriv < 0) |
1633 | return __remove_suid(dentry, kill); | 1635 | return killpriv; |
1636 | if (killpriv) | ||
1637 | error = security_inode_killpriv(dentry); | ||
1638 | if (!error && killsuid) | ||
1639 | error = __remove_suid(dentry, killsuid); | ||
1634 | 1640 | ||
1635 | return 0; | 1641 | return error; |
1636 | } | 1642 | } |
1637 | EXPORT_SYMBOL(remove_suid); | 1643 | EXPORT_SYMBOL(remove_suid); |
1638 | 1644 | ||
diff --git a/security/Kconfig b/security/Kconfig index a94ee94cf49..8086e61058e 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -80,6 +80,16 @@ config SECURITY_CAPABILITIES | |||
80 | This enables the "default" Linux capabilities functionality. | 80 | This enables the "default" Linux capabilities functionality. |
81 | If you are unsure how to answer this question, answer Y. | 81 | If you are unsure how to answer this question, answer Y. |
82 | 82 | ||
83 | config SECURITY_FILE_CAPABILITIES | ||
84 | bool "File POSIX Capabilities (EXPERIMENTAL)" | ||
85 | depends on (SECURITY=n || SECURITY_CAPABILITIES!=n) && EXPERIMENTAL | ||
86 | default n | ||
87 | help | ||
88 | This enables filesystem capabilities, allowing you to give | ||
89 | binaries a subset of root's powers without using setuid 0. | ||
90 | |||
91 | If in doubt, answer N. | ||
92 | |||
83 | config SECURITY_ROOTPLUG | 93 | config SECURITY_ROOTPLUG |
84 | bool "Root Plug Support" | 94 | bool "Root Plug Support" |
85 | depends on USB=y && SECURITY | 95 | depends on USB=y && SECURITY |
diff --git a/security/capability.c b/security/capability.c index fda6a14cb24..9e99f36a8b5 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -37,7 +37,13 @@ static struct security_operations capability_ops = { | |||
37 | 37 | ||
38 | .inode_setxattr = cap_inode_setxattr, | 38 | .inode_setxattr = cap_inode_setxattr, |
39 | .inode_removexattr = cap_inode_removexattr, | 39 | .inode_removexattr = cap_inode_removexattr, |
40 | .inode_need_killpriv = cap_inode_need_killpriv, | ||
41 | .inode_killpriv = cap_inode_killpriv, | ||
40 | 42 | ||
43 | .task_kill = cap_task_kill, | ||
44 | .task_setscheduler = cap_task_setscheduler, | ||
45 | .task_setioprio = cap_task_setioprio, | ||
46 | .task_setnice = cap_task_setnice, | ||
41 | .task_post_setuid = cap_task_post_setuid, | 47 | .task_post_setuid = cap_task_post_setuid, |
42 | .task_reparent_to_init = cap_task_reparent_to_init, | 48 | .task_reparent_to_init = cap_task_reparent_to_init, |
43 | 49 | ||
diff --git a/security/commoncap.c b/security/commoncap.c index 0f8a2ce3f3a..afca6dd4ae6 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 | ||
26 | int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | 27 | int 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 | ||
112 | static 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 | |||
121 | int 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 | |||
135 | int 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 | |||
145 | static 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: */ | ||
170 | static 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 | |||
202 | out: | ||
203 | dput(dentry); | ||
204 | if (rc) | ||
205 | bprm_clear_caps(bprm); | ||
206 | |||
207 | return rc; | ||
208 | } | ||
209 | |||
210 | #else | ||
211 | int cap_inode_need_killpriv(struct dentry *dentry) | ||
212 | { | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | int cap_inode_killpriv(struct dentry *dentry) | ||
217 | { | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static inline int get_file_caps(struct linux_binprm *bprm) | ||
222 | { | ||
223 | bprm_clear_caps(bprm); | ||
224 | return 0; | ||
225 | } | ||
226 | #endif | ||
227 | |||
111 | int cap_bprm_set_security (struct linux_binprm *bprm) | 228 | int 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 | ||
139 | void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) | 257 | void 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 | ||
182 | int cap_bprm_secureexec (struct linux_binprm *bprm) | 301 | int 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) | |||
193 | int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, | 316 | int 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 | ||
203 | int cap_inode_removexattr(struct dentry *dentry, char *name) | 330 | int 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 | */ | ||
444 | static 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 | |||
452 | int cap_task_setscheduler (struct task_struct *p, int policy, | ||
453 | struct sched_param *lp) | ||
454 | { | ||
455 | return cap_safe_nice(p); | ||
456 | } | ||
457 | |||
458 | int cap_task_setioprio (struct task_struct *p, int ioprio) | ||
459 | { | ||
460 | return cap_safe_nice(p); | ||
461 | } | ||
462 | |||
463 | int cap_task_setnice (struct task_struct *p, int nice) | ||
464 | { | ||
465 | return cap_safe_nice(p); | ||
466 | } | ||
467 | |||
468 | int 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 | ||
490 | int cap_task_setscheduler (struct task_struct *p, int policy, | ||
491 | struct sched_param *lp) | ||
492 | { | ||
493 | return 0; | ||
494 | } | ||
495 | int cap_task_setioprio (struct task_struct *p, int ioprio) | ||
496 | { | ||
497 | return 0; | ||
498 | } | ||
499 | int cap_task_setnice (struct task_struct *p, int nice) | ||
500 | { | ||
501 | return 0; | ||
502 | } | ||
503 | int cap_task_kill(struct task_struct *p, struct siginfo *info, | ||
504 | int sig, u32 secid) | ||
505 | { | ||
506 | return 0; | ||
507 | } | ||
508 | #endif | ||
509 | |||
302 | void cap_task_reparent_to_init (struct task_struct *p) | 510 | void 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); | |||
336 | EXPORT_SYMBOL(cap_inode_setxattr); | 544 | EXPORT_SYMBOL(cap_inode_setxattr); |
337 | EXPORT_SYMBOL(cap_inode_removexattr); | 545 | EXPORT_SYMBOL(cap_inode_removexattr); |
338 | EXPORT_SYMBOL(cap_task_post_setuid); | 546 | EXPORT_SYMBOL(cap_task_post_setuid); |
547 | EXPORT_SYMBOL(cap_task_kill); | ||
548 | EXPORT_SYMBOL(cap_task_setscheduler); | ||
549 | EXPORT_SYMBOL(cap_task_setioprio); | ||
550 | EXPORT_SYMBOL(cap_task_setnice); | ||
339 | EXPORT_SYMBOL(cap_task_reparent_to_init); | 551 | EXPORT_SYMBOL(cap_task_reparent_to_init); |
340 | EXPORT_SYMBOL(cap_syslog); | 552 | EXPORT_SYMBOL(cap_syslog); |
341 | EXPORT_SYMBOL(cap_vm_enough_memory); | 553 | EXPORT_SYMBOL(cap_vm_enough_memory); |
diff --git a/security/dummy.c b/security/dummy.c index 4129dcf3dae..c77dec82238 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
@@ -376,6 +376,16 @@ static int dummy_inode_removexattr (struct dentry *dentry, char *name) | |||
376 | return 0; | 376 | return 0; |
377 | } | 377 | } |
378 | 378 | ||
379 | static int dummy_inode_need_killpriv(struct dentry *dentry) | ||
380 | { | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int dummy_inode_killpriv(struct dentry *dentry) | ||
385 | { | ||
386 | return 0; | ||
387 | } | ||
388 | |||
379 | static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err) | 389 | static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err) |
380 | { | 390 | { |
381 | return -EOPNOTSUPP; | 391 | return -EOPNOTSUPP; |
@@ -1022,6 +1032,8 @@ void security_fixup_ops (struct security_operations *ops) | |||
1022 | set_to_dummy_if_null(ops, inode_getxattr); | 1032 | set_to_dummy_if_null(ops, inode_getxattr); |
1023 | set_to_dummy_if_null(ops, inode_listxattr); | 1033 | set_to_dummy_if_null(ops, inode_listxattr); |
1024 | set_to_dummy_if_null(ops, inode_removexattr); | 1034 | set_to_dummy_if_null(ops, inode_removexattr); |
1035 | set_to_dummy_if_null(ops, inode_need_killpriv); | ||
1036 | set_to_dummy_if_null(ops, inode_killpriv); | ||
1025 | set_to_dummy_if_null(ops, inode_xattr_getsuffix); | 1037 | set_to_dummy_if_null(ops, inode_xattr_getsuffix); |
1026 | set_to_dummy_if_null(ops, inode_getsecurity); | 1038 | set_to_dummy_if_null(ops, inode_getsecurity); |
1027 | set_to_dummy_if_null(ops, inode_setsecurity); | 1039 | set_to_dummy_if_null(ops, inode_setsecurity); |
diff --git a/security/security.c b/security/security.c index 5b1c034815a..2e1b35dd255 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -518,6 +518,16 @@ int security_inode_removexattr(struct dentry *dentry, char *name) | |||
518 | return security_ops->inode_removexattr(dentry, name); | 518 | return security_ops->inode_removexattr(dentry, name); |
519 | } | 519 | } |
520 | 520 | ||
521 | int security_inode_need_killpriv(struct dentry *dentry) | ||
522 | { | ||
523 | return security_ops->inode_need_killpriv(dentry); | ||
524 | } | ||
525 | |||
526 | int security_inode_killpriv(struct dentry *dentry) | ||
527 | { | ||
528 | return security_ops->inode_killpriv(dentry); | ||
529 | } | ||
530 | |||
521 | const char *security_inode_xattr_getsuffix(void) | 531 | const char *security_inode_xattr_getsuffix(void) |
522 | { | 532 | { |
523 | return security_ops->inode_xattr_getsuffix(); | 533 | return security_ops->inode_xattr_getsuffix(); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 83a535b7bc6..221def6a0b1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -2297,6 +2297,25 @@ static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
2297 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); | 2297 | return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); |
2298 | } | 2298 | } |
2299 | 2299 | ||
2300 | static int selinux_inode_setotherxattr(struct dentry *dentry, char *name) | ||
2301 | { | ||
2302 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | ||
2303 | sizeof XATTR_SECURITY_PREFIX - 1)) { | ||
2304 | if (!strcmp(name, XATTR_NAME_CAPS)) { | ||
2305 | if (!capable(CAP_SETFCAP)) | ||
2306 | return -EPERM; | ||
2307 | } else if (!capable(CAP_SYS_ADMIN)) { | ||
2308 | /* A different attribute in the security namespace. | ||
2309 | Restrict to administrator. */ | ||
2310 | return -EPERM; | ||
2311 | } | ||
2312 | } | ||
2313 | |||
2314 | /* Not an attribute we recognize, so just check the | ||
2315 | ordinary setattr permission. */ | ||
2316 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | ||
2317 | } | ||
2318 | |||
2300 | static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) | 2319 | static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) |
2301 | { | 2320 | { |
2302 | struct task_security_struct *tsec = current->security; | 2321 | struct task_security_struct *tsec = current->security; |
@@ -2307,19 +2326,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value | |||
2307 | u32 newsid; | 2326 | u32 newsid; |
2308 | int rc = 0; | 2327 | int rc = 0; |
2309 | 2328 | ||
2310 | if (strcmp(name, XATTR_NAME_SELINUX)) { | 2329 | if (strcmp(name, XATTR_NAME_SELINUX)) |
2311 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 2330 | return selinux_inode_setotherxattr(dentry, name); |
2312 | sizeof XATTR_SECURITY_PREFIX - 1) && | ||
2313 | !capable(CAP_SYS_ADMIN)) { | ||
2314 | /* A different attribute in the security namespace. | ||
2315 | Restrict to administrator. */ | ||
2316 | return -EPERM; | ||
2317 | } | ||
2318 | |||
2319 | /* Not an attribute we recognize, so just check the | ||
2320 | ordinary setattr permission. */ | ||
2321 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | ||
2322 | } | ||
2323 | 2331 | ||
2324 | sbsec = inode->i_sb->s_security; | 2332 | sbsec = inode->i_sb->s_security; |
2325 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 2333 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) |
@@ -2393,20 +2401,8 @@ static int selinux_inode_listxattr (struct dentry *dentry) | |||
2393 | 2401 | ||
2394 | static int selinux_inode_removexattr (struct dentry *dentry, char *name) | 2402 | static int selinux_inode_removexattr (struct dentry *dentry, char *name) |
2395 | { | 2403 | { |
2396 | if (strcmp(name, XATTR_NAME_SELINUX)) { | 2404 | if (strcmp(name, XATTR_NAME_SELINUX)) |
2397 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 2405 | return selinux_inode_setotherxattr(dentry, name); |
2398 | sizeof XATTR_SECURITY_PREFIX - 1) && | ||
2399 | !capable(CAP_SYS_ADMIN)) { | ||
2400 | /* A different attribute in the security namespace. | ||
2401 | Restrict to administrator. */ | ||
2402 | return -EPERM; | ||
2403 | } | ||
2404 | |||
2405 | /* Not an attribute we recognize, so just check the | ||
2406 | ordinary setattr permission. Might want a separate | ||
2407 | permission for removexattr. */ | ||
2408 | return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); | ||
2409 | } | ||
2410 | 2406 | ||
2411 | /* No one is allowed to remove a SELinux security label. | 2407 | /* No one is allowed to remove a SELinux security label. |
2412 | You can change the label, but all data must be labeled. */ | 2408 | You can change the label, but all data must be labeled. */ |
@@ -2464,6 +2460,16 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t | |||
2464 | return len; | 2460 | return len; |
2465 | } | 2461 | } |
2466 | 2462 | ||
2463 | static int selinux_inode_need_killpriv(struct dentry *dentry) | ||
2464 | { | ||
2465 | return secondary_ops->inode_need_killpriv(dentry); | ||
2466 | } | ||
2467 | |||
2468 | static int selinux_inode_killpriv(struct dentry *dentry) | ||
2469 | { | ||
2470 | return secondary_ops->inode_killpriv(dentry); | ||
2471 | } | ||
2472 | |||
2467 | /* file security operations */ | 2473 | /* file security operations */ |
2468 | 2474 | ||
2469 | static int selinux_revalidate_file_permission(struct file *file, int mask) | 2475 | static int selinux_revalidate_file_permission(struct file *file, int mask) |
@@ -2882,6 +2888,12 @@ static int selinux_task_setnice(struct task_struct *p, int nice) | |||
2882 | 2888 | ||
2883 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) | 2889 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) |
2884 | { | 2890 | { |
2891 | int rc; | ||
2892 | |||
2893 | rc = secondary_ops->task_setioprio(p, ioprio); | ||
2894 | if (rc) | ||
2895 | return rc; | ||
2896 | |||
2885 | return task_has_perm(current, p, PROCESS__SETSCHED); | 2897 | return task_has_perm(current, p, PROCESS__SETSCHED); |
2886 | } | 2898 | } |
2887 | 2899 | ||
@@ -2911,6 +2923,12 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim | |||
2911 | 2923 | ||
2912 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) | 2924 | static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) |
2913 | { | 2925 | { |
2926 | int rc; | ||
2927 | |||
2928 | rc = secondary_ops->task_setscheduler(p, policy, lp); | ||
2929 | if (rc) | ||
2930 | return rc; | ||
2931 | |||
2914 | return task_has_perm(current, p, PROCESS__SETSCHED); | 2932 | return task_has_perm(current, p, PROCESS__SETSCHED); |
2915 | } | 2933 | } |
2916 | 2934 | ||
@@ -4830,6 +4848,8 @@ static struct security_operations selinux_ops = { | |||
4830 | .inode_getsecurity = selinux_inode_getsecurity, | 4848 | .inode_getsecurity = selinux_inode_getsecurity, |
4831 | .inode_setsecurity = selinux_inode_setsecurity, | 4849 | .inode_setsecurity = selinux_inode_setsecurity, |
4832 | .inode_listsecurity = selinux_inode_listsecurity, | 4850 | .inode_listsecurity = selinux_inode_listsecurity, |
4851 | .inode_need_killpriv = selinux_inode_need_killpriv, | ||
4852 | .inode_killpriv = selinux_inode_killpriv, | ||
4833 | 4853 | ||
4834 | .file_permission = selinux_file_permission, | 4854 | .file_permission = selinux_file_permission, |
4835 | .file_alloc_security = selinux_file_alloc_security, | 4855 | .file_alloc_security = selinux_file_alloc_security, |